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.
1239 lines
32 KiB
C++
1239 lines
32 KiB
C++
//===========================================================================//
|
|
// File: NetGenericMessages.cpp
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 01/06/1999 JSE Inital coding
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1998, Microsoft Corp. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
|
|
#include "MW4Headers.hpp"
|
|
|
|
#include "NetGenericMessages.hpp"
|
|
#include "MWEntityManager.hpp"
|
|
#include "Objective.hpp"
|
|
#include "Flag.hpp"
|
|
#include "MWApplication.hpp"
|
|
#include "MWPlayer.hpp"
|
|
#include "MWMission.hpp"
|
|
|
|
#include "NavPoint.hpp"
|
|
#include <Adept\NameTable.hpp>
|
|
#include <Adept\Map.hpp>
|
|
|
|
|
|
|
|
#include <GameOS\Network.hpp>
|
|
#include <Adept\DamageObject.hpp>
|
|
#include <Adept\GlobalPointerManager.hpp>
|
|
#include "MW4\Bucket.hpp"
|
|
#include "MW4\MWDamageObject.hpp"
|
|
#include "MW4\VehicleInterface.hpp"
|
|
#include "MW4\Vehicle.hpp"
|
|
#include "MW4\Mech.hpp"
|
|
#include "MW4\WeaponMover.hpp"
|
|
#include "MW4\HeatManager.hpp"
|
|
#include "MW4\JumpJet.hpp"
|
|
#include "MW4\Weapon.hpp"
|
|
#include "MW4\NetMovement.hpp"
|
|
#include "MW4\NetWeapon.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void MissionObjectiveUpdate::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
|
|
int size = table->nameTableArray[NameTable::ObjectiveArray].GetLength ();
|
|
for (int objective=0;objective<size;objective++)
|
|
{
|
|
NameTableEntry *data;
|
|
|
|
data = &table->nameTableArray [NameTable::ObjectiveArray][objective];
|
|
|
|
Objective *obj;
|
|
|
|
Entity *ent;
|
|
ent = data->dataPointer->GetCurrent ();
|
|
if (ent)
|
|
{
|
|
|
|
obj = Cast_Object (Objective *,ent);
|
|
Check_Object (obj);
|
|
|
|
bool visibile;
|
|
memory_stream->ReadBit(visibile);
|
|
|
|
if (visibile)
|
|
{
|
|
obj->Reveal();
|
|
|
|
int status = 0; // jcem: critical error - should clear before ReadBits(...)...
|
|
memory_stream->ReadBits(&status, 2);
|
|
|
|
//SPEW(("jerryeds", "%d : 1-%d", objective, status));
|
|
|
|
switch(status)
|
|
{
|
|
case Objective::Objective_Failed:
|
|
obj->Fail();
|
|
break;
|
|
|
|
case Objective::Objective_Succeeded:
|
|
obj->Succeed();
|
|
break;
|
|
|
|
case Objective::Objective_Neutral:
|
|
//should never switch to neutral
|
|
//and should always start in neutral
|
|
break;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
obj->Hide();
|
|
//SPEW(("jerryeds", "%d : 0", objective));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void MissionObjectiveUpdate::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(memory_stream);
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
int table_size = table->nameTableArray[NameTable::ObjectiveArray].GetLength ();
|
|
for (int objective=0;objective<table_size;objective++)
|
|
{
|
|
NameTableEntry *data;
|
|
data = &table->nameTableArray [NameTable::ObjectiveArray][objective];
|
|
|
|
Entity *ent;
|
|
ent = data->dataPointer->GetCurrent ();
|
|
if (ent)
|
|
{
|
|
|
|
bool visibile;
|
|
memory_stream->ReadBit(visibile);
|
|
|
|
if (visibile)
|
|
{
|
|
int status = 0; // jcem: critical error - should clear before ReadBits(...)...
|
|
memory_stream->ReadBits(&status, 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int MissionObjectiveUpdate::MaxSize(Entity *entity, int debug_level, int bandwidth)
|
|
{
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
int table_size = table->nameTableArray[NameTable::ObjectiveArray].GetLength ();
|
|
|
|
return table_size*3;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void MissionObjectiveUpdate::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
int size = table->nameTableArray[NameTable::ObjectiveArray].GetLength ();
|
|
for (int objective=0;objective<size;objective++)
|
|
{
|
|
NameTableEntry *data;
|
|
|
|
data = &table->nameTableArray [NameTable::ObjectiveArray][objective];
|
|
|
|
Objective *obj;
|
|
|
|
Entity *ent;
|
|
ent = data->dataPointer->GetCurrent ();
|
|
if (ent)
|
|
{
|
|
|
|
obj = Cast_Object (Objective *,ent);
|
|
Check_Object (obj);
|
|
|
|
if (obj->Visible())
|
|
{
|
|
memory_stream->WriteBit(true);
|
|
int status = obj->Status();
|
|
memory_stream->WriteBits(&status, 2);
|
|
|
|
//SPEW(("jerryeds", "%d : 1-%d", objective, status));
|
|
|
|
}
|
|
else
|
|
{
|
|
//SPEW(("jerryeds", "%d : 0", objective));
|
|
memory_stream->WriteBit(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
//SPEW(("jerryeds",""));
|
|
|
|
}
|
|
|
|
//====================================================================================================================================================
|
|
//
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void NavPointUpdate::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
|
|
int size = table->nameTableArray[NameTable::NavArray].GetLength ();
|
|
for (int objective=0;objective<size;objective++)
|
|
{
|
|
NameTableEntry *data;
|
|
|
|
data = &table->nameTableArray [NameTable::NavArray][objective];
|
|
|
|
NavPoint *obj;
|
|
|
|
Entity *ent;
|
|
ent = data->dataPointer->GetCurrent ();
|
|
if (ent)
|
|
{
|
|
|
|
obj = Cast_Object (NavPoint *,ent);
|
|
Check_Object (obj);
|
|
|
|
bool visibile;
|
|
memory_stream->ReadBit(visibile);
|
|
|
|
if (visibile)
|
|
{
|
|
unsigned char radarid = 0; // jcem: critical error - should clear before ReadBits(...)...
|
|
obj->Reveal();
|
|
memory_stream->ReadBits (&radarid,3);
|
|
if (radarid == 7)
|
|
obj->m_RadarID = -1;
|
|
else
|
|
obj->m_RadarID = radarid;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void NavPointUpdate::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(memory_stream);
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
int table_size = table->nameTableArray[NameTable::NavArray].GetLength ();
|
|
for (int objective=0;objective<table_size;objective++)
|
|
{
|
|
NameTableEntry *data;
|
|
data = &table->nameTableArray [NameTable::NavArray][objective];
|
|
|
|
Entity *ent;
|
|
ent = data->dataPointer->GetCurrent ();
|
|
if (ent)
|
|
{
|
|
|
|
bool visibile;
|
|
memory_stream->ReadBit(visibile);
|
|
if (visibile)
|
|
{
|
|
BYTE temp = 0; // jcem: critical error - should clear before ReadBits(...)...
|
|
memory_stream->ReadBits (&temp,3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int NavPointUpdate::MaxSize(Entity *entity, int debug_level, int bandwidth)
|
|
{
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
int table_size = table->nameTableArray[NameTable::NavArray].GetLength ();
|
|
|
|
return (table_size*4); // 1 for visible, 3 for radarid
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void NavPointUpdate::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
int size = table->nameTableArray[NameTable::NavArray].GetLength ();
|
|
for (int objective=0;objective<size;objective++)
|
|
{
|
|
NameTableEntry *data;
|
|
|
|
data = &table->nameTableArray [NameTable::NavArray][objective];
|
|
|
|
NavPoint *obj;
|
|
|
|
Entity *ent;
|
|
ent = data->dataPointer->GetCurrent ();
|
|
if (ent)
|
|
{
|
|
|
|
obj = Cast_Object (NavPoint *,ent);
|
|
Check_Object (obj);
|
|
|
|
|
|
|
|
if (obj->IsVisible())
|
|
{
|
|
memory_stream->WriteBit(true);
|
|
unsigned char radarid;
|
|
if (obj->m_RadarID == -1)
|
|
radarid = 7;
|
|
else
|
|
radarid = (unsigned char) obj->m_RadarID;
|
|
memory_stream->WriteBits (&radarid,3);
|
|
|
|
//SPEW(("jerryeds", "%d : 1-%d", objective, status));
|
|
|
|
}
|
|
else
|
|
{
|
|
//SPEW(("jerryeds", "%d : 0", objective));
|
|
memory_stream->WriteBit(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
//SPEW(("jerryeds",""));
|
|
|
|
}
|
|
|
|
//====================================================================================================================================================
|
|
//
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void FlagUpdate::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth)
|
|
{
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
MWMission* mwmission = Cast_Object(MWMission*,MWMission::GetInstance());
|
|
|
|
bool flags_as_nav_points(mwmission->GetFlagsAsNavPoints());
|
|
memory_stream->ReadBit(flags_as_nav_points);
|
|
mwmission->SetFlagsAsNavPoints(flags_as_nav_points);
|
|
|
|
int temp(0);
|
|
memory_stream->ReadBits(&temp,2);
|
|
|
|
MWMission::FLAG_ENABLE_STATE flags_enabled = (MWMission::FLAG_ENABLE_STATE)temp;
|
|
|
|
mwmission->SetFlagsEnabled(flags_enabled);
|
|
|
|
int size = table->nameTableArray[NameTable::FlagArray].GetLength ();
|
|
for (int objective=0;objective<size;objective++)
|
|
{
|
|
NameTableEntry *data;
|
|
|
|
data = &table->nameTableArray [NameTable::FlagArray][objective];
|
|
|
|
Flag *flag;
|
|
|
|
Entity *ent;
|
|
ent = data->dataPointer->GetCurrent ();
|
|
if (ent)
|
|
{
|
|
|
|
flag = Cast_Object (Flag *,ent);
|
|
Check_Object (flag);
|
|
|
|
bool visible;
|
|
memory_stream->ReadBit(visible);
|
|
|
|
if (visible)
|
|
{
|
|
flag->RevealFlag();
|
|
|
|
int last_event = 0;
|
|
memory_stream->ReadBits(&last_event,2);
|
|
flag->SetLastFlagEvent((Flag::FlagEvent)last_event);
|
|
|
|
int mode = 0;
|
|
memory_stream->ReadBits(&mode,2);
|
|
|
|
if (mode == GroundMode)
|
|
{
|
|
if (flag->Attached())
|
|
{
|
|
flag->Attach(NULL);
|
|
}
|
|
|
|
Point3D position;
|
|
position = flag->GetLocalToWorld();
|
|
|
|
Scalar min_z, max_z, min_x, max_x;
|
|
Map::GetInstance()->GetMapExtents(&min_z, &max_z, &min_x, &max_x);
|
|
|
|
memory_stream->ReadBitsToScaledFloat(position.x, min_x, max_x, BitDepthManager::BitDepth(UpdateType,XPositionUpdateEntryID));
|
|
memory_stream->ReadBitsToScaledFloat(position.z, min_z, max_z, BitDepthManager::BitDepth(UpdateType,ZPositionUpdateEntryID));
|
|
|
|
UnitQuaternion rot;
|
|
rot = flag->GetLocalToWorld();
|
|
|
|
LinearMatrix4D new_mat;
|
|
new_mat.BuildTranslation(position);
|
|
new_mat.BuildRotation(rot);
|
|
|
|
flag->SetNewLocalToParent(new_mat);
|
|
flag->SyncMatrices(true);
|
|
|
|
}
|
|
else if (mode == ServerObjectMode)
|
|
{
|
|
|
|
WORD object_id;
|
|
memory_stream->ReadBits(&object_id, 16);
|
|
|
|
ReplicatorID obj_id(Connection::Server->GetID(), object_id);
|
|
|
|
// if we are not connected to the right object
|
|
if (flag->Attached() && flag->Attached()->GetReplicatorID().localID != object_id)
|
|
{
|
|
flag->Attach(NULL);
|
|
}
|
|
|
|
// if we are not connected
|
|
if (flag->Attached() == NULL)
|
|
{
|
|
// find the object...
|
|
|
|
Connection *conn = Network::GetInstance()->GetConnection(Connection::Server->GetID());
|
|
|
|
if (conn != NULL)
|
|
{
|
|
Entity *entity = Cast_Object(Entity*, conn->FindReplicator(obj_id));
|
|
if (entity)
|
|
flag->Attach(entity);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WORD object_id = 0; // jcem: critical error - should clear before ReadBits(...)...
|
|
memory_stream->ReadBits(&object_id, 8);
|
|
|
|
if (flag->Attached() && flag->Attached()->GetReplicatorID().connectionID != object_id)
|
|
{
|
|
flag->Attach(NULL);
|
|
}
|
|
|
|
if (flag->Attached() == NULL)
|
|
{
|
|
|
|
|
|
Entity *entity = NULL;
|
|
if (MWApplication::GetInstance()->servedConnectionData[object_id].clientPlayer)
|
|
entity = MWApplication::GetInstance()->servedConnectionData[object_id].clientPlayer->vehicle;
|
|
|
|
if (entity)
|
|
flag->Attach(entity);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void FlagUpdate::Skip(MemoryStream *memory_stream, int , Time till, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(memory_stream);
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
bool flags_as_nav_points;
|
|
memory_stream->ReadBit(flags_as_nav_points);
|
|
|
|
int flags_enabled(0);
|
|
memory_stream->ReadBits(&flags_enabled,2);
|
|
|
|
int size = table->nameTableArray[NameTable::FlagArray].GetLength ();
|
|
for (int objective=0;objective<size;objective++)
|
|
{
|
|
NameTableEntry *data;
|
|
|
|
data = &table->nameTableArray [NameTable::FlagArray][objective];
|
|
|
|
Flag *flag;
|
|
|
|
Entity *ent;
|
|
ent = data->dataPointer->GetCurrent ();
|
|
if (ent)
|
|
{
|
|
|
|
flag = Cast_Object (Flag *,ent);
|
|
Check_Object (flag);
|
|
|
|
bool visible;
|
|
|
|
memory_stream->ReadBit(visible);
|
|
|
|
if (visible)
|
|
{
|
|
int last_event = 0;
|
|
memory_stream->ReadBits(&last_event,2);
|
|
|
|
int mode = 0;
|
|
memory_stream->ReadBits(&mode,2);
|
|
|
|
if (mode == GroundMode)
|
|
{
|
|
Scalar min_z, max_z, min_x, max_x;
|
|
Map::GetInstance()->GetMapExtents(&min_z, &max_z, &min_x, &max_x);
|
|
|
|
int throw_away;
|
|
memory_stream->ReadBits(&throw_away, BitDepthManager::BitDepth(UpdateType,XPositionUpdateEntryID));
|
|
memory_stream->ReadBits(&throw_away, BitDepthManager::BitDepth(UpdateType,ZPositionUpdateEntryID));
|
|
|
|
}
|
|
else if (mode == ServerObjectMode)
|
|
{
|
|
|
|
int object_id;
|
|
memory_stream->ReadBits(&object_id, 16);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
int object_id;
|
|
memory_stream->ReadBits(&object_id, 8);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int FlagUpdate::MaxSize(Entity *entity, int debug_level, int bandwidth)
|
|
{
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
int table_size = table->nameTableArray[NameTable::NavArray].GetLength ();
|
|
|
|
int size_per_entry = BitDepthManager::BitDepth(UpdateType,XPositionUpdateEntryID) + 5;
|
|
|
|
return ((table_size * size_per_entry) + 3);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void FlagUpdate::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
|
|
NameTable *table = NameTable::GetInstance();
|
|
Check_Object (table);
|
|
|
|
MWMission* mwmission = Cast_Object(MWMission*,MWMission::GetInstance());
|
|
|
|
memory_stream->WriteBit(mwmission->GetFlagsAsNavPoints());
|
|
|
|
MWMission::FLAG_ENABLE_STATE flags_enabled(mwmission->GetFlagsEnabled());
|
|
memory_stream->WriteBits(&flags_enabled,2);
|
|
|
|
int size = table->nameTableArray[NameTable::FlagArray].GetLength ();
|
|
for (int objective=0;objective<size;objective++)
|
|
{
|
|
NameTableEntry *data;
|
|
|
|
data = &table->nameTableArray [NameTable::FlagArray][objective];
|
|
|
|
Flag *flag;
|
|
|
|
Entity *ent;
|
|
ent = data->dataPointer->GetCurrent ();
|
|
if (ent)
|
|
{
|
|
|
|
flag = Cast_Object (Flag *,ent);
|
|
Check_Object (flag);
|
|
|
|
bool visible = flag->IsVisible();
|
|
|
|
memory_stream->WriteBit(visible);
|
|
|
|
if (visible)
|
|
{
|
|
int last_event = (int)flag->GetLastFlagEvent();
|
|
memory_stream->WriteBits(&last_event,2);
|
|
|
|
Entity *attached_to = flag->Attached();
|
|
|
|
int mode = GroundMode;
|
|
|
|
if (!attached_to)
|
|
{
|
|
mode = GroundMode;
|
|
memory_stream->WriteBits(&mode,2);
|
|
|
|
Point3D position;
|
|
position = flag->GetLocalToWorld();
|
|
|
|
Scalar min_z, max_z, min_x, max_x;
|
|
Map::GetInstance()->GetMapExtents(&min_z, &max_z, &min_x, &max_x);
|
|
|
|
memory_stream->WriteScaledFloatToBits(position.x, min_x, max_x, BitDepthManager::BitDepth(UpdateType,XPositionUpdateEntryID));
|
|
memory_stream->WriteScaledFloatToBits(position.z, min_z, max_z, BitDepthManager::BitDepth(UpdateType,ZPositionUpdateEntryID));
|
|
|
|
}
|
|
else if (attached_to->GetReplicatorID().connectionID == Connection::Server->GetID())
|
|
{
|
|
mode = ServerObjectMode;
|
|
memory_stream->WriteBits(&mode,2);
|
|
|
|
int object_id = attached_to->GetReplicatorID().localID;
|
|
memory_stream->WriteBits(&object_id, 16);
|
|
|
|
}
|
|
else
|
|
{
|
|
mode = PlayerMode;
|
|
memory_stream->WriteBits(&mode,2);
|
|
|
|
int object_id = attached_to->GetReplicatorID().connectionID;
|
|
memory_stream->WriteBits(&object_id, 8);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//====================================================================================================================================================
|
|
//
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void TimeUpdate::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
Scalar mission_time;
|
|
memory_stream->ReadBits(&mission_time, 32);
|
|
|
|
mission_time += packet_latency;
|
|
|
|
MWMission *mission = Cast_Object(MWMission*, MWMission::GetInstance());
|
|
mission->SetNetworkTime(mission_time);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void TimeUpdate::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(memory_stream);
|
|
|
|
|
|
Scalar mission_time;
|
|
memory_stream->ReadBits(&mission_time, 32);
|
|
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int TimeUpdate::MaxSize(Entity *entity, int debug_level, int bandwidth)
|
|
{
|
|
return 32;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void TimeUpdate::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
|
|
//SPEW(("jerryeds",""));
|
|
|
|
MWMission *mission = Cast_Object(MWMission*, MWMission::GetInstance());
|
|
|
|
Scalar mission_time;
|
|
mission_time = mission->GetMissionTime();
|
|
memory_stream->WriteBits(&mission_time, 32);
|
|
|
|
|
|
}
|
|
//====================================================================================================================================================
|
|
//
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void PingUpdate::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
|
|
Scalar ping_time;
|
|
|
|
memory_stream->ReadBitsToScaledFloat(ping_time, 0.0f, 10000.0f, 8);
|
|
MWApplication::GetInstance()->servedConnectionData[entity->GetReplicatorID().connectionID].effectivePing = ping_time;
|
|
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void PingUpdate::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(memory_stream);
|
|
|
|
|
|
Scalar ping_time;
|
|
memory_stream->ReadBits(&ping_time, 8);
|
|
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int PingUpdate::MaxSize(Entity *entity, int debug_level, int bandwidth)
|
|
{
|
|
return 8;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void PingUpdate::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
Scalar ping_time;
|
|
ping_time = MWApplication::GetInstance()->servedConnectionData[entity->GetReplicatorID().connectionID].averagePing.CalculateAverage();
|
|
|
|
Clamp(ping_time, 0, 10000.0f);
|
|
memory_stream->WriteScaledFloatToBits(ping_time, 0.0f, 10000.0f, 8);
|
|
|
|
|
|
|
|
}
|
|
//====================================================================================================================================================
|
|
//
|
|
|
|
void __cdecl MechWarrior4::NetGenericMessagesSecurityCheckStart(void)
|
|
{
|
|
_asm
|
|
{
|
|
nop
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//define USE_HACK_CRC 1
|
|
|
|
#ifdef USE_HACK_CRC
|
|
|
|
#include "crckey.hpp"
|
|
|
|
void *security_array[] =
|
|
{
|
|
(void*)&sequirity_0[0],
|
|
(void*)&sequirity_1[0],
|
|
(void*)&sequirity_2[0],
|
|
(void*)&sequirity_3[0],
|
|
(void*)&sequirity_4[0],
|
|
(void*)&sequirity_5[0],
|
|
(void*)&sequirity_6[0],
|
|
(void*)&sequirity_7[0],
|
|
(void*)&sequirity_8[0],
|
|
(void*)&sequirity_9[0],
|
|
(void*)&sequirity_10[0],
|
|
(void*)&sequirity_11[0],
|
|
(void*)&sequirity_12[0],
|
|
(void*)&sequirity_13[0],
|
|
(void*)&sequirity_14[0]
|
|
};
|
|
|
|
DWORD security_length[] =
|
|
{
|
|
(DWORD)ELEMENTS(sequirity_0)<<2,
|
|
(DWORD)ELEMENTS(sequirity_1)<<2,
|
|
(DWORD)ELEMENTS(sequirity_2)<<2,
|
|
(DWORD)ELEMENTS(sequirity_3)<<2,
|
|
(DWORD)ELEMENTS(sequirity_4)<<2,
|
|
(DWORD)ELEMENTS(sequirity_5)<<2,
|
|
(DWORD)ELEMENTS(sequirity_6)<<2,
|
|
(DWORD)ELEMENTS(sequirity_7)<<2,
|
|
(DWORD)ELEMENTS(sequirity_8)<<2,
|
|
(DWORD)ELEMENTS(sequirity_9)<<2,
|
|
(DWORD)ELEMENTS(sequirity_10)<<2,
|
|
(DWORD)ELEMENTS(sequirity_11)<<2,
|
|
(DWORD)ELEMENTS(sequirity_12)<<2,
|
|
(DWORD)ELEMENTS(sequirity_13)<<2,
|
|
(DWORD)ELEMENTS(sequirity_14)<<2
|
|
};
|
|
|
|
#else
|
|
|
|
void *security_array[] =
|
|
{
|
|
(void*)&MD5SecurityCheckStart,
|
|
(void*)&AdeptDamageSecurityCheckStart,
|
|
(void*)&AdeptGlobalPointerSecurityCheckStart,
|
|
(void*)&BucketSecurityCheckStart,
|
|
(void*)&MW4DamageSecurityCheckStart,
|
|
(void*)&VehicleInterfaceSecurityCheckStart,
|
|
(void*)&VehicleSecurityCheckStart,
|
|
(void*)&MechSecurityCheckStart,
|
|
(void*)&WeaponMoverSecurityCheckStart,
|
|
(void*)&HeatSecurityCheckStart,
|
|
(void*)&JumpJetSecurityCheckStart,
|
|
(void*)&WeaponSecurityCheckStart,
|
|
(void*)&NetMovementSecurityCheckStart,
|
|
(void*)&NetWeaponSecurityCheckStart,
|
|
(void*)&NetGenericMessagesSecurityCheckStart
|
|
};
|
|
|
|
|
|
|
|
DWORD security_length[] =
|
|
{
|
|
(DWORD)&MD5SecurityCheckStop - (DWORD)&MD5SecurityCheckStart,
|
|
(DWORD)&AdeptDamageSecurityCheckStop - (DWORD)&AdeptDamageSecurityCheckStart,
|
|
(DWORD)&AdeptGlobalPointerSecurityCheckStop - (DWORD)&AdeptGlobalPointerSecurityCheckStart,
|
|
(DWORD)&BucketSecurityCheckStop - (DWORD)&BucketSecurityCheckStart,
|
|
(DWORD)&MW4DamageSecurityCheckStop - (DWORD)&MW4DamageSecurityCheckStart,
|
|
(DWORD)&VehicleInterfaceSecurityCheckStop - (DWORD)&VehicleInterfaceSecurityCheckStart,
|
|
(DWORD)&VehicleSecurityCheckStop - (DWORD)&VehicleSecurityCheckStart,
|
|
(DWORD)&MechSecurityCheckStop - (DWORD)&MechSecurityCheckStart,
|
|
(DWORD)&WeaponMoverSecurityCheckStop - (DWORD)&WeaponMoverSecurityCheckStart,
|
|
(DWORD)&HeatSecurityCheckStop - (DWORD)&HeatSecurityCheckStart,
|
|
(DWORD)&JumpJetSecurityCheckStop - (DWORD)&JumpJetSecurityCheckStart,
|
|
(DWORD)&WeaponSecurityCheckStop - (DWORD)&WeaponSecurityCheckStart,
|
|
(DWORD)&NetMovementSecurityCheckStop - (DWORD)&NetMovementSecurityCheckStart,
|
|
(DWORD)&NetWeaponSecurityCheckStop - (DWORD)&NetWeaponSecurityCheckStart,
|
|
(DWORD)&NetGenericMessagesSecurityCheckStop - (DWORD)&NetGenericMessagesSecurityCheckStart
|
|
};
|
|
|
|
#endif
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void SecurityQuery::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth)
|
|
{
|
|
//Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
int key = 0;
|
|
memory_stream->ReadBits(&key, 16);
|
|
|
|
SecurityQueryInfo *seq_info;
|
|
MWEntityManager *manger = (MWEntityManager*)MWEntityManager::GetInstance();
|
|
if (MWApplication::GetInstance()->serverFlag)
|
|
{
|
|
seq_info = &manger->serverController->securityQuery[connection];
|
|
}
|
|
else
|
|
{
|
|
seq_info = &manger->clientController->securityQuery;
|
|
}
|
|
|
|
|
|
seq_info->otherSidesKey = key;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void SecurityQuery::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(memory_stream);
|
|
|
|
|
|
int key = 0;
|
|
memory_stream->ReadBits(&key, 16);
|
|
|
|
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int SecurityQuery::MaxSize(Entity *entity, int debug_level, int bandwidth)
|
|
{
|
|
return 16;
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void SecurityQuery::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
|
|
{
|
|
|
|
SecurityQueryInfo *seq_info;
|
|
MWEntityManager *manger = (MWEntityManager*)MWEntityManager::GetInstance();
|
|
if (MWApplication::GetInstance()->serverFlag)
|
|
{
|
|
seq_info = &manger->serverController->securityQuery[connection];
|
|
}
|
|
else
|
|
{
|
|
seq_info = &manger->clientController->securityQuery;
|
|
}
|
|
|
|
|
|
memory_stream->WriteBits(&seq_info->securityKey, 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KickPlayer(int connection)
|
|
{
|
|
//SPEW(("jerryeds", "KICK PLAYER"));
|
|
|
|
if (MWApplication::GetInstance()->serverFlag)
|
|
{
|
|
MWApplication::GetInstance()->servedConnectionData[connection].clientQuedForKick = true;
|
|
}
|
|
else
|
|
{
|
|
MWApplication::GetInstance()->networkExitCode = MWApplication::BadServerExitCode;
|
|
MWApplication::GetInstance()->QueStopGame(true);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//====================================================================================================================================================
|
|
//
|
|
|
|
|
|
void SecurityResponse::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth)
|
|
{
|
|
//Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
|
|
|
|
int key = 0;
|
|
WORD client_answer = 0;
|
|
|
|
memory_stream->ReadBits(&key, 16);
|
|
memory_stream->ReadBits(&client_answer, 16);
|
|
|
|
|
|
bool server_flag = MWApplication::GetInstance()->serverFlag;
|
|
|
|
|
|
SecurityQueryInfo *seq_info;
|
|
MWEntityManager *manger = (MWEntityManager*)MWEntityManager::GetInstance();
|
|
if (server_flag)
|
|
{
|
|
seq_info = &manger->serverController->securityQuery[connection];
|
|
}
|
|
else
|
|
{
|
|
seq_info = &manger->clientController->securityQuery;
|
|
}
|
|
|
|
|
|
GUID null_hash;
|
|
memset(&null_hash, 0, sizeof(null_hash));
|
|
|
|
|
|
if (seq_info->needInit)
|
|
{
|
|
seq_info->needInit = false;
|
|
// we need an init!
|
|
MD5_CTX resource_context;
|
|
GUID new_code_hash;
|
|
unsigned char * buff=(unsigned char *) &new_code_hash;
|
|
|
|
|
|
MD5Init(&resource_context);
|
|
int new_key = 0;
|
|
|
|
for (int i = 0; i < ELEMENTS(security_array); ++i)
|
|
{
|
|
MD5Update(&resource_context, (unsigned char *) security_array[i], security_length[i]);
|
|
MD5Update(&resource_context, (unsigned char *) &key, 4);
|
|
}
|
|
|
|
MD5Final(buff, &resource_context);
|
|
|
|
seq_info->securityKey = new_key;
|
|
seq_info->securityAnswer = new_code_hash;
|
|
seq_info->securityTimer = (Scalar)gos_GetElapsedTime();
|
|
seq_info->lastSecurityKey = new_key;
|
|
seq_info->lastSecurityAnswer = new_code_hash;
|
|
|
|
}
|
|
|
|
|
|
if (key == seq_info->securityKey)
|
|
{
|
|
//if (memcmp(&code_hash, &seq_info->securityAnswer, sizeof(code_hash)) != 0)
|
|
|
|
WORD server_answer=0;
|
|
WORD *break_down = (WORD*)&seq_info->securityAnswer;
|
|
for (int i = 0; i < 8; ++i)
|
|
{
|
|
server_answer ^= break_down[i];
|
|
}
|
|
|
|
if (client_answer != server_answer)
|
|
{
|
|
// KICK PLAYER
|
|
//STOP(("KICK PLAYER"));
|
|
|
|
KickPlayer(connection);
|
|
}
|
|
else
|
|
{
|
|
// roll a new key
|
|
seq_info->lastSecurityKey = seq_info->securityKey;
|
|
seq_info->lastSecurityAnswer = seq_info->securityAnswer;
|
|
|
|
|
|
MD5_CTX resource_context;
|
|
GUID new_code_hash;
|
|
unsigned char * buff=(unsigned char *) &new_code_hash;
|
|
|
|
|
|
MD5Init(&resource_context);
|
|
int temp = Random::GetInt();
|
|
|
|
int new_key = temp >> 16;
|
|
new_key ^= (temp&0xffff);
|
|
|
|
|
|
for (int i = 0; i < ELEMENTS(security_array); ++i)
|
|
{
|
|
MD5Update(&resource_context, (unsigned char *) security_array[i], security_length[i]);
|
|
MD5Update(&resource_context, (unsigned char *) &new_key, 4);
|
|
}
|
|
|
|
MD5Final(buff, &resource_context);
|
|
|
|
|
|
seq_info->securityKey = new_key;
|
|
seq_info->securityAnswer = new_code_hash;
|
|
seq_info->securityTimer = (Scalar)gos_GetElapsedTime();
|
|
|
|
|
|
}
|
|
}
|
|
else if (key == seq_info->lastSecurityKey)
|
|
{
|
|
WORD server_answer=0;
|
|
WORD *break_down = (WORD*)&seq_info->lastSecurityAnswer;
|
|
for (int i = 0; i < 8; ++i)
|
|
{
|
|
server_answer ^= break_down[i];
|
|
}
|
|
|
|
if (client_answer != server_answer)
|
|
{
|
|
// KICK PLAYER
|
|
KickPlayer(connection);
|
|
}
|
|
else
|
|
{
|
|
// check the timer...
|
|
Scalar current_time = (Scalar)gos_GetElapsedTime();
|
|
if (current_time-seq_info->securityTimer > 75.0f + packet_latency)
|
|
{
|
|
KickPlayer(connection);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
KickPlayer(connection);
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void SecurityResponse::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
|
|
{
|
|
Check_Object(memory_stream);
|
|
|
|
|
|
|
|
int key = 0;
|
|
|
|
memory_stream->ReadBits(&key, 16);
|
|
memory_stream->ReadBits(&key, 16);
|
|
|
|
|
|
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int SecurityResponse::MaxSize(Entity *entity, int debug_level, int bandwidth)
|
|
{
|
|
return 32;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void SecurityResponse::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
|
|
{
|
|
//Check_Object(entity);
|
|
Check_Object(memory_stream);
|
|
|
|
|
|
Verify(ELEMENTS(security_array) == ELEMENTS(security_length));
|
|
|
|
MD5_CTX resource_context;
|
|
GUID code_hash;
|
|
unsigned char * buff=(unsigned char *) &code_hash;
|
|
|
|
|
|
SecurityQueryInfo *seq_info;
|
|
MWEntityManager *manger = (MWEntityManager*)MWEntityManager::GetInstance();
|
|
if (MWApplication::GetInstance()->serverFlag)
|
|
{
|
|
seq_info = &manger->serverController->securityQuery[connection];
|
|
}
|
|
else
|
|
{
|
|
seq_info = &manger->clientController->securityQuery;
|
|
}
|
|
|
|
|
|
MD5Init(&resource_context);
|
|
int key = seq_info->otherSidesKey;
|
|
|
|
for (int i = 0; i < ELEMENTS(security_array); ++i)
|
|
{
|
|
MD5Update(&resource_context, (unsigned char *) security_array[i], security_length[i]);
|
|
MD5Update(&resource_context, (unsigned char *) &key, 4);
|
|
}
|
|
MD5Final(buff, &resource_context);
|
|
|
|
WORD *break_down = (WORD*)&code_hash;
|
|
memory_stream->WriteBits(&key, 16);
|
|
|
|
WORD result = 0;
|
|
for (i = 0; i < 8; ++i)
|
|
{
|
|
result ^= break_down[i];
|
|
}
|
|
|
|
|
|
memory_stream->WriteBits(&result, 16);
|
|
|
|
//SPEW(("jerryeds", "SEC_RESP ENCODE : %d :%d, %u-%u-%u-%u", Connection::Local->GetID(), key, break_down[0], break_down[1],break_down[2],break_down[3]));
|
|
|
|
}
|
|
|
|
|
|
|
|
__int64 MechWarrior4::CalculateCodeHash(int key)
|
|
{
|
|
MD5_CTX resource_context;
|
|
GUID code_hash;
|
|
unsigned char * buff=(unsigned char *) &code_hash;
|
|
|
|
|
|
MD5Init(&resource_context);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < ELEMENTS(security_array); ++i)
|
|
{
|
|
|
|
|
|
|
|
MD5Update(&resource_context, (unsigned char *) security_array[i], security_length[i]);
|
|
MD5Update(&resource_context, (unsigned char *) &key, 4);
|
|
}
|
|
MD5Final(buff, &resource_context);
|
|
|
|
__int64 *break_down = (__int64*)&code_hash;
|
|
|
|
__int64 final = break_down[0] ^ break_down[1];
|
|
|
|
return final;
|
|
|
|
}
|
|
|
|
|
|
void __cdecl MechWarrior4::NetGenericMessagesSecurityCheckStop()
|
|
{
|
|
_asm
|
|
{
|
|
nop
|
|
}
|
|
}
|
|
|
|
|