mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-27 16:07:22 +00:00
0545adfac3
Have fun!
1977 lines
67 KiB
C++
1977 lines
67 KiB
C++
#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()<data->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<SystemAddress,SystemAddress>::IMPLEMENT_DEFAULT_COMPARISON();
|
|
}
|
|
ReplicaManager2::~ReplicaManager2()
|
|
{
|
|
}
|
|
void ReplicaManager2::SendConstruction(Replica2 *replica, BitStream *replicaData, SystemAddress recipient, RakNetTime timestamp, bool sendMessage,
|
|
DataStructures::OrderedList<SystemAddress,SystemAddress> &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<SystemAddress, Connection_RM2*,ReplicaManager2::Connection_RM2CompBySystemAddress> 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<SystemAddress,SystemAddress> &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<SystemAddress, Connection_RM2*,ReplicaManager2::Connection_RM2CompBySystemAddress> 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<SystemAddress,SystemAddress> &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<SystemAddress, Connection_RM2*,ReplicaManager2::Connection_RM2CompBySystemAddress> 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<SystemAddress,SystemAddress> &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<SystemAddress, Connection_RM2*,ReplicaManager2::Connection_RM2CompBySystemAddress> 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<SystemAddress, Connection_RM2*,ReplicaManager2::Connection_RM2CompBySystemAddress> &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<SystemAddress, Connection_RM2*,ReplicaManager2::Connection_RM2CompBySystemAddress> &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<SystemAddress,SystemAddress> 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<SystemAddress,SystemAddress> exclusionList;
|
|
ReadExclusionList(&incomingBitstream, exclusionList);
|
|
exclusionList.Insert(sender,sender, false);
|
|
Replica2 * replica = rakPeer->GetNetworkIDManager()->GET_OBJECT_FROM_ID<Replica2*>( 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<SystemAddress,SystemAddress> exclusionList;
|
|
ReadExclusionList(&incomingBitstream, exclusionList);
|
|
exclusionList.Insert(sender,sender, false);
|
|
|
|
Replica2 *replica = rakPeer->GetNetworkIDManager()->GET_OBJECT_FROM_ID<Replica2 *>( 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<SystemAddress,SystemAddress> exclusionList;
|
|
ReadExclusionList(&incomingBitstream, exclusionList);
|
|
exclusionList.Insert(sender,sender, false);
|
|
|
|
Replica2 *replica = rakPeer->GetNetworkIDManager()->GET_OBJECT_FROM_ID<Replica2 *>( 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<SystemAddress,SystemAddress> &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<SystemAddress,SystemAddress> &exclusionList)
|
|
{
|
|
bs->WriteCompressed(exclusionList.Size());
|
|
for (unsigned exclusionListIndex=0; exclusionListIndex < exclusionList.Size(); exclusionListIndex++ )
|
|
bs->Write(exclusionList[exclusionListIndex]);
|
|
}
|
|
|
|
void ReplicaManager2::CullByAndAddToExclusionList(
|
|
DataStructures::OrderedList<SystemAddress, Connection_RM2*,ReplicaManager2::Connection_RM2CompBySystemAddress> &inputList,
|
|
DataStructures::OrderedList<SystemAddress, Connection_RM2*,ReplicaManager2::Connection_RM2CompBySystemAddress> &culledOutput,
|
|
DataStructures::OrderedList<SystemAddress,SystemAddress> &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<SystemAddress,SystemAddress> &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<SerializationType, AutoSerializeEvent*>::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<SystemAddress,SystemAddress> 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<SystemAddress,SystemAddress> 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<SystemAddress,SystemAddress> 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<SystemAddress,SystemAddress> 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<SystemAddress,SystemAddress> 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<SystemAddress,SystemAddress> &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<SystemAddress,SystemAddress> 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<SystemAddress, Connection_RM2*,ReplicaManager2::Connection_RM2CompBySystemAddress> culledOutput;
|
|
DataStructures::OrderedList<SystemAddress,SystemAddress> 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<SystemAddress,SystemAddress> 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<SystemAddress,SystemAddress> &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<SystemAddress,SystemAddress> &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<SystemAddress,SystemAddress> &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<SystemAddress,SystemAddress> 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<Replica2*, Replica2*, ReplicaManager2::Replica2ObjectComp> ¤tVisibility, ReplicaManager2 *replicaManager)
|
|
{
|
|
(void) replicaManager;
|
|
|
|
DataStructures::OrderedList<Replica2*, Replica2*, ReplicaManager2::Replica2ObjectComp> 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<Replica2*, Replica2*, ReplicaManager2::Replica2ObjectComp> ¤tVisibility, ReplicaManager2 *replicaManager)
|
|
{
|
|
(void) replicaManager;
|
|
|
|
DataStructures::OrderedList<Replica2*, Replica2*, ReplicaManager2::Replica2ObjectComp> 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<Replica2*, Replica2*, ReplicaManager2::Replica2ObjectComp> &listOne,
|
|
const DataStructures::OrderedList<Replica2*, Replica2*, ReplicaManager2::Replica2ObjectComp> &listTwo,
|
|
DataStructures::OrderedList<Replica2*, Replica2*, ReplicaManager2::Replica2ObjectComp> &exclusiveToListOne,
|
|
DataStructures::OrderedList<Replica2*, Replica2*, ReplicaManager2::Replica2ObjectComp> &exclusiveToListTwo
|
|
) const
|
|
{
|
|
int res;
|
|
unsigned listOneIndex=0, listTwoIndex=0;
|
|
|
|
while (listOneIndex<listOne.Size() && listTwoIndex < listTwo.Size())
|
|
{
|
|
res = ReplicaManager2::Replica2ObjectComp(listOne[listOneIndex],listTwo[listTwoIndex]);
|
|
if (res<0)
|
|
{
|
|
exclusiveToListOne.InsertAtEnd(listOne[listOneIndex]);
|
|
listOneIndex++;
|
|
}
|
|
else if (res>0)
|
|
{
|
|
exclusiveToListTwo.InsertAtEnd(listTwo[listTwoIndex]);
|
|
listTwoIndex++;
|
|
}
|
|
else
|
|
{
|
|
listOneIndex++;
|
|
listTwoIndex++;
|
|
}
|
|
}
|
|
|
|
while (listOneIndex<listOne.Size())
|
|
{
|
|
exclusiveToListOne.InsertAtEnd(listOne[listOneIndex]);
|
|
listOneIndex++;
|
|
}
|
|
|
|
while (listTwoIndex<listTwo.Size())
|
|
{
|
|
exclusiveToListTwo.InsertAtEnd(listTwo[listTwoIndex]);
|
|
listTwoIndex++;
|
|
}
|
|
}
|
|
void Connection_RM2::SetConstructionByReplicaQuery(ReplicaManager2 *replicaManager)
|
|
{
|
|
DataStructures::OrderedList<Replica2*, Replica2*, ReplicaManager2::Replica2ObjectComp> 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<Replica2*, Replica2*, ReplicaManager2::Replica2ObjectComp> 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<SystemAddress,SystemAddress> &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<NetworkIDObject*>( 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<SystemAddress,SystemAddress> 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
|