Index: /code/branches/netp3/src/network/TrafficControl.cc
===================================================================
--- /code/branches/netp3/src/network/TrafficControl.cc	(revision 3042)
+++ /code/branches/netp3/src/network/TrafficControl.cc	(revision 3043)
@@ -142,24 +142,28 @@
     assert(clientListTemp_.find(clientID) != clientListTemp_.end() );
     assert(clientListPerm_.find(clientID) != clientListPerm_.end() );
-	  assert( clientListTemp_[clientID].find(gamestateID) != clientListTemp_[clientID].end() );
-
-    for(itvec = clientListTemp_[clientID][gamestateID].begin(); itvec != clientListTemp_[clientID][gamestateID].end(); itvec++)
+    assert( clientListTemp_[clientID].find(gamestateID) != clientListTemp_[clientID].end() );
+    
+    // shortcut for maps
+    std::map<unsigned int, objInfo >& objectListPerm = clientListPerm_[clientID];
+    std::map<unsigned int, std::vector<obj> >& objectListTemp = clientListTemp_[clientID];
+
+    for(itvec = objectListTemp[gamestateID].begin(); itvec != objectListTemp[gamestateID].end(); itvec++)
 	  {
-      if(clientListPerm_[clientID].find((*itvec).objID) != clientListPerm_[clientID].end()) // check whether the obj already exists in our lists
-      {
-        clientListPerm_[clientID][(*itvec).objID].objCurGS = gamestateID;
-        clientListPerm_[clientID][(*itvec).objID].objValueSched = 0; //set scheduling value back
+      if(objectListPerm.find((*itvec).objID) != objectListPerm.end()) // check whether the obj already exists in our lists
+      {
+        objectListPerm[(*itvec).objID].objCurGS = gamestateID;
+        objectListPerm[(*itvec).objID].objValueSched = 0; //set scheduling value back
       }
       else
       {
         assert(0);
-        clientListPerm_[clientID][(*itvec).objID].objCurGS = gamestateID;
-        clientListPerm_[clientID][(*itvec).objID].objID = (*itvec).objID;
-        clientListPerm_[clientID][(*itvec).objID].objCreatorID = (*itvec).objCreatorID;
-        clientListPerm_[clientID][(*itvec).objID].objSize = (*itvec).objSize;
+        objectListPerm[(*itvec).objID].objCurGS = gamestateID;
+        objectListPerm[(*itvec).objID].objID = (*itvec).objID;
+        objectListPerm[(*itvec).objID].objCreatorID = (*itvec).objCreatorID;
+        objectListPerm[(*itvec).objID].objSize = (*itvec).objSize;
       }
 	  }
 	   // remove temporary list (with acked objects) from the map
-    clientListTemp_[clientID].erase( clientListTemp_[clientID].find(gamestateID) );
+    objectListTemp.erase( objectListTemp.find(gamestateID) );
 	}
 
@@ -227,11 +231,14 @@
     //if listToProcess contains new Objects, add them to clientListPerm
     std::vector<obj>::iterator itvec;
+    
+    std::map<unsigned int, objInfo >& objectListPerm = clientListPerm_[clientID];
+    
 	  for( itvec=list.begin(); itvec != list.end(); itvec++)
 	  {
-	    if ( clientListPerm_[clientID].find( (*itvec).objID) != clientListPerm_[clientID].end() )
+	    if ( objectListPerm.find( (*itvec).objID) != objectListPerm.end() )
       {
         // we already have the object in our map
         //obj bleibt in liste und permanente prio wird berechnet
-        clientListPerm_[clientID][(*itvec).objID].objDiffGS = currentGamestateID - clientListPerm_[clientID][(*itvec).objID].objCurGS;
+        objectListPerm[(*itvec).objID].objDiffGS = currentGamestateID - objectListPerm[(*itvec).objID].objCurGS;
         continue;//check next objId
       }
Index: /code/branches/netp3/src/network/packet/Gamestate.cc
===================================================================
--- /code/branches/netp3/src/network/packet/Gamestate.cc	(revision 3042)
+++ /code/branches/netp3/src/network/packet/Gamestate.cc	(revision 3043)
@@ -110,5 +110,5 @@
 
     tempsize = it->getData(mem, id, mode);
-    if ( it->doSync( id, mode ) )
+    if ( tempsize != 0 )
       dataVector_.push_back( obj(it->getObjectID(), it->getCreatorID(), tempsize, mem-data_) );
     
@@ -339,16 +339,46 @@
   uint8_t *ndata = new uint8_t[dest_length*sizeof(uint8_t)+GamestateHeader::getSize()];
   uint8_t *dest = ndata + GamestateHeader::getSize();
-  while(of < diffHeader.getDataSize() && of < header_->getDataSize()){
-    *(dest+of)=*(basep+of)^*(gs+of); // do the xor
-    ++of;
-  }
-  if(diffHeader.getDataSize()!=header_->getDataSize()){
-    uint8_t n=0;
-    if(diffHeader.getDataSize() < header_->getDataSize()){
-      while(of<dest_length){
-        *(dest+of)=n^*(gs+of);
-        of++;
-      }
-    }
+  
+  
+  // LOOP-UNROLLED DIFFING
+  uint32_t *dest32 = (uint32_t*)dest, *base32 = (uint32_t*)basep, *gs32 = (uint32_t*)gs;
+  // diff in 4-byte steps
+  while( of < (uint32_t)(header_->getDataSize())/4 ){
+    if( of < (uint32_t)(diffHeader.getDataSize())/4 )
+    {
+      *(dest32+of)=*(base32+of) ^ *(gs32+of); // do the xor
+      ++of;
+    } else
+    {
+      *(dest32+of)=*(gs32+of); // same as 0 ^ *(gs32+of)
+      ++of;
+    }
+  }
+  uint32_t base_rest = 0;
+  // fill the base_rest first with 0 and then with the remaining bytes in base32
+  switch( diffHeader.getDataSize()%sizeof(uint32_t) )
+  {
+    case 3:
+      *((uint8_t*)(&base_rest)+2) = *((uint8_t*)(base32+of-1)+2); // save the last byte to the buffer
+    case 2:
+      *((uint16_t*)(&base_rest)) = *((uint16_t*)(base32+of-1)); // xor 2 bytes at once (either 2nd and 3rd last or the 2 last bytes)
+      break;
+    case 1:
+      *((uint8_t*)(&base_rest)) = *((uint8_t*)(base32+of-1)); // xor the last byte
+    case 0:
+      break; // leave 0
+  }
+  // now diff the rest and save it to dest32 in 2- and 1-byte steps
+  switch( header_->getDataSize()%sizeof(uint32_t) )
+  {
+    case 3:
+      *((uint8_t*)(dest32+of)+2) = *((uint8_t*)&base_rest+2) ^ *((uint8_t*)(gs32+of-1)+2); // save the last byte to the buffer
+    case 2:
+      *((uint16_t*)(dest32+of)) = *((uint16_t*)&base_rest) ^ *((uint16_t*)(gs32+of-1)); // xor 2 bytes at once (either 2nd and 3rd last or the 2 last bytes)
+      break;
+    case 1:
+      *((uint8_t*)(dest32+of)) = *((uint8_t*)&base_rest) ^ *((uint8_t*)(gs32+of-1)); // xor the last byte
+    case 0:
+      break;
   }
 
Index: /code/branches/netp3/src/orxonox/objects/worldentities/PongBall.cc
===================================================================
--- /code/branches/netp3/src/orxonox/objects/worldentities/PongBall.cc	(revision 3042)
+++ /code/branches/netp3/src/orxonox/objects/worldentities/PongBall.cc	(revision 3043)
@@ -32,5 +32,4 @@
 #include "core/CoreIncludes.h"
 #include "core/GameMode.h"
-#include "objects/worldentities/PongBat.h"
 #include "objects/gametypes/Gametype.h"
 
@@ -47,5 +46,16 @@
         this->speed_ = 0;
         this->bat_ = 0;
+        this->batID_ = new unsigned int[2];
+        this->batID_[0] = OBJECTID_UNKNOWN;
+        this->batID_[1] = OBJECTID_UNKNOWN;
         this->relMercyOffset_ = 0.05;
+        
+        this->registerVariables();
+    }
+    
+    void PongBall::registerVariables()
+    {
+        registerVariable( this->batID_[0] );
+        registerVariable( this->batID_[1], variableDirection::toclient, new NetworkCallback<PongBall>( this, &PongBall::applyBats) );
     }
 
@@ -119,4 +129,53 @@
                 this->setPosition(position);
         }
+        else
+        {
+          Vector3 position = this->getPosition();
+          Vector3 velocity = this->getVelocity();
+
+          if (position.z > this->fieldHeight_ / 2 || position.z < -this->fieldHeight_ / 2)
+          {
+            velocity.z = -velocity.z;
+
+            if (position.z > this->fieldHeight_ / 2)
+              position.z = this->fieldHeight_ / 2;
+            if (position.z < -this->fieldHeight_ / 2)
+              position.z = -this->fieldHeight_ / 2;
+          }
+
+          if (position.x > this->fieldWidth_ / 2 || position.x < -this->fieldWidth_ / 2)
+          {
+            float distance = 0;
+
+            if (this->bat_)
+            {
+              if (position.x > this->fieldWidth_ / 2 && this->bat_[1])
+              {
+                distance = (position.z - this->bat_[1]->getPosition().z) / (this->fieldHeight_ * (this->batlength_ * 1.10) / 2);
+                if (fabs(distance) <= 1)
+                {
+                  position.x = this->fieldWidth_ / 2;
+                  velocity.x = -velocity.x;
+                  velocity.z = distance * distance * sgn(distance) * PongBall::MAX_REL_Z_VELOCITY * this->speed_;
+                }
+              }
+              if (position.x < -this->fieldWidth_ / 2 && this->bat_[0])
+              {
+                distance = (position.z - this->bat_[0]->getPosition().z) / (this->fieldHeight_ * (this->batlength_ * 1.10) / 2);
+                if (fabs(distance) <= 1)
+                {
+                  position.x = -this->fieldWidth_ / 2;
+                  velocity.x = -velocity.x;
+                  velocity.z = distance * distance * sgn(distance) * PongBall::MAX_REL_Z_VELOCITY * this->speed_;
+                }
+              }
+            }
+          }
+
+          if (velocity != this->getVelocity())
+            this->setVelocity(velocity);
+          if (position != this->getPosition())
+            this->setPosition(position);
+        }
     }
 
Index: /code/branches/netp3/src/orxonox/objects/worldentities/PongBall.h
===================================================================
--- /code/branches/netp3/src/orxonox/objects/worldentities/PongBall.h	(revision 3042)
+++ /code/branches/netp3/src/orxonox/objects/worldentities/PongBall.h	(revision 3043)
@@ -33,4 +33,5 @@
 
 #include "objects/worldentities/MovableEntity.h"
+#include "objects/worldentities/PongBat.h"
 
 namespace orxonox
@@ -43,4 +44,6 @@
 
             virtual void tick(float dt);
+            
+            void registerVariables();
 
             void setFieldDimension(float width, float height)
@@ -61,5 +64,8 @@
 
             void setBats(PongBat** bats)
-                { this->bat_ = bats; }
+            { this->bat_ = bats; this->batID_[0] = this->bat_[0]->getObjectID(); this->batID_[1] = this->bat_[1]->getObjectID(); }
+            
+            void applyBats()
+            { if(!this->bat_) this->bat_ = new PongBat*[2]; if(this->batID_[0] != OBJECTID_UNKNOWN) this->bat_[0] = dynamic_cast<PongBat*>(Synchronisable::getSynchronisable(this->batID_[0])); if(this->batID_[1] != OBJECTID_UNKNOWN) this->bat_[1] = dynamic_cast<PongBat*>(Synchronisable::getSynchronisable(this->batID_[1])); }
 
             static const float MAX_REL_Z_VELOCITY;
@@ -71,4 +77,5 @@
             float batlength_;
             PongBat** bat_;
+            unsigned int* batID_;
             float relMercyOffset_;
     };
