1 #include "NativeFeatureIncludes.h"
2 #if _RAKNET_SUPPORT_ReplicaManager==1
3
4 #include "ReplicaManager.h"
5 #include "RakPeerInterface.h"
6 #include "GetTime.h"
7 #include "MessageIdentifiers.h"
8 #include "BitStream.h"
9 #include "Replica.h"
10
11 #include <memory.h>
12
13 #include "RakAssert.h"
14 #include <stdio.h> // For my debug printfs
15 #include "RakAssert.h"
16 #include "NetworkIDManager.h"
17
18 #ifdef _MSC_VER
19 #pragma warning( push )
20 #endif
21
CommandStructComp(Replica * const & key,const ReplicaManager::CommandStruct & data)22 int ReplicaManager::CommandStructComp( Replica* const &key, const ReplicaManager::CommandStruct &data )
23 {
24 if (key->GetSortPriority() < data.replica->GetSortPriority())
25 return -1;
26 else if (key->GetSortPriority() > data.replica->GetSortPriority())
27 return 1;
28 if (key->GetAllocationNumber() < data.replica->GetAllocationNumber())
29 return -1;
30 if (key->GetAllocationNumber()==data.replica->GetAllocationNumber())
31 return 0;
32 return 1;
33 }
34
RegisteredReplicaComp(Replica * const & key,const ReplicaManager::RegisteredReplica & data)35 int ReplicaManager::RegisteredReplicaComp( Replica* const &key, const ReplicaManager::RegisteredReplica &data )
36 {
37 if (key->GetAllocationNumber() < data.replica->GetAllocationNumber())
38 return -1;
39 if (key->GetAllocationNumber()==data.replica->GetAllocationNumber())
40 return 0;
41 return 1;
42 }
43
RegisteredReplicaRefOrderComp(const unsigned int & key,const ReplicaManager::RegisteredReplica & data)44 int ReplicaManager::RegisteredReplicaRefOrderComp( const unsigned int &key, const ReplicaManager::RegisteredReplica &data )
45 {
46 if (key < data.referenceOrder)
47 return -1;
48 if (key==data.referenceOrder)
49 return 0;
50 return 1;
51 }
52
RemoteObjectComp(Replica * const & key,const ReplicaManager::RemoteObject & data)53 int ReplicaManager::RemoteObjectComp( Replica* const &key, const ReplicaManager::RemoteObject &data )
54 {
55 if (key->GetAllocationNumber() < data.replica->GetAllocationNumber())
56 return -1;
57 if (key->GetAllocationNumber()==data.replica->GetAllocationNumber())
58 return 0;
59 return 1;
60 }
61
ParticipantStructComp(const SystemAddress & key,ReplicaManager::ParticipantStruct * const & data)62 int ReplicaManager::ParticipantStructComp( const SystemAddress &key, ReplicaManager::ParticipantStruct * const &data )
63 {
64 if (key < data->systemAddress)
65 return -1;
66 if (key==data->systemAddress)
67 return 0;
68 return 1;
69 }
70
ReplicaManager()71 ReplicaManager::ReplicaManager()
72 {
73 _constructionCB=0;
74 _sendDownloadCompleteCB=0;
75 _receiveDownloadCompleteCB=0;
76 sendChannel=0;
77 autoParticipateNewConnections=false;
78 defaultScope=false;
79 autoConstructToNewParticipants=false;
80 autoSerializeInScope=false;
81 nextReferenceIndex=0;
82 #ifdef _DEBUG
83 inUpdate=false;
84 #endif
85 }
~ReplicaManager()86 ReplicaManager::~ReplicaManager()
87 {
88 Clear();
89 }
SetAutoParticipateNewConnections(bool autoAdd)90 void ReplicaManager::SetAutoParticipateNewConnections(bool autoAdd)
91 {
92 autoParticipateNewConnections=autoAdd;
93 }
AddParticipant(SystemAddress systemAddress)94 bool ReplicaManager::AddParticipant(SystemAddress systemAddress)
95 {
96 RakAssert(systemAddress!=UNASSIGNED_SYSTEM_ADDRESS);
97
98 // If this player is already in the list of participants, just return.
99 ParticipantStruct *participantStruct;
100 participantStruct=GetParticipantBySystemAddress(systemAddress);
101 if (participantStruct)
102 return false;
103
104 // Create a new participant with this systemAddress
105 participantStruct = RakNet::OP_NEW<ParticipantStruct>( __FILE__, __LINE__ );
106 participantStruct->systemAddress=systemAddress;
107
108 // Signal that when done sending SendConstruction for each existing object, we call sendDownloadCompleteCB
109 participantStruct->callDownloadCompleteCB=true;
110
111 // Add the new participant to the list of participants
112 participantList.Insert(systemAddress,participantStruct, true, __FILE__,__LINE__);
113
114 /*
115 if (autoConstructToNewParticipants)
116 {
117 // Signal that we need to call SendConstruction for each existing object to this participant
118 unsigned i;
119 CommandStruct replicaAndCommand;
120 replicaAndCommand.command=REPLICA_EXPLICIT_CONSTRUCTION;
121 if (defaultScope==true)
122 replicaAndCommand.command |= REPLICA_SCOPE_TRUE;
123 replicaAndCommand.userFlags=0;
124
125 // Auto replicate objects in the order they were originally referenced, rather than the random sorted order they are in now
126 // This way dependencies are created first.
127 DataStructures::OrderedList<unsigned int, RegisteredReplica, ReplicaManager::RegisteredReplicaRefOrderComp> sortByRefList;
128 for (i=0; i < replicatedObjects.Size(); i++)
129 sortByRefList.Insert(replicatedObjects[i].referenceOrder, replicatedObjects[i]);
130
131 for (i=0; i < sortByRefList.Size(); i++)
132 {
133 replicaAndCommand.replica=sortByRefList[i].replica;
134 participantStruct->commandList.Insert(replicaAndCommand.replica,replicaAndCommand);
135 }
136 }
137 */
138
139
140 if (autoConstructToNewParticipants)
141 {
142 // Signal that we need to call SendConstruction for each existing object to this participant
143 unsigned i;
144 CommandStruct replicaAndCommand;
145 replicaAndCommand.command=REPLICA_EXPLICIT_CONSTRUCTION;
146 if (defaultScope==true)
147 replicaAndCommand.command |= REPLICA_SCOPE_TRUE;
148 replicaAndCommand.userFlags=0;
149 for (i=0; i < replicatedObjects.Size(); i++)
150 {
151 replicaAndCommand.replica=replicatedObjects[i].replica;
152 participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
153 }
154 }
155
156 return true;
157 }
RemoveParticipant(SystemAddress systemAddress)158 bool ReplicaManager::RemoveParticipant(SystemAddress systemAddress)
159 {
160 RakAssert(systemAddress!=UNASSIGNED_SYSTEM_ADDRESS);
161
162 // Find this participant by systemAddress
163 ParticipantStruct *participantStruct;
164 participantStruct=GetParticipantBySystemAddress(systemAddress);
165
166 // If found, remove and free this participant structure
167 if (participantStruct)
168 {
169 participantList.Remove(systemAddress);
170 RakNet::OP_DELETE(participantStruct, __FILE__, __LINE__);
171 return true;
172 }
173
174 return false;
175 }
176
Construct(Replica * replica,bool isCopy,SystemAddress systemAddress,bool broadcast)177 void ReplicaManager::Construct(Replica *replica, bool isCopy, SystemAddress systemAddress, bool broadcast)
178 {
179 RakAssert(replica);
180
181 unsigned i;
182 ParticipantStruct *participantStruct;
183 CommandStruct replicaAndCommand;
184 unsigned index;
185 bool objectExists;
186 replicaAndCommand.replica=replica;
187 replicaAndCommand.userFlags=0;
188
189 ReferencePointer(replica);
190
191 for (i=0; i < participantList.Size(); i++)
192 {
193 participantStruct=participantList[i];
194 if ((broadcast==true && systemAddress!=participantStruct->systemAddress) ||
195 (broadcast==false && systemAddress==participantStruct->systemAddress))
196 {
197 if (participantStruct->remoteObjectList.HasData(replica)==false)
198 {
199 index = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
200 // index = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
201 if (objectExists)
202 {
203 #ifdef _DEBUG
204 // Implicit is only used for objects that were not already registered.
205 RakAssert(isCopy==false);
206 #endif
207 participantStruct->commandList[index].command|=REPLICA_EXPLICIT_CONSTRUCTION; // Set this bit
208 participantStruct->commandList[index].command&=0xFF ^ REPLICA_IMPLICIT_CONSTRUCTION; // Unset this bit
209
210 if (defaultScope==true && (participantStruct->commandList[index].command & REPLICA_SCOPE_FALSE) == 0)
211 participantStruct->commandList[index].command |= REPLICA_SCOPE_TRUE;
212 }
213 else
214 {
215 if (isCopy)
216 replicaAndCommand.command=REPLICA_IMPLICIT_CONSTRUCTION; // Set this bit
217 else
218 replicaAndCommand.command=REPLICA_EXPLICIT_CONSTRUCTION; // Set this bit
219
220 if (defaultScope==true)
221 replicaAndCommand.command |= REPLICA_SCOPE_TRUE;
222
223 participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
224 }
225 }
226 }
227 }
228
229 // Update immediately, otherwise if we take action on this object the first frame, the action packets will arrive before the object is created
230 Update();
231 }
Destruct(Replica * replica,SystemAddress systemAddress,bool broadcast)232 void ReplicaManager::Destruct(Replica *replica, SystemAddress systemAddress, bool broadcast)
233 {
234 RakAssert(replica);
235
236 bool sendTimestamp;
237 bool objectExists;
238 unsigned replicatedObjectsIndex;
239 replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
240 if (objectExists==false)
241 return;
242
243 // For each existing participant, send a packet telling them of this object destruction
244 RakNet::BitStream outBitstream, userDataBitStream;
245 unsigned i,tempIndex;
246 bool replicaReferenced;
247 ParticipantStruct *participantStruct;
248 replicaReferenced=false;
249 for (i=0; i < participantList.Size(); i++)
250 {
251 participantStruct=participantList[i];
252
253 if ((broadcast==true && systemAddress!=participantStruct->systemAddress) ||
254 (broadcast==false && systemAddress==participantStruct->systemAddress))
255 {
256 // Remove any remote object state tracking for this object, for this player
257 tempIndex = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
258 if (objectExists)
259 {
260 // Send the destruction packet immediately
261 if (replica->GetNetworkID()!=UNASSIGNED_NETWORK_ID &&
262 (replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_DESTRUCTION))
263 {
264 userDataBitStream.Reset();
265 userDataBitStream.Write((MessageID)ID_REPLICA_MANAGER_DESTRUCTION);
266 userDataBitStream.Write(replica->GetNetworkID());
267 sendTimestamp=false;
268 ReplicaReturnResult res = replica->SendDestruction(&userDataBitStream, participantStruct->systemAddress, &sendTimestamp);
269 if (res==REPLICA_PROCESSING_DONE)
270 {
271 outBitstream.Reset();
272 if (sendTimestamp)
273 {
274 outBitstream.Write((MessageID)ID_TIMESTAMP);
275 outBitstream.Write(RakNet::GetTime());
276 outBitstream.Write(&userDataBitStream);
277 SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
278 }
279 else
280 SendUnified(&userDataBitStream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
281 }
282 }
283
284 participantStruct->remoteObjectList.RemoveAtIndex(tempIndex);
285 }
286
287 // Remove any pending commands that reference this object, for this player
288 tempIndex = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
289 // tempIndex = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
290 if (objectExists)
291 participantStruct->commandList.RemoveAtIndex(tempIndex);
292 }
293 else if (replicaReferenced==false)
294 {
295 bool objectExists;
296 GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
297 // See if any commands or objects reference replica
298 //if (participantStruct->commandList.HasData(replica))
299 if (objectExists)
300 replicaReferenced=true;
301 else if (participantStruct->remoteObjectList.HasData(replica))
302 replicaReferenced=true;
303 }
304 }
305
306 // Remove replica from the list if no commands and no remote objects reference it
307 if (replicaReferenced==false)
308 replicatedObjects.RemoveAtIndex(replicatedObjectsIndex);
309 }
ReferencePointer(Replica * replica)310 void ReplicaManager::ReferencePointer(Replica *replica)
311 {
312 // Start tracking this object, if we are not already
313 if (replicatedObjects.HasData(replica)==false)
314 {
315 RegisteredReplica replicaAndTime;
316 replicaAndTime.replica=replica;
317 replicaAndTime.lastDeserializeTrue=0;
318 replicaAndTime.allowedInterfaces=REPLICA_SET_ALL;
319 replicaAndTime.referenceOrder=nextReferenceIndex++;
320 replicatedObjects.Insert(replica,replicaAndTime, true, __FILE__,__LINE__);
321 /// Try setting the network ID manager if the user forgot
322 if (replica->GetNetworkIDManager()==0)
323 replica->SetNetworkIDManager(rakPeerInterface->GetNetworkIDManager());
324 }
325 }
DereferencePointer(Replica * replica)326 void ReplicaManager::DereferencePointer(Replica *replica)
327 {
328 bool objectExists;
329 unsigned replicatedObjectsIndex;
330 unsigned tempIndex;
331 replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
332 if (objectExists==false)
333 return;
334 replicatedObjects.RemoveAtIndex(replicatedObjectsIndex);
335
336 ParticipantStruct *participantStruct;
337 unsigned i;
338 for (i=0; i < participantList.Size(); i++)
339 {
340 participantStruct=participantList[i];
341
342 // Remove any pending commands that reference this object for any player
343 tempIndex = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
344 // tempIndex = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
345 if (objectExists)
346 participantStruct->commandList.RemoveAtIndex(tempIndex);
347
348 // Remove any remote object state tracking for this object for any player
349 tempIndex = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
350 if (objectExists)
351 participantStruct->remoteObjectList.RemoveAtIndex(tempIndex);
352 }
353 }
SetScope(Replica * replica,bool inScope,SystemAddress systemAddress,bool broadcast)354 void ReplicaManager::SetScope(Replica *replica, bool inScope, SystemAddress systemAddress, bool broadcast)
355 {
356 RakAssert(replica);
357
358 // Autoreference the pointer if necessary. This way the user can call functions on an object without having to worry
359 // About the order of operations.
360 ReferencePointer(replica);
361
362 // For each player that we want, flag to call SendScopeChange if inScope is different from what they already have
363 unsigned i;
364 ParticipantStruct *participantStruct;
365 bool objectExists;
366 unsigned index;
367 CommandStruct replicaAndCommand;
368 if (inScope)
369 replicaAndCommand.command=REPLICA_SCOPE_TRUE;
370 else
371 replicaAndCommand.command=REPLICA_SCOPE_FALSE;
372 replicaAndCommand.replica=replica;
373 replicaAndCommand.userFlags=0;
374 for (i=0; i < participantList.Size(); i++)
375 {
376 participantStruct=participantList[i];
377
378 if ((broadcast==true && systemAddress!=participantStruct->systemAddress) ||
379 (broadcast==false && systemAddress==participantStruct->systemAddress))
380 {
381 // If there is already a pending command for this object, add to it. Otherwise, add a new pending command
382 index = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
383 // index = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
384 if (objectExists)
385 {
386 // Update a pending command
387 if (inScope)
388 {
389 participantStruct->commandList[index].command&=0xFF ^ REPLICA_SCOPE_FALSE; // Unset this bit
390 participantStruct->commandList[index].command|=REPLICA_SCOPE_TRUE; // Set this bit
391 }
392 else
393 {
394 participantStruct->commandList[index].command&=0xFF ^ REPLICA_SCOPE_TRUE; // Unset this bit
395 participantStruct->commandList[index].command|=REPLICA_SCOPE_FALSE; // Set this bit
396 }
397 }
398 else
399 {
400 // Add a new command, since there are no pending commands for this object
401 participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
402 }
403 }
404 }
405 }
SignalSerializeNeeded(Replica * replica,SystemAddress systemAddress,bool broadcast)406 void ReplicaManager::SignalSerializeNeeded(Replica *replica, SystemAddress systemAddress, bool broadcast)
407 {
408 RakAssert(replica);
409
410 // Autoreference the pointer if necessary. This way the user can call functions on an object without having to worry
411 // About the order of operations.
412 if (replicatedObjects.HasData(replica)==false)
413 ReferencePointer(replica);
414
415 // For each player that we want, if this object exists on that system, flag to call Serialize
416 // (this may not necessarily happen - it depends on if the object is inScope when Update actually processes it.)
417 unsigned i;
418 ParticipantStruct *participantStruct;
419 bool objectExists;
420 unsigned index;
421 CommandStruct replicaAndCommand;
422 replicaAndCommand.command=REPLICA_SERIALIZE;
423 replicaAndCommand.replica=replica;
424 replicaAndCommand.userFlags=0;
425 for (i=0; i < participantList.Size(); i++)
426 {
427 participantStruct=participantList[i];
428
429 if ((broadcast==true && systemAddress!=participantStruct->systemAddress) ||
430 (broadcast==false && systemAddress==participantStruct->systemAddress))
431 {
432 // If there is already a pending command for this object, add to it. Otherwise, add a new pending command
433 // index = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
434 index = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
435 if (objectExists)
436 {
437 participantStruct->commandList[index].command|=REPLICA_SERIALIZE; // Set this bit
438 }
439 else
440 {
441 // Add a new command, since there are no pending commands for this object
442 participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
443 }
444 }
445 }
446 }
SetReceiveConstructionCB(ReceiveConstructionInterface * ReceiveConstructionInterface)447 void ReplicaManager::SetReceiveConstructionCB(ReceiveConstructionInterface *ReceiveConstructionInterface)
448 {
449 // Just overwrite the construction callback pointer
450 _constructionCB=ReceiveConstructionInterface;
451 }
SetDownloadCompleteCB(SendDownloadCompleteInterface * sendDownloadComplete,ReceiveDownloadCompleteInterface * receiveDownloadComplete)452 void ReplicaManager::SetDownloadCompleteCB(SendDownloadCompleteInterface *sendDownloadComplete, ReceiveDownloadCompleteInterface *receiveDownloadComplete)
453 {
454 // Just overwrite the send and receive download complete pointers.
455 _sendDownloadCompleteCB=sendDownloadComplete;
456 _receiveDownloadCompleteCB=receiveDownloadComplete;
457 }
SetSendChannel(unsigned char channel)458 void ReplicaManager::SetSendChannel(unsigned char channel)
459 {
460 // Change the send channel from the default of 0
461 sendChannel=channel;
462 }
SetAutoConstructToNewParticipants(bool autoConstruct)463 void ReplicaManager::SetAutoConstructToNewParticipants(bool autoConstruct)
464 {
465 autoConstructToNewParticipants=autoConstruct;
466 }
SetDefaultScope(bool scope)467 void ReplicaManager::SetDefaultScope(bool scope)
468 {
469 defaultScope=scope;
470 }
SetAutoSerializeInScope(bool autoSerialize)471 void ReplicaManager::SetAutoSerializeInScope(bool autoSerialize)
472 {
473 autoSerializeInScope=autoSerialize;
474 }
EnableReplicaInterfaces(Replica * replica,unsigned char interfaceFlags)475 void ReplicaManager::EnableReplicaInterfaces(Replica *replica, unsigned char interfaceFlags)
476 {
477 bool objectExists;
478 unsigned replicatedObjectsIndex;
479 replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
480 if (objectExists==false)
481 {
482 // Autoreference the pointer if necessary. This way the user can call functions on an object without having to worry
483 // About the order of operations.
484 ReferencePointer(replica);
485 replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
486 }
487 replicatedObjects[replicatedObjectsIndex].allowedInterfaces|=interfaceFlags;
488 }
DisableReplicaInterfaces(Replica * replica,unsigned char interfaceFlags)489 void ReplicaManager::DisableReplicaInterfaces(Replica *replica, unsigned char interfaceFlags)
490 {
491 bool objectExists;
492 unsigned replicatedObjectsIndex;
493 replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
494 if (objectExists==false)
495 {
496 // Autoreference the pointer if necessary. This way the user can call functions on an object without having to worry
497 // About the order of operations.
498 ReferencePointer(replica);
499 replicatedObjectsIndex = replicatedObjects.GetIndexFromKey(replica, &objectExists);
500 }
501 replicatedObjects[replicatedObjectsIndex].allowedInterfaces&= 0xFF ^ interfaceFlags;
502 }
IsConstructed(Replica * replica,SystemAddress systemAddress)503 bool ReplicaManager::IsConstructed(Replica *replica, SystemAddress systemAddress)
504 {
505 ParticipantStruct *participantStruct = GetParticipantBySystemAddress(systemAddress);
506 if (participantStruct)
507 {
508 bool objectExists;
509 participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
510 return objectExists;
511 }
512 return false;
513 }
IsInScope(Replica * replica,SystemAddress systemAddress)514 bool ReplicaManager::IsInScope(Replica *replica, SystemAddress systemAddress)
515 {
516 ParticipantStruct *participantStruct = GetParticipantBySystemAddress(systemAddress);
517 if (participantStruct)
518 {
519 bool objectExists;
520 unsigned remoteObjectListIndex = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
521 if (objectExists)
522 return participantStruct->remoteObjectList[remoteObjectListIndex].inScope;
523 }
524 return false;
525 }
GetReplicaCount(void) const526 unsigned ReplicaManager::GetReplicaCount(void) const
527 {
528 return replicatedObjects.Size();
529 }
GetReplicaAtIndex(unsigned index)530 Replica *ReplicaManager::GetReplicaAtIndex(unsigned index)
531 {
532 return replicatedObjects[index].replica;
533 }
GetParticipantCount(void) const534 unsigned ReplicaManager::GetParticipantCount(void) const
535 {
536 return participantList.Size();
537 }
GetParticipantAtIndex(unsigned index)538 SystemAddress ReplicaManager::GetParticipantAtIndex(unsigned index)
539 {
540 return participantList[index]->systemAddress;
541 }
HasParticipant(SystemAddress systemAddress)542 bool ReplicaManager::HasParticipant(SystemAddress systemAddress)
543 {
544 return participantList.HasData(systemAddress);
545 }
SignalSerializationFlags(Replica * replica,SystemAddress systemAddress,bool broadcast,bool set,unsigned int flags)546 void ReplicaManager::SignalSerializationFlags(Replica *replica, SystemAddress systemAddress, bool broadcast, bool set, unsigned int flags)
547 {
548 RakAssert(replica);
549
550 // Autoreference the pointer if necessary. This way the user can call functions on an object without having to worry
551 // About the order of operations.
552 ReferencePointer(replica);
553
554 CommandStruct replicaAndCommand;
555 replicaAndCommand.replica=replica;
556 replicaAndCommand.userFlags=flags;
557 replicaAndCommand.command=0;
558
559 bool objectExists;
560 unsigned i, index;
561 ParticipantStruct *participantStruct;
562 for (i=0; i < participantList.Size(); i++)
563 {
564 participantStruct=participantList[i];
565
566 if ((broadcast==true && systemAddress!=participantStruct->systemAddress) ||
567 (broadcast==false && systemAddress==participantStruct->systemAddress))
568 {
569 // Set the flags in the object if the object exists
570 index = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
571 if (objectExists)
572 {
573 if (set)
574 participantStruct->remoteObjectList[index].userFlags|=flags; // Set these user flags
575 else
576 participantStruct->remoteObjectList[index].userFlags&=~flags; // Unset these user flags
577 }
578 else
579 {
580 // The object is not yet created. Add to the pending command, or create a new command.
581 // index = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
582 index = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
583 if (objectExists)
584 {
585 if (set)
586 participantStruct->commandList[index].userFlags|=flags; // Set these user flags
587 else
588 participantStruct->commandList[index].userFlags&=~flags; // Unset these user flags
589 }
590 else if (set)
591 {
592 // Add a new command, since there are no pending commands for this object
593 participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
594 }
595 }
596 }
597 }
598 }
AccessSerializationFlags(Replica * replica,SystemAddress systemAddress)599 unsigned int* ReplicaManager::AccessSerializationFlags(Replica *replica, SystemAddress systemAddress)
600 {
601 RakAssert(replica);
602
603 // Autoreference the pointer if necessary. This way the user can call functions on an object without having to worry
604 // About the order of operations.
605 ReferencePointer(replica);
606
607 unsigned index;
608 bool objectExists;
609 ParticipantStruct *participantStruct;
610 CommandStruct replicaAndCommand;
611 replicaAndCommand.replica=replica;
612 replicaAndCommand.userFlags=0;
613 replicaAndCommand.command=0;
614
615 participantStruct=GetParticipantBySystemAddress(systemAddress);
616 if (participantStruct)
617 {
618 // Set the flags in the object if the object exists
619 index = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
620 if (objectExists)
621 {
622 return &(participantStruct->remoteObjectList[index].userFlags);
623 }
624 else
625 {
626 // index = participantStruct->commandList.GetIndexFromKey(replica, &objectExists);
627 index = GetCommandListReplicaIndex(participantStruct->commandList, replica, &objectExists);
628 if (objectExists)
629 {
630 return &(participantStruct->commandList[index].userFlags);
631 }
632 else
633 {
634 // Add a new command, since there are no pending commands for this object
635 //index =
636 participantStruct->commandList.Insert(replicaAndCommand, __FILE__, __LINE__);
637 // return &(participantStruct->commandList[index].userFlags);
638 return & (participantStruct->commandList[participantStruct->commandList.Size()-1].userFlags);
639 }
640 }
641 }
642
643 // No such participant
644 return 0;
645 }
646
Clear(void)647 void ReplicaManager::Clear(void)
648 {
649 // Free all memory
650 unsigned i;
651 for (i=0; i < participantList.Size(); i++)
652 RakNet::OP_DELETE(participantList[i], __FILE__, __LINE__);
653 participantList.Clear(false, __FILE__, __LINE__);
654 replicatedObjects.Clear(false, __FILE__, __LINE__);
655 nextReferenceIndex=0;
656 }
AssertReplicatedObjectsClear(void)657 void ReplicaManager::AssertReplicatedObjectsClear(void)
658 {
659 RakAssert(replicatedObjects.Size()==0);
660 }
AssertParticipantsClear(void)661 void ReplicaManager::AssertParticipantsClear(void)
662 {
663 RakAssert(participantList.Size()==0);
664 }
Update(void)665 void ReplicaManager::Update(void)
666 {
667 if (participantList.Size()==0)
668 return;
669
670 // Check for recursive calls, which is not supported and should not happen
671 #ifdef _DEBUG
672 RakAssert(inUpdate==false);
673 inUpdate=true;
674 #endif
675
676 unsigned participantIndex, remoteObjectListIndex, replicatedObjectsIndex;
677 ReplicaReturnResult res;
678 bool sendTimestamp;
679 ParticipantStruct *participantStruct;
680 unsigned commandListIndex;
681 RakNet::BitStream outBitstream, userDataBitstream;
682 RakNetTime currentTime;
683 bool objectExists;
684 PacketPriority priority;
685 PacketReliability reliability;
686 ReceivedCommand *receivedCommand;
687 Replica *replica;
688 // unsigned int userFlags;
689 unsigned char command;
690 currentTime=0;
691
692 // For each participant
693 for (participantIndex=0; participantIndex < participantList.Size(); participantIndex++)
694 {
695 participantStruct = participantList[participantIndex];
696
697 // Sends the download complete packet
698 // If callDownloadCompleteCB is true then check all the remaining objects starting at commandListIndex
699 // I scan every frame in case the callback returns false to delay, and after that time a new object is Replicated
700 if (participantStruct->callDownloadCompleteCB)
701 {
702 bool anyHasConstruction;
703 unsigned j;
704 anyHasConstruction=false;
705 for (j=0; j < participantStruct->commandList.Size(); j++)
706 {
707 if (participantStruct->commandList[j].command & REPLICA_EXPLICIT_CONSTRUCTION)
708 {
709 anyHasConstruction=true;
710 break;
711 }
712 }
713 // If none have REPLICA_EXPLICIT_CONSTRUCTION, send ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE and set callDownloadCompleteCB false
714 if (anyHasConstruction==false)
715 {
716 ReplicaReturnResult sendDLComplete;
717 userDataBitstream.Reset();
718 if (_sendDownloadCompleteCB)
719 sendDLComplete=_sendDownloadCompleteCB->SendDownloadComplete(&userDataBitstream, currentTime, participantStruct->systemAddress, this); // If you return false, this will be called again next update
720 else
721 sendDLComplete=REPLICA_CANCEL_PROCESS;
722 if (sendDLComplete==REPLICA_PROCESSING_DONE)
723 {
724 outBitstream.Reset();
725 outBitstream.Write((MessageID)ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE);
726 outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());
727 SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
728 participantStruct->callDownloadCompleteCB=false;
729 }
730 else if (sendDLComplete==REPLICA_CANCEL_PROCESS)
731 {
732 participantStruct->callDownloadCompleteCB=false;
733 }
734 else
735 {
736 RakAssert(sendDLComplete==REPLICA_PROCESS_LATER);
737 // else REPLICA_PROCESS_LATER
738 }
739 }
740 }
741
742 // For each CommandStruct to send
743 for (commandListIndex=0; commandListIndex < participantStruct->commandList.Size(); commandListIndex++)
744 {
745 // Only call RakNet::GetTime() once because it's slow
746 if (currentTime==0)
747 currentTime=RakNet::GetTime();
748
749 replica=participantStruct->commandList[commandListIndex].replica;
750 command=participantStruct->commandList[commandListIndex].command;
751 // userFlags=participantStruct->commandList[commandListIndex].userFlags;
752 replicatedObjectsIndex=replicatedObjects.GetIndexFromKey(replica, &objectExists);
753 #ifdef _DEBUG
754 RakAssert(objectExists);
755 #endif
756 if (objectExists==false)
757 continue;
758
759 // If construction is set, call SendConstruction. The only precondition is that the object was not already created,
760 // which was checked in ReplicaManager::Replicate
761 if (command & REPLICA_EXPLICIT_CONSTRUCTION)
762 {
763 if (replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_CONSTRUCTION)
764 {
765 userDataBitstream.Reset();
766 sendTimestamp=false;
767 res=replica->SendConstruction(currentTime, participantStruct->systemAddress,
768 participantStruct->commandList[commandListIndex].userFlags, &userDataBitstream, &sendTimestamp);
769
770 if (res==REPLICA_PROCESSING_DONE)
771 {
772 outBitstream.Reset();
773 // 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.
774 if (sendTimestamp)
775 {
776 outBitstream.Write((MessageID)ID_TIMESTAMP);
777 outBitstream.Write(currentTime);
778 }
779 outBitstream.Write((MessageID)ID_REPLICA_MANAGER_CONSTRUCTION);
780 // It's required to send an NetworkID if available.
781 // Problem:
782 // A->B->C
783 // | |
784 // D->E
785 //
786 // A creates.
787 // B->C->E->D->B will cycle forever.
788 // Fix is to always include an networkID. Objects are not created if that object id already is present.
789 if (replica->GetNetworkID()!=UNASSIGNED_NETWORK_ID)
790 {
791 outBitstream.Write(true);
792 outBitstream.Write(replica->GetNetworkID());
793 }
794 else
795 outBitstream.Write(false);
796
797 outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());
798
799 SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
800
801 // Turn off this bit
802 participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_EXPLICIT_CONSTRUCTION;
803
804 // Add the object to the participant's object list, indicating this object has been remotely created
805 RemoteObject remoteObject;
806 remoteObject.replica=replica;
807 //remoteObject.inScope=defaultScope;
808 remoteObject.inScope=false;
809 remoteObject.lastSendTime=0;
810 remoteObject.userFlags=participantStruct->commandList[commandListIndex].userFlags;
811 // Create an entry for this object. We do this now, even if the user might refuse the SendConstruction override,
812 // because that call may be delayed and other commands sent while that is pending. We always do the REPLICA_EXPLICIT_CONSTRUCTION call first.
813 participantStruct->remoteObjectList.Insert(remoteObject.replica,remoteObject, true, __FILE__,__LINE__);
814 }
815 else if (res==REPLICA_PROCESS_IMPLICIT)
816 {
817 // Turn off this bit
818 participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_EXPLICIT_CONSTRUCTION;
819
820 // Add the object to the participant's object list, indicating this object has been remotely created
821 RemoteObject remoteObject;
822 remoteObject.replica=replica;
823 //remoteObject.inScope=defaultScope;
824 remoteObject.inScope=false;
825 remoteObject.lastSendTime=0;
826 remoteObject.userFlags=participantStruct->commandList[commandListIndex].userFlags;
827 // Create an entry for this object. We do this now, even if the user might refuse the SendConstruction override,
828 // because that call may be delayed and other commands sent while that is pending. We always do the REPLICA_EXPLICIT_CONSTRUCTION call first.
829 participantStruct->remoteObjectList.Insert(remoteObject.replica,remoteObject, true, __FILE__,__LINE__);
830 }
831 else if (res==REPLICA_PROCESS_LATER)
832 {
833 continue;
834 }
835 else // REPLICA_CANCEL_PROCESS
836 {
837 RakAssert(res==REPLICA_CANCEL_PROCESS);
838 participantStruct->commandList[commandListIndex].command=0;
839 }
840 }
841 else
842 {
843 // Don't allow construction, or anything else for this object, as the construction send call is disallowed
844 participantStruct->commandList[commandListIndex].command=0;
845 }
846 }
847 else if (command & REPLICA_IMPLICIT_CONSTRUCTION)
848 {
849 // Turn off this bit
850 participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_IMPLICIT_CONSTRUCTION;
851
852 // Add the object to the participant's object list, indicating this object is assumed to be remotely created
853 RemoteObject remoteObject;
854 remoteObject.replica=replica;
855 //remoteObject.inScope=defaultScope;
856 remoteObject.inScope=false;
857 remoteObject.lastSendTime=0;
858 remoteObject.userFlags=participantStruct->commandList[commandListIndex].userFlags;
859 // Create an entry for this object. We do this now, even if the user might refuse the SendConstruction override,
860 // because that call may be delayed and other commands sent while that is pending. We always do the REPLICA_EXPLICIT_CONSTRUCTION call first.
861 participantStruct->remoteObjectList.Insert(remoteObject.replica,remoteObject, true, __FILE__,__LINE__);
862 }
863
864 // The remaining commands, SendScopeChange and Serialize, require the object the command references exists on the remote system, so check that
865 remoteObjectListIndex = participantStruct->remoteObjectList.GetIndexFromKey(replica, &objectExists);
866 if (objectExists)
867 {
868 command = participantStruct->commandList[commandListIndex].command;
869
870 // Process SendScopeChange.
871 if ((command & (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE)))
872 {
873 if (replica->GetNetworkID()==UNASSIGNED_NETWORK_ID)
874 continue; // Not set yet so call this later.
875
876 if (replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_SCOPE_CHANGE)
877 {
878 bool scopeTrue = (command & REPLICA_SCOPE_TRUE)!=0;
879
880 // Only send scope changes if the requested change is different from what they already have
881 if (participantStruct->remoteObjectList[remoteObjectListIndex].inScope!=scopeTrue)
882 {
883 userDataBitstream.Reset();
884 sendTimestamp=false;
885 res=replica->SendScopeChange(scopeTrue, &userDataBitstream, currentTime, participantStruct->systemAddress, &sendTimestamp);
886
887 if (res==REPLICA_PROCESSING_DONE)
888 {
889 // 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.
890 outBitstream.Reset();
891 if (sendTimestamp)
892 {
893 outBitstream.Write((MessageID)ID_TIMESTAMP);
894 outBitstream.Write(currentTime);
895 }
896 outBitstream.Write((MessageID)ID_REPLICA_MANAGER_SCOPE_CHANGE);
897 outBitstream.Write(replica->GetNetworkID());
898 outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());
899 SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, sendChannel, participantStruct->systemAddress, false);
900
901 // Set the scope for this object and system
902 participantStruct->remoteObjectList[remoteObjectListIndex].inScope=scopeTrue;
903
904 // If scope is true, turn on serialize, since you virtually always want to serialize when an object goes in scope
905 if (scopeTrue && autoSerializeInScope)
906 participantStruct->commandList[commandListIndex].command |= REPLICA_SERIALIZE;
907
908 // Turn off these bits - Call is processed
909 participantStruct->commandList[commandListIndex].command &= 0xFF ^ (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE);
910 }
911 else if (res==REPLICA_CANCEL_PROCESS)
912 {
913 // Turn off these bits - Call is canceled
914 participantStruct->commandList[commandListIndex].command &= 0xFF ^ (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE);
915 }
916 else
917 {
918 // 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.
919 if (scopeTrue==false)
920 continue;
921
922 // If the user returns false and the scope is currently set to false, process the next command for this CommandStruct, if any.
923 }
924 }
925 }
926 else
927 {
928 // Turn off these bits - Call is disallowed
929 participantStruct->commandList[commandListIndex].command &= 0xFF ^ (REPLICA_SCOPE_TRUE | REPLICA_SCOPE_FALSE);
930
931 // Set the scope - even if the actual send is disabled we might still be able to serialize.
932 participantStruct->remoteObjectList[remoteObjectListIndex].inScope=(command & REPLICA_SCOPE_TRUE)!=0;
933 }
934 }
935
936 command = participantStruct->commandList[commandListIndex].command;
937 // Process Serialize
938 if ((command & REPLICA_SERIALIZE))
939 {
940 if (replica->GetNetworkID()==UNASSIGNED_NETWORK_ID)
941 continue; // Not set yet so call this later.
942
943 // If scope is currently false for this object in the RemoteObject list, cancel this serialize as the scope changed before the serialization went out
944 if (participantStruct->remoteObjectList[remoteObjectListIndex].inScope && (replicatedObjects[replicatedObjectsIndex].allowedInterfaces & REPLICA_SEND_SERIALIZE))
945 {
946 do
947 {
948 userDataBitstream.Reset();
949 priority=HIGH_PRIORITY;
950 reliability=RELIABLE_ORDERED;
951 sendTimestamp=false;
952 res=replica->Serialize(&sendTimestamp, &userDataBitstream, participantStruct->remoteObjectList[remoteObjectListIndex].lastSendTime, &priority, &reliability, currentTime, participantStruct->systemAddress, participantStruct->remoteObjectList[remoteObjectListIndex].userFlags);
953
954 if (res==REPLICA_PROCESSING_DONE || res==REPLICA_PROCESS_AGAIN)
955 {
956 participantStruct->remoteObjectList[remoteObjectListIndex].lastSendTime=currentTime;
957
958 outBitstream.Reset();
959 if (sendTimestamp)
960 {
961 outBitstream.Write((MessageID)ID_TIMESTAMP);
962 outBitstream.Write(currentTime);
963 }
964 outBitstream.Write((MessageID)ID_REPLICA_MANAGER_SERIALIZE);
965 outBitstream.Write(replica->GetNetworkID());
966 outBitstream.Write(&userDataBitstream, userDataBitstream.GetNumberOfBitsUsed());
967 SendUnified(&outBitstream, priority, reliability, sendChannel, participantStruct->systemAddress, false);
968
969 // Clear the serialize bit when done
970 if (res==REPLICA_PROCESSING_DONE)
971 participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_SERIALIZE;
972 // else res==REPLICA_PROCESS_AGAIN so it will repeat the enclosing do {} while(); loop
973 }
974 else if (res==REPLICA_CANCEL_PROCESS)
975 {
976 // Clear the serialize bit
977 participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_SERIALIZE;
978 }
979 else
980 {
981 // if the user returns REPLICA_PROCESS_LATER, just continue with another CommandStruct.
982 RakAssert(res==REPLICA_PROCESS_LATER);
983 }
984 } while(res==REPLICA_PROCESS_AGAIN);
985 }
986 else
987 {
988 // Cancel this serialize
989 participantStruct->commandList[commandListIndex].command &= 0xFF ^ REPLICA_SERIALIZE;
990 }
991 }
992 }
993 }
994
995 // 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
996 commandListIndex=participantStruct->commandList.Size();
997 if (commandListIndex>0)
998 {
999 #ifdef _MSC_VER
1000 #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
1001 #endif
1002 while (1)
1003 {
1004 if (participantStruct->commandList[commandListIndex-1].command==0)
1005 {
1006 // 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
1007 participantStruct->commandList.RemoveAtIndex(commandListIndex-1);
1008 }
1009
1010 if (--commandListIndex==0)
1011 break;
1012 }
1013 }
1014
1015 // Now process queued receives
1016 while (participantStruct->pendingCommands.Size())
1017 {
1018 receivedCommand=participantStruct->pendingCommands.Pop();
1019 participantStruct=GetParticipantBySystemAddress(receivedCommand->systemAddress);
1020 if (participantStruct)
1021 {
1022 res=ProcessReceivedCommand(participantStruct, receivedCommand);
1023 // Returning false means process this command again later
1024 if (res==REPLICA_PROCESS_LATER)
1025 {
1026 // Push the command back in the queue
1027 participantStruct->pendingCommands.PushAtHead(receivedCommand, 0, __FILE__,__LINE__);
1028
1029 // Stop processing, because all processing is in order
1030 break;
1031 }
1032 else
1033 {
1034 RakAssert(res==REPLICA_CANCEL_PROCESS);
1035 }
1036 }
1037
1038 // Done with this command, so delete it
1039 RakNet::OP_DELETE(receivedCommand->userData, __FILE__, __LINE__);
1040 RakNet::OP_DELETE(receivedCommand, __FILE__, __LINE__);
1041 }
1042 }
1043 #ifdef _DEBUG
1044 inUpdate=false;
1045 #endif
1046 }
OnClosedConnection(SystemAddress systemAddress,RakNetGUID rakNetGUID,PI2_LostConnectionReason lostConnectionReason)1047 void ReplicaManager::OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
1048 {
1049 (void) systemAddress;
1050 (void) rakNetGUID;
1051 (void) lostConnectionReason;
1052
1053 RemoveParticipant(systemAddress);
1054 }
OnRakPeerShutdown(void)1055 void ReplicaManager::OnRakPeerShutdown(void)
1056 {
1057 Clear();
1058 }
OnNewConnection(SystemAddress systemAddress,RakNetGUID rakNetGUID,bool isIncoming)1059 void ReplicaManager::OnNewConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
1060 {
1061 (void) systemAddress;
1062 (void) rakNetGUID;
1063 (void) isIncoming;
1064
1065 if (autoParticipateNewConnections)
1066 AddParticipant(systemAddress);
1067 }
OnReceive(Packet * packet)1068 PluginReceiveResult ReplicaManager::OnReceive(Packet *packet)
1069 {
1070 unsigned char packetIdentifier;
1071 if ( ( unsigned char ) packet->data[ 0 ] == ID_TIMESTAMP )
1072 {
1073 if ( packet->length > sizeof( unsigned char ) + sizeof( unsigned int ) )
1074 packetIdentifier = ( unsigned char ) packet->data[ sizeof( unsigned char ) + sizeof( unsigned int ) ];
1075 else
1076 return RR_STOP_PROCESSING_AND_DEALLOCATE;
1077 }
1078 else
1079 packetIdentifier = ( unsigned char ) packet->data[ 0 ];
1080
1081 switch (packetIdentifier)
1082 {
1083 case ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE:
1084 if (_receiveDownloadCompleteCB==0)
1085 {
1086 return RR_STOP_PROCESSING_AND_DEALLOCATE;
1087 }
1088 case ID_REPLICA_MANAGER_CONSTRUCTION:
1089 case ID_REPLICA_MANAGER_DESTRUCTION:
1090 case ID_REPLICA_MANAGER_SCOPE_CHANGE:
1091 case ID_REPLICA_MANAGER_SERIALIZE:
1092 {
1093 ParticipantStruct *participantStruct;
1094 bool hasNetworkId=false;
1095 ReceivedCommand receivedCommand;
1096 bool b=true;
1097 RakNet::BitStream inBitstream(packet->data, packet->length, false);
1098 // SetWriteOffset is used here to get around a design flaw, where I should have had the bitstream constructor take bits, rather than bytes
1099 // It sets the actual number of bits in the packet
1100 inBitstream.SetWriteOffset(packet->bitSize);
1101 receivedCommand.systemAddress=packet->systemAddress;
1102 receivedCommand.command=packetIdentifier;
1103
1104 if ( ( unsigned char ) packet->data[ 0 ] == ID_TIMESTAMP )
1105 {
1106 inBitstream.IgnoreBits(8);
1107 b=inBitstream.Read(receivedCommand.u1);
1108 }
1109 else
1110 receivedCommand.u1=0;
1111 inBitstream.IgnoreBits(8); // Ignore the packet id
1112 receivedCommand.networkID=UNASSIGNED_NETWORK_ID;
1113 if (packetIdentifier==ID_REPLICA_MANAGER_CONSTRUCTION) // ID_REPLICA_MANAGER_CONSTRUCTION has an optional networkID
1114 {
1115 b=inBitstream.Read(hasNetworkId);
1116 if (hasNetworkId)
1117 b=inBitstream.Read(receivedCommand.networkID);
1118 }
1119 else if (packetIdentifier!=ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE)
1120 {
1121 b=inBitstream.Read(receivedCommand.networkID); // Other packets always have an networkID
1122 }
1123
1124 if (b==false)
1125 {
1126 // Invalid packet
1127 #ifdef _DEBUG
1128 RakAssert(0);
1129 #endif
1130 return RR_STOP_PROCESSING_AND_DEALLOCATE;
1131 }
1132 receivedCommand.userData=&inBitstream;
1133 participantStruct=GetParticipantBySystemAddress(receivedCommand.systemAddress);
1134 if (participantStruct)
1135 {
1136 // .Size()>0 is because commands are always processed in order. If a command is delayed, no further commands are processed.
1137 // ProcessReceivedCommand(...)==false means that the use signaled to delay a command
1138 if (participantStruct->pendingCommands.Size()>0 || ProcessReceivedCommand(participantStruct, &receivedCommand)==REPLICA_PROCESS_LATER)
1139 {
1140 // Copy the data and add this to a queue that will call ProcessReceivedCommand again in Update.
1141
1142 // Allocate and copy structure
1143 ReceivedCommand *rc = RakNet::OP_NEW<ReceivedCommand>( __FILE__, __LINE__ );
1144 memcpy(rc, &receivedCommand, sizeof(ReceivedCommand));
1145
1146 // Allocate and copy inBitstream remaining data
1147 rc->userData = RakNet::OP_NEW<RakNet::BitStream>( __FILE__, __LINE__ );
1148 rc->userData->Write(&inBitstream, inBitstream.GetNumberOfBitsUsed());
1149
1150 participantStruct->pendingCommands.Push(rc, __FILE__, __LINE__ );
1151 }
1152 }
1153
1154 return RR_STOP_PROCESSING_AND_DEALLOCATE;
1155 }
1156 }
1157
1158 return RR_CONTINUE_PROCESSING;
1159 }
1160
GetParticipantBySystemAddress(const SystemAddress systemAddress) const1161 ReplicaManager::ParticipantStruct* ReplicaManager::GetParticipantBySystemAddress(const SystemAddress systemAddress) const
1162 {
1163 bool objectExists;
1164 unsigned index;
1165 index = participantList.GetIndexFromKey(systemAddress, &objectExists);
1166 if (objectExists==false)
1167 return 0;
1168 return participantList[index];
1169 }
1170 #ifdef _MSC_VER
1171 #pragma warning( disable : 4701 ) // warning C4701: local variable <variable name> may be used without having been initialized
1172 #endif
ProcessReceivedCommand(ParticipantStruct * participantStruct,ReceivedCommand * receivedCommand)1173 ReplicaReturnResult ReplicaManager::ProcessReceivedCommand(ParticipantStruct *participantStruct, ReceivedCommand *receivedCommand)
1174 {
1175 (void) participantStruct;
1176
1177 // If this assert hits you didn't first call RakPeer::SetNetworkIDManager as required.
1178 RakAssert(rakPeerInterface->GetNetworkIDManager());
1179 if (rakPeerInterface->GetNetworkIDManager()==0)
1180 return REPLICA_CANCEL_PROCESS;
1181
1182 Replica *replica = (Replica*) rakPeerInterface->GetNetworkIDManager()->GET_BASE_OBJECT_FROM_ID(receivedCommand->networkID);
1183
1184 bool objectExists;
1185 unsigned index=0;
1186 ReplicaReturnResult b;
1187 if (replica)
1188 {
1189 index = replicatedObjects.GetIndexFromKey(replica, &objectExists);
1190 if (objectExists==false)
1191 {
1192 if (receivedCommand->command==ID_REPLICA_MANAGER_CONSTRUCTION)
1193 {
1194 // Object already exists with this ID, but call construction anyway
1195 #ifdef _DEBUG
1196 RakAssert(_constructionCB);
1197 #endif
1198 // Call the registered callback. If it crashes, you forgot to register the callback in SetReceiveConstructionCB
1199 return _constructionCB->ReceiveConstruction(receivedCommand->userData, receivedCommand->u1, receivedCommand->networkID, replica, receivedCommand->systemAddress, this);
1200 }
1201 else
1202 {
1203 // This networkID is already in use but ReferencePointer was never called on it.
1204 // RakAssert(0);
1205 return REPLICA_CANCEL_PROCESS;
1206 }
1207
1208 }
1209 }
1210
1211 if (receivedCommand->command==ID_REPLICA_MANAGER_SERIALIZE)
1212 {
1213 if (replica && (replicatedObjects[index].allowedInterfaces & REPLICA_RECEIVE_SERIALIZE))
1214 {
1215 b=replica->Deserialize(receivedCommand->userData, receivedCommand->u1, replicatedObjects[index].lastDeserializeTrue, receivedCommand->systemAddress);
1216 if (b==REPLICA_PROCESSING_DONE)
1217 replicatedObjects[index].lastDeserializeTrue=RakNet::GetTime();
1218 return b;
1219 }
1220 }
1221 else if (receivedCommand->command==ID_REPLICA_MANAGER_CONSTRUCTION)
1222 {
1223 // If networkID already exists on this system, ignore the packet
1224 #ifdef _DEBUG
1225 RakAssert(_constructionCB);
1226 #endif
1227 // Call the registered callback. If it crashes, you forgot to register the callback in SetReceiveConstructionCB
1228 return _constructionCB->ReceiveConstruction(receivedCommand->userData, receivedCommand->u1, receivedCommand->networkID, replica, receivedCommand->systemAddress, this);
1229 }
1230 else if (receivedCommand->command==ID_REPLICA_MANAGER_SCOPE_CHANGE)
1231 {
1232 if (replica && (replicatedObjects[index].allowedInterfaces & REPLICA_RECEIVE_SCOPE_CHANGE))
1233 {
1234 return replica->ReceiveScopeChange(receivedCommand->userData, receivedCommand->systemAddress, receivedCommand->u1);
1235 }
1236 }
1237 else if (receivedCommand->command==ID_REPLICA_MANAGER_DESTRUCTION)
1238 {
1239 if (replica && (replicatedObjects[index].allowedInterfaces & REPLICA_RECEIVE_DESTRUCTION))
1240 {
1241 return replica->ReceiveDestruction(receivedCommand->userData, receivedCommand->systemAddress, receivedCommand->u1);
1242 }
1243 }
1244 else if (receivedCommand->command==ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE)
1245 {
1246 if (_receiveDownloadCompleteCB)
1247 {
1248 return _receiveDownloadCompleteCB->ReceiveDownloadComplete(receivedCommand->userData, receivedCommand->systemAddress, this);
1249 }
1250 }
1251
1252 return REPLICA_CANCEL_PROCESS;
1253 }
1254
~ParticipantStruct()1255 ReplicaManager::ParticipantStruct::~ParticipantStruct()
1256 {
1257 ReceivedCommand *receivedCommand;
1258 while ( pendingCommands.Size() )
1259 {
1260 receivedCommand=pendingCommands.Pop();
1261 RakNet::OP_DELETE(receivedCommand->userData, __FILE__, __LINE__);
1262 RakNet::OP_DELETE(receivedCommand, __FILE__, __LINE__);
1263 }
1264 }
1265
GetCommandListReplicaIndex(const DataStructures::List<ReplicaManager::CommandStruct> & commandList,Replica * replica,bool * objectExists) const1266 unsigned ReplicaManager::GetCommandListReplicaIndex(const DataStructures::List<ReplicaManager::CommandStruct> &commandList, Replica *replica, bool *objectExists) const
1267 {
1268 unsigned i;
1269 for (i=0; i < commandList.Size(); i++)
1270 {
1271 if (commandList[i].replica==replica)
1272 {
1273 *objectExists=true;
1274 return i;
1275 }
1276 }
1277 *objectExists=false;
1278 return 0;
1279 }
1280
1281 #ifdef _MSC_VER
1282 #pragma warning( pop )
1283 #endif
1284
1285 #endif // _RAKNET_SUPPORT_*
1286