Files
mcpe/thirdparty/raknet/ReplicaManager3.cpp
iProgramInCpp 9642818a88 * Initial commit.
:)
2023-07-30 22:22:02 +03:00

2594 lines
92 KiB
C++

/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_ReplicaManager3==1
#include "ReplicaManager3.h"
#include "GetTime.h"
#include "MessageIdentifiers.h"
#include "RakPeerInterface.h"
#include "NetworkIDManager.h"
using namespace RakNet;
// DEFINE_MULTILIST_PTR_TO_MEMBER_COMPARISONS(LastSerializationResult,Replica3*,replica);
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool PRO::operator==( const PRO& right ) const
{
return priority == right.priority && reliability == right.reliability && orderingChannel == right.orderingChannel && sendReceipt == right.sendReceipt;
}
bool PRO::operator!=( const PRO& right ) const
{
return priority != right.priority || reliability != right.reliability || orderingChannel != right.orderingChannel || sendReceipt != right.sendReceipt;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int Connection_RM3::Replica3LSRComp( Replica3 * const &replica3, LastSerializationResult * const &data )
{
/*
if (replica3->GetNetworkID() < data->replica->GetNetworkID())
return -1;
if (replica3->GetNetworkID() > data->replica->GetNetworkID())
return 1;
*/
// 7/28/2013 - If GetNetworkID chagned during runtime, the list would be out of order and lookup would always fail or go out of bounds
// I remember before that I could not directly compare
if (replica3->referenceIndex < data->replica->referenceIndex)
return -1;
if (replica3->referenceIndex > data->replica->referenceIndex)
return 1;
return 0;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
LastSerializationResult::LastSerializationResult()
{
replica=0;
lastSerializationResultBS=0;
whenLastSerialized = RakNet::GetTime();
}
LastSerializationResult::~LastSerializationResult()
{
if (lastSerializationResultBS)
RakNet::OP_DELETE(lastSerializationResultBS,_FILE_AND_LINE_);
}
void LastSerializationResult::AllocBS(void)
{
if (lastSerializationResultBS==0)
{
lastSerializationResultBS=RakNet::OP_NEW<LastSerializationResultBS>(_FILE_AND_LINE_);
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ReplicaManager3::ReplicaManager3()
{
defaultSendParameters.orderingChannel=0;
defaultSendParameters.priority=HIGH_PRIORITY;
defaultSendParameters.reliability=RELIABLE_ORDERED;
defaultSendParameters.sendReceipt=0;
autoSerializeInterval=30;
lastAutoSerializeOccurance=0;
autoCreateConnections=true;
autoDestroyConnections=true;
currentlyDeallocatingReplica=0;
for (unsigned int i=0; i < 255; i++)
worldsArray[i]=0;
AddWorld(0);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ReplicaManager3::~ReplicaManager3()
{
if (autoDestroyConnections)
{
for (unsigned int i=0; i < worldsList.Size(); i++)
{
RakAssert(worldsList[i]->connectionList.Size()==0);
}
}
Clear(true);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::SetAutoManageConnections(bool autoCreate, bool autoDestroy)
{
autoCreateConnections=autoCreate;
autoDestroyConnections=autoDestroy;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool ReplicaManager3::GetAutoCreateConnections(void) const
{
return autoCreateConnections;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool ReplicaManager3::GetAutoDestroyConnections(void) const
{
return autoDestroyConnections;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::AutoCreateConnectionList(
DataStructures::List<RakNetGUID> &participantListIn,
DataStructures::List<Connection_RM3*> &participantListOut,
WorldId worldId)
{
for (unsigned int index=0; index < participantListIn.Size(); index++)
{
if (GetConnectionByGUID(participantListIn[index], worldId)==nullptr)//false)
{
Connection_RM3 *connection = AllocConnection(rakPeerInterface->GetSystemAddressFromGuid(participantListIn[index]), participantListIn[index]);
if (connection)
{
PushConnection(connection);
participantListOut.Push(connection, _FILE_AND_LINE_);
}
}
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool ReplicaManager3::PushConnection(RakNet::Connection_RM3 *newConnection, WorldId worldId)
{
if (newConnection==0)
return false;
if (GetConnectionByGUID(newConnection->GetRakNetGUID(), worldId))
return false;
// Was this intended?
RakAssert(newConnection->GetRakNetGUID()!=rakPeerInterface->GetMyGUID());
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
unsigned int index = world->connectionList.GetIndexOf(newConnection);
if (index==(unsigned int)-1)
{
world->connectionList.Push(newConnection,_FILE_AND_LINE_);
// Send message to validate the connection
newConnection->SendValidation(rakPeerInterface, worldId);
Connection_RM3::ConstructionMode constructionMode = newConnection->QueryConstructionMode();
if (constructionMode==Connection_RM3::QUERY_REPLICA_FOR_CONSTRUCTION || constructionMode==Connection_RM3::QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION)
{
unsigned int pushIdx;
for (pushIdx=0; pushIdx < world->userReplicaList.Size(); pushIdx++)
newConnection->OnLocalReference(world->userReplicaList[pushIdx], this);
}
}
return true;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::DeallocReplicaNoBroadcastDestruction(RakNet::Connection_RM3 *connection, RakNet::Replica3 *replica3)
{
currentlyDeallocatingReplica=replica3;
replica3->DeallocReplica(connection);
currentlyDeallocatingReplica=0;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RakNet::Connection_RM3 * ReplicaManager3::PopConnection(unsigned int index, WorldId worldId)
{
DataStructures::List<Replica3*> replicaList;
DataStructures::List<NetworkID> destructionList;
DataStructures::List<Replica3*> broadcastList;
RakNet::Connection_RM3 *connection;
unsigned int index2;
RM3ActionOnPopConnection action;
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
connection=world->connectionList[index];
// Clear out downloadGroup
connection->ClearDownloadGroup(rakPeerInterface);
RakNetGUID guid = connection->GetRakNetGUID();
// This might be wrong, I am relying on the variable creatingSystemGuid which is transmitted
// automatically from the first system to reference the object. However, if an object changes
// owners then it is not going to be returned here, and therefore QueryActionOnPopConnection()
// will not be called for the new owner.
GetReplicasCreatedByGuid(guid, replicaList);
for (index2=0; index2 < replicaList.Size(); index2++)
{
action = replicaList[index2]->QueryActionOnPopConnection(connection);
replicaList[index2]->OnPoppedConnection(connection);
if (action==RM3AOPC_DELETE_REPLICA)
{
if (replicaList[index2]->GetNetworkIDManager())
destructionList.Push( replicaList[index2]->GetNetworkID(), _FILE_AND_LINE_ );
}
else if (action==RM3AOPC_DELETE_REPLICA_AND_BROADCAST_DESTRUCTION)
{
if (replicaList[index2]->GetNetworkIDManager())
destructionList.Push( replicaList[index2]->GetNetworkID(), _FILE_AND_LINE_ );
broadcastList.Push( replicaList[index2], _FILE_AND_LINE_ );
}
else if (action==RM3AOPC_DO_NOTHING)
{
for (unsigned int index3 = 0; index3 < connection->queryToSerializeReplicaList.Size(); index3++)
{
LastSerializationResult *lsr = connection->queryToSerializeReplicaList[index3];
lsr->whenLastSerialized=0;
if (lsr->lastSerializationResultBS)
{
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
lsr->lastSerializationResultBS->bitStream[z].Reset();
}
}
}
}
BroadcastDestructionList(broadcastList, connection->GetSystemAddress());
for (index2=0; index2 < destructionList.Size(); index2++)
{
// Do lookup in case DeallocReplica destroyed one of of the later Replica3 instances in the list
Replica3* replicaToDestroy = world->networkIDManager->GET_OBJECT_FROM_ID<Replica3*>(destructionList[index2]);
if (replicaToDestroy)
{
replicaToDestroy->PreDestruction(connection);
replicaToDestroy->DeallocReplica(connection);
}
}
world->connectionList.RemoveAtIndex(index);
return connection;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RakNet::Connection_RM3 * ReplicaManager3::PopConnection(RakNetGUID guid, WorldId worldId)
{
unsigned int index;
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
for (index=0; index < world->connectionList.Size(); index++)
{
if (world->connectionList[index]->GetRakNetGUID()==guid)
{
return PopConnection(index, worldId);
}
}
return 0;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::Reference(RakNet::Replica3 *replica3, WorldId worldId)
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
unsigned int index = ReferenceInternal(replica3, worldId);
if (index!=(unsigned int)-1)
{
unsigned int pushIdx;
for (pushIdx=0; pushIdx < world->connectionList.Size(); pushIdx++)
{
Connection_RM3::ConstructionMode constructionMode = world->connectionList[pushIdx]->QueryConstructionMode();
if (constructionMode==Connection_RM3::QUERY_REPLICA_FOR_CONSTRUCTION || constructionMode==Connection_RM3::QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION)
{
world->connectionList[pushIdx]->OnLocalReference(replica3, this);
}
}
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
unsigned int ReplicaManager3::ReferenceInternal(RakNet::Replica3 *replica3, WorldId worldId)
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
unsigned int index;
index = world->userReplicaList.GetIndexOf(replica3);
if (index==(unsigned int)-1)
{
RakAssert(world->networkIDManager);
replica3->SetNetworkIDManager(world->networkIDManager);
// If it crashes on rakPeerInterface==0 then you didn't call RakPeerInterface::AttachPlugin()
if (replica3->creatingSystemGUID==UNASSIGNED_RAKNET_GUID)
replica3->creatingSystemGUID=rakPeerInterface->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS);
replica3->replicaManager=this;
if (replica3->referenceIndex==(uint32_t)-1)
{
replica3->referenceIndex=nextReferenceIndex++;
}
world->userReplicaList.Push(replica3,_FILE_AND_LINE_);
return world->userReplicaList.Size()-1;
}
return (unsigned int) -1;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::Dereference(RakNet::Replica3 *replica3, WorldId worldId)
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
unsigned int index, index2;
for (index=0; index < world->userReplicaList.Size(); index++)
{
if (world->userReplicaList[index]==replica3)
{
world->userReplicaList.RemoveAtIndex(index);
break;
}
}
// Remove from all connections
for (index2=0; index2 < world->connectionList.Size(); index2++)
{
world->connectionList[index2]->OnDereference(replica3, this);
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::DereferenceList(DataStructures::List<Replica3*> &replicaListIn, WorldId worldId)
{
unsigned int index;
for (index=0; index < replicaListIn.Size(); index++)
Dereference(replicaListIn[index], worldId);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::GetReplicasCreatedByMe(DataStructures::List<Replica3*> &replicaListOut, WorldId worldId)
{
//RakNetGUID myGuid = rakPeerInterface->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS);
GetReplicasCreatedByGuid(rakPeerInterface->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS), replicaListOut, worldId);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::GetReferencedReplicaList(DataStructures::List<Replica3*> &replicaListOut, WorldId worldId)
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
replicaListOut=world->userReplicaList;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::GetReplicasCreatedByGuid(RakNetGUID guid, DataStructures::List<Replica3*> &replicaListOut, WorldId worldId)
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
replicaListOut.Clear(false,_FILE_AND_LINE_);
unsigned int index;
for (index=0; index < world->userReplicaList.Size(); index++)
{
if (world->userReplicaList[index]->creatingSystemGUID==guid)
replicaListOut.Push(world->userReplicaList[index],_FILE_AND_LINE_);
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
unsigned ReplicaManager3::GetReplicaCount(WorldId worldId) const
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
return world->userReplicaList.Size();
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Replica3 *ReplicaManager3::GetReplicaAtIndex(unsigned index, WorldId worldId)
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
return world->userReplicaList[index];
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
unsigned int ReplicaManager3::GetConnectionCount(WorldId worldId) const
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
return world->connectionList.Size();
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Connection_RM3* ReplicaManager3::GetConnectionAtIndex(unsigned index, WorldId worldId) const
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
return world->connectionList[index];
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Connection_RM3* ReplicaManager3::GetConnectionBySystemAddress(const SystemAddress &sa, WorldId worldId) const
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
unsigned int index;
for (index=0; index < world->connectionList.Size(); index++)
{
if (world->connectionList[index]->GetSystemAddress()==sa)
{
return world->connectionList[index];
}
}
return 0;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Connection_RM3* ReplicaManager3::GetConnectionByGUID(RakNetGUID guid, WorldId worldId) const
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
unsigned int index;
for (index=0; index < world->connectionList.Size(); index++)
{
if (world->connectionList[index]->GetRakNetGUID()==guid)
{
return world->connectionList[index];
}
}
return 0;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::SetDefaultOrderingChannel(char def)
{
defaultSendParameters.orderingChannel=def;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::SetDefaultPacketPriority(PacketPriority def)
{
defaultSendParameters.priority=def;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::SetDefaultPacketReliability(PacketReliability def)
{
defaultSendParameters.reliability=def;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::SetAutoSerializeInterval(RakNet::Time intervalMS)
{
autoSerializeInterval=intervalMS;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::GetConnectionsThatHaveReplicaConstructed(Replica3 *replica, DataStructures::List<Connection_RM3*> &connectionsThatHaveConstructedThisReplica, WorldId worldId)
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
connectionsThatHaveConstructedThisReplica.Clear(false,_FILE_AND_LINE_);
unsigned int index;
for (index=0; index < world->connectionList.Size(); index++)
{
if (world->connectionList[index]->HasReplicaConstructed(replica))
connectionsThatHaveConstructedThisReplica.Push(world->connectionList[index],_FILE_AND_LINE_);
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool ReplicaManager3::GetAllConnectionDownloadsCompleted(WorldId worldId) const
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
unsigned int index;
for (index=0; index < world->connectionList.Size(); index++)
{
if (world->connectionList[index]->GetDownloadWasCompleted()==false)
return false;
}
return true;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::Clear(bool deleteWorlds)
{
for (unsigned int i=0; i < worldsList.Size(); i++)
{
worldsList[i]->Clear(this);
if (deleteWorlds)
{
worldsArray[worldsList[i]->worldId]=0;
delete worldsList[i];
}
}
if (deleteWorlds)
worldsList.Clear(false, _FILE_AND_LINE_);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ReplicaManager3::RM3World::RM3World()
{
networkIDManager=0;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::RM3World::Clear(ReplicaManager3 *replicaManager3)
{
if (replicaManager3->GetAutoDestroyConnections())
{
for (unsigned int i=0; i < connectionList.Size(); i++)
replicaManager3->DeallocConnection(connectionList[i]);
}
else
{
// Clear out downloadGroup even if not auto destroying the connection, since the packets need to go back to RakPeer
for (unsigned int i=0; i < connectionList.Size(); i++)
connectionList[i]->ClearDownloadGroup(replicaManager3->GetRakPeerInterface());
}
for (unsigned int i=0; i < userReplicaList.Size(); i++)
{
userReplicaList[i]->replicaManager=0;
userReplicaList[i]->SetNetworkIDManager(0);
}
connectionList.Clear(true,_FILE_AND_LINE_);
userReplicaList.Clear(true,_FILE_AND_LINE_);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PRO ReplicaManager3::GetDefaultSendParameters(void) const
{
return defaultSendParameters;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::AddWorld(WorldId worldId)
{
RakAssert(worldsArray[worldId]==0 && "World already in use");
RM3World *newWorld = RakNet::OP_NEW<RM3World>(_FILE_AND_LINE_);
newWorld->worldId=worldId;
worldsArray[worldId]=newWorld;
worldsList.Push(newWorld,_FILE_AND_LINE_);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::RemoveWorld(WorldId worldId)
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
for (unsigned int i=0; i < worldsList.Size(); i++)
{
if (worldsList[i]==worldsArray[worldId])
{
RakNet::OP_DELETE(worldsList[i],_FILE_AND_LINE_);
worldsList.RemoveAtIndexFast(i);
break;
}
}
worldsArray[worldId]=0;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
NetworkIDManager *ReplicaManager3::GetNetworkIDManager(WorldId worldId) const
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
return world->networkIDManager;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::SetNetworkIDManager(NetworkIDManager *_networkIDManager, WorldId worldId)
{
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
world->networkIDManager=_networkIDManager;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PluginReceiveResult ReplicaManager3::OnReceive(Packet *packet)
{
if (packet->length<2)
return RR_CONTINUE_PROCESSING;
WorldId incomingWorldId;
RakNet::Time timestamp=0;
unsigned char packetIdentifier, packetDataOffset;
if ( ( unsigned char ) packet->data[ 0 ] == ID_TIMESTAMP )
{
if ( packet->length > sizeof( unsigned char ) + sizeof( RakNet::Time ) )
{
packetIdentifier = ( unsigned char ) packet->data[ sizeof( unsigned char ) + sizeof( RakNet::Time ) ];
// Required for proper endian swapping
RakNet::BitStream tsBs(packet->data+sizeof(MessageID),packet->length-1,false);
tsBs.Read(timestamp);
// Next line assumes worldId is only 1 byte
RakAssert(sizeof(WorldId)==1);
incomingWorldId=packet->data[sizeof( unsigned char )*2 + sizeof( RakNet::Time )];
packetDataOffset=sizeof( unsigned char )*3 + sizeof( RakNet::Time );
}
else
return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
else
{
packetIdentifier = ( unsigned char ) packet->data[ 0 ];
// Next line assumes worldId is only 1 byte
RakAssert(sizeof(WorldId)==1);
incomingWorldId=packet->data[sizeof( unsigned char )];
packetDataOffset=sizeof( unsigned char )*2;
}
if (worldsArray[incomingWorldId]==0)
return RR_CONTINUE_PROCESSING;
switch (packetIdentifier)
{
case ID_REPLICA_MANAGER_CONSTRUCTION:
return OnConstruction(packet, packet->data, packet->length, packet->guid, packetDataOffset, incomingWorldId);
case ID_REPLICA_MANAGER_SERIALIZE:
return OnSerialize(packet, packet->data, packet->length, packet->guid, timestamp, packetDataOffset, incomingWorldId);
case ID_REPLICA_MANAGER_DOWNLOAD_STARTED:
if (packet->wasGeneratedLocally==false)
{
return OnDownloadStarted(packet, packet->data, packet->length, packet->guid, packetDataOffset, incomingWorldId);
}
else
break;
case ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE:
if (packet->wasGeneratedLocally==false)
{
return OnDownloadComplete(packet, packet->data, packet->length, packet->guid, packetDataOffset, incomingWorldId);
}
else
break;
case ID_REPLICA_MANAGER_SCOPE_CHANGE:
{
Connection_RM3 *connection = GetConnectionByGUID(packet->guid, incomingWorldId);
if (connection && connection->isValidated==false)
{
// This connection is now confirmed bidirectional
connection->isValidated=true;
// Reply back on validation
connection->SendValidation(rakPeerInterface,incomingWorldId);
}
}
}
return RR_CONTINUE_PROCESSING;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::AutoConstructByQuery(ReplicaManager3 *replicaManager3, WorldId worldId)
{
ValidateLists(replicaManager3);
ConstructionMode constructionMode = QueryConstructionMode();
unsigned int index;
RM3ConstructionState constructionState;
LastSerializationResult *lsr;
index=0;
constructedReplicasCulled.Clear(false,_FILE_AND_LINE_);
destroyedReplicasCulled.Clear(false,_FILE_AND_LINE_);
if (constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION || constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION)
{
while (index < queryToConstructReplicaList.Size())
{
lsr=queryToConstructReplicaList[index];
constructionState=lsr->replica->QueryConstruction(this, replicaManager3);
if (constructionState==RM3CS_ALREADY_EXISTS_REMOTELY || constructionState==RM3CS_ALREADY_EXISTS_REMOTELY_DO_NOT_CONSTRUCT)
{
OnReplicaAlreadyExists(index, replicaManager3);
if (constructionState==RM3CS_ALREADY_EXISTS_REMOTELY)
constructedReplicasCulled.Push(lsr->replica,_FILE_AND_LINE_);
/*
if (constructionState==RM3CS_ALREADY_EXISTS_REMOTELY)
{
// Serialize construction data to this connection
RakNet::BitStream bsOut;
bsOut.Write((MessageID)ID_REPLICA_MANAGER_3_SERIALIZE_CONSTRUCTION_EXISTING);
bsOut.Write(replicaManager3->GetWorldID());
NetworkID networkId;
networkId=lsr->replica->GetNetworkID();
bsOut.Write(networkId);
BitSize_t bitsWritten = bsOut.GetNumberOfBitsUsed();
lsr->replica->SerializeConstructionExisting(&bsOut, this);
if (bsOut.GetNumberOfBitsUsed()!=bitsWritten)
replicaManager3->SendUnified(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,GetSystemAddress(), false);
}
// Serialize first serialization to this connection.
// This is done here, as it isn't done in PushConstruction
SerializeParameters sp;
RakNet::BitStream emptyBs;
for (index=0; index < (unsigned int) RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; index++)
{
sp.lastSentBitstream[index]=&emptyBs;
sp.pro[index]=replicaManager3->GetDefaultSendParameters();
}
sp.bitsWrittenSoFar=0;
sp.destinationConnection=this;
sp.messageTimestamp=0;
sp.whenLastSerialized=0;
RakNet::Replica3 *replica = lsr->replica;
RM3SerializationResult res = replica->Serialize(&sp);
if (res!=RM3SR_NEVER_SERIALIZE_FOR_THIS_CONNECTION &&
res!=RM3SR_DO_NOT_SERIALIZE &&
res!=RM3SR_SERIALIZED_UNIQUELY)
{
bool allIndices[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS];
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
{
sp.bitsWrittenSoFar+=sp.outputBitstream[z].GetNumberOfBitsUsed();
allIndices[z]=true;
}
if (SendSerialize(replica, allIndices, sp.outputBitstream, sp.messageTimestamp, sp.pro, replicaManager3->GetRakPeerInterface(), replicaManager3->GetWorldID())==SSICR_SENT_DATA)
lsr->replica->whenLastSerialized=RakNet::GetTimeMS();
}
*/
}
else if (constructionState==RM3CS_SEND_CONSTRUCTION)
{
OnConstructToThisConnection(index, replicaManager3);
RakAssert(lsr->replica);
constructedReplicasCulled.Push(lsr->replica,_FILE_AND_LINE_);
}
else if (constructionState==RM3CS_NEVER_CONSTRUCT)
{
OnNeverConstruct(index, replicaManager3);
}
else// if (constructionState==RM3CS_NO_ACTION)
{
// Do nothing
index++;
}
}
if (constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION)
{
RM3DestructionState destructionState;
index=0;
while (index < queryToDestructReplicaList.Size())
{
lsr=queryToDestructReplicaList[index];
destructionState=lsr->replica->QueryDestruction(this, replicaManager3);
if (destructionState==RM3DS_SEND_DESTRUCTION)
{
OnSendDestructionFromQuery(index, replicaManager3);
destroyedReplicasCulled.Push(lsr->replica,_FILE_AND_LINE_);
}
else if (destructionState==RM3DS_DO_NOT_QUERY_DESTRUCTION)
{
OnDoNotQueryDestruction(index, replicaManager3);
}
else// if (destructionState==RM3CS_NO_ACTION)
{
// Do nothing
index++;
}
}
}
}
else if (constructionMode==QUERY_CONNECTION_FOR_REPLICA_LIST)
{
QueryReplicaList(constructedReplicasCulled,destroyedReplicasCulled);
unsigned int idx1, idx2;
// Create new
for (idx2=0; idx2 < constructedReplicasCulled.Size(); idx2++)
OnConstructToThisConnection(constructedReplicasCulled[idx2], replicaManager3);
bool exists;
for (idx2=0; idx2 < destroyedReplicasCulled.Size(); idx2++)
{
exists=false;
bool objectExists;
idx1=constructedReplicaList.GetIndexFromKey(destroyedReplicasCulled[idx2], &objectExists);
if (objectExists)
{
constructedReplicaList.RemoveAtIndex(idx1);
unsigned int j;
for (j=0; j < queryToSerializeReplicaList.Size(); j++)
{
if (queryToSerializeReplicaList[j]->replica==destroyedReplicasCulled[idx2] )
{
queryToSerializeReplicaList.RemoveAtIndex(j);
break;
}
}
}
}
}
SendConstruction(constructedReplicasCulled,destroyedReplicasCulled,replicaManager3->defaultSendParameters,replicaManager3->rakPeerInterface,worldId,replicaManager3);
}
void ReplicaManager3::Update(void)
{
unsigned int index,index2,index3;
WorldId worldId;
RM3World *world;
RakNet::Time time = RakNet::GetTime();
for (index3=0; index3 < worldsList.Size(); index3++)
{
world = worldsList[index3];
worldId = world->worldId;
for (index=0; index < world->connectionList.Size(); index++)
{
if (world->connectionList[index]->isValidated==false)
continue;
world->connectionList[index]->AutoConstructByQuery(this, worldId);
}
}
if (time - lastAutoSerializeOccurance >= autoSerializeInterval)
{
for (index3=0; index3 < worldsList.Size(); index3++)
{
world = worldsList[index3];
worldId = world->worldId;
for (index=0; index < world->userReplicaList.Size(); index++)
{
world->userReplicaList[index]->forceSendUntilNextUpdate=false;
world->userReplicaList[index]->OnUserReplicaPreSerializeTick();
}
unsigned int index;
SerializeParameters sp;
sp.curTime=time;
Connection_RM3 *connection;
SendSerializeIfChangedResult ssicr;
LastSerializationResult *lsr;
sp.messageTimestamp=0;
for (int i=0; i < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; i++)
sp.pro[i]=defaultSendParameters;
index2=0;
for (index=0; index < world->connectionList.Size(); index++)
{
connection = world->connectionList[index];
sp.bitsWrittenSoFar=0;
index2=0;
sp.destinationConnection=connection;
DataStructures::List<Replica3*> replicasToSerialize;
replicasToSerialize.Clear(true, _FILE_AND_LINE_);
if (connection->QuerySerializationList(replicasToSerialize))
{
// Update replica->lsr so we can lookup in the next block
// lsr is per connection / per replica
while (index2 < connection->queryToSerializeReplicaList.Size())
{
connection->queryToSerializeReplicaList[index2]->replica->lsr=connection->queryToSerializeReplicaList[index2];
index2++;
}
// User is manually specifying list of replicas to serialize
index2=0;
while (index2 < replicasToSerialize.Size())
{
lsr=replicasToSerialize[index2]->lsr;
RakAssert(lsr->replica==replicasToSerialize[index2]);
sp.whenLastSerialized=lsr->whenLastSerialized;
ssicr=connection->SendSerializeIfChanged(lsr, &sp, GetRakPeerInterface(), worldId, this, time);
if (ssicr==SSICR_SENT_DATA)
lsr->whenLastSerialized=time;
index2++;
}
}
else
{
while (index2 < connection->queryToSerializeReplicaList.Size())
{
lsr=connection->queryToSerializeReplicaList[index2];
sp.destinationConnection=connection;
sp.whenLastSerialized=lsr->whenLastSerialized;
ssicr=connection->SendSerializeIfChanged(lsr, &sp, GetRakPeerInterface(), worldId, this, time);
if (ssicr==SSICR_SENT_DATA)
{
lsr->whenLastSerialized=time;
index2++;
}
else if (ssicr==SSICR_NEVER_SERIALIZE)
{
// Removed from the middle of the list
}
else
index2++;
}
}
}
}
lastAutoSerializeOccurance=time;
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
{
(void) lostConnectionReason;
(void) systemAddress;
if (autoDestroyConnections)
{
Connection_RM3 *connection = PopConnection(rakNetGUID);
if (connection)
DeallocConnection(connection);
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
{
(void) isIncoming;
if (autoCreateConnections)
{
Connection_RM3 *connection = AllocConnection(systemAddress, rakNetGUID);
if (connection)
PushConnection(connection);
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::OnRakPeerShutdown(void)
{
if (autoDestroyConnections)
{
RM3World *world;
unsigned int index3;
for (index3=0; index3 < worldsList.Size(); index3++)
{
world = worldsList[index3];
while (world->connectionList.Size())
{
Connection_RM3 *connection = PopConnection(world->connectionList.Size()-1, world->worldId);
if (connection)
DeallocConnection(connection);
}
}
}
Clear(false);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::OnDetach(void)
{
OnRakPeerShutdown();
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PluginReceiveResult ReplicaManager3::OnConstruction(Packet *packet, unsigned char *packetData, int packetDataLength, RakNetGUID senderGuid, unsigned char packetDataOffset, WorldId worldId)
{
RM3World *world = worldsArray[worldId];
Connection_RM3 *connection = GetConnectionByGUID(senderGuid, worldId);
if (connection==0)
{
// Almost certainly a bug
RakAssert("Got OnConstruction but no connection yet" && 0);
return RR_CONTINUE_PROCESSING;
}
if (connection->groupConstructionAndSerialize)
{
connection->downloadGroup.Push(packet, __FILE__, __LINE__);
return RR_STOP_PROCESSING;
}
RakNet::BitStream bsIn(packetData,packetDataLength,false);
bsIn.IgnoreBytes(packetDataOffset);
uint16_t constructionObjectListSize, destructionObjectListSize, index, index2;
BitSize_t streamEnd, writeAllocationIDEnd;
Replica3 *replica;
NetworkID networkId;
RakNetGUID creatingSystemGuid;
bool actuallyCreateObject=false;
DataStructures::List<bool> actuallyCreateObjectList;
DataStructures::List<Replica3*> constructionTickStack;
RakAssert(world->networkIDManager);
bsIn.Read(constructionObjectListSize);
for (index=0; index < constructionObjectListSize; index++)
{
bsIn.Read(streamEnd);
bsIn.Read(networkId);
Replica3* existingReplica = world->networkIDManager->GET_OBJECT_FROM_ID<Replica3*>(networkId);
bsIn.Read(actuallyCreateObject);
actuallyCreateObjectList.Push(actuallyCreateObject, _FILE_AND_LINE_);
bsIn.AlignReadToByteBoundary();
if (actuallyCreateObject)
{
bsIn.Read(creatingSystemGuid);
bsIn.Read(writeAllocationIDEnd);
//printf("OnConstruction: %i\n",networkId.guid.g); // Removeme
if (existingReplica)
{
existingReplica->replicaManager=this;
// Network ID already in use
connection->OnDownloadExisting(existingReplica, this);
constructionTickStack.Push(0, _FILE_AND_LINE_);
bsIn.SetReadOffset(streamEnd);
continue;
}
bsIn.AlignReadToByteBoundary();
replica = connection->AllocReplica(&bsIn, this);
if (replica==0)
{
constructionTickStack.Push(0, _FILE_AND_LINE_);
bsIn.SetReadOffset(streamEnd);
continue;
}
// Go past the bitStream written to with WriteAllocationID(). Necessary in case the user didn't read out the bitStream the same way it was written
// bitOffset2 is already aligned
bsIn.SetReadOffset(writeAllocationIDEnd);
replica->SetNetworkIDManager(world->networkIDManager);
replica->SetNetworkID(networkId);
replica->replicaManager=this;
replica->creatingSystemGUID=creatingSystemGuid;
if (!replica->QueryRemoteConstruction(connection) ||
!replica->DeserializeConstruction(&bsIn, connection))
{
DeallocReplicaNoBroadcastDestruction(connection, replica);
bsIn.SetReadOffset(streamEnd);
constructionTickStack.Push(0, _FILE_AND_LINE_);
continue;
}
constructionTickStack.Push(replica, _FILE_AND_LINE_);
// Register the replica
ReferenceInternal(replica, worldId);
}
else
{
if (existingReplica)
{
existingReplica->DeserializeConstructionExisting(&bsIn, connection);
constructionTickStack.Push(existingReplica, _FILE_AND_LINE_);
}
else
{
constructionTickStack.Push(0, _FILE_AND_LINE_);
}
}
bsIn.SetReadOffset(streamEnd);
bsIn.AlignReadToByteBoundary();
}
RakAssert(constructionTickStack.Size()==constructionObjectListSize);
RakAssert(actuallyCreateObjectList.Size()==constructionObjectListSize);
RakNet::BitStream empty;
for (index=0; index < constructionObjectListSize; index++)
{
bool pdcWritten=false;
bsIn.Read(pdcWritten);
if (pdcWritten)
{
bsIn.AlignReadToByteBoundary();
bsIn.Read(streamEnd);
bsIn.Read(networkId);
if (constructionTickStack[index]!=0)
{
bsIn.AlignReadToByteBoundary();
if (actuallyCreateObjectList[index])
constructionTickStack[index]->PostDeserializeConstruction(&bsIn, connection);
else
constructionTickStack[index]->PostDeserializeConstructionExisting(&bsIn, connection);
}
bsIn.SetReadOffset(streamEnd);
}
else
{
if (constructionTickStack[index]!=0)
{
if (actuallyCreateObjectList[index])
constructionTickStack[index]->PostDeserializeConstruction(&empty, connection);
else
constructionTickStack[index]->PostDeserializeConstructionExisting(&empty, connection);
}
}
}
for (index=0; index < constructionObjectListSize; index++)
{
if (constructionTickStack[index]!=0)
{
if (actuallyCreateObjectList[index])
{
// Tell the connection(s) that this object exists since they just sent it to us
connection->OnDownloadFromThisSystem(constructionTickStack[index], this);
for (index2=0; index2 < world->connectionList.Size(); index2++)
{
if (world->connectionList[index2]!=connection)
world->connectionList[index2]->OnDownloadFromOtherSystem(constructionTickStack[index], this);
}
}
}
}
// Destructions
bool b = bsIn.Read(destructionObjectListSize);
(void) b;
RakAssert(b);
for (index=0; index < destructionObjectListSize; index++)
{
bsIn.Read(networkId);
bsIn.Read(streamEnd);
replica = world->networkIDManager->GET_OBJECT_FROM_ID<Replica3*>(networkId);
if (replica==0)
{
// Unknown object
bsIn.SetReadOffset(streamEnd);
continue;
}
bsIn.Read(replica->deletingSystemGUID);
if (replica->DeserializeDestruction(&bsIn,connection))
{
// Make sure it wasn't deleted in DeserializeDestruction
if (world->networkIDManager->GET_OBJECT_FROM_ID<Replica3*>(networkId))
{
replica->PreDestruction(connection);
// Forward deletion by remote system
if (replica->QueryRelayDestruction(connection))
BroadcastDestruction(replica,connection->GetSystemAddress());
Dereference(replica);
DeallocReplicaNoBroadcastDestruction(connection, replica);
}
}
else
{
replica->PreDestruction(connection);
connection->OnDereference(replica, this);
}
bsIn.AlignReadToByteBoundary();
}
return RR_CONTINUE_PROCESSING;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PluginReceiveResult ReplicaManager3::OnSerialize(Packet *packet, unsigned char *packetData, int packetDataLength, RakNetGUID senderGuid, RakNet::Time timestamp, unsigned char packetDataOffset, WorldId worldId)
{
Connection_RM3 *connection = GetConnectionByGUID(senderGuid, worldId);
if (connection==0)
return RR_CONTINUE_PROCESSING;
if (connection->groupConstructionAndSerialize)
{
connection->downloadGroup.Push(packet, __FILE__, __LINE__);
return RR_STOP_PROCESSING;
}
RM3World *world = worldsArray[worldId];
RakAssert(world->networkIDManager);
RakNet::BitStream bsIn(packetData,packetDataLength,false);
bsIn.IgnoreBytes(packetDataOffset);
struct DeserializeParameters ds;
ds.timeStamp=timestamp;
ds.sourceConnection=connection;
Replica3 *replica;
NetworkID networkId;
BitSize_t bitsUsed;
bsIn.Read(networkId);
//printf("OnSerialize: %i\n",networkId.guid.g); // Removeme
replica = world->networkIDManager->GET_OBJECT_FROM_ID<Replica3*>(networkId);
if (replica)
{
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
{
bsIn.Read(ds.bitstreamWrittenTo[z]);
if (ds.bitstreamWrittenTo[z])
{
bsIn.ReadCompressed(bitsUsed);
bsIn.AlignReadToByteBoundary();
bsIn.Read(ds.serializationBitstream[z], bitsUsed);
}
}
replica->Deserialize(&ds);
}
return RR_CONTINUE_PROCESSING;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PluginReceiveResult ReplicaManager3::OnDownloadStarted(Packet *packet, unsigned char *packetData, int packetDataLength, RakNetGUID senderGuid, unsigned char packetDataOffset, WorldId worldId)
{
Connection_RM3 *connection = GetConnectionByGUID(senderGuid, worldId);
if (connection==0)
return RR_CONTINUE_PROCESSING;
if (connection->QueryGroupDownloadMessages() &&
// ID_DOWNLOAD_STARTED will be processed twice, being processed the second time once ID_DOWNLOAD_COMPLETE arrives.
// However, the second time groupConstructionAndSerialize will be set to true so it won't be processed a third time
connection->groupConstructionAndSerialize==false
)
{
// These messages will be held by the plugin and returned when the download is complete
connection->groupConstructionAndSerialize=true;
RakAssert(connection->downloadGroup.Size()==0);
connection->downloadGroup.Push(packet, __FILE__, __LINE__);
return RR_STOP_PROCESSING;
}
connection->groupConstructionAndSerialize=false;
RakNet::BitStream bsIn(packetData,packetDataLength,false);
bsIn.IgnoreBytes(packetDataOffset);
connection->DeserializeOnDownloadStarted(&bsIn);
return RR_CONTINUE_PROCESSING;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PluginReceiveResult ReplicaManager3::OnDownloadComplete(Packet *packet, unsigned char *packetData, int packetDataLength, RakNetGUID senderGuid, unsigned char packetDataOffset, WorldId worldId)
{
Connection_RM3 *connection = GetConnectionByGUID(senderGuid, worldId);
if (connection==0)
return RR_CONTINUE_PROCESSING;
if (connection->groupConstructionAndSerialize==true && connection->downloadGroup.Size()>0)
{
// Push back buffered packets in front of this one
unsigned int i;
for (i=0; i < connection->downloadGroup.Size(); i++)
rakPeerInterface->PushBackPacket(connection->downloadGroup[i],false);
// Push this one to be last too. It will be processed again, but the second time
// groupConstructionAndSerialize will be false and downloadGroup will be empty, so it will go past this block
connection->downloadGroup.Clear(__FILE__,__LINE__);
rakPeerInterface->PushBackPacket(packet,false);
return RR_STOP_PROCESSING;
}
RakNet::BitStream bsIn(packetData,packetDataLength,false);
bsIn.IgnoreBytes(packetDataOffset);
connection->gotDownloadComplete=true;
connection->DeserializeOnDownloadComplete(&bsIn);
return RR_CONTINUE_PROCESSING;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Replica3* ReplicaManager3::GetReplicaByNetworkID(NetworkID networkId, WorldId worldId)
{
RM3World *world = worldsArray[worldId];
unsigned int i;
for (i=0; i < world->userReplicaList.Size(); i++)
{
if (world->userReplicaList[i]->GetNetworkID()==networkId)
return world->userReplicaList[i];
}
return 0;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::BroadcastDestructionList(DataStructures::List<Replica3*> &replicaListSource, const SystemAddress &exclusionAddress, WorldId worldId)
{
RakNet::BitStream bsOut;
unsigned int i,j;
RakAssert(worldsArray[worldId]!=0 && "World not in use");
RM3World *world = worldsArray[worldId];
DataStructures::List<Replica3*> replicaList;
for (i=0; i < replicaListSource.Size(); i++)
{
if (replicaListSource[i]==currentlyDeallocatingReplica)
continue;
replicaList.Push(replicaListSource[i], __FILE__, __LINE__);
}
if (replicaList.Size()==0)
return;
for (i=0; i < replicaList.Size(); i++)
{
if (replicaList[i]->deletingSystemGUID==UNASSIGNED_RAKNET_GUID)
replicaList[i]->deletingSystemGUID=GetRakPeerInterface()->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS);
}
for (j=0; j < world->connectionList.Size(); j++)
{
if (world->connectionList[j]->GetSystemAddress()==exclusionAddress)
continue;
bsOut.Reset();
bsOut.Write((MessageID)ID_REPLICA_MANAGER_CONSTRUCTION);
bsOut.Write(worldId);
uint16_t cnt=0;
bsOut.Write(cnt); // No construction
cnt=(uint16_t) replicaList.Size();
BitSize_t cntOffset=bsOut.GetWriteOffset();;
bsOut.Write(cnt); // Overwritten at send call
cnt=0;
for (i=0; i < replicaList.Size(); i++)
{
if (world->connectionList[j]->HasReplicaConstructed(replicaList[i])==false)
continue;
cnt++;
NetworkID networkId;
networkId=replicaList[i]->GetNetworkID();
bsOut.Write(networkId);
BitSize_t offsetStart, offsetEnd;
offsetStart=bsOut.GetWriteOffset();
bsOut.Write(offsetStart);
bsOut.Write(replicaList[i]->deletingSystemGUID);
replicaList[i]->SerializeDestruction(&bsOut, world->connectionList[j]);
bsOut.AlignWriteToByteBoundary();
offsetEnd=bsOut.GetWriteOffset();
bsOut.SetWriteOffset(offsetStart);
bsOut.Write(offsetEnd);
bsOut.SetWriteOffset(offsetEnd);
}
if (cnt>0)
{
BitSize_t curOffset=bsOut.GetWriteOffset();
bsOut.SetWriteOffset(cntOffset);
bsOut.Write(cnt);
bsOut.SetWriteOffset(curOffset);
rakPeerInterface->Send(&bsOut,defaultSendParameters.priority,defaultSendParameters.reliability,defaultSendParameters.orderingChannel,world->connectionList[j]->GetSystemAddress(),false, defaultSendParameters.sendReceipt);
}
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ReplicaManager3::BroadcastDestruction(Replica3 *replica, const SystemAddress &exclusionAddress)
{
DataStructures::List<Replica3*> replicaList;
replicaList.Push(replica, _FILE_AND_LINE_ );
BroadcastDestructionList(replicaList,exclusionAddress);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Connection_RM3::Connection_RM3(const SystemAddress &_systemAddress, RakNetGUID _guid)
: systemAddress(_systemAddress), guid(_guid)
{
isValidated=false;
isFirstConstruction=true;
groupConstructionAndSerialize=false;
gotDownloadComplete=false;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Connection_RM3::~Connection_RM3()
{
unsigned int i;
for (i=0; i < constructedReplicaList.Size(); i++)
RakNet::OP_DELETE(constructedReplicaList[i], _FILE_AND_LINE_);
for (i=0; i < queryToConstructReplicaList.Size(); i++)
RakNet::OP_DELETE(queryToConstructReplicaList[i], _FILE_AND_LINE_);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::GetConstructedReplicas(DataStructures::List<Replica3*> &objectsTheyDoHave)
{
objectsTheyDoHave.Clear(true,_FILE_AND_LINE_);
for (unsigned int idx=0; idx < constructedReplicaList.Size(); idx++)
{
objectsTheyDoHave.Push(constructedReplicaList[idx]->replica, _FILE_AND_LINE_ );
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool Connection_RM3::HasReplicaConstructed(RakNet::Replica3 *replica)
{
bool objectExists;
constructedReplicaList.GetIndexFromKey(replica, &objectExists);
return objectExists;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::SendSerializeHeader(RakNet::Replica3 *replica, RakNet::Time timestamp, RakNet::BitStream *bs, WorldId worldId)
{
bs->Reset();
if (timestamp!=0)
{
bs->Write((MessageID)ID_TIMESTAMP);
bs->Write(timestamp);
}
bs->Write((MessageID)ID_REPLICA_MANAGER_SERIALIZE);
bs->Write(worldId);
bs->Write(replica->GetNetworkID());
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::ClearDownloadGroup(RakPeerInterface *rakPeerInterface)
{
unsigned int i;
for (i=0; i < downloadGroup.Size(); i++)
rakPeerInterface->DeallocatePacket(downloadGroup[i]);
downloadGroup.Clear(__FILE__,__LINE__);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SendSerializeIfChangedResult Connection_RM3::SendSerialize(RakNet::Replica3 *replica, bool indicesToSend[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS], RakNet::BitStream serializationData[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS], RakNet::Time timestamp, PRO sendParameters[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS], RakPeerInterface *rakPeer, unsigned char worldId, RakNet::Time curTime)
{
bool channelHasData;
BitSize_t sum=0;
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
{
if (indicesToSend[z])
sum+=serializationData[z].GetNumberOfBitsUsed();
}
RakNet::BitStream out;
BitSize_t bitsPerChannel[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS];
if (sum==0)
{
memset(bitsPerChannel, 0, sizeof(bitsPerChannel));
replica->OnSerializeTransmission(&out, this, bitsPerChannel, curTime);
return SSICR_DID_NOT_SEND_DATA;
}
RakAssert(replica->GetNetworkID()!=UNASSIGNED_NETWORK_ID);
BitSize_t bitsUsed;
int channelIndex;
PRO lastPro=sendParameters[0];
for (channelIndex=0; channelIndex < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; channelIndex++)
{
if (channelIndex==0)
{
SendSerializeHeader(replica, timestamp, &out, worldId);
}
else if (lastPro!=sendParameters[channelIndex])
{
// Write out remainder
for (int channelIndex2=channelIndex; channelIndex2 < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; channelIndex2++)
{
bitsPerChannel[channelIndex2]=0;
out.Write(false);
}
// Send remainder
replica->OnSerializeTransmission(&out, this, bitsPerChannel, curTime);
rakPeer->Send(&out,lastPro.priority,lastPro.reliability,lastPro.orderingChannel,systemAddress,false,lastPro.sendReceipt);
// If no data left to send, quit out
bool anyData=false;
for (int channelIndex2=channelIndex; channelIndex2 < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; channelIndex2++)
{
if (serializationData[channelIndex2].GetNumberOfBitsUsed()>0)
{
anyData=true;
break;
}
}
if (anyData==false)
return SSICR_SENT_DATA;
// Restart stream
SendSerializeHeader(replica, timestamp, &out, worldId);
for (int channelIndex2=0; channelIndex2 < channelIndex; channelIndex2++)
{
bitsPerChannel[channelIndex2]=0;
out.Write(false);
}
lastPro=sendParameters[channelIndex];
}
bitsUsed=serializationData[channelIndex].GetNumberOfBitsUsed();
channelHasData = indicesToSend[channelIndex]==true && bitsUsed>0;
out.Write(channelHasData);
if (channelHasData)
{
bitsPerChannel[channelIndex] = bitsUsed;
out.WriteCompressed(bitsUsed);
out.AlignWriteToByteBoundary();
out.Write(serializationData[channelIndex]);
// Crap, forgot this line, was a huge bug in that I'd only send to the first 3 systems
serializationData[channelIndex].ResetReadPointer();
}
else
{
bitsPerChannel[channelIndex] = 0;
}
}
replica->OnSerializeTransmission(&out, this, bitsPerChannel, curTime);
rakPeer->Send(&out,lastPro.priority,lastPro.reliability,lastPro.orderingChannel,systemAddress,false,lastPro.sendReceipt);
return SSICR_SENT_DATA;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SendSerializeIfChangedResult Connection_RM3::SendSerializeIfChanged(LastSerializationResult *lsr, SerializeParameters *sp, RakNet::RakPeerInterface *rakPeer, unsigned char worldId, ReplicaManager3 *replicaManager, RakNet::Time curTime)
{
RakNet::Replica3 *replica = lsr->replica;
if (replica->GetNetworkID()==UNASSIGNED_NETWORK_ID)
return SSICR_DID_NOT_SEND_DATA;
RM3QuerySerializationResult rm3qsr = replica->QuerySerialization(this);
if (rm3qsr==RM3QSR_NEVER_CALL_SERIALIZE)
{
// Never again for this connection and replica pair
OnNeverSerialize(lsr, replicaManager);
return SSICR_NEVER_SERIALIZE;
}
if (rm3qsr==RM3QSR_DO_NOT_CALL_SERIALIZE)
return SSICR_DID_NOT_SEND_DATA;
if (replica->forceSendUntilNextUpdate)
{
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
{
if (replica->lastSentSerialization.indicesToSend[z])
sp->bitsWrittenSoFar+=replica->lastSentSerialization.bitStream[z].GetNumberOfBitsUsed();
}
return SendSerialize(replica, replica->lastSentSerialization.indicesToSend, replica->lastSentSerialization.bitStream, sp->messageTimestamp, sp->pro, rakPeer, worldId, curTime);
}
for (int i=0; i < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; i++)
{
sp->outputBitstream[i].Reset();
if (lsr->lastSerializationResultBS)
sp->lastSentBitstream[i]=&lsr->lastSerializationResultBS->bitStream[i];
else
sp->lastSentBitstream[i]=&replica->lastSentSerialization.bitStream[i];
}
RM3SerializationResult serializationResult = replica->Serialize(sp);
if (serializationResult==RM3SR_NEVER_SERIALIZE_FOR_THIS_CONNECTION)
{
// Never again for this connection and replica pair
OnNeverSerialize(lsr, replicaManager);
return SSICR_NEVER_SERIALIZE;
}
if (serializationResult==RM3SR_DO_NOT_SERIALIZE)
{
// Don't serialize this tick only
return SSICR_DID_NOT_SEND_DATA;
}
// This is necessary in case the user in the Serialize() function for some reason read the bitstream they also wrote
// WIthout this code, the Write calls to another bitstream would not write the entire bitstream
BitSize_t sum=0;
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
{
sp->outputBitstream[z].ResetReadPointer();
sum+=sp->outputBitstream[z].GetNumberOfBitsUsed();
}
if (sum==0)
{
// Don't serialize this tick only
return SSICR_DID_NOT_SEND_DATA;
}
if (serializationResult==RM3SR_SERIALIZED_ALWAYS)
{
bool allIndices[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS];
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
{
sp->bitsWrittenSoFar+=sp->outputBitstream[z].GetNumberOfBitsUsed();
allIndices[z]=true;
lsr->AllocBS();
lsr->lastSerializationResultBS->bitStream[z].Reset();
lsr->lastSerializationResultBS->bitStream[z].Write(&sp->outputBitstream[z]);
sp->outputBitstream[z].ResetReadPointer();
}
return SendSerialize(replica, allIndices, sp->outputBitstream, sp->messageTimestamp, sp->pro, rakPeer, worldId, curTime);
}
if (serializationResult==RM3SR_SERIALIZED_ALWAYS_IDENTICALLY)
{
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
{
replica->lastSentSerialization.indicesToSend[z]=sp->outputBitstream[z].GetNumberOfBitsUsed()>0;
sp->bitsWrittenSoFar+=sp->outputBitstream[z].GetNumberOfBitsUsed();
replica->lastSentSerialization.bitStream[z].Reset();
replica->lastSentSerialization.bitStream[z].Write(&sp->outputBitstream[z]);
sp->outputBitstream[z].ResetReadPointer();
replica->forceSendUntilNextUpdate=true;
}
return SendSerialize(replica, replica->lastSentSerialization.indicesToSend, sp->outputBitstream, sp->messageTimestamp, sp->pro, rakPeer, worldId, curTime);
}
bool indicesToSend[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS];
if (serializationResult==RM3SR_BROADCAST_IDENTICALLY || serializationResult==RM3SR_BROADCAST_IDENTICALLY_FORCE_SERIALIZATION)
{
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
{
if (sp->outputBitstream[z].GetNumberOfBitsUsed() > 0 &&
(serializationResult==RM3SR_BROADCAST_IDENTICALLY_FORCE_SERIALIZATION ||
((sp->outputBitstream[z].GetNumberOfBitsUsed()!=replica->lastSentSerialization.bitStream[z].GetNumberOfBitsUsed() ||
memcmp(sp->outputBitstream[z].GetData(), replica->lastSentSerialization.bitStream[z].GetData(), sp->outputBitstream[z].GetNumberOfBytesUsed())!=0))))
{
indicesToSend[z]=true;
replica->lastSentSerialization.indicesToSend[z]=true;
sp->bitsWrittenSoFar+=sp->outputBitstream[z].GetNumberOfBitsUsed();
replica->lastSentSerialization.bitStream[z].Reset();
replica->lastSentSerialization.bitStream[z].Write(&sp->outputBitstream[z]);
sp->outputBitstream[z].ResetReadPointer();
replica->forceSendUntilNextUpdate=true;
}
else
{
indicesToSend[z]=false;
replica->lastSentSerialization.indicesToSend[z]=false;
}
}
}
else
{
lsr->AllocBS();
// RM3SR_SERIALIZED_UNIQUELY
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
{
if (sp->outputBitstream[z].GetNumberOfBitsUsed() > 0 &&
(sp->outputBitstream[z].GetNumberOfBitsUsed()!=lsr->lastSerializationResultBS->bitStream[z].GetNumberOfBitsUsed() ||
memcmp(sp->outputBitstream[z].GetData(), lsr->lastSerializationResultBS->bitStream[z].GetData(), sp->outputBitstream[z].GetNumberOfBytesUsed())!=0)
)
{
indicesToSend[z]=true;
sp->bitsWrittenSoFar+=sp->outputBitstream[z].GetNumberOfBitsUsed();
lsr->lastSerializationResultBS->bitStream[z].Reset();
lsr->lastSerializationResultBS->bitStream[z].Write(&sp->outputBitstream[z]);
sp->outputBitstream[z].ResetReadPointer();
}
else
{
indicesToSend[z]=false;
}
}
}
if (serializationResult==RM3SR_BROADCAST_IDENTICALLY || serializationResult==RM3SR_BROADCAST_IDENTICALLY_FORCE_SERIALIZATION)
replica->forceSendUntilNextUpdate=true;
// Send out the data
return SendSerialize(replica, indicesToSend, sp->outputBitstream, sp->messageTimestamp, sp->pro, rakPeer, worldId, curTime);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnLocalReference(Replica3* replica3, ReplicaManager3 *replicaManager)
{
ConstructionMode constructionMode = QueryConstructionMode();
RakAssert(constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION || constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION);
RakAssert(replica3);
(void) replicaManager;
(void) constructionMode;
#ifdef _DEBUG
for (unsigned int i=0; i < queryToConstructReplicaList.Size(); i++)
{
if (queryToConstructReplicaList[i]->replica==replica3)
{
RakAssert("replica added twice to queryToConstructReplicaList" && 0);
}
}
if (constructedReplicaList.HasData(replica3)==true)
{
RakAssert("replica added to queryToConstructReplicaList when already in constructedReplicaList" && 0);
}
#endif
LastSerializationResult* lsr=RakNet::OP_NEW<LastSerializationResult>(_FILE_AND_LINE_);
lsr->replica=replica3;
queryToConstructReplicaList.Push(lsr,_FILE_AND_LINE_);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnDereference(Replica3* replica3, ReplicaManager3 *replicaManager)
{
ValidateLists(replicaManager);
if (replica3->GetNetworkIDManager() == 0)
return;
LastSerializationResult* lsr=0;
unsigned int idx;
bool objectExists;
idx=constructedReplicaList.GetIndexFromKey(replica3, &objectExists);
if (objectExists)
{
lsr=constructedReplicaList[idx];
constructedReplicaList.RemoveAtIndex(idx);
}
for (idx=0; idx < queryToConstructReplicaList.Size(); idx++)
{
if (queryToConstructReplicaList[idx]->replica==replica3)
{
lsr=queryToConstructReplicaList[idx];
queryToConstructReplicaList.RemoveAtIndex(idx);
break;
}
}
for (idx=0; idx < queryToSerializeReplicaList.Size(); idx++)
{
if (queryToSerializeReplicaList[idx]->replica==replica3)
{
lsr=queryToSerializeReplicaList[idx];
queryToSerializeReplicaList.RemoveAtIndex(idx);
break;
}
}
for (idx=0; idx < queryToDestructReplicaList.Size(); idx++)
{
if (queryToDestructReplicaList[idx]->replica==replica3)
{
lsr=queryToDestructReplicaList[idx];
queryToDestructReplicaList.RemoveAtIndex(idx);
break;
}
}
ValidateLists(replicaManager);
if (lsr)
RakNet::OP_DELETE(lsr,_FILE_AND_LINE_);
ValidateLists(replicaManager);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnDownloadFromThisSystem(Replica3* replica3, ReplicaManager3 *replicaManager)
{
RakAssert(replica3);
ValidateLists(replicaManager);
LastSerializationResult* lsr=RakNet::OP_NEW<LastSerializationResult>(_FILE_AND_LINE_);
lsr->replica=replica3;
ConstructionMode constructionMode = QueryConstructionMode();
if (constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION || constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION)
{
unsigned int j;
for (j=0; j < queryToConstructReplicaList.Size(); j++)
{
if (queryToConstructReplicaList[j]->replica==replica3 )
{
queryToConstructReplicaList.RemoveAtIndex(j);
break;
}
}
queryToDestructReplicaList.Push(lsr,_FILE_AND_LINE_);
}
if (constructedReplicaList.Insert(lsr->replica, lsr, true, _FILE_AND_LINE_) != (unsigned) -1)
{
//assert(queryToSerializeReplicaList.GetIndexOf(replica3)==(unsigned int)-1);
queryToSerializeReplicaList.Push(lsr,_FILE_AND_LINE_);
}
ValidateLists(replicaManager);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnDownloadFromOtherSystem(Replica3* replica3, ReplicaManager3 *replicaManager)
{
ConstructionMode constructionMode = QueryConstructionMode();
if (constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION || constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION)
{
unsigned int j;
for (j=0; j < queryToConstructReplicaList.Size(); j++)
{
if (queryToConstructReplicaList[j]->replica==replica3 )
{
return;
}
}
OnLocalReference(replica3, replicaManager);
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnNeverConstruct(unsigned int queryToConstructIdx, ReplicaManager3 *replicaManager)
{
ConstructionMode constructionMode = QueryConstructionMode();
RakAssert(constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION || constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION);
(void) constructionMode;
ValidateLists(replicaManager);
LastSerializationResult* lsr = queryToConstructReplicaList[queryToConstructIdx];
queryToConstructReplicaList.RemoveAtIndex(queryToConstructIdx);
RakNet::OP_DELETE(lsr,_FILE_AND_LINE_);
ValidateLists(replicaManager);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnConstructToThisConnection(unsigned int queryToConstructIdx, ReplicaManager3 *replicaManager)
{
ConstructionMode constructionMode = QueryConstructionMode();
RakAssert(constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION || constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION);
(void) constructionMode;
ValidateLists(replicaManager);
LastSerializationResult* lsr = queryToConstructReplicaList[queryToConstructIdx];
queryToConstructReplicaList.RemoveAtIndex(queryToConstructIdx);
//assert(constructedReplicaList.GetIndexOf(lsr->replica)==(unsigned int)-1);
constructedReplicaList.Insert(lsr->replica,lsr,true,_FILE_AND_LINE_);
//assert(queryToDestructReplicaList.GetIndexOf(lsr->replica)==(unsigned int)-1);
queryToDestructReplicaList.Push(lsr,_FILE_AND_LINE_);
//assert(queryToSerializeReplicaList.GetIndexOf(lsr->replica)==(unsigned int)-1);
queryToSerializeReplicaList.Push(lsr,_FILE_AND_LINE_);
ValidateLists(replicaManager);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnConstructToThisConnection(Replica3 *replica, ReplicaManager3 *replicaManager)
{
RakAssert(replica);
RakAssert(QueryConstructionMode()==QUERY_CONNECTION_FOR_REPLICA_LIST);
(void) replicaManager;
LastSerializationResult* lsr=RakNet::OP_NEW<LastSerializationResult>(_FILE_AND_LINE_);
lsr->replica=replica;
constructedReplicaList.Insert(replica,lsr,true,_FILE_AND_LINE_);
queryToSerializeReplicaList.Push(lsr,_FILE_AND_LINE_);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnNeverSerialize(LastSerializationResult *lsr, ReplicaManager3 *replicaManager)
{
ValidateLists(replicaManager);
unsigned int j;
for (j=0; j < queryToSerializeReplicaList.Size(); j++)
{
if (queryToSerializeReplicaList[j]==lsr )
{
queryToSerializeReplicaList.RemoveAtIndex(j);
break;
}
}
ValidateLists(replicaManager);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnReplicaAlreadyExists(unsigned int queryToConstructIdx, ReplicaManager3 *replicaManager)
{
ConstructionMode constructionMode = QueryConstructionMode();
RakAssert(constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION || constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION);
(void) constructionMode;
ValidateLists(replicaManager);
LastSerializationResult* lsr = queryToConstructReplicaList[queryToConstructIdx];
queryToConstructReplicaList.RemoveAtIndex(queryToConstructIdx);
//assert(constructedReplicaList.GetIndexOf(lsr->replica)==(unsigned int)-1);
constructedReplicaList.Insert(lsr->replica,lsr,true,_FILE_AND_LINE_);
//assert(queryToDestructReplicaList.GetIndexOf(lsr->replica)==(unsigned int)-1);
queryToDestructReplicaList.Push(lsr,_FILE_AND_LINE_);
//assert(queryToSerializeReplicaList.GetIndexOf(lsr->replica)==(unsigned int)-1);
queryToSerializeReplicaList.Push(lsr,_FILE_AND_LINE_);
ValidateLists(replicaManager);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnDownloadExisting(Replica3* replica3, ReplicaManager3 *replicaManager)
{
ValidateLists(replicaManager);
ConstructionMode constructionMode = QueryConstructionMode();
if (constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION || constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION)
{
unsigned int idx;
for (idx=0; idx < queryToConstructReplicaList.Size(); idx++)
{
if (queryToConstructReplicaList[idx]->replica==replica3)
{
OnConstructToThisConnection(idx, replicaManager);
return;
}
}
}
else
{
OnConstructToThisConnection(replica3, replicaManager);
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnSendDestructionFromQuery(unsigned int queryToDestructIdx, ReplicaManager3 *replicaManager)
{
ConstructionMode constructionMode = QueryConstructionMode();
RakAssert(constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION || constructionMode==QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION);
(void) constructionMode;
ValidateLists(replicaManager);
LastSerializationResult* lsr = queryToDestructReplicaList[queryToDestructIdx];
queryToDestructReplicaList.RemoveAtIndex(queryToDestructIdx);
unsigned int j;
for (j=0; j < queryToSerializeReplicaList.Size(); j++)
{
if (queryToSerializeReplicaList[j]->replica==lsr->replica )
{
queryToSerializeReplicaList.RemoveAtIndex(j);
break;
}
}
for (j=0; j < constructedReplicaList.Size(); j++)
{
if (constructedReplicaList[j]->replica==lsr->replica )
{
constructedReplicaList.RemoveAtIndex(j);
break;
}
}
//assert(queryToConstructReplicaList.GetIndexOf(lsr->replica)==(unsigned int)-1);
queryToConstructReplicaList.Push(lsr,_FILE_AND_LINE_);
ValidateLists(replicaManager);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::OnDoNotQueryDestruction(unsigned int queryToDestructIdx, ReplicaManager3 *replicaManager)
{
ValidateLists(replicaManager);
queryToDestructReplicaList.RemoveAtIndex(queryToDestructIdx);
ValidateLists(replicaManager);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::ValidateLists(ReplicaManager3 *replicaManager) const
{
(void) replicaManager;
/*
#ifdef _DEBUG
// Each object should exist only once in either constructedReplicaList or queryToConstructReplicaList
// replicaPointer from LastSerializationResult should be same among all lists
unsigned int idx, idx2;
for (idx=0; idx < constructedReplicaList.Size(); idx++)
{
idx2=queryToConstructReplicaList.GetIndexOf(constructedReplicaList[idx]->replica);
if (idx2!=(unsigned int)-1)
{
int a=5;
assert(a==0);
int *b=0;
*b=5;
}
}
for (idx=0; idx < queryToConstructReplicaList.Size(); idx++)
{
idx2=constructedReplicaList.GetIndexOf(queryToConstructReplicaList[idx]->replica);
if (idx2!=(unsigned int)-1)
{
int a=5;
assert(a==0);
int *b=0;
*b=5;
}
}
LastSerializationResult *lsr, *lsr2;
for (idx=0; idx < constructedReplicaList.Size(); idx++)
{
lsr=constructedReplicaList[idx];
idx2=queryToSerializeReplicaList.GetIndexOf(lsr->replica);
if (idx2!=(unsigned int)-1)
{
lsr2=queryToSerializeReplicaList[idx2];
if (lsr2!=lsr)
{
int a=5;
assert(a==0);
int *b=0;
*b=5;
}
}
idx2=queryToDestructReplicaList.GetIndexOf(lsr->replica);
if (idx2!=(unsigned int)-1)
{
lsr2=queryToDestructReplicaList[idx2];
if (lsr2!=lsr)
{
int a=5;
assert(a==0);
int *b=0;
*b=5;
}
}
}
for (idx=0; idx < queryToConstructReplicaList.Size(); idx++)
{
lsr=queryToConstructReplicaList[idx];
idx2=queryToSerializeReplicaList.GetIndexOf(lsr->replica);
if (idx2!=(unsigned int)-1)
{
lsr2=queryToSerializeReplicaList[idx2];
if (lsr2!=lsr)
{
int a=5;
assert(a==0);
int *b=0;
*b=5;
}
}
idx2=queryToDestructReplicaList.GetIndexOf(lsr->replica);
if (idx2!=(unsigned int)-1)
{
lsr2=queryToDestructReplicaList[idx2];
if (lsr2!=lsr)
{
int a=5;
assert(a==0);
int *b=0;
*b=5;
}
}
}
// Verify pointer integrity
for (idx=0; idx < constructedReplicaList.Size(); idx++)
{
if (constructedReplicaList[idx]->replica->replicaManager!=replicaManager)
{
int a=5;
assert(a==0);
int *b=0;
*b=5;
}
}
// Verify pointer integrity
for (idx=0; idx < queryToConstructReplicaList.Size(); idx++)
{
if (queryToConstructReplicaList[idx]->replica->replicaManager!=replicaManager)
{
int a=5;
assert(a==0);
int *b=0;
*b=5;
}
}
#endif
*/
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::SendConstruction(DataStructures::List<Replica3*> &newObjects, DataStructures::List<Replica3*> &deletedObjects, PRO sendParameters, RakNet::RakPeerInterface *rakPeer, unsigned char worldId, ReplicaManager3 *replicaManager3)
{
if (newObjects.Size()==0 && deletedObjects.Size()==0)
return;
// All construction and destruction takes place in the same network message
// Otherwise, if objects rely on each other being created the same tick to be valid, this won't always be true
// DataStructures::List<LastSerializationResult* > serializedObjects;
BitSize_t offsetStart, offsetStart2, offsetEnd;
unsigned int newListIndex, oldListIndex;
RakNet::BitStream bsOut;
NetworkID networkId;
if (isFirstConstruction)
{
bsOut.Write((MessageID)ID_REPLICA_MANAGER_DOWNLOAD_STARTED);
bsOut.Write(worldId);
SerializeOnDownloadStarted(&bsOut);
rakPeer->Send(&bsOut,sendParameters.priority,RELIABLE_ORDERED,sendParameters.orderingChannel,systemAddress,false,sendParameters.sendReceipt);
}
// LastSerializationResult* lsr;
bsOut.Reset();
bsOut.Write((MessageID)ID_REPLICA_MANAGER_CONSTRUCTION);
bsOut.Write(worldId);
uint16_t objectSize = (uint16_t) newObjects.Size();
bsOut.Write(objectSize);
// Construction
for (newListIndex=0; newListIndex < newObjects.Size(); newListIndex++)
{
offsetStart=bsOut.GetWriteOffset();
bsOut.Write(offsetStart); // overwritten to point to the end of the stream
networkId=newObjects[newListIndex]->GetNetworkID();
bsOut.Write(networkId);
RM3ConstructionState cs = newObjects[newListIndex]->QueryConstruction(this, replicaManager3);
bool actuallyCreateObject = cs==RM3CS_SEND_CONSTRUCTION;
bsOut.Write(actuallyCreateObject);
bsOut.AlignWriteToByteBoundary();
if (actuallyCreateObject)
{
// Actually create the object
bsOut.Write(newObjects[newListIndex]->creatingSystemGUID);
offsetStart2=bsOut.GetWriteOffset();
bsOut.Write(offsetStart2); // overwritten to point to after the call to WriteAllocationID
bsOut.AlignWriteToByteBoundary(); // Give the user an aligned bitStream in case they use memcpy
newObjects[newListIndex]->WriteAllocationID(this, &bsOut);
bsOut.AlignWriteToByteBoundary(); // Give the user an aligned bitStream in case they use memcpy
offsetEnd=bsOut.GetWriteOffset();
bsOut.SetWriteOffset(offsetStart2);
bsOut.Write(offsetEnd);
bsOut.SetWriteOffset(offsetEnd);
newObjects[newListIndex]->SerializeConstruction(&bsOut, this);
}
else
{
newObjects[newListIndex]->SerializeConstructionExisting(&bsOut, this);
}
bsOut.AlignWriteToByteBoundary();
offsetEnd=bsOut.GetWriteOffset();
bsOut.SetWriteOffset(offsetStart);
bsOut.Write(offsetEnd);
bsOut.SetWriteOffset(offsetEnd);
}
RakNet::BitStream bsOut2;
for (newListIndex=0; newListIndex < newObjects.Size(); newListIndex++)
{
bsOut2.Reset();
RM3ConstructionState cs = newObjects[newListIndex]->QueryConstruction(this, replicaManager3);
if (cs==RM3CS_SEND_CONSTRUCTION)
{
newObjects[newListIndex]->PostSerializeConstruction(&bsOut2, this);
}
else
{
RakAssert(cs==RM3CS_ALREADY_EXISTS_REMOTELY);
newObjects[newListIndex]->PostSerializeConstructionExisting(&bsOut2, this);
}
if (bsOut2.GetNumberOfBitsUsed()>0)
{
bsOut.Write(true);
bsOut.AlignWriteToByteBoundary();
offsetStart=bsOut.GetWriteOffset();
bsOut.Write(offsetStart); // overwritten to point to the end of the stream
networkId=newObjects[newListIndex]->GetNetworkID();
bsOut.Write(networkId);
bsOut.AlignWriteToByteBoundary(); // Give the user an aligned bitStream in case they use memcpy
bsOut.Write(&bsOut2);
bsOut.AlignWriteToByteBoundary(); // Give the user an aligned bitStream in case they use memcpy
offsetEnd=bsOut.GetWriteOffset();
bsOut.SetWriteOffset(offsetStart);
bsOut.Write(offsetEnd);
bsOut.SetWriteOffset(offsetEnd);
}
else
bsOut.Write(false);
}
bsOut.AlignWriteToByteBoundary();
// Destruction
objectSize = (uint16_t) deletedObjects.Size();
bsOut.Write(objectSize);
for (oldListIndex=0; oldListIndex < deletedObjects.Size(); oldListIndex++)
{
networkId=deletedObjects[oldListIndex]->GetNetworkID();
bsOut.Write(networkId);
offsetStart=bsOut.GetWriteOffset();
bsOut.Write(offsetStart);
deletedObjects[oldListIndex]->deletingSystemGUID=rakPeer->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS);
bsOut.Write(deletedObjects[oldListIndex]->deletingSystemGUID);
deletedObjects[oldListIndex]->SerializeDestruction(&bsOut, this);
bsOut.AlignWriteToByteBoundary();
offsetEnd=bsOut.GetWriteOffset();
bsOut.SetWriteOffset(offsetStart);
bsOut.Write(offsetEnd);
bsOut.SetWriteOffset(offsetEnd);
}
rakPeer->Send(&bsOut,sendParameters.priority,RELIABLE_ORDERED,sendParameters.orderingChannel,systemAddress,false,sendParameters.sendReceipt);
// TODO - shouldn't this be part of construction?
// Initial Download serialize to a new system
// Immediately send serialize after construction if the replica object already has saved data
// If the object was serialized identically, and does not change later on, then the new connection never gets the data
SerializeParameters sp;
sp.whenLastSerialized=0;
RakNet::BitStream emptyBs;
for (int index=0; index < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; index++)
{
sp.lastSentBitstream[index]=&emptyBs;
sp.pro[index]=sendParameters;
sp.pro[index].reliability=RELIABLE_ORDERED;
}
sp.bitsWrittenSoFar=0;
// RakNet::Time t = RakNet::GetTimeMS();
for (newListIndex=0; newListIndex < newObjects.Size(); newListIndex++)
{
sp.destinationConnection=this;
sp.messageTimestamp=0;
RakNet::Replica3 *replica = newObjects[newListIndex];
// 8/22/09 Forgot ResetWritePointer
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
{
sp.outputBitstream[z].ResetWritePointer();
}
RM3SerializationResult res = replica->Serialize(&sp);
if (res!=RM3SR_NEVER_SERIALIZE_FOR_THIS_CONNECTION &&
res!=RM3SR_DO_NOT_SERIALIZE &&
res!=RM3SR_SERIALIZED_UNIQUELY)
{
bool allIndices[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS];
for (int z=0; z < RM3_NUM_OUTPUT_BITSTREAM_CHANNELS; z++)
{
sp.bitsWrittenSoFar+=sp.outputBitstream[z].GetNumberOfBitsUsed();
allIndices[z]=true;
}
SendSerialize(replica, allIndices, sp.outputBitstream, sp.messageTimestamp, sp.pro, rakPeer, worldId, GetTime());
/// newObjects[newListIndex]->whenLastSerialized=t;
}
// else wait for construction request accepted before serializing
}
if (isFirstConstruction)
{
bsOut.Reset();
bsOut.Write((MessageID)ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE);
bsOut.Write(worldId);
SerializeOnDownloadComplete(&bsOut);
rakPeer->Send(&bsOut,sendParameters.priority,RELIABLE_ORDERED,sendParameters.orderingChannel,systemAddress,false,sendParameters.sendReceipt);
}
isFirstConstruction=false;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Connection_RM3::SendValidation(RakNet::RakPeerInterface *rakPeer, WorldId worldId)
{
// Hijack to mean sendValidation
RakNet::BitStream bsOut;
bsOut.Write((MessageID)ID_REPLICA_MANAGER_SCOPE_CHANGE);
bsOut.Write(worldId);
rakPeer->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,false);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Replica3::Replica3()
{
creatingSystemGUID=UNASSIGNED_RAKNET_GUID;
deletingSystemGUID=UNASSIGNED_RAKNET_GUID;
replicaManager=0;
forceSendUntilNextUpdate=false;
lsr=0;
referenceIndex = (uint32_t)-1;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Replica3::~Replica3()
{
if (replicaManager)
{
replicaManager->Dereference(this);
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void Replica3::BroadcastDestruction(void)
{
replicaManager->BroadcastDestruction(this,UNASSIGNED_SYSTEM_ADDRESS);
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RakNetGUID Replica3::GetCreatingSystemGUID(void) const
{
return creatingSystemGUID;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RM3ConstructionState Replica3::QueryConstruction_ClientConstruction(RakNet::Connection_RM3 *destinationConnection, bool isThisTheServer)
{
(void) destinationConnection;
if (creatingSystemGUID==replicaManager->GetRakPeerInterface()->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS))
return RM3CS_SEND_CONSTRUCTION;
// Send back to the owner client too, because they couldn't assign the network ID
if (isThisTheServer)
return RM3CS_SEND_CONSTRUCTION;
return RM3CS_NEVER_CONSTRUCT;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool Replica3::QueryRemoteConstruction_ClientConstruction(RakNet::Connection_RM3 *sourceConnection, bool isThisTheServer)
{
(void) sourceConnection;
(void) isThisTheServer;
// OK to create
return true;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RM3ConstructionState Replica3::QueryConstruction_ServerConstruction(RakNet::Connection_RM3 *destinationConnection, bool isThisTheServer)
{
(void) destinationConnection;
if (isThisTheServer)
return RM3CS_SEND_CONSTRUCTION;
return RM3CS_NEVER_CONSTRUCT;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool Replica3::QueryRemoteConstruction_ServerConstruction(RakNet::Connection_RM3 *sourceConnection, bool isThisTheServer)
{
(void) sourceConnection;
if (isThisTheServer)
return false;
return true;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RM3ConstructionState Replica3::QueryConstruction_PeerToPeer(RakNet::Connection_RM3 *destinationConnection, Replica3P2PMode p2pMode)
{
(void) destinationConnection;
if (p2pMode==R3P2PM_SINGLE_OWNER)
{
// We send to all, others do nothing
if (creatingSystemGUID==replicaManager->GetRakPeerInterface()->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS))
return RM3CS_SEND_CONSTRUCTION;
// RM3CS_NEVER_CONSTRUCT will not send the object, and will not Serialize() it
return RM3CS_NEVER_CONSTRUCT;
}
else if (p2pMode==R3P2PM_MULTI_OWNER_CURRENTLY_AUTHORITATIVE)
{
return RM3CS_SEND_CONSTRUCTION;
}
else if (p2pMode==R3P2PM_STATIC_OBJECT_CURRENTLY_AUTHORITATIVE)
{
return RM3CS_ALREADY_EXISTS_REMOTELY;
}
else if (p2pMode==R3P2PM_STATIC_OBJECT_NOT_CURRENTLY_AUTHORITATIVE)
{
return RM3CS_ALREADY_EXISTS_REMOTELY_DO_NOT_CONSTRUCT;
}
else
{
RakAssert(p2pMode==R3P2PM_MULTI_OWNER_NOT_CURRENTLY_AUTHORITATIVE);
// RM3CS_ALREADY_EXISTS_REMOTELY will not send the object, but WILL call QuerySerialization() and Serialize() on it.
return RM3CS_ALREADY_EXISTS_REMOTELY;
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool Replica3::QueryRemoteConstruction_PeerToPeer(RakNet::Connection_RM3 *sourceConnection)
{
(void) sourceConnection;
return true;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RM3QuerySerializationResult Replica3::QuerySerialization_ClientSerializable(RakNet::Connection_RM3 *destinationConnection, bool isThisTheServer)
{
// Owner client sends to all
if (creatingSystemGUID==replicaManager->GetRakPeerInterface()->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS))
return RM3QSR_CALL_SERIALIZE;
// Server sends to all but owner client
if (isThisTheServer && destinationConnection->GetRakNetGUID()!=creatingSystemGUID)
return RM3QSR_CALL_SERIALIZE;
// Remote clients do not send
return RM3QSR_NEVER_CALL_SERIALIZE;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RM3QuerySerializationResult Replica3::QuerySerialization_ServerSerializable(RakNet::Connection_RM3 *destinationConnection, bool isThisTheServer)
{
(void) destinationConnection;
// Server sends to all
if (isThisTheServer)
return RM3QSR_CALL_SERIALIZE;
// Clients do not send
return RM3QSR_NEVER_CALL_SERIALIZE;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RM3QuerySerializationResult Replica3::QuerySerialization_PeerToPeer(RakNet::Connection_RM3 *destinationConnection, Replica3P2PMode p2pMode)
{
(void) destinationConnection;
if (p2pMode==R3P2PM_SINGLE_OWNER)
{
// Owner peer sends to all
if (creatingSystemGUID==replicaManager->GetRakPeerInterface()->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS))
return RM3QSR_CALL_SERIALIZE;
// Remote peers do not send
return RM3QSR_NEVER_CALL_SERIALIZE;
}
else if (p2pMode==R3P2PM_MULTI_OWNER_CURRENTLY_AUTHORITATIVE)
{
return RM3QSR_CALL_SERIALIZE;
}
else if (p2pMode==R3P2PM_STATIC_OBJECT_CURRENTLY_AUTHORITATIVE)
{
return RM3QSR_CALL_SERIALIZE;
}
else if (p2pMode==R3P2PM_STATIC_OBJECT_NOT_CURRENTLY_AUTHORITATIVE)
{
return RM3QSR_DO_NOT_CALL_SERIALIZE;
}
else
{
RakAssert(p2pMode==R3P2PM_MULTI_OWNER_NOT_CURRENTLY_AUTHORITATIVE);
return RM3QSR_DO_NOT_CALL_SERIALIZE;
}
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RM3ActionOnPopConnection Replica3::QueryActionOnPopConnection_Client(RakNet::Connection_RM3 *droppedConnection) const
{
(void) droppedConnection;
return RM3AOPC_DELETE_REPLICA;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RM3ActionOnPopConnection Replica3::QueryActionOnPopConnection_Server(RakNet::Connection_RM3 *droppedConnection) const
{
(void) droppedConnection;
return RM3AOPC_DELETE_REPLICA_AND_BROADCAST_DESTRUCTION;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RM3ActionOnPopConnection Replica3::QueryActionOnPopConnection_PeerToPeer(RakNet::Connection_RM3 *droppedConnection) const
{
(void) droppedConnection;
return RM3AOPC_DELETE_REPLICA;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#endif // _RAKNET_SUPPORT_*