Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Changeset 436


Ignore:
Timestamp:
Dec 9, 2007, 12:42:46 PM (17 years ago)
Author:
scheusso
Message:

extended gamestatehandling for diffed and not diffed gamestates (initial states, etc)

Location:
code/branches/FICN/src/network
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • code/branches/FICN/src/network/ClientInformation.cc

    r432 r436  
    1616ClientInformation::ClientInformation()
    1717{
     18  gamestateID_=GAMESTATEID_INITIAL;
    1819  preve=0;
    1920  nexte=0;
     21  this->head=false;
     22}
     23
     24ClientInformation::ClientInformation(bool head)
     25{
     26  gamestateID_=GAMESTATEID_INITIAL;
     27  preve=0;
     28  nexte=0;
     29  this->head=head;
    2030}
    2131//
     
    5464}
    5565
    56 void ClientInformation::setPrev(ClientInformation *prev){
    57   this->preve = prev;
     66bool ClientInformation::setPrev(ClientInformation *prev){
     67  if(!head)
     68    this->preve = prev;
     69  else
     70    return false;
     71  return true;
    5872}
    5973
    60 void ClientInformation::setNext(ClientInformation *next){
     74bool ClientInformation::setNext(ClientInformation *next){
    6175  this->nexte = next;
     76  return true;
    6277}
    6378
    64 void ClientInformation::insertAfter(ClientInformation *ins){
     79ClientInformation *ClientInformation::insertAfter(ClientInformation *ins){
    6580  this->nexte->setPrev(ins);
    6681  ins->setNext(this->nexte);
    6782  ins->setPrev(this);
    6883  this->nexte = ins;
     84  return ins;
    6985}
    7086
    71 void ClientInformation::insertBefore(ClientInformation *ins){
     87ClientInformation *ClientInformation::insertBefore(ClientInformation *ins){
    7288  this->prev()->setNext(ins);
    7389  ins->setPrev(this->preve);
    7490  this->preve=ins;
    7591  ins->setNext(this);
     92  return ins;
     93}
     94
     95void ClientInformation::setID(int clientID){
     96  clientID_ = clientID;
     97}
     98void ClientInformation::setPeer(ENetPeer *peer){
     99  peer_ = peer;
     100}
     101
     102void ClientInformation::setGamestateID(int id){
     103  gamestateID_=id;
     104}
     105
     106int ClientInformation::getID(){
     107  return clientID_;
     108}
     109ENetPeer *ClientInformation::getPeer(){
     110  return peer_;
     111}
     112
     113int ClientInformation::getGamestateID(){
     114  return gamestateID_;
     115}
     116
     117ClientInformation *ClientInformation::insertBack(ClientInformation *ins){
     118  ClientInformation *temp = this;
     119  while(temp->next()!=0){
     120    temp = temp->next();
     121  }
     122  temp->setNext(ins);
     123  ins->setPrev(temp);
     124  return ins;
     125}
     126
     127bool ClientInformation::removeClient(int clientID){
     128  ClientInformation *temp = this;
     129  while(temp!=0 && temp->getID()!=clientID)
     130    temp = temp->next();
     131  if(temp==0)
     132    return false;
     133  delete temp;
     134  return true;
     135}
     136
     137bool ClientInformation::removeClient(ENetPeer *peer){
     138  ClientInformation *temp = this;
     139  while(temp!=0 && (temp->getPeer()->address.host!=peer->address.host || temp->getPeer()->address.port!=peer->address.port))
     140    temp = temp->next();
     141  if(temp==0)
     142    return false;
     143  delete temp;
     144  return true;
     145}
     146
     147/**
     148 * This function goes forward through the list and looks for an element with clientID
     149 * This function should only be applied to the head of the list
     150 * @param clientID id to look for
     151 * @return pointer to the element in the list or 0 if the search was unsuccessfull
     152 */
     153ClientInformation *ClientInformation::findClient(int clientID, bool look_backwards){
     154  ClientInformation *temp = this;
     155  while(temp!=0 && temp->getID()!=clientID)
     156    temp = temp->next();
     157  // returns 0 if nothing has been found
     158  return temp;
     159}
     160
     161/**
     162 * This function goes forward through the list and looks for an element with clientID
     163 * This function should only be applied to the head of the list
     164 * @param peer peer to look for
     165 * @return pointer to the element in the list
     166 */
     167ClientInformation *ClientInformation::findClient(ENetAddress *address, bool look_backwards){
     168  ClientInformation *temp = this;
     169  while(temp!=0 && (temp->getPeer()->address.host!=address->host || temp->getPeer()->address.port != address->port))
     170    temp = temp->next();
     171  // returns 0 if nothing has been found
     172  return temp;
    76173}
    77174
  • code/branches/FICN/src/network/ClientInformation.h

    r432 r436  
    1313#define NETWORKCLIENTINFORMATION_H
    1414
     15#include <enet/enet.h>
     16
     17#define GAMESTATEID_INITIAL -1
     18
    1519namespace network {
    1620
     
    2226public:
    2327  ClientInformation();
     28  ClientInformation(bool head);
    2429//   ClientInformation(ClientInformation *prev, ClientInformation *next);
    2530//   ClientInformation(ClientInformation *prev);
     
    2732  ClientInformation *next();
    2833  ClientInformation *prev();
    29   void setNext(ClientInformation *next);
    30   void setPrev(ClientInformation *prev);
    31   void insertAfter(ClientInformation *ins);
    32   void insertBefore(ClientInformation *ins);
     34  bool setNext(ClientInformation *next);
     35  bool setPrev(ClientInformation *prev);
     36  ClientInformation *insertAfter(ClientInformation *ins);
     37  ClientInformation *insertBefore(ClientInformation *ins);
     38  ClientInformation *insertBack(ClientInformation *ins);
     39  void setID(int clientID);
     40  void setPeer(ENetPeer *peer);
     41  void setGamestateID(int id);
     42  int getID();
     43  ENetPeer *getPeer();
     44  int getGamestateID();
     45  bool removeClient(int clientID);
     46  bool removeClient(ENetPeer *peer);
     47  ClientInformation *findClient(int clientID, bool look_backwards=false);
     48  ClientInformation *findClient(ENetAddress *address, bool look_backwards=false);
     49  bool head;
    3350 
    3451private:
    3552  ClientInformation *preve;
    3653  ClientInformation *nexte;
     54  //actual information:
     55  ENetPeer *peer_;
     56  int clientID_;
     57  int gamestateID_;
    3758};
    3859
  • code/branches/FICN/src/network/ConnectionManager.cc

    r415 r436  
    2525  boost::thread_group network_threads;
    2626 
    27   ConnectionManager::ConnectionManager(){
     27  ConnectionManager::ConnectionManager(ClientInformation *head){
    2828    quit=false;
    2929    bindAddress.host = ENET_HOST_ANY;
    3030    bindAddress.port = NETWORK_PORT;
    31   }
    32 
    33   ConnectionManager::ConnectionManager(int port, std::string address){
     31    head_ = head;
     32  }
     33
     34  ConnectionManager::ConnectionManager(int port, std::string address, ClientInformation *head){
    3435    quit=false;
    3536    enet_address_set_host (& bindAddress, address.c_str());
    3637    bindAddress.port = NETWORK_PORT;
    37   }
    38 
    39   ConnectionManager::ConnectionManager(int port, const char *address){
     38    head_ = head;
     39  }
     40
     41  ConnectionManager::ConnectionManager(int port, const char *address, ClientInformation *head){
    4042    quit=false;
    4143    enet_address_set_host (& bindAddress, address);
    4244    bindAddress.port = NETWORK_PORT;
     45    head_ = head;
    4346  }
    4447
     
    5356    ENetAddress address;
    5457    ENetPacket *packet=getPacket(address);
    55     clientID=clientMap.find(address)->second;
     58    clientID=head_->findClient(&address)->getID();
    5659    return packet;
    5760  }
     
    7477
    7578  bool ConnectionManager::addPacket(ENetPacket *packet, ENetPeer *peer){
    76     if(clientVector.size()==0)
    77       return false;
    78     if(enet_peer_send(peer, clientMap.find(peer->address)->second , packet)!=0)
     79    if(enet_peer_send(peer, head_->findClient(&(peer->address))->getID() , packet)!=0)
    7980      return false;
    8081    return true;
     
    8283 
    8384  bool ConnectionManager::addPacket(ENetPacket *packet, int clientID){
    84     if(clientVector.size()==0)
    85       return false;
    86     if(enet_peer_send(&(peerMap.find(clientVector[clientID])->second), clientID, packet)!=0)
     85    if(enet_peer_send(head_->findClient(clientID)->getPeer(), clientID, packet)!=0)
    8786      return false;
    8887    return true;
     
    9089 
    9190  bool ConnectionManager::addPacketAll(ENetPacket *packet){
    92     for(unsigned int i=0; i<clientVector.size(); i++){
    93       if(enet_peer_send(&(peerMap.find(clientVector[i])->second), i, packet)!=0)
     91    for(ClientInformation *i=head_->next(); i!=0; i=i->next()){
     92      if(enet_peer_send(i->getPeer(), i->getID(), packet)!=0)
    9493         return false;
    9594    }
     
    156155 
    157156  void ConnectionManager::disconnectClients(){
    158     bool disconnected=false;
    159157    ENetEvent event;
    160     for(unsigned int i=0; i<clientVector.size(); i++){
    161       enet_peer_disconnect(&(peerMap.find(clientVector[i])->second), 0);
    162       while( !disconnected && enet_host_service(server, &event, NETWORK_WAIT_TIMEOUT) > 0){
    163         switch (event.type)
    164         {
    165           case ENET_EVENT_TYPE_NONE:
    166           case ENET_EVENT_TYPE_CONNECT:
    167           case ENET_EVENT_TYPE_RECEIVE:
    168             enet_packet_destroy(event.packet);
    169             break;
    170           case ENET_EVENT_TYPE_DISCONNECT:
    171             disconnected=true;
    172             break;
    173         }
    174       }
    175       disconnected=false;
     158    ClientInformation *temp = head_->next();
     159    while(temp!=0){
     160      enet_peer_disconnect(temp->getPeer(), 0);
     161      temp = temp->next();
     162    }
     163    temp = temp->next();
     164    while( temp!=0 && enet_host_service(server, &event, NETWORK_WAIT_TIMEOUT) > 0){
     165      switch (event.type)
     166      {
     167        case ENET_EVENT_TYPE_NONE:
     168        case ENET_EVENT_TYPE_CONNECT:
     169        case ENET_EVENT_TYPE_RECEIVE:
     170          enet_packet_destroy(event.packet);
     171          break;
     172        case ENET_EVENT_TYPE_DISCONNECT:
     173          delete head_->findClient(&(event.peer->address));
     174          temp = temp->next();
     175          break;
     176      }
    176177    }
    177178    return;
     
    184185  }
    185186
     187//   bool ConnectionManager::clientDisconnect(ENetPeer *peer){
     188//     return clientDisconnect(*peer);
     189//   }
     190 
     191 
     192 
    186193  bool ConnectionManager::clientDisconnect(ENetPeer *peer){
    187     return clientDisconnect(*peer);
    188   }
    189  
    190   bool ConnectionManager::clientDisconnect(ENetPeer peer){
    191     std::map<ENetAddress, int>::iterator it;
    192     it=clientMap.find(peer.address);
    193     clientVector.erase(clientVector.begin()+it->second);
    194     clientMap.erase(it);
    195     peerMap.erase(peerMap.find(peer.address));
     194    return head_->removeClient(peer);
    196195    return true;
    197196  }
    198197
    199198  bool ConnectionManager::addClient(ENetEvent *event){
    200     int id=clientVector.size();
    201     clientVector.push_back((event->peer->address));
    202     clientMap[event->peer->address]=id;
    203     peerMap[event->peer->address]=*(event->peer);
    204     syncClassid(id);
     199    ClientInformation *temp = head_->insertBack(new ClientInformation);
     200    temp->setID(temp->prev()->getID());
     201    temp->setPeer(event->peer);
    205202    return true;
    206203  }
    207204 
    208205  int ConnectionManager::getClientID(ENetPeer peer){
    209     return clientMap.find(peer.address)->second;
     206    return getClientID(peer.address);
    210207  }
    211208 
    212209  int ConnectionManager::getClientID(ENetAddress address){
    213     return clientMap.find(address)->second;
    214   }
    215  
    216   ENetPeer ConnectionManager::getClientPeer(int clientID){
    217     return peerMap.find(clientVector[clientID])->second;
     210    return head_->findClient(&address)->getID();
     211  }
     212 
     213  ENetPeer *ConnectionManager::getClientPeer(int clientID){
     214    return head_->findClient(clientID)->getPeer();
    218215  }
    219216 
  • code/branches/FICN/src/network/ConnectionManager.h

    r400 r436  
    2323#include <boost/bind.hpp>
    2424// headerfiles
     25#include "ClientInformation.h"
    2526#include "ConnectionManager.h"
    2627#include "PacketBuffer.h"
     
    4748  class ConnectionManager{
    4849    public:
    49     ConnectionManager();
    50     ConnectionManager(int port, const char *address);
    51     ConnectionManager(int port, std::string address);
     50    ConnectionManager(ClientInformation *head);
     51    ConnectionManager(int port, const char *address, ClientInformation *head);
     52    ConnectionManager(int port, std::string address, ClientInformation *head);
    5253    ENetPacket *getPacket(ENetAddress &address); // thread1
    5354    ENetPacket *getPacket(int &clientID);
     
    6061    bool sendPackets(ENetEvent *event);
    6162    bool sendPackets();
    62     private:
     63  private:
    6364    bool clientDisconnect(ENetPeer *peer);
    64     bool clientDisconnect(ENetPeer peer);
     65    //bool clientDisconnect(ENetPeer peer);
    6566    bool processData(ENetEvent *event);
    6667    bool addClient(ENetEvent *event);
     
    7071    int getClientID(ENetAddress address);
    7172    void syncClassid(int clientID);
    72     ENetPeer getClientPeer(int clientID);
     73    ENetPeer *getClientPeer(int clientID);
    7374    PacketBuffer buffer;
    7475    PacketGenerator packet_gen;
     
    7879   
    7980    bool quit; // quit-variable (communication with threads)
    80     std::map<ENetAddress, int> clientMap;
    81     std::map<ENetAddress, ENetPeer> peerMap;
    82     std::vector<ENetAddress> clientVector;
     81    ClientInformation *head_;
    8382  };
    8483
  • code/branches/FICN/src/network/GameStateClient.cc

    r416 r436  
    1313
    1414bool GameStateClient::pushGameState(GameStateCompressed compstate){
    15   return loadSnapshot(decode(reference, compstate));
     15  if(compstate.diffed)
     16    return loadSnapshot(decode(reference, compstate));
     17  else
     18    return loadSnapshot(decode(compstate));
    1619}
    1720
     
    127130  gamestate.size = normsize;
    128131  gamestate.data = dest;
     132  gamestate.diffed = a.diffed;
    129133 
    130134  return gamestate;
     
    137141}
    138142
     143GameState GameStateClient::decode(GameStateCompressed x){
     144  GameState t = decompress(x);
     145  return t;
     146}
     147
    139148
    140149
  • code/branches/FICN/src/network/GameStateClient.h

    r416 r436  
    3333  GameState decompress(GameStateCompressed a);
    3434  GameState decode(GameState a, GameStateCompressed x);
     35  GameState decode(GameStateCompressed x);
    3536  void removeObject(orxonox::Iterator<Synchronisable> &it);
    3637 
  • code/branches/FICN/src/network/GameStateManager.cc

    r425 r436  
    1414namespace network {
    1515
    16 GameStateManager::GameStateManager()
     16GameStateManager::GameStateManager(ClientInformation *head)
    1717{
    1818  id=0;
     19  head_=head;
    1920}
    2021
     
    2526void GameStateManager::update(){
    2627  reference = getSnapshot(id);
    27   idGameState[id]=reference;
     28  gameStateMap.insert(std::pair<int, GameState*>(id, reference));
     29  gameStateUsed[id]=0;
    2830  ++id;
    2931  return;
     
    3133
    3234GameStateCompressed GameStateManager::popGameState(int clientID){
    33   GameState *client = clientGameState[clientID];
     35  int gID = head_->findClient(clientID)->getGamestateID();
     36  if(gID!=GAMESTATEID_INITIAL){
     37    GameState *client = gameStateMap[gID];
     38    GameState *server = reference;
     39    return encode(client, server);
     40  }
    3441  GameState *server = reference;
    35   return encode(client, server);
     42  return encode(server);
     43  // return an undiffed gamestate and set appropriate flags
    3644}
    3745
     
    8593
    8694GameStateCompressed GameStateManager::encode(GameState *a, GameState *b){
    87   GameState r = diff(a,b);
    88   return compress_(r);
     95    GameState r = diff(a,b);
     96  r.diffed = true;
     97  return compress_(&r);
    8998}
    9099
     100GameStateCompressed GameStateManager::encode(GameState *a){
     101  a->diffed=false;
     102  return compress_(a);
     103}
    91104
    92105GameState GameStateManager::diff(GameState *a, GameState *b){
     
    122135}
    123136
    124 GameStateCompressed GameStateManager::compress_(GameState a) {
    125   int size = a.size;
    126   uLongf buffer = (uLongf)((a.size + 12)*1.01)+1;
     137GameStateCompressed GameStateManager::compress_(GameState *a) {
     138  int size = a->size;
     139  uLongf buffer = (uLongf)((a->size + 12)*1.01)+1;
    127140  unsigned char* dest = (unsigned char*)malloc( buffer );
    128141  int retval;
    129   retval = compress( dest, &buffer, a.data, (uLong)size ); 
     142  retval = compress( dest, &buffer, a->data, (uLong)size ); 
    130143 
    131144  switch ( retval ) {
     
    141154  compressedGamestate.id = GAMESTATE;
    142155  compressedGamestate.data = dest;
     156  compressedGamestate.diffed = a->diffed;
    143157 
    144158  return compressedGamestate;
     
    146160
    147161void GameStateManager::ackGameState(int clientID, int gamestateID){
     162  ClientInformation *temp = head_->findClient(clientID);
     163  int curid = temp->getID();
     164  // decrease usage of gamestate and save it
     165  deleteUnusedGameState(curid);
     166  //increase gamestateused
     167  ++gameStateUsed.find(gamestateID)->second;
     168  temp->setGamestateID(gamestateID);
     169  /*
    148170  GameState *old = clientGameState[clientID];
    149171  deleteUnusedGameState(old);
    150   clientGameState[clientID]=idGameState[gamestateID];
     172  clientGameState[clientID]=idGameState[gamestateID];*/
    151173}
    152174
    153 bool GameStateManager::deleteUnusedGameState(GameState *state){
    154   for(unsigned int i=0; i<clientGameState.size(); i++){
    155     if(clientGameState[i]==state)
    156       return false;
     175bool GameStateManager::deleteUnusedGameState(int gamestateID){
     176  int used = --(gameStateUsed.find(gamestateID)->second);
     177  if(id-gamestateID>KEEP_GAMESTATES && used==0){
     178    // delete gamestate
     179    delete gameStateMap.find(gamestateID)->second;
     180    gameStateMap.erase(gamestateID);
     181    return true;
    157182  }
    158   delete state;
    159   return true;
    160 }
    161 
    162 void GameStateManager::removeClient(int clientID){
    163   clientGameState.erase(clientGameState.begin()+clientID);
     183  return false;
    164184}
    165185
  • code/branches/FICN/src/network/GameStateManager.h

    r425 r436  
    1313#define NETWORK_GAMESTATEMANAGER_H
    1414
    15 #include <vector>
     15#include <map>
    1616
    1717#include "zlib.h"
    1818
     19#include "ClientInformation.h"
    1920#include "Synchronisable.h"
    2021#include "orxonox/core/IdentifierIncludes.h"
     
    2425namespace network {
    2526
    26 
     27#define KEEP_GAMESTATES 20
    2728
    2829/**
     
    4344class GameStateManager{
    4445public:
    45   GameStateManager();
     46  GameStateManager(ClientInformation *head);
    4647  ~GameStateManager();
    4748  void update();
    4849  GameStateCompressed popGameState(int clientID);
    4950  void ackGameState(int clientID, int gamestateID);
    50   void removeClient(int clientID);
    5151private:
    5252  GameState *getSnapshot(int id);
    5353  GameStateCompressed encode(GameState *a, GameState *b);
     54  GameStateCompressed encode(GameState *a);
    5455  GameState diff(GameState *a, GameState *b);
    55   GameStateCompressed compress_(GameState a);
    56   bool deleteUnusedGameState(GameState *state);
     56  GameStateCompressed compress_(GameState *a);
     57  bool deleteUnusedGameState(int gamestateID);
    5758 
    58   std::vector<GameState *> clientGameState;
    59   std::vector<GameState *> idGameState;
     59  std::map<int, GameState*> gameStateMap; //map gsID to gamestate*
     60  std::map<int, int> gameStateUsed; // save the number of clients, that use the specific gamestate
    6061  GameState *reference;
    6162  int id;
     63  ClientInformation *head_;
    6264};
    6365
  • code/branches/FICN/src/network/PacketTypes.h

    r417 r436  
    3333    int id;
    3434    int size;
     35    // new ---- change functions
     36    bool diffed;
    3537    unsigned char *data;
    3638  };
     
    4648    int compsize;
    4749    int normsize;
     50    // new ----- change functions
     51    bool diffed;
    4852    unsigned char *data;
    4953  };
  • code/branches/FICN/src/network/Server.cc

    r425 r436  
    2121   */
    2222  Server::Server(){
    23     connection = ConnectionManager();
    24     gamestates = GameStateManager();
    2523    packet_gen = PacketGenerator();
     24    clients = new ClientInformation();
     25    connection = new ConnectionManager(clients);
     26    gamestates = new GameStateManager(clients);
    2627  }
    2728
     
    3233   */
    3334  Server::Server(int port, std::string bindAddress){
    34     connection = ConnectionManager(port, bindAddress);
    35     gamestates = GameStateManager();
    3635    packet_gen = PacketGenerator();
     36    clients = new ClientInformation();
     37    connection = new ConnectionManager(port, bindAddress, clients);
     38    gamestates = new GameStateManager(clients);
    3739  }
    3840
     
    4345   */
    4446  Server::Server(int port, const char *bindAddress){
    45     connection = ConnectionManager(port, bindAddress);
    46     gamestates = GameStateManager();
    4747    packet_gen = PacketGenerator();
     48    clients = new ClientInformation();
     49    connection = new ConnectionManager(port, bindAddress, clients);
     50    gamestates = new GameStateManager(clients);
    4851  }
    4952 
     
    5255   */
    5356  void Server::open(){
    54     connection.createListener();
     57    connection->createListener();
    5558    return;
    5659  }
     
    6063   */
    6164  void Server::close(){
    62     connection.quitListener();
     65    connection->quitListener();
    6366    return;
    6467  }
     
    7174  bool Server::sendMSG(std::string msg){
    7275    ENetPacket *packet = packet_gen.chatMessage(msg.c_str());
    73     connection.addPacketAll(packet);
    74     return connection.sendPackets();
     76    connection->addPacketAll(packet);
     77    return connection->sendPackets();
    7578  }
    7679  /**
     
    8184  bool Server::sendMSG(const char *msg){
    8285    ENetPacket *packet = packet_gen.chatMessage(msg);
    83     connection.addPacketAll(packet);
    84     return connection.sendPackets();
     86    connection->addPacketAll(packet);
     87    return connection->sendPackets();
    8588  }
    8689 
     
    101104    ENetPacket *packet;
    102105    int clientID=-1;
    103     while(!connection.queueEmpty()){
    104       packet = connection.getPacket(clientID);
     106    while(!connection->queueEmpty()){
     107      packet = connection->getPacket(clientID);
    105108      elaborate(packet, clientID);
    106109    }
     
    111114   */
    112115  void Server::updateGamestate(){
    113     gamestates.update();
     116    gamestates->update();
    114117    sendGameState();
    115118  }
  • code/branches/FICN/src/network/Server.h

    r422 r436  
    2020#include "GameStateManager.h"
    2121#include "enet/enet.h"
     22#include "ClientInformation.h"
    2223
    2324namespace network{
     
    3940    private:
    4041    bool sendGameState();
    41     ConnectionManager connection;
    42     GameStateManager gamestates;
     42    ConnectionManager *connection;
     43    GameStateManager *gamestates;
    4344    PacketGenerator packet_gen;
    4445   
    4546    void processQueue();
    4647    void updateGamestate();
     48    ClientInformation *clients;
    4749  };
    4850
  • code/branches/FICN/src/network/TODO

    r429 r436  
    33- change ConnectionManager clientlist
    44- change gamestatemanager clientlist
    5 - put them together into ClientInformation
     5- put them together into ClientInformation [done]
    66
    77- do better gamestate-update/snapshot-handling
     8- integrate ClientInformation into gamestatemanager [done]
    89
    910- write dummyserver and dummyclient (chat system)
Note: See TracChangeset for help on using the changeset viewer.