//===========================================================================//
// 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(&current_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(&current_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));

		}

	}

}