Files
firestorm/Gameleap/code/mw4/Libraries/Adept/Network.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
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.
2026-06-24 21:28:16 -05:00

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);
}