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