#include "ReplicaManager2.h" #include "MessageIdentifiers.h" #include "RakAssert.h" #include "RakPeerInterface.h" #include "NetworkIDManager.h" using namespace RakNet; unsigned char Replica2::clientSharedID=0; Replica2* Replica2::clientPtrArray[256]; #ifdef _MSC_VER #pragma warning( push ) #endif bool SerializationContext::IsSerializationCommand(SerializationType r) { return r>=SEND_SERIALIZATION_GENERIC_TO_SYSTEM && r<=RELAY_SERIALIZATION_TO_SYSTEMS; } bool SerializationContext::IsDownloadCommand(SerializationType r) { return r>=SEND_CONSTRUCTION_SERIALIZATION_AUTO_INITIAL_DOWNLOAD_TO_SYSTEM && r<=SEND_DATA_SERIALIZATION_AUTO_INITIAL_DOWNLOAD_TO_SYSTEM; } bool SerializationContext::IsDestructionCommand(SerializationType r) { return r>=SEND_DESTRUCTION_GENERIC_TO_SYSTEM && r<=RELAY_DESTRUCTION_TO_SYSTEMS; } bool SerializationContext::IsConstructionCommand(SerializationType r) { return r>=SEND_CONSTRUCTION_GENERIC_TO_SYSTEM && r<=SEND_CONSTRUCTION_REPLY_DENIED_TO_CLIENT; } bool SerializationContext::IsVisibilityCommand(SerializationType r) { return r>=SEND_VISIBILITY_TRUE_TO_SYSTEM && r<=RELAY_VISIBILITY_FALSE_TO_SYSTEMS; } bool SerializationContext::IsVisible(SerializationType r) { return r==SEND_VISIBILITY_TRUE_TO_SYSTEM || r==BROADCAST_VISIBILITY_TRUE_TO_SYSTEM || r==RELAY_VISIBILITY_TRUE_TO_SYSTEMS; } int ReplicaManager2::Replica2CompByNetworkID( const NetworkID &key, RakNet::Replica2 * const &data ) { if (key < data->GetNetworkID()) return -1; if (key == data->GetNetworkID()) return 0; return 1; } int ReplicaManager2::Replica2ObjectComp( RakNet::Replica2 * const &key, RakNet::Replica2 * const &data ) { if (key->GetAllocationNumber()GetAllocationNumber()) return -1; if (key->GetAllocationNumber()==data->GetAllocationNumber()) return 0; return 1; } int ReplicaManager2::Connection_RM2CompBySystemAddress( const SystemAddress &key, RakNet::Connection_RM2 * const &data ) { if (key < data->GetSystemAddress()) return -1; if (key == data->GetSystemAddress()) return 0; return 1; } ReplicaManager2::ReplicaManager2() { connectionFactoryInterface=0; defaultOrderingChannel=0; defaultPacketPriority=HIGH_PRIORITY; defaultPacketReliablity=RELIABLE_ORDERED; autoUpdateConstruction=true; autoUpdateVisibility=true; autoAddNewConnections=true; doReplicaAutoUpdate=true; DataStructures::OrderedList::IMPLEMENT_DEFAULT_COMPARISON(); } ReplicaManager2::~ReplicaManager2() { } void ReplicaManager2::SendConstruction(Replica2 *replica, BitStream *replicaData, SystemAddress recipient, RakNetTime timestamp, bool sendMessage, DataStructures::OrderedList &exclusionList, unsigned char localClientId, SerializationType type, PacketPriority priority, PacketReliability reliability, char orderingChannel) { if (replica==0) return; // Why would you request an object you already have? if (replica->GetNetworkID()!=UNASSIGNED_NETWORK_ID && replica->QueryIsConstructionAuthority()==false) return; RakAssert(replica->QueryConstruction(0)!=BQR_NEVER); bool newConnection; Connection_RM2* connection; // Add to list of replicas if not already there bool newReference; Reference(replica, &newReference); RakNet::BitStream bs; WriteHeader(&bs, ID_REPLICA_MANAGER_CONSTRUCTION, timestamp); bs.Write((unsigned char) type); bs.Write(replica->GetNetworkID()); bs.Write(localClientId); if (recipient!=UNASSIGNED_SYSTEM_ADDRESS) { connection = AutoCreateConnection(recipient, &newConnection); if (connection==0) return; if (newConnection) { // If a new connection, the replica was constructed automatically anyway DownloadToNewConnection(connection, timestamp, defaultPacketPriority, defaultPacketReliablity, defaultOrderingChannel); return; } if (AddToAndWriteExclusionList(recipient, &bs, exclusionList)==false) return; bs.Write(replicaData); // Lookup connection by target. If does not exist, create AddConstructionReference(connection, replica); if (sendMessage) { // Send the packet Send(&bs, recipient, priority, reliability, orderingChannel); if (newReference && replica->QueryVisibility(connection)==BQR_ALWAYS) { // SerializationContext sc; // sc.recipientAddress=recipient; // sc.timestamp=timestamp; // sc.relaySourceAddress=UNASSIGNED_SYSTEM_ADDRESS; // sc.serializationType=SEND_SERIALIZATION_GENERIC_TO_SYSTEM; replica->SendSerialize(recipient, SEND_SERIALIZATION_CONSTRUCTION_TO_SYSTEM); } } } else { DataStructures::OrderedList culledOutput; CullByAndAddToExclusionList(connectionList, culledOutput, exclusionList); WriteExclusionList(&bs, exclusionList); bs.Write(replicaData); unsigned i; for (i=0; i < culledOutput.Size(); i++) { connection=culledOutput[i]; AddConstructionReference(connection, replica); if (sendMessage) Send(&bs, connection->GetSystemAddress(), priority, reliability, orderingChannel); if (newReference && replica->QueryIsSerializationAuthority() && replica->QueryVisibility(connection)==BQR_ALWAYS) { // SerializationContext sc; // sc.recipientAddress=connection->GetSystemAddress(); // sc.timestamp=0; // sc.relaySourceAddress=UNASSIGNED_SYSTEM_ADDRESS; // sc.serializationType=BROADCAST_SERIALIZATION_GENERIC_TO_SYSTEM; replica->SendSerialize(connection->GetSystemAddress(), BROADCAST_SERIALIZATION_CONSTRUCTION_TO_SYSTEM); } } } } void ReplicaManager2::SendDestruction(Replica2 *replica, BitStream *replicaData, SystemAddress recipient, RakNetTime timestamp, bool sendMessage, DataStructures::OrderedList &exclusionList, SerializationType type, PacketPriority priority, PacketReliability reliability, char orderingChannel) { if (replica==0) return; if (replica->QueryIsDestructionAuthority()==false) return; if (recipient!=UNASSIGNED_SYSTEM_ADDRESS) { bool newConnection; // Lookup connection by target. If does not exist, create Connection_RM2* connection = AutoCreateConnection(recipient, &newConnection); if (connection==0) return; // Have this system stop referencing the replica object connection->Deref(replica); if (newConnection) { // If a new connection, the object didn't exist anyway DownloadToNewConnection(connection, timestamp, defaultPacketPriority, defaultPacketReliablity, defaultOrderingChannel); return; } } if (sendMessage && replica->GetNetworkID()!=UNASSIGNED_NETWORK_ID) { // Send the packet RakNet::BitStream bs; WriteHeader(&bs, ID_REPLICA_MANAGER_DESTRUCTION, timestamp); bs.Write((unsigned char) type); bs.Write(replica->GetNetworkID()); if (recipient!=UNASSIGNED_SYSTEM_ADDRESS) { if (AddToAndWriteExclusionList(recipient, &bs, exclusionList)==false) return; bs.Write(replicaData); Send(&bs, recipient, priority, reliability, orderingChannel); } else { DataStructures::OrderedList output, culledOutput; GetConnectionsWithReplicaConstructed(replica, output); CullByAndAddToExclusionList(output, culledOutput, exclusionList); WriteExclusionList(&bs, exclusionList); bs.Write(replicaData); unsigned i; for (i=0; i < output.Size(); i++) Send(&bs, output[i]->GetSystemAddress(), priority, reliability, orderingChannel); } } } void ReplicaManager2::SendSerialize(Replica2 *replica, BitStream *replicaData, SystemAddress recipient, RakNetTime timestamp, DataStructures::OrderedList &exclusionList, SerializationType type, PacketPriority priority, PacketReliability reliability, char orderingChannel) { if (replica==0) return; if (replica->GetNetworkID()==UNASSIGNED_NETWORK_ID) return; if (replica->QueryIsSerializationAuthority()==false) return; // Add to list of replicas if not already there bool newReference; Reference(replica, &newReference); if (newReference && replica->QueryConstruction(0)==BQR_ALWAYS) { replica->BroadcastConstruction(); } bool newConnection; Connection_RM2* connection; RakNet::BitStream bs; WriteHeader(&bs, ID_REPLICA_MANAGER_SERIALIZE, timestamp); bs.Write((unsigned char) type); bs.Write(replica->GetNetworkID()); if (recipient!=UNASSIGNED_SYSTEM_ADDRESS) { connection = AutoCreateConnection(recipient, &newConnection); if (connection==0) return; if (newConnection) DownloadToNewConnection(connection, timestamp, defaultPacketPriority, defaultPacketReliablity, defaultOrderingChannel); if (AddToAndWriteExclusionList(recipient, &bs, exclusionList)==false) return; bs.Write(replicaData); // Send the packet Send(&bs, recipient, priority, reliability, orderingChannel); } else { DataStructures::OrderedList output, culledOutput; GetConnectionsWithSerializeVisibility(replica, output); CullByAndAddToExclusionList(output, culledOutput, exclusionList); WriteExclusionList(&bs, exclusionList); bs.Write(replicaData); unsigned i; for (i=0; i < culledOutput.Size(); i++) { connection=culledOutput[i]; Send(&bs, connection->GetSystemAddress(), priority, reliability, orderingChannel); } } } void ReplicaManager2::SendVisibility(Replica2 *replica, BitStream *replicaData, SystemAddress recipient, RakNetTime timestamp, DataStructures::OrderedList &exclusionList, SerializationType type, PacketPriority priority, PacketReliability reliability, char orderingChannel) { if (replica==0) return; bool newConnection; Connection_RM2* connection; if (replica->GetNetworkID()==UNASSIGNED_NETWORK_ID) return; // Add to list of replicas if not already there bool newReference; Reference(replica, &newReference); if (newReference && replica->QueryConstruction(0)==BQR_ALWAYS) { replica->BroadcastConstruction(); } RakNet::BitStream bs; WriteHeader(&bs, ID_REPLICA_MANAGER_SCOPE_CHANGE, timestamp); bs.Write((unsigned char) type); bs.Write(replica->GetNetworkID()); if (recipient!=UNASSIGNED_SYSTEM_ADDRESS) { if (AddToAndWriteExclusionList(recipient, &bs, exclusionList)==false) return; connection = AutoCreateConnection(recipient, &newConnection); if (connection==0) return; if (newConnection) DownloadToNewConnection(connection, timestamp, defaultPacketPriority, defaultPacketReliablity, defaultOrderingChannel); bs.Write(replicaData); if (SerializationContext::IsVisibilityCommand(type)) { if (SerializationContext::IsVisible(type)) AddVisibilityReference(connection, replica); else RemoveVisibilityReference(connection, replica); } // Send the packet Send(&bs, recipient, priority, reliability, orderingChannel); } else { DataStructures::OrderedList culledOutput; CullByAndAddToExclusionList(connectionList, culledOutput, exclusionList); WriteExclusionList(&bs, exclusionList); bs.Write(replicaData); unsigned i; for (i=0; i < culledOutput.Size(); i++) { connection=culledOutput[i]; if (SerializationContext::IsVisible(type)) AddVisibilityReference(connection, replica); else RemoveVisibilityReference(connection, replica); Send(&bs, connection->GetSystemAddress(), priority, reliability, orderingChannel); } } } void ReplicaManager2::Dereference(Replica2 *replica) { unsigned i; if (replica==0) return; for (i=0; i < connectionList.Size(); i++) { connectionList[i]->lastConstructionList.RemoveIfExists(replica); connectionList[i]->lastSerializationList.RemoveIfExists(replica); } for (i=0; i < fullReplicaUnorderedList.Size(); i++) { if (fullReplicaUnorderedList[i]==replica) { fullReplicaUnorderedList.RemoveAtIndex(i); break; } } fullReplicaOrderedList.RemoveIfExists(replica); alwaysDoConstructReplicaOrderedList.RemoveIfExists(replica); alwaysDoSerializeReplicaOrderedList.RemoveIfExists(replica); variableConstructReplicaOrderedList.RemoveIfExists(replica); variableSerializeReplicaOrderedList.RemoveIfExists(replica); } void ReplicaManager2::Update(RakPeerInterface *peer) { (void) peer; unsigned i; if (autoUpdateConstruction || autoUpdateVisibility) { for (i=0; i < connectionList.Size(); i++) { if (autoUpdateConstruction) connectionList[i]->SetConstructionByReplicaQuery(this); if (autoUpdateVisibility) connectionList[i]->SetVisibilityByReplicaQuery(this); } } if (doReplicaAutoUpdate) { RakNetTime currentTime = RakNet::GetTime(); for (i=0; i < fullReplicaUnorderedList.Size(); i++) { fullReplicaUnorderedList[i]->ElapseAutoSerializeTimers(currentTime-lastUpdateTime,false); } lastUpdateTime=currentTime; } } unsigned ReplicaManager2::GetReplicaCount(void) const { return fullReplicaUnorderedList.Size(); } Replica2 *ReplicaManager2::GetReplicaAtIndex(unsigned index) { return fullReplicaUnorderedList[index]; } void ReplicaManager2::SetAutoAddNewConnections(bool autoDownload) { autoAddNewConnections=autoDownload; } void ReplicaManager2::SetDoReplicaAutoSerializeUpdate(bool autoUpdate) { doReplicaAutoUpdate=autoUpdate; } void ReplicaManager2::SetConnectionFactory(Connection_RM2Factory *factory) { RakAssert(factory); connectionFactoryInterface=factory; } unsigned ReplicaManager2::GetConnectionCount(void) const { return connectionList.Size(); } Connection_RM2* ReplicaManager2::GetConnectionAtIndex(unsigned index) const { return connectionList[index]; } Connection_RM2* ReplicaManager2::GetConnectionBySystemAddress(SystemAddress systemAddress) const { bool objectExists; unsigned index = connectionList.GetIndexFromKey(systemAddress, &objectExists); if (objectExists) return connectionList[index]; return 0; } unsigned int ReplicaManager2::GetConnectionIndexBySystemAddress(SystemAddress systemAddress) const { bool objectExists; unsigned index = connectionList.GetIndexFromKey(systemAddress, &objectExists); if (objectExists) return index; return (unsigned int) -1; } void ReplicaManager2::SetDefaultOrderingChannel(char def) { defaultOrderingChannel=def; } void ReplicaManager2::SetDefaultPacketPriority(PacketPriority def) { defaultPacketPriority=def; } void ReplicaManager2::SetDefaultPacketReliability(PacketReliability def) { defaultPacketReliablity=def; } void ReplicaManager2::SetAutoUpdateScope(bool construction, bool visibility) { autoUpdateConstruction=construction; autoUpdateVisibility=visibility; } void ReplicaManager2::RecalculateVisibility(Replica2 *replica) { Dereference(replica); bool newReference; Reference(replica, &newReference); if (replica->QueryConstruction(0)==BQR_NEVER && autoUpdateConstruction) { // Destroy on all systems replica->SendDestruction(UNASSIGNED_SYSTEM_ADDRESS, SEND_DESTRUCTION_VISIBILITY_RECALCULATION_TO_SYSTEM); } if (replica->QueryConstruction(0)==BQR_ALWAYS && autoUpdateConstruction) { // Create on all systems replica->SendConstruction(UNASSIGNED_SYSTEM_ADDRESS, SEND_CONSTRUCTION_VISIBILITY_RECALCULATION_TO_SYSTEM); } if (replica->QueryVisibility(0)==BQR_ALWAYS && autoUpdateVisibility) { // Set visibility and creation on all systems replica->SendVisibility(UNASSIGNED_SYSTEM_ADDRESS, UNDEFINED_REASON); replica->SendSerialize(UNASSIGNED_SYSTEM_ADDRESS, UNDEFINED_REASON); } } void ReplicaManager2::GetConnectionsWithReplicaConstructed(Replica2 *replica, DataStructures::OrderedList &output) { BooleanQueryResult res; res = replica->QueryConstruction(0); if (res==BQR_ALWAYS) { output=connectionList; } else if (res!=BQR_NEVER) { unsigned i; for (i=0; i < connectionList.Size(); i++) { if (connectionList[i]->lastConstructionList.HasData(replica)) output.Insert(connectionList[i]->GetSystemAddress(),connectionList[i], false); } } } void ReplicaManager2::GetConnectionsWithSerializeVisibility(Replica2 *replica, DataStructures::OrderedList &output) { BooleanQueryResult res; res = replica->QueryVisibility(0); if (res==BQR_ALWAYS) { GetConnectionsWithReplicaConstructed(replica, output); } else if (res!=BQR_NEVER) { unsigned i; for (i=0; i < connectionList.Size(); i++) { if (connectionList[i]->lastSerializationList.HasData(replica)) output.Insert(connectionList[i]->GetSystemAddress(),connectionList[i], false); } } } RakPeerInterface *ReplicaManager2::GetRakPeer(void) const { return rakPeer; } Connection_RM2* ReplicaManager2::AutoCreateConnection(SystemAddress systemAddress, bool *newConnection) { if (autoAddNewConnections) return CreateConnectionIfDoesNotExist(systemAddress, newConnection); else { bool objectExists; unsigned index = connectionList.GetIndexFromKey(systemAddress, &objectExists); *newConnection=false; if (objectExists==false) { return 0; } return connectionList[index]; } } Connection_RM2* ReplicaManager2::CreateConnectionIfDoesNotExist(SystemAddress systemAddress, bool *newConnection) { bool objectExists; unsigned index = connectionList.GetIndexFromKey(systemAddress, &objectExists); if (objectExists==false) { // If it crashes here, you need to call SetConnection_RM2Factory Connection_RM2 *connection = connectionFactoryInterface->AllocConnection(); connection->SetSystemAddress(systemAddress); connectionList.Insert(systemAddress, connection, false); *newConnection=true; return connection; } *newConnection=false; return connectionList[index]; } bool ReplicaManager2::AddNewConnection(SystemAddress systemAddress) { bool newConnection; Connection_RM2* connection = CreateConnectionIfDoesNotExist(systemAddress, &newConnection); if (newConnection) DownloadToNewConnection(connection, 0, defaultPacketPriority, defaultPacketReliablity, defaultOrderingChannel); return newConnection; } bool ReplicaManager2::RemoveConnection(SystemAddress systemAddress) { unsigned int index = GetConnectionIndexBySystemAddress(systemAddress); if (index!=(unsigned int) -1) { connectionFactoryInterface->DeallocConnection(connectionList[index]); connectionList.RemoveAtIndex(index); return true; } return false; } bool ReplicaManager2::HasConnection(SystemAddress systemAddress) { unsigned int index = GetConnectionIndexBySystemAddress(systemAddress); return index!=(unsigned int) -1; } void ReplicaManager2::Reference(Replica2* replica, bool *newReference) { replica->SetReplicaManager(this); bool objectExists; unsigned index = fullReplicaOrderedList.GetIndexFromKey(replica,&objectExists); if (objectExists==false) { fullReplicaUnorderedList.Insert(replica); fullReplicaOrderedList.InsertAtIndex(replica, index); BooleanQueryResult queryResult; queryResult = replica->QueryConstruction(0); if (queryResult==BQR_ALWAYS) alwaysDoConstructReplicaOrderedList.Insert(replica,replica, false); else if (queryResult!=BQR_NEVER) variableConstructReplicaOrderedList.Insert(replica,replica, false); queryResult = replica->QueryVisibility(0); if (queryResult==BQR_ALWAYS) alwaysDoSerializeReplicaOrderedList.Insert(replica,replica, false); else if (queryResult!=BQR_NEVER) variableSerializeReplicaOrderedList.Insert(replica,replica, false); *newReference=true; return; } *newReference=false; } void ReplicaManager2::AddConstructionReference(Connection_RM2* connection, Replica2* replica) { if (replica->QueryIsConstructionAuthority() && replica->QueryConstruction(0)!=BQR_ALWAYS && replica->QueryConstruction(0)!=BQR_NEVER) connection->lastConstructionList.Insert(replica, replica, false); } void ReplicaManager2::AddVisibilityReference(Connection_RM2* connection, Replica2* replica) { if (replica->QueryIsVisibilityAuthority() && replica->QueryVisibility(0)!=BQR_ALWAYS && replica->QueryVisibility(0)!=BQR_NEVER) connection->lastSerializationList.Insert(replica, replica, false); } void ReplicaManager2::RemoveVisibilityReference(Connection_RM2* connection, Replica2* replica) { if (replica->QueryIsVisibilityAuthority() && replica->QueryVisibility(0)!=BQR_ALWAYS && replica->QueryVisibility(0)!=BQR_NEVER) connection->lastSerializationList.RemoveIfExists(replica); } void ReplicaManager2::WriteHeader(RakNet::BitStream *bs, MessageID type, RakNetTime timestamp) { if (timestamp!=0) { bs->Write((MessageID)ID_TIMESTAMP); bs->Write(timestamp); } bs->Write(type); } void ReplicaManager2::OnCloseConnection(RakPeerInterface *peer, SystemAddress systemAddress) { (void) peer; RemoveConnection(systemAddress); } void ReplicaManager2::OnShutdown(RakPeerInterface *peer) { (void) peer; Clear(); } void ReplicaManager2::OnAttach(RakPeerInterface *peer) { rakPeer=peer; lastUpdateTime=RakNet::GetTime(); } PluginReceiveResult ReplicaManager2::OnReceive(RakPeerInterface *peer, Packet *packet) { RakNetTime timestamp=0; unsigned char packetIdentifier, packetDataOffset; if ( ( unsigned char ) packet->data[ 0 ] == ID_TIMESTAMP ) { if ( packet->length > sizeof( unsigned char ) + sizeof( RakNetTime ) ) { packetIdentifier = ( unsigned char ) packet->data[ sizeof( unsigned char ) + sizeof( RakNetTime ) ]; // Required for proper endian swapping RakNet::BitStream tsBs(packet->data+sizeof(MessageID),packet->length-1,false); tsBs.Read(timestamp); packetDataOffset=sizeof( unsigned char )*2 + sizeof( RakNetTime ); } else return RR_STOP_PROCESSING_AND_DEALLOCATE; } else { packetIdentifier = ( unsigned char ) packet->data[ 0 ]; packetDataOffset=sizeof( unsigned char ); } switch (packetIdentifier) { case ID_NEW_INCOMING_CONNECTION: case ID_CONNECTION_REQUEST_ACCEPTED: if (autoAddNewConnections) AddNewConnection(packet->systemAddress); return RR_CONTINUE_PROCESSING; case ID_DISCONNECTION_NOTIFICATION: case ID_CONNECTION_LOST: OnCloseConnection(peer, packet->systemAddress); return RR_CONTINUE_PROCESSING; case ID_REPLICA_MANAGER_DOWNLOAD_STARTED: return OnDownloadStarted(packet->data+packetDataOffset, packet->length-packetDataOffset, packet->systemAddress, timestamp); case ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE: return OnDownloadComplete(packet->data+packetDataOffset, packet->length-packetDataOffset, packet->systemAddress, timestamp); case ID_REPLICA_MANAGER_CONSTRUCTION: return OnConstruction(packet->data+packetDataOffset, packet->length-packetDataOffset, packet->systemAddress, timestamp); case ID_REPLICA_MANAGER_DESTRUCTION: return OnDestruction(packet->data+packetDataOffset, packet->length-packetDataOffset, packet->systemAddress, timestamp); case ID_REPLICA_MANAGER_SCOPE_CHANGE: return OnVisibilityChange(packet->data+packetDataOffset, packet->length-packetDataOffset, packet->systemAddress, timestamp); case ID_REPLICA_MANAGER_SERIALIZE: return OnSerialize(packet->data+packetDataOffset, packet->length-packetDataOffset, packet->systemAddress, timestamp); } return RR_CONTINUE_PROCESSING; } PluginReceiveResult ReplicaManager2::OnDownloadStarted(unsigned char *packetData, int packetDataLength, SystemAddress sender, RakNetTime timestamp) { RakNet::BitStream incomingBitstream(packetData, packetDataLength, false); bool newConnection; Connection_RM2* connection = AutoCreateConnection(sender, &newConnection); if (connection==0) return RR_CONTINUE_PROCESSING; SerializationType serializationType; unsigned char c; incomingBitstream.Read(c); serializationType=(SerializationType) c; connection->DeserializeDownloadStarted(&incomingBitstream, sender, this, timestamp, serializationType); if (newConnection) DownloadToNewConnection(connection, timestamp, defaultPacketPriority, defaultPacketReliablity, defaultOrderingChannel); return RR_STOP_PROCESSING_AND_DEALLOCATE; } PluginReceiveResult ReplicaManager2::OnDownloadComplete(unsigned char *packetData, int packetDataLength, SystemAddress sender, RakNetTime timestamp) { RakNet::BitStream incomingBitstream(packetData, packetDataLength, false); bool newConnection; Connection_RM2* connection = AutoCreateConnection(sender, &newConnection); if (connection==0) return RR_CONTINUE_PROCESSING; SerializationType serializationType; unsigned char c; incomingBitstream.Read(c); serializationType=(SerializationType) c; connection->DeserializeDownloadComplete(&incomingBitstream, sender, this, timestamp, serializationType); if (newConnection) DownloadToNewConnection(connection, timestamp, defaultPacketPriority, defaultPacketReliablity, defaultOrderingChannel); return RR_STOP_PROCESSING_AND_DEALLOCATE; } PluginReceiveResult ReplicaManager2::OnConstruction(unsigned char *packetData, int packetDataLength, SystemAddress sender, RakNetTime timestamp) { RakNet::BitStream incomingBitstream(packetData, packetDataLength, false); bool newConnection; Connection_RM2* connection = AutoCreateConnection(sender, &newConnection); if (connection==0) return RR_CONTINUE_PROCESSING; SerializationType serializationType; unsigned char c; incomingBitstream.Read(c); serializationType=(SerializationType) c; NetworkID networkId=UNASSIGNED_NETWORK_ID; unsigned char localClientId=255; bool success; incomingBitstream.Read(networkId); success=incomingBitstream.Read(localClientId); RakAssert(success); DataStructures::OrderedList exclusionList; ReadExclusionList(&incomingBitstream, exclusionList); exclusionList.Insert(sender,sender, false); Replica2* replica; replica = connection->ReceiveConstruct(&incomingBitstream, networkId, sender, localClientId, serializationType, this, timestamp,exclusionList); if (replica) { // Register this object on this connection AddConstructionReference(connection, replica); } return RR_STOP_PROCESSING_AND_DEALLOCATE; } PluginReceiveResult ReplicaManager2::OnDestruction(unsigned char *packetData, int packetDataLength, SystemAddress sender, RakNetTime timestamp) { if (HasConnection(sender)==false) return RR_CONTINUE_PROCESSING; RakNet::BitStream incomingBitstream(packetData, packetDataLength, false); SerializationType serializationType; unsigned char c; incomingBitstream.Read(c); serializationType=(SerializationType) c; NetworkID networkId; incomingBitstream.Read(networkId); DataStructures::OrderedList exclusionList; ReadExclusionList(&incomingBitstream, exclusionList); exclusionList.Insert(sender,sender, false); Replica2 * replica = rakPeer->GetNetworkIDManager()->GET_OBJECT_FROM_ID( networkId ); if (replica) { // Verify that this is a registered object, so it actually is a Replica2 if (fullReplicaOrderedList.HasData((Replica2 *)replica)==false) { // This object is not registered return RR_STOP_PROCESSING_AND_DEALLOCATE; } replica->ReceiveDestruction(sender, &incomingBitstream, serializationType, timestamp,exclusionList ); } // else this object is unknown return RR_STOP_PROCESSING_AND_DEALLOCATE; } PluginReceiveResult ReplicaManager2::OnVisibilityChange(unsigned char *packetData, int packetDataLength, SystemAddress sender, RakNetTime timestamp) { RakNet::BitStream incomingBitstream(packetData, packetDataLength, false); bool newConnection; Connection_RM2* connection = AutoCreateConnection(sender, &newConnection); if (connection==0) return RR_CONTINUE_PROCESSING; SerializationType serializationType; unsigned char c; incomingBitstream.Read(c); serializationType=(SerializationType) c; NetworkID networkId; incomingBitstream.Read(networkId); DataStructures::OrderedList exclusionList; ReadExclusionList(&incomingBitstream, exclusionList); exclusionList.Insert(sender,sender, false); Replica2 *replica = rakPeer->GetNetworkIDManager()->GET_OBJECT_FROM_ID( networkId ); if (replica) { // Verify that this is a registered object, so it actually is a Replica2 if (fullReplicaOrderedList.HasData((Replica2 *)replica)==false) { RakAssert(0); return RR_STOP_PROCESSING_AND_DEALLOCATE; } replica->ReceiveVisibility(sender, &incomingBitstream, serializationType, timestamp,exclusionList); AddConstructionReference(connection, replica); // Update the last known visibility list if (SerializationContext::IsVisibilityCommand(serializationType)) { if (SerializationContext::IsVisible(serializationType)) AddVisibilityReference(connection, replica); else RemoveVisibilityReference(connection, replica); } } return RR_STOP_PROCESSING_AND_DEALLOCATE; } PluginReceiveResult ReplicaManager2::OnSerialize(unsigned char *packetData, int packetDataLength, SystemAddress sender, RakNetTime timestamp) { RakNet::BitStream incomingBitstream(packetData, packetDataLength, false); Connection_RM2* connection = GetConnectionBySystemAddress(sender); if (connection==0) return RR_CONTINUE_PROCESSING; SerializationType serializationType; unsigned char c; incomingBitstream.Read(c); serializationType=(SerializationType) c; NetworkID networkId; incomingBitstream.Read(networkId); DataStructures::OrderedList exclusionList; ReadExclusionList(&incomingBitstream, exclusionList); exclusionList.Insert(sender,sender, false); Replica2 *replica = rakPeer->GetNetworkIDManager()->GET_OBJECT_FROM_ID( networkId ); if (replica) { // Verify that this is a registered object, so it actually is a Replica2 if (fullReplicaOrderedList.HasData((Replica2 *)replica)==false) { RakAssert(0); return RR_STOP_PROCESSING_AND_DEALLOCATE; } exclusionList.Insert(sender,sender, false); replica->ReceiveSerialize(sender, &incomingBitstream, serializationType, timestamp,exclusionList); AddConstructionReference(connection, replica); } return RR_STOP_PROCESSING_AND_DEALLOCATE; } bool ReplicaManager2::AddToAndWriteExclusionList(SystemAddress recipient, RakNet::BitStream *bs, DataStructures::OrderedList &exclusionList) { if (exclusionList.HasData(recipient)) return false; exclusionList.Insert(recipient,recipient,true); WriteExclusionList(bs,exclusionList); return true; } void ReplicaManager2::WriteExclusionList(RakNet::BitStream *bs, DataStructures::OrderedList &exclusionList) { bs->WriteCompressed(exclusionList.Size()); for (unsigned exclusionListIndex=0; exclusionListIndex < exclusionList.Size(); exclusionListIndex++ ) bs->Write(exclusionList[exclusionListIndex]); } void ReplicaManager2::CullByAndAddToExclusionList( DataStructures::OrderedList &inputList, DataStructures::OrderedList &culledOutput, DataStructures::OrderedList &exclusionList) { Connection_RM2* connection; unsigned i; unsigned exclusionListIndex=0; for (i=0; i < inputList.Size(); i++) { connection=inputList[i]; while (exclusionListIndex < exclusionList.Size() && exclusionList[exclusionListIndex] < connection->GetSystemAddress()) exclusionListIndex++; if (exclusionListIndex < exclusionList.Size() && exclusionList[exclusionListIndex]==connection->GetSystemAddress()) { exclusionListIndex++; continue; } culledOutput.InsertAtEnd(connection); } for (i=0; i < culledOutput.Size(); i++) exclusionList.Insert(culledOutput[i]->GetSystemAddress(),culledOutput[i]->GetSystemAddress(),true); } void ReplicaManager2::ReadExclusionList(RakNet::BitStream *bs, DataStructures::OrderedList &exclusionList) { unsigned int exclusionListSize; bs->ReadCompressed(exclusionListSize); for (unsigned exclusionListIndex=0; exclusionListIndex < exclusionListSize; exclusionListIndex++) { SystemAddress systemToExclude; bs->Read(systemToExclude); exclusionList.InsertAtEnd(systemToExclude); } } void ReplicaManager2::Send(RakNet::BitStream *bs, SystemAddress recipient, PacketPriority priority, PacketReliability reliability, char orderingChannel) { if (priority==NUMBER_OF_PRIORITIES) priority=defaultPacketPriority; if (reliability==NUMBER_OF_RELIABILITIES) reliability=defaultPacketReliablity; if (orderingChannel==-1) orderingChannel=defaultOrderingChannel; rakPeer->Send(bs, priority,reliability,orderingChannel,recipient,false); } void ReplicaManager2::Clear(void) { fullReplicaUnorderedList.Clear(); fullReplicaOrderedList.Clear(); alwaysDoConstructReplicaOrderedList.Clear(); alwaysDoSerializeReplicaOrderedList.Clear(); variableConstructReplicaOrderedList.Clear(); variableSerializeReplicaOrderedList.Clear(); unsigned i; for (i=0; i < connectionList.Size(); i++) connectionFactoryInterface->DeallocConnection(connectionList[i]); connectionList.Clear(); } void ReplicaManager2::DownloadToNewConnection(Connection_RM2* connection, RakNetTime timestamp, PacketPriority priority, PacketReliability reliability, char orderingChannel) { unsigned int i; RakNet::BitStream bs, bs2; BooleanQueryResult bqr; SystemAddress systemAddress = connection->GetSystemAddress(); SerializationContext serializationContext; serializationContext.recipientAddress=systemAddress; serializationContext.relaySourceAddress=UNASSIGNED_SYSTEM_ADDRESS; serializationContext.serializationType=SEND_CONSTRUCTION_SERIALIZATION_AUTO_INITIAL_DOWNLOAD_TO_SYSTEM; serializationContext.timestamp=0; // bs2 is so SerializeDownloadStarted can change the timestamp connection->SerializeDownloadStarted(&bs2, this, &serializationContext); WriteHeader(&bs, ID_REPLICA_MANAGER_DOWNLOAD_STARTED, timestamp); bs.Write((unsigned char) SEND_CONSTRUCTION_SERIALIZATION_AUTO_INITIAL_DOWNLOAD_TO_SYSTEM); bs.Write(&bs2); Send(&bs, connection->GetSystemAddress(), priority, reliability, orderingChannel); // Construct all objects before serializing them. This way the recipient will have valid NetworkID references. // Send all objects that always exist for (i=0; i < fullReplicaUnorderedList.Size(); i++) { if (fullReplicaUnorderedList[i]->QueryIsConstructionAuthority()) { bqr=fullReplicaUnorderedList[i]->QueryConstruction(connection); if (bqr==BQR_ALWAYS || bqr==BQR_YES) fullReplicaUnorderedList[i]->SendConstruction(systemAddress, SEND_CONSTRUCTION_SERIALIZATION_AUTO_INITIAL_DOWNLOAD_TO_SYSTEM); // Remember for this particular connection that we already sent this update to this system if (bqr==BQR_YES) AddConstructionReference(connection, fullReplicaUnorderedList[i]); } } bool notVisible; // Send all objects that are always visible for (i=0; i < fullReplicaUnorderedList.Size(); i++) { notVisible=false; if (fullReplicaUnorderedList[i]->QueryIsVisibilityAuthority()) { bqr=fullReplicaUnorderedList[i]->QueryVisibility(connection); if (bqr==BQR_ALWAYS || bqr==BQR_YES) { fullReplicaUnorderedList[i]->SendVisibility(systemAddress, SEND_VISIBILITY_AUTO_INITIAL_DOWNLOAD_TO_SYSTEM); // Remember for this particular connection that we already sent this update to this system if (bqr==BQR_YES) AddVisibilityReference(connection, fullReplicaUnorderedList[i]); } else notVisible=true; } if (fullReplicaUnorderedList[i]->QueryIsSerializationAuthority() && notVisible==false) fullReplicaUnorderedList[i]->SendSerialize(systemAddress, SEND_DATA_SERIALIZATION_AUTO_INITIAL_DOWNLOAD_TO_SYSTEM); } bs.Reset(); // bs2 is so SerializeDownloadComplete can change the timestamp connection->SerializeDownloadComplete(&bs2, this,&serializationContext); WriteHeader(&bs, ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE, timestamp); bs.Write((unsigned char) SEND_CONSTRUCTION_SERIALIZATION_AUTO_INITIAL_DOWNLOAD_TO_SYSTEM); bs.Write(&bs2); Send(&bs, connection->GetSystemAddress(), priority, reliability, orderingChannel); } Replica2::Replica2() { rm2=0; hasClientID=false; DataStructures::Map::IMPLEMENT_DEFAULT_COMPARISON(); } Replica2::~Replica2() { rm2->Dereference(this); if (hasClientID) clientPtrArray[clientID]=0; ClearAutoSerializeTimers(); } void Replica2::SetReplicaManager(ReplicaManager2* rm) { rm2=rm; if (GetNetworkIDManager()==0) SetNetworkIDManager(rm->GetRakPeer()->GetNetworkIDManager()); } ReplicaManager2* Replica2::GetReplicaManager(void) const { return rm2; } bool Replica2::SerializeDestruction(RakNet::BitStream *bitStream, SerializationContext *serializationContext) { (void) bitStream; (void) serializationContext; return true; } bool Replica2::Serialize(RakNet::BitStream *bitStream, SerializationContext *serializationContext) { (void) bitStream; (void) serializationContext; return true; } bool Replica2::SerializeVisibility(RakNet::BitStream *bitStream, SerializationContext *serializationContext) { (void) bitStream; (void) serializationContext; return true; } void Replica2::DeserializeDestruction(RakNet::BitStream *bitStream, SerializationType serializationType, SystemAddress sender, RakNetTime timestamp) { (void) bitStream; (void) serializationType; (void) sender; (void) timestamp; } void Replica2::Deserialize(RakNet::BitStream *bitStream, SerializationType serializationType, SystemAddress sender, RakNetTime timestamp) { (void) bitStream; (void) serializationType; (void) sender; (void) timestamp; } void Replica2::DeserializeVisibility(RakNet::BitStream *bitStream, SerializationType serializationType, SystemAddress sender, RakNetTime timestamp) { (void) bitStream; (void) serializationType; (void) sender; (void) timestamp; } void Replica2::SendConstruction(SystemAddress recipientAddress, SerializationType serializationType) { RakNet::BitStream bs; SerializationContext defaultContext; if (serializationType==UNDEFINED_REASON) { if (QueryIsConstructionAuthority()==false) defaultContext.serializationType=SEND_CONSTRUCTION_REQUEST_TO_SERVER; else defaultContext.serializationType=SEND_CONSTRUCTION_GENERIC_TO_SYSTEM; } else defaultContext.serializationType=serializationType; defaultContext.relaySourceAddress=UNASSIGNED_SYSTEM_ADDRESS; defaultContext.recipientAddress=recipientAddress; defaultContext.timestamp=0; unsigned char localId; if (QueryIsConstructionAuthority()==false) localId=Replica2::clientSharedID++; else localId=0; DataStructures::OrderedList exclusionList; if (SerializeConstruction(&bs, &defaultContext)) rm2->SendConstruction(this,&bs,recipientAddress,defaultContext.timestamp,true,exclusionList,localId,defaultContext.serializationType); } void Replica2::SendDestruction(SystemAddress recipientAddress, SerializationType serializationType) { RakNet::BitStream bs; SerializationContext defaultContext(serializationType, UNASSIGNED_SYSTEM_ADDRESS, recipientAddress,0); if (serializationType==UNDEFINED_REASON) defaultContext.serializationType=SEND_DESTRUCTION_GENERIC_TO_SYSTEM; DataStructures::OrderedList exclusionList; if (SerializeDestruction(&bs, &defaultContext)) rm2->SendDestruction(this,&bs,recipientAddress,defaultContext.timestamp,true,exclusionList,defaultContext.serializationType); } void Replica2::SendSerialize(SystemAddress recipientAddress, SerializationType serializationType) { RakNet::BitStream bs; SerializationContext defaultContext(serializationType, UNASSIGNED_SYSTEM_ADDRESS, recipientAddress,0); if (serializationType==UNDEFINED_REASON) defaultContext.serializationType=SEND_SERIALIZATION_GENERIC_TO_SYSTEM; if (Serialize(&bs, &defaultContext)) { DataStructures::OrderedList exclusionList; rm2->SendSerialize(this,&bs,recipientAddress,defaultContext.timestamp,exclusionList,defaultContext.serializationType); } } void Replica2::SendVisibility(SystemAddress recipientAddress, SerializationType serializationType) { RakNet::BitStream bs; SerializationContext defaultContext(serializationType, UNASSIGNED_SYSTEM_ADDRESS, recipientAddress,0); if (serializationType==UNDEFINED_REASON) defaultContext.serializationType=SEND_VISIBILITY_TRUE_TO_SYSTEM; if (SerializeVisibility(&bs, &defaultContext)) { DataStructures::OrderedList exclusionList; rm2->SendVisibility(this,&bs,recipientAddress,defaultContext.timestamp,exclusionList,defaultContext.serializationType); } } void Replica2::BroadcastSerialize(SerializationContext *serializationContext) { RakNet::BitStream bs; SerializationContext defaultContext(BROADCAST_SERIALIZATION_GENERIC_TO_SYSTEM, UNASSIGNED_SYSTEM_ADDRESS, UNASSIGNED_SYSTEM_ADDRESS,0); SerializationContext *usedContext; if (serializationContext) usedContext=serializationContext; else usedContext=&defaultContext; bool newReference; rm2->Reference(this, &newReference); // If this is a new object, then before sending serialization we should send construction to all systems if (newReference && QueryConstruction(0)==BQR_ALWAYS) { BroadcastConstruction(); } DataStructures::OrderedList exclusionList; for (unsigned i=0; i < rm2->GetConnectionCount(); i++) { usedContext->recipientAddress=rm2->GetConnectionAtIndex(i)->GetSystemAddress(); if (usedContext->relaySourceAddress==usedContext->recipientAddress) continue; bs.Reset(); if (Serialize(&bs, usedContext)==false) continue; exclusionList.Clear(); for (unsigned j=0; j < rm2->connectionList.Size(); j++) { if (rm2->connectionList[j]->GetSystemAddress()!=usedContext->recipientAddress) exclusionList.InsertAtEnd(rm2->connectionList[j]->GetSystemAddress()); } rm2->SendSerialize(this,&bs,usedContext->recipientAddress,usedContext->timestamp,exclusionList,usedContext->serializationType); } } void Replica2::ReceiveSerialize(SystemAddress sender, RakNet::BitStream *serializedObject, SerializationType serializationType, RakNetTime timestamp, DataStructures::OrderedList &exclusionList ) { // Force all autoserialize timers to go off early, so any variable changes from the Deserialize event do not themselves trigger an autoserialize event ForceElapseAllAutoserializeTimers(false); // Deserialize the new data Deserialize(serializedObject, serializationType, sender, timestamp); // Update last values for all autoserialize timers ForceElapseAllAutoserializeTimers(true); SerializationContext serializationContext; serializationContext.serializationType=RELAY_SERIALIZATION_TO_SYSTEMS; serializationContext.timestamp=timestamp; serializationContext.relaySourceAddress=sender; BooleanQueryResult bqr; RakNet::BitStream bs; unsigned exclusionListIndex=0; for (unsigned i=0; i < rm2->connectionList.Size(); i++) { serializationContext.recipientAddress=rm2->connectionList[i]->GetSystemAddress(); while (exclusionListIndex < exclusionList.Size() && exclusionList[exclusionListIndex] < serializationContext.recipientAddress) exclusionListIndex++; if (exclusionListIndex < exclusionList.Size() && exclusionList[exclusionListIndex]==serializationContext.recipientAddress) { exclusionListIndex++; continue; } // Don't relay serializations if this object should not be visible bqr=QueryVisibility(rm2->connectionList[i]); if (bqr==BQR_NEVER || bqr==BQR_NO) continue; bs.Reset(); if (Serialize(&bs, &serializationContext)==false) continue; rm2->SendSerialize(this,&bs,serializationContext.recipientAddress,serializationContext.timestamp,exclusionList,serializationContext.serializationType); } } void Replica2::BroadcastConstruction(SerializationContext *serializationContext) { RakNet::BitStream bs; SerializationContext defaultContext(BROADCAST_CONSTRUCTION_GENERIC_TO_SYSTEM, UNASSIGNED_SYSTEM_ADDRESS, UNASSIGNED_SYSTEM_ADDRESS,0); SerializationContext *usedContext; if (serializationContext) usedContext=serializationContext; else { usedContext=&defaultContext; if (QueryIsConstructionAuthority()==false) defaultContext.serializationType=SEND_CONSTRUCTION_REQUEST_TO_SERVER; } bool newReference; rm2->Reference(this, &newReference); DataStructures::OrderedList exclusionList; for (unsigned i=0; i < rm2->GetConnectionCount(); i++) { usedContext->recipientAddress=rm2->GetConnectionAtIndex(i)->GetSystemAddress(); if (usedContext->relaySourceAddress==usedContext->recipientAddress) continue; bs.Reset(); if (SerializeConstruction(&bs, usedContext)==false) continue; unsigned char localId; if (QueryIsConstructionAuthority()==false) { clientPtrArray[Replica2::clientSharedID]=this; localId=Replica2::clientSharedID++; } else localId=0; exclusionList.Clear(); for (unsigned j=0; j < rm2->connectionList.Size(); j++) { if (rm2->connectionList[j]->GetSystemAddress()!=usedContext->recipientAddress) exclusionList.InsertAtEnd(rm2->connectionList[j]->GetSystemAddress()); } rm2->SendConstruction(this,&bs,usedContext->recipientAddress,usedContext->timestamp,true,exclusionList, localId, usedContext->serializationType); } // If this is a new object, then after sending construction we should send visibility and serialization if it is always visible or serialized if (newReference) { bool notVisible=false; BooleanQueryResult bqr; bqr=QueryVisibility(0); if (bqr==BQR_ALWAYS) BroadcastVisibility(true); else if (bqr==BQR_NEVER) notVisible=true; if (notVisible==false) BroadcastSerialize(); } } Replica2 * Replica2::ReceiveConstructionReply(SystemAddress sender, BitStream *replicaData, bool constructionAllowed) { (void) replicaData; (void) sender; if (constructionAllowed==false) { delete this; return 0; } return this; } void Replica2::BroadcastDestruction(SerializationContext *serializationContext) { RakNet::BitStream bs; SerializationContext defaultContext(BROADCAST_DESTRUCTION_GENERIC_TO_SYSTEM, UNASSIGNED_SYSTEM_ADDRESS, UNASSIGNED_SYSTEM_ADDRESS, 0); SerializationContext *usedContext; if (serializationContext) usedContext=serializationContext; else usedContext=&defaultContext; DataStructures::OrderedList culledOutput; DataStructures::OrderedList exclusionList; rm2->CullByAndAddToExclusionList(rm2->connectionList, culledOutput, exclusionList); for (unsigned i=0; i < rm2->GetConnectionCount(); i++) { usedContext->recipientAddress=rm2->GetConnectionAtIndex(i)->GetSystemAddress(); if (usedContext->relaySourceAddress==usedContext->recipientAddress) continue; bs.Reset(); if (SerializeDestruction(&bs, usedContext)==false) continue; exclusionList.Clear(); for (unsigned j=0; j < rm2->connectionList.Size(); j++) { if (rm2->connectionList[j]->GetSystemAddress()!=usedContext->recipientAddress) exclusionList.InsertAtEnd(rm2->connectionList[j]->GetSystemAddress()); } rm2->SendDestruction(this,&bs,usedContext->recipientAddress,usedContext->timestamp,true,exclusionList,usedContext->serializationType); } } void Replica2::BroadcastVisibility(bool isVisible, SerializationContext *serializationContext) { RakNet::BitStream bs; SerializationContext defaultContext; SerializationContext *usedContext; if (serializationContext) { usedContext=serializationContext; } else { if (isVisible) defaultContext.serializationType=BROADCAST_VISIBILITY_TRUE_TO_SYSTEM; else defaultContext.serializationType=BROADCAST_VISIBILITY_FALSE_TO_SYSTEM; defaultContext.relaySourceAddress=UNASSIGNED_SYSTEM_ADDRESS; defaultContext.timestamp=0; usedContext=&defaultContext; } if ((QueryVisibility(0)==BQR_ALWAYS && isVisible==false) || (QueryVisibility(0)==BQR_NEVER && isVisible==true)) { // This doesn't make sense RakAssert(0); return; } bool newReference; rm2->Reference(this, &newReference); // If this is a new object, then before sending visibility we should send construction to all systems if (newReference && QueryConstruction(0)==BQR_ALWAYS) { BroadcastConstruction(); } DataStructures::OrderedList exclusionList; for (unsigned i=0; i < rm2->GetConnectionCount(); i++) { usedContext->recipientAddress=rm2->GetConnectionAtIndex(i)->GetSystemAddress(); if (usedContext->relaySourceAddress==usedContext->recipientAddress) continue; bs.Reset(); if (SerializeVisibility(&bs, usedContext)==false) continue; exclusionList.Clear(); for (unsigned j=0; j < rm2->connectionList.Size(); j++) { if (rm2->connectionList[j]->GetSystemAddress()!=usedContext->recipientAddress) exclusionList.InsertAtEnd(rm2->connectionList[j]->GetSystemAddress()); } rm2->SendVisibility(this,&bs,usedContext->recipientAddress,usedContext->timestamp,exclusionList,usedContext->serializationType); } if (newReference && QueryVisibility(0)==BQR_ALWAYS) { BroadcastSerialize(); } } void Replica2::ReceiveDestruction(SystemAddress sender, RakNet::BitStream *serializedObject, SerializationType serializationType, RakNetTime timestamp, DataStructures::OrderedList &exclusionList ) { DeserializeDestruction(serializedObject, serializationType, sender, timestamp); SerializationContext serializationContext; serializationContext.serializationType=RELAY_DESTRUCTION_TO_SYSTEMS; serializationContext.relaySourceAddress=sender; serializationContext.timestamp=0; RakNet::BitStream bs; unsigned exclusionListIndex=0; for (unsigned i=0; i < rm2->connectionList.Size(); i++) { serializationContext.recipientAddress=rm2->connectionList[i]->GetSystemAddress(); while (exclusionListIndex < exclusionList.Size() && exclusionList[exclusionListIndex] < serializationContext.recipientAddress) exclusionListIndex++; if (exclusionListIndex < exclusionList.Size() && exclusionList[exclusionListIndex]==serializationContext.recipientAddress) { exclusionListIndex++; continue; } bs.Reset(); if (SerializeDestruction(&bs, &serializationContext)==false) continue; rm2->SendDestruction(this,&bs,serializationContext.recipientAddress,serializationContext.timestamp,true,exclusionList,serializationContext.serializationType); } DeleteOnReceiveDestruction(sender, serializedObject, serializationType, timestamp, exclusionList); } void Replica2::DeleteOnReceiveDestruction(SystemAddress sender, RakNet::BitStream *serializedObject, SerializationType serializationType, RakNetTime timestamp, DataStructures::OrderedList &exclusionList ) { (void) sender; (void) serializedObject; (void) serializationType; (void) timestamp; (void) exclusionList; delete this; } void Replica2::ReceiveVisibility(SystemAddress sender, RakNet::BitStream *serializedObject, SerializationType serializationType, RakNetTime timestamp, DataStructures::OrderedList &exclusionList) { DeserializeVisibility(serializedObject, serializationType, sender, timestamp); SerializationContext serializationContext; if (serializationType==SEND_VISIBILITY_TRUE_TO_SYSTEM || serializationType==BROADCAST_VISIBILITY_TRUE_TO_SYSTEM) serializationContext.serializationType=RELAY_VISIBILITY_TRUE_TO_SYSTEMS; else if (serializationType==SEND_VISIBILITY_FALSE_TO_SYSTEM || serializationType==BROADCAST_VISIBILITY_FALSE_TO_SYSTEM) serializationContext.serializationType=RELAY_VISIBILITY_FALSE_TO_SYSTEMS; else serializationContext.serializationType=serializationType; serializationContext.timestamp=timestamp; serializationContext.relaySourceAddress=sender; RakNet::BitStream bs; unsigned exclusionListIndex=0; for (unsigned i=0; i < rm2->connectionList.Size(); i++) { serializationContext.recipientAddress=rm2->connectionList[i]->GetSystemAddress(); while (exclusionListIndex < exclusionList.Size() && exclusionList[exclusionListIndex] < serializationContext.recipientAddress) exclusionListIndex++; if (exclusionListIndex < exclusionList.Size() && exclusionList[exclusionListIndex]==serializationContext.recipientAddress) { exclusionListIndex++; continue; } bs.Reset(); if (SerializeVisibility(&bs, &serializationContext)==false) continue; rm2->SendVisibility(this,&bs,serializationContext.recipientAddress,serializationContext.timestamp,exclusionList,serializationContext.serializationType); } } BooleanQueryResult Replica2::QueryConstruction(Connection_RM2 *connection) { (void) connection; return BQR_ALWAYS; } BooleanQueryResult Replica2::QueryVisibility(Connection_RM2 *connection) { (void) connection; return BQR_ALWAYS; } bool Replica2::QueryIsConstructionAuthority(void) const { return rm2->GetRakPeer()->GetNetworkIDManager()->IsNetworkIDAuthority(); } bool Replica2::QueryIsDestructionAuthority(void) const { return rm2->GetRakPeer()->GetNetworkIDManager()->IsNetworkIDAuthority(); } bool Replica2::QueryIsVisibilityAuthority(void) const { return rm2->GetRakPeer()->GetNetworkIDManager()->IsNetworkIDAuthority(); } bool Replica2::QueryIsSerializationAuthority(void) const { return rm2->GetRakPeer()->GetNetworkIDManager()->IsNetworkIDAuthority(); } bool Replica2::AllowRemoteConstruction(SystemAddress sender, RakNet::BitStream *replicaData, SerializationType type, RakNetTime timestamp) { (void) sender; (void) replicaData; (void) type; (void) timestamp; return true; } void Replica2::ForceElapseAllAutoserializeTimers(bool resynchOnly) { ElapseAutoSerializeTimers(99999999, resynchOnly); } void Replica2::ElapseAutoSerializeTimers(RakNetTime timeElapsed, bool resynchOnly) { AutoSerializeEvent* ase; unsigned i; for (i=0; i < autoSerializeTimers.Size(); i++) { ase = autoSerializeTimers[i]; if (ase->remainingCountdown>timeElapsed) { ase->remainingCountdown-=timeElapsed; } else { ase->remainingCountdown=ase->initialCountdown; RakNet::BitStream *lastWrite, *newWrite; if (ase->writeToResult1) { newWrite=&ase->lastAutoSerializeResult1; lastWrite=&ase->lastAutoSerializeResult2; } else { newWrite=&ase->lastAutoSerializeResult2; lastWrite=&ase->lastAutoSerializeResult1; } newWrite->Reset(); OnAutoSerializeTimerElapsed(ase->serializationType,newWrite,lastWrite,ase->remainingCountdown, resynchOnly); ase->writeToResult1=!ase->writeToResult1; } } } void Replica2::OnAutoSerializeTimerElapsed(SerializationType serializationType, RakNet::BitStream *output, RakNet::BitStream *lastOutput, RakNetTime lastAutoSerializeCountdown, bool resynchOnly) { (void) lastAutoSerializeCountdown; SerializationContext context; if (resynchOnly) context.serializationType=AUTOSERIALIZE_RESYNCH_ONLY; else context.serializationType=serializationType; context.relaySourceAddress=UNASSIGNED_SYSTEM_ADDRESS; context.recipientAddress=UNASSIGNED_SYSTEM_ADDRESS; context.timestamp=0; if (Serialize(output, &context)) { if (resynchOnly==false && output->GetNumberOfBitsUsed()>0 && (output->GetNumberOfBitsUsed()!=lastOutput->GetNumberOfBitsUsed() || memcmp(output->GetData(), lastOutput->GetData(), (size_t) output->GetNumberOfBytesUsed())!=0)) { BroadcastAutoSerialize(&context, output); } } } void Replica2::BroadcastAutoSerialize(SerializationContext *serializationContext, RakNet::BitStream *serializedObject) { DataStructures::OrderedList exclusionList; rm2->SendSerialize(this,serializedObject,UNASSIGNED_SYSTEM_ADDRESS, serializationContext->timestamp, exclusionList, BROADCAST_AUTO_SERIALIZE_TO_SYSTEM); } void Replica2::AddAutoSerializeTimer(RakNetTime interval, SerializationType serializationType, RakNetTime countdown ) { if (countdown==(RakNetTime)-1) countdown=interval; if (autoSerializeTimers.Has(serializationType)) { AutoSerializeEvent *ase = autoSerializeTimers.Get(serializationType); if (interval==0) { // Elapse this timer immediately, then go back to initialCountdown ase->remainingCountdown=ase->initialCountdown; RakNet::BitStream *lastWrite, *newWrite; if (ase->writeToResult1) { newWrite=&ase->lastAutoSerializeResult1; lastWrite=&ase->lastAutoSerializeResult2; } else { newWrite=&ase->lastAutoSerializeResult2; lastWrite=&ase->lastAutoSerializeResult1; } newWrite->Reset(); OnAutoSerializeTimerElapsed(serializationType,newWrite,lastWrite,ase->initialCountdown, false); ase->remainingCountdown=ase->initialCountdown; } else { ase->initialCountdown=interval; ase->remainingCountdown=countdown; } } else { AutoSerializeEvent *ase = new AutoSerializeEvent; ase->serializationType=serializationType; ase->initialCountdown=interval; ase->remainingCountdown=countdown; ase->writeToResult1=true; SerializationContext context; context.serializationType=AUTOSERIALIZE_RESYNCH_ONLY; context.relaySourceAddress=UNASSIGNED_SYSTEM_ADDRESS; context.recipientAddress=UNASSIGNED_SYSTEM_ADDRESS; context.timestamp=0; Serialize(&ase->lastAutoSerializeResult2, &context); autoSerializeTimers.Set(serializationType,ase); } } RakNetTime Replica2::GetTimeToNextAutoSerialize(SerializationType serializationType) { if (autoSerializeTimers.Has(serializationType)) { AutoSerializeEvent *ase = autoSerializeTimers.Get(serializationType); return ase->remainingCountdown; } return (RakNetTime)-1; } void Replica2::CancelAutoSerializeTimer(SerializationType serializationType) { unsigned i=0; while (i < autoSerializeTimers.Size()) { if (autoSerializeTimers[i]->serializationType==serializationType) { delete autoSerializeTimers[i]; autoSerializeTimers.RemoveAtIndex(i); } else i++; } } void Replica2::ClearAutoSerializeTimers(void) { unsigned i; for (i=0; i < autoSerializeTimers.Size(); i++) delete autoSerializeTimers[i]; autoSerializeTimers.Clear(); } Connection_RM2::Connection_RM2() { } Connection_RM2::~Connection_RM2() { } void Connection_RM2::SetConstructionByList(DataStructures::OrderedList ¤tVisibility, ReplicaManager2 *replicaManager) { (void) replicaManager; DataStructures::OrderedList exclusiveToCurrentConstructionList, exclusiveToLastConstructionList; CalculateListExclusivity(currentVisibility, lastConstructionList, exclusiveToCurrentConstructionList, exclusiveToLastConstructionList); unsigned i; for (i=0; i < exclusiveToCurrentConstructionList.Size(); i++) { // Construct if (exclusiveToCurrentConstructionList[i]->QueryIsConstructionAuthority()) { exclusiveToCurrentConstructionList[i]->SendConstruction(systemAddress); // lastConstructionList.Insert(exclusiveToCurrentConstructionList[i],exclusiveToCurrentConstructionList[i],true); } } for (i=0; i < exclusiveToLastConstructionList.Size(); i++) { // Destruction if (exclusiveToLastConstructionList[i]->QueryIsDestructionAuthority()) { exclusiveToLastConstructionList[i]->SendDestruction(systemAddress); lastConstructionList.RemoveIfExists(exclusiveToLastConstructionList[i]); lastSerializationList.RemoveIfExists(exclusiveToLastConstructionList[i]); } } } void Connection_RM2::SetVisibilityByList(DataStructures::OrderedList ¤tVisibility, ReplicaManager2 *replicaManager) { (void) replicaManager; DataStructures::OrderedList exclusiveToCurrentSerializationList, exclusiveToLastSerializationList; CalculateListExclusivity(currentVisibility, lastSerializationList, exclusiveToCurrentSerializationList, exclusiveToLastSerializationList); unsigned i; for (i=0; i < exclusiveToCurrentSerializationList.Size(); i++) { // In scope if (exclusiveToCurrentSerializationList[i]->QueryIsVisibilityAuthority()) { exclusiveToCurrentSerializationList[i]->SendVisibility(systemAddress,SEND_VISIBILITY_TRUE_TO_SYSTEM); exclusiveToCurrentSerializationList[i]->SendSerialize(systemAddress); // lastSerializationList.Insert(exclusiveToCurrentSerializationList[i],exclusiveToCurrentSerializationList[i], true); } } for (i=0; i < exclusiveToLastSerializationList.Size(); i++) { // Out of scope if (exclusiveToLastSerializationList[i]->QueryIsVisibilityAuthority()) { exclusiveToLastSerializationList[i]->SendVisibility(systemAddress,SEND_VISIBILITY_FALSE_TO_SYSTEM); lastSerializationList.RemoveIfExists(exclusiveToLastSerializationList[i]); } } } void Connection_RM2::CalculateListExclusivity( const DataStructures::OrderedList &listOne, const DataStructures::OrderedList &listTwo, DataStructures::OrderedList &exclusiveToListOne, DataStructures::OrderedList &exclusiveToListTwo ) const { int res; unsigned listOneIndex=0, listTwoIndex=0; while (listOneIndex0) { exclusiveToListTwo.InsertAtEnd(listTwo[listTwoIndex]); listTwoIndex++; } else { listOneIndex++; listTwoIndex++; } } while (listOneIndex constructedObjects; unsigned i; BooleanQueryResult res; for (i=0; i < replicaManager->variableConstructReplicaOrderedList.Size(); i++) { if (replicaManager->variableConstructReplicaOrderedList[i]->QueryIsConstructionAuthority()) { res = replicaManager->variableConstructReplicaOrderedList[i]->QueryConstruction(this); if (res==BQR_YES) constructedObjects.InsertAtEnd(replicaManager->variableConstructReplicaOrderedList[i]); } } SetConstructionByList(constructedObjects, replicaManager); } void Connection_RM2::SetVisibilityByReplicaQuery(ReplicaManager2 *replicaManager) { DataStructures::OrderedList currentVisibility; unsigned i; BooleanQueryResult res; for (i=0; i < replicaManager->variableSerializeReplicaOrderedList.Size(); i++) { if (replicaManager->variableSerializeReplicaOrderedList[i]->QueryIsVisibilityAuthority()) { res = replicaManager->variableSerializeReplicaOrderedList[i]->QueryVisibility(this); if (res==BQR_YES) currentVisibility.InsertAtEnd(replicaManager->variableSerializeReplicaOrderedList[i]); } } SetVisibilityByList(currentVisibility, replicaManager); } void Connection_RM2::SerializeDownloadStarted(RakNet::BitStream *objectData, ReplicaManager2 *replicaManager, SerializationContext *serializationContext) { (void) objectData; (void) replicaManager; (void) serializationContext; } void Connection_RM2::SerializeDownloadComplete(RakNet::BitStream *objectData, ReplicaManager2 *replicaManager, SerializationContext *serializationContext) { (void) objectData; (void) replicaManager; (void) serializationContext; } void Connection_RM2::DeserializeDownloadStarted(RakNet::BitStream *objectData, SystemAddress sender, ReplicaManager2 *replicaManager, RakNetTime timestamp, SerializationType serializationType){ (void) objectData; (void) sender; (void) replicaManager; (void) timestamp; (void) replicaManager; (void) serializationType; } void Connection_RM2::DeserializeDownloadComplete(RakNet::BitStream *objectData, SystemAddress sender, ReplicaManager2 *replicaManager, RakNetTime timestamp, SerializationType serializationType){ (void) objectData; (void) sender; (void) replicaManager; (void) timestamp; (void) serializationType; } Replica2 * Connection_RM2::ReceiveConstruct(RakNet::BitStream *replicaData, NetworkID networkId, SystemAddress sender, unsigned char localClientId, SerializationType type, ReplicaManager2 *replicaManager, RakNetTime timestamp, DataStructures::OrderedList &exclusionList) { Replica2 *obj=0; bool newReference=false; if (type==SEND_CONSTRUCTION_REPLY_ACCEPTED_TO_CLIENT || type==SEND_CONSTRUCTION_REPLY_DENIED_TO_CLIENT) { obj = Replica2::clientPtrArray[localClientId]; if (obj) { obj = obj->ReceiveConstructionReply(sender, replicaData, type==SEND_CONSTRUCTION_REPLY_ACCEPTED_TO_CLIENT); obj->SetNetworkID(networkId); replicaManager->Reference(obj, &newReference); replicaManager->AddConstructionReference(this,obj); // The object could not be serialized before because it didn't have a NetworkID. So serialize it now. if (obj->QueryIsSerializationAuthority() && (obj->QueryVisibility(this)==BQR_ALWAYS || obj->QueryVisibility(this)==BQR_YES)) { SerializationContext sc; sc.recipientAddress=UNASSIGNED_SYSTEM_ADDRESS; sc.timestamp=timestamp; sc.relaySourceAddress=UNASSIGNED_SYSTEM_ADDRESS; sc.serializationType=BROADCAST_SERIALIZATION_GENERIC_TO_SYSTEM; obj->BroadcastSerialize(&sc); replicaManager->AddVisibilityReference(this,obj); } } } else { // Create locally, relay, send back reply bool collision = replicaManager->GetRakPeer()->GetNetworkIDManager()->GET_OBJECT_FROM_ID( networkId )!=0; obj = Construct(replicaData, sender, type, replicaManager, timestamp, networkId, collision); if (obj) { replicaManager->Reference(obj, &newReference); if (obj->AllowRemoteConstruction(sender, replicaData, type, timestamp)==false) { if (type==SEND_CONSTRUCTION_REQUEST_TO_SERVER) obj->SendConstruction(sender, SEND_CONSTRUCTION_REPLY_DENIED_TO_CLIENT); delete obj; obj=0; } else { if (networkId!=UNASSIGNED_NETWORK_ID) obj->SetNetworkID(networkId); SerializationContext serializationContext; serializationContext.relaySourceAddress=sender; serializationContext.recipientAddress=UNASSIGNED_SYSTEM_ADDRESS; if (type==SEND_CONSTRUCTION_REQUEST_TO_SERVER) serializationContext.serializationType=BROADCAST_CONSTRUCTION_REQUEST_ACCEPTED_TO_SYSTEM; else serializationContext.serializationType=BROADCAST_CONSTRUCTION_GENERIC_TO_SYSTEM; exclusionList.Insert(sender,sender,false); RakNet::BitStream bs; unsigned exclusionListIndex=0; for (unsigned i=0; i < replicaManager->connectionList.Size(); i++) { serializationContext.recipientAddress=replicaManager->connectionList[i]->GetSystemAddress(); while (exclusionListIndex < exclusionList.Size() && exclusionList[exclusionListIndex] < serializationContext.recipientAddress) exclusionListIndex++; if (exclusionListIndex < exclusionList.Size() && exclusionList[exclusionListIndex]==serializationContext.recipientAddress) { exclusionListIndex++; continue; } bs.Reset(); if (obj->SerializeConstruction(&bs, &serializationContext)==false) continue; unsigned char localId; if (obj->QueryIsConstructionAuthority()==false) localId=Replica2::clientSharedID++; else localId=0; replicaManager->SendConstruction(obj,&bs,serializationContext.recipientAddress,serializationContext.timestamp,true,exclusionList, localId, serializationContext.serializationType); } if (type==SEND_CONSTRUCTION_REQUEST_TO_SERVER) { DataStructures::OrderedList emptyList; replicaManager->SendConstruction(obj, &bs, sender, timestamp, true, emptyList, localClientId, SEND_CONSTRUCTION_REPLY_ACCEPTED_TO_CLIENT); } } } } if (obj && newReference && obj->QueryIsSerializationAuthority() && obj->QueryVisibility(this)==BQR_ALWAYS) { SerializationContext sc; sc.recipientAddress=UNASSIGNED_SYSTEM_ADDRESS; sc.timestamp=timestamp; sc.relaySourceAddress=UNASSIGNED_SYSTEM_ADDRESS; sc.serializationType=BROADCAST_SERIALIZATION_GENERIC_TO_SYSTEM; obj->BroadcastSerialize(&sc); } return obj; } void Connection_RM2::SetSystemAddress(SystemAddress sa) { systemAddress=sa; } SystemAddress Connection_RM2::GetSystemAddress(void) const { return systemAddress; } void Connection_RM2::Deref(Replica2* replica) { lastConstructionList.RemoveIfExists(replica); lastSerializationList.RemoveIfExists(replica); } #ifdef _MSC_VER #pragma warning( pop ) #endif