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

5. Update of objects

In this test we will set up a ServerData object on the server, replicate it to the client upon connect using the member-method:
void sendCreateObject( Client * client) const;
Then during each pass of the mainLoop on the server, we will change the object and send an update to all connected clients using the member-method:
void sendUpdateToAll(unsigned char type, bool reliable) const;
The client will print out the object during each pass of its mainLoop, thus showing the change.

Client Application

In this example you should notice the implementation of the member method:
virtual void updatePacket(ClientFramework * f, char updatetype, ClientPacket * packet);
This is the method which is called when we receive updates from the server. The updatetype is used to determine which kind of update this is. In this simple test we only use one type, but you can specify any number from 4 to 255. The update-types below 4 are reserved for constructors, destructors, plugins and the framework packets.

/// @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 MyClientData : public ClientData
{
   private:
      int x,y;
      std::string name;

   public:
      MyClientData(ClientFramework * f, ClientPacket * p) : ClientData(f,p),x(0),y(0)
      {
         name = p->readString();
         x = p->readInt32();
         y = p->readInt32();
         std::cout << "Constructed a new object of class: MyClientData" << std::endl;
         std::cout << " - The new object has ID: " << getFrameworkId() << std::endl;
         std::cout << " - And (x:"<<x<<",y:"<<y<<")" << std::endl;
      }
      virtual void updatePacket(ClientFramework * f, unsigned char updatetype, ClientPacket * p)
      {
         switch(updatetype)
         {
            case 42:
               // This is the only kind of update we expect
               x = p->readInt32();
               y = p->readInt32();
               break;
         }
      }
      void print() const
      {
         std::cout << "MyClientData["<<name<<"](x:"<<x<<",y:"<<y<<")" << std::endl;
      }

      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();

            // Here we iterate over all data-objects in the framework
            // Please note: the typecast here is DANGEROUS, the only reason
            // we can do it is that we KNOW FOR SURE that all objects are of
            // class MyClientData
            std::map<unsigned int, ClientData *>::const_iterator it;
            for(it = getClientDataObjects().begin(); it != getClientDataObjects().end(); ++it)
            {
               MyClientData * dataobj = dynamic_cast<MyClientData *>(it->second);
               if(dataobj)
               {
                  dataobj->print();
               }
            }

            // 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

There is not much to notice here, we create 3 dataobjects and each pass in the mainLoop we update their position, and send an update to all connected clients. You should notice the member method:
virtual void fillUpdatePacket(ServerPacket * packet, unsigned char type) const;
This method is called when ever we need an update packet of a specific type from the object. All this method does in this example is write its coordinates to the 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 MyServerData : public ServerData
{
   private:
      int x,y;
      std::string name;

   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)
      {
         x = 0;
         y = 0;
      };
   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
      {
         switch(type)
         {
            case 42: // This is the only update we send in this test
               packet->writeInt32(x);
               packet->writeInt32(y);
               break;
         }
      }
      /// Here the data-class should fill in all data required by the constructor on the client side.
      virtual void fillCreateObjectPacket(ServerPacket * packet) const
      {
         // Here we supply enough data to create the client-version of this object
         // Remember to make absolutely sure that what you write here is exactly the
         //   same as the client version reads in its constructor.
         packet->writeString(name);
         packet->writeInt32(x);
         packet->writeInt32(y);
      }
      /// 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.
      }

      void move(int dx, int dy)
      {
         x += dx;
         y += dy;
      }
};

/**
 * This is just a test server-framework;
 * @author Lars Langer and Emanuel Greisen
 */
class TestServerFramework : public ServerFramework
{
   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";
      }
      virtual void onClientDisconnected(Client * client)
      {
         std::cout << "Client: " << client->getId() << " disconnected\n";
      }
      virtual Client * createClient(const ipaddress &addr, int port)
      {
         Client * client = new Client(this, addr, port);
         // Here we send the construction packages for all Framework Data
         std::map<unsigned int, ServerData *>::const_iterator it;
         for(it = getServerDataObjects().begin(); it != getServerDataObjects().end(); ++it)
         {
            ServerData * s_data = it->second;
            s_data->sendCreateObject(client);
         }

         return client;
      }

   public:
      void mainLoop()
      {
         std::cout << "TestServerFramework: Running\n";
         MyServerData mydata1(this, "MyData1");
         MyServerData mydata2(this, "MyData2");
         MyServerData mydata3(this, "MyData3");
         while(true)
         {
            // Get all incomming messages
            keepAlive();

            mydata1.move(2,1);
            mydata2.move(1,4);
            mydata3.move(3,2);

            // The update type matches the expected update type on the client side
            //   and we don't need this periodic updates to be sent reliable.
            mydata1.sendUpdateToAll(42, false);
            mydata2.sendUpdateToAll(42, false);
            mydata3.sendUpdateToAll(42, false);

            // 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:57 2006 for Ganef by  doxygen 1.4.4