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

doxygen.html

00001 /**
00002 @defgroup Common GanefCommon
00003 This is the Common Module, very nice.
00004 @defgroup Client GanefClient
00005 This is the Client Module, should be linked with the client application.
00006 @defgroup Server GanefServer
00007 This is the Server Module, should be linked with the server application.
00008 */
00009 
00010 
00011 
00012 /**
00013 @mainpage API
00014 
00015 <!--h2><font color=red>Ga</font>me <font color=red>Ne</font>twork <font color=red>F</font>ramework</h2-->
00016 
00017 The following describes how to use Ganef in a network based game, or similar application. It is highly recommended that you read these pages, and take a close look at the test-application:
00018 
00019 <ol>
00020  <li> @subpage Topology </li>
00021  <li> @subpage ClientServerSetup </li>
00022  <li> @subpage Data </li>
00023  <li> @subpage ServerSetup </li>
00024  <li> @subpage ClientSetup </li>
00025  <li> @subpage ConnectionEvents </li>
00026  <li> @subpage TestApplication </li>
00027  <li> @subpage Plugins </li>
00028  <li> @subpage Installation </li>
00029  <li> @subpage Misc </li>
00030 </ol>
00031 
00032 <hr>[Next: @ref Topology ]
00033 
00034 
00035 
00036 
00037 
00038 @page Topology The Network Topology of Ganef
00039 Before we begin, it is important to understand that Ganef was made to facilitate server-client based games. The following assumptions are made about the game in which Ganef will be used:
00040 <ul>
00041    <li>The game has only one dedicated server</li>
00042    <li>The server holds the "truth" about the gameworld (the server is always right)</li>
00043    <li>The server is the <i>only</i> one to alter the game-world</li>
00044    <li>The clients only send requests about what they <i>want</i> to do, not what they <i>did</i>
00045    <li>The server knows the whole game-world, the clients need not know all of it at any point in time.
00046 </ul>
00047 As you might have guessed, this means that Ganef is not made for all games, but only a subset of them. The reason for these strict assumptions is that if they hold for any game, using Ganef will make the development of the game a lot easier.
00048 
00049 <hr>[Next: @ref ClientServerSetup ]
00050 
00051 
00052 @page ClientServerSetup Client-Server setup
00053 As mentioned game using Ganef will have one server, and one or more clients. To acheive this you will inherit from two classes in Ganef, ClientFramework and ServerFramework. Since we are using C++ you can inherit from more than one class, hence you could let your main game-class (if you have one such) inherit from one of these even though it is already inheriting from an other base class.
00054 
00055 <h3>%Client</h3>
00056 The client-class must as mentioned inherit the ClientFramework class as follows:
00057 \code
00058 class MyGameClient : public ClientFramework
00059 {
00060    // ... your client class members and methods.
00061 };
00062 \endcode
00063 <p>
00064 The ClientFramework class declares several abstract methods:
00065 \code
00066 protected: // These must be implemented in a derived class
00067    virtual void writeHandshakeInitMessage(FrameworkPacket * fp) = 0; //give first message
00068    virtual void onHandshakingDiscontinue(FrameworkPacket * fp) = 0; //recieve
00069    virtual bool onHandshakeDescription(FrameworkPacket * fp, FrameworkPacket * reply) = 0;
00070    virtual void onDisconnect() = 0;
00071    virtual void onConnect() = 0;
00072 \endcode
00073 These must be implemented before you can run your client application, what you should do in each of them will be explained later.
00074 
00075 <h3>%Server</h3>
00076 The server class must inherit from the ServerFramework class as follows:
00077 \code
00078 class MyGameServer : public ServerFramework
00079 {
00080    // ... your server class members and methods.
00081 };
00082 \endcode
00083 Like the client, the server must implement a few abstract methods, the content of these will be discussed as we explain later:
00084 \code
00085 protected: // These method should be implemented on the GameServer
00086    /// This method should write it's reply in the reply-packet, and return true or false depending on wether it want's us to continue the handshaking.
00087    virtual bool onInitialHandshake(FrameworkPacket * handshake, FrameworkPacket * reply) = 0;
00088    /// This method will be invoked when a new client has passed the handshaking-phase.
00089    virtual void onClientConnected(Client * client) = 0;
00090    /// This method will be invoked when a client has timed out.
00091    virtual void onClientDisconnected(Client * client) = 0;
00092    /// This method should return some dirivative of the Client-class.
00093    virtual Client * createClient(ServerFramework *fw, const ost::InetHostAddress &addr, ost::tpport_t port) = 0;
00094 \endcode
00095 A thing to notice here is that you are forced to implement a method called createClient(...), this method should return an object of the class Client. But if you want to assosiate more data with a connected client, you can just inherit from the Client class and add what ever data you find usefull.
00096 
00097 <hr>[Next: @ref Data ]
00098 
00099 
00100 @page Data Gameworld Data
00101 Most gameworlds are represented as a bunch of well organized data-structures. In strict server-client based games, the server holds a full copy of the world, and the client hold a subset of the data constituting the world. The datatypes might not even be the same on server and client, because the client might not need to know all about every entity in the game. This is why Ganef uses two distinct base classes for datatypes, ClientData and ServerData.
00102 <p>
00103 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:
00104 \code
00105    public:
00106    /// Will send a create-object packet to all clients.
00107    void sendCreateObjectToAll() const;
00108    /// Creates and sends a create-object packet to a list of clients.
00109    void sendCreateObject(const std::map<unsigned int, Client *> & clientlist) const;
00110    void sendCreateObject( Client * client) const;
00111 
00112    /// Will send an update packet to all clients.
00113    void sendUpdateToAll(char type, bool reliable) const;
00114    /// Creates and sends an update packet to a list of clients.
00115    void sendUpdate(const std::map<unsigned int, Client *> & clientlist, char type, bool reliable) const;
00116    void sendUpdate( Client * client, char type, bool reliable) const;
00117 
00118    /// Will send a destroy/delete-object packet to all clients.
00119    void sendDestroyToAll() const;
00120    /// Create and sends a destroy-object packet to a list of clients.
00121    void sendDestroy(const std::map<unsigned int, Client *> & clientlist) const;
00122    void sendDestroy( Client * client ) const;
00123 \endcode
00124 The important thing to notice here is that when you call the sendCreateXXX methods, a similar datastructure inheriting from ClientData will be initialized and inserted into the ClientFramework on the clients you specify. The important thing to notice here is that every class in your gameworld must have a unique id. This id should be returned by the serverside data with the virtual method:
00125 \code
00126    /// This must produce a unique id for this class, it will be used on the client side to construct new objects.
00127    virtual const unsigned int getClassId() const = 0;
00128 \endcode
00129 And on the client side you should register a static method as the "constructor" for the client side class. This could be done as follows:
00130 \code
00131 class MyServerData : public ServerData
00132 {
00133    private:
00134       double x,y;
00135       /// [... other members ...]
00136    public:
00137       virtual const unsigned int getClassId() const { return 42; };
00138       /// Here the data-class should fill in all data required by the constructor on the client side.
00139       virtual void fillCreateObjectPacket(FrameworkPacket * packet) const
00140       {
00141          packet->writeInt32((int)x);
00142          packet->writeInt32((int)y);
00143       }
00144       /// [... other methods ...]
00145 };
00146 
00147 class MyClientData : public ClientData
00148 {
00149    private:
00150       int x,y;
00151    public:
00152       MyClientData(ClientFramework * f, FrameworkPacket * p) : ClientData(f,p)
00153       {
00154          // Here you would read your class data from the packet
00155          x = p->readInt32();
00156          y = p->readInt32();
00157       }
00158       static ClientData * constructMyData(ClientFramework * f, FrameworkPacket * p)
00159       {
00160          return new MyClientData(f,p);
00161       };
00162 };
00163 
00164 class GameClient : public ClientFramework
00165 {
00166    // [... class methods and members ...]
00167 } app;
00168 app.registerConstructor(42, &MyData::constructMyData);
00169 \endcode
00170 Now if the server has an object of class MyServerData and calls "sendCreateObject(client)", a FrameworkPacket will be created and inserted in the outqueue on the server. Once the packet is sent and received on the client the packet will hint the client about what constructor method to call (based on the class id, in this case "42") and thereby accuire a new object of class MyClientData. An important thing to notice is that MyClientData calls the constructor "ClientData(ClientFramework * f, FrameworkPacket * p)" of ClientData. This is <em>very important</em> because the ClientData should get to read from the packet first, because the very first thing in the packet is the <em>unique object id</em> see @ref UniqueFrameworkID.
00171 <p> 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:
00172 \code
00173 class MyServerBaseData : public ServerData
00174 {
00175    private:
00176       double x,y;
00177    public:
00178       virtual const unsigned int getClassId() const = 0; // Not implemented, because this class is still abstract
00179       /// Here the data-class should fill in all data required by the constructor on the client side.
00180       virtual void fillCreateObjectPacket(FrameworkPacket * packet) const
00181       {
00182          packet->writeInt32((int)x);
00183          packet->writeInt32((int)y);
00184       }
00185 };
00186 class MyServerRealData1 : public MyServerBaseData
00187 {
00188    private:
00189       std::string name;
00190       MyServerBaseData * best_friend;
00191    public:
00192       virtual const unsigned int getClassId() const { return 42; };
00193       /// Here the data-class should fill in all data required by the constructor on the client side.
00194       virtual void fillCreateObjectPacket(FrameworkPacket * packet) const
00195       {
00196          // Let our base class write first
00197          this->MyServerBaseData::fillCreateObjectPacket(packet);
00198          // Then we write
00199          packet->writeString(name);
00200          packet->writePtr(best_friend);
00201       }
00202 };
00203 \endcode
00204 On the client you would have:
00205 \code
00206 class MyClientBaseData : public ClientData
00207 {
00208    private:
00209       int x,y;
00210    public:
00211       MyClientBaseData(ClientFramework * f, FrameworkPacket * p) : ClientData(f,p)
00212       {
00213          // Here the base data is read (before us the ClientData class read its unique framework id)
00214          x = p->readInt32();
00215          y = p->readInt32();
00216       }
00217 };
00218 
00219 class MyClientReal1Data : public MyClientBaseData
00220 {
00221    private:
00222       std::string name;
00223       MyClientBaseData * best_friend;
00224    public:
00225       MyClientBaseData(ClientFramework * f, FrameworkPacket * p) : MyClientBaseData(f,p)
00226       {
00227          // It's time to read our data
00228          name = p->readString();
00229          p->readPtr(this, &best_friend, f);
00230       }
00231 
00232       static ClientData * constructMyData(ClientFramework * f, FrameworkPacket * p)
00233       {
00234          return new MyClientReal1Data(f,p);
00235       };
00236 };
00237 \endcode
00238 
00239 <hr>[Next: @ref ServerSetup ]
00240 
00241 
00242 @page ServerSetup Setting up the server
00243 When you have created your derived classes of ClientFramework and ServerFramework you should tell the server application to start listening on some port, then enter its @ref MainLoop. Then to process any incomming packets from clients, then @ref MainLoop <em>must</em> call the keepAlive(...) method. When ever this method is called any packets from clients will be processed.
00244 
00245 <hr>[Next: @ref ClientSetup ]
00246 
00247 
00248 @page ClientSetup Establish a Connection from a client
00249 When you want to connect to a game server you just call the initServerConnection(...) with a hostname and port number. Then the client will start trying to connect to the server. Like on the server side, you must enter the @ref MainLoop of your game, where you <em>must</em> call the keepAlive(...) method to make sure you process any incomming packets from the server.
00250 
00251 <hr>[Next: @ref ConnectionEvents ]
00252 
00253 
00254 @page ConnectionEvents Connection Events
00255 - onConnect(...)
00256 - onDisconnect(...)
00257 - onClientConnect(...)
00258 To make sure that no two thread manipulate the same data at the same time, all these event-methods that you are forced to implement on server and client will not be called unless you call keepAlive(...). That is these methods will be called from the same thread of execution as your @ref MainLoop. This garanties that these methods can manipulate the gameworld data (on client or server). The threads started by the framework to handle sending, receiving and retransmitting packets will never touch the actual game-data, this <em>only</em> happens in the code you write, and this code will only be touched by one thread of execution.
00259 
00260 <h2>Keeping the framework running</h2>
00261 As explained earlier, you must call the keepAlive(...) method in your @ref MainLoop. If you fail to do this very often, then the connection between server and client might drop, because the heartbeats sent out by the client are sent from there. This is not very convenient, and will likely be changed in the future.
00262 
00263 <hr>[Next: @ref TestApplication ]
00264 
00265 
00266 @page TestApplication Complete Test Application
00267 To better show how this is all used, we have constructed a test-application. It uses SDL and TTF so these libraries must be installed to compile the testapplication.
00268 <p>
00269 The "game" is rather simple: the client connects to the server and is given a "snake" consisting of 10 bites. When the client moves the mouse he request that the head of his snake be moved to that possition. The server keeps telling all connected client where all snakebites are possitioned.
00270 <h3>%Client files</h3>
00271 <ul>
00272    <li>client_main.cpp</li>
00273    <li>testclientframework.cpp / testclientframework.h</li>
00274    <li>testclientsnakebite.cpp / testclientsnakebite.h</li>
00275 </ul>
00276 
00277 <h3>Server Files</h3>
00278 <ul>
00279    <li>server_main.cpp</li>
00280    <li>testserverframework.cpp / testserverframework.h</li>
00281    <li>testserversnakebite.cpp / testserversnakebite.h</li>
00282 </ul>
00283 
00284 <hr>[Next: @ref Plugins ]
00285 
00286 
00287 @page Plugins Creating Plugins
00288 [To be written]
00289 
00290 <hr>[Next: @ref Installation ]
00291 
00292 
00293 @page Installation Installation
00294 [To be written]
00295 
00296 <h2>Dependencies</h2>
00297 The framework uses <a href="http://www.gnu.org/software/commoncpp/">"Common C++"</a>. And the testapplication uses SDL, SDL_image, SDL_ttf.
00298 
00299 <hr>[Next: @ref Misc ]
00300 
00301 
00302 
00303 
00304 
00305 @page Misc Miscellaneous
00306 <h2>Wordlist</h2>
00307 - @anchor UniqueFrameworkID <b> Unique object id </b>: In the server framework of Ganef, every data entity (every object of a class derived from ServerData) will be given a unique id (unsigned integer 32 bit). This id will be used to uniquely identify the object, both on the server and on the client.
00308 - @anchor MainLoop <b> Main loop</b>: most games have some method containing a while-loop where all the game-related things are done. This would on the client often include: (process any user input) (get any data sent from the server) (draw the gameworld to the screen). On the server it could include: (get and process any actions sent from clients) (integrate the gameworld with time elapsed since last iteration) (send any updates to clients).
00309 
00310 
00311 */

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