Skip to main content
GameDev.net gamedev.net
🔒 Locked

passing data using strings like in networking

Started by Atomical Dec 15, 2010 at 11:21 AM 4 replies 1k views
Original Post
Atomical
Atomical
So I've been wondering about this lately and before I evolve my game even further I wonder if this is an effective way of passing data through my event functions.

So I've mainly been doing this in event and command handling where I do a network packet-like way of sending my events to my entities, and then my entities do the work of parsing that information.

This is an example before I start making a binary serialization class that returns the same string.

char event[4];event[0] = EVENT_EXPLOSION; // Value 11event[1] = 32; // X event[2] = 75; // Yevent[3] = 20 // MagnitudeEventHandler::Instance()->handleEvent(event,NULL); //Send the event to entities who care about EVENT_EXPLOSION;

Don't care about the X and Y being only 1 byte, this is just an example of something I would make. I also don't remember on the fly of writing this if I have to use memcpy but whatever.

So my question is: Is this an effective way of doing this? Speed wise? I mean, I could make structures but they are not so great in course of being dynamic data containers. I had a vague idea about passing void* pure data, but that brings me back to the same idea of using my approach since a string is basically pure data in the form of bytes.
Sneftel
Sneftel
Gamebryo Lightspeed does (well, did) this. Works fine for network stuff. Requires a lot of easy-to-mess-up boilerplate unless you use a framework for it like Google's protocol buffers. For local event sending, it's not clear what the advantages are.
ApochPiQ
ApochPiQ
I'd have to agree with Sneftel here... serialization when you don't need a serialized byte stream (i.e. for disk or network transfer) doesn't make much sense. Why not just represent the data directly in a structure?
Mantear
Mantear
If the event system stays local, you could use some simple class hierarchy. Make a base Event class with some basic members such as what event type it is and maybe some small, generic data holders that will be common for most events. For more specialized events, created derived classes based off the Event class and add the extra information there. Now have your event passing/handling system work with Event pointers and cast to derived Events as needed.

If the event system isn't local and has to talk across some transport layer, you can use the same as above but also add in some serialize/deserialize methods.

It might look something like this:
class Event{public:    enum    {        EVENT_EXPLOSION,        EVENT_A,        EVENT_B,        EVENT_C    } EventTypes;    Event(EventTypes type)      : m_Type(type),         m_Timestamp(0)    {}    virtual ~Event() {}    // Only use these if the events have to go over some transport protocol.    virtual bool SerializeEvent(char*& pBuffer, unsigned int& bufferSize)    {        // Serialize a basic Event.    }    virtual bool DeserializeEvent(char*& pBuffer, unsigned int& bufferSize)    {        // Deserialize a basic Event.    }protected:    EventTypes m_Type;    unsigned long m_Timestamp;    // Other generic event data, maybe a small generic buffer}class ExplosionEvent : public Event{public:    ExplosionEvent()      : Event(EVENT_EXPLOSION)    {        m_Timestamp(gettime());    }    virtual ~ExplosionEvent() {}    // Other ExplosionEvent specific functions.    // Only use these if the events have to go over some transport protocol.    virtual bool SerializeEvent(char*& pBuffer, unsigned int& bufferSize)    {        // Serialize an ExplosionEvent.    }    virtual bool DeserializeEvent(char*& pBuffer, unsigned int& bufferSize)    {        // Deserialize an ExplosionEvent.    }private:    int m_X;    int m_Y;    int m_Magnitude;}

NOTE: the above is uncompiled/untested! But I have used a system like shown above with pretty good success. It let me talk between two processors, one big-endian and one little-endian, over a PCI bus while they both used the same event/message handling system using a common code base.
Atomical
Atomical
With my way of doing it saves time and code when creating new commands or events. You only have to add a new line in the enum and how entities should handle and send, commands and events.

My main reason why I chose to do this was to stop bothering with making derived classes dude to different data types or unknown number of attributes. With this method I just send a string of bytes to the entity. Since the entity knows what kind of event or command it got, It also knows how to parse the information within the string. Like a packet in server <-> client communication.
My theory is that since it doesn't do any external function calls to parse the information, but rather does it directly, it should increase speed. But I'm unsure about this.
Sneftel
Sneftel
Quote:
Original post by Atomical
My main reason why I chose to do this was to stop bothering with making derived classes dude to different data types or unknown number of attributes. With this method I just send a string of bytes to the entity. Since the entity knows what kind of event or command it got, It also knows how to parse the information within the string.
So rather than let the compiler catch type errors for you, you're telling the compiler to back off and assume that you'll never make any mistakes regarding the types or ordering of data. Not a great tradeoff, IMHO.
Quote:

My theory is that since it doesn't do any external function calls to parse the information, but rather does it directly, it should increase speed.

Your theory doesn't really hold water, particularly if you're just storing data in structs.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.