Contents
A Templated C++ Attribute Library for Object Persistence and Export
 
 
Printer-Friendly VersionPrinter-Friendly Version
 
Latest News
spacer View All spacer
 
November 22, 2009
 
Video Game Watchdog National Institute On Media And The Family Shutting Down [11]
 
Modern Warfare 2 Infinity Ward's 'Most Successful PC Version' Yet [12]
 
New Tech, Design Details Of Project Natal To Emerge At Gamefest In February
spacer
Latest Jobs
spacer View All     Post a Job     RSS spacer
 
November 22, 2009
 
Sucker Punch Productions
Character Artist
 
Sucker Punch Productions
3D Environment Artist
 
Sucker Punch Productions
Network Programmer
 
Sucker Punch Productions
Texture Artist
 
Sony Online Entertainment
Brand Manager
 
Monolith Productions
Sr. Software Engineer, Engine - Monolith Productions - #113767
 
Crystal Dynamics
Sr. Level Designer
 
Gargantuan Studios
Lead World Designer
spacer
Latest Features
spacer View All spacer
 
November 22, 2009
 
arrow Upping The Craft: Susan O'Connor On Games Writing [6]
 
arrow Small Developers: Minimizing Risks in Large Productions - Part II [6]
 
arrow iPhone Piracy: The Inside Story [48]
 
arrow And Yet It Grows: Analyzing the Size and Growth of the European Game Market [5]
 
arrow NPD: Behind the Numbers, October 2009 [13]
 
arrow Reflecting On Uncharted 2: How They Did It [5]
 
arrow Sponsored Feature: Rasterization on Larrabee -- Adaptive Rasterization Helps Boost Efficiency
 
arrow Postmortem: Wadjet Eye's The Blackwell Convergence [2]
spacer
Latest Blogs
spacer View All     Post     RSS spacer
 
November 22, 2009
 
Accepting the Inherent Value of Games
 
Planckogenesis, Part II: Song Structure & Gravy Train [1]
 
Designing Games Is About Matching Personalities [1]
spacer
About
spacer News Director:
Leigh Alexander
Features Director:
Christian Nutt
Editor At Large:
Chris Remo
Advertising:
John 'Malik' Watson
Recruitment/Education:
Gina Gross
 
Features
  A Templated C++ Attribute Library for Object Persistence and Export
by Gary McNickle
1 comments
Share RSS
 
 
June 4, 2008 Article Start Previous Page 3 of 5 Next
 

Consider the following scenario: a game server object contains (among other things) a list of connected sockets indicating players who have either connected successfully or are in the process of connecting.

Each connection object will typically have a unique identifier, commonly the socket ID. Until the connection is complete, the player object which will ultimately contain the connecting socket has not yet been created.

Advertisement

One of the things the server may want to do is keep a list, unique to each socket, of the number of attempts a player makes at entering their password. Most of the time, a player will connect without ever failing to enter the correct password, but you have to support tracking password attempts per socket. What do you do?

A common approach is to add a counter in each socket class to track the number of failed attempts. While this works fine, it can be wasteful when those counters are not necessary. AttributeContainer provides an alternate solution: temporary attributes.

For example:

Listing 3

GameServer::FailedConnect(Socket& socket)
{
string identifier = "login_attempts_" + socket.guid();
int nAttempts = 1;

if (m_Attributes.GetValue(identifier, nAttempts) == false )
m_Attributes.Bind(identifier, new int(1), ATTR_TEMPORARY);
else
m_Attributes.SetValue(identifier, ++nAttempts);
// do some processing with nAttempts;
}

The ‘identifier' attribute will now remain within m_Attributes until either you specifically ‘Release' it or until m_Attributes goes out of scope, at which point the ATTR_TEMPORARY bit will cause the AttributeContainer to delete the memory allocated by the call to ‘new int'.

While this is a somewhat contrived example, it serves to illustrate the ability of AttributeContainer to perform basic garbage collection of temporary attributes.

Querying AttributeContainer for All Bound Attributes

One useful feature of AttributeContainer is that it can be asked for a list of all Attributes, returning their names and values. This is especially useful in User Interfaces such as console windows or property panes. Listing 4 gives an example.

Listing 4

void PropertyPane::DrawControlProperties(Control* pControl)
{
t_vAttributes list;
t_vAttributes::iterator pos;

pControl->GetAttributes(list);
for (pos = list.begin(); pos != list.end(); pos++)
{
AttributeBase* p = (*pos);
DrawProperty(p->GetName(), p->GetValue());
}
}

In this example, the ‘Control’ object inherits directly from AttributeContainer, allowing the PropertyPane, which has no knowledge of Control or what Attributes it might have, to query the control for all of its attributes and their values, which the PropertyPane object then displays to the user. It is a trivial matter at this point to allow the PropertyPane to be editable, modifying each attribute as the user sees fit.

Exposing Attributes to Scripting Languages

Embedding a scripting language into your application is fairly simple. However, exposing your C++ objects to that scripting language is complex and time consuming, typically entailing modification of each and every object that you want exposed to the interpreter and creating separate, language specific definition and or code files for each object.

If you need your scripting language to be able to create instances of your C++ objects, this may be your only alternative.

Often, all you need is to allow the embedded interpreter to query those objects for values and to change those values through a script. AttributeContainer can make this job much easier. Consider the Python script in listing 5:

Listing 5

import game

# Locate the actor 'Player1'
# Note that LocateActor returns a type 'long' that indicates the actors GUID
# or -1 if the actor cannot be found
nActor = game.LocateActor("Player1")

if nActor > -1:
# Locate one of the actors bound attributes
szName = game.GetAttribute(nActor, "Name")

# Ok, now change the value of the attribute
szName = game.SetAttribute(nActor, "Name", "Joe")
else:
print "Unable to locate 'Player1' anywhere."

After embedding Python into the application, all that was needed for the interpreter to be able to query and change attributes were three methods, which I had defined as:

PyObject* pyGetAttribute(PyObject* self, PyObject* args);
PyObject* pySetAttribute(PyObject* self, PyObject* args);
PyObject* pyLocateActor(PyObject* self, PyObject* args);

static PyMethodDef pyMethods[] =
{
{"LocateActor", pyLocateActor, METH_VARARGS, "Locate an actor."},
{"GetAttribute", pyGetAttribute, METH_VARARGS, "Get an actor attribute."},
{"SetAttriubte", pySetAttribute, METH_VARARGS, "Set an actor attribute."},
{NULL, NULL, 0, NULL}
};

When exposing C++ objects to embedded interpreters, it is often necessary to wrap the objects in obscure macros and write separate definition files in order for the interpreter to gain even the most basic access to the objects or their data. The method described here avoids the need for such practices.

 
Article Start Previous Page 3 of 5 Next
 
Comments

Andrew Ames
profile image
The biggest memory savings can be found by separating the attribute container into a class meta data object that is instantiated and filled only once for the class, instead of for each object instance.

After rereading the article, I see you mentioned this refactor potential:

"One alternative is to have a global instance of AttributeContainer (or at least one that is in a larger scope than the objects it manages). While this saves some memory, it does complicate use, as each bound attribute must be somehow uniquely identified per object."

There are certainly some not-too-difficult solutions that simplify the global shared container pattern for client code.

In a system I worked with, the following client code would serialize an object's properties to a stream:

Object *pObject = ...;

MutableString mutstr;
StringOutputStream sos(mutstr);
XmlSerializer ser(os);

ser.Serialize(pObject);


none
 
Comment:
 


Submit Comment