The idea is that every entity in your gameworld on the serverside inherit from ServerData. This gives you some very nice methods for replicating the data from server to one or more clients, the names and comments of these methods should explain what they do:
public: /// Will send a create-object packet to all clients. void sendCreateObjectToAll() const; /// Creates and sends a create-object packet to a list of clients. void sendCreateObject(const std::map<unsigned int, Client *> & clientlist) const; void sendCreateObject( Client * client) const; /// Will send an update packet to all clients. void sendUpdateToAll(char type, bool reliable) const; /// Creates and sends an update packet to a list of clients. void sendUpdate(const std::map<unsigned int, Client *> & clientlist, char type, bool reliable) const; void sendUpdate( Client * client, char type, bool reliable) const; /// Will send a destroy/delete-object packet to all clients. void sendDestroyToAll() const; /// Create and sends a destroy-object packet to a list of clients. void sendDestroy(const std::map<unsigned int, Client *> & clientlist) const; void sendDestroy( Client * client ) const;
/// This must produce a unique id for this class, it will be used on the client side to construct new objects. virtual const unsigned int getClassId() const = 0;
class MyServerData : public ServerData { private: double x,y; /// [... other members ...] public: virtual const unsigned int getClassId() const { return 42; }; /// Here the data-class should fill in all data required by the constructor on the client side. virtual void fillCreateObjectPacket(FrameworkPacket * packet) const { packet->writeInt32((int)x); packet->writeInt32((int)y); } /// [... other methods ...] }; class MyClientData : public ClientData { private: int x,y; public: MyClientData(ClientFramework * f, FrameworkPacket * p) : ClientData(f,p) { // Here you would read your class data from the packet x = p->readInt32(); y = p->readInt32(); } static ClientData * constructMyData(ClientFramework * f, FrameworkPacket * p) { return new MyClientData(f,p); }; }; class GameClient : public ClientFramework { // [... class methods and members ...] } app; app.registerConstructor(42, &MyData::constructMyData);
This also gives you the option of deriving classes even more, and then in each contructor read what ever data is expected, hence reducing duplication of code. If you have the same inheritance structure on the server you must likewise call the method for writing the initial constructor packet recursively, here is an example:
class MyServerBaseData : public ServerData { private: double x,y; public: virtual const unsigned int getClassId() const = 0; // Not implemented, because this class is still abstract /// Here the data-class should fill in all data required by the constructor on the client side. virtual void fillCreateObjectPacket(FrameworkPacket * packet) const { packet->writeInt32((int)x); packet->writeInt32((int)y); } }; class MyServerRealData1 : public MyServerBaseData { private: std::string name; MyServerBaseData * best_friend; public: virtual const unsigned int getClassId() const { return 42; }; /// Here the data-class should fill in all data required by the constructor on the client side. virtual void fillCreateObjectPacket(FrameworkPacket * packet) const { // Let our base class write first this->MyServerBaseData::fillCreateObjectPacket(packet); // Then we write packet->writeString(name); packet->writePtr(best_friend); } };
class MyClientBaseData : public ClientData { private: int x,y; public: MyClientBaseData(ClientFramework * f, FrameworkPacket * p) : ClientData(f,p) { // Here the base data is read (before us the ClientData class read its unique framework id) x = p->readInt32(); y = p->readInt32(); } }; class MyClientReal1Data : public MyClientBaseData { private: std::string name; MyClientBaseData * best_friend; public: MyClientBaseData(ClientFramework * f, FrameworkPacket * p) : MyClientBaseData(f,p) { // It's time to read our data name = p->readString(); p->readPtr(this, &best_friend, f); } static ClientData * constructMyData(ClientFramework * f, FrameworkPacket * p) { return new MyClientReal1Data(f,p); }; };