Property lists

 
Post new topic   Reply to topic    mudlab.org Forum Index -> Coding
View previous topic :: View next topic  
Author Message
Yui Unifex
Site Admin


Joined: 11 May 2005
Posts: 47
Location: Florida

PostPosted: Sat May 14, 2005 6:31 pm    Post subject: Property lists Reply with quote

Something I've found extremely useful in developing a codebase is the concept of the property list. Traditionally, if you wanted to store character information such as the number of hit points, you would embed a variable in a hard datastructure which could be referenced directly. While this is a perfectly viable approach, it creates work because these values aren't immediately accessible from scripts, the database serializer, builder applications, and inherited templates.

Property lists do away with these problems by storing all of this data as a list of name/value pairs. A standard get/set interface is provided which can manipulate these values, along with an accessor for retrieving the entire list. I would also recommend setting up alias methods so that you avoid typobugs and casting errors. For example, the player name accessors could be defined as follows:

Code:
string Player::GetName () const {  return GetString("name"); }
string Player::SetName (string newName) { Set("name", newName); }


This is certainly less efficient for most scenarios than the hardcoded value approach, but it can often make up for this when coupled with a data inheritance scheme. In fact, data inheritance becomes a snap with a few lines of code:

Code:
string Player::GetString (string propName) {
   if (_template != null) {
      string value = _template->GetString(propName);
      if (!value.empty())
         return value;
   }

   return _props.GetString(propName);
}

void Player::SetString (string propName, string propValue) {
   _props.SetString(propName, propValue);
}


Data inheritance is a large topic in its own right, so I'll discuss that in another thread later.

If you decide to go with the property list approach, I think it's advantageous to make a distinction between a set of flat properties that you can count on existing, and a list of dynamic properties. A dynamic property is any transient property -- usually used by a script -- that does not need to exist for the normal functioning of the player within the world. These can be used to track scores in minigames, store the player's title, or store configuration settings that override game defaults. In my codebases, flat properties are stored as columns in the database just like a hardcoded variable would be.

A major advantage of property lists is their use in scripts. Instead of worrying if a permanent storage location for a variable exists on a player, the script simply sets a property and forgets about it. If the engine's event system is powerful enough, one could code their entire game entirely with dynamic properties used by scripts. Properties accessible from scripts are not without problems, however: A rogue script could define a number of properties that are for essentially permanent. A method for expiring properties which have been set dynamically is certainly important.

Property expiration is also useful for effects which only last for some amount of time. Let's say you've scripted a command called 'blink' which allows you to teleport some distance from your current location, but you don't want the command to be spammed for travel. The command could set a cooldown property which expires in 10 seconds, and it would check this property before allowing the teleportation to occur.

In summary, property lists are a powerful way to simplify your systems and extend their flexibility immensely.
Back to top
View user's profile Send private message Send e-mail Visit poster's website AIM Address
Author Message
eiz



Joined: 11 May 2005
Posts: 152
Location: Florida

PostPosted: Sat May 14, 2005 8:11 pm    Post subject: Reply with quote

There's a very simple optimization you can make to this system which will drastically (2-3x at least) improve its performance, which is to use shared strings instead of normal strings. This will allow you to use pointer comparisons for lookups. Basically, it looks like this (in C++):

Code:

class symbol {
public:
    static const symbol *intern(const string &s) {
        symbol_table::iterator i = _symtab.find(s);
        if (i == _symtab.end()) {
            symbol *sym = new symbol(s);
            _symtab[s] = sym;
            return sym;
        } else {
            return (*i).second;
        }
    }

    const string &name() const {
        return _name;
    }
private:
    string _name;
    typedef map<string, symbol *> symbol_table;
    static symbol_table _symtab;

    // symbols should always be created with intern
    symbol(const string &name): _name(name) {}
    symbol(const symbol& s) {} // prevent copying
};

symbol::symbol_table symbol::_symtab;


Then you can pre-declare all of the symbols that are statically known in your code:

Code:

const symbol *x = symbol::intern("x");
const symbol *y = symbol::intern("y");


And a property map now looks like this:

Code:

map<const symbol *, value_type> properties;
Back to top
View user's profile Send private message Visit poster's website
Author Message
raz



Joined: 13 May 2005
Posts: 11

PostPosted: Sat May 14, 2005 10:34 pm    Post subject: Re: Property lists Reply with quote

As an add-on for those interested in using unifex's idea with C++, I would also suggest looking at the Boost Any library (http://www.boost.org). Using a boost::any type as the key part would give you great flexibility and power in your property code. There will most likely be some trade-offs, but I don't think it would be too much of a hinderance.
Back to top
View user's profile Send private message MSN Messenger
Author Message
eiz



Joined: 11 May 2005
Posts: 152
Location: Florida

PostPosted: Sat May 14, 2005 10:43 pm    Post subject: Re: Property lists Reply with quote

raz wrote:
As an add-on for those interested in using unifex's idea with C++, I would also suggest looking at the Boost Any library (http://www.boost.org). Using a boost::any type as the key part would give you great flexibility and power in your property code. There will most likely be some trade-offs, but I don't think it would be too much of a hinderance.


Do you mean as the value part? I don't really see much of an advantage in using it for the keys (as it would just slow lookups down even more), but boost::any would let you store more than one kind of value without building a whole class hierarchy of wrapper objects around them (which is incidentally what we did).
Back to top
View user's profile Send private message Visit poster's website
Author Message
raz



Joined: 13 May 2005
Posts: 11

PostPosted: Sat May 14, 2005 10:57 pm    Post subject: Re: Property lists Reply with quote

eiz wrote:
Do you mean as the value part? I don't really see much of an advantage in using it for the keys (as it would just slow lookups down even more), but boost::any would let you store more than one kind of value without building a whole class hierarchy of wrapper objects around them (which is incidentally what we did).


Yep. Definately meant the value part. Which is odd since I was even thinking "value" rather than "key" when I wrote that...

Oh well. "Mistkaes" happen. Wink

As a side note, it might be an interesting use boost::any for a key. It might allow a script to have more control over its own properties so other scripts don't try to tamper with them. Essentially, it would act as a "namespace" for keys. But I would begin to wonder if that would be worth the cost.
Back to top
View user's profile Send private message MSN Messenger
Author Message
eiz



Joined: 11 May 2005
Posts: 152
Location: Florida

PostPosted: Sat May 14, 2005 11:09 pm    Post subject: Re: Property lists Reply with quote

raz wrote:

As a side note, it might be an interesting use boost::any for a key. It might allow a script to have more control over its own properties so other scripts don't try to tamper with them. Essentially, it would act as a "namespace" for keys. But I would begin to wonder if that would be worth the cost.


Hmm. Well if you're using a symbol object like the one I posted, it's not difficult at all to add namespace separation for that, which I suppose is another advantage of not using raw strings for your keys. Actually, is boost::any even less-than comparable or hashable? Can they be used as keys? I don't think I've ever actually tried it...

Currently we've just been using naming conventions to ensure that scripts don't step on each other. It's not ideal, I know, but it does work out alright with a tiny bit of care.
Back to top
View user's profile Send private message Visit poster's website
Author Message
raz



Joined: 13 May 2005
Posts: 11

PostPosted: Sun May 15, 2005 3:31 am    Post subject: Re: Property lists Reply with quote

eiz wrote:
Actually, is boost::any even less-than comparable or hashable? Can they be used as keys? I don't think I've ever actually tried it...


That's part of the problem. There is no given less-than operator. You'll need to devise a system yourself, which is a pain. It can be done, but it isn't pretty.
Back to top
View user's profile Send private message MSN Messenger
Author Message
angelbob



Joined: 23 Aug 2005
Posts: 4
Location: Fremont, CA

PostPosted: Tue Aug 23, 2005 2:33 pm    Post subject: Reply with quote

Phantasmal has these, but calls them 'tags' rather than 'properties'. I use DGD, which gives me dynamic typing (like the boost::any class) automatically, as well as shared strings.
Back to top
View user's profile Send private message Visit poster's website
Author Message
Yui Unifex
Site Admin


Joined: 11 May 2005
Posts: 47
Location: Florida

PostPosted: Tue Aug 23, 2005 2:56 pm    Post subject: Re: Property lists Reply with quote

raz wrote:
As a side note, it might be an interesting use boost::any for a key. It might allow a script to have more control over its own properties so other scripts don't try to tamper with them. Essentially, it would act as a "namespace" for keys. But I would begin to wonder if that would be worth the cost.

I tend to use conventions instead of hard rules for my property names. The standard properties (e.g., name, hp, description, etc.) are all global, while non-standard ad hoc properties should have a prefix denoting the property origin. So if BakerBob in Midgaard area had set an indicator when he had some bread in the oven, it might be named Midgaard.BakerBob.BakingBread.

It certainly might be a good idea to codify the convention in some way, but you walk a fine line between ease of use and safety.

angelbob wrote:
Phantasmal has these, but calls them 'tags' rather than 'properties'.

Are there any details of Phantasmals implementations not already discussed here? How often are they used?
Back to top
View user's profile Send private message Send e-mail Visit poster's website AIM Address
Author Message
Kaz



Joined: 05 Jun 2005
Posts: 24
Location: Hampshire, UK

PostPosted: Tue Aug 23, 2005 6:46 pm    Post subject: Reply with quote

My Vision codebase (in development) has a (Pascal-ish) scripting language attached to it, and properties play a large part in it. There are only three types to the language: Number, String and Object. Objects can have arbitrary properties of any of those types, and can be created and destroyed at will:

Code:

# A function called "enchant" takes three arguments: player, item
# and spell, all of which are type object.  The function does not
# return any values.
function enchant(player, item, spell : object) returns none is
    # This checks for the presence of the object property
    # called "enchantment" on item.
    if item.enchantment
        # Send a message to the player that this is already enchanted.
        _msg(player, "That item is already enchanted.")
    else
        # Spontaneously create an object property called "enchantment"
        # on the item, and assign it the value of the parameter "spell".
        item.enchantment = spell
    endif
end


In compiled code, objects simply have three linked lists (I plan to change this to binary trees, but other things have priority for now), one for each type. Since each of the types evaluates to a number -- for Strings and Objects, which are reference-counted entities, it's simply their address in the runtime environment --, this is a very simple structure to maintain.
Back to top
View user's profile Send private message
Author Message
angelbob



Joined: 23 Aug 2005
Posts: 4
Location: Fremont, CA

PostPosted: Wed Aug 24, 2005 6:24 pm    Post subject: Re: Property lists Reply with quote

Yui Unifex wrote:

Are there any details of Phantasmals implementations not already discussed here? How often are they used?


The primary thing that Phantasmal has that isn't discussed here is data inheritance. Phantasmal has parent objects, and any object which has a field unset will inherit the value from the parent. There are a couple of other forms of inheritance planned, which will allow me to start turning other characteristics of the objects (like, say, their container capacity) into tags. Tags can be marked as inheritable, and an inheritable tag, if not set on an object, will return the value of the parent's tag, if the parent has the same tag set.

Tags aren't used much yet. They're a fairly new addition to Phantasmal, and were originally for scripting, to allow scripts to store data in the object.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    mudlab.org Forum Index -> Coding All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2001, 2002 phpBB Group
BBTech Template by © 2003-04 MDesign