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

310 lines
8.5 KiB
C++

/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_ConnectionGraph2==1
#include "ConnectionGraph2.h"
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include "BitStream.h"
using namespace RakNet;
STATIC_FACTORY_DEFINITIONS(ConnectionGraph2,ConnectionGraph2)
int RakNet::ConnectionGraph2::RemoteSystemComp( const RakNetGUID &key, RemoteSystem * const &data )
{
if (key < data->guid)
return -1;
if (key > data->guid)
return 1;
return 0;
}
int RakNet::ConnectionGraph2::SystemAddressAndGuidComp( const SystemAddressAndGuid &key, const SystemAddressAndGuid &data )
{
if (key.guid<data.guid)
return -1;
if (key.guid>data.guid)
return 1;
return 0;
}
ConnectionGraph2::ConnectionGraph2()
{
autoProcessNewConnections=true;
}
ConnectionGraph2::~ConnectionGraph2()
{
}
bool ConnectionGraph2::GetConnectionListForRemoteSystem(RakNetGUID remoteSystemGuid, SystemAddress *saOut, RakNetGUID *guidOut, unsigned int *outLength)
{
if ((saOut==0 && guidOut==0) || outLength==0 || *outLength==0 || remoteSystemGuid==UNASSIGNED_RAKNET_GUID)
{
*outLength=0;
return false;
}
bool objectExists;
unsigned int idx = remoteSystems.GetIndexFromKey(remoteSystemGuid, &objectExists);
if (objectExists==false)
{
*outLength=0;
return false;
}
unsigned int idx2;
if (remoteSystems[idx]->remoteConnections.Size() < *outLength)
*outLength=remoteSystems[idx]->remoteConnections.Size();
for (idx2=0; idx2 < *outLength; idx2++)
{
if (guidOut)
guidOut[idx2]=remoteSystems[idx]->remoteConnections[idx2].guid;
if (saOut)
saOut[idx2]=remoteSystems[idx]->remoteConnections[idx2].systemAddress;
}
return true;
}
bool ConnectionGraph2::ConnectionExists(RakNetGUID g1, RakNetGUID g2)
{
if (g1==g2)
return false;
bool objectExists;
unsigned int idx = remoteSystems.GetIndexFromKey(g1, &objectExists);
if (objectExists==false)
{
return false;
}
SystemAddressAndGuid sag;
sag.guid=g2;
return remoteSystems[idx]->remoteConnections.HasData(sag);
}
uint16_t ConnectionGraph2::GetPingBetweenSystems(RakNetGUID g1, RakNetGUID g2) const
{
if (g1==g2)
return 0;
if (g1==rakPeerInterface->GetMyGUID())
return (uint16_t) rakPeerInterface->GetAveragePing(g2);
if (g2==rakPeerInterface->GetMyGUID())
return (uint16_t) rakPeerInterface->GetAveragePing(g1);
bool objectExists;
unsigned int idx = remoteSystems.GetIndexFromKey(g1, &objectExists);
if (objectExists==false)
{
return (uint16_t) -1;
}
SystemAddressAndGuid sag;
sag.guid=g2;
unsigned int idx2 = remoteSystems[idx]->remoteConnections.GetIndexFromKey(sag, &objectExists);
if (objectExists==false)
{
return (uint16_t) -1;
}
return remoteSystems[idx]->remoteConnections[idx2].sendersPingToThatSystem;
}
/// Returns the system with the lowest total ping among all its connections. This can be used as the 'best host' for a peer to peer session
RakNetGUID ConnectionGraph2::GetLowestAveragePingSystem(void) const
{
float lowestPing=-1.0;
unsigned int lowestPingIdx=(unsigned int) -1;
float thisAvePing=0.0f;
unsigned int idx, idx2;
int ap, count=0;
for (idx=0; idx<remoteSystems.Size(); idx++)
{
thisAvePing=0.0f;
ap = rakPeerInterface->GetAveragePing(remoteSystems[idx]->guid);
if (ap!=-1)
{
thisAvePing+=(float) ap;
count++;
}
}
if (count>0)
{
lowestPing=thisAvePing/count;
}
for (idx=0; idx<remoteSystems.Size(); idx++)
{
thisAvePing=0.0f;
count=0;
RemoteSystem *remoteSystem = remoteSystems[idx];
for (idx2=0; idx2 < remoteSystem->remoteConnections.Size(); idx2++)
{
ap=remoteSystem->remoteConnections[idx2].sendersPingToThatSystem;
if (ap!=-1)
{
thisAvePing+=(float) ap;
count++;
}
}
if (count>0 && (lowestPing==-1.0f || thisAvePing/count < lowestPing))
{
lowestPing=thisAvePing/count;
lowestPingIdx=idx;
}
}
if (lowestPingIdx==(unsigned int) -1)
return rakPeerInterface->GetMyGUID();
return remoteSystems[lowestPingIdx]->guid;
}
void ConnectionGraph2::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
{
// Send notice to all existing connections
RakNet::BitStream bs;
if (lostConnectionReason==LCR_CONNECTION_LOST)
bs.Write((MessageID)ID_REMOTE_CONNECTION_LOST);
else
bs.Write((MessageID)ID_REMOTE_DISCONNECTION_NOTIFICATION);
bs.Write(systemAddress);
bs.Write(rakNetGUID);
SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,true);
bool objectExists;
unsigned int idx = remoteSystems.GetIndexFromKey(rakNetGUID, &objectExists);
if (objectExists)
{
RakNet::OP_DELETE(remoteSystems[idx],_FILE_AND_LINE_);
remoteSystems.RemoveAtIndex(idx);
}
}
void ConnectionGraph2::SetAutoProcessNewConnections(bool b)
{
autoProcessNewConnections=b;
}
bool ConnectionGraph2::GetAutoProcessNewConnections(void) const
{
return autoProcessNewConnections;
}
void ConnectionGraph2::AddParticipant(const SystemAddress &systemAddress, RakNetGUID rakNetGUID)
{
// Relay the new connection to other systems.
RakNet::BitStream bs;
bs.Write((MessageID)ID_REMOTE_NEW_INCOMING_CONNECTION);
bs.Write((uint32_t)1);
bs.Write(systemAddress);
bs.Write(rakNetGUID);
bs.WriteCasted<uint16_t>(rakPeerInterface->GetAveragePing(rakNetGUID));
SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,true);
// Send everyone to the new guy
DataStructures::List<SystemAddress> addresses;
DataStructures::List<RakNetGUID> guids;
rakPeerInterface->GetSystemList(addresses, guids);
bs.Reset();
bs.Write((MessageID)ID_REMOTE_NEW_INCOMING_CONNECTION);
BitSize_t writeOffset = bs.GetWriteOffset();
bs.Write((uint32_t) addresses.Size());
unsigned int i;
uint32_t count=0;
for (i=0; i < addresses.Size(); i++)
{
if (addresses[i]==systemAddress)
continue;
bs.Write(addresses[i]);
bs.Write(guids[i]);
bs.WriteCasted<uint16_t>(rakPeerInterface->GetAveragePing(guids[i]));
count++;
}
if (count>0)
{
BitSize_t writeOffset2 = bs.GetWriteOffset();
bs.SetWriteOffset(writeOffset);
bs.Write(count);
bs.SetWriteOffset(writeOffset2);
SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,false);
}
bool objectExists;
unsigned int ii = remoteSystems.GetIndexFromKey(rakNetGUID, &objectExists);
if (objectExists==false)
{
RemoteSystem* remoteSystem = RakNet::OP_NEW<RemoteSystem>(_FILE_AND_LINE_);
remoteSystem->guid=rakNetGUID;
remoteSystems.InsertAtIndex(remoteSystem,ii,_FILE_AND_LINE_);
}
}
void ConnectionGraph2::GetParticipantList(DataStructures::OrderedList<RakNetGUID, RakNetGUID> &participantList)
{
participantList.Clear(true, _FILE_AND_LINE_);
unsigned int i;
for (i=0; i < remoteSystems.Size(); i++)
participantList.InsertAtEnd(remoteSystems[i]->guid, _FILE_AND_LINE_);
}
void ConnectionGraph2::OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
{
(void) isIncoming;
if (autoProcessNewConnections)
AddParticipant(systemAddress, rakNetGUID);
}
PluginReceiveResult ConnectionGraph2::OnReceive(Packet *packet)
{
if (packet->data[0]==ID_REMOTE_CONNECTION_LOST || packet->data[0]==ID_REMOTE_DISCONNECTION_NOTIFICATION)
{
bool objectExists;
unsigned idx = remoteSystems.GetIndexFromKey(packet->guid, &objectExists);
if (objectExists)
{
RakNet::BitStream bs(packet->data,packet->length,false);
bs.IgnoreBytes(1);
SystemAddressAndGuid saag;
bs.Read(saag.systemAddress);
bs.Read(saag.guid);
unsigned long idx2 = remoteSystems[idx]->remoteConnections.GetIndexFromKey(saag, &objectExists);
if (objectExists)
remoteSystems[idx]->remoteConnections.RemoveAtIndex(idx2);
}
}
else if (packet->data[0]==ID_REMOTE_NEW_INCOMING_CONNECTION)
{
bool objectExists;
unsigned idx = remoteSystems.GetIndexFromKey(packet->guid, &objectExists);
if (objectExists)
{
uint32_t numAddresses;
RakNet::BitStream bs(packet->data,packet->length,false);
bs.IgnoreBytes(1);
bs.Read(numAddresses);
for (unsigned int idx2=0; idx2 < numAddresses; idx2++)
{
SystemAddressAndGuid saag;
bs.Read(saag.systemAddress);
bs.Read(saag.guid);
bs.Read(saag.sendersPingToThatSystem);
bool objectExists;
unsigned int ii = remoteSystems[idx]->remoteConnections.GetIndexFromKey(saag, &objectExists);
if (objectExists==false)
remoteSystems[idx]->remoteConnections.InsertAtIndex(saag,ii,_FILE_AND_LINE_);
}
}
}
return RR_CONTINUE_PROCESSING;
}
#endif // _RAKNET_SUPPORT_*