SA-MP/raknet/Router.cpp
RD42 bcdbedc0be Revert RakNet source files back to the original v2.518 state
* Add RakNet source files to the VS project
2024-08-16 23:33:48 +08:00

336 lines
10 KiB
C++

#include "Router.h"
#include "BitStream.h"
#include "RakPeerInterface.h"
#include "PacketEnumerations.h"
#include "RakAssert.h"
//#define _DO_PRINTF
#ifdef _DO_PRINTF
#include <stdio.h>
#endif
#ifdef _MSC_VER
#pragma warning( push )
#endif
Router::Router()
{
graph=0;
restrictByType=false;
rakPeer=0;
DataStructures::OrderedList<unsigned char,unsigned char>::IMPLEMENT_DEFAULT_COMPARISON();
}
Router::~Router()
{
}
void Router::SetRestrictRoutingByType(bool restrict)
{
restrictByType=restrict;
}
void Router::AddAllowedType(unsigned char messageId)
{
if (allowedTypes.HasData(messageId)==false)
allowedTypes.Insert(messageId,messageId);
}
void Router::RemoveAllowedType(unsigned char messageId)
{
if (allowedTypes.HasData(messageId)==true)
allowedTypes.Remove(messageId);
}
void Router::SetConnectionGraph(DataStructures::WeightedGraph<ConnectionGraph::PlayerIdAndGroupId, unsigned short, false> *connectionGraph)
{
graph=connectionGraph;
}
bool Router::Send( const char *data, unsigned bitLength, PacketPriority priority, PacketReliability reliability, char orderingChannel, PlayerID playerId )
{
if (playerId!=UNASSIGNED_PLAYER_ID)
{
RakAssert(data);
RakAssert(bitLength);
// Prevent recursion in case a routing call itself calls the router
if (bitLength>=8 && data[0]==ID_ROUTE_AND_MULTICAST)
return false;
SystemAddressList systemAddressList;
systemAddressList.AddSystem(playerId);
return Send((char*)data, bitLength, priority, reliability, orderingChannel, &systemAddressList);
}
return false;
}
bool Router::Send( char *data, unsigned bitLength, PacketPriority priority, PacketReliability reliability, char orderingChannel, SystemAddressList *recipients )
{
RakAssert(data);
RakAssert(bitLength);
if (recipients->GetList()->Size()==0)
return false;
if (bitLength==0)
return false;
DataStructures::Tree<ConnectionGraph::PlayerIdAndGroupId> tree;
PlayerID root;
root = rakPeer->GetExternalID(rakPeer->GetPlayerIDFromIndex(0));
if (root==UNASSIGNED_PLAYER_ID)
return false;
DataStructures::List<ConnectionGraph::PlayerIdAndGroupId> recipientList;
unsigned i;
for (i=0; i < recipients->Size(); i++)
recipientList.Insert(ConnectionGraph::PlayerIdAndGroupId(recipients->GetList()->operator [](i),0));
if (graph->GetSpanningTree(tree, &recipientList, ConnectionGraph::PlayerIdAndGroupId(root,0), 65535)==false)
return false;
RakNet::BitStream out;
// Write timestamp first, if the user had a timestamp
if (data[0]==ID_TIMESTAMP && bitLength >= BYTES_TO_BITS(sizeof(MessageID)+sizeof(RakNetTime)))
{
out.Write(data, sizeof(MessageID)+sizeof(RakNetTime));
data+=sizeof(MessageID)+sizeof(RakNetTime);
bitLength-=BYTES_TO_BITS(sizeof(MessageID)+sizeof(RakNetTime));
}
SendTree(priority, reliability, orderingChannel, &tree, data, bitLength, &out, recipients);
return true;
}
void Router::SendTree(PacketPriority priority, PacketReliability reliability, char orderingChannel, DataStructures::Tree<ConnectionGraph::PlayerIdAndGroupId> *tree, const char *data, unsigned bitLength, RakNet::BitStream *out, SystemAddressList *recipients)
{
unsigned outputOffset;
// Write routing identifer
out->Write((unsigned char)ID_ROUTE_AND_MULTICAST);
// Write the send parameters
out->WriteCompressed((unsigned char)priority);
out->WriteCompressed((unsigned char)reliability);
out->WriteCompressed((unsigned char)orderingChannel);
// Write the user payload length
out->Write((unsigned int)bitLength);
// out->PrintBits();
// payload->PrintBits();
out->AlignWriteToByteBoundary();
// payload->AlignReadToByteBoundary();
// out->Write(payload, payload->GetNumberOfUnreadBits());
// out->PrintBits();
if ((bitLength % 8)==0)
out->Write(data, BITS_TO_BYTES(bitLength));
else
out->WriteBits((const unsigned char*)data, bitLength, false);
// Save where to start writing per-system data
outputOffset=out->GetWriteOffset();
// Write every child of the root of the tree (PlayerID, isRecipient, branch)
unsigned i;
for (i=0; i < tree->children.Size(); i++)
{
// Start writing at the per-system data byte
out->SetWriteOffset(outputOffset);
// Write our external IP to designate the sender
out->Write(rakPeer->GetExternalID(tree->children[i]->data.playerId));
// Serialize the tree
SerializePreorder(tree->children[i], out, recipients);
// Send to the first hop
#ifdef _DO_PRINTF
printf("%i sending to %i\n", rakPeer->GetExternalID(tree->children[i]->data).port, tree->children[i]->data.port);
#endif
rakPeer->Send(out, priority, reliability, orderingChannel, tree->children[i]->data.playerId, false);
}
}
#ifdef _MSC_VER
#pragma warning( disable : 4100 ) // warning C4100: <variable name> : unreferenced formal parameter
#endif
PluginReceiveResult Router::OnReceive(RakPeerInterface *peer, Packet *packet)
{
if (packet->data[0]==ID_ROUTE_AND_MULTICAST ||
(packet->length>5 && packet->data[0]==ID_TIMESTAMP && packet->data[5]==ID_ROUTE_AND_MULTICAST))
{
#ifdef _DO_PRINTF
printf("%i got routed message from %i\n", peer->GetExternalID(packet->playerId).port, packet->playerId.port);
#endif
RakNetTime timestamp;
PacketPriority priority;
PacketReliability reliability;
unsigned char orderingChannel;
PlayerID originalSender;
RakNet::BitStream out;
unsigned outStartingOffset;
unsigned int payloadBitLength;
unsigned payloadWriteByteOffset;
RakNet::BitStream incomingBitstream(packet->data, packet->length, false);
incomingBitstream.IgnoreBits(8);
if (packet->data[0]==ID_TIMESTAMP)
{
incomingBitstream.Read(timestamp);
out.Write((unsigned char)ID_TIMESTAMP);
out.Write(timestamp);
}
// Read the send parameters
unsigned char c;
incomingBitstream.ReadCompressed(c);
priority=(PacketPriority)c;
incomingBitstream.ReadCompressed(c);
reliability=(PacketReliability)c;
incomingBitstream.ReadCompressed(orderingChannel);
incomingBitstream.Read(payloadBitLength);
out.Write((unsigned char) ID_ROUTE_AND_MULTICAST);
out.WriteCompressed((unsigned char)priority);
out.WriteCompressed((unsigned char)reliability);
out.WriteCompressed((unsigned char)orderingChannel);
out.Write(payloadBitLength);
out.AlignWriteToByteBoundary();
incomingBitstream.AlignReadToByteBoundary();
payloadWriteByteOffset=BITS_TO_BYTES(out.GetWriteOffset());
out.Write(&incomingBitstream, payloadBitLength); // This write also does a read on incomingBitStream
if (restrictByType)
{
RakNet::BitStream t(out.GetData()+payloadWriteByteOffset, sizeof(unsigned char), false);
unsigned char messageID;
t.Read(messageID);
if (allowedTypes.HasData(messageID)==false)
return RR_STOP_PROCESSING_AND_DEALLOCATE; // Don't route restricted types
}
incomingBitstream.Read(originalSender);
out.Write(originalSender);
outStartingOffset=out.GetWriteOffset();
// Deserialize the root
bool hasData;
PlayerID recipient;
unsigned short numberOfChildren;
incomingBitstream.Read(hasData);
incomingBitstream.Read(recipient); // This should be our own address
if (incomingBitstream.ReadCompressed(numberOfChildren)==false)
{
#ifdef _DEBUG
assert(0);
#endif
return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
unsigned childIndex;
bool childHasData;
PlayerID childRecipient;
unsigned short childNumberOfChildren;
PlayerID immediateRecipient;
immediateRecipient=UNASSIGNED_PLAYER_ID;
int pendingNodeCount=0;
for (childIndex=0; childIndex < numberOfChildren; childIndex++)
{
while (pendingNodeCount!=-1)
{
// Copy out the serialized subtree for this child
incomingBitstream.Read(childHasData);
incomingBitstream.Read(childRecipient);
if (!incomingBitstream.ReadCompressed(childNumberOfChildren))
return RR_STOP_PROCESSING_AND_DEALLOCATE;
if (immediateRecipient==UNASSIGNED_PLAYER_ID)
{
immediateRecipient=childRecipient;
}
pendingNodeCount+=childNumberOfChildren-1;
out.Write(childHasData);
out.Write(childRecipient);
out.WriteCompressed(childNumberOfChildren);
}
#ifdef _DO_PRINTF
printf("%i routing to %i\n", peer->GetExternalID(packet->playerId).port, immediateRecipient.port);
#endif
// Send what we got so far
rakPeer->Send(&out, priority, reliability, orderingChannel, immediateRecipient, false);
// Restart writing the per recipient data
out.SetWriteOffset(outStartingOffset);
// Reread the top level node
immediateRecipient=UNASSIGNED_PLAYER_ID;
pendingNodeCount=0;
}
// Write the user payload to the packet struct if this is a destination and change the sender and return true
if (hasData)
{
#ifdef _DO_PRINTF
printf("%i returning payload to user\n", peer->GetExternalID(packet->playerId).port);
#endif
if (packet->data[0]==ID_TIMESTAMP )
{
memcpy( packet->data + sizeof(RakNetTime)+sizeof(unsigned char), out.GetData()+payloadWriteByteOffset, BITS_TO_BYTES(payloadBitLength) );
packet->bitSize=sizeof(RakNetTime)+sizeof(unsigned char)+payloadBitLength;
}
else
{
memcpy( packet->data, out.GetData()+payloadWriteByteOffset, BITS_TO_BYTES(payloadBitLength) );
packet->bitSize=payloadBitLength;
}
packet->length=BITS_TO_BYTES(packet->bitSize);
packet->playerIndex=65535;
packet->playerId=originalSender;
return RR_CONTINUE_PROCESSING;
}
// Absorb
return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
return RR_CONTINUE_PROCESSING;
}
void Router::OnAttach(RakPeerInterface *peer)
{
rakPeer=peer;
peer->SetRouterInterface(this);
}
void Router::OnDetach(RakPeerInterface *peer)
{
peer->RemoveRouterInterface(this);
}
#ifdef _MSC_VER
#pragma warning( disable : 4100 ) // warning C4100: <variable name> : unreferenced formal parameter
#endif
void Router::OnDisconnect(RakPeerInterface *peer)
{
}
#ifdef _MSC_VER
#pragma warning( disable : 4100 ) // warning C4100: <variable name> : unreferenced formal parameter
#endif
void Router::Update(RakPeerInterface *peer)
{
}
#ifdef _MSC_VER
#pragma warning( disable : 4100 ) // warning C4100: <variable name> : unreferenced formal parameter
#endif
void Router::OnCloseConnection(RakPeerInterface *peer, PlayerID playerId)
{
}
void Router::SerializePreorder(DataStructures::Tree<ConnectionGraph::PlayerIdAndGroupId> *tree, RakNet::BitStream *out, SystemAddressList *recipients) const
{
unsigned i;
out->Write((bool) (recipients->GetList()->GetIndexOf(tree->data.playerId)!=MAX_UNSIGNED_LONG));
out->Write(tree->data.playerId);
out->WriteCompressed((unsigned short) tree->children.Size());
for (i=0; i < tree->children.Size(); i++)
SerializePreorder(tree->children[i], out, recipients);
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif