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.
1529 lines
48 KiB
C++
1529 lines
48 KiB
C++
//===========================================================================//
|
|
// File: NetClientServerController.hpp
|
|
// Contents : All movement messages and rewind capabilites
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 01/18/1999 JSE Inital coding
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1998, Microsoft Corp. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "MW4Headers.hpp"
|
|
|
|
#include "NetClientServerController.hpp"
|
|
#include "MWEntityManager.hpp"
|
|
#include "MWApplication.hpp"
|
|
#include "Mech.hpp"
|
|
#include "Torso.hpp"
|
|
#include "VehicleInterface.hpp"
|
|
#include "MWPlayer.hpp"
|
|
#include "Weapon.hpp"
|
|
#include "MissileWeapon.hpp"
|
|
#include "SubsystemClassData.hpp"
|
|
|
|
#include <Adept\CollisionGrid.hpp>
|
|
#include <Adept\Site.hpp>
|
|
|
|
#include <Adept\Map.hpp>
|
|
#include <Adept\NetStatCollector.hpp>
|
|
|
|
// for OutputDebugString^^
|
|
#include <windows.h>
|
|
#undef min
|
|
#undef max
|
|
// for OutputDebugString^^
|
|
#define DIRECTINPUT_VERSION 0x700
|
|
#include <dinput.h>
|
|
#include <dsetup.h>
|
|
#include <dsound.h>
|
|
#include <d3d.h>
|
|
#include <dplay.h>
|
|
#include <dplobby.h>
|
|
|
|
#pragma warning( disable: 4201 ) // nameless struct/union (again - something reenables this!)
|
|
#include <amstream.h>
|
|
#include <control.h>
|
|
#include <process.h>
|
|
#include <mmreg.h>
|
|
#include <msacm.h>
|
|
#ifndef __IDDrawExclModeVideo_FWD_DEFINED__
|
|
#error DirectX Media 6.0 SDK is required
|
|
#endif
|
|
|
|
#include "gameos\Net_header.hpp"
|
|
#include "gameos\mreplay.h"
|
|
#include "mreplay2.h"
|
|
extern bool g_bCOOP;
|
|
|
|
DWORD g_clientControlPackets;
|
|
DWORD g_clientPacketsWaitingConfirmation;
|
|
DWORD g_clientForgotenPackets;
|
|
DWORD g_clientSkippedPackets;
|
|
DWORD g_clientTimedOutPackets;
|
|
DWORD g_clientLatePackets;
|
|
DWORD g_clientFullConfirms;
|
|
DWORD g_clientSmallConfirms;
|
|
|
|
DWORD g_serverControlsApplied;
|
|
DWORD g_serverFullRetransmits;
|
|
DWORD g_serverSmallRetransmits;
|
|
DWORD g_serverPacketsOutOfRange;
|
|
DWORD g_serverFullConfirms;
|
|
DWORD g_serverSmallConfirms;
|
|
DWORD g_serverTimeOuts;
|
|
|
|
SecurityQueryInfo::SecurityQueryInfo()
|
|
{
|
|
lastSecurityKey = 0;
|
|
memset(&lastSecurityAnswer,0,sizeof(lastSecurityAnswer));
|
|
securityKey = 0;
|
|
memset(&securityAnswer,0,sizeof(securityAnswer));
|
|
securityTimer = 0;
|
|
otherSidesKey = 0;
|
|
needInit = true;
|
|
}
|
|
|
|
void SecurityQueryInfo::Reset(void)
|
|
{
|
|
lastSecurityKey = 0;
|
|
memset(&lastSecurityAnswer,0,sizeof(lastSecurityAnswer));
|
|
securityKey = 0;
|
|
memset(&securityAnswer,0,sizeof(securityAnswer));
|
|
securityTimer = 0;
|
|
otherSidesKey = 0;
|
|
needInit = true;
|
|
}
|
|
|
|
|
|
Point3D ClampPoint(Point3D origin, Point3D target, Point3D min_box, Point3D max_box)
|
|
{
|
|
|
|
Verify(origin.x > min_box.x);
|
|
Verify(origin.z > min_box.z);
|
|
Verify(origin.x < max_box.x);
|
|
Verify(origin.z < max_box.z);
|
|
|
|
Verify(origin != target);
|
|
|
|
if (origin == target)
|
|
return target;
|
|
|
|
Scalar original_y = target.y;
|
|
|
|
|
|
origin.y = 0.0f;
|
|
target.y = 0.0f;
|
|
min_box.y = 0.0f;
|
|
max_box.y = 0.0f;
|
|
|
|
|
|
Vector3D vec;
|
|
vec.Subtract(target,origin);
|
|
|
|
UnitVector3D u_vec;
|
|
u_vec = vec;
|
|
Line3D line(origin, u_vec, vec.GetLength());
|
|
|
|
Scalar max_distance = line.m_length;
|
|
|
|
Scalar distance;
|
|
|
|
if (target.x > max_box.x)
|
|
{
|
|
distance = Abs((max_box.x - origin.x) / line.m_direction.x);
|
|
if (distance < max_distance)
|
|
{
|
|
max_distance = distance;
|
|
}
|
|
}
|
|
else if (target.x < min_box.x)
|
|
{
|
|
distance = Abs((min_box.x - origin.x) / line.m_direction.x);
|
|
if (distance < max_distance)
|
|
{
|
|
max_distance = distance;
|
|
}
|
|
}
|
|
|
|
if (target.z > max_box.z)
|
|
{
|
|
|
|
distance = Abs((max_box.z - origin.z) / line.m_direction.z);
|
|
if (distance < max_distance)
|
|
{
|
|
max_distance = distance;
|
|
}
|
|
}
|
|
else if (target.z < min_box.z)
|
|
{
|
|
distance = Abs((min_box.x - origin.z) / line.m_direction.z);
|
|
if (distance < max_distance)
|
|
{
|
|
max_distance = distance;
|
|
}
|
|
}
|
|
|
|
line.m_length = max_distance * 0.9f;
|
|
|
|
|
|
Point3D end_point;
|
|
line.FindEnd(&end_point);
|
|
|
|
Verify(end_point.x <= max_box.x);
|
|
Verify(end_point.x >= min_box.x);
|
|
Verify(end_point.z <= max_box.z);
|
|
Verify(end_point.z >= min_box.z);
|
|
|
|
end_point.y = original_y;
|
|
|
|
return end_point;
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
|
|
|
|
ServerController::ServerController()
|
|
{
|
|
|
|
m_EntityManager = Cast_Object(MWEntityManager*, EntityManager::GetInstance());
|
|
|
|
for (int i = 0; i < Maximum_Players; ++i)
|
|
{
|
|
lastControlPacketID[i] = 0;
|
|
lastPingDelta[i] = 0.0f;
|
|
lastControlPacket[i] = 0.0f;
|
|
lastControlPacketLocal[i] = (float)gos_GetElapsedTime(1);
|
|
lastTimeFailure[i] = (float)gos_GetElapsedTime(1);
|
|
lastReportedPosition[i] = Point3D::HellPoint;
|
|
positionErrors[i] = 0;
|
|
waitingForRespawn[i] = true;
|
|
clockDifference[i] = 0.0f;
|
|
lowestLatency[i] = 1000000.0f;
|
|
latencyDelay[i] = 0;
|
|
|
|
securityQuery[i].Reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
ServerController::~ServerController()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
void ServerController::Reset()
|
|
{
|
|
|
|
|
|
for (int i = 0; i < Maximum_Players; ++i)
|
|
{
|
|
lastControlPacketID[i] = 0;
|
|
lastPingDelta[i] = 0.0f;
|
|
lastControlPacket[i] = 0.0f;
|
|
lastControlPacketLocal[i] = (float)gos_GetElapsedTime(1);
|
|
lastTimeFailure[i] = (float)gos_GetElapsedTime(1);
|
|
lastReportedPosition[i] = Point3D::HellPoint;
|
|
positionErrors[i] = 0;
|
|
waitingForRespawn[i] = true;
|
|
clockDifference[i] = 0.0f;
|
|
lowestLatency[i] = 1000000.0f;
|
|
latencyDelay[i] = 0;
|
|
|
|
securityQuery[i].Reset();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void ServerController::ResetClient(int connection_id)
|
|
{
|
|
lastControlPacketID[connection_id] = 0;
|
|
lastPingDelta[connection_id] = 0.0f;
|
|
lastControlPacket[connection_id] = 0.0f;
|
|
lastControlPacketLocal[connection_id] = (float)gos_GetElapsedTime(1);
|
|
lastTimeFailure[connection_id] = (float)gos_GetElapsedTime(1);
|
|
lastReportedPosition[connection_id] = Point3D::HellPoint;
|
|
positionErrors[connection_id] = 0;
|
|
waitingForRespawn[connection_id] = true;
|
|
clockDifference[connection_id] = 0.0f;
|
|
lowestLatency[connection_id] = 1000000.0f;
|
|
latencyDelay[connection_id] = 0;
|
|
|
|
securityQuery[connection_id].Reset();
|
|
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void ServerController::ReceivePlayerControl(int connection, Stuff::MemoryStream *message)
|
|
{
|
|
|
|
MWEntityManager *manager = Cast_Object (MWEntityManager*, MWEntityManager::GetInstance());
|
|
|
|
ThrottleTest(connection);
|
|
|
|
Mech *vehicle = (Mech *) manager->playerVehicle[connection];
|
|
|
|
int bandwidth = 0;
|
|
|
|
if (vehicle != NULL)
|
|
{
|
|
|
|
Scalar old_speed = vehicle->currentSpeedMPS;
|
|
|
|
Scalar packet_time = 0;
|
|
double latency = 0;
|
|
double better_latency = 0;
|
|
|
|
DictionaryManager *dictionary_manager = manager->GetDictionaryManager(connection);
|
|
if(dictionary_manager != NULL)
|
|
{
|
|
int version = 0;
|
|
message->ReadBits(&version,8);
|
|
|
|
BYTE packet_number;
|
|
message->ReadBits(&packet_number,8);
|
|
|
|
|
|
if (MWEntityManager::IsNumberBehind(packet_number, lastControlPacketID[connection], 40, 255))
|
|
{
|
|
//SPEWALWAYS(("jerryeds", "LATE CONTROL PACKET THROWN OUT"));
|
|
return;
|
|
}
|
|
|
|
// calculate ping...
|
|
|
|
//t1-t2
|
|
Scalar t2_minus_t1;
|
|
message->ReadBits(&t2_minus_t1, 32);
|
|
Scalar t3;
|
|
Scalar t4 = (float)(gos_GetElapsedTime(1) * 1000.0);
|
|
message->ReadBits(&t3, 32);
|
|
lastPingDelta[connection] = t4 - t3;
|
|
|
|
|
|
//SPEWALWAYS(("jerryeds", "S-REC - %d : t2-t1 : %f, t4-t3 %f : t3 : %f t4 : %f", packet_number, t2_minus_t1, t4 - t3, t3, t4));
|
|
|
|
|
|
MWApplication::GetInstance()->servedConnectionData[connection].effectivePing = t2_minus_t1 + (t4 - t3);
|
|
MWApplication::GetInstance()->servedConnectionData[connection].averagePing.Add(MWApplication::GetInstance()->servedConnectionData[connection].effectivePing);
|
|
|
|
latency = MWApplication::GetInstance()->servedConnectionData[connection].effectivePing * 0.5f;
|
|
|
|
bool do_clock_sync = true;
|
|
if (latency < 0.0f)
|
|
do_clock_sync = false;
|
|
|
|
Min_Clamp(latency, 0.01f);
|
|
latency *= 0.001f;
|
|
|
|
|
|
packet_time = t3 * 0.001f;
|
|
|
|
|
|
|
|
double current_time = gos_GetElapsedTime(1);
|
|
|
|
|
|
if (do_clock_sync && latencyDelay[connection] > 5 )
|
|
{
|
|
if (latency < lowestLatency[connection])
|
|
{
|
|
lowestLatency[connection] = latency;
|
|
clockDifference[connection] = current_time - (packet_time + latency);
|
|
//SPEWALWAYS(("jerryeds", "new clock diff %f", clockDifference[connection]));
|
|
}
|
|
}
|
|
else if (do_clock_sync)
|
|
{
|
|
clockDifference[connection] = current_time - (packet_time + latency);
|
|
//SPEWALWAYS(("jerryeds", "DELAY - new clock diff %f", clockDifference[connection]));
|
|
++latencyDelay[connection];
|
|
}
|
|
|
|
|
|
|
|
//latency now equals current_time - packet_time+clock_difference
|
|
|
|
better_latency = current_time - (packet_time + clockDifference[connection]);
|
|
//SPEWALWAYS(("jerryeds", "better latency %f : orig: %f diff: %f\n", better_latency, latency, better_latency - latency));
|
|
|
|
//latency = better_latency;
|
|
|
|
Min_Clamp(latency, 0.00001f);
|
|
Min_Clamp(better_latency, 0.00001f);
|
|
|
|
// clockDifference[connection] - (current_time - (packet_time + latency))
|
|
//
|
|
|
|
//SPEWALWAYS(("jerryeds", "local:%f client:%f clock_adj:%f", current_time, packet_time, clockDifference[connection] ));
|
|
|
|
|
|
//MWApplication::GetInstance()->servedConnectionData[connection].effectivePing = (float)(latency * 2.0 * 1000.0);
|
|
|
|
//doesn't get executed due to the above clamp and never has. I can remove this, but am not for compile consistancy.
|
|
if (do_clock_sync && latency < 0.0f)
|
|
{
|
|
clockDifference[connection] += latency;
|
|
//SPEWALWAYS(("jerryeds", "clock adj : %f", clockDifference[connection]));
|
|
}
|
|
|
|
|
|
lastControlPacketID[connection] = packet_number;
|
|
|
|
// used to be GetVersion, but that will cause packets to not be read for no reason.
|
|
Dictionary *dictionary = dictionary_manager->GetCurrentDictionary();
|
|
|
|
if (dictionary != NULL)
|
|
{
|
|
|
|
bandwidth = dictionary->dictionaryBandwidth;
|
|
|
|
// if this is ahead and not more than 30 messages ahead...
|
|
|
|
int rate_type = manager->bitManager->GetUpdateRate(UpdateManager::MechPositionUpdateID, dictionary->dictionaryBandwidth).m_ActiveRate;
|
|
Scalar rate = DictionaryPage::CalculateSeconds(rate_type);
|
|
|
|
SecurityQuery::Decode(vehicle, message, 0.0, (float)latency, connection, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
MechPositionUpdate::Decode(vehicle, message, 0.0, (float)latency, connection, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth, rate);
|
|
SecurityResponse::Decode(vehicle, message, 0.0, (float)latency, connection, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
ExternalJumpJetUpdate::Decode(vehicle, message, 0.0, (float)latency, connection, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth, rate);
|
|
|
|
//MechMovemntUpdate::Decode(vehicle, message, 0.0, latency, connection, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth, rate);
|
|
//MechAnimationUpdate::Decode(vehicle, message, 0.0, latency, connection, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth, rate);
|
|
|
|
|
|
|
|
int command_count=0;
|
|
message->ReadBits(&command_count, 8);
|
|
|
|
while (command_count)
|
|
{
|
|
int command=0;
|
|
message->ReadBits(&command, 5);
|
|
|
|
vehicle->ProcessCommand(command);
|
|
command_count--;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
YawPitchRoll ypr;
|
|
vehicle->GetDeadReckonedNetworkPosition(MWApplication::GetInstance()->servedConnectionData[connection].vehiclePosition, ypr);
|
|
MWApplication::GetInstance()->servedConnectionData[connection].vehicleRotation.yaw = ypr.yaw;
|
|
|
|
Point3D current_position;
|
|
current_position = vehicle->GetLocalToWorld();
|
|
Point3D distance_traveled;
|
|
|
|
|
|
//SPEWALWAYS(("jerryeds", "MOVE COMMAND : %d", connection));
|
|
//SPEWALWAYS(("jerryeds", "CUR POS %f %f %f", current_position.x, current_position.y, current_position.z));
|
|
//SPEWALWAYS(("jerryeds", "NET POS %f %f %f", MWApplication::GetInstance()->servedConnectionData[connection].vehiclePosition.x, MWApplication::GetInstance()->servedConnectionData[connection].vehiclePosition.y, MWApplication::GetInstance()->servedConnectionData[connection].vehiclePosition.z));
|
|
|
|
|
|
|
|
|
|
if (!waitingForRespawn[connection])
|
|
{
|
|
|
|
|
|
//SPEWALWAYS((0,"CLIENT : %d", connection));
|
|
|
|
positionErrors[connection] = 0;
|
|
|
|
|
|
Point3D real_last_position = lastReportedPosition[connection];
|
|
lastReportedPosition[connection] = MWApplication::GetInstance()->servedConnectionData[connection].vehiclePosition;
|
|
|
|
|
|
//SPEWALWAYS(("jerryeds", "REAL LAST %f %f %f", real_last_position.x, real_last_position.y, real_last_position.z));
|
|
//SPEWALWAYS(("jerryeds", "LAST REPORTED %f %f %f", lastReportedPosition[connection].x, lastReportedPosition[connection].y, lastReportedPosition[connection].z));
|
|
|
|
|
|
|
|
distance_traveled.Subtract(lastReportedPosition[connection], real_last_position);
|
|
// if the mech was breaking the rules....
|
|
|
|
Scalar local_time = (Scalar)gos_GetElapsedTime(1) - (Scalar)better_latency;
|
|
|
|
|
|
Scalar local_dif = local_time-lastControlPacketLocal[connection];
|
|
Scalar remote_dif = packet_time-lastControlPacket[connection];
|
|
|
|
//SPEW(("jerryeds","TIME DIFFERENCE %f", local_dif-remote_dif));
|
|
|
|
|
|
|
|
Scalar time_dif = remote_dif - local_dif;
|
|
// jcem - Verify(fabs(time_dif) > 0.0f);
|
|
|
|
|
|
|
|
//SPEWALWAYS((0,"local_time : %f remote_time : %f", gos_GetElapsedTime(), packet_time));
|
|
|
|
//SPEWALWAYS((0,"TIME SINCE FAILURE : %f", gos_GetElapsedTime() - lastTimeFailure[connection]));
|
|
|
|
bool loose_time = true;
|
|
if (gos_GetElapsedTime(1) - lastTimeFailure[connection] < 3.0f)
|
|
{
|
|
loose_time = false;
|
|
}
|
|
|
|
//double time_since_failure = (float)gos_GetElapsedTime(1) - lastTimeFailure[connection];
|
|
|
|
if (time_dif > 0.04f)
|
|
{
|
|
lastTimeFailure[connection] = (float)gos_GetElapsedTime(1);
|
|
//SPEWALWAYS((0, "ALLOWED TIME RULE BREAKER"));
|
|
}
|
|
|
|
//SPEWALWAYS((0,"SERVER : %f - CLIENT : %f - DIF %f - latency %f\n", local_dif, remote_dif, time_dif, latency));
|
|
|
|
|
|
//SPEWALWAYS((0, "TIME DIFF %f : %f : %f", local_dif, remote_dif, fabs(time_dif)));
|
|
|
|
if (Close_Enough(real_last_position, Point3D::HellPoint, 100.0f))
|
|
{
|
|
// the real position is in hell on the server but the client got to move
|
|
// go ahead and let this one by
|
|
|
|
}
|
|
else if (loose_time && time_dif > 0.25f)
|
|
{
|
|
|
|
|
|
|
|
//Connection *conn = Network::GetInstance()->GetConnection(connection);
|
|
//DWORD que = reinterpret_cast<DWORD>(gos_NetInformation(gos_GetOutboundWindowSizeDpid, conn->GetNetworkAddress()));
|
|
|
|
lowestLatency[connection] = 0.5f;
|
|
clockDifference[connection] = gos_GetElapsedTime(1) - packet_time + 0.5f;
|
|
|
|
|
|
//SPEWALWAYS((0, "LOOSE TIME - RULE BREAK"));
|
|
//SPEWALWAYS((0,"CLIENT : %d : %s", connection, (char *)Network::GetInstance()->GetConnection(connection)->GetConnectionName()));
|
|
//SPEWALWAYS((0,"connection speed : %d", bandwidth));
|
|
//SPEWALWAYS((0,"QUE : %d", que));
|
|
//SPEWALWAYS((0, "clock_adj:%f", clockDifference[connection] ));
|
|
//SPEWALWAYS((0,"local_time : %f remote_time : %f : diff : %f", gos_GetElapsedTime(1), packet_time, gos_GetElapsedTime(1) - packet_time));
|
|
//SPEWALWAYS((0,"TIME SINCE FAILURE : %f", time_since_failure));
|
|
//SPEWALWAYS((0,"SERVER : %f - CLIENT : %f - DIF %f - latency %f", local_dif, remote_dif, time_dif, latency));
|
|
//SPEWALWAYS((0, "TIME DIFF %f : %f : %f", local_dif, remote_dif, fabs(time_dif)));
|
|
//SPEWALWAYS((0,"-----------------------------\n", connection));
|
|
|
|
|
|
//PAUSE(("RULE BREAKER"));
|
|
vehicle->ClearNetworkPosition();
|
|
vehicle->speedDemand = 0.0f;
|
|
vehicle->yawDemand = 0.0f;
|
|
vehicle->currentSpeedMPS = old_speed;
|
|
SendFullConfirmation(connection);
|
|
lastReportedPosition[connection] = vehicle->GetLocalToWorld();
|
|
|
|
}
|
|
else if (!loose_time && time_dif > 0.04f)
|
|
{
|
|
|
|
|
|
//Connection *conn = Network::GetInstance()->GetConnection(connection);
|
|
//DWORD que = reinterpret_cast<DWORD>(gos_NetInformation(gos_GetOutboundWindowSizeDpid, conn->GetNetworkAddress()));
|
|
|
|
|
|
lowestLatency[connection] = 0.5f;
|
|
clockDifference[connection] = gos_GetElapsedTime(1) - packet_time + 0.5f;
|
|
|
|
|
|
//SPEWALWAYS((0,"NO LOOSE TIME - RULE BREAKER"));
|
|
//SPEWALWAYS((0,"CLIENT : %d : %s", connection, (char *)Network::GetInstance()->GetConnection(connection)->GetConnectionName()));
|
|
//SPEWALWAYS((0,"connection speed : %d", bandwidth));
|
|
//SPEWALWAYS((0,"QUE : %d", que));
|
|
//SPEWALWAYS((0, "clock_adj:%f", clockDifference[connection] ));
|
|
//SPEWALWAYS((0,"local_time : %f remote_time : %f : diff : %f", gos_GetElapsedTime(1), packet_time, gos_GetElapsedTime(1) - packet_time));
|
|
//SPEWALWAYS((0,"TIME SINCE FAILURE : %f", time_since_failure));
|
|
//SPEWALWAYS((0,"SERVER : %f - CLIENT : %f - DIF %f - latency %f", local_dif, remote_dif, time_dif, latency));
|
|
//SPEWALWAYS((0, "TIME DIFF %f : %f : %f", local_dif, remote_dif, fabs(time_dif)));
|
|
//SPEWALWAYS((0,"-----------------------------\n", connection));
|
|
|
|
//PAUSE(("RULE BREAKER"));
|
|
vehicle->ClearNetworkPosition();
|
|
vehicle->speedDemand = 0.0f;
|
|
vehicle->yawDemand = 0.0f;
|
|
vehicle->currentSpeedMPS = old_speed;
|
|
SendFullConfirmation(connection);
|
|
lastReportedPosition[connection] = vehicle->GetLocalToWorld();
|
|
}
|
|
else if (vehicle->executionState->GetState() == Mech::ExecutionStateEngine::FlyingMotionState)
|
|
{
|
|
|
|
Scalar time = packet_time-lastControlPacket[connection];
|
|
Scalar max_speed_squared = vehicle->GetMaxSpeed()*2.0f*time;
|
|
max_speed_squared *= max_speed_squared;
|
|
|
|
distance_traveled.y = 0.0f;
|
|
|
|
if (!Small_Enough(time))
|
|
{
|
|
if (distance_traveled.GetLengthSquared() > max_speed_squared)
|
|
{
|
|
|
|
|
|
//rule breaker...
|
|
//PAUSE(("RULE BREAKER"));
|
|
//SPEWALWAYS(("jerryeds", "RULE BREAKER %f : %f : %f > %f ", MWApplication::GetInstance()->servedConnectionData[connection].effectivePing, time, distance_traveled.GetLength(), sqrt(max_speed_squared)));
|
|
vehicle->ClearNetworkPosition();
|
|
vehicle->speedDemand = 0.0f;
|
|
vehicle->yawDemand = 0.0f;
|
|
vehicle->currentSpeedMPS = old_speed;
|
|
SendFullConfirmation(connection);
|
|
lastReportedPosition[connection] = current_position;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Scalar time = packet_time-lastControlPacket[connection];
|
|
Scalar max_speed_squared = vehicle->GetMaxSpeed()*1.5f*time;
|
|
max_speed_squared *= max_speed_squared;
|
|
|
|
distance_traveled.y = 0.0f;
|
|
|
|
if (!Small_Enough(time))
|
|
{
|
|
if (distance_traveled.GetLengthSquared() > max_speed_squared)
|
|
{
|
|
|
|
//rule breaker...
|
|
//PAUSE(("RULE BREAKER"));
|
|
//SPEWALWAYS(("jerryeds", "RULE BREAKER %f : %f : %f > %f ", MWApplication::GetInstance()->servedConnectionData[connection].effectivePing, time, distance_traveled.GetLength(), sqrt(max_speed_squared)));
|
|
vehicle->ClearNetworkPosition();
|
|
vehicle->speedDemand = 0.0f;
|
|
vehicle->yawDemand = 0.0f;
|
|
vehicle->currentSpeedMPS = old_speed;
|
|
SendFullConfirmation(connection);
|
|
lastReportedPosition[connection] = current_position;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
lastControlPacketLocal[connection] = local_time;
|
|
lastControlPacket[connection] = packet_time;
|
|
|
|
|
|
//SPEWALWAYS((0,"-----------------------------\n", connection));
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
// if this is the actual respawn...
|
|
|
|
|
|
|
|
|
|
|
|
//SPEWALWAYS(("jerryeds", "WAITING FOR RESPAWN <%f:%f:%f> -> <%f:%f:%f>",
|
|
// MWApplication::GetInstance()->servedConnectionData[connection].vehiclePosition.x,
|
|
// MWApplication::GetInstance()->servedConnectionData[connection].vehiclePosition.y,
|
|
// MWApplication::GetInstance()->servedConnectionData[connection].vehiclePosition.z,
|
|
// lastReportedPosition[connection].x, lastReportedPosition[connection].y, lastReportedPosition[connection].z));
|
|
|
|
if (lastReportedPosition[connection] == Point3D::HellPoint && MWApplication::GetInstance()->servedConnectionData[connection].vehiclePosition != Point3D::HellPoint)
|
|
{
|
|
//STOP (("NEVER SHOULD THIS HAPPEN"));
|
|
waitingForRespawn[connection] = false;
|
|
|
|
Point3D trans;
|
|
YawPitchRoll rot;
|
|
vehicle->GetDeadReckonedNetworkPosition(trans, rot);
|
|
vehicle->ClearNetworkPosition();
|
|
LinearMatrix4D drop_position;
|
|
drop_position.BuildTranslation(trans);
|
|
drop_position.BuildRotation(rot);
|
|
|
|
vehicle->SetNewLocalToParent(drop_position);
|
|
vehicle->SyncMatrices(true);
|
|
Map::GetInstance()->UpdateZone(vehicle);
|
|
|
|
}
|
|
else
|
|
{
|
|
Point3D distance;
|
|
distance.Subtract(lastReportedPosition[connection],MWApplication::GetInstance()->servedConnectionData[connection].vehiclePosition);
|
|
distance.y = 0.0f;
|
|
|
|
if (Small_Enough(distance.GetLengthSquared(),100.0f))
|
|
{
|
|
|
|
waitingForRespawn[connection] = false;
|
|
|
|
Point3D trans;
|
|
YawPitchRoll rot;
|
|
vehicle->GetDeadReckonedNetworkPosition(trans, rot);
|
|
vehicle->ClearNetworkPosition();
|
|
LinearMatrix4D drop_position;
|
|
drop_position.BuildTranslation(trans);
|
|
drop_position.BuildRotation(rot);
|
|
|
|
vehicle->SetNewLocalToParent(drop_position);
|
|
vehicle->SyncMatrices(true);
|
|
Map::GetInstance()->UpdateZone(vehicle);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
vehicle->speedDemand = 0.0f;
|
|
vehicle->yawDemand = 0.0f;
|
|
vehicle->currentSpeedMPS = old_speed;
|
|
vehicle->ClearNetworkPosition();
|
|
|
|
++positionErrors[connection];
|
|
|
|
if (positionErrors[connection] > 10)
|
|
{
|
|
|
|
//SPEWALWAYS(("jerryeds", "NO RESPAWN %f %f %f", current_position.x, current_position.y, current_position.z));
|
|
|
|
Point3D trans;
|
|
YawPitchRoll rot;
|
|
|
|
|
|
LinearMatrix4D drop_position = LinearMatrix4D::Identity;
|
|
drop_position.BuildTranslation(lastReportedPosition[connection]);
|
|
|
|
vehicle->SetNewLocalToParent(drop_position);
|
|
vehicle->SyncMatrices(true);
|
|
Map::GetInstance()->UpdateZone(vehicle);
|
|
|
|
SendFullConfirmation(connection);
|
|
vehicle->ClearNetworkPosition();
|
|
//lastReportedPosition[connection] = current_position;
|
|
waitingForRespawn[connection] = false;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void ServerController::SendFullConfirmation(int connection)
|
|
{
|
|
|
|
MWEntityManager *manager = Cast_Object (MWEntityManager*, MWEntityManager::GetInstance());
|
|
|
|
DictionaryManager *dictionary_manager = manager->GetDictionaryManager(connection);
|
|
if(dictionary_manager != NULL)
|
|
{
|
|
|
|
Dictionary *dictionary = dictionary_manager->GetCurrentDictionary();
|
|
//int rate_type = manager->bitManager->GetUpdateRate(UpdateManager::MechPositionUpdateID, dictionary->dictionaryBandwidth).m_ActiveRate;
|
|
//Scalar rate = DictionaryPage::CalculateSeconds(rate_type);
|
|
|
|
|
|
DynamicMemoryStream movement_packet(MWEntityManager::Packet_Buffer, DefaultPacketBufferSize);
|
|
|
|
Player *player = MWApplication::GetInstance()->servedConnectionData[connection].clientPlayer;
|
|
|
|
|
|
movement_packet.WriteBits(&dictionary->versionNumber,8);
|
|
|
|
MechPositionUpdate::Encode(player->vehicle, &movement_packet, player->vehicle->GetReplicatorID().connectionID, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
ExternalJumpJetUpdate::Encode(player->vehicle, &movement_packet, player->vehicle->GetReplicatorID().connectionID, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
MechInternalDamageUpdate::Encode(player->vehicle, &movement_packet, player->vehicle->GetReplicatorID().connectionID, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
|
|
movement_packet.WriteByteAlign();
|
|
movement_packet.Rewind();
|
|
|
|
Network::GetInstance()->SendNetMessage(connection, MWEntityManager::FirstPersonFullConfirmationMessageID, &movement_packet, false);
|
|
}
|
|
/*
|
|
if (!((g_nMR == 1) && (connection != 1)))
|
|
return;
|
|
dictionary_manager = manager->GetDictionaryManager(1);
|
|
if(dictionary_manager != NULL)
|
|
{
|
|
|
|
Dictionary *dictionary = dictionary_manager->GetCurrentDictionary();
|
|
//int rate_type = manager->bitManager->GetUpdateRate(UpdateManager::MechPositionUpdateID, dictionary->dictionaryBandwidth).m_ActiveRate;
|
|
//Scalar rate = DictionaryPage::CalculateSeconds(rate_type);
|
|
|
|
|
|
DynamicMemoryStream movement_packet(MWEntityManager::Packet_Buffer, DefaultPacketBufferSize);
|
|
|
|
movement_packet.WriteBits(&dictionary->versionNumber,8);
|
|
|
|
Player *player = MWApplication::GetInstance()->servedConnectionData[connection].clientPlayer;
|
|
Vehicle* vehicle = Cast_Object(Vehicle*, player->vehicle);
|
|
|
|
ReplicatorID id = vehicle->GetReplicatorID();
|
|
movement_packet.WriteBits(&id.connectionID, 8);
|
|
movement_packet.WriteBits(&id.localID, 16);
|
|
|
|
MechPositionUpdate::Encode(vehicle, &movement_packet, id.connectionID, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
ExternalJumpJetUpdate::Encode(vehicle, &movement_packet, id.connectionID, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
|
|
movement_packet.WriteByteAlign();
|
|
|
|
movement_packet.Rewind();
|
|
|
|
g_MRF.SendMessage(1, &movement_packet, MRP_FULLCONFIRM);
|
|
}*/
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void ServerController::ReceivePlayerObserverControl(int connection, Stuff::MemoryStream *message)
|
|
{
|
|
|
|
ThrottleTest(connection);
|
|
|
|
YawPitchRange viewing_rotation = YawPitchRange::Identity;
|
|
Point3D viewing_position = Point3D::Identity;
|
|
|
|
Scalar min_z, max_z, min_x, max_x;
|
|
Map::GetInstance()->GetMapExtents(&min_z, &max_z, &min_x, &max_x);
|
|
message->ReadBitsToScaledFloat(viewing_position.x, min_x, max_x, 24);
|
|
message->ReadBitsToScaledFloat(viewing_position.y, -2005.0f, 1005.0f, 24);
|
|
message->ReadBitsToScaledFloat(viewing_position.z, min_z, max_z, 24);
|
|
message->ReadBitsToScaledFloat(viewing_rotation.yaw.angle, -Stuff::Pi, Stuff::Pi, 24);
|
|
|
|
Scalar t2_minus_t1;
|
|
message->ReadBits(&t2_minus_t1, 32);
|
|
Scalar t3;
|
|
Scalar t4 = (float)(gos_GetElapsedTime(1) * 1000.0);
|
|
message->ReadBits(&t3, 32);
|
|
lastPingDelta[connection] = t4 - t3;
|
|
|
|
|
|
//SPEWALWAYS(("jerryeds", "S-REC - %d : t2-t1 : %f, t4-t3 %f : t3 : %f t4 : %f", packet_number, t2_minus_t1, t4 - t3, t3, t4));
|
|
|
|
|
|
MWApplication::GetInstance()->servedConnectionData[connection].effectivePing = t2_minus_t1 + (t4 - t3);
|
|
MWApplication::GetInstance()->servedConnectionData[connection].averagePing.Add(MWApplication::GetInstance()->servedConnectionData[connection].effectivePing);
|
|
|
|
|
|
|
|
SecurityQuery::Decode(NULL, message, 0.0f, 0.0f, connection, 0, 0);
|
|
SecurityResponse::Decode(NULL, message, 0.0f, 0.0f, connection, 0, 0);
|
|
|
|
|
|
|
|
|
|
MWApplication::GetInstance()->servedConnectionData[connection].vehiclePosition = viewing_position;
|
|
MWApplication::GetInstance()->servedConnectionData[connection].vehicleRotation = viewing_rotation;
|
|
|
|
Network::GetInstance()->netStatCollector[Network::IncomingMechMovementBitSizeStat].AddToStatistic(connection,72);
|
|
|
|
|
|
//SPEWALWAYS(("jerryeds","REC CAM - %f %f %f : %f", viewing_position.x, viewing_position.y, viewing_position.z, viewing_rotation.yaw.angle));
|
|
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void ServerController::ReceiveWeaponCommand(int connection, int message_type, Stuff::MemoryStream *message)
|
|
{
|
|
Verify(message_type >= MWEntityManager::StartFirstPersonWeaponMessageID && message_type <= MWEntityManager::EndFirstPersonWeaponMessageID);
|
|
|
|
|
|
Verify(Network::GetInstance()->AmIServer());
|
|
|
|
#if defined(_DEBUG) && 0 // jcem - for MR test
|
|
{
|
|
char Buffer[128];
|
|
sprintf(Buffer, "Server::ReceiveWeaponCommand\n");
|
|
OutputDebugString(Buffer);
|
|
}
|
|
#endif // _DEBUG && ...
|
|
|
|
WeaponUpdate *data = new WeaponUpdate;
|
|
WeaponCommand::SpecialDecode(connection, message_type, *data, message);
|
|
|
|
// send the weapon data to the other clients.
|
|
|
|
if (data->obsolete)
|
|
return;
|
|
if (data->originator.GetCurrent() == NULL)
|
|
return;
|
|
|
|
#if 0
|
|
|
|
//SPEW(("jerryeds", "SERVER RECIEVED WEAPON COMMAND FROM : %d", data.originator->GetReplicatorID().connectionID));
|
|
|
|
|
|
int message_offset = message_type - MWEntityManager::StartFirstPersonWeaponMessageID;
|
|
|
|
DynamicMemoryStream weapon_packet(MWEntityManager::Packet_Buffer, DefaultPacketBufferSize);
|
|
WeaponCommand::SpecialEncode((BYTE)connection, MWEntityManager::StartThirdPersonWeaponMessageID+message_offset, *data, &weapon_packet);
|
|
weapon_packet.WriteByteAlign();
|
|
weapon_packet.Rewind();
|
|
|
|
|
|
for (int i = 0; i < Maximum_Players; ++i)
|
|
{
|
|
if(MWApplication::GetInstance()->servedConnectionData[i].clientReady && i != connection && i != Connection::Server->GetID())
|
|
{
|
|
Network::GetInstance()->netStatCollector[Network::OutgoingWeaponMessageBitSizeStat].AddToStatistic(i,message->GetBufferBytesUsed()*8);
|
|
Network::GetInstance()->SendNetMessage(i, MWEntityManager::StartThirdPersonWeaponMessageID+message_offset, &weapon_packet, false);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
m_EntityManager->PlayerWeaponUpdate(data);
|
|
// create the collision packet and fire the weapon
|
|
|
|
//m_EntityManager->CreateWeaponEffect(data);
|
|
|
|
m_EntityManager->QueWeapon(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
bool ServerController::SendWeaponCommands()
|
|
{
|
|
|
|
|
|
Stuff::ChainIteratorOf<WeaponUpdate*> iterator(&m_EntityManager->weaponUpdates);
|
|
WeaponUpdate *update;
|
|
|
|
DynamicMemoryStream weapon_bundle_packet(DefaultPacketBufferSize);
|
|
|
|
while ((update = iterator.GetCurrent()) != NULL)
|
|
{
|
|
|
|
if (update->originator.GetCurrent())
|
|
{
|
|
|
|
DynamicMemoryStream weapon_packet(MWEntityManager::Packet_Buffer, DefaultPacketBufferSize);
|
|
|
|
|
|
int message_type = 0;
|
|
bool fire_weapon = false;
|
|
|
|
if (update->originator.GetCurrent()->IsPlayerVehicle())
|
|
message_type = MWEntityManager::StartThirdPersonWeaponMessageID;
|
|
else
|
|
message_type = MWEntityManager::StartAIWeaponMessageID;
|
|
|
|
if (update->target.GetCurrent() == NULL)
|
|
{
|
|
// SPEWALWAYS(("jackyc", "Server Sends - Third Person Weapon To No Target"));
|
|
|
|
message_type += MWEntityManager::ToNoTargetOffset;
|
|
|
|
Point3D min(Point3D::Identity);
|
|
Point3D max(Point3D::Identity);
|
|
Map::GetInstance()->GetMapExtents(&min.z, &max.z, &min.x, &max.x);
|
|
Point3D origin;
|
|
origin = update->originator.GetCurrent()->GetLocalToWorld();
|
|
update->targetOffset = ClampPoint(origin, update->targetOffset, min, max);
|
|
|
|
|
|
Clamp(update->targetOffset.y, -1000.0f, 1000.0f);
|
|
|
|
fire_weapon = true;
|
|
}
|
|
else if (update->target.GetCurrent() == Map::GetInstance())
|
|
{
|
|
message_type += MWEntityManager::ToGroundOffset;
|
|
fire_weapon = true;
|
|
}
|
|
else if (update->target.GetCurrent()->GetReplicatorID().connectionID == Connection::Hermit->GetID())
|
|
{
|
|
// SPEWALWAYS(("jackyc", "Server Sends - Third Person Weapon To Ground"));
|
|
|
|
message_type += MWEntityManager::ToGroundOffset;
|
|
|
|
Point3D new_point;
|
|
new_point.Multiply(update->targetOffset, update->target.GetCurrent()->GetLocalToWorld());
|
|
update->targetOffset = new_point;
|
|
update->target.Remove();
|
|
update->target.Add( Map::GetInstance() );
|
|
|
|
fire_weapon = true;
|
|
|
|
}
|
|
else if (update->target.GetCurrent()->GetReplicatorID().connectionID != Connection::Server->GetID())
|
|
{
|
|
// SPEWALWAYS(("jackyc", "Server Sends - Third Person Weapon To Mech"));
|
|
|
|
message_type += MWEntityManager::ToMechOffset;
|
|
fire_weapon = true;
|
|
}
|
|
else if (update->target.GetCurrent()->GetReplicatorID().connectionID == Connection::Server->GetID())
|
|
{
|
|
// SPEWALWAYS(("jackyc", "Server Sends - Third Person Weapon To Server"));
|
|
|
|
// we hit a server object
|
|
message_type += MWEntityManager::ToServerOffset;
|
|
fire_weapon = true;
|
|
}
|
|
|
|
|
|
if (fire_weapon)
|
|
{
|
|
WeaponCommand::SpecialEncode((BYTE)Connection::Server->GetID(), message_type, *update, &weapon_packet);
|
|
//weapon_packet.WriteByteAlign();
|
|
//weapon_packet.Rewind();
|
|
|
|
weapon_packet.WriteByteAlign();
|
|
weapon_packet.Rewind();
|
|
int size = weapon_packet.GetBufferBytesUsed();
|
|
|
|
weapon_bundle_packet.WriteBytes(&size, 1);
|
|
weapon_bundle_packet.WriteBytes(&message_type, 1);
|
|
weapon_bundle_packet.WriteBytes(weapon_packet.GetPointer(), size);
|
|
|
|
// SPEW(("jackyc", "SIZE - %d", size));
|
|
// SPEW(("jackyc", "TYPE - %d", message_type));
|
|
|
|
}
|
|
|
|
iterator.Remove();
|
|
delete update;
|
|
|
|
if (weapon_bundle_packet.GetBufferBytesUsed() + 45 >= Network::DefaultPacketSize)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
|
|
iterator.Remove();
|
|
delete update;
|
|
}
|
|
}
|
|
|
|
if (weapon_bundle_packet.GetBufferBytesUsed() > 0)
|
|
{
|
|
for (int i = 0; i < Maximum_Players; ++i)
|
|
{
|
|
if(MWApplication::GetInstance()->servedConnectionData[i].clientReady)
|
|
{
|
|
if (i == Connection::Server->GetID()) {
|
|
if ((g_nMR != 1) || (g_MRF.m_nCount < 0))
|
|
continue;
|
|
}
|
|
Network::GetInstance()->SendNetMessage(i, MWEntityManager::WeaponBundleMessageID, &weapon_bundle_packet, false);
|
|
Network::GetInstance()->netStatCollector[Network::OutgoingWeaponMessageBitSizeStat].AddToStatistic(i,weapon_bundle_packet.GetBufferBytesUsed()*8);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (iterator.GetCurrent())
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void ServerController::SendAIWeaponCommands()
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
|
|
void ServerController::RespawnClient(int connection_id, Point3D translation)
|
|
{
|
|
waitingForRespawn[connection_id] = true;
|
|
lastReportedPosition[connection_id] = translation;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
|
|
void ServerController::ThrottleTest(int connection_id)
|
|
{
|
|
MWApplication *app = MWApplication::GetInstance();
|
|
Network *net = Network::GetInstance();
|
|
|
|
|
|
if (app->servedConnectionData[connection_id].bandwidthThrottle)
|
|
return;
|
|
|
|
|
|
|
|
Scalar cur_time = (Scalar)gos_GetElapsedTime();
|
|
|
|
if (app->servedConnectionData[connection_id].timeSinceLastThrottleTest == -1.0f)
|
|
{
|
|
app->servedConnectionData[connection_id].timeSinceLastThrottleTest = cur_time;
|
|
net->packetsSent[connection_id] = 0;
|
|
net->packetsDropped[connection_id] = 0;
|
|
|
|
}
|
|
else if (cur_time - app->servedConnectionData[connection_id].timeSinceLastThrottleTest > 30.0f)
|
|
{
|
|
Scalar percent = 0.0f;
|
|
|
|
app->servedConnectionData[connection_id].timeSinceLastThrottleTest = cur_time;
|
|
|
|
if (net->packetsSent[connection_id])
|
|
{
|
|
percent = (Scalar)net->packetsDropped[connection_id] / (Scalar)net->packetsSent[connection_id];
|
|
}
|
|
|
|
if (percent > 0.1)
|
|
{
|
|
//PAUSE(("THROTTLE TEST"));
|
|
app->servedConnectionData[connection_id].bandwidthThrottle = 1;
|
|
MWEntityManager::GetInstance()->UpdateDictionaries(connection_id);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
ClientController::ClientController()
|
|
{
|
|
|
|
m_EntityManager = Cast_Object(MWEntityManager*, EntityManager::GetInstance());
|
|
controlUpdateTimer = 0.0f;
|
|
lastControlPacketID = 0;
|
|
lastPingDelta = 0.0f;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
ClientController::~ClientController()
|
|
{
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void ClientController::Reset()
|
|
{
|
|
controlUpdateTimer = 0.0f;
|
|
|
|
securityQuery.Reset();
|
|
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
|
|
void ClientController::SendControlPacketToServer(Scalar time_slice)
|
|
{
|
|
|
|
controlUpdateTimer += time_slice;
|
|
MWPlayer *player = Cast_Object(MWPlayer *, MWPlayer::GetInstance());
|
|
|
|
VehicleInterface *veh_interface = Cast_Object(VehicleInterface *, player->playerInterface);
|
|
|
|
if (!veh_interface->observerMode)
|
|
{
|
|
|
|
if (MWEntityManager::GetInstance() == NULL)
|
|
return;
|
|
|
|
MWEntityManager *manager = Cast_Object (MWEntityManager*, MWEntityManager::GetInstance());
|
|
|
|
if (manager->GetDictionaryManager(Connection::Local->GetID()) == NULL)
|
|
return;
|
|
|
|
Dictionary *dictionary = manager->GetDictionaryManager(Connection::Local->GetID())->GetCurrentDictionary();
|
|
if (dictionary == NULL)
|
|
return;
|
|
|
|
|
|
int rate_type = manager->bitManager->GetUpdateRate(UpdateManager::MechPositionUpdateID, dictionary->dictionaryBandwidth).m_ActiveRate;
|
|
Scalar rate = DictionaryPage::CalculateSeconds(rate_type);
|
|
|
|
if (controlUpdateTimer < rate)
|
|
{
|
|
return;
|
|
}
|
|
|
|
controlUpdateTimer = 0.0f;
|
|
|
|
|
|
|
|
DynamicMemoryStream movement_packet(MWEntityManager::Packet_Buffer, DefaultPacketBufferSize);
|
|
|
|
|
|
|
|
|
|
movement_packet.WriteBits(&dictionary->versionNumber,8);
|
|
|
|
++lastControlPacketID;
|
|
if (lastControlPacketID == 255)
|
|
lastControlPacketID = 0;
|
|
|
|
movement_packet.WriteBits(&lastControlPacketID,8);
|
|
|
|
movement_packet.WriteBits(&lastPingDelta, 32);
|
|
Scalar current_time = (float)(gos_GetElapsedTime(1) * 1000.0);
|
|
movement_packet.WriteBits(¤t_time, 32);
|
|
|
|
|
|
//SPEWALWAYS(("jerryeds", "C-SEND - %d : t2-t1 : %f, t3 : %f", lastControlPacketID, lastPingDelta, current_time));
|
|
|
|
|
|
SecurityQuery::Encode(player->vehicle, &movement_packet, player->vehicle->GetReplicatorID().connectionID, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
MechPositionUpdate::Encode(player->vehicle, &movement_packet, player->vehicle->GetReplicatorID().connectionID, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
SecurityResponse::Encode(player->vehicle, &movement_packet, player->vehicle->GetReplicatorID().connectionID, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
ExternalJumpJetUpdate::Encode(player->vehicle, &movement_packet, player->vehicle->GetReplicatorID().connectionID, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
|
|
|
|
//MechMovemntUpdate::Encode(player->vehicle, &movement_packet, player->vehicle->GetReplicatorID().connectionID, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
//MechAnimationUpdate::Encode(player->vehicle, &movement_packet, player->vehicle->GetReplicatorID().connectionID, dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth);
|
|
|
|
movement_packet.WriteBits(&m_EntityManager->commandCount, 8);
|
|
|
|
|
|
Verify(m_EntityManager->commandCount < 256);
|
|
|
|
ChainIteratorOf<VehicleCommand*> command_iterator(&m_EntityManager->quedCommands);
|
|
VehicleCommand *command;
|
|
|
|
while ((command = command_iterator.GetCurrent()) != NULL)
|
|
{
|
|
movement_packet.WriteBits(&command->m_Command, 5);
|
|
|
|
m_EntityManager->commandCount--;
|
|
command_iterator.Remove();
|
|
delete command;
|
|
}
|
|
|
|
Verify(m_EntityManager->commandCount == 0);
|
|
|
|
|
|
|
|
movement_packet.WriteByteAlign();
|
|
movement_packet.Rewind();
|
|
|
|
Network::GetInstance()->SendNetMessage(Connection::Server->GetID(), MWEntityManager::FirstPersonControlMessageID, &movement_packet, false);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if (controlUpdateTimer < 1.0f)
|
|
{
|
|
return;
|
|
}
|
|
|
|
controlUpdateTimer = 0.0f;
|
|
|
|
|
|
Point3D viewing_position;
|
|
YawPitchRoll viewing_rotation;
|
|
|
|
//if(veh_interface->observingEntity.GetCurrent() != NULL)
|
|
//{
|
|
// viewing_position = veh_interface->observingEntity.GetCurrent()->GetLocalToWorld();
|
|
// viewing_rotation = veh_interface->observingEntity.GetCurrent()->GetLocalToWorld();
|
|
//}
|
|
//else
|
|
//{
|
|
// viewing_position = veh_interface->vehicle->GetLocalToWorld();
|
|
// viewing_rotation = veh_interface->vehicle->GetLocalToWorld();
|
|
//}
|
|
|
|
viewing_position = Player::GetInstance()->GetEyePoint();
|
|
viewing_rotation = Player::GetInstance()->GetEyePoint();
|
|
|
|
DynamicMemoryStream movement_packet(MWEntityManager::Packet_Buffer, DefaultPacketBufferSize);
|
|
|
|
Scalar min_z, max_z, min_x, max_x;
|
|
Map::GetInstance()->GetMapExtents(&min_z, &max_z, &min_x, &max_x);
|
|
movement_packet.WriteScaledFloatToBits(viewing_position.x, min_x, max_x, 24);
|
|
movement_packet.WriteScaledFloatToBits(viewing_position.y, -2005.0f, 1005.0f, 24);
|
|
movement_packet.WriteScaledFloatToBits(viewing_position.z, min_z, max_z, 24);
|
|
movement_packet.WriteScaledFloatToBits(viewing_rotation.yaw.angle, -Stuff::Pi, Stuff::Pi, 24);
|
|
|
|
|
|
movement_packet.WriteBits(&lastPingDelta, 32);
|
|
Scalar current_time = (float)(gos_GetElapsedTime(1) * 1000.0);
|
|
movement_packet.WriteBits(¤t_time, 32);
|
|
|
|
SecurityQuery::Encode(player->vehicle, &movement_packet, player->vehicle->GetReplicatorID().connectionID, 0, 0);
|
|
SecurityResponse::Encode(player->vehicle, &movement_packet, player->vehicle->GetReplicatorID().connectionID, 0, 0);
|
|
|
|
|
|
movement_packet.Rewind();
|
|
|
|
|
|
//SPEWALWAYS(("jerryeds","SEND CAM - %f %f %f : %f", viewing_position.x, viewing_position.y, viewing_position.z, viewing_rotation.yaw.angle));
|
|
|
|
|
|
Network::GetInstance()->SendNetMessage(Connection::Server->GetID(), MWEntityManager::FirstPersonObserverControlMessageID, &movement_packet, false);
|
|
|
|
Network::GetInstance()->netStatCollector[Network::OutgoingMechMovementBitSizeStat].AddToStatistic(Connection::Server->GetID(),72);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void ClientController::SendWeaponCommands(void)
|
|
{
|
|
|
|
|
|
Stuff::ChainIteratorOf<WeaponUpdate*> iterator(&m_EntityManager->weaponUpdates);
|
|
WeaponUpdate *update;
|
|
|
|
while ((update = iterator.GetCurrent()) != NULL)
|
|
{
|
|
|
|
int message_type = 0;
|
|
bool fire_weapon = false;
|
|
|
|
if (update->target.GetCurrent() == NULL)
|
|
{
|
|
// SPEWALWAYS(("jackyc", "Client Sends - First Person Weapon To No Target"));
|
|
|
|
message_type = MWEntityManager::FirstPersonWeaponNoTargetCommandMessageID;
|
|
|
|
Point3D min(Point3D::Identity);
|
|
Point3D max(Point3D::Identity);
|
|
Map::GetInstance()->GetMapExtents(&min.z, &max.z, &min.x, &max.x);
|
|
Point3D origin;
|
|
origin = update->originator.GetCurrent()->GetLocalToWorld();
|
|
update->targetOffset = ClampPoint(origin, update->targetOffset, min, max);
|
|
|
|
|
|
Clamp(update->targetOffset.y, -1000.0f, 1000.0f);
|
|
|
|
fire_weapon = true;
|
|
}
|
|
else if (update->target.GetCurrent() == Map::GetInstance())
|
|
{
|
|
// SPEWALWAYS(("jackyc", "Client Sends - First Person Weapon To Ground"));
|
|
|
|
message_type = MWEntityManager::FirstPersonWeaponToGroundCommandMessageID;
|
|
fire_weapon = true;
|
|
}
|
|
else if (update->target.GetCurrent()->GetReplicatorID().connectionID == Connection::Hermit->GetID())
|
|
{
|
|
// SPEWALWAYS(("jackyc", "Client Sends - First Person Weapon To Ground"));
|
|
|
|
message_type = MWEntityManager::FirstPersonWeaponToGroundCommandMessageID;
|
|
|
|
Point3D new_point;
|
|
new_point.Multiply(update->targetOffset, update->target.GetCurrent()->GetLocalToWorld());
|
|
update->targetOffset = new_point;
|
|
update->target.Add( Map::GetInstance() );
|
|
|
|
fire_weapon = true;
|
|
|
|
}
|
|
else if (update->target.GetCurrent()->GetReplicatorID().connectionID != Connection::Server->GetID())
|
|
{
|
|
// SPEWALWAYS(("jackyc", "Client Sends - First Person Weapon To Mech"));
|
|
|
|
message_type = MWEntityManager::FirstPersonWeaponToMechCommandMessageID;
|
|
fire_weapon = true;
|
|
}
|
|
else if (update->target.GetCurrent()->GetReplicatorID().connectionID == Connection::Server->GetID())
|
|
{
|
|
// SPEWALWAYS(("jackyc", "Client Sends - First Person Weapon To Server Object"));
|
|
|
|
// we hit a server object
|
|
message_type = MWEntityManager::FirstPersonWeaponToServerObjectCommandMessageID;
|
|
fire_weapon = true;
|
|
}
|
|
|
|
|
|
if (fire_weapon)
|
|
{
|
|
DynamicMemoryStream weapon_packet(MWEntityManager::Packet_Buffer, DefaultPacketBufferSize);
|
|
WeaponCommand::SpecialEncode((BYTE)Connection::Server->GetID(), message_type, *update, &weapon_packet);
|
|
weapon_packet.WriteByteAlign();
|
|
weapon_packet.Rewind();
|
|
|
|
Network::GetInstance()->netStatCollector[Network::OutgoingWeaponMessageBitSizeStat].AddToStatistic(Connection::Server->GetID(),weapon_packet.GetBufferBytesUsed()*8);
|
|
Network::GetInstance()->SendNetMessage(Connection::Server->GetID(), message_type, &weapon_packet, false);
|
|
}
|
|
|
|
iterator.Remove();
|
|
delete update;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void ClientController::ReceiveWeaponCommand(int connection, int message_type, Stuff::MemoryStream *message)
|
|
{
|
|
Verify(message_type >= MWEntityManager::StartThirdPersonWeaponMessageID && message_type <= MWEntityManager::EndAIWeaponMessageID);
|
|
|
|
Verify(!Network::GetInstance()->AmIServer());
|
|
|
|
#if defined(_DEBUG) && 0 // jcem - for MR test
|
|
{
|
|
char Buffer[128];
|
|
sprintf(Buffer, "Client::ReceiveWeaponCommand\n");
|
|
OutputDebugString(Buffer);
|
|
}
|
|
#endif // _DEBUG && ...
|
|
|
|
WeaponUpdate *data = new WeaponUpdate;
|
|
WeaponCommand::SpecialDecode(connection, message_type, *data, message);
|
|
|
|
//SPEW(("jerryeds", "CLEINT RECEIVED WEAPON COMMAND FROM : %d ", data.originator->GetReplicatorID().connectionID));
|
|
|
|
// create the collision packet and fire the weapon
|
|
|
|
//m_EntityManager->CreateWeaponEffect(data);
|
|
|
|
m_EntityManager->QueWeapon(data);
|
|
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
|
|
void ClientController::ReceiveWeaponBundle(int connection, int message_type, Stuff::MemoryStream *message)
|
|
{
|
|
Verify(message_type == MWEntityManager::WeaponBundleMessageID);
|
|
|
|
if (g_nMR != 2)
|
|
Verify(!Network::GetInstance()->AmIServer());
|
|
|
|
while (message->GetBytesRemaining())
|
|
{
|
|
int size = 0;
|
|
int real_type = 0;
|
|
message->ReadBytes(&size,1);
|
|
message->ReadBytes(&real_type,1);
|
|
// SPEW(("jackyc", "SIZE - %d", size));
|
|
// SPEW(("jackyc", "TYPE - %d", real_type));
|
|
MemoryStream sub_message(message->GetPointer(), size);
|
|
message->AdvancePointer(size);
|
|
WeaponUpdate *data = new WeaponUpdate;
|
|
WeaponCommand::SpecialDecode(connection, real_type, *data, &sub_message);
|
|
|
|
//SPEW(("jerryeds", "CLEINT RECEIVED WEAPON COMMAND FROM : %d ", data.originator->GetReplicatorID().connectionID));
|
|
|
|
// create the collision packet and fire the weapon
|
|
|
|
//m_EntityManager->CreateWeaponEffect(data);
|
|
|
|
m_EntityManager->QueWeapon(data);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
|
|
void ClientController::RespawnClient(int connection_id)
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
|
|
void ClientController::ReceiveFullConfirmation(Stuff::MemoryStream *message)
|
|
{
|
|
MWEntityManager *manager = Cast_Object (MWEntityManager*, MWEntityManager::GetInstance());
|
|
|
|
|
|
DictionaryManager *dictionary_manager = manager->GetDictionaryManager(Connection::Local->GetID());
|
|
if(dictionary_manager != NULL)
|
|
{
|
|
int version = 0;
|
|
message->ReadBits(&version,8);
|
|
|
|
Dictionary *dictionary = dictionary_manager->GetDictionary(version);
|
|
|
|
if (dictionary != NULL)
|
|
{
|
|
Player *player = MWApplication::GetInstance()->servedConnectionData[Connection::Local->GetID()].clientPlayer;
|
|
|
|
|
|
int rate_type = manager->bitManager->GetUpdateRate(UpdateManager::MechPositionUpdateID, dictionary->dictionaryBandwidth).m_ActiveRate;
|
|
Scalar rate = DictionaryPage::CalculateSeconds(rate_type);
|
|
|
|
MechPositionUpdate::Decode(player->vehicle, message, 0.0, 0.0f, Connection::Local->GetID(), dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth, rate);
|
|
ExternalJumpJetUpdate::Decode(player->vehicle, message, 0.0, 0.0f, Connection::Local->GetID(), dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth, rate);
|
|
MechInternalDamageUpdate::Decode(player->vehicle, message, 0.0, 0.0f, Connection::Local->GetID(), dictionary->debugDictionaryLevel, dictionary->dictionaryBandwidth, rate);
|
|
|
|
#if 0
|
|
YawPitchRoll ypr;
|
|
Point3D position;
|
|
|
|
Vehicle *vehicle = Cast_Object(Vehicle *, player->vehicle);
|
|
vehicle->GetDeadReckonedNetworkPosition(position, ypr);
|
|
#endif
|
|
|
|
//SPEW(("jerryeds","MOVEMENT CONF : %f %f %f", position.x, position.y, position.z));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} |