Index: trunk/src/lib/network/synchronizeable.cc
===================================================================
--- trunk/src/lib/network/synchronizeable.cc	(revision 6753)
+++ trunk/src/lib/network/synchronizeable.cc	(revision 7954)
@@ -20,4 +20,5 @@
 #include "network_stream.h"
 #include "netdefs.h"
+#include "network_log.h"
 
 #include "state.h"
@@ -36,13 +37,10 @@
   this->setClassID(CL_SYNCHRONIZEABLE, "Synchronizeable");
   this->owner = -1;
-  this->state = 0;
   this->hostID = SharedNetworkData::getInstance()->getHostID();
   this->setIsServer(this->hostID == 0);
   this->uniqueID = NET_UID_UNASSIGNED;
   this->networkStream = NULL;
-  this->setRequestedSync( false );
-  this->setIsOutOfSync( !(this->isServer()) );
   this->bSynchronize = false;
-
+  
   if( State::isOnline())
   {
@@ -52,4 +50,11 @@
     this->setUniqueID(SharedNetworkData::getInstance()->getNewUniqueID());
   }
+
+  /* make sure loadClassId is first synced var because this is read by networkStream */
+  assert( syncVarList.size() == 0 );
+  mLeafClassId = this->registerVarId( new SynchronizeableInt( (int*)&this->getLeafClassID(), (int*)&this->getLeafClassID(), "leafClassId" ) );
+    
+  this->registerVar( new SynchronizeableInt( &this->owner, &this->owner, "owner" ) );
+  this->registerVar( new SynchronizeableString( &this->objectName, &this->objectName, "objectName" ) );
 }
 
@@ -64,31 +69,4 @@
     this->networkStream->disconnectSynchronizeable(*this);
 }
-
-
-/**
- *  write data to NetworkStream
- */
-int Synchronizeable::writeBytes(const byte* data, int length, int sender)
-{
-  PRINTF(5)("Synchronizeable::writeBytes was called\n");
-}
-
-
-/**
- *  read data from NetworkStream
- */
-int Synchronizeable::readBytes(byte* data, int maxLength, int * reciever)
-{
-  PRINTF(5)("Synchronizeable::readBytes was called\n");
-}
-
-
-void Synchronizeable::writeDebug() const
-{}
-
-
-void Synchronizeable::readDebug() const
-{}
-
 
 /**
@@ -106,18 +84,4 @@
 
 /**
- * Sets the outofsync flag to a given value
- * @param outOfSync: the boolean value which the outofsync flag is to set to
- */
-void Synchronizeable::setIsOutOfSync(bool outOfSync)
-{
-  if( outOfSync )
-    this->state = this->state | STATE_OUTOFSYNC;
-  else
-    this->state = this->state & (~STATE_OUTOFSYNC);
-  //PRINTF(0)("isoutofsync %s %d\n", this->getClassName(), state);
-}
-
-
-/**
  * Determines if the server flag is set
  * @return true, if the server flag is true, false else
@@ -129,36 +93,453 @@
 
 
-/**
- * Determines if the outofsync flag is set
- * @return true, if the outofsync flag is true, false else
- */
-bool Synchronizeable::isOutOfSync()
-{
-  return (this->state & STATE_OUTOFSYNC) >0;
-}
-
-
-/**
- * Determines if the requestedSync flag is set
- * @return true, if the requestedSync flag is true, false else
- */
-bool Synchronizeable::requestedSync()
-{
-  return (this->state & STATE_REQUESTEDSYNC) >0;
-}
-
-
-/**
- * Sets the requestedsync flag to a given value
- * @param requestedSync: the boolean value which the requestedsync flag is to set to
- */
-void Synchronizeable::setRequestedSync( bool requestedSync )
-{
-  if( requestedSync )
-    this->state = this->state | STATE_REQUESTEDSYNC;
+
+int Synchronizeable::getStateDiff( int userId, byte* data, int maxLength, int stateId, int fromStateId, int priorityTH )
+{
+  //make sure this user has his history
+  if ( sentStates.size() <= userId )
+    sentStates.resize( userId+1 );
+
+  //calculate needed memory
+  int neededSize = 0;
+
+  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
+    neededSize += (*it)->getSize();
+
+  if ( !( neededSize <= maxLength ) )
+  {
+    PRINTF(0)( "%d > %d\n", neededSize, maxLength );
+    assert(false);
+  }
+
+  //remove older states from history than fromStateId
+  StateHistory::iterator it = sentStates[userId].begin();
+
+  while ( it != sentStates[userId].end() && (*it)->stateId < fromStateId )
+    it++;
+
+  if ( it != sentStates[userId].begin() )
+  {
+    for ( StateHistory::iterator it2 = sentStates[userId].begin(); it2 != it; it2++ )
+    {
+      if ( (*it2)->data != NULL )
+      {
+        delete [] (*it2)->data;
+        (*it2)->data = NULL;
+      }
+    }
+    sentStates[userId].erase( sentStates[userId].begin(), it );
+  }
+
+  //find state to create diff from
+  StateHistoryEntry * stateFrom = NULL;
+
+  it = sentStates[userId].begin();
+  while ( it != sentStates[userId].end() && (*it)->stateId != fromStateId )
+    it++;
+  
+//  if ( getLeafClassID() == CL_SPACE_SHIP )
+//  {
+//    PRINTF(0)("getStateDiff:SpaceShip from: %d stateId: %d\n", (it == sentStates[userId].end())?-1:fromStateId, stateId);
+//  }
+
+  if ( it == sentStates[userId].end() )
+  {
+    StateHistoryEntry * initialEntry = new StateHistoryEntry();
+
+    initialEntry->stateId = fromStateId;
+    initialEntry->dataLength = 0;
+    initialEntry->data = NULL;
+
+    stateFrom = initialEntry;
+  }
   else
-    this->state = this->state & (~STATE_REQUESTEDSYNC);
-}
-
-
-
+    stateFrom = (*it);
+
+  StateHistoryEntry * stateTo = new StateHistoryEntry();
+
+  stateTo->stateId = stateId;
+  stateTo->dataLength = neededSize;
+  stateTo->data = new byte[ neededSize ];
+
+  std::list<int>::iterator sizeIter = stateFrom->sizeList.begin();
+
+  int i = 0;
+  int n;
+  
+  bool hasPermission;
+
+  // now do the actual synchronization: kick all variables to write into a common buffer
+  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
+  {
+    hasPermission = (
+            this->isServer() && (*it)->checkPermission( PERMISSION_SERVER ) ||
+            this->owner == this->hostID && (*it)->checkPermission( PERMISSION_OWNER ) ||
+            (*it)->checkPermission( PERMISSION_ALL ) 
+                    );
+    
+    if ( ( hasPermission && (*it)->getPriority() >= priorityTH ) || sizeIter == stateFrom->sizeList.end() )
+    {
+      n = (*it)->writeToBuf( stateTo->data+i, stateTo->dataLength - i );
+      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), n);
+      stateTo->sizeList.push_back( n );
+      //(*it)->debug();
+      i += n;
+    }
+    else
+    {
+      for ( int j = 0; j<(*sizeIter); j++ )
+      {
+        assert( i < stateFrom->dataLength );
+        stateTo->data[i] = stateFrom->data[i];
+        i++;
+      }
+      //NETPRINTF(0)("getvar %s %d\n", (*it)->getName().c_str(), *sizeIter);
+      stateTo->sizeList.push_back( (*sizeIter) );
+    }
+
+    if ( sizeIter != stateFrom->sizeList.end() )
+      sizeIter++;
+  }
+
+  sentStates[userId].push_back( stateTo );
+  
+  assert( i == neededSize );
+
+  //write diff to data
+  for ( i = 0; i<neededSize; i++ )
+  {
+    if ( i < stateFrom->dataLength )
+      data[i] = stateTo->data[i] - stateFrom->data[i];
+    else
+      data[i] = stateTo->data[i];
+  }
+
+  return neededSize;
+}
+
+/**
+ * sets a new state out of a diff created on another host
+ * @param userId hostId of user who send me that diff
+ * @param data pointer to diff
+ * @param length length of diff
+ * @param stateId id of current state
+ * @param fromStateId id of the base state id
+ * @return number bytes read
+ * @todo check for permissions
+ */
+int Synchronizeable::setStateDiff( int userId, byte* data, int length, int stateId, int fromStateId )
+{
+  //make sure this user has his history
+  if ( recvStates.size() <= userId )
+    recvStates.resize( userId+1 );
+
+  //create new state
+  StateHistoryEntry * stateTo = new StateHistoryEntry();
+  stateTo->stateId = stateId;
+  stateTo->dataLength = length;
+  stateTo->data = new byte[ length ];
+
+
+  //find state to apply diff to
+  StateHistoryEntry * stateFrom = NULL;
+
+  StateHistory::iterator it = recvStates[userId].begin();
+  while ( it != recvStates[userId].end() && (*it)->stateId != fromStateId )
+    it++;
+
+  
+//  if ( getLeafClassID() == CL_SPACE_SHIP )
+//  {
+//    PRINTF(0)("setStateDiff:SpaceShip from: %d stateId: %d\n", (it == recvStates[userId].end())?-1:fromStateId, stateId);
+//  }
+
+  if ( it == recvStates[userId].end() )
+  {
+    StateHistoryEntry * initialEntry = new StateHistoryEntry();
+
+    initialEntry->stateId = fromStateId;
+    initialEntry->dataLength = 0;
+    initialEntry->data = NULL;
+
+    stateFrom = initialEntry;
+  }
+  else
+    stateFrom = (*it);
+  
+  //apply diff
+  for ( int i = 0; i<length; i++ )
+  {
+    if ( i < stateFrom->dataLength )
+      stateTo->data[i] = stateFrom->data[i] + data[i];
+    else
+      stateTo->data[i] = data[i];
+    
+  }
+  
+  //add state to state history
+  recvStates[userId].push_back( stateTo );
+  
+  int i = 0;
+  int n = 0;
+  std::list<int> changes;
+  
+  for ( SyncVarList::iterator it = syncVarList.begin(); it != syncVarList.end(); it++ )
+  {
+    if (
+        (*it)->checkPermission( PERMISSION_SERVER ) && networkStream->isUserServer( userId ) ||
+        (*it)->checkPermission( PERMISSION_OWNER ) && this->owner == userId ||
+        (*it)->checkPermission( PERMISSION_ALL ) 
+       )
+    {
+      n = (*it)->readFromBuf( stateTo->data + i, stateTo->dataLength - i );
+      i += n;
+      //NETPRINTF(0)("%s::setvar %s %d\n", getClassName(), (*it)->getName().c_str(), n);
+      //(*it)->debug();
+      if ( (*it)->getHasChanged() )
+      {
+        changes.push_back( (*it)->getVarId() );
+      }
+    }
+    else
+    {
+//      PRINTF(0)("DONT SET VAR BECAUSE OF PERMISSION: %s %d %d %d %d %d %d\n", (*it)->getName().c_str(), (*it)->checkPermission( PERMISSION_SERVER ), (*it)->checkPermission( PERMISSION_OWNER ), (*it)->checkPermission( PERMISSION_ALL ), networkStream->isUserServer( userId ), this->owner, userId );
+      n = (*it)->getSizeFromBuf( stateTo->data + i, stateTo->dataLength - i );
+      //NETPRINTF(0)("%s::setvar %s %d\n", getClassName(), (*it)->getName().c_str(), n);
+      //(*it)->debug();
+      i += n;
+    }
+  }
+
+  this->varChangeHandler( changes );
+  
+  return i;
+}
+
+ /**
+ * override this function to be notified on change
+ * of your registred variables.
+ * @param id id's which have changed
+ */
+void Synchronizeable::varChangeHandler( std::list<int> & id )
+{
+}
+
+/**
+ * registers a varable to be synchronized over network
+ * @param var see src/lib/network/synchronizeable_var/ for available classes
+ */
+void Synchronizeable::registerVar( SynchronizeableVar * var )
+{
+  PRINTF(0)("ADDING VAR: %s\n", var->getName().c_str());
+  syncVarList.push_back( var );
+}
+
+/**
+ * registers a varable to be synchronized over network
+ * return value is passed to varChangeHandler on change
+ * @param var see src/lib/network/synchronizeable_var/ for available classes
+ * @return handle passed to varChangeHandler on changes
+ */
+int Synchronizeable::registerVarId( SynchronizeableVar * var )
+{
+  PRINTF(0)("ADDING VAR: %s\n", var->getName().c_str());
+  syncVarList.push_back( var );
+  var->setWatched( true );
+  var->setVarId( syncVarList.size()-1 );
+  return syncVarList.size()-1;
+}
+
+/**
+ * removed user's states from memory
+ * @param userId user to clean
+ */
+void Synchronizeable::cleanUpUser( int userId )
+{
+  for ( UserStateHistory::iterator it = sentStates.begin(); it != sentStates.end(); it++ )
+  {
+    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
+    {
+      if ( (*it2)->data )
+        delete [] (*it2)->data;
+      (*it2)->data = NULL;
+      
+      delete *it2;
+    }
+  }
+  
+  sentStates.clear();
+  
+  for ( UserStateHistory::iterator it = recvStates.begin(); it != recvStates.end(); it++ )
+  {
+    for ( StateHistory::iterator it2 = it->begin(); it2 != it->end(); it2++ )
+    {
+      if ( (*it2)->data )
+        delete [] (*it2)->data;
+      (*it2)->data = NULL;
+      
+      delete *it2;
+    }
+  }
+  
+  recvStates.clear();
+}
+
+/**
+ * this function is called after recieving a state.
+ * @param userId 
+ * @param stateId 
+ * @param fromStateId 
+ */
+void Synchronizeable::handleRecvState( int userId, int stateId, int fromStateId )
+{
+   //make sure this user has his history
+  if ( recvStates.size() <= userId )
+    recvStates.resize( userId+1 );
+  
+  //remove old states
+  StateHistory::iterator it = recvStates[userId].begin();
+
+#if 0
+  while ( it != recvStates[userId].end() && (*it)->stateId < fromStateId )
+    it++;
+
+  if ( it != recvStates[userId].begin() )
+  {
+    for ( StateHistory::iterator it2 = recvStates[userId].begin(); it2 != it; it2++ )
+    {
+      if ( (*it2)->data != NULL )
+      {
+        delete [] (*it2)->data;
+        (*it2)->data = NULL;
+      }
+    }
+    recvStates[userId].erase( recvStates[userId].begin(), it );
+  }
+#endif
+
+  for ( it = recvStates[userId].begin(); it != recvStates[userId].end();  )
+  {
+    if ( (*it)->stateId < fromStateId )
+    {
+      StateHistory::iterator delIt = it;
+      it ++;
+      
+      if ( (*delIt)->data )
+        delete [] (*delIt)->data;
+      recvStates[userId].erase( delIt );
+      
+      continue;
+    }
+    it++;
+  }
+  
+  StateHistory::iterator fromState = recvStates[userId].end();
+  StateHistory::iterator toState = recvStates[userId].end();
+  
+  for ( it = recvStates[userId].begin(); it != recvStates[userId].end(); it++ )
+  {
+    if ( (*it)->stateId == stateId )
+      toState = it;
+    if ( (*it)->stateId == fromStateId )
+      fromState = it;
+    
+    if ( fromState != recvStates[userId].end() && toState != recvStates[userId].end() )
+      break;
+  }
+  
+  // setStateDiff was not called and i know fromStateId
+  if ( fromState != recvStates[userId].end() && toState == recvStates[userId].end() )
+  {
+    StateHistoryEntry * entry = new StateHistoryEntry;
+    
+    entry->dataLength = (*fromState)->dataLength;
+    if ( entry->dataLength > 0 )
+    {
+      entry->data = new byte[entry->dataLength];
+          
+      assert( (*fromState)->data );
+      memcpy( entry->data, (*fromState)->data, entry->dataLength );
+    }
+    else
+      entry->data = NULL;
+    
+    entry->sizeList = (*fromState)->sizeList;
+    entry->stateId = stateId;
+    
+    recvStates[userId].push_back(entry);
+  }
+}
+
+/**
+ * this function is called after sending a state
+ * @param userId 
+ * @param stateId 
+ * @param fromStateId 
+ */
+void Synchronizeable::handleSentState( int userId, int stateId, int fromStateId )
+{
+   //make sure this user has his history
+  if ( sentStates.size() <= userId )
+    sentStates.resize( userId+1 );
+
+   //remove old states
+  StateHistory::iterator it = sentStates[userId].begin();
+
+  for ( it = sentStates[userId].begin(); it != sentStates[userId].end();  )
+  {
+    if ( (*it)->stateId < fromStateId )
+    {
+      StateHistory::iterator delIt = it;
+      it ++;
+      
+      if ( (*delIt)->data )
+        delete [] (*delIt)->data;
+      sentStates[userId].erase( delIt );
+      
+      continue;
+    }
+    it++;
+  }
+
+  
+  StateHistory::iterator fromState = sentStates[userId].end();
+  StateHistory::iterator toState = sentStates[userId].end();
+  
+  for ( it = sentStates[userId].begin(); it != sentStates[userId].end(); it++ )
+  {
+    if ( (*it)->stateId == stateId )
+      toState = it;
+    if ( (*it)->stateId == fromStateId )
+      fromState = it;
+    
+    if ( fromState != sentStates[userId].end() && toState != sentStates[userId].end() )
+      break;
+  }
+
+  
+  // getStateDiff was not called and i know fromStateId
+  if ( fromState != sentStates[userId].end() && toState == sentStates[userId].end() )
+  {
+    StateHistoryEntry * entry = new StateHistoryEntry;
+    
+    entry->dataLength = (*fromState)->dataLength;
+    if ( entry->dataLength > 0 )
+    {
+      entry->data = new byte[entry->dataLength];
+      
+      assert( (*fromState)->data );
+      memcpy( entry->data, (*fromState)->data, entry->dataLength );
+    }
+    else
+      entry->data = NULL;
+    
+    entry->sizeList = (*fromState)->sizeList;
+    entry->stateId = stateId;
+    
+    sentStates[userId].push_back(entry);
+  }
+  
+}
+
+
+
