08 Jan, 2010, Sorressean wrote in the 1st comment:
Votes: 0
Hello all,
I'm currently stuck with a slight problem, and am trying to find a solution.
I want to allow player objects to be persistent; that is, when a player quits, I want to store their objects with them so that when they log on again their objects are there in their inventory. This is providing a bit of a problem. If I were to have a weapon, it would be easy enough to store the list of contents and then load the object, but this leads to two questions:
First, how would I serialize the object back to a weapon without storing type info? Does this mean that every object whether just an object or an instance of that opbject needs to contain a type?
Second,, short of storing versioning information on the object, how do I keep track of whether or not the object has been updated since the player last logged on? For example, if I have a weapon as follows:
struct weapon
{
int damage;
int attack;
int value;
};
And I decide to add a durability integer, I can easily add it to the structure and the serialization and deserialization functions for that object. But when a player who logged on after the change logs on again, the object will read 4 bytes past what is already there.

Last, I'm trying to set this up so I can script it in python. I would like to create an object and then let it be extended upon, if the coder wants to use python to create weapons and that he or she can, or the weapons can be created in the c++ code, and then used later in python as a type of object. Any tips here would be great. My main issue is how to manage new objects in python; will they just be created as objects? If a player creates an object of type Object, and sets it to be a clonable object of sorts and wants it to be a brink, they may add something like capacity for liquid. How would that be taken back to be serialized?

I hope this all made sense. My thoughts are kind of jumbled right now, but this seems like the biggest hurtle so far.t
08 Jan, 2010, Barm wrote in the 2nd comment:
Votes: 0
I would suggest not trying to serialize the object itself for the simple reason that objects tend to get changed a lot and you'd find your stored copies broken. Design your objects to accept configuration from data structure like a dictionary or JSON file and store those. Your weapon object would have a method like set_durability(int) and the dictionary you saved for the player's corresponding slot would have keys like "durability":92.

For my project, I have a single dictionary of game objects indexed by UUID. So the player's primary hand slot would contain a UUID string that I use to look up the item and get stats / effects. If I change the name of a sword, it changes for everyone because all players use the same objects. I don't have durability but if I did, I'd probably fake it with a personal durability dictionary attached to the actor.
08 Jan, 2010, elanthis wrote in the 3rd comment:
Votes: 0
Everything Barm said is spot on. Serialization technologies were never meant to be used for storing persistent data of this type. They were meant for live transition of objects between applications and for temporary storage. Long-term storage of evolving data sets is almost always better off in a rich data format that can evolve with the application. A lot of game development sites will tell you to use serialization, but realize that they are solving a very different problem than a MUD: they are worried about a static set of data released with a finished (non-evolving) game where performance/load-time is critical to user satisfaction. A MUD is a totally different beast than your average FPS and the data storage choices you make for each should be different.

I want to reinforce the idea Barm hinted on of using an object description separate from individual instances of objects. That is, each item in your game should NOT have a full copy of all its parameters. That is a maintenance nightmare and incredibly inflexible (even though at first blush it might seem _more_ flexible than what I suggested; believe me, it's not).

For every item in your game, you essentially have two objects. One is the template/base/blueprint/definition (whatever you want to call it). This contains all of the static information about the item, e.g. its name, value, description, attack properties, etc. For each copy of that type of item that exists in the game world, you then have a separate instance object that refers to the definition object. This instance object contains the reference and any per-instance data your items have (remaining charges, remaining item durability, temporary spell effects, etc.).

This has all kinds of advantages. First, you can easily create new item instances in the game with a simple "create item from <definition name>" command. Second, if you realize you need to tweak the values of some common item in the game world (like the every-popular longsword), you change the value in one place and all instances are updated. This can even happen in real time with OLC edits of the definition. You can also do things like run stats to see how many items of a particular definition exist, which may be useful if you want to check that some particular rare item hasn't inexplicably become not-rare. In the event that you need truly unique one-off items that you don't want to have to add a permanent item definition for, you can add support for "anonymous definitions." These would just be definition objects that have no name, are referenced by only a single object instance, and are saved to and loaded from that object instance's file.

I would also highly suggest you do the same thing for mobs, for all the same reasons.
09 Jan, 2010, Twisol wrote in the 4th comment:
Votes: 0
Man, this thread is totally getting bookmarked…
09 Jan, 2010, Barm wrote in the 5th comment:
Votes: 0
I got to thinking about this and realized it is (or nearly is) a discussion on ORMs.

Modern, object oriented languages have numerous libraries that provided Object Relational Mapping (or ORM). These are designed to abstract away the complexity and tedium of slogging out your own SQL and promise to work across multiple databases so you can switch without rewriting your code. There are two popular designs of ORMs – Active Records and Data Mappers. With Active Records, the objects you want persistence for are inherited from classes of the active record library with some extra meta data. The appeal is they serialize themselves; when you set employee.name = "Jack" some magic behind the scenes generates SQL equivalent to "UPDATE employees SET name = "Jack" WHERE id = '7842' and writes itself to the database. Data Mappers are a bit more complex. They help you create objects that know how to load, save, and update your program's objects instead of the objects saving themselves. Typically, Data Mappers expose extra functionality like creating objects from table joins.

Warning: opinion and coding religion ahead.

Active Records suck.

Unfortunately, it's hard to convey that the suck because when you first use them they seem kinda awesome and when people criticize them for being inflexible or having slower performance, well, that doesn't sound THAT bad to someone who skipped having to slog through a bunch of SQL. Novice programmers love them because they work fantastic for novice programs, but as your skills grow you'll find yourself stubbing your toes over and over again until you decide to dump them for something better and realize it's going to take major surgery to do so. I say this as someone who used active records for his web apps five years ago and thought they were kinda awesome and read the criticisms thinking, 'those don't sound THAT bad'.

So use Data Mappers, right? Well, they are better than Active Record but again, as your skills grows you're going to find yourself jumping through hoops trying to trick them into auto-generating the SQL you actually want. Personally, I recommend slogging the SQL. An ORM cannot create a "better" SQL statement than a competent programmer and they can very easily generate a worse one.

That was a whole bunch of words to preface a suggestion that your google "Active Record vs. Data Mapper", but I think you'll find discussions relevant to your project, even if you aren't using a relational database for storage. If you separate the saving and loading from the objects themselves it becomes a lot easier to make sweeping design changes. For example. I've been working with SQLite3 for my persistence but I'm considering changing to pickled Python dictionaries for the speed.
09 Jan, 2010, Sorressean wrote in the 6th comment:
Votes: 0
I think I got what your saying, and have an idea for implamentation. Still the question remains: How will I know what type of object it is? I guess I could do something like call Object::SetKeys() to set the base keys fror the object, then set the keys for the constructer, is this a valid solution? Also, I'm using c++ for this project; how might I go about doing the mapping? Is there another solution besides a union?

Thanks again for all the help, I really like the key-value pair idea, and is probably what I'm going to do. Then objects can just have a get and set method that is templated to return the type of info that it needs to.
09 Jan, 2010, Sorressean wrote in the 7th comment:
Votes: 0
I sort of understand what your saying–I like the dictionary idea. I'm not quite sure I got all the rest, but that I grabbed on to at least. This is my question, from your earlier post: using what you said with the dictionary, and getting the name and etc from the object template or whatever you'd like to call it that is used to clone all the deriving objects of that type off of, the name would be stored in memory, but not serialized. This means that I still need some way to say "load this object, and attach this dictionary file to it," no? Maybe I've got it all wrong, but that seems like what it's coming down to–how would you suggest this be done? How do you handle this in your own project?
09 Jan, 2010, Confuto wrote in the 8th comment:
Votes: 0
Sorressean said:
I sort of understand what your saying–I like the dictionary idea. I'm not quite sure I got all the rest, but that I grabbed on to at least. This is my question, from your earlier post: using what you said with the dictionary, and getting the name and etc from the object template or whatever you'd like to call it that is used to clone all the deriving objects of that type off of, the name would be stored in memory, but not serialized. This means that I still need some way to say "load this object, and attach this dictionary file to it," no? Maybe I've got it all wrong, but that seems like what it's coming down to–how would you suggest this be done? How do you handle this in your own project?

The prototype (or template) is a class that - when instantiated - creates an actual game object. The data that you're storing is anything that is unique to a particular instance of that class (i.e. durability). The dictionary is a collection of key/prototype pairs. When you load an item's data from disk, you use the stored key to locate the item's prototype in the dictionary and instantiate the item itself. You then call a load function (or something) on that instance and pass it any extra data that was stored. The instance loads that data appropriately (i.e. by calling a set_durability method on itself). The logical time to load an item (or a mobile, for that matter) is when its container is loaded. I.e. Player A logs in, their data is read off of the disk, each item in their inventory is instantiated and passed any extra data associated with it.

That's one way, at least. :biggrin:
09 Jan, 2010, Sorressean wrote in the 9th comment:
Votes: 0
I see what your saying, and that makes sense, but I don't think I was very clear. Lets say I have a class of type Object. All in-game objects will inherit from this. Next, I create two derivatives off of this: a container, and a weapon. When loading this back, how do I know if this is a container, or a weapon?
09 Jan, 2010, Confuto wrote in the 10th comment:
Votes: 0
Sorressean said:
I see what your saying, and that makes sense, but I don't think I was very clear. Lets say I have a class of type Object. All in-game objects will inherit from this. Next, I create two derivatives off of this: a container, and a weapon. When loading this back, how do I know if this is a container, or a weapon?

The container and weapon prototypes are given unique, persistent IDs. When the MUD is booted up, the prototype dictionary is constructed using these IDs as keys and the prototypes themselves as values. If you want to store an item's data then you also store its prototype ID. When you load that stored data back up, you use the ID to locate its prototype in the dictionary, instantiate the prototype and pass the rest of the data to the new instance to load.

I'm not sure how well that would work with coded classes. I was more assuming that your prototypes would be stored as XML or YAML flatfiles or something and then be loaded into memory at boot.

The way I'm approaching it is to have a Prototype class which is instantiated for each individual prototype (these instances are stored as flatfiles). When a particular method is called on the Prototype class, it uses its instance-specific data to create a new instance of a core game object (item, mobile, whatever it's been configured to do) and then returns that object.

EDIT: Just to elaborate - at boot, every single flatfile prototype is loaded into memory as an instance of the Prototype class. The Prototype class consists of a single create() method that reads its own data and then uses it to create a new game object. This data might include things like "type" (room, mob, item), "name", etc, etc. All the instances of the Prototype class are stored in a dictionary under their ID. To create a new game object based on a specific prototype, then, you only need to know its prototype's ID. You use that to get the prototype instance from the dictionary, then call the create() method on that prototype, passing it any extra data that was stored along with the prototype ID.

I don't feel that was very clear. Sorry >.<

EDIT: Using the approach described above, your container and weapon classes would in fact be prototype that are used to create a modified instance of the base object class. Re-reading your post, I get the feeling that I'm describing a somewhat different system than what you're after.
09 Jan, 2010, elanthis wrote in the 11th comment:
Votes: 0
Alas, Barm, you were so on the right track at first. ;)

Quote
I got to thinking about this and realized it is (or nearly is) a discussion on ORMs.


No, not it is not even remotely a discussion on ORMs, at least until you brought them up. An OODBMS is not the same thing as an ORM, an object persistence system is not the same thing as an OODBMS, and a simple mechanism to save and load the state of data in an object-oriented application is not the same thing as object-persistence.

An ORM is meant to solve a particular problem that the OP does not have and (if he is smart) never will have.

Quote
For example. I've been working with SQLite3 for my persistence but I'm considering changing to pickled Python dictionaries for the speed.


Bolded the part that scares me. Are you actually seeing ANY evidence at all that you are having performance problems? If yes, are you actually seeing ANY evidence at all that they are solely within SQLite3 and not other parts of your application or the way your application is (mis)using the SQLite3 API?

I ask for two reasons: first, SQLite3 is known for its speed. Second, if you're talking about a MUD, I can't imagine ANY storage choice you may have made to be a bottleneck in any noticeable way ever.

Quote
I see what your saying, and that makes sense, but I don't think I was very clear. Lets say I have a class of type Object. All in-game objects will inherit from this. Next, I create two derivatives off of this: a container, and a weapon. When loading this back, how do I know if this is a container, or a weapon?


First, don't do that. The thing with the separate weapon and container classes that inherit from Object. That's a bad, bad way to design a game engine. :)

Just in case you don't care about the rambling tangent I'm going to characteristically go off on, here's the simple answer to your question: your file needs to encode what type of object it represents, and when you load the file you need to read this and create and instance of the proper class. This is usually implemented using the "factory design pattern" (google is your friend).

So, back to why you shouldn't do what you said you were going to do. I cannot possibly explain the reasoning in enough detail and clarity in a mere forum posting, so I will give a condensed explanation, a better solution, and you (being the intrepid learning programming seeking the knowledge to better you craft and yourself) can google up more information. :)

You are designing a system based off of a class hierarchy. The problem with a design like you're suggesting is that, at some point, you end up wanting a game object that does both. Maybe you don't ever end up needing a weapon that is a container, but what about armor that is a container? Like, say, a cloak that you can put things into. I've seen a few games that do that, it's pretty cool. What if you end up with a Wand item type for casting spells, and then want a Staff item type that can be used like a Wand and also like a Weapon?

Every single moderately flexible or complete game engine that started off with class hierarchy has eventually ends up where much (if not all) of the behavior implemented into each of those derived class migrates its way into the base game class. Take the Unreal engine as a perfect example: every single bullet fired in a massive raging gunfight takes up 2K of memory just in the base game object. Each bullet has all kinds of information attached to it, such as weight (unused by the physics simulators for bullets), dimensions (again, unused), animation system information (unused), UI control information (unused), camera attachment information (unused), particle system data (unused), etc. The reason for that is that all of the bullet-specific behavior eventually was needed by someone at some point in something that wasn't a bullet. The bullet physics stuff has uses with things like laser lights and such, for example. So the bullet physics can't be just in bullet, it has to get moved up into the base game object. The player has a camera attached to it, and bullets don't need cameras… up until they do when someone decides that having a neat bullet-zoom slow-motion effect would be cool. Or until some other non-player object needs a camera, for various cinematic reasons. So the camera information gets moved up into the base game object. Games need a way to let players be AI controller when they get Charmed or Stunned or go link dead, so they can't limit the AI code to just the Enemy class, it has to get moved up into the base game object.

Not a single bit of that is an exaggeration – that is actually what has happened to the actual Unreal engine used today in many top-tier triple-A games. And it sucks, and I'm told that a lot of the developers that licensed Unreal have spend a large portion of them time hacking the hell out of it just get it into a sane and usable state.

Thankfully, there is a better alternative. It is slightly more complex to implement (in C/C++ at least) and ever so slightly more complex to understand by a beginner, but only then because programming isn't taught very well (and if you're self taught, you probably learned from tutorials and books written by people who didn't learn how to program very well but felt a need to share anyway… which was the same way I learned, and it took a lot of time and pain to relearn a lot of bad habits I picked up when I was a teen programmer, believe me).

The class hierarchy you are thinking of is what's called an "is-a" relationship. An Item is-a GameObject, and a Weapon is-a Item. Perfectly logical. Looks totally correct on paper. Pretty easy to code. Eventually falls prey to the Unreal effect (and to clarify, I ran into the same situation in my original AweMUD code years and years before Unreal was even a twinkle in Sweeney's eye, but back then people hadn't truly realized how bad the problem was and so there weren't papers and books and whole companies or schools that focus on the alternatives to deep class trees as a fundamental truth of good object-oriented programming).

And now for a tangent inside of a tangent. To really grok the the better solution, you have to think like a programmer. This is not easy for most people, at least not at first. Object-oriented programming in particular is touted as making programming so much easier because it lets programmers think about code using real-life metaphors. Weapons are items, after all, so why not model weapons as items in the code? Well, see, there's a different way to approach the problem in which you look at those real-life metaphors and then abstract away the core bits of what they mean and do instead of copying them directly into your architecture. Programmers need to think in terms of algorithms and architecture and abstractions (I might need to coin the "triple A programmer" term, hmm) and not in metaphors. Instead of thinking about what a weapon IS, think about what it DOES, and how it does it in the context of your simulation.

What i'm getting at is that you shouldn't think that a weapon is an item just because you can. A weapon is NOT an item. An item is just a collection of properties, and a weapon is collection of additional properties that an item can optionally have. Think about it. A weapon is not an item, but an item can have the properties of a weapon. Really think about that for a minute.

We have our is-a relationship that we can easily model with class inheritance. We have other relationships we can model, too. For example, we can easily model the has-a relationship. With a simple object-oriented language, this can be done using member variables that contain/reference other objects. (Some languages also can model it using multiple-inheritance; that's an entire different lengthy topic that I find far less interesting, so I'll just sum it up as "don't ever freaking do that.")

We can now think about how to better model our items and weapons and containers. Since a weapon is not an item, but an item can have the properties of a weapon, this can be easily modeled using a has-a relationship. You have your Item class (you don't even need that, honestly, since an Item is not a GameObject, but some GameObjects have the properties of Items… you see where that's going, right?) and it has a (has-a!) set of members that represent optional components, like the Weapon component, the Container component, the Armor component, the Consumable component, etc.

The cool part is that now you can compose all these components (that's why they're called components!) any way you want. Maybe you never-ever need a sword that is also a bag, but you might very well want a magic staff with charges for spells, which you can get with a game object that has the Weapon component and the Consumable component (going with the D&D-definition of consumables here, where it includes any limited-use item). Otherwise, you'd end up with your old-skool class hierarchy, scratching your head wondering how you are going to get the behaviour from your Weapon class and your Consumable class merged together, and either end up with a new cut-n-paste-together ConsumableWeapon class or just moving all that code up into Item (or Object) and making the entire purpose of having the sub-classes pretty much moot.

Of course, there are some things that all items have in common. If you decide to have an Item subclass of Object, that's where you put it. If you are thinking about going with a full object composition system where you don't have sub-classes of Object, then worry not, for there is a simple and obvious solution: just have an Item component. Any generic behavior and data that all items have lives in ComponentItem. If the weapon component has some kind of actual dependency on that data (say, all items have durability, and the weapon component needs to know its current durability level to calculate damage), that's perfectly fine. Don't add unnecessary dependencies and try to avoid them when you can, but have no fear of them where the dependency makes sense.

You may even go so far as to put no data at all in Object besides the components, and have a component for the basic stuff all game objects have (like a name and description). In 3D games using object composition it's common for there to be a transform component that handles the position and orientation of the game object in world space. I'm personally luke-warm on the idea; if you want to go that way, that's fine and there's no real reason not to, but on the other hand I see no reason not to put data you KNOW every object will always have (by definition of it existing at all) inside the base Object class.

In case you're wondering, yes, components are a different beast than what Unreal does. Unreal is not componentized. Every single game object has all of the code and data for a bunch of features stuffed into the base object. While the base object is a composition of a bunch of functionality, as a design pattern it's more of a swiss-army-knife than object composition. When talking about object composition, we are generally assuming that you have the ability to very easily add and remove components, possibly even at runtime, and that an object that doesn't need a particular component isn't forced to have it anyway.

In C++, a very simplistic implementation of static composition may look something like:

class ComponentItem;
class ComponentWeapon;
class ComponentConsumable;
class ComponentArmor;

class Object {
public:
// all the generic object code

// component lookup
virtual ComponentItem* GetComponentItem() { return NULL; }
virtual ComponentWeapon* GetComponentWeapon() { return NULL; }
virtual ComponentConsumable* GetComponentConsumable() { return NULL; }
virtual ComponentArmor* GetComponentArmor() { return NULL; }
};

// static weapon class – there would barely be any more to it in real code,
// and that little extra would just be pure boilerplate
class ObjectWeapon : public Object {
public:
virtual ComponentItem* GetComponentItem() { return &mCmpItem; }
virtual ComponentWeapon* GetComponentWeapon() { return &mCmpWeapon; }

private:
ComponentItem mCmpItem;
ComponentWeapon mCmpWeapon;
};


So if you need a weapon, you ask the object factory to construct a new ObjectWeapon and you get back an Object pointer. You don't even need to cast it; you just get the pointer to the weapon component with GetComponentWeapon and do what you need to. That's it.

Dynamic composition is barely more complex. If you don't mind, you can just keep a bunch of pointers in the Object class to each possible component object, and allocate only the components you need and hook up the pointers. Gets rid of the need for the sub-classes entirely, which is handy. With a tiny bit of low-level work overloading operator new, you can even do it without having to allocate multiple chunks of memory for all the components.

In a language like Python, it's actually easier to do dynamic composition than static composition, since Python makes all objects stored by reference. You just store your component objects in a dictionary on the game object and look them up by name. Tada.

As with all things in life, object composition is not "right" and inheritance is not "wrong." I've unfortunately seen a few too many game programmers go "omg composition I <3 you so much" and get all frothy-mouthed if you say you want to use a flat hierarchy of game objects. There are plenty of times when inheritance is entirely the right tool for the job.

A hierarchy or tree of types is entirely what you want when you are in fact modelling certain kinds of real-world data… but modelling data and modelling code are different, if for no other reason than because code is supposed to be written by programmers who understand architecture and algorithms and basic problem solving while data is often from the kind of people who think OOP is the best thing programmers ever made (beside Al Gore's Internet) because it lets them model real-world objects in real-world ways in code. ;)

So, code-wise, same solution as I gave up at the top. Your files that you save your objects/definitions in just have a list of components, and the data for each component. You then, instead of (or in addition to) a game object factory, you have a component factory. Instead of the file saying "I'm a weapon" (is-a) it says "I have the weapon component" (has-a) and your loader code constructs the new game object and a new weapon component object and hooks 'em up and there you go.
09 Jan, 2010, David Haley wrote in the 12th comment:
Votes: 0
elanthis said:
but back then people hadn't truly realized how bad the problem was and so there weren't papers and books and whole companies or schools that focus on the alternatives to deep class trees as a fundamental truth of good object-oriented programming

As additional reference along these lines, I would highly recommend the book Design Patterns by the so-called "Gang of Four". They cover this issue in more depth with more examples and code. They tend to use GUIs as examples, explaining the perils of having a Window, from which you subclass a TextWindow, from which you subclass a ScrollableTextWindow, but then if you have a PictureWindow and want it to scroll you need ScrollablePictureWindows etc.

The Is-A model is not that bad, but it's too easy for people to think that every relation is a, err, is-a. Elanthis's point is that you should strongly differentiate between "is" and "behaves like". Some things truly are other things in a very strong sense of the term with very little reason for cross-over of class trees. For example, a List can be subclassed as a linked list or an array list: you would never join these two classes together somehow, and you choose one or the other for implementation/performance reasons. Things like objects vs. weapons vs. armor aren't really the same: a "weapon" is not capturing the fundamental essence of an object inherently different from the fundamental essence of a "container": as Elanthis said these are behaviors or aspects of objects, that are certainly not mutually exclusive or otherwise incompatible.

To be honest I think it helps to think about things from an almost philosophical perspective ("thinking like a programmer" means this more than people realize, IMO). When designing complex object frameworks you need to think about whether you are capturing essence behavior, or maybe even just implementation details. What is the "essence" of a weapon? What are its fundamental properties? When does an item stop being a generic item and start being a weapon? When does an item stop being a weapon and start being a container? (Is that last question even relevant, for is there actually a spectrum of discrete categories?)

This thought process is relevant to you because in order to understand how you persist your stuff in a generic manner, you need to understand how you're modeling that stuff in the first place.

Prototypes get even more interesting because you are in a sense implementing your own "class framework" inside another language's class framework. I think we've had this discussion on MB somewhere before, but there's really no reason for your "prototype class hierarchy" to map one-to-one onto the language's class hierarchy. Anyhow, enough for now…
09 Jan, 2010, Cratylus wrote in the 13th comment:
Votes: 0
blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah
09 Jan, 2010, Barm wrote in the 14th comment:
Votes: 0
elanthis said:
No, not it is not even remotely a discussion on ORMs, at least until you brought them up. An OODBMS is not the same thing as an ORM, an object persistence system is not the same thing as an OODBMS, and a simple mechanism to save and load the state of data in an object-oriented application is not the same thing as object-persistence.


I think you missed where I was going. Directly serializing objects is very much like using Active Records and carries many of the same drawbacks. The objects become inflexible to change without having to convert your stored data. You have less control over the load/saving stages – for example, you might want to do something entirely different when loading a player with -20 hitpoints. You may even find yourself forced to instance objects just to gather stats, like the number of gnome clerics.

These are the same "tightly vs. loosely coupled" arguments you'll find in ORM discussions.


Quote
Are you actually seeing ANY evidence at all that you are having performance problems? If yes, are you actually seeing ANY evidence at all that they are solely within SQLite3 and not other parts of your application or the way your application is (mis)using the SQLite3 API?

I ask for two reasons: first, SQLite3 is known for its speed. Second, if you're talking about a MUD, I can't imagine ANY storage choice you may have made to be a bottleneck in any noticeable way ever.


I adore SQLite – it's concetrated awesome and I would never suggest that I could write a faster database, but as my project progresses I find myself working with key-value sets more and more. After obtaining the user's UUID at login, I may not need to do any more searches, only retrievals. There is no chance that SQLite (using file based storage) can beat the speed of directly retrieving a binary cPickle'd dictionary. I can further reduce disk IO by using gzip files (if the object size makes it worth it). Python's 'marshal' is even faster but it's not guaranteed to work across versions – which didn't keep the authors of Gadfly from using it but I'm a scaredy cat.

You're right though, SQLite is very fast and MUD data needs are very shallow. Like I said, I'm considering changing. One of my design goals is to operate under a single thread which means data IO blocks. I think we'd both agree that even with a modest PC we're talking less than a millisecond per activity and I can probably support several hundred players without breaking a sweat.

Pickling is my plan B if that proves to be wrong.
09 Jan, 2010, KaVir wrote in the 15th comment:
Votes: 0
elanthis said:
As with all things in life, object composition is not "right" and inheritance is not "wrong." I've unfortunately seen a few too many game programmers go "omg composition I <3 you so much" and get all frothy-mouthed if you say you want to use a flat hierarchy of game objects. There are plenty of times when inheritance is entirely the right tool for the job.

Agreed - it's important to consider the problem before deciding on the tool for the job.

Of course this is easier said than done for a mud, as it'll probably evolve over time, rather than having a clear finishing point like most software projects. Personally I ended up using a mixture of inheritance and composition, and it works fairly well, but it's still given me a few headaches as the game has expanded over the years.

At the end of the day though, my goal is to create a fun game, not a perfect example of software engineering. As long as the code remains readable and maintainable, and does what I want without too much fuss, I don't mind cutting a few corners here and there.
09 Jan, 2010, Sorressean wrote in the 16th comment:
Votes: 0
For some reason, I haven't managed to get this thing to quote posts, so thanks to all who provided information–and thanks, Elanthis for taking the time to explain that; I understand what your saying, and it makes a lot of sense to set it up the way you described (with the components), and etc. Storing these should be easy as well–I can call serialize and deserialize on the components to flatten their contents into dictionariess, which makes things a bit easier than trying to trace back through inheritance and serialize that way.
09 Jan, 2010, Runter wrote in the 17th comment:
Votes: 0
Just make a post with more than 100 or so words. Fun always ensues.

I think it's because there's just something in there for everyone.

Or maybe because tldr.
09 Jan, 2010, kiasyn wrote in the 18th comment:
Votes: 0
Cratylus said:
blah blah blah blah blah blah blah blah blah


This isn't justrage, don't do that here.
09 Jan, 2010, Scandum wrote in the 19th comment:
Votes: 0
What worked for me is using a unique identifier (aka vnum) to load a template, followed by a list of key-value pairs (if any) to set custom data, mostly just the wear location and a unique object identifier.
09 Jan, 2010, Twisol wrote in the 20th comment:
Votes: 0
:stare: First events (in the other thread) and now inheritance/composition, it's like you're reading my mind. I'll be referring to this (particularly elanthis' post) for quite a while…
0.0/36