# Data storage for a MUD

This topic is 3628 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I've been working on my own next generation MUD server for years, but I've finally gotten down to brass tacks and want to complete it. The issue I am running in to now is data storage. I am definitely going to use an RDBMS back end, but how do you make it extensible? I can release the MUD server with a sane default data storage setup, but what if the new MUD administrator wants to add new properties to his Player object? I don't want them to have to update the database tables to reflect this. So I came up with the idea of making the data store a bit more property driven. For instance, rather than storing Player to a Player table, I store it to a Thing table, which has a bunch of foreign key references to a ThingProperty table, which stores free form properties for the object. Two issues I worry about with this: What is the definer of the object "base class", so to speak? Do I simply use reflection to basically serialize the object to the data store? Do I use .NET attributes to determine what properties of an object are actually persisted? Do I store something like a "ThingClass" in the database, that determines exactly what properties of every object type should be saved? Currently I am going down path C, defining every object "class" in the database, using a tool I call my MUD Schema Editor. Part of that editor is the ability to create the partial C# class stubs for those object types (honoring the hierarchy the MUD administrator decides on). Does this make sense? Is it over engineering? Is performance going to be an issue? Obviously the ThingProperties table could get huge, as it will contain a row, for every property, of every object, in the MUD world. Also, there has to be a differentiation between a blueprint of an object and the instances that have been created of the object. The instances need to also be persist-able, raising the number of rows that table could have even higher. In the "old world" of MUD servers, you really had two ways to define things: The DIKU way, which were this space delimited text files, that changing the format or storing a new property was very painful. And the LPC way, where every entity in the MUD world was a complete code object that was loaded at runtime (and probably sub classed from a system object, like /Sys/Lib/Mobile). Some projects like ColdC have come along, and what I am trying to achieve is sort of a hybrid. I want my data definition separate from code (so not LPC style), but I want my data store to be flexible to the world the MUD builder wants to make (not DIKU style), without a ton of code changes. I guess I'm not really asking a question, so much as looking for validation of my ideas (or invalidation of them, which serves my purposes just as well at this point).

##### Share on other sites
Can't you just mark properties that you don't want to save, such as with the NonSerialized attribute? Or you can even just write your own attribute for each property that allows you to specify the database field name (or just get it from the property name) and only save/load properties with this attribute.

##### Share on other sites
The problem with storing each property as a separate row in a "properties" table is that the index for properties becomes very big, which slows down all queries. Also, databases don't like the 18-way self-joins you get when you do things like

select prop1.value as int, prop2.value as dex, prop3.value as cha, ...   from property prop1, property prop2, property prop3, ...   where prop1.object = id and prop1.name = 'int' and prop2.object = id   and prop2.name = 'dex' and ...;

If you want to go that way, I would suggest creating a new table for extension properties. Store all the common properties in the "player" database, and if another admin wants to add the properties "foo" and "bar," he creates a new table "player_foo_bar" with player id, foo and bar columns. You can create triggers that make sure player_foo_bar gets created and deleted in sync with the general player table. This will perform somewhat better.

Another option is to store all properties you want to index on in the table, but store all other properties as a serialized blob. That will make it easy to add new properties, as long as you don't want to index them.

[Edited by - hplus0603 on July 11, 2008 12:01:24 AM]

##### Share on other sites
One of my major rules is that I want properties to be easy to add, without needing to update the database or change it's schema.

The issue with defining the common properties, as you suggest (which, btw, was my first choice), is ...what are the common properties? There are a few, Name, ShortDescription, LongDescription, Id...but, in the example of a Player object, if I make Strength a common property...what if a MUD admin doesn't want his players to have a Strength attribute? Maybe he is creating a new kind of MUD entirely. So when you boil it down, you end up with five or six common properties, and still a whole lot that need to be free form.

As a side note, I would never do an 18 way join like that.

I would simply do:

SELECT * FROM ThingProperty WHERE ThingProperty.ThingId = <ThingId>

I can use reflection to map properties at runtime. I also don't really need to index on any of these properties, as you won't be searching through the database much, it will mostly be pure load/save operations.

The other thought I had was to store all the extra properties in a blob column in the Thing table, as you suggest. It would probably be an XML document, but may be a binary serialize I suppose.

##### Share on other sites
So you want to be able to add more information to the database without adding more fields? Or do you want to be able to add properties to characters but not require the database to contain a field for the property? If the latter, you use a "SELECT * FROM ... WHERE 0=1" to grab all the fields in the database. You can then use reflection to find what properties contain a field in the database. You can also use the gathered information to find out what properties need to save to the database. I use this technique for my game right now for the stats, though I also add an attribute to the stats that states if it is contained in the database to force an error if the field does not exist just since I know I'll forget to add the field sometimes.

You can also use reflection to find the properties and check if all the fields needed exist in the database, then create them if they don't. To prevent every property being in the database, you can use attributes to explicitly mark the properties that will be stored in the database.

If you don't want the database's schema to be modified at all, then my guess is that you will have to use blobs like you mentioned. Though you'll lose a lot of the user-friendly attributes that structured databases offer.

##### Share on other sites
Quote:
 what if a MUD admin doesn't want his players to have a Strength attribute?

So you're really building a MUD creation platform, not a MUD itself?

In that case, you could just as well have a way where the admin describes the properties, and you generate schema for the database. When building a new version with new properties, the toolkit would see that the table doesn't match the new schema, and do the appropriate ALTER TABLE. To the user, he doesn't see that the database schema changes; he just adds/removes attributes to object class descriptions.

##### Share on other sites
I'd agree with that: have the database schema reflect the logical schema, don't try to implement some sort of meta-schema that leaves your DB looking completely abstract and meaningless and forces you to implement all your joins at the code level.

##### Share on other sites
Actually, that's a great idea. I think I will go with that. The schema editor will simply edit the database schema to match the property definitions.

And yes, I am creating a MUD creation platform, that I will then use to create a MUD ;)

##### Share on other sites
You might consider dividing your schema into tables that you can't modify (so that your code can make assumptions about their existence) and tables you can't (which users can use for customisation). One-to-one joins can bridge the gap where needed.

1. 1
2. 2
3. 3
4. 4
Rutin
16
5. 5

• 12
• 9
• 12
• 37
• 12
• ### Forum Statistics

• Total Topics
631419
• Total Posts
2999981
×