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:

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:

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.

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++):

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.

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).

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.

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.

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.

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?

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.

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.