• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

ReplicaManager.cpp

Go to the documentation of this file.
00001 #include "NativeFeatureIncludes.h"
00002 #if _RAKNET_SUPPORT_ReplicaManager==1
00003 
00004 #include "ReplicaManager.h"
00005 #include "RakPeerInterface.h"
00006 #include "GetTime.h"
00007 #include "MessageIdentifiers.h"
00008 #include "BitStream.h"
00009 #include "Replica.h"
00010 #if !defined(_PS3) && !defined(__PS3__) && !defined(SN_TARGET_PS3)
00011 #include <memory.h>
00012 #endif
00013 #include "RakAssert.h"
00014 #include <stdio.h> // For my debug printfs
00015 #include "RakAssert.h"
00016 #include "NetworkIDManager.h"
00017 
00018 #ifdef _MSC_VER
00019 #pragma warning( push )
00020 #endif
00021 
00022 int ReplicaManager::CommandStructComp( Replica* const &key, const ReplicaManager::CommandStruct &data )
00023 {
00024         if (key->GetSortPriority() < data.replica->GetSortPriority())
00025                 return -1;
00026         else if (key->GetSortPriority() > data.replica->GetSortPriority())
00027                 return 1;
00028         if (key->GetAllocationNumber() < data.replica->GetAllocationNumber())
00029                 return -1;
00030         if (key->GetAllocationNumber()==data.replica->GetAllocationNumber())
00031                 return 0;
00032         return 1;
00033 }
00034 
00035 int ReplicaManager::RegisteredReplicaComp( Replica* const &key, const ReplicaManager::RegisteredReplica &data )
00036 {
00037         if (key->GetAllocationNumber() < data.replica->GetAllocationNumber())
00038                 return -1;
00039         if (key->GetAllocationNumber()==data.replica->GetAllocationNumber())
00040                 return 0;
00041         return 1;
00042 }
00043 
00044 int ReplicaManager::RegisteredReplicaRefOrderComp( const unsigned int &key, const ReplicaManager::RegisteredReplica &data )
00045 {
00046         if (key < data.referenceOrder)
00047                 return -1;
00048         if (key==data.referenceOrder)
00049                 return 0;
00050         return 1;
00051 }
00052 
00053 int ReplicaManager::RemoteObjectComp( Replica* const &key, const ReplicaManager::RemoteObject &data )
00054 {
00055         if (key->GetAllocationNumber() < data.replica->GetAllocationNumber())
00056                 return -1;
00057         if (key->GetAllocationNumber()==data.replica->GetAllocationNumber())
00058                 return 0;
00059         return 1;
00060 }
00061 
00062 int ReplicaManager::ParticipantStructComp( const SystemAddress &key, ReplicaManager::ParticipantStruct * const &data )
00063 {
00064         if (key < data->systemAddress)
00065                 return -1;
00066         if (key==data->systemAddress)
00067                 return 0;
00068         return 1;
00069 }
00070 
00071 ReplicaManager::ReplicaManager()
00072 {
00073         _constructionCB=0;
00074         _sendDownloadCompleteCB=0;
00075         _receiveDownloadCompleteCB=0;
00076         sendChannel=0;
00077         autoParticipateNewConnections=false;
00078         defaultScope=false;
00079         autoConstructToNewParticipants=false;
00080         autoSerializeInScope=false;
00081         nextReferenceIndex=0;
00082 #ifdef _DEBUG
00083         inUpdate=false;
00084 #endif
00085 }
00086 ReplicaManager::~ReplicaManager()
00087 {
00088         Clear();
00089 }
00090 void ReplicaManager::SetAutoParticipateNewConnections(bool autoAdd)
00091 {
00092         autoParticipateNewConnections=autoAdd;
00093 }
00094 bool ReplicaManager::AddParticipant(SystemAddress systemAddress)
00095 {
00096         RakAssert(systemAddress!=UNASSIGNED_SYSTEM_ADDRESS);
00097 
00098         // If this player is already in the list of participants, just return.
00099         ParticipantStruct *participantStruct;
00100         participantStruct=GetParticipantBySystemAddress(systemAddress);
00101         if (participantStruct)
00102                 return false;
00103 
00104         // Create a new participant with this systemAddress
00105         participantStruct = RakNet::OP_NEW<ParticipantStruct>( __FILE__, __LINE__ );
00106         participantStruct->systemAddress=systemAddress;
00107 
00108         // Signal that when done sending SendConstruction for each existing object, we call sendDownloadCompleteCB
00109         participantStruct->callDownloadCompleteCB=true;
00110 
00111     // Add the new participant to the list of participants
00112         participantList.Insert(systemAddress,participantStruct, true, __FILE__,__LINE__);
00113 
00114         /*
00115         if (autoConstructToNewParticipants)
00116         {
00117                 // Signal that we need to call SendConstruction for each existing object to this participant
00118                 unsigned i;
00119                 CommandStruct replicaAndCommand;
00120                 replicaAndCommand.command=REPLICA_EXPLICIT_CONSTRUCTION;
00121                 if (defaultScope==true)
00122                         replicaAndCommand.command |= REPLICA_SCOPE_TRUE;
00123                 replicaAndCommand.userFlags=0;
00124 
00125                 // Auto replicate objects in the order they were originally referenced, rather than the random sorted order they are in now
00126                 // This way dependencies are created first.
00127                 DataStructures::OrderedList<unsigned int, RegisteredReplica, ReplicaManager::RegisteredReplicaRefOrderComp> sortByRefList;
00128                 for (i=0; i < replicatedObjects.Size(); i++)
00129                         sortByRefList.Insert(replicatedObjects[i].referenceOrder, replicatedObjects[i]);
00130 
00131                 for (i=0; i < sortByRefList.Size(); i++)
00132                 {
00133                         replicaAndCommand.replica=sortByRefList[i].replica;
00134                         participantStruct->commandList.Insert(replicaAndCommand.replica,replicaAndCommand);
00135                 }
00136         }
00137         */
00138 
00139 
00140         if (autoConstructToNewParticipants)
00141         {
00142                 // Signal that we need to call SendConstruction for each existing object to this participant
00143                 unsigned i;
00144                 CommandStruct replicaAndCommand;
00145                 replicaAndCommand.command=REPLICA_EXPLICIT_CONSTRUCTION;
00146                 if (defaultScope==true)
00147                         replicaAndCommand.command |= REPLICA_SCOPE_TRUE;
00148                 replicaAndCommand.userFlags=0;
00149                 for (i=0; i < replicatedObjects.Size(); i++)
00150                 {
00151                         replicaAndCommand.replica=replicatedObjects[i].replica;
00152                         participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
00153                 }
00154         }
00155 
00156         return true;
00157 }
00158 bool ReplicaManager::RemoveParticipant(SystemAddress systemAddress)
00159 {
00160         RakAssert(systemAddress!=UNASSIGNED_SYSTEM_ADDRESS);
00161 
00162         // Find this participant by systemAddress
00163         ParticipantStruct *participantStruct;
00164         participantStruct=GetParticipantBySystemAddress(systemAddress);
00165 
00166         // If found, remove and free this participant structure
00167         if (participantStruct)
00168         {
00169                 participantList.Remove(systemAddress);
00170                 RakNet::OP_DELETE(participantStruct, __FILE__, __LINE__);
00171                 return true;
00172         }
00173 
00174         return false;
00175 }
00176 
00177 void ReplicaManager::Construct(Replica *replica, bool isCopy, SystemAddress systemAddress, bool broadcast)
00178 {
00179         RakAssert(replica);
00180 
00181         unsigned i;
00182         ParticipantStruct *participantStruct;
00183         CommandStruct replicaAndCommand;
00184         unsigned index;
00185         bool objectExists;
00186         replicaAndCommand.replica=replica;
00187         replicaAndCommand.userFlags=0;
00188     
00189         ReferencePointer(replica);
00190 
00191         for (i=0; i < participantList.Size(); i++)
00192         {
00193                 participantStruct=participantList[i];
00194                 if ((broadcast==true && systemAddress!=participantStruct->systemAddress) || 
00195                         (broadcast==false && systemAddress==participantStruct->systemAddress))
00196                 {
00197                         if (participantStruct->remoteObjectList.HasData(replica)==false)
00198                         {
00199                                 index = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
00200                                 // index = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
00201                                 if (objectExists)
00202                                 {
00203 #ifdef _DEBUG
00204                                         // Implicit is only used for objects that were not already registered.
00205                                         RakAssert(isCopy==false);
00206 #endif
00207                                         participantStruct->commandList[index].command|=REPLICA_EXPLICIT_CONSTRUCTION; // Set this bit
00208                                         participantStruct->commandList[index].command&=0xFF ^ REPLICA_IMPLICIT_CONSTRUCTION; // Unset this bit
00209 
00210                                         if (defaultScope==true && (participantStruct->commandList[index].command & REPLICA_SCOPE_FALSE) == 0)
00211                                                 participantStruct->commandList[index].command |= REPLICA_SCOPE_TRUE;
00212                                 }
00213                                 else
00214                                 {
00215                                         if (isCopy)
00216                                                 replicaAndCommand.command=REPLICA_IMPLICIT_CONSTRUCTION; // Set this bit
00217                                         else
00218                                                 replicaAndCommand.command=REPLICA_EXPLICIT_CONSTRUCTION; // Set this bit
00219 
00220                                         if (defaultScope==true)
00221                                                 replicaAndCommand.command |= REPLICA_SCOPE_TRUE;
00222 
00223                                         participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
00224                                 }
00225                         }
00226                 }
00227         }
00228 
00229         // Update immediately, otherwise if we take action on this object the first frame, the action packets will arrive before the object is created
00230         Update();
00231 }
00232 void ReplicaManager::Destruct(Replica *replica, SystemAddress systemAddress, bool broadcast)
00233 {
00234         RakAssert(replica);
00235 
00236         bool sendTimestamp;
00237         bool objectExists;
00238         unsigned replicatedObjectsIndex;
00239         replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
00240         if (objectExists==false)
00241                 return;
00242 
00243         // For each existing participant, send a packet telling them of this object destruction
00244         RakNet::BitStream outBitstream, userDataBitStream;
00245         unsigned i,tempIndex;
00246         bool replicaReferenced;
00247         ParticipantStruct *participantStruct;
00248         replicaReferenced=false;
00249         for (i=0; i < participantList.Size(); i++)
00250         {
00251                 participantStruct=participantList[i];
00252 
00253                 if ((broadcast==true && systemAddress!=participantStruct->systemAddress) || 
00254                         (broadcast==false && systemAddress==participantStruct->systemAddress))
00255                 {
00256                         // Remove any remote object state tracking for this object, for this player
00257                         tempIndex = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
00258                         if (objectExists)
00259                         {
00260                                 // Send the destruction packet immediately
00261                                 if (replica->GetNetworkID()!=UNASSIGNED_NETWORK_ID &&
00262                                         (replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_DESTRUCTION))
00263                                 {
00264                                         userDataBitStream.Reset();
00265                                         userDataBitStream.Write((MessageID)ID_REPLICA_MANAGER_DESTRUCTION);
00266                                         userDataBitStream.Write(replica->GetNetworkID());
00267                                         sendTimestamp=false;
00268                                         ReplicaReturnResult res = replica->SendDestruction(&userDataBitStream, participantStruct->systemAddress, &sendTimestamp);
00269                                         if (res==REPLICA_PROCESSING_DONE)
00270                                         {
00271                                                 outBitstream.Reset();
00272                                                 if (sendTimestamp)
00273                                                 {
00274                                                         outBitstream.Write((MessageID)ID_TIMESTAMP);
00275                                                         outBitstream.Write(RakNet::GetTime());
00276                                                         outBitstream.Write(&userDataBitStream);
00277                                                         SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
00278                                                 }
00279                                                 else
00280                                                         SendUnified(&userDataBitStream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
00281                                         }
00282                                 }
00283 
00284                                 participantStruct->remoteObjectList.RemoveAtIndex(tempIndex);
00285                         }
00286 
00287                         // Remove any pending commands that reference this object, for this player
00288                         tempIndex = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
00289                 //      tempIndex = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
00290                         if (objectExists)
00291                                 participantStruct->commandList.RemoveAtIndex(tempIndex);
00292                 }
00293                 else if (replicaReferenced==false)
00294                 {
00295                         bool objectExists;
00296                         GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
00297                         // See if any commands or objects reference replica
00298                         //if (participantStruct->commandList.HasData(replica))
00299                         if (objectExists)
00300                                 replicaReferenced=true;
00301                         else if (participantStruct->remoteObjectList.HasData(replica))
00302                                 replicaReferenced=true;
00303                 }
00304         }
00305 
00306         // Remove replica from the list if no commands and no remote objects reference it
00307         if (replicaReferenced==false)
00308                 replicatedObjects.RemoveAtIndex(replicatedObjectsIndex);
00309 }
00310 void ReplicaManager::ReferencePointer(Replica *replica)
00311 {
00312         // Start tracking this object, if we are not already
00313         if (replicatedObjects.HasData(replica)==false)
00314         {
00315                 RegisteredReplica replicaAndTime;
00316                 replicaAndTime.replica=replica;
00317                 replicaAndTime.lastDeserializeTrue=0;
00318                 replicaAndTime.allowedInterfaces=REPLICA_SET_ALL;
00319                 replicaAndTime.referenceOrder=nextReferenceIndex++;
00320                 replicatedObjects.Insert(replica,replicaAndTime, true, __FILE__,__LINE__);
00322                 if (replica->GetNetworkIDManager()==0)
00323                         replica->SetNetworkIDManager(rakPeerInterface->GetNetworkIDManager());
00324         }
00325 }
00326 void ReplicaManager::DereferencePointer(Replica *replica)
00327 {
00328         bool objectExists;
00329         unsigned replicatedObjectsIndex;
00330         unsigned tempIndex;
00331         replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
00332         if (objectExists==false)
00333                 return;
00334         replicatedObjects.RemoveAtIndex(replicatedObjectsIndex);
00335 
00336         ParticipantStruct *participantStruct;
00337         unsigned i;
00338         for (i=0; i < participantList.Size(); i++)
00339         {
00340                 participantStruct=participantList[i];
00341 
00342                 // Remove any pending commands that reference this object for any player
00343                 tempIndex = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
00344         //      tempIndex = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
00345                 if (objectExists)
00346                         participantStruct->commandList.RemoveAtIndex(tempIndex);
00347 
00348                 // Remove any remote object state tracking for this object for any player
00349                 tempIndex = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
00350                 if (objectExists)
00351                         participantStruct->remoteObjectList.RemoveAtIndex(tempIndex);
00352         }
00353 }
00354 void ReplicaManager::SetScope(Replica *replica, bool inScope, SystemAddress systemAddress, bool broadcast)
00355 {
00356         RakAssert(replica);
00357 
00358         // Autoreference the pointer if necessary.  This way the user can call functions on an object without having to worry
00359         // About the order of operations.
00360         ReferencePointer(replica);
00361 
00362         // For each player that we want, flag to call SendScopeChange if inScope is different from what they already have
00363         unsigned i;
00364         ParticipantStruct *participantStruct;
00365         bool objectExists;
00366         unsigned index;
00367         CommandStruct replicaAndCommand;
00368         if (inScope)
00369                 replicaAndCommand.command=REPLICA_SCOPE_TRUE;
00370         else
00371                 replicaAndCommand.command=REPLICA_SCOPE_FALSE;
00372         replicaAndCommand.replica=replica;
00373         replicaAndCommand.userFlags=0;
00374         for (i=0; i < participantList.Size(); i++)
00375         {
00376                 participantStruct=participantList[i];
00377 
00378                 if ((broadcast==true && systemAddress!=participantStruct->systemAddress) || 
00379                         (broadcast==false && systemAddress==participantStruct->systemAddress))
00380                 {
00381                         // If there is already a pending command for this object, add to it.  Otherwise, add a new pending command
00382                         index = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
00383 //                      index = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
00384             if (objectExists)
00385                         {
00386                                 // Update a pending command
00387                                 if (inScope)
00388                                 {
00389                                         participantStruct->commandList[index].command&=0xFF ^ REPLICA_SCOPE_FALSE; // Unset this bit
00390                                         participantStruct->commandList[index].command|=REPLICA_SCOPE_TRUE; // Set this bit
00391                                 }
00392                                 else
00393                                 {
00394                                         participantStruct->commandList[index].command&=0xFF ^ REPLICA_SCOPE_TRUE; // Unset this bit
00395                                         participantStruct->commandList[index].command|=REPLICA_SCOPE_FALSE; // Set this bit
00396                                 }                                               
00397                         }
00398                         else
00399                         {
00400                                 // Add a new command, since there are no pending commands for this object
00401                                 participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
00402                         }
00403                 }
00404         }
00405 }
00406 void ReplicaManager::SignalSerializeNeeded(Replica *replica, SystemAddress systemAddress, bool broadcast)
00407 {
00408         RakAssert(replica);
00409 
00410         // Autoreference the pointer if necessary.  This way the user can call functions on an object without having to worry
00411         // About the order of operations.
00412         if (replicatedObjects.HasData(replica)==false)
00413                 ReferencePointer(replica);
00414 
00415         // For each player that we want, if this object exists on that system, flag to call Serialize
00416         // (this may not necessarily happen - it depends on if the object is inScope when Update actually processes it.)
00417         unsigned i;
00418         ParticipantStruct *participantStruct;
00419         bool objectExists;
00420         unsigned index;
00421         CommandStruct replicaAndCommand;
00422         replicaAndCommand.command=REPLICA_SERIALIZE;
00423         replicaAndCommand.replica=replica;
00424         replicaAndCommand.userFlags=0;
00425         for (i=0; i < participantList.Size(); i++)
00426         {
00427                 participantStruct=participantList[i];
00428 
00429                 if ((broadcast==true && systemAddress!=participantStruct->systemAddress) || 
00430                         (broadcast==false && systemAddress==participantStruct->systemAddress))
00431                 {
00432                         // If there is already a pending command for this object, add to it.  Otherwise, add a new pending command
00433                         // index = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
00434                         index = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
00435                         if (objectExists)
00436                         {
00437                                 participantStruct->commandList[index].command|=REPLICA_SERIALIZE; // Set this bit                       
00438                         }
00439                         else
00440                         {
00441                                 // Add a new command, since there are no pending commands for this object
00442                                 participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
00443                         }
00444                 }
00445         }
00446 }
00447 void ReplicaManager::SetReceiveConstructionCB(ReceiveConstructionInterface *ReceiveConstructionInterface)
00448 {
00449         // Just overwrite the construction callback pointer
00450         _constructionCB=ReceiveConstructionInterface;
00451 }
00452 void ReplicaManager::SetDownloadCompleteCB(SendDownloadCompleteInterface *sendDownloadComplete, ReceiveDownloadCompleteInterface *receiveDownloadComplete)
00453 {
00454         // Just overwrite the send and receive download complete pointers.
00455         _sendDownloadCompleteCB=sendDownloadComplete;
00456         _receiveDownloadCompleteCB=receiveDownloadComplete;
00457 }
00458 void ReplicaManager::SetSendChannel(unsigned char channel)
00459 {
00460         // Change the send channel from the default of 0
00461         sendChannel=channel;
00462 }
00463 void ReplicaManager::SetAutoConstructToNewParticipants(bool autoConstruct)
00464 {
00465         autoConstructToNewParticipants=autoConstruct;
00466 }
00467 void ReplicaManager::SetDefaultScope(bool scope)
00468 {
00469         defaultScope=scope;
00470 }
00471 void ReplicaManager::SetAutoSerializeInScope(bool autoSerialize)
00472 {
00473         autoSerializeInScope=autoSerialize;
00474 }
00475 void ReplicaManager::EnableReplicaInterfaces(Replica *replica, unsigned char interfaceFlags)
00476 {
00477         bool objectExists;
00478         unsigned replicatedObjectsIndex;
00479         replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
00480         if (objectExists==false)
00481         {
00482                 // Autoreference the pointer if necessary.  This way the user can call functions on an object without having to worry
00483                 // About the order of operations.
00484                 ReferencePointer(replica);
00485                 replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
00486         }
00487         replicatedObjects[replicatedObjectsIndex].allowedInterfaces|=interfaceFlags;
00488 }
00489 void ReplicaManager::DisableReplicaInterfaces(Replica *replica, unsigned char interfaceFlags)
00490 {
00491         bool objectExists;
00492         unsigned replicatedObjectsIndex;
00493         replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
00494         if (objectExists==false)
00495         {
00496                 // Autoreference the pointer if necessary.  This way the user can call functions on an object without having to worry
00497                 // About the order of operations.
00498                 ReferencePointer(replica);
00499                 replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
00500         }
00501         replicatedObjects[replicatedObjectsIndex].allowedInterfaces&= 0xFF ^ interfaceFlags;
00502 }
00503 bool ReplicaManager::IsConstructed(Replica *replica, SystemAddress systemAddress)
00504 {
00505         ParticipantStruct *participantStruct = GetParticipantBySystemAddress(systemAddress);
00506         if (participantStruct)
00507         {
00508                 bool objectExists;
00509                 participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
00510                 return objectExists;
00511         }
00512         return false;
00513 }
00514 bool ReplicaManager::IsInScope(Replica *replica, SystemAddress systemAddress)
00515 {
00516         ParticipantStruct *participantStruct = GetParticipantBySystemAddress(systemAddress);
00517         if (participantStruct)
00518         {
00519                 bool objectExists;
00520                 unsigned remoteObjectListIndex = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
00521                 if (objectExists)
00522                         return participantStruct->remoteObjectList[remoteObjectListIndex].inScope;
00523         }
00524         return false;
00525 }
00526 unsigned ReplicaManager::GetReplicaCount(void) const
00527 {
00528         return replicatedObjects.Size();
00529 }
00530 Replica *ReplicaManager::GetReplicaAtIndex(unsigned index)
00531 {
00532         return replicatedObjects[index].replica;
00533 }
00534 unsigned ReplicaManager::GetParticipantCount(void) const
00535 {
00536         return participantList.Size();
00537 }
00538 SystemAddress ReplicaManager::GetParticipantAtIndex(unsigned index)
00539 {
00540         return participantList[index]->systemAddress;
00541 }
00542 bool ReplicaManager::HasParticipant(SystemAddress systemAddress)
00543 {
00544         return participantList.HasData(systemAddress);
00545 }
00546 void ReplicaManager::SignalSerializationFlags(Replica *replica, SystemAddress systemAddress, bool broadcast, bool set, unsigned int flags)
00547 {
00548         RakAssert(replica);
00549 
00550         // Autoreference the pointer if necessary.  This way the user can call functions on an object without having to worry
00551         // About the order of operations.
00552         ReferencePointer(replica);
00553 
00554         CommandStruct replicaAndCommand;
00555         replicaAndCommand.replica=replica;
00556         replicaAndCommand.userFlags=flags;
00557         replicaAndCommand.command=0;
00558 
00559         bool objectExists;
00560         unsigned i, index;
00561         ParticipantStruct *participantStruct;
00562         for (i=0; i < participantList.Size(); i++)
00563         {
00564                 participantStruct=participantList[i];
00565 
00566                 if ((broadcast==true && systemAddress!=participantStruct->systemAddress) || 
00567                         (broadcast==false && systemAddress==participantStruct->systemAddress))
00568                 {
00569                         // Set the flags in the object if the object exists
00570                         index = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
00571                         if (objectExists)
00572                         {
00573                                 if (set)
00574                                         participantStruct->remoteObjectList[index].userFlags|=flags; // Set these user flags
00575                                 else
00576                                         participantStruct->remoteObjectList[index].userFlags&=~flags; // Unset these user flags
00577                         }
00578                         else
00579                         {
00580                                 // The object is not yet created.  Add to the pending command, or create a new command.
00581                                 // index = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
00582                                 index = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
00583                                 if (objectExists)
00584                                 {
00585                                         if (set)
00586                                                 participantStruct->commandList[index].userFlags|=flags; // Set these user flags
00587                                         else
00588                                                 participantStruct->commandList[index].userFlags&=~flags; // Unset these user flags
00589                                 }
00590                                 else if (set)
00591                                 {
00592                                         // Add a new command, since there are no pending commands for this object
00593                                         participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
00594                                 }
00595                         }
00596                 }
00597         }
00598 }
00599 unsigned int* ReplicaManager::AccessSerializationFlags(Replica *replica, SystemAddress systemAddress)
00600 {
00601         RakAssert(replica);
00602 
00603         // Autoreference the pointer if necessary.  This way the user can call functions on an object without having to worry
00604         // About the order of operations.
00605         ReferencePointer(replica);
00606 
00607         unsigned index;
00608         bool objectExists;
00609         ParticipantStruct *participantStruct;
00610         CommandStruct replicaAndCommand;
00611         replicaAndCommand.replica=replica;
00612         replicaAndCommand.userFlags=0;
00613         replicaAndCommand.command=0;
00614 
00615         participantStruct=GetParticipantBySystemAddress(systemAddress);
00616         if (participantStruct)
00617         {
00618                 // Set the flags in the object if the object exists
00619                 index = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
00620                 if (objectExists)
00621                 {
00622                         return &(participantStruct->remoteObjectList[index].userFlags);
00623                 }
00624                 else
00625                 {
00626 //                      index = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
00627                         index = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
00628                         if (objectExists)
00629                         {
00630                                 return &(participantStruct->commandList[index].userFlags);
00631                         }
00632                         else
00633                         {
00634                                 // Add a new command, since there are no pending commands for this object
00635                                 //index =
00636                                         participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
00637                                 // return &(participantStruct->commandList[index].userFlags);
00638                                         return & (participantStruct->commandList[participantStruct->commandList.Size()-1].userFlags);
00639                         }
00640                 }
00641         }
00642 
00643         // No such participant
00644         return 0;
00645 }
00646 
00647 void ReplicaManager::Clear(void)
00648 {
00649         // Free all memory
00650         unsigned i;
00651         for (i=0; i < participantList.Size(); i++)
00652                 RakNet::OP_DELETE(participantList[i], __FILE__, __LINE__);
00653         participantList.Clear(false, __FILE__, __LINE__);
00654         replicatedObjects.Clear(false, __FILE__, __LINE__);
00655         nextReferenceIndex=0;
00656 }
00657 void ReplicaManager::AssertReplicatedObjectsClear(void)
00658 {
00659         RakAssert(replicatedObjects.Size()==0);
00660 }
00661 void ReplicaManager::AssertParticipantsClear(void)
00662 {
00663         RakAssert(participantList.Size()==0);
00664 }
00665 void ReplicaManager::Update(void)
00666 {
00667         if (participantList.Size()==0)
00668                 return;
00669 
00670         // Check for recursive calls, which is not supported and should not happen
00671 #ifdef _DEBUG
00672         RakAssert(inUpdate==false);
00673         inUpdate=true;
00674 #endif
00675 
00676         unsigned participantIndex, remoteObjectListIndex, replicatedObjectsIndex;
00677         ReplicaReturnResult res;
00678         bool sendTimestamp;
00679         ParticipantStruct *participantStruct;
00680         unsigned commandListIndex;
00681         RakNet::BitStream outBitstream, userDataBitstream;
00682         RakNetTime currentTime;
00683         bool objectExists;
00684         PacketPriority priority;
00685         PacketReliability reliability;
00686         ReceivedCommand *receivedCommand;
00687         Replica *replica;
00688 //      unsigned int userFlags;
00689         unsigned char command;
00690         currentTime=0;
00691 
00692         // For each participant
00693         for (participantIndex=0; participantIndex < participantList.Size(); participantIndex++)
00694         {
00695                 participantStruct = participantList[participantIndex];
00696 
00697                 // Sends the download complete packet
00698                 // If callDownloadCompleteCB is true then check all the remaining objects starting at commandListIndex
00699                 // I scan every frame in case the callback returns false to delay, and after that time a new object is Replicated
00700                 if (participantStruct->callDownloadCompleteCB)
00701                 {
00702                         bool anyHasConstruction;
00703                         unsigned j;
00704                         anyHasConstruction=false;
00705                         for (j=0; j < participantStruct->commandList.Size(); j++)
00706                         {
00707                                 if (participantStruct->commandList[j].command & REPLICA_EXPLICIT_CONSTRUCTION)
00708                                 {
00709                                         anyHasConstruction=true;
00710                                         break;
00711                                 }
00712                         }
00713                         // If none have REPLICA_EXPLICIT_CONSTRUCTION, send ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE and set callDownloadCompleteCB false
00714                         if (anyHasConstruction==false)
00715                         {
00716                                 ReplicaReturnResult sendDLComplete;
00717                                 userDataBitstream.Reset();
00718                                 if (_sendDownloadCompleteCB)
00719                                         sendDLComplete=_sendDownloadCompleteCB->SendDownloadComplete(&userDataBitstream, currentTime, participantStruct->systemAddress, this); // If you return false, this will be called again next update
00720                                 else
00721                                         sendDLComplete=REPLICA_CANCEL_PROCESS;
00722                                 if (sendDLComplete==REPLICA_PROCESSING_DONE)
00723                                 {
00724                                         outBitstream.Reset();
00725                                         outBitstream.Write((MessageID)ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE);
00726                                         outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());
00727                                         SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
00728                                         participantStruct->callDownloadCompleteCB=false;
00729                                 }
00730                                 else if (sendDLComplete==REPLICA_CANCEL_PROCESS)
00731                                 {
00732                                         participantStruct->callDownloadCompleteCB=false;
00733                                 }
00734                                 else
00735                                 {
00736                                         RakAssert(sendDLComplete==REPLICA_PROCESS_LATER);
00737                                         // else REPLICA_PROCESS_LATER
00738                                 }
00739                         }
00740                 }
00741 
00742                 // For each CommandStruct to send
00743                 for (commandListIndex=0; commandListIndex < participantStruct->commandList.Size(); commandListIndex++)
00744                 {
00745                         // Only call RakNet::GetTime() once because it's slow
00746                         if (currentTime==0)
00747                                 currentTime=RakNet::GetTime();
00748 
00749                         replica=participantStruct->commandList[commandListIndex].replica;
00750                         command=participantStruct->commandList[commandListIndex].command;
00751                 //      userFlags=participantStruct->commandList[commandListIndex].userFlags;
00752                         replicatedObjectsIndex=replicatedObjects.GetIndexFromKey(replica, &objectExists);
00753 #ifdef _DEBUG
00754                         RakAssert(objectExists);
00755 #endif
00756                         if (objectExists==false)
00757                                 continue;
00758 
00759                         // If construction is set, call SendConstruction.  The only precondition is that the object was not already created,
00760                         // which was checked in ReplicaManager::Replicate
00761                         if (command & REPLICA_EXPLICIT_CONSTRUCTION)
00762                         {
00763                                 if (replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_CONSTRUCTION)
00764                                 {
00765                                         userDataBitstream.Reset();
00766                                         sendTimestamp=false;
00767                                         res=replica->SendConstruction(currentTime, participantStruct->systemAddress,
00768                                                 participantStruct->commandList[commandListIndex].userFlags, &userDataBitstream, &sendTimestamp);
00769 
00770                                         if (res==REPLICA_PROCESSING_DONE)
00771                                         {
00772                                                 outBitstream.Reset();
00773                                                 // If SendConstruction returns true and writes to outBitStream, do this send.  Clear the construction command.  Then process the next command for this CommandStruct, if any.
00774                                                 if (sendTimestamp)
00775                                                 {
00776                                                         outBitstream.Write((MessageID)ID_TIMESTAMP);
00777                                                         outBitstream.Write(currentTime);
00778                                                 }
00779                                                 outBitstream.Write((MessageID)ID_REPLICA_MANAGER_CONSTRUCTION);
00780                                                 // It's required to send an NetworkID if available.
00781                                                 // Problem:
00782                                                 // A->B->C
00783                                                 //      |  |
00784                                                 //      D->E
00785                                                 //
00786                                                 // A creates.
00787                                                 // B->C->E->D->B will cycle forever.
00788                                                 // Fix is to always include an networkID.  Objects are not created if that object id already is present.
00789                                                 if (replica->GetNetworkID()!=UNASSIGNED_NETWORK_ID)
00790                                                 {
00791                                                         outBitstream.Write(true);
00792                                                         outBitstream.Write(replica->GetNetworkID());
00793                                                 }
00794                                                 else
00795                                                         outBitstream.Write(false);
00796 
00797                                                 outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());
00798 
00799                                                 SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
00800 
00801                                                 // Turn off this bit
00802                                                 participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_EXPLICIT_CONSTRUCTION;
00803 
00804                                                 // Add the object to the participant's object list, indicating this object has been remotely created
00805                                                 RemoteObject remoteObject;
00806                                                 remoteObject.replica=replica;
00807                                                 //remoteObject.inScope=defaultScope;
00808                                                 remoteObject.inScope=false;
00809                                                 remoteObject.lastSendTime=0;
00810                                                 remoteObject.userFlags=participantStruct->commandList[commandListIndex].userFlags;
00811                                                 // Create an entry for this object.  We do this now, even if the user might refuse the SendConstruction override,
00812                                                 // because that call may be delayed and other commands sent while that is pending.  We always do the REPLICA_EXPLICIT_CONSTRUCTION call first.
00813                                                 participantStruct->remoteObjectList.Insert(remoteObject.replica,remoteObject, true, __FILE__,__LINE__);
00814                                         }
00815                                         else if (res==REPLICA_PROCESS_IMPLICIT)
00816                                         {
00817                                                 // Turn off this bit
00818                                                 participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_EXPLICIT_CONSTRUCTION;
00819 
00820                                                 // Add the object to the participant's object list, indicating this object has been remotely created
00821                                                 RemoteObject remoteObject;
00822                                                 remoteObject.replica=replica;
00823                                                 //remoteObject.inScope=defaultScope;
00824                                                 remoteObject.inScope=false;
00825                                                 remoteObject.lastSendTime=0;
00826                                                 remoteObject.userFlags=participantStruct->commandList[commandListIndex].userFlags;
00827                                                 // Create an entry for this object.  We do this now, even if the user might refuse the SendConstruction override,
00828                                                 // because that call may be delayed and other commands sent while that is pending.  We always do the REPLICA_EXPLICIT_CONSTRUCTION call first.
00829                                                 participantStruct->remoteObjectList.Insert(remoteObject.replica,remoteObject, true, __FILE__,__LINE__);
00830                                         }
00831                                         else if (res==REPLICA_PROCESS_LATER)
00832                                         {
00833                                                 continue;
00834                                         }
00835                                         else // REPLICA_CANCEL_PROCESS
00836                                         {
00837                                                 RakAssert(res==REPLICA_CANCEL_PROCESS);
00838                                                 participantStruct->commandList[commandListIndex].command=0;
00839                                         }
00840                                 }
00841                                 else
00842                                 {
00843                                         // Don't allow construction, or anything else for this object, as the construction send call is disallowed
00844                                         participantStruct->commandList[commandListIndex].command=0;
00845                                 }
00846                         }
00847                         else if (command & REPLICA_IMPLICIT_CONSTRUCTION)
00848                         {
00849                                 // Turn off this bit
00850                                 participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_IMPLICIT_CONSTRUCTION;
00851 
00852                                 // Add the object to the participant's object list, indicating this object is assumed to be remotely created
00853                                 RemoteObject remoteObject;
00854                                 remoteObject.replica=replica;
00855                                 //remoteObject.inScope=defaultScope;
00856                                 remoteObject.inScope=false;
00857                                 remoteObject.lastSendTime=0;
00858                                 remoteObject.userFlags=participantStruct->commandList[commandListIndex].userFlags;
00859                                 // Create an entry for this object.  We do this now, even if the user might refuse the SendConstruction override,
00860                                 // because that call may be delayed and other commands sent while that is pending.  We always do the REPLICA_EXPLICIT_CONSTRUCTION call first.
00861                                 participantStruct->remoteObjectList.Insert(remoteObject.replica,remoteObject, true, __FILE__,__LINE__);
00862                         }
00863 
00864                         // The remaining commands, SendScopeChange and Serialize, require the object the command references exists on the remote system, so check that
00865                         remoteObjectListIndex = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
00866                         if (objectExists)
00867                         {
00868                                 command = participantStruct->commandList[commandListIndex].command;
00869 
00870                                 // Process SendScopeChange.
00871                                 if ((command & (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE)))
00872                                 {
00873                                         if (replica->GetNetworkID()==UNASSIGNED_NETWORK_ID)
00874                                                 continue; // Not set yet so call this later.
00875 
00876                                         if (replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_SCOPE_CHANGE)
00877                                         {
00878                                                 bool scopeTrue = (command & REPLICA_SCOPE_TRUE)!=0;
00879 
00880                                                 // Only send scope changes if the requested change is different from what they already have
00881                                                 if (participantStruct->remoteObjectList[remoteObjectListIndex].inScope!=scopeTrue)
00882                                                 {
00883                                                         userDataBitstream.Reset();
00884                                                         sendTimestamp=false;
00885                                                         res=replica->SendScopeChange(scopeTrue, &userDataBitstream, currentTime, participantStruct->systemAddress, &sendTimestamp);
00886 
00887                                                         if (res==REPLICA_PROCESSING_DONE)
00888                                                         {
00889                                                                 // If the user returns true and does write to outBitstream, do this send.  Clear the scope change command. Then process the next command for this CommandStruct, if any.
00890                                                                 outBitstream.Reset();
00891                                                                 if (sendTimestamp)
00892                                                                 {
00893                                                                         outBitstream.Write((MessageID)ID_TIMESTAMP);
00894                                                                         outBitstream.Write(currentTime);
00895                                                                 }
00896                                                                 outBitstream.Write((MessageID)ID_REPLICA_MANAGER_SCOPE_CHANGE);
00897                                                                 outBitstream.Write(replica->GetNetworkID());
00898                                                                 outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());
00899                                                                 SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
00900 
00901                                                                 // Set the scope for this object and system
00902                                                                 participantStruct->remoteObjectList[remoteObjectListIndex].inScope=scopeTrue;
00903 
00904                                                                 // If scope is true, turn on serialize, since you virtually always want to serialize when an object goes in scope
00905                                                                 if (scopeTrue && autoSerializeInScope)
00906                                                                         participantStruct->commandList[commandListIndex].command |= REPLICA_SERIALIZE;
00907 
00908                                                                 // Turn off these bits - Call is processed
00909                                                                 participantStruct->commandList[commandListIndex].command &= 0xFF ^ (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE);
00910                                                         }
00911                                                         else if (res==REPLICA_CANCEL_PROCESS)
00912                                                         {
00913                                                                 // Turn off these bits - Call is canceled
00914                                                                 participantStruct->commandList[commandListIndex].command &= 0xFF ^ (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE);
00915                                                         }
00916                                                         else
00917                                                         {
00918                                                                 // If the user returns false and the scope is currently set to false, just continue with another CommandStruct.  Don't process serialization until scoping is resolved first.
00919                                                                 if (scopeTrue==false)
00920                                                                         continue;
00921 
00922                                                                 // If the user returns false and the scope is currently set to false, process the next command for this CommandStruct, if any.
00923                                                         }
00924                                                 }
00925                                         }
00926                                         else
00927                                         {
00928                                                 // Turn off these bits - Call is disallowed
00929                                                 participantStruct->commandList[commandListIndex].command &= 0xFF ^ (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE);
00930 
00931                                                 // Set the scope - even if the actual send is disabled we might still be able to serialize.
00932                                                 participantStruct->remoteObjectList[remoteObjectListIndex].inScope=(command & REPLICA_SCOPE_TRUE)!=0;
00933                                         }
00934                                 }
00935 
00936                                 command = participantStruct->commandList[commandListIndex].command;
00937                                 // Process Serialize
00938                                 if ((command & REPLICA_SERIALIZE))
00939                                 {
00940                                         if (replica->GetNetworkID()==UNASSIGNED_NETWORK_ID)
00941                                                 continue; // Not set yet so call this later.
00942 
00943                                         // If scope is currently false for this object in the RemoteObject list, cancel this serialize as the scope changed before the serialization went out
00944                                         if (participantStruct->remoteObjectList[remoteObjectListIndex].inScope && (replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_SERIALIZE))
00945                                         {
00946                                                 do 
00947                                                 {
00948                                                         userDataBitstream.Reset();
00949                                                         priority=HIGH_PRIORITY;
00950                                                         reliability=RELIABLE_ORDERED;
00951                                                         sendTimestamp=false;
00952                                                         res=replica->Serialize(&sendTimestamp, &userDataBitstream, participantStruct->remoteObjectList[remoteObjectListIndex].lastSendTime, &priority, &reliability, currentTime, participantStruct->systemAddress, participantStruct->remoteObjectList[remoteObjectListIndex].userFlags);
00953 
00954                                                         if (res==REPLICA_PROCESSING_DONE || res==REPLICA_PROCESS_AGAIN)
00955                                                         {
00956                                                                 participantStruct->remoteObjectList[remoteObjectListIndex].lastSendTime=currentTime;
00957 
00958                                                                 outBitstream.Reset();
00959                                                                 if (sendTimestamp)
00960                                                                 {
00961                                                                         outBitstream.Write((MessageID)ID_TIMESTAMP);
00962                                                                         outBitstream.Write(currentTime);
00963                                                                 }
00964                                                                 outBitstream.Write((MessageID)ID_REPLICA_MANAGER_SERIALIZE);
00965                                                                 outBitstream.Write(replica->GetNetworkID());
00966                                                                 outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());
00967                                                                 SendUnified(&outBitstream, priority, reliability, sendChannel, participantStruct->systemAddress, false);                
00968 
00969                                                                 // Clear the serialize bit when done
00970                                                                 if (res==REPLICA_PROCESSING_DONE)
00971                                                                         participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_SERIALIZE;
00972                                                                 // else res==REPLICA_PROCESS_AGAIN so it will repeat the enclosing do {} while(); loop
00973                                                         }
00974                                                         else if (res==REPLICA_CANCEL_PROCESS)
00975                                                         {
00976                                                                 // Clear the serialize bit
00977                                                                 participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_SERIALIZE;
00978                                                         }
00979                                                         else
00980                                                         {
00981                                                                 // if the user returns REPLICA_PROCESS_LATER, just continue with another CommandStruct.
00982                                                                 RakAssert(res==REPLICA_PROCESS_LATER);
00983                                                         }
00984                                                 } while(res==REPLICA_PROCESS_AGAIN);
00985                                         }
00986                                         else
00987                                         {
00988                                                 // Cancel this serialize
00989                                                 participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_SERIALIZE;
00990                                         }
00991                                 }
00992                         }
00993                 }
00994 
00995                 // Go through the command list and delete all cleared commands, from back to front.  It is more efficient to do this than to delete them as we process
00996                 commandListIndex=participantStruct->commandList.Size();
00997                 if (commandListIndex>0)
00998                 {
00999 #ifdef _MSC_VER
01000 #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
01001 #endif
01002                         while (1)
01003                         {
01004                                 if (participantStruct->commandList[commandListIndex-1].command==0)
01005                                 {
01006                                         // If this is the last item in the list, and it probably is, then it just changes a number rather than shifts the entire array
01007                                         participantStruct->commandList.RemoveAtIndex(commandListIndex-1);
01008                                 }
01009 
01010                                 if (--commandListIndex==0)
01011                                         break;
01012                         }
01013                 }
01014                 
01015                 // Now process queued receives
01016                 while (participantStruct->pendingCommands.Size())
01017                 {
01018                         receivedCommand=participantStruct->pendingCommands.Pop();
01019                         participantStruct=GetParticipantBySystemAddress(receivedCommand->systemAddress);
01020                         if (participantStruct)
01021                         {
01022                                 res=ProcessReceivedCommand(participantStruct, receivedCommand);
01023                                 // Returning false means process this command again later
01024                                 if (res==REPLICA_PROCESS_LATER)
01025                                 {
01026                                         // Push the command back in the queue
01027                                         participantStruct->pendingCommands.PushAtHead(receivedCommand, 0, __FILE__,__LINE__);
01028 
01029                                         // Stop processing, because all processing is in order
01030                                         break;
01031                                 }
01032                                 else
01033                                 {
01034                                         RakAssert(res==REPLICA_CANCEL_PROCESS);
01035                                 }
01036                         }
01037                         
01038                         // Done with this command, so delete it
01039                         RakNet::OP_DELETE(receivedCommand->userData, __FILE__, __LINE__);
01040                         RakNet::OP_DELETE(receivedCommand, __FILE__, __LINE__);
01041                 }
01042         }
01043 #ifdef _DEBUG
01044         inUpdate=false;
01045 #endif
01046 }
01047 void ReplicaManager::OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
01048 {
01049         (void) systemAddress;
01050         (void) rakNetGUID;
01051         (void) lostConnectionReason;
01052 
01053         RemoveParticipant(systemAddress);
01054 }
01055 void ReplicaManager::OnRakPeerShutdown(void)
01056 {
01057         Clear();
01058 }
01059 void ReplicaManager::OnNewConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
01060 {
01061         (void) systemAddress;
01062         (void) rakNetGUID;
01063         (void) isIncoming;
01064         
01065         if (autoParticipateNewConnections)
01066                 AddParticipant(systemAddress);
01067 }
01068 PluginReceiveResult ReplicaManager::OnReceive(Packet *packet)
01069 {
01070         unsigned char packetIdentifier;
01071         if ( ( unsigned char ) packet->data[ 0 ] == ID_TIMESTAMP )
01072         {
01073                 if ( packet->length > sizeof( unsigned char ) + sizeof( unsigned int ) )
01074                         packetIdentifier = ( unsigned char ) packet->data[ sizeof( unsigned char ) + sizeof( unsigned int ) ];
01075                 else
01076                         return RR_STOP_PROCESSING_AND_DEALLOCATE;
01077         }
01078         else
01079                 packetIdentifier = ( unsigned char ) packet->data[ 0 ];
01080 
01081         switch (packetIdentifier)
01082         {
01083         case ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE:
01084                 if (_receiveDownloadCompleteCB==0)
01085                 {
01086                         return RR_STOP_PROCESSING_AND_DEALLOCATE;
01087                 }
01088         case ID_REPLICA_MANAGER_CONSTRUCTION:
01089         case ID_REPLICA_MANAGER_DESTRUCTION:
01090         case ID_REPLICA_MANAGER_SCOPE_CHANGE:
01091         case ID_REPLICA_MANAGER_SERIALIZE:
01092                 {
01093                         ParticipantStruct *participantStruct;
01094                         bool hasNetworkId=false;
01095                         ReceivedCommand receivedCommand;
01096                         bool b=true;
01097                         RakNet::BitStream inBitstream(packet->data, packet->length, false);
01098                         // SetWriteOffset is used here to get around a design flaw, where I should have had the bitstream constructor take bits, rather than bytes
01099                         // It sets the actual number of bits in the packet
01100                         inBitstream.SetWriteOffset(packet->bitSize);
01101                         receivedCommand.systemAddress=packet->systemAddress;
01102                         receivedCommand.command=packetIdentifier;
01103 
01104                         if ( ( unsigned char ) packet->data[ 0 ] == ID_TIMESTAMP )
01105                         {
01106                                 inBitstream.IgnoreBits(8);
01107                                 b=inBitstream.Read(receivedCommand.u1);
01108                         }
01109                         else
01110                                 receivedCommand.u1=0;
01111                         inBitstream.IgnoreBits(8); // Ignore the packet id
01112                         receivedCommand.networkID=UNASSIGNED_NETWORK_ID;
01113                         if (packetIdentifier==ID_REPLICA_MANAGER_CONSTRUCTION) // ID_REPLICA_MANAGER_CONSTRUCTION has an optional networkID
01114                         {
01115                                 b=inBitstream.Read(hasNetworkId);
01116                                 if (hasNetworkId)
01117                                         b=inBitstream.Read(receivedCommand.networkID);
01118                         }
01119                         else if (packetIdentifier!=ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE)
01120                         {
01121                                 b=inBitstream.Read(receivedCommand.networkID); // Other packets always have an networkID
01122                         }
01123 
01124                         if (b==false)
01125                         {
01126                                 // Invalid packet
01127 #ifdef _DEBUG
01128                                 RakAssert(0);
01129 #endif
01130                                 return RR_STOP_PROCESSING_AND_DEALLOCATE;
01131                         }
01132                         receivedCommand.userData=&inBitstream;
01133                         participantStruct=GetParticipantBySystemAddress(receivedCommand.systemAddress);
01134                         if (participantStruct)
01135                         {
01136                                 // .Size()>0 is because commands are always processed in order.  If a command is delayed, no further commands are processed.
01137                                 // ProcessReceivedCommand(...)==false means that the use signaled to delay a command
01138                                 if (participantStruct->pendingCommands.Size()>0 || ProcessReceivedCommand(participantStruct, &receivedCommand)==REPLICA_PROCESS_LATER)
01139                                 {
01140                                         // Copy the data and add this to a queue that will call ProcessReceivedCommand again in Update.
01141 
01142                                         // Allocate and copy structure
01143                                         ReceivedCommand *rc = RakNet::OP_NEW<ReceivedCommand>( __FILE__, __LINE__ );
01144                                         memcpy(rc, &receivedCommand, sizeof(ReceivedCommand));
01145 
01146                                         // Allocate and copy inBitstream remaining data
01147                                         rc->userData = RakNet::OP_NEW<RakNet::BitStream>( __FILE__, __LINE__ );
01148                                         rc->userData->Write(&inBitstream, inBitstream.GetNumberOfBitsUsed());
01149 
01150                                         participantStruct->pendingCommands.Push(rc, __FILE__, __LINE__ );
01151                                 }
01152                         }
01153 
01154                         return RR_STOP_PROCESSING_AND_DEALLOCATE;
01155                 }
01156         }
01157 
01158         return RR_CONTINUE_PROCESSING;
01159 }
01160 
01161 ReplicaManager::ParticipantStruct* ReplicaManager::GetParticipantBySystemAddress(const SystemAddress systemAddress) const
01162 {
01163         bool objectExists;
01164         unsigned index;
01165         index = participantList.GetIndexFromKey(systemAddress, &objectExists);
01166         if (objectExists==false)
01167                 return 0;
01168         return participantList[index];
01169 }
01170 #ifdef _MSC_VER
01171 #pragma warning( disable : 4701 ) // warning C4701: local variable <variable name> may be used without having been initialized
01172 #endif
01173 ReplicaReturnResult ReplicaManager::ProcessReceivedCommand(ParticipantStruct *participantStruct, ReceivedCommand *receivedCommand)
01174 {
01175         (void) participantStruct;
01176 
01177         // If this assert hits you didn't first call RakPeer::SetNetworkIDManager as required.
01178         RakAssert(rakPeerInterface->GetNetworkIDManager());
01179         if (rakPeerInterface->GetNetworkIDManager()==0)
01180                 return REPLICA_CANCEL_PROCESS;
01181 
01182         Replica *replica = (Replica*) rakPeerInterface->GetNetworkIDManager()->GET_BASE_OBJECT_FROM_ID(receivedCommand->networkID);
01183         
01184         bool objectExists;
01185         unsigned index=0;
01186         ReplicaReturnResult b;
01187         if (replica)
01188         {
01189                 index = replicatedObjects.GetIndexFromKey(replica, &objectExists);
01190                 if (objectExists==false)
01191                 {
01192                         if (receivedCommand->command==ID_REPLICA_MANAGER_CONSTRUCTION)
01193                         {
01194                                 // Object already exists with this ID, but call construction anyway
01195 #ifdef _DEBUG
01196                                 RakAssert(_constructionCB);
01197 #endif
01198                                 // Call the registered callback.  If it crashes, you forgot to register the callback in SetReceiveConstructionCB
01199                                 return _constructionCB->ReceiveConstruction(receivedCommand->userData, receivedCommand->u1, receivedCommand->networkID, replica, receivedCommand->systemAddress, this);
01200                         }
01201                         else
01202                         {
01203                                 // This networkID is already in use but ReferencePointer was never called on it.
01204                                 // RakAssert(0);
01205                                 return REPLICA_CANCEL_PROCESS;
01206                         }
01207                         
01208                 }
01209         }
01210 
01211         if (receivedCommand->command==ID_REPLICA_MANAGER_SERIALIZE)
01212         {
01213                 if (replica && (replicatedObjects[index].allowedInterfaces & REPLICA_RECEIVE_SERIALIZE))
01214                 {
01215                         b=replica->Deserialize(receivedCommand->userData, receivedCommand->u1, replicatedObjects[index].lastDeserializeTrue, receivedCommand->systemAddress);
01216                         if (b==REPLICA_PROCESSING_DONE)
01217                                 replicatedObjects[index].lastDeserializeTrue=RakNet::GetTime();
01218                         return b;
01219                 }
01220         }
01221         else if (receivedCommand->command==ID_REPLICA_MANAGER_CONSTRUCTION)
01222         {
01223                 // If networkID already exists on this system, ignore the packet
01224 #ifdef _DEBUG
01225                 RakAssert(_constructionCB);
01226 #endif
01227                 // Call the registered callback.  If it crashes, you forgot to register the callback in SetReceiveConstructionCB
01228                 return _constructionCB->ReceiveConstruction(receivedCommand->userData, receivedCommand->u1, receivedCommand->networkID, replica, receivedCommand->systemAddress, this);
01229         }
01230         else if (receivedCommand->command==ID_REPLICA_MANAGER_SCOPE_CHANGE)
01231         {
01232                 if (replica && (replicatedObjects[index].allowedInterfaces & REPLICA_RECEIVE_SCOPE_CHANGE))
01233                 {
01234                         return replica->ReceiveScopeChange(receivedCommand->userData, receivedCommand->systemAddress, receivedCommand->u1);
01235                 }
01236         }
01237         else if (receivedCommand->command==ID_REPLICA_MANAGER_DESTRUCTION)
01238         {
01239                 if (replica && (replicatedObjects[index].allowedInterfaces & REPLICA_RECEIVE_DESTRUCTION))
01240                 {
01241                         return replica->ReceiveDestruction(receivedCommand->userData, receivedCommand->systemAddress, receivedCommand->u1);
01242                 }        
01243         }
01244         else if (receivedCommand->command==ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE)
01245         {
01246                 if (_receiveDownloadCompleteCB)
01247                 {
01248                         return _receiveDownloadCompleteCB->ReceiveDownloadComplete(receivedCommand->userData, receivedCommand->systemAddress, this);
01249                 }
01250         }
01251 
01252         return REPLICA_CANCEL_PROCESS;
01253 }
01254 
01255 ReplicaManager::ParticipantStruct::~ParticipantStruct()
01256 {
01257         ReceivedCommand *receivedCommand;
01258         while ( pendingCommands.Size() )
01259         {
01260                 receivedCommand=pendingCommands.Pop();
01261                 RakNet::OP_DELETE(receivedCommand->userData, __FILE__, __LINE__);
01262                 RakNet::OP_DELETE(receivedCommand, __FILE__, __LINE__);
01263         }
01264 }
01265 
01266 unsigned ReplicaManager::GetCommandListReplicaIndex(const DataStructures::List<ReplicaManager::CommandStruct> &commandList, Replica *replica, bool *objectExists) const
01267 {
01268         unsigned i;
01269         for (i=0; i < commandList.Size(); i++)
01270         {
01271                 if (commandList[i].replica==replica)
01272                 {
01273                         *objectExists=true;
01274                         return i;
01275                 }
01276         }
01277         *objectExists=false;
01278         return 0;
01279 }
01280 
01281 #ifdef _MSC_VER
01282 #pragma warning( pop )
01283 #endif
01284 
01285 #endif // _RAKNET_SUPPORT_*

Generated on Thu Sep 30 2010 01:27:27 for RakNet by  doxygen 1.7.1