Sign in to follow this  
rick_appleton

Unique identifiers for each object?

Recommended Posts

rick_appleton    864
I was thinking on how to pass messages from one computer and another, and it seems to me, that each and every updateable object in the game at a single time needs a unique identifier so the client and server can synchronize. Is this correct?

Share this post


Link to post
Share on other sites
Soul    162
Yep spot on, you will need some kind of unique identifier for every object so you can keep track of them all

Share this post


Link to post
Share on other sites
rick_appleton    864
One option I had thought of was having a simple array of pointers, and using the ID to index into that. Are there any problems I might expect with this? Of course the array would have to contain pointers to void types, so I'd lose all type information.

Share this post


Link to post
Share on other sites
rypyr    252
Why not use a base class (which includes a unique identifier)?


class BaseObject {
static unsigned long getUniqueID() {
static id = 0;
++id;
return id;
}

unsigned long m_id = BaseObject::getUniqueID();
};


Regards,
Jeff

Share this post


Link to post
Share on other sites
rick_appleton    864
This works perfectly when pushing the object over the channel (objectID, data), but how would I find the correct object on the receiving side? (ah I received data for object X, now where is that object? I have to go through all objects and see if the ID matches)

Share this post


Link to post
Share on other sites
Lord Bart    226
Hello rick_appleton,

Yes each object should have a unique id and but should be base on a hierarchy of ids.

Not everything needs a unique id across the all objects.

ex.
You have list of:
Each type of object should have a type id player type 1, NPC 2, monsters 3.
Monsters each should have a type id (troll 1, goblin 2 etc) and a unique id within monsters type (troll num 5).
NPC same.
Players same.

If you break the ids base on object type then sub type and then a number it is easy to update list across clients and server.

When update monster you know it is monster and is type 5 and identity(num) 10.
So you can go to the monster list for type 5 and update monster 10.

examle struct for id


struct objId
{
Byte type; // main type pleyer, NPC, monster etc.
Byte sub; // troll, goblin, etc.
Short num; // actual id of object in type and sub type.
};
union uniqueId
{
int id;
objId full_id;
};


Then you can use id get the int value and full_id to get type, subtype, and number.

Also need to think about who controls the objects.
The client(s), the server, or shared between clients and server.
You might need/want to have the id of the controling system in there to.

Lord Bart :)

Share this post


Link to post
Share on other sites
rick_appleton    864
Thank you everybody for replying.

Lord Bart: interesting option, but it sounds a bit too much bookkeeping to me.

I still plan on implementing the universal array in some way because I feel it is the least intrusive in the used classes, and I was wondering if there are any problems I might have overlooked (except for the loss of type information).

Share this post


Link to post
Share on other sites
Lord Bart    226
Hello rick_appleton,

Yes it involes some book keeping but it is a solution to your question.

[quote]
but how would I find the correct object on the receiving side? (ah I received data for object X, now where is that object? I have to go through all objects and see if the ID matches)
[/qoute]

By having type, sub type as part of id you know what kind of object and what list(s) it could be in.

Othewise you would have to do what you think you would, go through every object in list.
Unless you used a map. (hint use map with id as key)

Anyway sounds like you understand the way your going, so have fun :)

Lord Bart :)

Share this post


Link to post
Share on other sites
Axenation    127

psuedo code example of how i handle uid generation.


typedef unsigned int SERIAL;

class CBaseObject
{
// my uid.
SERIAL serial;

//the mapsector i am located in (see below)
MapSector *sector;
}

//
// the high byte of a serial is the
// type identifier. the lower 3 bytes
// are the actual index in the array.
//
const SERIAL TYPE_MONSTER = 0x80000000;
const SERIAL TYPE_PLAYER = 0x40000000;
const SERIAL TYPE_ITEM = 0x20000000;

//
// array of object pointers
//
static CBaseObject* serial_array[MAXSIZE];

//
// add an object to the array
// returns 0 if error occurred
// else returns objects serial
//
SERIAL SerialGenerator::AddObject(CBaseObject* object)
{
//
// starts at 1 because serial
// id 0 is reserved for errors
// in the generator (see below).
//
static SERIAL next_serial = 1;

if(next_serial == 0xFFFFFF)
next_serial = 1;

if(serial_array[next_serial & 0xFFFFFF] == NULL)
{
object->serial = next_serial;
serial_array[next_serial++] = object;
return object->serial;
}
else
{
// error!
object->serial = 0;
return 0;
}
}

//
// get an object by it's uid
// returns NULL if the serial
// is not valid.
//
CBasebject* SerialGenerator::GetObject(SERIAL id)
{
if(serial_array[id & 0xFFFFFF] != NULL)
return serial_array[id];
else
return NULL;
}




As for handling objects between the server and the client.

ServerSide, I'd chop the map into a 2d array of rectangles. The client only stores objects from the sector he is standing in, and the 8 surrounding sectors. When an object comes into the client's view, the server sends a packet with the object info and it's serial uid. The client then stores the object in an std::list or an array indexed by the serial that the server sent. When the client needs to send info about the object back to the server, it will send the info packet (containing the object's serial). When the object is out of view remove it from the list/array.

some more psuedo code.

class MapSector
{
int x,y,w,h; //location of the sector(w and h = 64)

//
// store objects in small lists.
// it's more efficient to loop
// through several small lists
// than one huge list.
//
std::list<CMonster*> monsters;
std::list<CPlayer*> players;
std::list<CItem*> items;

void InsertObject(CBaseObject* object)
{
if(object->serial & TYPE_MONSTER)
monsters.push_back(object);
elseif(object->serial & TYPE_PLAYER)
players.push_back(object);
elseif(object->serial & TYPE_ITEM)
items.push_back(object);
}

void RemoveObject(SERIAL uid);
};


class GameServer
{
SerialGenerator SerialGen;

// 2d array of map sectors, each one
// 64x64 tiles in size.
MapSector sectors[MAPWIDTH/64][MAPHEIGHT/64];
}



sorry it doesnt contain more comments, it's 9 am and i need to sleep :-)

Share this post


Link to post
Share on other sites
markr    1692
To find your objects by ID, you could easily create a std::map which had unique IDs as keys and pointers to your objects as values. Then you'd be able to easily find them.

Mark

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this