@kamac cheers!
I'm not sure if anyone's interested in technical details, but I'll write a few more words on the design just in case. I mocked up some of this design in code the last couple of days.
Every character, item, weapon, effect, gui element, etc., in moonman is an
Entity. An Entity is composed of
Attributes and
Properties. Attributes are key-value pairs which specify the shared data of an entity, and the sum of properties in an entity specify its capabilities. For instance, an npc in the game might be created as follows:
// script
npc = create_entity {x=0,y=0,vx=0,vy=0,onground=false,sprite="someguy.png"}
npc:add_property(physics)
npc:add_property(walker)
npc:add_property(renderable)
npc:add_property(ai_controller)
Each property has an
update and
onMessage function, and has access to the shared data in an entity. e.g.,
// c++
class PhysicsProperty {
public:
virtual void update(Entity* e, double dt){
e->attrib(x) += e->attrib(vx)*dt
// ...
}
}
The attributes are accessible by all the properties because there is commonality between them (e.g., the Renderable property needs the x and y coordinates to draw the npc in the right location.) This simplifies things, at the cost of being easier to shoot yourself in the foot (so as rule of thumb:
each attribute should be modified by only one property).
An attribute in my engine is implemented as a boost::variant:
typedef boost::variant<bool,int32,float,std::string> Attribute;
Each attribute and property is assigned a unique integer id. This is for efficiency reasons (an integer lookup is quicker than a string lookup and an integer is smaller than a string). However, because users can add new attributes and properties, the assigning of ids is done dynamically. E.g., a user can add a new entity attribute of type float, with a default value of 1.5., by writing
// lua
id1 = register_attribute_float("foo",1.5)
The registry returns an attribute id that the script can store (for this instance) to refer to the attribute, e.g.,
// lua
some_entity.attrib(id1) = .5
... although I'm investigating Lua meta-tables to see if I can allow the much simpler...
some_entity.foo = .5
In regard to the multiplayer aspect the server and client may be running different scripts/mods (or have them loaded in different order), which means that the attribute id's may be different. Hence, the client needs to store an mapping between the servers ids and the clients ids. This can be done fairly efficiently just by recording which blocks of ids belong to which mods. Saving a game world to disk is also simplified using a global id system.
I've never built a game this way, I typically just hard hard-coded all the classes into some inheritance hierarchy, so I find it very interesting to build types dynamically. It seemed to work for Dungeon Siege, Neverwinter Nights, etc, but I'm just a lone coder .. so we'll see whether I'm consumed by the extra work required or not!