Programming and other useless stuff

Wednesday, August 13, 2008

Stressful life...

Gosh... sometimes life can be stressful :) My cousin, who will be my witness (is it called like this?) at my marriage, had some problems with the date. In fact on august 23rd (a saturday) he should have a university exam. Today was the last day I had to confirm the witnesses of my marriage to the major of our town. So... I started asking friends to replace my cousin. Finally, an hour before desk closure at the major hall, my cousin called me to confirm his presence. He managed to move the exam by one week (there are several of those exams and he was pushed into another group). But I can tell you that I had some sleepless nights because of this :)

Phew... back to work. I had some problems concentrating today (missing sleep) and only managed to get some work done in the afternoon. I've been taking a step back from my source code and the overall layout of the Logic implementation. I'm pleased with most of it. Those who carefully ( :) ) read my blog know that I wasn't pleased with the template stuff in the EntityManager. Also, I didn't like the idea of having the components and entities that might be created by a simple new anywhere in the code. I finally decided to use factories for template, entity and component creation.

The factory approach also allowed me to reconsider the create functions for the templates. Remember that I had 2 different create functions? One for the entity template and one for the component template. The factory approach led me to the conclusion that only one function is needed for both. Basically I kept the create function for the entity template which uses a type and a name string. Component templates do have those two strings, too, since they're derived from the template class. Component templates just set the type string into the name string (Currently I think that component templates don't have to be named).

Ok... now I have 2 factories: the template factory and the component factory:

typedef Template* (*templateCreator)(Sidema::String _name);

class TemplateFactory : public Sidema::Singleton
{
public:
// ----------------------------
// Template management.
void registerTemplate( const Sidema::String &_type, templateCreator _func);
void unregisterTemplate( const Sidema::String &_type );
void clearAllTemplates();

Template* createTemplate(const Sidema::String &_type, const Sidema::String &_name );

protected:
// ----------------------------
// Xtructors.
TemplateFactory();
~TemplateFactory();

private:
friend class Sidema::Singleton;

typedef std::map TEMPLATECREATORS;
TEMPLATECREATORS m_templateCreateFunctions;
};

typedef Component* (*componentCreator)(ComponentTemplate *_template);

class ComponentFactory : public Sidema::Singleton
{
public:
// ----------------------------
// Component creator management.
void registerComponent( const Sidema::String &_type, componentCreator _func);
void unregisterComponent( const Sidema::String &_type );
void clearAllComponents();

Component* createComponent(const Sidema::String &_type, ComponentTemplate *_template);

protected:
// ----------------------------
// Xtructors.
ComponentFactory();
~ComponentFactory();

private:
friend class Sidema::Singleton;

typedef std::map COMPONENTCREATORS;
COMPONENTCREATORS m_componentCreateFunctions;
};


The fact that I didn't like the management of the templates within the entity manager led me to implement a template manager. There wasn't much to do since I only had to move some functions from the entity manager to the template manager.

class TemplateManager : public Sidema::Singleton
{
public:
// ----------------------------
// Template management.
bool loadTemplates(Sidema::String _filename);
void unloadTemplates();
EntityTemplate *getTemplate(Sidema::String _name);

protected:
// ----------------------------
// Xtructors.
TemplateManager();
~TemplateManager();

// ----------------------------
// Template management.
bool addTemplate(const Sidema::String &_name, Template *_template);
void removeTemplate(const Sidema::String &_name);
void releaseAllTemplates();

private:
friend class Sidema::Singleton;

typedef std::map TEMPLATEMAP;
TEMPLATEMAP m_templates;
};


As you can see, the template manager returns a pointer to a entity template. The component templates aren't stored in the template manager. In fact, since the component templates are stored within the enitity template (remember: each component template is unique to the entity template it belongs to), there was no need to do so. I could have simply returned a pointer to a template instance, but this would lead to confusion about the basic type of the template. One could think that it might be a component template he just got...

With all this information (in this blog entry and the previous one), I've implemented a translator for the health component. There's only a constructor, a destructor and the create function of the translator (I'm think of renaming the create function to translate or something else because I normally use create to name static functions which create an instance of that very class; nevertheless, the function really creates something: the translated object).

class HealthTemplateTranslator : public ComponentTemplateTranslator
{
public:
HealthTemplateTranslator() {}
~HealthTemplateTranslator() {}

virtual Component *create(ComponentTemplate *_template) const;
};

Component*
HealthTemplateTranslator::create(ComponentTemplate *_template) const
{
HealthComponent *component = NULL;

// Check for valid template.
if ( _template && !_template->getType().compare(HealthComponentTemplate::TEMPLATE_NAME) )
{
// Get the health and create the component.
float maxHealth = 0.0f;
if ( static_cast(_template)->getMaxHealth( maxHealth ) )
{
component = static_cast(ComponentFactory::Instance().createComponent(HealthComponent::COMPONENT_NAME, _template));
if ( component )
{
// Set the health values.
// Note: The current health should be set to the maximum health
// to have at least living entities, when they startup :)
component->setMaxHealth(maxHealth);
component->setCurrentHealth(maxHealth);
}
}
}

return component;
}


Et voila... the returned component is a translated instance of the health component, filled with the data of the health component template.

The next step is to create an entity from an entity template. While this might sound strange, I still have some problems to pinpoint the differences between a static and a dynamic object. Every difference I can think of can be implemented by components... is it possible that I don't need different specializations of entities?!?

Have fun,
Stefan

PS: I once again changed a little bit the css of the blog... I still got comments that the font was a) too bright and b) the letters were not far apart enough... Fixed this with another font :)

Labels: , , ,

Tuesday, August 12, 2008

Style change and template stuff

Hi,

I had some people tell me that the old style in this blog had some tiny font settings. So I increased it a little bit and cleared up the font colors to actually make it more readable. I hope you have a better reading experience now... Please make a comment if you have any suggestion for improvement.

Well... that said, let's dig into some code :) As I mentioned in one of my earlier postings, I have some ideas on how to handle the transition from a template to the actual object. But before I tell you about the decision I made (on how to achieve that transition), let me tell you about the components and entities.

A component, as stated in my earlier posts, represents a piece of code that achieves a given task for an entity. This might be holding the health data, holding the current animation state, holding a list of animations or sounds, holding the current experience points.

Although I use the word "holding" a lot when talking about components, they're not only about data storing. Components must be able to alter the entity. While this might sound strange to some ears, it makes perfectly sense in my case. Since I want to have a component that is able to hold the current state of an animation, the very same component must be able to make an update to that animation (ie. call an update on it using a time interval). Also, there might be a component that is able to manage buffs or debuffs for a character. Those buffs must be updated and (in most cases) removed if ie. they usage time has expired. For the above mentioned reasons, a component not only holds data, but also has an update function which receives a delta time since the last call to that function.

The entities store a set of components. This is the very basis of all components. Now, to make my life a little bit easier, I'll have some specialisation for entities: there'll be static entities (those who wont do anything in the world; one might call them decorators) and dynamic entities. Dynamic entities will be (in most cases) NPCs and PCCs (player controlled characters :) ). There will also be dynamic entities representing gfx and sound effects, bullets and other physics driven objects, etc.

Ok... now that we have a basic sketch about components and entities, I'll write about the templates and how they're going to be "translated" into objects. "Translated" is the right wording at this point. In fact, the templates for ie. a component have to be translated into the class instance of that very component. To achieve this, I decided not to use the template class itself but a seperate class which I call TemplateTranslator. In fact, there are two basis classes: ComponentTemplateTranslator and EntityTemplateTranslator (two since I already made the difference on the template side for the templates). The translator itself on has one basic function: create.

Here are the interfaces for the component and entity template translators:

class ComponentTemplateTranslator
{
public:
virtual Component *create(const ComponentTemplate *_template) const = 0;
};

class EntityTemplateTranslator
{
public:
virtual Entity *create(const EntityTemplate *_template) const = 0;
};

Easy and straight-forward... just as I like it :)

Now, I don't want to have a bunch of translators hanging around... so I have a small manager who holds the different translators. The interface is small:

class TemplateTranslatorManager : public Sidema::Singleton
{
public:
// ----------------------------
// Translator handling.
void registerComponentTranslator(Sidema::String _type, ComponentTemplateTranslator* _translator);
void registerEntityTranslator(Sidema::String _type, EntityTemplateTranslator* _translator);

// ----------------------------
// Translator usage.
Component* useTranslator(const ComponentTemplate *_template) const;
Entity* useTranslator(const EntityTemplate *_template) const;

protected:
// ----------------------------
// Xtructors.
TemplateTranslatorManager();
~TemplateTranslatorManager();

private:
friend class Sidema::Singleton;

// ----------------------------
// Translator handling.
void freeAllTranslators();

typedef std::map COMPONENTTRANSLATOR;
COMPONENTTRANSLATOR m_componentTranslators;

typedef std::map ENTITYTRANSLATOR;
ENTITYTRANSLATOR m_entityTranslators;
};


To register a translator, you simply tell the manager, which type (or in case of the entity template determined the name) is handled by the translator. Opposed to component templates which are identified by the type, entity templates are identified by their name. Thus you cannot have a template named "xyz" creating an dynamic entity while another template having the same name would create a static entity.

To create a component, you simply call the useTranslator() function with the component template, and the according component is created (if a translator has been registered for it).

I sense that you want to ask me: Why the heck don't you just implement the "translator" into the template itself since you already have a specialisation for the template?

The answer ist: because the client and the server behave different. While the translators on the client would transfer all information from the template to the object, the translators on the server might want to drop unnecessary information. You don't need gfx information about door on the server, you only need to know if it's open, closed or locked. Also, you might want to have some AI calculations on the server and thus add an ai component to the template, but only create an instance of it on the server.

If you have any questions, suggestions or if you simply want to discuss about this topic, don't hesitate to post a comment :)

Have fun,
Stefan

Labels: , , , ,

Sunday, August 10, 2008

Basis of templates and componenttemplates finished.

After a day "off" at my futre mother-in-law's home, and my son getting sick this night, I managed to find some time to work on the template and component template implementation.

While there might still remain some polishing (I don't yet like the embedding of the factory functions for the templates within my entity manager), the basis seems to be finished. This means that I can load templates and refer to component templates. The code itself is straight forward since I relied on some classes I already used some years ago.

First of all, I decided to use XML. For the XML loading I embedded tinyXML into my source code. tinyXML usage is easy and since I already use it for the SSCXML lib, I didn't see any reason to switch to another reader.

Second I use some classes I created some years ago: Parameter, ParameterList and Parameterized. Basically those 3 classes allow embedding of parameters of any depth to an object. The interfaces are slim and it was easy to alter the loading code to use tinyXML. Here's a preview of the interfaces:


class Parameter : public Parameterized
{
public:
// ---------------
// Xtructors.
Parameter();
Parameter( String &_rsName, const String &_rsValue );
Parameter( const Parameter *_pParam );
virtual ~Parameter();

// ---------------
// Data access.
void setName(const String &_rsName);
String getName() const;
String getValue() const;
void setValue(const String &_rsValue);
void setValue(const char* _pValue);

// ---------------
// I/O
virtual bool load( const TiXmlElement *_pElement );
virtual bool save( TiXmlElement *_pElement );

Parameter& operator =(const Parameter& _pParam);

private:
// ---------------
// Data.
String m_sName;
String m_sValue;
};

class Parameterized
{
public:
// ---------------
// Xtructors.
Parameterized();
Parameterized(const Parameterized *_pElement );
virtual ~Parameterized();

// ---------------
// Parameter access.
ParameterList* getParamList() const;
void clear();
void createParamList();

// ---------------
// I/O
virtual bool load( const TiXmlElement *_pElement );
virtual bool save( TiXmlElement *_pElement );

Parameterized& operator =(const Parameterized& _pParameterized);

protected:
// ---------------
// Data.
ParameterList* m_pParamList;
};

class ParameterList
{
public:
// ---------------
// Xtructors.
ParameterList();
ParameterList(const ParameterList *_pList );
virtual ~ParameterList();

// ---------------
// Parameter management.
void addParam( const Parameter* _pElement );
void removeParam( Parameter* _pElement, bool _bDelete = false );
void clear();
unlong getNrParams() const;
Parameter* getParam( unlong _uIndex ) const;
bool findParam( const String &_rsName, Parameter **_rpParam ) const;

ParameterList& operator =(const ParameterList& _pParamList);

private:
// ---------------
// Data.
TDynArray m_apParams;
};

As you can see, the interfaces are quite clear.

Now, I have three base classes: Template, EntityTemplate and ComponentTemplate. While EntityTemplate and ComponentTemplate are derivations of Template, I felt it was necessary to make a difference between a simple templates, an entity template and templates for the components.


class Template
{
public:
// ----------------------------
// Xtructors.
Template() {}
Template(Sidema::String _type, Sidema::String _name) : m_type(_type), m_name(_name) {}
Template(const Template &_temp) : m_type(_temp.m_type), m_name(_temp.m_name) {}
Template(const Template *_temp) : m_type(_temp->m_type), m_name(_temp->m_name) {}
virtual ~Template() {}

// ----------------------------
// Identify the template.
Sidema::String getType() const { return m_type; }
void setType(Sidema::String _type) { m_type = _type; }

Sidema::String getName() const { return m_name; }
void setName(Sidema::String _name) { m_name = _name; }

// ---------------
// I/O
virtual bool load( const TiXmlElement *_pElement ) { return true; }
virtual bool save( TiXmlElement *_pElement ) { return true; }

private:
Sidema::String m_type;
Sidema::String m_name;
};

// An entity template holds the basic components of an entity.
// This can be all elements that are placed within the gaming world, from
// trees and bushes to the NPCs.
class EntityTemplate : public Template
{
public:
static Sidema::String TEMPLATE_NAME;

// ----------------------------
// Creator/Destroyer
static Template* create(Sidema::String _name);
static void destroy(Template *_template);

// ----------------------------
// I/O
bool load( const TiXmlElement *_pElement );
bool save( TiXmlElement *_pElement );

// ----------------------------
// An entity has components that define its "look".
// Components are ie. health, inventory, experience points, gfx, sound, ...
bool addComponent(ComponentTemplate *_component);
void removeComponent(ComponentTemplate *_component);

protected:
// ----------------------------
// Xtructors.
EntityTemplate();
EntityTemplate(const Sidema::String &_name);
virtual ~EntityTemplate();

private:
// Components of this entity.
typedef std::list COMPONENTARRAY;
COMPONENTARRAY m_components;
};

// A component template contains only basic information about the component itself.
// Basically, it holds the initial values. Templates cannot be "updated".
//
class ComponentTemplate : public Template, public Sidema::Parameterized, public Sidema::IReferenceCounted
{
public:
// ----------------------------
// Xtructors.
virtual ~ComponentTemplate();

// ----------------------------
// I/O
virtual bool load( const TiXmlElement *_pElement );
virtual bool save( TiXmlElement *_pElement );

// ----------------------------
// Owner access.
Template *getOwner() const;
void setOwner(Template *_owner);

// ----------------------------
// Reference counted interface.
unlong addRef(void);
unlong release(void);

protected:
// ----------------------------
// Xtructors.
ComponentTemplate(Sidema::String _type, Sidema::String _name);

private:
unlong m_refCount;
Template *m_owner;
};


IReferenceCounted is a reference counter interface. Once the reference drops to 0 (due to release) the object is deleted.

The loading code is easy, too:

// Load the templates.
const TiXmlNode *node = root->FirstChild("template");
while ( node )
{
if ( TiXmlNode::ELEMENT == node->Type() )
{
const TiXmlElement *element = static_cast(node);

// Read the name and the type.
const char* tempName = element->Attribute("name");
const char* tempType = element->Attribute("type");
if ( NULL != tempType && NULL != tempName )
{
Template *theTemplate = createTemplate( tempType, tempName );
if ( NULL == theTemplate )
break;

if ( theTemplate->load(element) )
{
if (!addTemplate(tempName, theTemplate))
{
destroyTemplate( theTemplate );
break;
}
}
}
}
node = node->NextSibling("template");
}

You might have remarked the createTemplate function. Basically this function looks like this:

// Create a template of a given type.
Template*
EntityManager::createTemplate( const Sidema::String &_type, const Sidema::String &_name )
{
TEMPLATECREATORS::iterator it = m_templateCreateFunctions.find(_type);
if ( it != m_templateCreateFunctions.end() )
{
return it->second(_name);
}

return NULL;
}


The different templates are registered on class construction:

EntityManager::EntityManager()
{
registerTemplate(EntityTemplate::TEMPLATE_NAME, &EntityTemplate::create, &EntityTemplate::destroy );
registerComponentTemplate(HealthComponentTemplate::TEMPLATE_NAME, &HealthComponentTemplate::create, &HealthComponentTemplate::destroy);
}

Ok... this is what is basically needed for the templates of the entities and components. I still have to implement the inheritance for the entity templates. But that's quite easy to do, too.

An XML to create an entity templates looks like this:







Ah yes.. I forgot :) The loading code for the health component template looks like this:

bool
HealthComponentTemplate::load( const TiXmlElement *_pElement )
{
if ( ComponentTemplate::load(_pElement) )
{
if ( !getParamList() )
return false;

// Make sure the template vars have been loaded.
if ( getParamList()->findParam( "maxhealth", NULL) )
return true;
}

return false;
}

EDIT NOTE: I had to change the param tag to prm in order to display the xml and the rest of the text correctly. I didn't see this problem with IE. I encountered this with FF3.0.

The ComponentTemplate::load function just contains "return Parameterized::load(_pElement);" and thus loads the param-tags.

"getParamList()->findParam( "maxhealth", NULL)" makes sure that the maxhealth param has been loaded (actually the line says: find the maxheath parameter but don't actually return me it's pointer... I just want to know if it exists...).

Phew... that was a lot of code in this blog today. As you can see, most things are quite simple to implement. The ComponentTemplate class allows for a very flexible parameter definitions. Any derived class "only" has to check, if the parameters it needs are available.

Entity template composition is made easy by just sticking together several component templates.

There a three next steps:

a) implement inheritance for the entity templates.
b) implement the actual classes for the Entities and Components (those which you actually can alter).
c) implement the template to instance code. I have several ideas how to approach this...

Have fun,
Stefan

Labels: , , , ,