Main Page | Modules | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | Related Pages | Examples

14. Nested Objects (write/read)

In this test we set up a ServerData object, this object has multiple "children" all with baseclass ServerData. When we create the contruct-packet for the client we write these "children" to the packet also. On the client-side we use the method FrameworkPacket::readObject( ClientFramework * f ) to read and construct these "children".

Client Application

In this client application we use 2 datatypes, one that is the child and one that is the parent. What you should notice is the call to:
template<class T>
T * ClientPacket::readObject( ClientFramework * f );
This is the method used to read out a "sub-object" from a packet. It should be noted though, that this does NOT have the same posibilities as sending the objects by them selves, and refering them with pointers.

/// @cond EXCLUDEDTESTSOURCES
/***************************************************************************
 * The contents of this file are subject to the Mozilla Public             *
 * License Version 1.1 (the "License"); you may not use this file          *
 * except in compliance with the License. You may obtain a copy of         *
 * the License at http://www.mozilla.org/MPL/                              *
 *                                                                         *
 * Software distributed under the License is distributed on an "AS         *
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or              *
 * implied. See the License for the specific language governing            *
 * rights and limitations under the License.                               *
 *                                                                         *
 * The Original Code is Game Network Framework (GaNeF).                    *
 *                                                                         *
 * The Initial Developers of the Original Code are                         *
 * Lars Langer and Emanuel Greisen                                         *
 * Copyright (C) 2005. Lars Langer & Emanuel Greisen                       *
 * All Rights Reserved.                                                    *
 *                                                                         *
 * Contributor(s):                                                         *
 *   none yet....                                                          *
 *                                                                         *
 ***************************************************************************/

#include <iostream>
#include <cstdlib>

#include "../Ganef/client/clientframework.h"
#include "../Ganef/client/clientdata.h"


class MyClientDataChild : public ClientData
{
   private:
      int x,y;
      std::string name;

   public:
      MyClientDataChild(ClientFramework * f, ClientPacket * p) : ClientData(f,p)
      {
         x = p->readInt32();
         y = p->readInt32();
         name = p->readString();
         std::cout << "MyClientDataChild(";
         std::cout << "ID: " << getFrameworkId();
         std::cout << ",x:"<<x<<",y:"<<y<<")" << std::endl;
      }
      virtual void updatePacket(ClientFramework * f, unsigned char updatetype, ClientPacket * packet)
      {
         // Here we receive updates (but no updates are comming in this test)
      }

      static ClientData * constructMyClientData(ClientFramework * f, ClientPacket * p)
      {
         return new MyClientDataChild(f,p);
      }
};


class MyClientData : public ClientData
{
   private:
      std::string name;
      MyClientDataChild * children[3];

   public:
      MyClientData(ClientFramework * f, ClientPacket * p) : ClientData(f,p)
      {
         name = p->readString();
         std::cout << "Constructing: MyClientData(ID: " << getFrameworkId() <<",name:"<<name<<")"<< std::endl;
         children[0] = p->readObject<MyClientDataChild>(f);
         children[1] = p->readObject<MyClientDataChild>(f);
         children[2] = p->readObject<MyClientDataChild>(f);
      }
      virtual void updatePacket(ClientFramework * f, unsigned char updatetype, ClientPacket * packet)
      {
         // Here we receive updates (but no updates are comming in this test)
      }

      static ClientData * constructMyClientData(ClientFramework * f, ClientPacket * p)
      {
         return new MyClientData(f,p);
      }
};


/**
 * This is just a test-client-framework.
 * @author Lars Langer and Emanuel Greisen
 */
class TestClientFramework : public ClientFramework
{
   private:
      bool is_running;
      std::string server_hostname;

   public:
      TestClientFramework(const std::string & server_hostname) : ClientFramework(int(0)),server_hostname(server_hostname)
      {
         // Notice how the constructor is registered, now all we need is the
         // server sending a packet telling us to construct an object of
         // class with id: 0x424242
         registerConstructor(0x424242, MyClientData::constructMyClientData);
      }
      ~TestClientFramework()
      {
      };

   protected: // These must be implemented in a derived class
      virtual void writeHandshakeInitMessage( ClientPacket * fp ){}
      virtual void onHandshakingDiscontinue( ClientPacket * fp ){}
      virtual bool onHandshakeDescription( ClientPacket * fp, ClientPacket * reply )
      {
         return true;
      }
      virtual void onDisconnect( ) { std::cout << "Disconnected\n"; }
      virtual void onConnect( ){ std::cout << "Connected\n"; }

   public:
      void mainLoop( )
      {
         std::cout << "Connecting to: " << server_hostname <<":"<< 8000<< std::endl;
         initServerConnection(server_hostname, 8000);
         is_running = true;
         while(is_running)
         {
            // Get/handle Packets from the framework
            keepAlive();

            // Then we sleep to let the CPU live
            psleep(50);
         }
      }
};




int main(int argc, char *argv[])
{
   std::string server_host("localhost");
   if(argc > 1)
      server_host = argv[1];
   TestClientFramework app(server_host);

   // Start the Application
   app.mainLoop();
}

/// @endcond

Server Application

The server also uses two different datatypes. One as the children, and the other as the parent. Note that even though we are actually sending 4 data-objects we nest them all into one packet.

/// @cond EXCLUDEDTESTSOURCES
/***************************************************************************
 * The contents of this file are subject to the Mozilla Public             *
 * License Version 1.1 (the "License"); you may not use this file          *
 * except in compliance with the License. You may obtain a copy of         *
 * the License at http://www.mozilla.org/MPL/                              *
 *                                                                         *
 * Software distributed under the License is distributed on an "AS         *
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or              *
 * implied. See the License for the specific language governing            *
 * rights and limitations under the License.                               *
 *                                                                         *
 * The Original Code is Game Network Framework (GaNeF).                    *
 *                                                                         *
 * The Initial Developers of the Original Code are                         *
 * Lars Langer and Emanuel Greisen                                         *
 * Copyright (C) 2005. Lars Langer & Emanuel Greisen                       *
 * All Rights Reserved.                                                    *
 *                                                                         *
 * Contributor(s):                                                         *
 *   none yet....                                                          *
 *                                                                         *
 ***************************************************************************/

#include <iostream>
#include <cstdlib>
#include <vector>


#include "../Ganef/server/serverframework.h"


class MyServerDataChild : public ServerData
{
   private:
      int x,y;
      std::string name;
   public:
      MyServerDataChild(ServerFramework * fw, int x, int y, const std::string & name) : ServerData(fw, 10, false),x(x),y(y),name(name)
      {
      };
   public:
      virtual const unsigned int getClassId() const { return 0x123456; };
      virtual void fillUpdatePacket(ServerPacket * packet, unsigned char type) const
      {
         // We do not use updates in this test.
      }
      virtual void fillCreateObjectPacket(ServerPacket * packet) const
      {
         packet->writeInt32(x);
         packet->writeInt32(y);
         packet->writeString(name);
      }
      virtual void clientPacket(Client * client, unsigned char type, ServerPacket * packet)
      {
         // We wont receive any actions from the client
      }
};


class MyServerData : public ServerData
{
   private:
      std::string name;
      MyServerDataChild * child1;
      MyServerDataChild * child2;
      MyServerDataChild * child3;

   public:
      // The two last parameters for ServerData is the priority of its updatepackets
      //  and wether they should be sent reliable.
      MyServerData(ServerFramework * fw, const std::string & name) : ServerData(fw, 10, false),name(name)
      {
         child1 = new MyServerDataChild(fw, 100, 150, "Child one");
         child2 = new MyServerDataChild(fw, 130, 250, "Child two");
         child3 = new MyServerDataChild(fw, 160, 350, "Child three");
      };
   public:
      /// 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 { return 0x424242; };
      /// Here the data-class should fill in data according to update type `type`.
      virtual void fillUpdatePacket(ServerPacket * packet, unsigned char type) const
      {
         // We do not use updates in this test.
         // Also notice that the object read/write does not support updates.
      }
      /// Here the data-class should fill in all data required by the constructor on the client side.
      virtual void fillCreateObjectPacket(ServerPacket * packet) const
      {
         packet->writeString(name);
         packet->writeObject(child1);
         packet->writeObject(child2);
         packet->writeObject(child3);
      }
      /// Called when ever we receive a packet for this object from a client.
      virtual void clientPacket(Client * client, unsigned char type, ServerPacket * packet)
      {
         // We do not receive any actions from the client in this test.
      }

};

/**
 * This is just a test server-framework;
 * @author Lars Langer and Emanuel Greisen
 */
class TestServerFramework : public ServerFramework
{
   MyServerData * mydata;

   public:
      TestServerFramework() : ServerFramework(8000)
      {
      }

      ~TestServerFramework()
      {
      }

   protected: // These method should be implemented on the GameServer
      virtual bool onInitialHandshake(ServerPacket * handshake, ServerPacket * reply)
      {
         return true; // Accept all clients.
      }
      virtual void onClientConnected(Client * client)
      {
         std::cout << "Client: " << client->getId() << " connected\n";
         mydata->sendCreateObject(client);
      }
      virtual void onClientDisconnected(Client * client)
      {
         std::cout << "Client: " << client->getId() << " disconnected\n";
      }
      virtual Client * createClient(const ipaddress &addr, int port)
      {
         return new Client(this, addr, port);
      }

   public:
      void mainLoop()
      {
         std::cout << "TestServerFramework: Running\n";
         mydata = new MyServerData(this, "My Parent Data Object");
         while(true)
         {
            // Get all incomming messages
            keepAlive();

            // Sleep a little
            psleep(100);
         }
      }
};




int main(int argc, char *argv[])
{
   try
   {
      // Create a framework
      TestServerFramework framework;

      // Start the framework
      framework.start();

      // GameLoop
      framework.mainLoop();
   }
   catch(FrameworkError *err)
   {
      std::cout << "FrameworkError:" << err->msg << std::endl;
   }
   catch(PacketError *err)
   {
      std::cout << "PacketError:" << err->msg << std::endl;
   }

   return EXIT_SUCCESS;
}

/// @endcond

Generated on Mon Feb 6 12:24:58 2006 for Ganef by  doxygen 1.4.4