Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2039 lines
54 KiB
C++
2039 lines
54 KiB
C++
//===========================================================================//
|
|
// File: network.cc //
|
|
// Project: MUNGA Brick: Network Manager //
|
|
// Contents: Implementation details for network class //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 11/01/94 JMA Initial coding. //
|
|
// 03/02/95 GAC Added comments and functionality to support real net //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
|
|
// PROPRIETARY AND CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "AdeptHeaders.hpp"
|
|
|
|
#include "Network.hpp"
|
|
#include "Connection.hpp"
|
|
#include "Application.hpp"
|
|
#include "EntityManager.hpp"
|
|
#include "NetStatCollector.hpp"
|
|
#include <MissionLang\Resource.h>
|
|
#include <gameos\Network.hpp>
|
|
|
|
#include <dplay.h> // jcem for mission replay
|
|
#include <gameos\mreplay.h> // jcem for mission replay
|
|
|
|
#ifdef _DEBUG
|
|
int g_nLocalPacketLevel = 0;
|
|
#endif // _DEBUG
|
|
|
|
//#############################################################################
|
|
//########################### InBox ##############################
|
|
//#############################################################################
|
|
|
|
InBox::ClassData*
|
|
InBox::DefaultData = NULL;
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
InBox::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
InBoxClassID,
|
|
"Adept::InBox",
|
|
Receiver::DefaultData,
|
|
0,
|
|
NULL
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
InBox::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
InBox::InBox(
|
|
ClassData *class_data,
|
|
int box_ID
|
|
):
|
|
Receiver(class_data)
|
|
{
|
|
boxID = box_ID;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
InBox::~InBox()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
InBox::TestInstance()
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
InBox::ReceiveNetworkPacket(
|
|
const _NetPacket* packet,
|
|
const Message *message
|
|
)
|
|
{
|
|
Check_Object(message);
|
|
Dispatch(message);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
InBox::Send(
|
|
const Message *message,
|
|
Connection *connection
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
Check_Object(connection);
|
|
|
|
if (connection == Connection::Local)
|
|
{
|
|
ReceiveNetworkPacket(NULL, message);
|
|
}
|
|
else
|
|
{
|
|
SendIt(connection->GetNetworkAddress(), message);
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
InBox::SendIt(
|
|
DWORD destination,
|
|
const Message *message
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
|
|
STOP(("NO LONGER SUPPORTED"));
|
|
|
|
// use history if you need the old functionality.
|
|
|
|
}
|
|
|
|
//#############################################################################
|
|
|
|
|
|
QuedPacket::QuedPacket(int connection, int type, MemoryStream *packet_data):
|
|
Plug(DefaultData)
|
|
{
|
|
connectionID = connection;
|
|
messageType = type;
|
|
|
|
packetData = NULL;
|
|
|
|
if (packet_data != NULL)
|
|
{
|
|
int size = packet_data->GetBufferBytesUsed();
|
|
BYTE *mem_buffer = new BYTE[size];
|
|
|
|
packetData = new MemoryStream(mem_buffer,size);
|
|
packetData->WriteBytes(packet_data->GetPointer(), size);
|
|
packetData->Rewind();
|
|
}
|
|
}
|
|
|
|
//#############################################################################
|
|
|
|
QuedPacket::~QuedPacket()
|
|
{
|
|
|
|
if (packetData != NULL)
|
|
{
|
|
packetData->Rewind();
|
|
|
|
BYTE *mem_buffer = (BYTE*)packetData->GetPointer();
|
|
delete[] mem_buffer;
|
|
|
|
delete packetData;
|
|
}
|
|
}
|
|
|
|
|
|
//#############################################################################
|
|
//########################## Network ##############################
|
|
//#############################################################################
|
|
|
|
Network::ClassData*
|
|
Network::DefaultData = NULL;
|
|
|
|
|
|
DWORD
|
|
Network::BroadcastAddress;
|
|
DWORD
|
|
Network::ServerAddress;
|
|
DWORD
|
|
Network::MyAddress;
|
|
bool Network::bUseNewUI = false;
|
|
|
|
int
|
|
Network::DefaultPacketSize = 512;
|
|
int
|
|
Network::HashMessageTypeFlags[255];
|
|
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Network::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
NetworkClassID,
|
|
"Adept::Network",
|
|
InBox::DefaultData,
|
|
0, NULL
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
Connection::Hermit = new Connection(0, -1, "HERMIT");
|
|
Register_Object(Connection::Hermit);
|
|
|
|
|
|
for (int i = 0; i < 255; ++i)
|
|
{
|
|
HashMessageTypeFlags[i] = NoHash;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Network::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
|
|
// the hermit lives and breathes at all times
|
|
Unregister_Object(Connection::Hermit);
|
|
delete Connection::Hermit;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Network::Network():
|
|
InBox(DefaultData, NetworkBoxID),
|
|
localPacketQue(NULL)
|
|
{
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// See if we are a networked game. If not, we need to create the local
|
|
// connection ourself and set the server connection to Null
|
|
//---------------------------------------------------------------------
|
|
//
|
|
|
|
|
|
// Start up the stat collectors...
|
|
//#ifdef _DEBUG // jcem - mapClientCRC will be changed if serverKey changed...
|
|
serverKey = 1000;
|
|
//#else // !_DEBUG
|
|
// serverKey = Random::GetInt();
|
|
//#endif // _DEBUG
|
|
|
|
netStatCollector = new NetStatCollector[NetStatCount];
|
|
|
|
|
|
netStatCollector[IncomingPacketCountStat].SetName("I-PPS");
|
|
netStatCollector[OutgoingPacketCountStat].SetName("O-PPS");
|
|
|
|
netStatCollector[IncomingTotalPacketSizeStat].SetName("I-Total");
|
|
netStatCollector[OutgoingTotalPacketSizeStat].SetName("O-Total");
|
|
|
|
netStatCollector[IncomingProtocolHeaderBitSizeStat].SetName("I-ProtHdr");
|
|
netStatCollector[OutgoingProtocolHeaderBitSizeStat].SetName("O-ProtHdr");
|
|
|
|
netStatCollector[IncomingHeaderBitSizeStat].SetName("I-GameHdr");
|
|
netStatCollector[OutgoingHeaderBitSizeStat].SetName("O-GameHdr");
|
|
netStatCollector[IncomingSystemMessageBitSizeStat].SetName("I-System");
|
|
netStatCollector[OutgoingSystemMessageBitSizeStat].SetName("O-System");
|
|
netStatCollector[IncomingWeaponMessageBitSizeStat].SetName("I-Weapon");
|
|
netStatCollector[OutgoingWeaponMessageBitSizeStat].SetName("O-Weapon");
|
|
|
|
netStatCollector[OutgoingMechMovementBitSizeStat].SetName("O-MechMvt");
|
|
netStatCollector[IncomingMechMovementBitSizeStat].SetName("I-MechMvt");
|
|
|
|
netStatCollector[MovementConfirmationBitSizeStat].SetName("Mvt-Conf");
|
|
|
|
netStatCollector[MechInternalBitSizeStat].SetName("O-MechInt");
|
|
netStatCollector[BuildingDamageBitSizeStat].SetName("O-Building");
|
|
netStatCollector[VehicleBitSizeStat].SetName("O-Vehicle");
|
|
|
|
|
|
|
|
for (int i = 0; i < Maximum_Connection_Numbers; ++i)
|
|
{
|
|
|
|
packetsSent[i] = 0;
|
|
packetsDropped[i] = 0;
|
|
|
|
|
|
m_bigMessageCollectors[i].m_bigMessageSize = 0;
|
|
m_bigMessageCollectors[i].m_bigMessageType = -1;
|
|
m_bigMessageCollectors[i].m_bigPacketCRC = 0;
|
|
m_bigMessageCollectors[i].m_bigMessage = NULL;
|
|
}
|
|
|
|
Check_Object(EntityManager::GetInstance());
|
|
EntityManager::GetInstance()->Reset();
|
|
|
|
|
|
|
|
for (int j = 0; j < Maximum_Connection_Numbers; ++j)
|
|
{
|
|
activeConnections[j] = NULL;
|
|
}
|
|
|
|
activeConnections[0] = Connection::Hermit;
|
|
|
|
if (!reinterpret_cast<DWORD>(gos_NetInformation(gos_Networking, 0)))
|
|
{
|
|
startedGosNet = false;
|
|
|
|
amIServer = true;
|
|
|
|
EntityManager::GetInstance()->StartServer();
|
|
|
|
|
|
Verify(!Connection::Local);
|
|
Verify(!Connection::Server);
|
|
Connection::Local = new Connection(1, 0, "");
|
|
|
|
Register_Object(Connection::Local);
|
|
Connection::Server = Connection::Local;
|
|
|
|
activeConnections[1] = Connection::Local;
|
|
|
|
Application::GetInstance()->ConnectClient(1, Connection::Local);
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
startedGosNet = true;
|
|
|
|
//
|
|
//----------------------------------
|
|
// Get the other network information
|
|
//----------------------------------
|
|
//
|
|
DWORD player_count =
|
|
reinterpret_cast<DWORD>(gos_NetInformation(gos_NumberOfPlayers, 0));
|
|
MyAddress =
|
|
reinterpret_cast<DWORD>(gos_NetInformation(gos_MyID, 0));
|
|
BroadcastAddress =
|
|
reinterpret_cast<DWORD>(gos_NetInformation(gos_AllID, 0));
|
|
ServerAddress =
|
|
reinterpret_cast<DWORD>(gos_NetInformation(gos_ServerID, 0));
|
|
|
|
//
|
|
//--------------------------------------------------
|
|
// Create a new connection for each connected player
|
|
//--------------------------------------------------
|
|
//
|
|
|
|
Verify(!Connection::Local);
|
|
Verify(!Connection::Server);
|
|
nextConnectionID = 2;
|
|
currentPlayerCount = 0;
|
|
|
|
if (reinterpret_cast<DWORD>(gos_NetInformation(gos_AmITheServer, 0)))
|
|
{
|
|
BYTE i;
|
|
for (i=1; i<=player_count; ++i)
|
|
{
|
|
|
|
//
|
|
//-------------------------------------------------------
|
|
// Get the player name and figure out the connection type
|
|
//-------------------------------------------------------
|
|
//
|
|
const char* player_name =
|
|
reinterpret_cast<const char*>(gos_NetInformation(gos_PlayerName, i-1));
|
|
DWORD net_id =
|
|
reinterpret_cast<DWORD>(gos_NetInformation(gos_PlayerID, i-1));
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// Build the connection, then stick it into the table and pointers
|
|
//----------------------------------------------------------------
|
|
//
|
|
Connection *connection = new Connection(i, net_id, player_name);
|
|
Register_Object(connection);
|
|
|
|
//SPEW(("jerryeds", "GAIN CONNECTION: - %x : %d %d", connection, connection->GetID(), connection->GetNetworkAddress()));
|
|
|
|
if (net_id == MyAddress)
|
|
{
|
|
Connection::Local = connection;
|
|
Connection::Server = connection;
|
|
connection->connectionID = 1;
|
|
}
|
|
else
|
|
{
|
|
|
|
Verify(nextConnectionID >= 0);
|
|
Verify(nextConnectionID < Maximum_Connection_Numbers);
|
|
connection->connectionID = (BYTE)nextConnectionID;
|
|
Network::GetInstance()->AddConnectionToStats(connection->GetID());
|
|
++nextConnectionID;
|
|
}
|
|
|
|
|
|
activeConnections[i] = connection;
|
|
|
|
Application::GetInstance()->ConnectClient(connection->connectionID, connection);
|
|
|
|
|
|
}
|
|
|
|
|
|
currentPlayerCount = player_count;
|
|
nextConnectionID = i;
|
|
Verify(nextConnectionID < Maximum_Connection_Numbers);
|
|
|
|
Check_Object(Connection::Local);
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// If we are the server, we need to send a message to everybody else to tell
|
|
// them our connection order
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
|
|
if (reinterpret_cast<DWORD>(gos_NetInformation(gos_AmITheServer, 0)))
|
|
{
|
|
EntityManager::GetInstance()->StartServer();
|
|
|
|
amIServer = true;
|
|
Connection::Server = Connection::Local;
|
|
SendConnections();
|
|
}
|
|
else
|
|
{
|
|
|
|
EntityManager::GetInstance()->StartClient();
|
|
|
|
|
|
amIServer = false;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
const char *Network::GetGameName()
|
|
{
|
|
Check_Object(this);
|
|
Verify(amIServer);
|
|
|
|
|
|
const char* game_name = reinterpret_cast<const char*>(gos_NetInformation(gos_NameOfGame, NULL));
|
|
|
|
return game_name;
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void Network::AdvanceStats()
|
|
{
|
|
if (Application::GetInstance()->applicationMode != Application::EditorMode)
|
|
{
|
|
|
|
for (int i = 0; i < NetStatCount; ++i)
|
|
{
|
|
netStatCollector[i].AdvanceTime();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void Network::AddConnectionToStats(int id)
|
|
{
|
|
for (int i = 0; i < NetStatCount; ++i)
|
|
{
|
|
netStatCollector[i].AddConnection(id);
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void Network::RemoveConnectionToStats(int id)
|
|
{
|
|
for (int i = 0; i < NetStatCount; ++i)
|
|
{
|
|
netStatCollector[i].RemoveConnection(id);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Network::~Network()
|
|
{
|
|
|
|
EntityManager::GetInstance()->StopServer();
|
|
EntityManager::GetInstance()->StopClient();
|
|
|
|
|
|
if (startedGosNet)
|
|
{
|
|
gos_NetEndGame();
|
|
}
|
|
|
|
Verify(Connection::Hermit);
|
|
Connection::Hermit->DeleteChildren();
|
|
|
|
for (unsigned i=1; i<Maximum_Connection_Numbers; ++i)
|
|
{
|
|
m_bigMessageCollectors[i].m_bigMessageSize = 0;
|
|
m_bigMessageCollectors[i].m_bigMessageType = -1;
|
|
m_bigMessageCollectors[i].m_bigPacketCRC = 0;
|
|
|
|
if (m_bigMessageCollectors[i].m_bigMessage != NULL)
|
|
{
|
|
Check_Object(m_bigMessageCollectors[i].m_bigMessage);
|
|
delete m_bigMessageCollectors[i].m_bigMessage;
|
|
m_bigMessageCollectors[i].m_bigMessage = NULL;
|
|
}
|
|
|
|
if (activeConnections[i] != NULL)
|
|
{
|
|
Application::GetInstance()->DisconnectClient(i, Connection::Local);
|
|
Connection *connection = activeConnections[i];
|
|
Unregister_Object(connection);
|
|
delete connection;
|
|
connection = NULL;
|
|
}
|
|
}
|
|
Connection::Local = NULL;
|
|
Connection::Server = NULL;
|
|
//Connection::Hermit = NULL; // this guy stays!
|
|
|
|
delete[] netStatCollector;
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void Network::Recycle(void)
|
|
{
|
|
|
|
|
|
|
|
Connection::Hermit->DeleteChildren();
|
|
|
|
// this is bad news.
|
|
// we should only delete packet ques when we leave the server
|
|
// that happens when the network is destructed
|
|
|
|
for (unsigned i=1; i<Maximum_Connection_Numbers; ++i)
|
|
{
|
|
#if 0
|
|
m_bigMessageCollectors[i].m_bigMessageSize = 0;
|
|
m_bigMessageCollectors[i].m_bigMessageType = -1;
|
|
m_bigMessageCollectors[i].m_bigPacketCRC = 0;
|
|
|
|
if (m_bigMessageCollectors[i].m_bigMessage != NULL)
|
|
{
|
|
Check_Object(m_bigMessageCollectors[i].m_bigMessage);
|
|
delete m_bigMessageCollectors[i].m_bigMessage;
|
|
m_bigMessageCollectors[i].m_bigMessage = NULL;
|
|
}
|
|
#endif
|
|
if (activeConnections[i] != NULL)
|
|
{
|
|
Connection *connection = activeConnections[i];
|
|
connection->DeleteChildren();
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Network::TestInstance()
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Network::ReceiveNetworkPacket(
|
|
const _NetPacket* packet,
|
|
const Message *message
|
|
)
|
|
{
|
|
Check_Pointer(packet);
|
|
|
|
//
|
|
//----------------------------------
|
|
// Find out who this message is from
|
|
//----------------------------------
|
|
//
|
|
Connection *connection = FindConnection(packet->FromID);
|
|
Check_Object(connection);
|
|
|
|
|
|
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// If we are not already starting a file transfer for this connection, look
|
|
// to find the type of thing to do
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
if (!connection->dataBuffer)
|
|
{
|
|
Verify(!connection->bytesToTransfer);
|
|
DataTransferMessage *data =
|
|
Cast_Pointer(DataTransferMessage*, packet->pData);
|
|
|
|
//
|
|
//-------------------------------------------------
|
|
// Otherwise, we must be requesting a file transfer
|
|
//-------------------------------------------------
|
|
//
|
|
|
|
connection->bytesToTransfer = data->dataLength;
|
|
connection->dataBuffer = new BYTE[data->dataLength];
|
|
Register_Pointer(connection->dataBuffer);
|
|
connection->dataPointer = connection->dataBuffer;
|
|
connection->dataTransferBox = data->inBox;
|
|
|
|
}
|
|
|
|
//
|
|
//------------------------------------------
|
|
// Otherwise, process the next chunk of data
|
|
//------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
Verify(connection->dataPointer >= connection->dataBuffer);
|
|
size_t len = packet->Length;
|
|
|
|
Verify(connection->bytesToTransfer >= len);
|
|
Mem_Copy(
|
|
connection->dataPointer,
|
|
packet->pData,
|
|
len,
|
|
connection->bytesToTransfer
|
|
);
|
|
connection->bytesToTransfer -= len;
|
|
connection->dataPointer += len;
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// If we are done with the transfer, send the completed message to the
|
|
// desired inbox
|
|
//--------------------------------------------------------------------
|
|
//
|
|
if (!connection->bytesToTransfer)
|
|
{
|
|
_NetPacket spoof(*packet);
|
|
spoof.Type = connection->dataTransferBox;
|
|
spoof.pData = connection->dataBuffer;
|
|
InBox *box = FindInBox(static_cast<BoxID>(spoof.Type));
|
|
Check_Object(box);
|
|
box->ReceiveNetworkPacket(&spoof, static_cast<Message*>(spoof.pData));
|
|
Unregister_Pointer(connection->dataBuffer);
|
|
delete[] connection->dataBuffer;
|
|
connection->dataBuffer = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//define HUNT_PACKET_CORUPTION
|
|
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
bool
|
|
Network::RoutePacket()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//---------------------------------
|
|
// See if we have a packet to route
|
|
//---------------------------------
|
|
//
|
|
NetPacket *packet = gos_NetGetMessage();
|
|
if (!packet)
|
|
{
|
|
//SPEW(("jerryeds", "%f : NO PACKET", gos_GetElapsedTime()));
|
|
return false;
|
|
}
|
|
//SPEW(("jerryeds", "%f : PACKET", gos_GetElapsedTime()));
|
|
|
|
|
|
#if defined(LAB_ONLY)
|
|
MWGameInfo::g_lastPacketType[MWGameInfo::nextPacketHistoryIndex] = packet->Type;
|
|
MWGameInfo::g_lastPacketSize[MWGameInfo::nextPacketHistoryIndex] = packet->Length;
|
|
MWGameInfo::g_lastPacketInbound[MWGameInfo::nextPacketHistoryIndex] = true;
|
|
MWGameInfo::g_lastPacketTime[MWGameInfo::nextPacketHistoryIndex] = gos_GetElapsedTime();
|
|
|
|
{
|
|
Check_Object(Application::GetInstance());
|
|
Connection *connection = FindConnection(packet->FromID);
|
|
|
|
if (connection != NULL)
|
|
{
|
|
MWGameInfo::g_lastPacketAddress[MWGameInfo::nextPacketHistoryIndex] = connection->GetID();
|
|
}
|
|
}
|
|
|
|
++MWGameInfo::nextPacketHistoryIndex;
|
|
|
|
if (MWGameInfo::nextPacketHistoryIndex >= MWGameInfo::Packet_History_Count)
|
|
MWGameInfo::nextPacketHistoryIndex = 0;
|
|
|
|
#endif
|
|
|
|
|
|
Check_Object(Application::GetInstance());
|
|
Connection *connection = FindConnection(packet->FromID);
|
|
|
|
if (connection != NULL)
|
|
{
|
|
|
|
|
|
Network::GetInstance()->netStatCollector[Network::IncomingPacketCountStat].AddToStatistic(connection->GetID(),1);
|
|
Network::GetInstance()->netStatCollector[Network::IncomingProtocolHeaderBitSizeStat].AddToStatistic(connection->GetID(),42*8);
|
|
Network::GetInstance()->netStatCollector[Network::IncomingTotalPacketSizeStat].AddToStatistic(connection->GetID(),packet->Length*8);
|
|
|
|
|
|
Adept::g_lastPacketFromPlayer[connection->GetID()] = gos_GetElapsedTime();
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------
|
|
// We have a packet, so route it to the appropiate place
|
|
//----------------------------------------------------------
|
|
//
|
|
|
|
if (packet->Type >= GameMessageStartID && packet->Type < GameMessageStopID)
|
|
{
|
|
Check_Object(Application::GetInstance());
|
|
Connection *connection = FindConnection(packet->FromID);
|
|
|
|
// some of our children types do not require a connection
|
|
// and instead create them. so we do that testing lower
|
|
int id = -1;
|
|
|
|
if (connection != NULL)
|
|
{
|
|
Check_Object(connection);
|
|
id = connection->GetID();
|
|
}
|
|
|
|
if (packet->Length > 0)
|
|
{
|
|
MemoryStream message(packet->pData, packet->Length);
|
|
ReceiveMessage(id, packet->Type, &message);
|
|
}
|
|
else if (packet->pData != NULL)
|
|
{
|
|
MemoryStream message(packet->pData, 256);
|
|
ReceiveMessage(id, packet->Type, &message);
|
|
}
|
|
else
|
|
{
|
|
if(packet->pData != NULL)
|
|
STOP(("EMPTY PACKET HAS DATA"));
|
|
ReceiveMessage(id, packet->Type, NULL);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
switch (packet->Type)
|
|
{
|
|
case BigPacketStartBufferBoxID:
|
|
{
|
|
if (connection == NULL)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
Verify(m_bigMessageCollectors[connection->GetID()].m_bigMessage == NULL);
|
|
|
|
Check_Pointer(packet->pData);
|
|
Verify(packet->Length > 0);
|
|
MemoryStream message(packet->pData, packet->Length);
|
|
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessageType = 0;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessageSize = 0;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigPacketCRC = 0;
|
|
message.ReadBytes(&m_bigMessageCollectors[connection->GetID()].m_bigMessageType, 1);
|
|
message.ReadBytes(&m_bigMessageCollectors[connection->GetID()].m_bigMessageSize, 4);
|
|
message.ReadBytes(&m_bigMessageCollectors[connection->GetID()].m_bigPacketCRC, 4);
|
|
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessage = new DynamicMemoryStream(m_bigMessageCollectors[connection->GetID()].m_bigMessageSize);
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessage->WriteBytes(message.GetPointer(), message.GetBytesRemaining());
|
|
|
|
message.Rewind();
|
|
|
|
#ifdef HUNT_PACKET_CORUPTION
|
|
DWORD crc = 0;
|
|
for (int i = 0; i < message.GetSize(); ++i)
|
|
{
|
|
BYTE data;
|
|
message.ReadBytes(&data, 1);
|
|
crc += data;
|
|
}
|
|
message.Rewind();
|
|
SPEW(("jerryeds", "START CRC %x", crc));
|
|
#endif
|
|
|
|
Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection->GetID(),3);
|
|
}
|
|
return true;
|
|
|
|
case BigPacketPartBufferBoxID:
|
|
{
|
|
Check_Object(m_bigMessageCollectors[connection->GetID()].m_bigMessage);
|
|
|
|
Check_Object(Application::GetInstance());
|
|
Connection *connection = FindConnection(packet->FromID);
|
|
|
|
if (connection == NULL)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
Check_Pointer(packet->pData);
|
|
Verify(packet->Length > 0);
|
|
|
|
MemoryStream message(packet->pData, packet->Length);
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessage->WriteBytes(message.GetPointer(), message.GetBytesRemaining());
|
|
|
|
|
|
message.Rewind();
|
|
#ifdef HUNT_PACKET_CORUPTION
|
|
DWORD crc = 0;
|
|
for (int i = 0; i < message.GetSize(); ++i)
|
|
{
|
|
BYTE data;
|
|
message.ReadBytes(&data, 1);
|
|
crc += data;
|
|
}
|
|
message.Rewind();
|
|
SPEW(("jerryeds", "PART CRC %x", crc));
|
|
#endif
|
|
|
|
}
|
|
return true;
|
|
|
|
case BigPacketEndBufferBoxID:
|
|
{
|
|
|
|
Check_Object(Application::GetInstance());
|
|
Connection *connection = FindConnection(packet->FromID);
|
|
|
|
if (connection == NULL)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
Check_Object(m_bigMessageCollectors[connection->GetID()].m_bigMessage);
|
|
|
|
Check_Pointer(packet->pData);
|
|
Verify(packet->Length > 0);
|
|
MemoryStream message(packet->pData, packet->Length);
|
|
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessage->WriteBytes(message.GetPointer(), message.GetBytesRemaining());
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessage->Rewind();
|
|
|
|
message.Rewind();
|
|
#ifdef HUNT_PACKET_CORUPTION
|
|
DWORD little_crc = 0;
|
|
for (int j = 0; j < message.GetSize(); ++j)
|
|
{
|
|
BYTE data;
|
|
message.ReadBytes(&data, 1);
|
|
little_crc += data;
|
|
}
|
|
message.Rewind();
|
|
SPEW(("jerryeds", "END CRC %x", little_crc));
|
|
#endif
|
|
|
|
DWORD crc = 0;
|
|
for (int i = 0; i < m_bigMessageCollectors[connection->GetID()].m_bigMessage->GetSize(); ++i)
|
|
{
|
|
BYTE data;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessage->ReadBytes(&data, 1);
|
|
crc += data;
|
|
}
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessage->Rewind();
|
|
|
|
if ( m_bigMessageCollectors[connection->GetID()].m_bigMessage->GetSize() < m_bigMessageCollectors[connection->GetID()].m_bigMessageSize)
|
|
{
|
|
delete m_bigMessageCollectors[connection->GetID()].m_bigMessage;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessage = NULL;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessageSize = 0;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessageType = -1;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigPacketCRC = 0;
|
|
|
|
RemovePlayer(connection->GetID());
|
|
return true;
|
|
//STOP(("Network::RoutePacket::BIG PACKET WRONG SIZE : SMALLER"));
|
|
}
|
|
|
|
if ( m_bigMessageCollectors[connection->GetID()].m_bigMessage->GetSize() > m_bigMessageCollectors[connection->GetID()].m_bigMessageSize)
|
|
{
|
|
delete m_bigMessageCollectors[connection->GetID()].m_bigMessage;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessage = NULL;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessageSize = 0;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessageType = -1;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigPacketCRC = 0;
|
|
|
|
RemovePlayer(connection->GetID());
|
|
return true;
|
|
//STOP(("Network::RoutePacket::BIG PACKET WRONG SIZE : LARGER"));
|
|
}
|
|
|
|
if (crc != m_bigMessageCollectors[connection->GetID()].m_bigPacketCRC)
|
|
{
|
|
delete m_bigMessageCollectors[connection->GetID()].m_bigMessage;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessage = NULL;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessageSize = 0;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessageType = -1;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigPacketCRC = 0;
|
|
|
|
RemovePlayer(connection->GetID());
|
|
return true;
|
|
//STOP(("Network::RoutePacket::BIG PACKET GOT CORRUPTED : From : %d Type : %d", connection->GetID(), m_bigMessageCollectors[connection->GetID()].m_bigMessageType));
|
|
}
|
|
|
|
ReceiveMessage(connection->GetID(), m_bigMessageCollectors[connection->GetID()].m_bigMessageType, m_bigMessageCollectors[connection->GetID()].m_bigMessage);
|
|
|
|
delete m_bigMessageCollectors[connection->GetID()].m_bigMessage;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessage = NULL;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessageSize = 0;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigMessageType = -1;
|
|
m_bigMessageCollectors[connection->GetID()].m_bigPacketCRC = 0;
|
|
|
|
|
|
}
|
|
return true;
|
|
|
|
case NetworkBoxID:
|
|
case ConnectionBoxID:
|
|
case ApplicationBoxID:
|
|
//SPEW(("jerryeds","BOX Message"));
|
|
{
|
|
STOP(("BOX MESSAGES DISABLED"));
|
|
//
|
|
//----------------------------------
|
|
// Find out who this message is from
|
|
//----------------------------------
|
|
//
|
|
Connection *connection = FindConnection(packet->FromID);
|
|
if (connection == NULL)
|
|
return true;
|
|
// no messages from "us" or from the "hermit"
|
|
if (connection == Connection::Local)
|
|
return true;
|
|
if (connection == Connection::Hermit)
|
|
return true;
|
|
|
|
Check_Object(connection);
|
|
|
|
InBox *box = FindInBox(static_cast<BoxID>(packet->Type));
|
|
if (box)
|
|
{
|
|
Check_Object(box);
|
|
box->ReceiveNetworkPacket(packet, static_cast<Message*>(packet->pData));
|
|
}
|
|
}
|
|
return true;
|
|
|
|
|
|
|
|
case gosNet_PlayerAdded:
|
|
|
|
|
|
if (reinterpret_cast<DWORD>(gos_NetInformation(gos_AmITheServer, 0)))
|
|
{
|
|
//SPEW(("jerryeds","PLAYER ADDED"));
|
|
|
|
DWORD net_id = packet->FromID;
|
|
if(FindConnection(net_id) == NULL)
|
|
{
|
|
const char* player_name = reinterpret_cast<const char*>(gos_NetInformation(gos_PlayerName, reinterpret_cast<DWORD>(gos_NetInformation(gos_PlayerNumber,packet->FromID))));
|
|
DWORD net_id = packet->FromID;
|
|
|
|
net_AddPlayer(player_name, net_id);
|
|
|
|
connection = FindConnection(net_id);
|
|
gosASSERT(connection);
|
|
if (g_pfn_ADDREMOVE_CONNECTION) {
|
|
(*g_pfn_ADDREMOVE_CONNECTION)(true, connection);
|
|
}
|
|
|
|
|
|
}
|
|
SendConnections();
|
|
}
|
|
return true;
|
|
|
|
case gosNet_PlayerDeleted:
|
|
|
|
|
|
if (reinterpret_cast<DWORD>(gos_NetInformation(gos_AmITheServer, 0)))
|
|
{
|
|
|
|
//SPEW(("jerryeds","PLAYER DELETED"));
|
|
// send the clients the remove command
|
|
|
|
Connection *connection = FindConnection(packet->FromID);
|
|
|
|
if (connection)
|
|
{
|
|
if (g_pfn_ADDREMOVE_CONNECTION) {
|
|
(*g_pfn_ADDREMOVE_CONNECTION)(false, connection);
|
|
}
|
|
|
|
net_RemovePlayer(packet->FromID);
|
|
|
|
SendConnections();
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
|
|
Connection *connection = FindConnection(packet->FromID);
|
|
|
|
if (connection == Connection::Server)
|
|
{
|
|
//
|
|
// we're the client, so on a player deleted message,
|
|
// end the game
|
|
//
|
|
if (g_pfn_SESSION_LOST) {
|
|
(*g_pfn_SESSION_LOST)();
|
|
}
|
|
Application::GetInstance()->SessionLost();
|
|
Check_Object(Application::GetInstance());
|
|
Application::GetInstance()->QueStopGame(true);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
case gosNet_GameEnded:
|
|
if (g_pfn_SESSION_LOST) {
|
|
(*g_pfn_SESSION_LOST)();
|
|
}
|
|
Application::GetInstance()->SessionLost();
|
|
Check_Object(Application::GetInstance());
|
|
Application::GetInstance()->QueStopGame(true);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
void Network::net_AddPlayer(const char* player_name, DWORD net_id)
|
|
{
|
|
gosASSERT(reinterpret_cast<DWORD>(gos_NetInformation(gos_AmITheServer, 0)));
|
|
gosASSERT(FindConnection(net_id) == NULL);
|
|
|
|
++currentPlayerCount;
|
|
|
|
int break_tester = 0;
|
|
while (activeConnections[nextConnectionID] != NULL)
|
|
{
|
|
++nextConnectionID;
|
|
if (nextConnectionID >= Maximum_Connection_Numbers)
|
|
nextConnectionID = 2;
|
|
|
|
++break_tester;
|
|
|
|
if (break_tester >= Maximum_Connection_Numbers)
|
|
STOP(("NO CONNECTIONS LEFT"));
|
|
}
|
|
|
|
|
|
Verify(activeConnections[nextConnectionID] == NULL);
|
|
|
|
Connection *connection = new Connection((BYTE)nextConnectionID, net_id, player_name);
|
|
Register_Object(connection);
|
|
Network::GetInstance()->AddConnectionToStats(connection->GetID());
|
|
|
|
Application::GetInstance()->ConnectClient(nextConnectionID, connection);
|
|
|
|
activeConnections[nextConnectionID] = connection;
|
|
++nextConnectionID;
|
|
|
|
if (true)
|
|
{
|
|
// MLYONS: added system chat message for player joining
|
|
char szString[256];
|
|
sprintf(szString, Application::GetInstance()->GetLocString(IDS_ADEPT_NET_PLAYER_HAS_CONNECTED), player_name);
|
|
Application::GetInstance()->SendChat(1, 0, 0, szString);
|
|
}
|
|
}
|
|
|
|
void Network::net_RemovePlayer(DWORD net_id)
|
|
{
|
|
gosASSERT(reinterpret_cast<DWORD>(gos_NetInformation(gos_AmITheServer, 0)));
|
|
//SPEW(("jerryeds","PLAYER DELETED"));
|
|
// send the clients the remove command
|
|
|
|
--currentPlayerCount;
|
|
Connection *connection = FindConnection(net_id);
|
|
gosASSERT(connection);
|
|
|
|
Check_Object(connection);
|
|
|
|
if (true)
|
|
{
|
|
// MLYONS: added system chat message for player leaving
|
|
char szString[256];
|
|
sprintf(szString, Application::GetInstance()->GetLocString(IDS_ADEPT_NET_PLAYER_HAS_DISCONNECTED), connection->GetConnectionName());
|
|
Application::GetInstance()->SendChat(1, 0, 0, szString);
|
|
}
|
|
|
|
BYTE id = connection->GetID();
|
|
|
|
Check_Object(Application::GetInstance());
|
|
|
|
|
|
if (m_bigMessageCollectors[id].m_bigMessage != NULL)
|
|
{
|
|
delete m_bigMessageCollectors[id].m_bigMessage;
|
|
m_bigMessageCollectors[id].m_bigMessage = NULL;
|
|
m_bigMessageCollectors[id].m_bigMessageSize = 0;
|
|
m_bigMessageCollectors[id].m_bigMessageType = -1;
|
|
m_bigMessageCollectors[id].m_bigPacketCRC = 0;
|
|
|
|
}
|
|
|
|
Application::GetInstance()->DisconnectClient(id, connection);
|
|
|
|
|
|
Unregister_Object(connection);
|
|
delete connection;
|
|
connection = NULL;
|
|
|
|
|
|
//fry deathrow
|
|
while(EntityManager::GetInstance()->FryDeathRow())
|
|
{
|
|
}
|
|
|
|
activeConnections[id] = NULL;
|
|
}
|
|
|
|
//#############################################################################
|
|
|
|
|
|
void Network::RemovePlayer(int connection_id)
|
|
{
|
|
Connection *connection = FindConnection(connection_id);
|
|
|
|
if (connection)
|
|
{
|
|
Check_Object(connection);
|
|
|
|
if (true)
|
|
{
|
|
// MLYONS: added system chat message for player leaving
|
|
char szString[256];
|
|
sprintf(szString, Application::GetInstance()->GetLocString(IDS_ADEPT_NET_PLAYER_HAS_DISCONNECTED), connection->GetConnectionName());
|
|
Application::GetInstance()->SendChat(1, 0, 0, szString);
|
|
}
|
|
|
|
BYTE id = connection->GetID();
|
|
|
|
Check_Object(Application::GetInstance());
|
|
|
|
|
|
if (m_bigMessageCollectors[id].m_bigMessage != NULL)
|
|
{
|
|
delete m_bigMessageCollectors[id].m_bigMessage;
|
|
m_bigMessageCollectors[id].m_bigMessage = NULL;
|
|
m_bigMessageCollectors[id].m_bigMessageSize = 0;
|
|
m_bigMessageCollectors[id].m_bigMessageType = -1;
|
|
m_bigMessageCollectors[id].m_bigPacketCRC = 0;
|
|
|
|
}
|
|
|
|
Application::GetInstance()->DisconnectClient(id, connection);
|
|
|
|
|
|
Unregister_Object(connection);
|
|
delete connection;
|
|
connection = NULL;
|
|
|
|
|
|
//fry deathrow
|
|
while(EntityManager::GetInstance()->FryDeathRow())
|
|
{
|
|
}
|
|
|
|
activeConnections[id] = NULL;
|
|
|
|
|
|
SendConnections();
|
|
}
|
|
}
|
|
|
|
//#############################################################################
|
|
|
|
|
|
bool
|
|
Network::RouteLocalPacket()
|
|
{
|
|
ChainIteratorOf<QuedPacket *> packets(&localPacketQue);
|
|
QuedPacket *packet;
|
|
if ((packet = packets.GetCurrent()) != NULL)
|
|
{
|
|
#ifdef _DEBUG
|
|
g_nLocalPacketLevel++;
|
|
#endif // _DEBUG
|
|
ReceiveMessage(packet->connectionID, packet->messageType, packet->packetData);
|
|
#ifdef _DEBUG
|
|
g_nLocalPacketLevel--;
|
|
#endif // _DEBUG
|
|
|
|
packets.Remove();
|
|
delete packet;
|
|
}
|
|
|
|
if (packets.GetCurrent())
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void Network::ReceiveMessage(int connection_id, int message_type, Stuff::MemoryStream *message)
|
|
{
|
|
|
|
|
|
if (message_type == FullConnectionListMessageID)
|
|
{
|
|
//
|
|
//--------------------------------------------
|
|
// Create a new server list in the right order
|
|
//--------------------------------------------
|
|
//
|
|
|
|
//Network::GetInstance()->netStatCollector[Network::IncomingSystemMessageBitSizeStat].AddToStatistic(Connection::Server->GetID(),message->GetCurrentBitCount()*8);
|
|
|
|
// read the player count
|
|
DWORD player_count;
|
|
*message >> player_count;
|
|
*message >> serverKey;
|
|
|
|
|
|
// make a "lost list"
|
|
// this list assumes everyone has been dropped from the game.
|
|
// as the player is found in the stream we mark him as not lost
|
|
// anyone at the end of the process who is still not marked is
|
|
// no longer in the game...
|
|
|
|
// this method is used so that only one connection message is needed
|
|
// and multiple players can be both removed and added with one message.
|
|
|
|
currentPlayerCount = player_count;
|
|
bool lost_list[Maximum_Connection_Numbers];
|
|
for (int i = 1; i < Maximum_Connection_Numbers; ++i)
|
|
{
|
|
lost_list[i] = true;
|
|
}
|
|
|
|
bool connect_server = false;
|
|
|
|
// read each player from the stream
|
|
|
|
|
|
|
|
for (i=1; i<=player_count; ++i)
|
|
{
|
|
BYTE connection_id;
|
|
DWORD address;
|
|
*message >> connection_id;
|
|
*message >> address;
|
|
|
|
MString player_name;
|
|
*message >> player_name;
|
|
|
|
|
|
Verify(connection_id < Maximum_Connection_Numbers);
|
|
|
|
// look for that player
|
|
Connection *connection = activeConnections[connection_id];
|
|
if (connection == NULL)
|
|
{
|
|
//we have a new player, create his connection
|
|
|
|
|
|
connection = new Connection(connection_id, address, player_name);
|
|
Register_Object(connection);
|
|
|
|
Application::GetInstance()->ConnectClient(connection_id, connection);
|
|
|
|
Verify(activeConnections[connection_id] == NULL);
|
|
activeConnections[connection_id] = connection;
|
|
|
|
lost_list[connection_id] = false;
|
|
|
|
//if (address == MyAddress)
|
|
// Connection::Local = connection;
|
|
//else
|
|
|
|
Network::GetInstance()->AddConnectionToStats(connection->GetID());
|
|
|
|
if (connection_id == 1)
|
|
{
|
|
Connection::Server = connection;
|
|
Network::GetInstance()->netStatCollector[Network::IncomingSystemMessageBitSizeStat].AddToStatistic(Connection::Server->GetID(),message->GetBufferBytesUsed()*8);
|
|
|
|
connect_server = true;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// we found this player so mark him as still in the game
|
|
Verify(address == connection->GetNetworkAddress());
|
|
lost_list[connection_id] = false;
|
|
}
|
|
|
|
|
|
|
|
|
|
Check_Object(connection);
|
|
}
|
|
|
|
|
|
BYTE local_player;
|
|
*message >> local_player;
|
|
|
|
if (Connection::Local == NULL)
|
|
{
|
|
Connection::Local = activeConnections[local_player];
|
|
Network::GetInstance()->RemoveConnectionToStats(local_player);
|
|
}
|
|
|
|
|
|
|
|
if (connect_server)
|
|
{
|
|
Application::GetInstance()->ConnectServer();
|
|
}
|
|
|
|
// now go thru the lost list and remove everyone who was lost...
|
|
for (i = 1; i < Maximum_Connection_Numbers; ++i)
|
|
{
|
|
if (lost_list[i] && activeConnections[i] != NULL)
|
|
{
|
|
// connection is now gone.
|
|
|
|
|
|
if (activeConnections[i] != Connection::Local)
|
|
{
|
|
Application::GetInstance()->DisconnectClient(i, activeConnections[i]);
|
|
|
|
Unregister_Object(activeConnections[i]);
|
|
delete activeConnections[i];
|
|
activeConnections[i] = NULL;
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
// fry death row to be doubly sure they are gone
|
|
while(EntityManager::GetInstance()->FryDeathRow())
|
|
{
|
|
}
|
|
|
|
Check_Object(Connection::Local);
|
|
Check_Object(Connection::Server);
|
|
#if defined(_DEBUG) && 0 // jcem - for MR test
|
|
{
|
|
OutputDebugString(":: FullConnectionListMessageID\n");
|
|
}
|
|
#endif // _DEBUG && ...
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// if we need to throw this away...
|
|
Connection *connection = Network::GetInstance()->GetConnection(connection_id);
|
|
|
|
if (connection == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
bool delete_message = false;
|
|
|
|
if (message && HashMessageTypeFlags[message_type] != NoHash)
|
|
{
|
|
|
|
MemoryStream sub_message(message->GetPointer(), message->GetSize());
|
|
//comp the hash..
|
|
|
|
MD5_CTX resource_context;
|
|
GUID resource_hash;
|
|
unsigned char * buff=(unsigned char *) &resource_hash;
|
|
|
|
MD5Init(&resource_context);
|
|
|
|
MD5Update(&resource_context, (unsigned char *) &serverKey, 4);
|
|
|
|
if (HashMessageTypeFlags[message_type] == GameSpecificHash)
|
|
{
|
|
int number = Application::GetInstance()->currentGameNumber^0x43215202;
|
|
MD5Update(&resource_context, (unsigned char *) &number, 4);
|
|
//SPEW(("jerryeds", "GAME : %d", number));
|
|
|
|
number = Connection::Server->GetLastReplicatorIDUsed();
|
|
MD5Update(&resource_context, (unsigned char *) &number, 4);
|
|
//SPEW(("jerryeds", "ID : %d", number));
|
|
}
|
|
|
|
MD5Update(&resource_context, (unsigned char *) connection->GetConnectionName(), strlen(connection->GetConnectionName()));
|
|
|
|
//SPEW(("jerryeds", "NAME : %s", connection->GetConnectionName()));
|
|
|
|
MD5Update(&resource_context, (unsigned char *) message->GetPointer(), message->GetSize()-2);
|
|
MD5Final(buff, &resource_context);
|
|
|
|
|
|
WORD part_1 = (WORD)buff[0];
|
|
WORD part_2 = (WORD)buff[2];
|
|
WORD part_3 = (WORD)buff[4];
|
|
WORD part_4 = (WORD)buff[6];
|
|
WORD part_5 = (WORD)buff[8];
|
|
WORD part_6 = (WORD)buff[10];
|
|
WORD part_7 = (WORD)buff[12];
|
|
WORD part_8 = (WORD)buff[14];
|
|
|
|
WORD total_crc;
|
|
total_crc = part_1;
|
|
total_crc ^= part_2;
|
|
total_crc ^= part_3;
|
|
total_crc ^= part_4;
|
|
total_crc ^= part_5;
|
|
total_crc ^= part_6;
|
|
total_crc ^= part_7;
|
|
total_crc ^= part_8;
|
|
|
|
message->AdvancePointer(message->GetSize()-2);
|
|
|
|
WORD comp_crc = 0;
|
|
message->ReadBytes(&comp_crc, 2);
|
|
|
|
|
|
//SPEW(("jerryeds", "CRC : %d", total_crc));
|
|
//SPEW(("jerryeds", "COMPCRC : %d", comp_crc));
|
|
|
|
if (comp_crc != total_crc)
|
|
{
|
|
SPEW(("jerryeds", "CORRUPTED PACKET"));
|
|
return;
|
|
}
|
|
|
|
Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection_id,16);
|
|
|
|
message->Rewind();
|
|
|
|
delete_message = true;
|
|
Stuff::MemoryStream *new_stream = new Stuff::MemoryStream(message->GetPointer(), message->GetSize()-2);
|
|
message = new_stream;
|
|
}
|
|
|
|
|
|
|
|
if (message_type >= FirstDirectApplicationMessageID && message_type < LastDirectApplicationMessageID)
|
|
{
|
|
// application messages are system messages...
|
|
if (message != NULL)
|
|
Network::GetInstance()->netStatCollector[Network::IncomingSystemMessageBitSizeStat].AddToStatistic(connection_id,message->GetBufferBytesUsed()*8);
|
|
|
|
Application::GetInstance()->ReceiveDirectMessage(connection_id, message_type, message);
|
|
}
|
|
else if (message_type >= FirstDictionaryPageMessageID && message_type < LastDictionaryPageMessageID)
|
|
{
|
|
EntityManager::GetInstance()->UpdateClientEntites(connection_id, message_type, message);
|
|
}
|
|
else
|
|
{
|
|
STOP(("UNKNOWN MESSAGE TYPE"));
|
|
}
|
|
|
|
|
|
if (delete_message)
|
|
{
|
|
delete message;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
InBox*
|
|
Network::FindInBox(BoxID box_id)
|
|
{
|
|
Check_Object(this);
|
|
switch (box_id)
|
|
{
|
|
case NetworkBoxID:
|
|
return this;
|
|
|
|
case ConnectionBoxID:
|
|
return Connection::Local;
|
|
|
|
case ApplicationBoxID:
|
|
Check_Object(Application::GetInstance());
|
|
return Application::GetInstance();
|
|
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Connection*
|
|
Network::FindConnection(DWORD net_address)
|
|
{
|
|
Check_Object(this);
|
|
|
|
for (BYTE i=1; i<Maximum_Connection_Numbers; ++i)
|
|
{
|
|
if (activeConnections[i] != NULL)
|
|
{
|
|
Check_Object(activeConnections[i]);
|
|
if (activeConnections[i]->GetNetworkAddress() == net_address)
|
|
return activeConnections[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//#############################################################################
|
|
|
|
|
|
Connection*
|
|
Network::GetConnection(int host_ID)
|
|
{
|
|
|
|
Check_Object(this);
|
|
|
|
if (host_ID < 0 || host_ID >= Maximum_Connection_Numbers) // jcem host_ID > Maximum_Connection_Numbers
|
|
return NULL;
|
|
|
|
return activeConnections[host_ID];
|
|
|
|
}
|
|
|
|
|
|
//#############################################################################
|
|
|
|
|
|
void Network::RemoveConnection(int host_ID)
|
|
{
|
|
if (activeConnections[host_ID] != NULL)
|
|
{
|
|
Unregister_Object(activeConnections[host_ID]);
|
|
delete activeConnections[host_ID];
|
|
activeConnections[host_ID] = NULL;
|
|
}
|
|
};
|
|
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
|
|
void
|
|
Network::SendConnections()
|
|
{
|
|
Check_Object(this);
|
|
|
|
// go ahead and get the max we could use.
|
|
// It will only send what is actually used.
|
|
|
|
for (BYTE j = 1; j < Maximum_Connection_Numbers; ++j)
|
|
{
|
|
if (activeConnections[j] != NULL && activeConnections[j] != Connection::Local)
|
|
{
|
|
|
|
|
|
DynamicMemoryStream stream(sizeof(DWORD)+(currentPlayerCount*(sizeof(DWORD)+256)));
|
|
|
|
stream << currentPlayerCount;
|
|
stream << serverKey;
|
|
|
|
BYTE i;
|
|
for (i=1; i<Maximum_Connection_Numbers; ++i)
|
|
{
|
|
//SPEW(("jerryeds", "SENDNG ADDRESS : %d %d", activeConnections[i]->GetID(), activeConnections[i]->GetNetworkAddress()));
|
|
if (activeConnections[i] != NULL)
|
|
{
|
|
stream << activeConnections[i]->GetID();
|
|
stream << activeConnections[i]->GetNetworkAddress();
|
|
MString name = activeConnections[i]->GetConnectionName();
|
|
stream << name;
|
|
}
|
|
}
|
|
|
|
|
|
stream << j;
|
|
|
|
stream.Rewind();
|
|
|
|
|
|
|
|
Network::GetInstance()->netStatCollector[Network::OutgoingSystemMessageBitSizeStat].AddToStatistic(j,1);
|
|
|
|
Check_Object(activeConnections[j]);
|
|
SendNetMessage(j, FullConnectionListMessageID, &stream, true);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//#############################################################################
|
|
|
|
void
|
|
Network::SendNetMessage(int connection_id, int message_type, Stuff::MemoryStream *message, bool reliable)
|
|
{
|
|
// jcem for mission review
|
|
if (g_nMR && (connection_id == 1)) {
|
|
if (!(*g_pfn_LOCALSENDNETMESSAGE)(message_type, message))
|
|
return;
|
|
}
|
|
|
|
#ifdef GROUP_ADEPT_NETWORK
|
|
LOG_BLOCK("Game Logic::Network::Send Message");
|
|
#endif
|
|
|
|
Connection *connection = Network::GetInstance()->GetConnection(connection_id);
|
|
Check_Object(connection);
|
|
|
|
_NetPacket packet;
|
|
packet.ToID = connection->GetNetworkAddress();
|
|
packet.Type = static_cast<BYTE>(message_type);
|
|
|
|
bool deletemessage = false;
|
|
|
|
if (message)
|
|
{
|
|
|
|
message->WriteByteAlign();
|
|
message->Rewind();
|
|
|
|
|
|
// Calculate a hash on this packet
|
|
if (HashMessageTypeFlags[message_type] != NoHash)
|
|
{
|
|
//add a hash..
|
|
|
|
MD5_CTX resource_context;
|
|
GUID resource_hash;
|
|
unsigned char * buff=(unsigned char *) &resource_hash;
|
|
|
|
MD5Init(&resource_context);
|
|
|
|
MD5Update(&resource_context, (unsigned char *) &serverKey, 4);
|
|
|
|
if (HashMessageTypeFlags[message_type] == GameSpecificHash)
|
|
{
|
|
int number = Application::GetInstance()->currentGameNumber^0x43215202;
|
|
MD5Update(&resource_context, (unsigned char *) &number, 4);
|
|
|
|
//SPEW(("jerryeds", "GAME : %d", number));
|
|
|
|
number = Connection::Server->GetLastReplicatorIDUsed();
|
|
MD5Update(&resource_context, (unsigned char *) &number, 4);
|
|
|
|
//SPEW(("jerryeds", "ID : %d", number));
|
|
|
|
}
|
|
|
|
MD5Update(&resource_context, (unsigned char *) Connection::Local->GetConnectionName(), strlen(Connection::Local->GetConnectionName()));
|
|
|
|
//SPEW(("jerryeds", "NAME : %s", Connection::Local->GetConnectionName()));
|
|
|
|
MD5Update(&resource_context, (unsigned char *) message->GetPointer(), message->GetBufferBytesUsed());
|
|
MD5Final(buff, &resource_context);
|
|
|
|
|
|
WORD part_1 = (WORD)buff[0];
|
|
WORD part_2 = (WORD)buff[2];
|
|
WORD part_3 = (WORD)buff[4];
|
|
WORD part_4 = (WORD)buff[6];
|
|
WORD part_5 = (WORD)buff[8];
|
|
WORD part_6 = (WORD)buff[10];
|
|
WORD part_7 = (WORD)buff[12];
|
|
WORD part_8 = (WORD)buff[14];
|
|
|
|
WORD total_crc;
|
|
total_crc = part_1;
|
|
total_crc ^= part_2;
|
|
total_crc ^= part_3;
|
|
total_crc ^= part_4;
|
|
total_crc ^= part_5;
|
|
total_crc ^= part_6;
|
|
total_crc ^= part_7;
|
|
total_crc ^= part_8;
|
|
|
|
//SPEW(("jerryeds", "CRC : %d", total_crc));
|
|
|
|
deletemessage = true;
|
|
Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection_id,16);
|
|
|
|
|
|
BYTE *data = new BYTE[message->GetBufferBytesUsed()+2];
|
|
MemoryStream *new_stream = new MemoryStream(data, message->GetBufferBytesUsed()+2);
|
|
|
|
new_stream->WriteBytes(message->GetPointer(), message->GetBufferBytesUsed());
|
|
new_stream->WriteBytes(&total_crc, 2);
|
|
new_stream->Rewind();
|
|
message = new_stream;
|
|
|
|
|
|
}
|
|
|
|
packet.pData = message->GetPointer();
|
|
packet.Length = (WORD)message->GetBufferBytesUsed();
|
|
|
|
}
|
|
else
|
|
{
|
|
packet.pData = NULL;
|
|
packet.Length = static_cast<BYTE>(0);
|
|
}
|
|
|
|
|
|
|
|
if (reliable)
|
|
{
|
|
packet.Flags = gosNetFlag_guaranteed;
|
|
}
|
|
else
|
|
{
|
|
packet.Flags = 0;
|
|
}
|
|
|
|
if (Connection::Local != NULL && connection_id == Connection::Local->GetID())
|
|
{
|
|
// if this message is a local message than just repeat it...
|
|
|
|
QuedPacket *packet = new QuedPacket(connection_id, message_type, message);
|
|
localPacketQue.Add(packet);
|
|
|
|
}
|
|
else if (message != NULL && message->GetBufferBytesUsed() > Network::DefaultPacketSize)
|
|
{
|
|
if (reliable)
|
|
{
|
|
SendBigMessage(connection_id, message_type, message, true);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
STOP(("Network::SendMessage - Message Larger than max network size and not reliable!"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// add gos packet overhead
|
|
Network::GetInstance()->netStatCollector[Network::OutgoingPacketCountStat].AddToStatistic(connection_id,1);
|
|
Network::GetInstance()->netStatCollector[Network::OutgoingProtocolHeaderBitSizeStat].AddToStatistic(connection_id,42*8);
|
|
Network::GetInstance()->netStatCollector[Network::OutgoingTotalPacketSizeStat].AddToStatistic(connection_id,packet.Length*8);
|
|
|
|
Adept::g_lastPacketToPlayer[connection_id] = gos_GetElapsedTime();
|
|
|
|
#if defined(LAB_ONLY)
|
|
MWGameInfo::g_lastPacketType[MWGameInfo::nextPacketHistoryIndex] = packet.Type;
|
|
MWGameInfo::g_lastPacketSize[MWGameInfo::nextPacketHistoryIndex] = packet.Length;
|
|
MWGameInfo::g_lastPacketInbound[MWGameInfo::nextPacketHistoryIndex] = false;
|
|
MWGameInfo::g_lastPacketTime[MWGameInfo::nextPacketHistoryIndex] = gos_GetElapsedTime();
|
|
|
|
if (connection != NULL)
|
|
{
|
|
MWGameInfo::g_lastPacketAddress[MWGameInfo::nextPacketHistoryIndex] = connection->GetID();
|
|
}
|
|
|
|
|
|
|
|
++MWGameInfo::nextPacketHistoryIndex;
|
|
|
|
if (MWGameInfo::nextPacketHistoryIndex >= MWGameInfo::Packet_History_Count)
|
|
MWGameInfo::nextPacketHistoryIndex = 0;
|
|
|
|
#endif
|
|
|
|
|
|
#if defined(LAB_ONLY)
|
|
|
|
if (message_type >= FirstDictionaryPageMessageID && message_type <= LastDictionaryPageMessageID)
|
|
{
|
|
if (packet.Length == 0)
|
|
STOP(("INVALID DICTIONARY PAGE LENGTH"));
|
|
}
|
|
|
|
#endif
|
|
|
|
{
|
|
#ifdef GROUP_ADEPT_NETWORK
|
|
LOG_BLOCK("Game Logic::Network::GOS Send Message");
|
|
#endif
|
|
|
|
if (!reliable)
|
|
{
|
|
++packetsSent[connection_id];
|
|
packetsDropped[connection_id] += !gos_NetSendMessage(&packet);
|
|
}
|
|
else
|
|
{
|
|
|
|
gos_NetSendMessage(&packet);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (deletemessage)
|
|
{
|
|
message->Rewind();
|
|
BYTE *data = (BYTE *)message->GetPointer();
|
|
delete[] data;
|
|
delete message;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//#############################################################################
|
|
|
|
void
|
|
Network::SendBigMessage(int connection, int message_type, Stuff::MemoryStream *message, bool reliable)
|
|
{
|
|
|
|
size_t bytes_remaining = message->GetBufferBytesUsed();
|
|
bool first_message = true;
|
|
|
|
do
|
|
{
|
|
size_t chunk_size = bytes_remaining;
|
|
Max_Clamp(chunk_size, Network::DefaultPacketSize-2);
|
|
|
|
|
|
if (first_message) // first packet
|
|
{
|
|
chunk_size;
|
|
|
|
Stuff::DynamicMemoryStream small_stream(chunk_size);
|
|
|
|
int size = message->GetBufferBytesUsed();
|
|
|
|
|
|
DWORD crc = 0;
|
|
for (int i = 0; i < message->GetSize(); ++i)
|
|
{
|
|
BYTE data;
|
|
message->ReadBytes(&data, 1);
|
|
crc += data;
|
|
}
|
|
message->Rewind();
|
|
|
|
|
|
|
|
|
|
small_stream.WriteBytes(&message_type,1);
|
|
small_stream.WriteBytes(&size, 4);
|
|
small_stream.WriteBytes(&crc, 4);
|
|
|
|
small_stream.WriteBytes(message->GetPointer(), chunk_size-7);
|
|
small_stream.Rewind();
|
|
|
|
message->AdvancePointer(chunk_size-7);
|
|
|
|
first_message = false;
|
|
Verify(bytes_remaining > 0);
|
|
SendNetMessage(connection, BigPacketStartBufferBoxID, &small_stream, true);
|
|
bytes_remaining -= chunk_size-7;
|
|
Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection,3);
|
|
|
|
|
|
small_stream.Rewind();
|
|
crc = 0;
|
|
for (i = 0; i < small_stream.GetSize(); ++i)
|
|
{
|
|
BYTE data;
|
|
small_stream.ReadBytes(&data, 1);
|
|
crc += data;
|
|
}
|
|
small_stream.Rewind();
|
|
//SPEW(("jerryeds", "START CRC %x", crc));
|
|
|
|
|
|
|
|
|
|
}
|
|
else if (bytes_remaining-chunk_size > 0) // if we still have some space left after this chunk
|
|
{
|
|
Stuff::MemoryStream small_stream(message->GetPointer(), chunk_size);
|
|
small_stream.AdvancePointer(chunk_size);
|
|
small_stream.Rewind();
|
|
message->AdvancePointer(chunk_size);
|
|
SendNetMessage(connection, BigPacketPartBufferBoxID, &small_stream, true);
|
|
bytes_remaining -= chunk_size;
|
|
|
|
small_stream.Rewind();
|
|
DWORD crc = 0;
|
|
for (int i = 0; i < small_stream.GetSize(); ++i)
|
|
{
|
|
BYTE data;
|
|
small_stream.ReadBytes(&data, 1);
|
|
crc += data;
|
|
}
|
|
small_stream.Rewind();
|
|
//SPEW(("jerryeds", "PART CRC %x", crc));
|
|
|
|
|
|
}
|
|
else // we are out of pieces so this is the last packet
|
|
{
|
|
Stuff::MemoryStream small_stream(message->GetPointer(), chunk_size);
|
|
small_stream.AdvancePointer(chunk_size);
|
|
small_stream.Rewind();
|
|
message->AdvancePointer(chunk_size);
|
|
SendNetMessage(connection, BigPacketEndBufferBoxID, &small_stream, true);
|
|
bytes_remaining -= chunk_size;
|
|
|
|
small_stream.Rewind();
|
|
DWORD crc = 0;
|
|
for (int i = 0; i < small_stream.GetSize(); ++i)
|
|
{
|
|
BYTE data;
|
|
small_stream.ReadBytes(&data, 1);
|
|
crc += data;
|
|
}
|
|
small_stream.Rewind();
|
|
//SPEW(("jerryeds", "END CRC %x", crc));
|
|
}
|
|
}
|
|
while (bytes_remaining > 0);
|
|
|
|
}
|