mirror of
https://github.com/dashr9230/SA-MP.git
synced 2024-12-22 14:37:29 +08:00
bcdbedc0be
* Add RakNet source files to the VS project
624 lines
20 KiB
C++
624 lines
20 KiB
C++
/// \file
|
|
///
|
|
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
|
|
///
|
|
/// Usage of RakNet is subject to the appropriate license agreement.
|
|
/// Creative Commons Licensees are subject to the
|
|
/// license found at
|
|
/// http://creativecommons.org/licenses/by-nc/2.5/
|
|
/// Single application licensees are subject to the license found at
|
|
/// http://www.rakkarsoft.com/SingleApplicationLicense.html
|
|
/// Custom license users are subject to the terms therein.
|
|
/// GPL license users are subject to the GNU General Public
|
|
/// License as published by the Free
|
|
/// Software Foundation; either version 2 of the License, or (at your
|
|
/// option) any later version.
|
|
|
|
#include "ConnectionGraph.h"
|
|
#include "RakPeerInterface.h"
|
|
#include "PacketEnumerations.h"
|
|
#include "BitStream.h"
|
|
#include "StringCompressor.h"
|
|
#include "GetTime.h"
|
|
#include <string.h>
|
|
#include "RakAssert.h"
|
|
#include "SHA1.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( push )
|
|
#endif
|
|
|
|
extern Packet *AllocPacket(unsigned dataSize);
|
|
|
|
static const int connectionGraphChannel=31;
|
|
|
|
ConnectionGraph::PlayerIdAndGroupId::PlayerIdAndGroupId()
|
|
{
|
|
|
|
}
|
|
ConnectionGraph::PlayerIdAndGroupId::~PlayerIdAndGroupId()
|
|
{
|
|
|
|
}
|
|
ConnectionGraph::PlayerIdAndGroupId::PlayerIdAndGroupId(PlayerID playerId, ConnectionGraphGroupID groupID)
|
|
{
|
|
this->playerId=playerId;
|
|
this->groupId=groupId;
|
|
}
|
|
bool ConnectionGraph::PlayerIdAndGroupId::operator==( const ConnectionGraph::PlayerIdAndGroupId& right ) const
|
|
{
|
|
return playerId==right.playerId;
|
|
}
|
|
bool ConnectionGraph::PlayerIdAndGroupId::operator!=( const ConnectionGraph::PlayerIdAndGroupId& right ) const
|
|
{
|
|
return playerId!=right.playerId;
|
|
}
|
|
bool ConnectionGraph::PlayerIdAndGroupId::operator > ( const ConnectionGraph::PlayerIdAndGroupId& right ) const
|
|
{
|
|
return playerId>right.playerId;
|
|
}
|
|
bool ConnectionGraph::PlayerIdAndGroupId::operator < ( const ConnectionGraph::PlayerIdAndGroupId& right ) const
|
|
{
|
|
return playerId<right.playerId;
|
|
}
|
|
ConnectionGraph::ConnectionGraph()
|
|
{
|
|
pw=0;
|
|
myGroupId=0;
|
|
autoAddNewConnections=true;
|
|
// forceBroadcastTime=0;
|
|
DataStructures::WeightedGraph<ConnectionGraph::PlayerIdAndGroupId, unsigned short, false>::IMPLEMENT_DEFAULT_COMPARISON();
|
|
DataStructures::OrderedList<PlayerID, PlayerID>::IMPLEMENT_DEFAULT_COMPARISON();
|
|
DataStructures::OrderedList<ConnectionGraph::PlayerIdAndGroupId, ConnectionGraph::PlayerIdAndGroupId>::IMPLEMENT_DEFAULT_COMPARISON();
|
|
DataStructures::OrderedList<ConnectionGraphGroupID, ConnectionGraphGroupID>::IMPLEMENT_DEFAULT_COMPARISON();
|
|
|
|
subscribedGroups.Insert(0,0);
|
|
}
|
|
|
|
ConnectionGraph::~ConnectionGraph()
|
|
{
|
|
if (pw)
|
|
delete [] pw;
|
|
}
|
|
|
|
void ConnectionGraph::SetPassword(const char *password)
|
|
{
|
|
if (pw)
|
|
{
|
|
delete [] pw;
|
|
pw=0;
|
|
}
|
|
|
|
if (password && password[0])
|
|
{
|
|
assert(strlen(password)<256);
|
|
pw=new char [strlen(password)+1];
|
|
strcpy(pw, password);
|
|
}
|
|
}
|
|
DataStructures::WeightedGraph<ConnectionGraph::PlayerIdAndGroupId, unsigned short, false> *ConnectionGraph::GetGraph(void)
|
|
{
|
|
return &graph;
|
|
}
|
|
void ConnectionGraph::SetAutoAddNewConnections(bool autoAdd)
|
|
{
|
|
autoAddNewConnections=autoAdd;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( disable : 4100 ) // warning C4100: <variable name> : unreferenced formal parameter
|
|
#endif
|
|
void ConnectionGraph::OnDisconnect(RakPeerInterface *peer)
|
|
{
|
|
graph.Clear();
|
|
participantList.Clear();
|
|
// forceBroadcastTime=0;
|
|
}
|
|
void ConnectionGraph::Update(RakPeerInterface *peer)
|
|
{
|
|
// RakNetTime time = RakNet::GetTime();
|
|
|
|
// If the time is past the next weight update time, then refresh all pings of all connected participants and send these out if substantially different.
|
|
// if (forceBroadcastTime && time > forceBroadcastTime)
|
|
// {
|
|
// DataStructures::OrderedList<PlayerID,PlayerID> none;
|
|
// BroadcastGraphUpdate(none, peer);
|
|
// forceBroadcastTime=0;
|
|
// }
|
|
}
|
|
PluginReceiveResult ConnectionGraph::OnReceive(RakPeerInterface *peer, Packet *packet)
|
|
{
|
|
switch (packet->data[0])
|
|
{
|
|
case ID_NEW_INCOMING_CONNECTION:
|
|
OnNewIncomingConnection(peer, packet);
|
|
return RR_CONTINUE_PROCESSING;
|
|
case ID_CONNECTION_REQUEST_ACCEPTED:
|
|
OnConnectionRequestAccepted(peer, packet);
|
|
return RR_CONTINUE_PROCESSING;
|
|
case ID_CONNECTION_GRAPH_REQUEST:
|
|
OnConnectionGraphRequest(peer, packet);
|
|
return RR_STOP_PROCESSING_AND_DEALLOCATE;
|
|
case ID_CONNECTION_GRAPH_REPLY:
|
|
OnConnectionGraphReply(peer, packet);
|
|
return RR_STOP_PROCESSING_AND_DEALLOCATE;
|
|
case ID_CONNECTION_GRAPH_UPDATE:
|
|
OnConnectionGraphUpdate(peer, packet);
|
|
return RR_STOP_PROCESSING_AND_DEALLOCATE;
|
|
case ID_CONNECTION_GRAPH_NEW_CONNECTION:
|
|
OnNewConnection(peer, packet);
|
|
return RR_STOP_PROCESSING_AND_DEALLOCATE;
|
|
// Remove connection lost
|
|
case ID_CONNECTION_GRAPH_CONNECTION_LOST:
|
|
case ID_CONNECTION_GRAPH_DISCONNECTION_NOTIFICATION:
|
|
if (OnConnectionLost(peer, packet, packet->data[0]))
|
|
{
|
|
if (packet->data[0]==ID_CONNECTION_GRAPH_CONNECTION_LOST)
|
|
packet->data[0]=ID_REMOTE_CONNECTION_LOST;
|
|
else
|
|
packet->data[0]=ID_REMOTE_DISCONNECTION_NOTIFICATION;
|
|
return RR_CONTINUE_PROCESSING; // Return this packet to the user
|
|
}
|
|
return RR_STOP_PROCESSING_AND_DEALLOCATE;
|
|
// Local connection lost
|
|
case ID_CONNECTION_LOST:
|
|
case ID_DISCONNECTION_NOTIFICATION:
|
|
{
|
|
unsigned char packetId;
|
|
// Change toe remote connection lost and relay the message
|
|
if (packet->data[0]==ID_CONNECTION_LOST)
|
|
packetId=ID_CONNECTION_GRAPH_CONNECTION_LOST;
|
|
else
|
|
packetId=ID_CONNECTION_GRAPH_DISCONNECTION_NOTIFICATION;
|
|
HandleDroppedConnection(peer, packet->playerId, packetId);
|
|
}
|
|
}
|
|
|
|
return RR_CONTINUE_PROCESSING;
|
|
}
|
|
void ConnectionGraph::OnCloseConnection(RakPeerInterface *peer, PlayerID playerId)
|
|
{
|
|
HandleDroppedConnection(peer, playerId, ID_CONNECTION_GRAPH_DISCONNECTION_NOTIFICATION);
|
|
}
|
|
|
|
void ConnectionGraph::HandleDroppedConnection(RakPeerInterface *peer, PlayerID playerId, unsigned char packetId)
|
|
{
|
|
assert(peer);
|
|
RemoveParticipant(playerId);
|
|
DataStructures::OrderedList<PlayerID,PlayerID> ignoreList;
|
|
RemoveAndRelayConnection(ignoreList, packetId, playerId, peer->GetExternalID(playerId), peer);
|
|
}
|
|
|
|
void ConnectionGraph::OnNewIncomingConnection(RakPeerInterface *peer, Packet *packet)
|
|
{
|
|
if (autoAddNewConnections==false)
|
|
return;
|
|
|
|
// 0 is the default groupId
|
|
AddNewConnection(peer, packet->playerId, 0);
|
|
}
|
|
void ConnectionGraph::OnConnectionRequestAccepted(RakPeerInterface *peer, Packet *packet)
|
|
{
|
|
if (autoAddNewConnections==false)
|
|
return;
|
|
|
|
RequestConnectionGraph(peer, packet->playerId);
|
|
|
|
// 0 is the default groupId
|
|
AddNewConnection(peer, packet->playerId, 0);
|
|
}
|
|
void ConnectionGraph::SetGroupId(ConnectionGraphGroupID groupId)
|
|
{
|
|
myGroupId=groupId;
|
|
}
|
|
void ConnectionGraph::AddNewConnection(RakPeerInterface *peer, PlayerID playerId, ConnectionGraphGroupID groupId)
|
|
{
|
|
if (autoAddNewConnections==false && subscribedGroups.HasData(groupId)==false)
|
|
return;
|
|
|
|
DataStructures::OrderedList<PlayerID,PlayerID> ignoreList;
|
|
|
|
PlayerIdAndGroupId first, second;
|
|
first.playerId=playerId;
|
|
first.groupId=groupId;
|
|
second.playerId=peer->GetExternalID(playerId);
|
|
second.groupId=myGroupId;
|
|
|
|
AddAndRelayConnection(ignoreList, first, second, (unsigned short)peer->GetAveragePing(playerId), peer);
|
|
}
|
|
void ConnectionGraph::SubscribeToGroup(ConnectionGraphGroupID groupId)
|
|
{
|
|
subscribedGroups.Insert(groupId, groupId);
|
|
}
|
|
void ConnectionGraph::UnsubscribeFromGroup(ConnectionGraphGroupID groupId)
|
|
{
|
|
subscribedGroups.Remove(groupId);
|
|
}
|
|
void ConnectionGraph::RequestConnectionGraph(RakPeerInterface *peer, PlayerID playerId)
|
|
{
|
|
RakNet::BitStream outBitstream;
|
|
outBitstream.Write((unsigned char) ID_CONNECTION_GRAPH_REQUEST);
|
|
stringCompressor->EncodeString(pw,256,&outBitstream);
|
|
peer->Send(&outBitstream, LOW_PRIORITY, RELIABLE_ORDERED, connectionGraphChannel, playerId, false);
|
|
|
|
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
|
|
printf("ID_CONNECTION_GRAPH_REQUEST from %i to %i\n", peer->GetInternalID().port, playerId.port);
|
|
#endif
|
|
}
|
|
void ConnectionGraph::OnConnectionGraphRequest(RakPeerInterface *peer, Packet *packet)
|
|
{
|
|
char password[256];
|
|
RakNet::BitStream inBitstream(packet->data, packet->length, false);
|
|
inBitstream.IgnoreBits(8);
|
|
stringCompressor->DecodeString(password,256,&inBitstream);
|
|
if (pw && pw[0] && strcmp(pw, password)!=0)
|
|
return;
|
|
|
|
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
|
|
printf("ID_CONNECTION_GRAPH_REPLY ");
|
|
#endif
|
|
|
|
RakNet::BitStream outBitstream;
|
|
outBitstream.Write((unsigned char) ID_CONNECTION_GRAPH_REPLY);
|
|
stringCompressor->EncodeString(pw,256,&outBitstream);
|
|
SerializeWeightedGraph(&outBitstream, graph);
|
|
peer->Send(&outBitstream, LOW_PRIORITY, RELIABLE_ORDERED, connectionGraphChannel, packet->playerId, false);
|
|
|
|
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
|
|
printf("from %i to %i\n", peer->GetInternalID().port, packet->playerId.port);
|
|
#endif
|
|
|
|
// Add packet->playerId to the participant list if it is not already there
|
|
AddParticipant(packet->playerId);
|
|
}
|
|
void ConnectionGraph::OnConnectionGraphReply(RakPeerInterface *peer, Packet *packet)
|
|
{
|
|
unsigned char password[256];
|
|
RakNet::BitStream inBitstream(packet->data, packet->length, false);
|
|
inBitstream.IgnoreBits(8);
|
|
stringCompressor->DecodeString((char*)password,256,&inBitstream);
|
|
if (pw && pw[0] && strcmp(pw, (const char*)password)!=0)
|
|
return;
|
|
|
|
// Serialize the weighted graph and send it to them
|
|
RakNet::BitStream outBitstream;
|
|
outBitstream.Write((unsigned char) ID_CONNECTION_GRAPH_UPDATE);
|
|
|
|
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
|
|
printf("ID_CONNECTION_GRAPH_UPDATE ");
|
|
#endif
|
|
|
|
// Send our current graph to the sender
|
|
SerializeWeightedGraph(&outBitstream, graph);
|
|
|
|
|
|
// Write the systems that have processed this graph so we don't resend to these systems
|
|
outBitstream.Write((unsigned short) 1);
|
|
outBitstream.Write(peer->GetExternalID(packet->playerId));
|
|
|
|
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
|
|
printf("from %i to %i\n", peer->GetInternalID().port, packet->playerId.port);
|
|
#endif
|
|
|
|
peer->Send(&outBitstream, LOW_PRIORITY, RELIABLE_ORDERED, connectionGraphChannel, packet->playerId, false);
|
|
|
|
// Add packet->playerId to the participant list if it is not already there
|
|
AddParticipant(packet->playerId);
|
|
|
|
if (DeserializeWeightedGraph(&inBitstream, peer)==false)
|
|
return;
|
|
|
|
// Forward the updated graph to all current participants
|
|
DataStructures::OrderedList<PlayerID,PlayerID> ignoreList;
|
|
ignoreList.Insert(packet->playerId,packet->playerId);
|
|
BroadcastGraphUpdate(ignoreList, peer);
|
|
}
|
|
void ConnectionGraph::OnConnectionGraphUpdate(RakPeerInterface *peer, Packet *packet)
|
|
{
|
|
// Only accept from participants
|
|
if (participantList.HasData(packet->playerId)==false)
|
|
return;
|
|
|
|
RakNet::BitStream inBitstream(packet->data, packet->length, false);
|
|
inBitstream.IgnoreBits(8);
|
|
|
|
if (DeserializeWeightedGraph(&inBitstream, peer)==false)
|
|
return;
|
|
|
|
DataStructures::OrderedList<PlayerID,PlayerID> ignoreList;
|
|
DeserializeIgnoreList(ignoreList, &inBitstream);
|
|
|
|
// Forward the updated graph to all participants.
|
|
if (ignoreList.HasData(packet->playerId)==false)
|
|
ignoreList.Insert(packet->playerId,packet->playerId);
|
|
BroadcastGraphUpdate(ignoreList, peer);
|
|
}
|
|
void ConnectionGraph::OnNewConnection(RakPeerInterface *peer, Packet *packet)
|
|
{
|
|
// Only accept from participants
|
|
if (participantList.HasData(packet->playerId)==false)
|
|
return;
|
|
|
|
PlayerIdAndGroupId node1, node2;
|
|
unsigned short ping;
|
|
RakNet::BitStream inBitstream(packet->data, packet->length, false);
|
|
inBitstream.IgnoreBits(8);
|
|
inBitstream.Read(node1.playerId);
|
|
inBitstream.Read(node1.groupId);
|
|
inBitstream.Read(node2.playerId);
|
|
inBitstream.Read(node2.groupId);
|
|
if (inBitstream.Read(ping)==false)
|
|
return;
|
|
DataStructures::OrderedList<PlayerID,PlayerID> ignoreList;
|
|
DeserializeIgnoreList(ignoreList, &inBitstream);
|
|
if (ignoreList.HasData(packet->playerId)==false)
|
|
ignoreList.Insert(packet->playerId,packet->playerId);
|
|
AddAndRelayConnection(ignoreList, node1, node2, ping, peer);
|
|
}
|
|
bool ConnectionGraph::OnConnectionLost(RakPeerInterface *peer, Packet *packet, unsigned char packetId)
|
|
{
|
|
// Only accept from participants
|
|
if (participantList.HasData(packet->playerId)==false)
|
|
return false;
|
|
|
|
PlayerID node1, node2;
|
|
RakNet::BitStream inBitstream(packet->data, packet->length, false);
|
|
inBitstream.IgnoreBits(8);
|
|
// This is correct - group IDs are not written for removal, only addition.
|
|
inBitstream.Read(node1);
|
|
if (inBitstream.Read(node2)==false)
|
|
return false;
|
|
DataStructures::OrderedList<PlayerID,PlayerID> ignoreList;
|
|
DeserializeIgnoreList(ignoreList, &inBitstream);
|
|
if (ignoreList.HasData(packet->playerId)==false)
|
|
ignoreList.Insert(packet->playerId, packet->playerId);
|
|
|
|
return RemoveAndRelayConnection(ignoreList, packetId, node1, node2, peer);
|
|
}
|
|
bool ConnectionGraph::DeserializeIgnoreList(DataStructures::OrderedList<PlayerID,PlayerID> &ignoreList, RakNet::BitStream *inBitstream )
|
|
{
|
|
unsigned short count;
|
|
PlayerID temp;
|
|
unsigned i;
|
|
inBitstream->Read(count);
|
|
for (i=0; i < count; i++)
|
|
{
|
|
if (inBitstream->Read(temp)==false)
|
|
{
|
|
assert(0);
|
|
return false;
|
|
}
|
|
ignoreList.Insert(temp,temp);
|
|
}
|
|
return true;
|
|
}
|
|
void ConnectionGraph::SerializeWeightedGraph(RakNet::BitStream *out, const DataStructures::WeightedGraph<ConnectionGraph::PlayerIdAndGroupId, unsigned short, false> &g) const
|
|
{
|
|
unsigned nodeIndex, connectionIndex;
|
|
unsigned countOffset, oldOffset;
|
|
unsigned short count;
|
|
PlayerIdAndGroupId node1, node2;
|
|
unsigned short weight;
|
|
out->WriteCompressed(g.GetNodeCount());
|
|
for (nodeIndex=0; nodeIndex < g.GetNodeCount(); nodeIndex++)
|
|
{
|
|
// Write the node
|
|
node1=g.GetNodeAtIndex(nodeIndex);
|
|
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
|
|
printf("[%i] ", node1.playerId.port);
|
|
#endif
|
|
out->Write(node1.playerId);
|
|
out->Write(node1.groupId);
|
|
|
|
// Write the adjacency list count
|
|
count=(unsigned short)g.GetConnectionCount(nodeIndex);
|
|
out->AlignWriteToByteBoundary();
|
|
countOffset=out->GetWriteOffset();
|
|
out->Write(count);
|
|
count=0;
|
|
for (connectionIndex=0; connectionIndex < g.GetConnectionCount(nodeIndex); connectionIndex++)
|
|
{
|
|
g.GetConnectionAtIndex(nodeIndex, connectionIndex, node2, weight);
|
|
// For efficiencies' sake, only serialize the upper half of the connection pairs
|
|
if (node2 > node1)
|
|
{
|
|
count++;
|
|
out->Write(node2.playerId);
|
|
out->Write(node2.groupId);
|
|
out->Write(weight);
|
|
|
|
#ifdef _CONNECTION_GRAPH_DEBUG_PRINT
|
|
printf("(%i) ", node2.playerId.port);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Go back and change how many elements were written
|
|
oldOffset=out->GetWriteOffset();
|
|
out->SetWriteOffset(countOffset);
|
|
out->Write(count);
|
|
out->SetWriteOffset(oldOffset);
|
|
}
|
|
}
|
|
bool ConnectionGraph::DeserializeWeightedGraph(RakNet::BitStream *inBitstream, RakPeerInterface *peer)
|
|
{
|
|
unsigned nodeCount, nodeIndex, connectionIndex;
|
|
unsigned short connectionCount;
|
|
PlayerIdAndGroupId node, connection;
|
|
bool anyConnectionsNew=false;
|
|
unsigned short weight;
|
|
inBitstream->ReadCompressed(nodeCount);
|
|
for (nodeIndex=0; nodeIndex < nodeCount; nodeIndex++)
|
|
{
|
|
inBitstream->Read(node.playerId);
|
|
inBitstream->Read(node.groupId);
|
|
|
|
inBitstream->AlignReadToByteBoundary();
|
|
if (inBitstream->Read(connectionCount)==false)
|
|
{
|
|
assert(0);
|
|
return false;
|
|
}
|
|
for (connectionIndex=0; connectionIndex < connectionCount; connectionIndex++)
|
|
{
|
|
inBitstream->Read(connection.playerId);
|
|
inBitstream->Read(connection.groupId);
|
|
if (inBitstream->Read(weight)==false)
|
|
{
|
|
assert(0);
|
|
return false;
|
|
}
|
|
if (subscribedGroups.HasData(connection.groupId)==false ||
|
|
subscribedGroups.HasData(node.groupId)==false)
|
|
continue;
|
|
RakAssert(node.playerId!=UNASSIGNED_PLAYER_ID);
|
|
RakAssert(connection.playerId!=UNASSIGNED_PLAYER_ID);
|
|
if (IsNewRemoteConnection(node,connection,peer))
|
|
NotifyUserOfRemoteConnection(node,connection,weight,peer);
|
|
|
|
if (graph.HasConnection(node,connection)==false)
|
|
anyConnectionsNew=true;
|
|
|
|
graph.AddConnection(node,connection,weight);
|
|
}
|
|
}
|
|
return anyConnectionsNew;
|
|
}
|
|
void ConnectionGraph::RemoveParticipant(PlayerID playerId)
|
|
{
|
|
unsigned index;
|
|
bool objectExists;
|
|
index=participantList.GetIndexFromKey(playerId, &objectExists);
|
|
if (objectExists)
|
|
participantList.RemoveAtIndex(index);
|
|
}
|
|
|
|
void ConnectionGraph::AddParticipant(PlayerID playerId)
|
|
{
|
|
if (participantList.HasData(playerId)==false)
|
|
participantList.Insert(playerId,playerId);
|
|
}
|
|
|
|
void ConnectionGraph::AddAndRelayConnection(DataStructures::OrderedList<PlayerID,PlayerID> &ignoreList, const PlayerIdAndGroupId &conn1, const PlayerIdAndGroupId &conn2, unsigned short ping, RakPeerInterface *peer)
|
|
{
|
|
if (graph.HasConnection(conn1,conn2))
|
|
return;
|
|
|
|
if (ping==65535)
|
|
ping=0;
|
|
assert(conn1.playerId!=UNASSIGNED_PLAYER_ID);
|
|
assert(conn2.playerId!=UNASSIGNED_PLAYER_ID);
|
|
|
|
graph.AddConnection(conn1,conn2,ping);
|
|
|
|
if (IsNewRemoteConnection(conn1,conn2,peer))
|
|
{
|
|
NotifyUserOfRemoteConnection(conn1,conn2,ping,peer);
|
|
return;
|
|
}
|
|
|
|
RakNet::BitStream outBitstream;
|
|
outBitstream.Write((unsigned char) ID_CONNECTION_GRAPH_NEW_CONNECTION);
|
|
outBitstream.Write(conn1.playerId);
|
|
outBitstream.Write(conn1.groupId);
|
|
outBitstream.Write(conn2.playerId);
|
|
outBitstream.Write(conn2.groupId);
|
|
outBitstream.Write(ping);
|
|
if (ignoreList.HasData(conn2.playerId)==false)
|
|
ignoreList.Insert(conn2.playerId,conn2.playerId);
|
|
if (ignoreList.HasData(conn1.playerId)==false)
|
|
ignoreList.Insert(conn1.playerId,conn1.playerId);
|
|
SerializeIgnoreListAndBroadcast(&outBitstream, ignoreList, peer);
|
|
}
|
|
bool ConnectionGraph::RemoveAndRelayConnection(DataStructures::OrderedList<PlayerID,PlayerID> &ignoreList, unsigned char packetId, const PlayerID node1, const PlayerID node2, RakPeerInterface *peer)
|
|
{
|
|
PlayerIdAndGroupId n1, n2;
|
|
n1.playerId=node1;
|
|
n2.playerId=node2;
|
|
if (graph.HasConnection(n1,n2)==false)
|
|
return false;
|
|
graph.RemoveConnection(n1,n2);
|
|
|
|
RakNet::BitStream outBitstream;
|
|
outBitstream.Write(packetId);
|
|
outBitstream.Write(node1);
|
|
outBitstream.Write(node2);
|
|
|
|
if (ignoreList.HasData(node1)==false)
|
|
ignoreList.Insert(node1,node1);
|
|
if (ignoreList.HasData(node2)==false)
|
|
ignoreList.Insert(node2,node2);
|
|
SerializeIgnoreListAndBroadcast(&outBitstream, ignoreList, peer);
|
|
|
|
return true;
|
|
}
|
|
|
|
void ConnectionGraph::BroadcastGraphUpdate(DataStructures::OrderedList<PlayerID,PlayerID> &ignoreList, RakPeerInterface *peer)
|
|
{
|
|
RakNet::BitStream outBitstream;
|
|
outBitstream.Write((unsigned char) ID_CONNECTION_GRAPH_UPDATE);
|
|
SerializeWeightedGraph(&outBitstream, graph);
|
|
SerializeIgnoreListAndBroadcast(&outBitstream, ignoreList, peer);
|
|
}
|
|
void ConnectionGraph::SerializeIgnoreListAndBroadcast(RakNet::BitStream *outBitstream, DataStructures::OrderedList<PlayerID,PlayerID> &ignoreList, RakPeerInterface *peer)
|
|
{
|
|
DataStructures::List<PlayerID> sendList;
|
|
unsigned i;
|
|
for (i=0; i < participantList.Size(); i++)
|
|
{
|
|
if (ignoreList.HasData(participantList[i])==false)
|
|
sendList.Insert(participantList[i]);
|
|
}
|
|
if (sendList.Size()==0)
|
|
return;
|
|
|
|
PlayerID self = peer->GetExternalID(sendList[0]);
|
|
if (ignoreList.HasData(self)==false)
|
|
ignoreList.Insert(self,self);
|
|
outBitstream->Write((unsigned short) (ignoreList.Size()+sendList.Size()));
|
|
for (i=0; i < ignoreList.Size(); i++)
|
|
outBitstream->Write(ignoreList[i]);
|
|
for (i=0; i < sendList.Size(); i++)
|
|
outBitstream->Write(sendList[i]);
|
|
|
|
for (i=0; i < sendList.Size(); i++)
|
|
{
|
|
peer->Send(outBitstream, LOW_PRIORITY, RELIABLE_ORDERED, connectionGraphChannel, sendList[i], false);
|
|
}
|
|
}
|
|
bool ConnectionGraph::IsNewRemoteConnection(const PlayerIdAndGroupId &conn1, const PlayerIdAndGroupId &conn2,RakPeerInterface *peer)
|
|
{
|
|
if (graph.HasConnection(conn1,conn2)==false &&
|
|
subscribedGroups.HasData(conn1.groupId) &&
|
|
subscribedGroups.HasData(conn2.groupId) &&
|
|
(peer->GetIndexFromPlayerID(conn1.playerId)==-1 || peer->GetIndexFromPlayerID(conn2.playerId)==-1))
|
|
{
|
|
PlayerID externalId1, externalId2;
|
|
externalId1=peer->GetExternalID(conn1.playerId);
|
|
externalId2=peer->GetExternalID(conn2.playerId);
|
|
return (externalId1!=conn1.playerId && externalId1!=conn2.playerId &&
|
|
externalId2!=conn1.playerId && externalId2!=conn2.playerId);
|
|
}
|
|
return false;
|
|
}
|
|
void ConnectionGraph::NotifyUserOfRemoteConnection(const PlayerIdAndGroupId &conn1, const PlayerIdAndGroupId &conn2,unsigned short ping, RakPeerInterface *peer)
|
|
{
|
|
// Create a packet to tell the user of this event
|
|
static const int length=sizeof(MessageID) + (sizeof(PlayerID) + sizeof(ConnectionGraphGroupID)) * 2 + sizeof(unsigned short);
|
|
Packet *p = AllocPacket(length);
|
|
RakNet::BitStream b(p->data, length, false);
|
|
p->bitSize=p->length*8;
|
|
b.SetWriteOffset(0);
|
|
b.Write((MessageID)ID_REMOTE_NEW_INCOMING_CONNECTION);
|
|
b.Write(conn1.playerId);
|
|
b.Write(conn1.groupId);
|
|
b.Write(conn2.playerId);
|
|
b.Write(conn2.groupId);
|
|
b.Write(ping);
|
|
peer->PushBackPacket(p, false);
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( pop )
|
|
#endif
|