/* * 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(_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 &participantListIn, DataStructures::List &participantListOut, WorldId worldId) { for (unsigned int index=0; index < participantListIn.Size(); index++) { if (GetConnectionByGUID(participantListIn[index], worldId)==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 replicaList; DataStructures::List destructionList; DataStructures::List 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(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 &replicaListIn, WorldId worldId) { unsigned int index; for (index=0; index < replicaListIn.Size(); index++) Dereference(replicaListIn[index], worldId); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void ReplicaManager3::GetReplicasCreatedByMe(DataStructures::List &replicaListOut, WorldId worldId) { //RakNetGUID myGuid = rakPeerInterface->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS); GetReplicasCreatedByGuid(rakPeerInterface->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS), replicaListOut, worldId); } // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void ReplicaManager3::GetReferencedReplicaList(DataStructures::List &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 &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 &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(_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 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 actuallyCreateObjectList; DataStructures::List 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(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(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(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(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 &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 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 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 &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(_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(_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(_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 &newObjects, DataStructures::List &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 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_*