3206 lines
81 KiB
C++
3206 lines
81 KiB
C++
///////////////////////////////////////////////////3///////////////////
|
|
//
|
|
// Game Source Code
|
|
//
|
|
// File: XClient.cpp
|
|
// Description: XClient implemetation.
|
|
//
|
|
// History:
|
|
// - August 3, 2001: Created by Alberto Demichelis
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "XClient.h"
|
|
#include "XPlayer.h"
|
|
|
|
#include "UIHud.h"
|
|
#include "XSystemClient.h"
|
|
#include "XSystemDummy.h"
|
|
#include "IngameDialog.h"
|
|
|
|
#include <I3dengine.h>
|
|
|
|
#include <IEntitySystem.h>
|
|
#include <IMovieSystem.h>
|
|
#include <ISound.h>
|
|
#include <IAISystem.h>
|
|
|
|
#include "XPlayer.h"
|
|
#include "Spectator.h" // CSpectator
|
|
#include "AdvCamSystem.h" // CAdvCamSystem
|
|
#include "XVehicle.h"
|
|
#include "PlayerSystem.h"
|
|
#include "XVehicleSystem.h"
|
|
|
|
#include "ScriptObjectVector.h"
|
|
#include "ScriptObjectPlayer.h"
|
|
//#include "ScriptObjectEntity.h"
|
|
#include "ScriptObjectVehicle.h"
|
|
#include "ScriptObjectSpectator.h" // CScriptObjectSpectator
|
|
#include "ScriptObjectAdvCamSystem.h" // CScriptObjectAdvCamSystem
|
|
#include "StreamData.h" // CStreamData_WorldPos
|
|
#include <map> // STL map<>
|
|
|
|
#include "Game.h"
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CXClient::OnSpawnContainer( CEntityDesc &ed,IEntity *pEntity )
|
|
{
|
|
m_pISystem->OnSpawnContainer(ed,pEntity);
|
|
}
|
|
|
|
void CXClient::OnSpawn(IEntity *ent, CEntityDesc &ed)
|
|
{
|
|
m_pISystem->OnSpawn(ent,ed);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
void CXClient::OnRemove(IEntity *ent)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////
|
|
CXClient::CXClient()
|
|
{
|
|
m_bConnected=0;
|
|
m_CameraParams=0;
|
|
m_pScriptObjectClient=0;
|
|
m_pIActionMapManager=0;
|
|
m_pEntitySystem=0;
|
|
m_pISystem=0;
|
|
m_pIClient=0;
|
|
m_pISystem=0;
|
|
m_wPlayerID=INVALID_WID;
|
|
m_pGame=0;
|
|
|
|
cl_explShakeDCoef = 0.07f;
|
|
cl_explShakeAmplH = 0.001;
|
|
cl_explShakeAmplV = 0.001;
|
|
cl_explShakeFreq = 11.73f;
|
|
cl_explShakeTime = 1.73f;
|
|
|
|
m_fFrontSound=0;
|
|
m_fBackSound=0;
|
|
m_fLeftSound=0;
|
|
m_fRightSound=0;
|
|
m_pClientStuff=0;
|
|
bDoSwitch=false;
|
|
m_pTimer=0;
|
|
m_bSelfDestruct=false; // to make sure the client is only released in one place
|
|
m_pSavedConsoleVars=0;
|
|
m_bLazyChannelState=false; // start with false on client and serverslot side
|
|
}
|
|
|
|
bool CXClient::Init(CXGame *pGame,bool bLocal)
|
|
{
|
|
m_fLastClientStringTime=0;
|
|
m_bDisplayHud=true;
|
|
m_bMapConnecting=false;
|
|
m_bRecordingDemo=false;
|
|
m_bPlaybackDemo=false;
|
|
// m_iaLastSeaponSwitch = 0;
|
|
m_wPlayerID = INVALID_WID;
|
|
m_pISystem = NULL;
|
|
m_bLocalHost = false;
|
|
m_bLinkListenerToCamera =true;
|
|
m_pGame = pGame;
|
|
m_pScriptSystem = m_pGame->GetScriptSystem();
|
|
m_pEntitySystem = m_pGame->GetSystem()->GetIEntitySystem();
|
|
m_pLog=m_pGame->m_pLog;
|
|
|
|
m_sopMsgNormal.Create( m_pScriptSystem );
|
|
m_sopMsgPos.Create( m_pScriptSystem );
|
|
|
|
m_pTimer =m_pGame->GetSystem()->GetITimer();
|
|
// Create the client
|
|
m_pIClient = m_pGame->CreateClient(this,bLocal);
|
|
|
|
m_PrevPlayerProcessingCmd = m_PlayerProcessingCmd;
|
|
|
|
// Set the first System interface.
|
|
UpdateISystem();
|
|
|
|
m_pIActionMapManager = m_pGame->GetActionMapManager();
|
|
if(m_pIActionMapManager)
|
|
m_pIActionMapManager->SetSink(this);
|
|
|
|
// Create the console variables
|
|
CreateConsoleVariables();
|
|
|
|
m_nGameState = CGS_INTERMISSION; // until we get first update from the mod
|
|
m_nGameLastTime = 0;
|
|
m_fGameLastTimeReceived = 0;
|
|
m_pScriptObjectClient=new CScriptObjectClient;
|
|
m_pScriptObjectClient->Create(pGame->GetScriptSystem(),pGame,this);
|
|
|
|
m_CameraParams = new SCameraParams;
|
|
m_pClientStuff=m_pScriptSystem->CreateEmptyObject();
|
|
m_iPhysicalWorldTime = 0;
|
|
m_bIgnoreSnapshot = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
CXClient::~CXClient()
|
|
{
|
|
assert(m_bSelfDestruct); // to make sure the client is only released in one place
|
|
|
|
if (m_pSavedConsoleVars)
|
|
{
|
|
RestoreServerSyncedVars(); // restore VF_REQUIRE_NET_SYNC marked console vars)
|
|
}
|
|
|
|
// delete the player
|
|
if (m_pISystem)
|
|
m_pISystem->RemoveEntity(m_wPlayerID);
|
|
m_wPlayerID = INVALID_WID;
|
|
|
|
// Release the System interface
|
|
SAFE_RELEASE(m_pISystem);
|
|
SAFE_DELETE(m_CameraParams);
|
|
SAFE_DELETE(m_pScriptObjectClient);
|
|
|
|
if(m_pIActionMapManager)
|
|
m_pIActionMapManager->SetSink(NULL);
|
|
|
|
if (m_pEntitySystem)
|
|
m_pEntitySystem->RemoveSink(this);
|
|
// Call disconnect to be sure that it has been done
|
|
//Disconnect("@ClientHasQuit");
|
|
|
|
SAFE_RELEASE(m_pIClient);
|
|
/*
|
|
if (cl_explShakeDCoef)
|
|
cl_explShakeDCoef->Release();
|
|
if (cl_explShakeAmplH)
|
|
cl_explShakeAmplH->Release();
|
|
if (cl_explShakeAmplV)
|
|
cl_explShakeAmplV->Release();
|
|
if (cl_explShakeFreq)
|
|
cl_explShakeFreq->Release();
|
|
if (cl_explShakeTime)
|
|
cl_explShakeTime->Release();
|
|
*/
|
|
m_pGame = NULL;
|
|
|
|
m_fFrontSound=0;
|
|
m_fBackSound=0;
|
|
m_fLeftSound=0;
|
|
m_fRightSound=0;
|
|
|
|
SAFE_RELEASE(m_pClientStuff);
|
|
|
|
if(m_pScriptSystem)
|
|
{
|
|
m_pScriptSystem->SetGlobalToNull("ClientStuff");
|
|
m_pScriptSystem->SetGlobalToNull("Client");
|
|
|
|
//Never force Lua GC, m_pScriptSystem->ForceGarbageCollection();
|
|
}
|
|
}
|
|
|
|
void CXClient::LoadPlayerDesc()
|
|
{
|
|
IScriptSystem *pSS = m_pGame->GetScriptSystem();
|
|
|
|
pSS->ExecuteFile("playercfg.lua",false);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
bool CXClient::CreateConsoleVariables()
|
|
{
|
|
IConsole *pConsole=m_pGame->GetSystem()->GetIConsole();
|
|
cl_runroll = pConsole->CreateVariable("cl_runroll","0",0,
|
|
"\n"
|
|
"Usage: cl_runroll ?\n"
|
|
"Default is 0.");
|
|
cl_runpitch = pConsole->CreateVariable("cl_runpitch","0.4",0,
|
|
"\n"
|
|
"Usage: cl_runpitch 0.4\n"
|
|
"Default is 0.4.");
|
|
cl_runheight = pConsole->CreateVariable("cl_runheight","0.03",0,
|
|
"\n"
|
|
"Usage: cl_runheight 0.03\n"
|
|
"Default is 0.03.");
|
|
cl_runheightspeed = pConsole->CreateVariable("cl_runheightspeed","1.5",0,
|
|
"\n"
|
|
"Usage: cl_runheightspeed 1.5\n"
|
|
"Default is 1.5.");
|
|
cl_playerclassid = pConsole->CreateVariable("cl_playerclassid","1",0,
|
|
"Sets the player class.\n"
|
|
"Usage: cl_playerclassid #\n"
|
|
"Default is 1.");
|
|
cl_netstats = pConsole->CreateVariable("cl_netstats","0",0,
|
|
"Toggles client network statistics.\n"
|
|
"Usage: cl_netstats [0/1]\n"
|
|
"Default is 0 (off). Set to 1 to display network statistics.");
|
|
cl_cmdrate = pConsole->CreateVariable("cl_cmdrate","40",0,
|
|
"Specify the max client network command rate\n"
|
|
"(less is better for bandwidth, more is better for response,\n"
|
|
"the actual rate is limited by frame rate as well)\n"
|
|
"Usage: cl_cmdrate [5..100]\n"
|
|
"Default is 40");
|
|
/*
|
|
cl_explShakeDCoef = pConsole->CreateVariable("cl_ExplShakeD",".07",0,
|
|
"Sets the damping co-efficient of the explosion shake effect.\n"
|
|
"Usage: cl_ExplShakeD .07\n"
|
|
"Default is 0.07. Higher values suppress the effect more quickly.");
|
|
cl_explShakeAmplH = pConsole->CreateVariable("cl_ExplShakeAmplH",".001",0,
|
|
"Sets the horizontal amplitude of the explosion shake effect.\n"
|
|
"Usage: cl_ExplShakeAmplH .001\n"
|
|
"Default is 0.001 metres. The view is horizontally displaced\n"
|
|
"by this amount when the player is near an explosion.");
|
|
cl_explShakeAmplV = pConsole->CreateVariable("cl_ExplShakeAmplV",".001",0,
|
|
"Sets the vertical amplitude of the explosion shake effect.\n"
|
|
"Usage: cl_ExplShakeAmplV .001\n"
|
|
"Default is 0.001 metres. The view is vertically displaced\n"
|
|
"by this amount when the player is near an explosion.");
|
|
cl_explShakeFreq = pConsole->CreateVariable("cl_ExplShakeFreq","11.73",0,
|
|
"Sets the frequency of the explosion shake effect.\n"
|
|
"Usage: cl_ExplShakeFreq 11.73\n"
|
|
"When the player is near an explosion, the view\n"
|
|
"shakes with a frequency of 11.73 Hz by default.");
|
|
cl_explShakeTime = pConsole->CreateVariable("cl_ExplShakeTime","1.73",0,
|
|
"Sets the duration of the explosion shake effect.\n"
|
|
"Usage: cl_ExplShakeTime 1.73\n"
|
|
"Default is 1.73 seconds. When the player is near an explosion,\n"
|
|
"the view shakes for this time.");
|
|
*/
|
|
cl_sound_detection_max_distance = pConsole->CreateVariable("cl_sound_detection_max_distance","50",0);
|
|
cl_sound_detection_min_distance = pConsole->CreateVariable("cl_sound_detection_min_distance","2",0);
|
|
cl_sound_event_radius = pConsole->CreateVariable("cl_sound_event_radius","50",0);
|
|
cl_sound_event_timeout = pConsole->CreateVariable("cl_sound_event_timeout","1",0);
|
|
|
|
pConsole->AddCommand("say","Client:Say(%line)",VF_NOHELP,"");
|
|
pConsole->AddCommand("sayteam","Client:SayTeam(%line)",VF_NOHELP,"");
|
|
pConsole->AddCommand("sayone","Client:SayOne(%%)",VF_NOHELP, "");
|
|
pConsole->AddCommand("tell","Client:SayOne(%%)",VF_NOHELP, "");
|
|
pConsole->AddCommand("team","Client:JoinTeamRequest(%%)",0,
|
|
"Sends a request to join a team.\n"
|
|
"Usage: team teamname\n");
|
|
pConsole->AddCommand("ready","Client:CallVote(\"ready\")",0,
|
|
"Asks if other players are ready.\n"
|
|
"Usage: ready\n"
|
|
"Works by sending a request to players.\n"
|
|
"Players respond y or n.\n");
|
|
pConsole->AddCommand("callvote","Client:CallVote(%%)",0,
|
|
"Asks players to vote on a command.\n"
|
|
"Usage: callvote commandname arg\n"
|
|
"Sends a request to players to vote on 'commandname arg'.\n"
|
|
"Players respond y or n.\n");
|
|
pConsole->AddCommand("vote","Client:Vote(%1)",0,
|
|
"Used to vote on suggestions from other players.\n"
|
|
"Usage: vote [y/n]\n"
|
|
"Vote y for yes or n for no.");
|
|
pConsole->AddCommand("name","Client:SetName(%line)",VF_NOHELP, "");
|
|
pConsole->AddCommand("kill","Client:Kill()",0,
|
|
"Kills the player.\n"
|
|
"Usage: kill\n"
|
|
"Player respawns as normal.");
|
|
pConsole->AddCommand("cl_maxrate","Client:SetBitsPerSecond(%1)",0,
|
|
"Sets client maximum download bandwidth\n"
|
|
"(the actual rate is limited by server setting as well)\n"
|
|
"Usage: cl_maxrate 28800\n"
|
|
"Sets bits per second the server is allowed to send to you (this client).");
|
|
pConsole->AddCommand("cl_updaterate","Client:SetUpdateRate(%1)",0,
|
|
"Specify the max server network update rate\n"
|
|
"(less is better for bandwidth, more is better for response,\n"
|
|
"the actual rate is limited by frame/update rate and the server setting as well)\n"
|
|
"Usage: cl_updaterate [5..100]\n"
|
|
"Default is 20");
|
|
return true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::OnXConnect()
|
|
{
|
|
//sound sources
|
|
m_fFrontSound=0;
|
|
m_fBackSound=0;
|
|
m_fLeftSound=0;
|
|
m_fRightSound=0;
|
|
m_lstSounds.clear();
|
|
m_nDiscardedPackets=0;
|
|
m_fLastRemoteAsyncCurrTime=0;
|
|
m_fLastScoreBoardTime = 0;
|
|
TRACE("CXClient::OnXConnect");
|
|
LoadPlayerDesc();
|
|
|
|
/* if (bDoSwitch)
|
|
{
|
|
// TODO
|
|
// Check if this works
|
|
m_pGame->GetSystem()->GetIConsole()->SetScrollMax(600);
|
|
m_pGame->GetSystem()->GetIConsole()->ShowConsole(true);
|
|
//m_pGame->SendMessage("Switch");
|
|
bDoSwitch=false;
|
|
}
|
|
*/
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::MarkForDestruct()
|
|
{
|
|
// m_pGame->GetSystem()->GetILog()->Log("CXClient MarkForDestruct");
|
|
m_bSelfDestruct=true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
bool CXClient::DestructIfMarked()
|
|
{
|
|
if(m_bSelfDestruct)
|
|
{
|
|
// m_pGame->GetSystem()->GetILog()->Log("CXClient DestructIfMarked true");
|
|
|
|
delete this;
|
|
return true; // was deleted
|
|
}
|
|
return false; // was not deleted
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::RestoreServerSyncedVars()
|
|
{
|
|
if(m_pSavedConsoleVars)
|
|
{
|
|
string varname,val;
|
|
|
|
if(m_bLocalHost) // only client have to restore their VF_REQUIRE_NET_SYNC console variables
|
|
{
|
|
while(!m_pSavedConsoleVars->EOS() && m_pSavedConsoleVars->Read(varname))
|
|
{
|
|
m_pSavedConsoleVars->Read(val);
|
|
|
|
// m_pGame->GetSystem()->GetILog()->Log("Restored console variable %s to %s",varname.c_str(),val.c_str());
|
|
|
|
m_pISystem->SetVariable(varname.c_str(),val.c_str());
|
|
}
|
|
}
|
|
|
|
delete m_pSavedConsoleVars;m_pSavedConsoleVars=0;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::OnXClientDisconnect(const char *szCause)
|
|
{
|
|
_SmartScriptObject pClientStuff(m_pScriptSystem,true);
|
|
if(m_pScriptSystem->GetGlobalValue("ClientStuff",pClientStuff)) // call ClientStuff:OnShutdown()
|
|
{
|
|
m_pScriptSystem->BeginCall("ClientStuff","OnShutdown");
|
|
m_pScriptSystem->PushFuncParam(pClientStuff);
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
TRACE(szCause);
|
|
SetPlayerID(0);
|
|
// <<FIXME>> Should cleanup the stuff with a new function of the IXSystem interface
|
|
|
|
m_bConnected=0;
|
|
|
|
if(m_pISystem)
|
|
m_pISystem->Disconnected(szCause);
|
|
|
|
m_pScriptSystem->BeginCall("ClientOnDisconnect");
|
|
m_pScriptSystem->PushFuncParam(szCause);
|
|
m_pScriptSystem->EndCall();
|
|
|
|
m_pGame->MarkClientForDestruct(); // to make sure the client is only released in one place
|
|
|
|
// hide console and reset progress bar after a disconnection
|
|
GetISystem()->GetIConsole()->ResetProgressBar(0);
|
|
GetISystem()->GetIConsole()->SetScrollMax(600/2);
|
|
GetISystem()->GetIConsole()->ShowConsole(0);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::Reset()
|
|
{
|
|
m_pScriptSystem->GetGlobalValue("ClientStuff",m_pClientStuff);
|
|
m_pScriptSystem->BeginCall("ClientStuff","OnReset");
|
|
m_pScriptSystem->PushFuncParam(m_pClientStuff);
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::OnXContextSetup(CStream &stm)
|
|
{
|
|
GetISystem()->GetILog()->Log("CXClient::OnXContextSetup");
|
|
|
|
SetPlayerID(INVALID_WID);
|
|
UpdateISystem();
|
|
|
|
m_GameContext.Read(stm); // Read the sended game context
|
|
|
|
if (m_pGame->IsMultiplayer())
|
|
{
|
|
if(m_GameContext.bInternetServer)
|
|
if(!GetISystem()->GetINetwork()->VerifyMultiplayerOverInternet())
|
|
return;
|
|
}
|
|
|
|
if (!m_pGame->m_bEditor)
|
|
{
|
|
HSCRIPTFUNCTION pfnOnConnectEstablished = m_pScriptSystem->GetFunctionPtr("Game", "OnConnectEstablished");
|
|
|
|
if (pfnOnConnectEstablished)
|
|
{
|
|
m_pScriptSystem->BeginCall(pfnOnConnectEstablished);
|
|
m_pScriptSystem->PushFuncParam(m_pGame->GetScriptObject());
|
|
m_pScriptSystem->EndCall();
|
|
|
|
m_pScriptSystem->ReleaseFunc(pfnOnConnectEstablished);
|
|
}
|
|
}
|
|
|
|
IGameMods *pModInterface=m_pGame->GetModsInterface();
|
|
|
|
assert(pModInterface); // otherwise the Game::Init failed
|
|
|
|
//if(m_GameContext.strMod!=string(pModInterface->GetCurrentMod()))
|
|
if (stricmp(m_GameContext.strMod.c_str(),pModInterface->GetCurrentMod())!=0)
|
|
{
|
|
m_pLog->LogError("Wrong Mod: CurrentMod='%s' RequestedMod='%s'",pModInterface->GetCurrentMod(),m_GameContext.strMod.c_str());
|
|
|
|
XDisconnect("@GameVersionError");
|
|
return;
|
|
}
|
|
|
|
if(!m_GameContext.IsVersionOk())
|
|
{
|
|
m_pLog->LogError("CXClient::OnXContextSetup - Versions do not match. Server version: %i.%d Client version: %i.%d",
|
|
m_GameContext.dwNetworkVersion,(int)m_GameContext.ucServerInfoVersion,NETWORK_FORMAT_VERSION,(int)SERVERINFO_FORMAT_VERSION);
|
|
|
|
XDisconnect("@GameVersionError");
|
|
return;
|
|
}
|
|
|
|
{
|
|
IConsole *pConsole=m_pGame->GetSystem()->GetIConsole();
|
|
static CDefaultStreamAllocator sa;
|
|
|
|
RestoreServerSyncedVars(); // restore VF_REQUIRE_NET_SYNC marked console vars
|
|
|
|
if(!stm.EOS())
|
|
{
|
|
m_pSavedConsoleVars = new CStream(1024, &sa); // saved console variable state (to restore the VF_REQUIRE_NET_SYNC marked vars)
|
|
|
|
string varname,val;
|
|
while(!stm.EOS() && stm.Read(varname))
|
|
{
|
|
stm.Read(val);
|
|
|
|
ICVar *pVar=pConsole->GetCVar(varname.c_str());
|
|
|
|
if(pVar)
|
|
{
|
|
m_pSavedConsoleVars->Write(varname.c_str());
|
|
m_pSavedConsoleVars->Write(pVar->GetString());
|
|
}
|
|
|
|
// m_pGame->GetSystem()->GetILog()->Log("Got Server synced console variable %s to %s (was %s)",varname.c_str(),val.c_str(),pVar->GetString());
|
|
|
|
m_pISystem->SetVariable(varname.c_str(),val.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
m_pGame->g_GameType->Set(m_GameContext.strGameType.c_str());
|
|
m_Snapshot.Reset();
|
|
|
|
m_pLog->Log("CXClient::OnXContextSetup - map : %s\n", m_GameContext.strMapFolder.c_str());
|
|
|
|
if(!m_pISystem->LoadLevel(m_GameContext.strMapFolder.c_str(), m_GameContext.strMission.c_str(), false))
|
|
{
|
|
m_pLog->LogError("CXClient::OnXContextSetup ERROR LOADING LEVEL: %s\n", m_GameContext.strMapFolder.c_str());
|
|
|
|
LoadingError("@LoadLevelError");
|
|
|
|
return;
|
|
}
|
|
|
|
if((!m_pGame->m_bEditor)
|
|
&& (!m_pGame->IsServer())
|
|
&& (m_pISystem->GetLevelDataCheckSum()!=m_GameContext.wLevelDataCheckSum))
|
|
{
|
|
m_pLog->LogError("CXClient::OnXContextSetup ERROR LOADING LEVEL: %s [INVALID CHECKSUM]\n", m_GameContext.strMapFolder.c_str());
|
|
|
|
LoadingError("@LevelVersionError");
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
_SmartScriptObject pClientStuff(m_pScriptSystem,true);
|
|
if(m_pScriptSystem->GetGlobalValue("ClientStuff",pClientStuff)) // call ClientStuff:OnShutdown()
|
|
{
|
|
m_pScriptSystem->BeginCall("ClientStuff","OnShutdown");
|
|
m_pScriptSystem->PushFuncParam(pClientStuff);
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
if(!m_pGame->m_bDedicatedServer) // don't load ClientStuff on dedicated server
|
|
{
|
|
if(!m_pGame->ExecuteScript("scripts/$GT$/ClientStuff.lua",true))
|
|
{
|
|
DebugBreak();
|
|
}
|
|
m_pScriptSystem->GetGlobalValue("ClientStuff",m_pClientStuff);
|
|
m_pScriptSystem->BeginCall("ClientStuff","OnInit");
|
|
m_pScriptSystem->PushFuncParam(m_pClientStuff);
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
// Write the stream to send to ContextReady
|
|
{
|
|
// m_pLog->Log("Write the stream to send to ContextReady");
|
|
stm.Reset();
|
|
|
|
// bLocalHost
|
|
stm.Write(m_bLocalHost);
|
|
|
|
// p_name
|
|
m_pLog->Log("p_name=%s",m_pGame->p_name->GetString());
|
|
stm.Write(m_pGame->p_name->GetString());
|
|
|
|
// p_model, mp_model
|
|
{
|
|
ICVar *model;
|
|
|
|
if (m_pGame->IsMultiplayer())
|
|
model = m_pGame->mp_model; // multiplayer model
|
|
else
|
|
model = m_pGame->p_model; // single player model
|
|
|
|
if(!model->GetString())
|
|
stm.Write("");
|
|
else
|
|
{
|
|
m_pLog->Log("p_model=%s",model->GetString());
|
|
stm.Write(model->GetString());
|
|
}
|
|
}
|
|
|
|
// p_color
|
|
{
|
|
ICVar *color = m_pGame->p_color; // player's color in non team base multiplayer mods
|
|
|
|
if(!color->GetString())
|
|
stm.Write("");
|
|
else
|
|
{
|
|
m_pLog->Log("p_color=%s",color->GetString());
|
|
stm.Write(color->GetString());
|
|
}
|
|
}
|
|
|
|
// player classid
|
|
stm.Write(cl_playerclassid->GetIVal());
|
|
|
|
m_pLog->Log("SEND ContextReady");
|
|
m_pIClient->ContextReady(stm);
|
|
}
|
|
|
|
// fade in when loading a new map
|
|
if (!m_pGame->m_bEditor)
|
|
{
|
|
m_pGame->m_p3DEngine->SetScreenFx("ScreenFade",1);
|
|
float fFadeTime=-2.5f;
|
|
m_pGame->m_p3DEngine->SetScreenFxParam("ScreenFade","ScreenFadeTime", &fFadeTime);
|
|
float fPreFade=5.0f;
|
|
m_pGame->m_p3DEngine->SetScreenFxParam("ScreenFade","ScreenPreFadeTime", &fPreFade);
|
|
}
|
|
|
|
if(!m_pGame->m_bEditor)
|
|
{
|
|
m_pGame->m_pSystem->SetIProcess(m_pGame->m_p3DEngine);
|
|
m_pGame->m_pSystem->GetIProcess()->SetFlags(PROC_3DENGINE);
|
|
}
|
|
|
|
m_pGame->m_pUIHud->Reset();
|
|
|
|
// We have to tell Ubisoft that the client has successfully connected
|
|
// If ubisoft is not running this won't do anything.
|
|
GetISystem()->GetINetwork()->Client_ReJoinGameServer();
|
|
|
|
m_bConnected = 1;
|
|
|
|
m_pGame->GetSystem()->SetForceNonDevMode(m_GameContext.bForceNonDevMode);
|
|
|
|
// clean up all the sounds that might have been started before the first
|
|
// frame to avoid problems with sloppy/bogus vis areas
|
|
// this calls RecomputeSoundOcclusion
|
|
|
|
if(m_pGame->GetSystem()->GetISoundSystem())
|
|
m_pGame->GetSystem()->GetISoundSystem()->Silence();
|
|
if(m_pGame->m_pSystem->GetIMusicSystem())
|
|
m_pGame->m_pSystem->GetIMusicSystem()->Silence();
|
|
|
|
if (!m_pGame->m_bIsLoadingLevelFromFile)
|
|
{
|
|
if (m_pGame->IsMultiplayer())
|
|
{
|
|
m_pGame->GotoMenu(true);
|
|
}
|
|
else
|
|
{
|
|
m_pGame->GotoGame(true);
|
|
}
|
|
}
|
|
|
|
if (!m_pGame->m_bIsLoadingLevelFromFile)
|
|
{
|
|
// m_pLog->Log("HIDE CONSOLE");
|
|
m_pGame->GetSystem()->GetIConsole()->ResetProgressBar(0);
|
|
m_pGame->m_pSystem->GetIConsole()->ShowConsole(false);
|
|
m_pGame->m_pSystem->GetIConsole()->SetScrollMax(600/2);
|
|
|
|
//if (m_pGame->IsMultiplayer())
|
|
m_pGame->GetSystem()->GetIRenderer()->ClearColorBuffer(Vec3(0,0,0));
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::UpdateClientNetwork()
|
|
{
|
|
assert(this);
|
|
if(m_bPlaybackDemo)
|
|
{
|
|
m_pGame->PlaybackChunk();
|
|
}
|
|
else
|
|
{
|
|
if(m_pIClient)
|
|
{
|
|
bool bThisExists=m_pIClient->Update(GetCurrentTime());// this pointer might be destroyed after this call
|
|
|
|
if(!bThisExists)
|
|
return;
|
|
}
|
|
}
|
|
|
|
assert(m_pTimer);
|
|
|
|
m_NetStats.Update(m_pTimer->GetCurrTimePrecise()); // keep statistics for one sec
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::OnXData(CStream &stm)
|
|
{
|
|
if(stm.GetReadPos()!=0)
|
|
{
|
|
CryError( "<CryGame> (CXClient::OnXData) Stream read position is zero" );
|
|
}
|
|
if(m_bRecordingDemo){
|
|
m_pGame->AddDemoChunk(stm);
|
|
}
|
|
// this is an incoming message for the client - it should not be processed on a server
|
|
ParseIncomingStream(stm);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
void CXClient::OnXServerTimeout()
|
|
{
|
|
m_pScriptSystem->BeginCall("ClientOnServerTimeout");
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
void CXClient::OnXServerRessurect()
|
|
{
|
|
m_pScriptSystem->BeginCall("ClientOnServerRessurect");
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::XConnect( const char *szAddr, bool _bDoLateSwitch, const bool inbCDAuthorization )
|
|
{
|
|
m_pIClient->SetServerIP(szAddr);
|
|
bDoSwitch=_bDoLateSwitch;
|
|
|
|
m_pIClient->InitiateCDKeyAuthorization(inbCDAuthorization);
|
|
|
|
m_pGame->m_szLastAddress = szAddr;
|
|
m_pGame->m_bLastDoLateSwitch = _bDoLateSwitch;
|
|
m_pGame->m_bLastCDAuthentication = inbCDAuthorization;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::DemoConnect()
|
|
{
|
|
m_bPlaybackDemo = true;
|
|
};
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::XDisconnect(const char *szCause)
|
|
{
|
|
if (m_pIClient)
|
|
m_pIClient->Disconnect(szCause);
|
|
}
|
|
|
|
void CXClient::UpdateSound( const float fFrameTime )
|
|
{
|
|
if(m_fFrontSound>0)
|
|
{
|
|
m_fFrontSound-=fFrameTime;
|
|
if(m_fFrontSound<0)
|
|
m_fFrontSound=0;
|
|
}
|
|
if(m_fBackSound>0)
|
|
{
|
|
m_fBackSound-=fFrameTime;
|
|
if(m_fBackSound<0)
|
|
m_fBackSound=0;
|
|
}
|
|
if(m_fLeftSound>0)
|
|
{
|
|
m_fLeftSound-=fFrameTime;
|
|
if(m_fLeftSound<0)
|
|
m_fLeftSound=0;
|
|
}
|
|
if(m_fRightSound>0)
|
|
{
|
|
m_fRightSound-=fFrameTime;
|
|
if(m_fRightSound<0)
|
|
m_fRightSound=0;
|
|
}
|
|
// remove old sounds from list
|
|
for (TSoundListIt It=m_lstSounds.begin();It!=m_lstSounds.end();)
|
|
{
|
|
SSoundInfo &SoundInfo=(*It);
|
|
SoundInfo.fTimeout-=fFrameTime;
|
|
if (SoundInfo.fTimeout<=0.0f)
|
|
{
|
|
It=m_lstSounds.erase(It);
|
|
}
|
|
else
|
|
{
|
|
++It;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::Update()
|
|
{
|
|
CPlayer *pPlayer=NULL;
|
|
CSpectator *pSpectator=NULL;
|
|
CAdvCamSystem *pAdvCamSystem=NULL;
|
|
|
|
ITimer *pTimer=m_pGame->m_pSystem->GetITimer();
|
|
float time = pTimer->GetCurrTime();
|
|
float fFrameTime=pTimer->GetFrameTime();
|
|
|
|
if(time-m_fLastClientStringTime>1)
|
|
m_sClientString="";
|
|
|
|
UpdateSound(fFrameTime);
|
|
|
|
IEntity *en=NULL;
|
|
IEntityContainer *pCnt=NULL;
|
|
|
|
if(m_wPlayerID != INVALID_WID)
|
|
{
|
|
en = m_pISystem->GetEntity(m_wPlayerID);
|
|
|
|
if(en && (pCnt=en->GetContainer()))
|
|
{
|
|
if(pCnt->QueryContainerInterface(CIT_IPLAYER,(void **) &pPlayer))
|
|
{
|
|
pPlayer->m_stats.concentration=false;
|
|
}
|
|
////////SPECTATOR CAMERA STUFF
|
|
if(pCnt->QueryContainerInterface(CIT_ISPECTATOR,(void **) &pSpectator))
|
|
{
|
|
EntityId idHost=pSpectator->GetHostId();
|
|
|
|
IEntity *pHost= m_pISystem->GetEntity(idHost);
|
|
if(pHost)
|
|
{
|
|
IEntityContainer *pHostCnt=pHost->GetContainer();
|
|
|
|
if(pHostCnt)
|
|
{
|
|
CPlayer *pPlayerHost;
|
|
|
|
if(pHostCnt->QueryContainerInterface(CIT_IPLAYER,(void **) &pPlayerHost))
|
|
{
|
|
pPlayerHost->SetViewMode(true);
|
|
pPlayerHost->UpdateCamera();
|
|
en=pHost;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if((!m_pGame->m_pSystem->GetIConsole()->IsOpened()) && (!m_pGame->m_bMenuOverlay) && m_pIActionMapManager)
|
|
m_pIActionMapManager->Update((unsigned int)(time*1000.f));
|
|
|
|
if(en==NULL)
|
|
return;
|
|
}
|
|
|
|
//ASSIGN THE CAMERA
|
|
IEntityCamera *pEntCam=NULL;
|
|
if (m_CameraParams->nCameraId)
|
|
{
|
|
IEntity *pEnt=m_pEntitySystem->GetEntity(m_CameraParams->nCameraId);
|
|
if (pEnt)
|
|
{
|
|
pEntCam=pEnt->GetCamera();
|
|
if (!pEntCam)
|
|
{
|
|
pEntCam=m_pGame->GetSystem()->GetIEntitySystem()->CreateEntityCamera();
|
|
pEnt->SetCamera(pEntCam);
|
|
pEntCam->GetCamera().Init(m_pGame->GetSystem()->GetIRenderer()->GetWidth(), m_pGame->GetSystem()->GetIRenderer()->GetHeight());
|
|
}
|
|
pEntCam->SetPos(pEnt->GetPos());
|
|
pEntCam->SetAngles(pEnt->GetAngles());
|
|
pEntCam->SetFov(m_CameraParams->fFOV, m_pGame->GetSystem()->GetIRenderer()->GetWidth(), m_pGame->GetSystem()->GetIRenderer()->GetHeight());
|
|
pEntCam->Update();
|
|
}
|
|
else
|
|
{
|
|
GameWarning( "Camera entity with Id %d not found",m_CameraParams->nCameraId );
|
|
}
|
|
}
|
|
|
|
if (!pEntCam)
|
|
{
|
|
if(en)
|
|
pEntCam=en->GetCamera();
|
|
}
|
|
|
|
{
|
|
bool bTimeToSend=(m_Snapshot.IsTimeToSend(fFrameTime) && m_pIClient->IsReady());
|
|
|
|
SendInputToServer(bTimeToSend);
|
|
}
|
|
|
|
if((m_wPlayerID != INVALID_WID))
|
|
{
|
|
if (m_nGameState != CGS_INTERMISSION)
|
|
{
|
|
if(m_fLastScoreBoardTime+0.5f<time)
|
|
{
|
|
m_fLastScoreBoardTime = time+10000;
|
|
m_pScriptSystem->BeginCall("ClientStuff", "ShowScoreBoard");
|
|
m_pScriptSystem->PushFuncParam(m_pClientStuff);
|
|
m_pScriptSystem->PushFuncParam(0);
|
|
m_pScriptSystem->EndCall();
|
|
};
|
|
}
|
|
}
|
|
|
|
if (m_pGame->UseFixedStep() && !m_lstUpdatedEntities.empty())
|
|
{
|
|
// send the list of off-sync entities
|
|
CStream stm;
|
|
unsigned char nEnts = min(255,m_lstUpdatedEntities.size());
|
|
stm.Write(nEnts);
|
|
for(int i=0;i<nEnts;i++)
|
|
stm.WritePkd(m_lstUpdatedEntities[i]->GetId());
|
|
m_lstUpdatedEntities.clear();
|
|
|
|
SendUnreliableMsg(XCLIENTMSG_ENTSOFFSYNC,stm);
|
|
}
|
|
|
|
if (pEntCam)
|
|
{
|
|
CCamera cam=pEntCam->GetCamera();
|
|
if(pPlayer)
|
|
cam.SetAngle(cam.GetAngles()+pPlayer->m_vShake);
|
|
//pEntCam->GetCamera().GetAngles()+m_vSh
|
|
m_pGame->m_pSystem->SetViewCamera(cam);
|
|
if(m_bLinkListenerToCamera && m_pGame->m_pSystem->GetISoundSystem())
|
|
m_pGame->m_pSystem->GetISoundSystem()->SetListener(cam,Vec3(0,0,0));
|
|
}
|
|
|
|
if (m_wPlayerID != INVALID_WID)
|
|
{
|
|
m_pScriptSystem->BeginCall("ClientStuff","OnUpdate");
|
|
m_pScriptSystem->PushFuncParam(m_pClientStuff);
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
|
|
// adjust commands per second (less is better for bandwidth, more is better for response)
|
|
{
|
|
int iCmdRate=cl_cmdrate->GetIVal();
|
|
|
|
iCmdRate=CLAMP(iCmdRate,5,100);
|
|
|
|
bool bInDrivingAVehicle=false; // reduce the command rate when in vehicles - to reduce upstream
|
|
|
|
if(pPlayer)
|
|
if(pPlayer->m_stats.inVehicleState==CPlayer::PVS_DRIVER)
|
|
bInDrivingAVehicle=true;
|
|
|
|
if(bInDrivingAVehicle && m_pGame->IsMultiplayer()) // only in MP we need the bandwidth
|
|
iCmdRate=(iCmdRate+1)/2;
|
|
|
|
if(m_Snapshot.GetSendPerSecond()!=iCmdRate)
|
|
m_Snapshot.SetSendPerSecond(iCmdRate);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////
|
|
// XCLIENTMSG_RETURNSCRIPTHASH
|
|
void CXClient::SendScriptHashResponse( const unsigned int dwHash )
|
|
{
|
|
CStream stm;
|
|
|
|
IBitStream *pBitStream = m_pGame->GetIBitStream();
|
|
|
|
pBitStream->WriteBitStream(stm,(uint32)dwHash,eDoNotCompress); // returned hash
|
|
SendReliableMsg(XCLIENTMSG_RETURNSCRIPTHASH,stm);
|
|
|
|
// debug
|
|
// m_pLog->Log("SendScriptHashResponse %p",dwHash);
|
|
}
|
|
|
|
|
|
void CXClient::SendInputToServer( const bool bTimeToSend )
|
|
{
|
|
if(m_wPlayerID==INVALID_WID)
|
|
return;
|
|
|
|
IEntity *en = m_pISystem->GetEntity(m_wPlayerID);
|
|
IBitStream *pBitStream=m_pGame->GetIBitStream(); // compressed or uncompressed
|
|
|
|
if(!en)
|
|
return;
|
|
|
|
IEntityContainer *pCnt=en->GetContainer();
|
|
|
|
if(!pCnt)
|
|
return;
|
|
|
|
CPlayer *pPlayer=NULL;
|
|
CSpectator *pSpectator=NULL;
|
|
CAdvCamSystem *pAdvCamSystem=NULL;
|
|
|
|
CStream &stm = m_Snapshot.GetReliableStream();
|
|
assert(!stm.GetSize());
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
//HANDLE A PLAYER CONTAINER
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
if(pCnt->QueryContainerInterface(CIT_IPLAYER,(void **) &pPlayer))
|
|
{
|
|
// Send the snapshot if it's time to do so
|
|
|
|
//when the game is in intermission state it will skip all client inputs
|
|
if(m_nGameState==CGS_INTERMISSION)
|
|
m_PlayerProcessingCmd.Reset();
|
|
|
|
// to clamp the angles (up/down)
|
|
pPlayer->ProcessAngles(m_PlayerProcessingCmd);
|
|
|
|
bool bSendToServer = false;
|
|
if (m_pGame->IsMultiplayer() || !pPlayer->IsAlive() || m_PlayerProcessingCmd.CheckAction(ACTION_SCORE_BOARD))
|
|
{
|
|
bSendToServer = true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (!bSendToServer)
|
|
{
|
|
// Perform player processing locally.
|
|
pPlayer->ProcessCmd( 0,m_PlayerProcessingCmd );
|
|
m_PrevPlayerProcessingCmd = m_PlayerProcessingCmd;
|
|
m_PlayerProcessingCmd.Reset();
|
|
}
|
|
else if(bTimeToSend)
|
|
{
|
|
CVehicle *pVehicle = pPlayer->GetVehicle();
|
|
pe_status_timeslices stc;
|
|
float slices[32];
|
|
stc.pTimeSlices = slices;
|
|
stc.sz = 32;
|
|
|
|
if (en->GetPhysics())
|
|
m_PrevPlayerProcessingCmd.AddTimeSlice(slices,en->GetPhysics()->GetStatus(&stc));
|
|
|
|
CXEntityProcessingCmd &epc=(m_pGame->IsServer() ? m_PlayerProcessingCmd : m_PrevPlayerProcessingCmd);
|
|
|
|
//AIMING STUFF
|
|
if(pPlayer->m_stats.aiming)
|
|
epc.AddAction(ACTION_ZOOM_TOGGLE);
|
|
else
|
|
epc.RemoveAction(ACTION_ZOOM_TOGGLE);
|
|
|
|
CPlayer::SWalkParams wp=pPlayer->GetWalkParams();
|
|
epc.SetLeaning(wp.fCurrLean);
|
|
if (pVehicle)
|
|
epc.ResetTimeSlices();
|
|
|
|
// write the player processing cmd
|
|
m_PrevPlayerProcessingCmd.SetPhysicalTime(m_pGame->GetSystem()->GetIPhysicalWorld()->GetiPhysicsTime());
|
|
|
|
// used for sending ordered reliable data over the unreliable connection (slow but never stalls, used for scoreboard)
|
|
stm.Write(m_bLazyChannelState);
|
|
|
|
{
|
|
// sync random seed (to the server)
|
|
bool bSyncToServer=pPlayer->m_SynchedRandomSeed.IsTimeToSyncToServerC();
|
|
|
|
stm.Write(bSyncToServer);
|
|
if(bSyncToServer)
|
|
{
|
|
stm.Write(pPlayer->m_SynchedRandomSeed.GetStartRandomSeedC());
|
|
// GetISystem()->GetILog()->Log(">> ClientCmd Write %d %d",(int)pPlayer->GetEntity()->GetId(),(int)pPlayer->m_SynchedRandomSeed.GetStartRandomSeedC()); // debug
|
|
}
|
|
}
|
|
|
|
epc.Write(stm,pBitStream,true);
|
|
|
|
if(pVehicle && pPlayer->m_stats.inVehicleState==CPlayer::PVS_DRIVER && !m_pGame->IsServer())
|
|
{
|
|
stm.Write(true);
|
|
pBitStream->WriteBitStream(stm,pVehicle->GetEntity()->GetId(),eEntityId);
|
|
// stm.Write(pVehicle->GetEntity()->GetId());
|
|
m_stmVehicle.Reset();
|
|
pVehicle->GetEntity()->Write(m_stmVehicle);
|
|
stm.Write((short)m_stmVehicle.GetSize());
|
|
stm.Write(m_stmVehicle);
|
|
}
|
|
else
|
|
stm.Write(false);
|
|
stm.Write(false); // client pos (used for spectators)
|
|
|
|
// send the main streams
|
|
SendUnreliableMsg(XCLIENTMSG_PLAYERPROCESSINGCMD,m_Snapshot.GetReliableStream(),true); // with size
|
|
|
|
m_Snapshot.Reset();
|
|
|
|
if(pPlayer && !m_pGame->IsServer())
|
|
{
|
|
pPlayer->ProcessMovements(m_PlayerProcessingCmd);
|
|
|
|
// special fire processing for the client in MP
|
|
// it will always perform the fire on the local event
|
|
if (m_pGame->IsMultiplayer() && pPlayer->IsMyPlayer())
|
|
{
|
|
CXEntityProcessingCmd tempPC;
|
|
if (m_PlayerProcessingCmd.CheckAction(ACTION_FIRE0))
|
|
tempPC.AddAction(ACTION_FIRE0);
|
|
if (m_PlayerProcessingCmd.CheckAction(ACTION_FIRE_GRENADE))
|
|
tempPC.AddAction(ACTION_FIRE_GRENADE);
|
|
pPlayer->ProcessWeapons(tempPC);
|
|
}
|
|
}
|
|
|
|
m_PrevPlayerProcessingCmd = m_PlayerProcessingCmd;
|
|
|
|
m_PlayerProcessingCmd.Reset();
|
|
}
|
|
|
|
}
|
|
else if(pCnt->QueryContainerInterface(CIT_ISPECTATOR,(void **) &pSpectator))
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
//HANDLE A SPECTATOR
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
pSpectator->ProcessKeys(m_PlayerProcessingCmd);
|
|
|
|
if(bTimeToSend)
|
|
{
|
|
// write the player processing cmd
|
|
m_PlayerProcessingCmd.SetPhysicalTime(m_pGame->GetSystem()->GetIPhysicalWorld()->GetiPhysicsTime());
|
|
|
|
// used for sending ordered reliable data over the unreliable connection (slow but never stalls, used for scoreboard)
|
|
stm.Write(m_bLazyChannelState);
|
|
|
|
stm.Write(false); // random seed (do not sync)
|
|
|
|
m_PlayerProcessingCmd.Write(stm,pBitStream,false);
|
|
|
|
stm.Write(false); // no vehicle data
|
|
stm.Write(true);
|
|
Vec3 pos = en->GetPos();
|
|
if (inrange(pos.x,0.0f,4095.0f)&inrange(pos.y,0.0f,4095.f)&inrange(pos.z,0.0f,511.0f))
|
|
{
|
|
stm.Write(true);
|
|
stm.WriteNumberInBits((int)(pos.x*16+0.5f),16);
|
|
stm.WriteNumberInBits((int)(pos.y*16+0.5f),16);
|
|
stm.WriteNumberInBits((int)(pos.z*16+0.5f),13);
|
|
}
|
|
else
|
|
{
|
|
stm.Write(false);
|
|
stm.Write(pos);
|
|
}
|
|
|
|
SendUnreliableMsg(XCLIENTMSG_PLAYERPROCESSINGCMD,m_Snapshot.GetReliableStream(),true); // with size
|
|
|
|
m_Snapshot.Reset();
|
|
}
|
|
m_PlayerProcessingCmd.Reset();
|
|
}
|
|
else if(pCnt->QueryContainerInterface(CIT_IADVCAMSYSTEM,(void **) &pAdvCamSystem))
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
//HANDLE A AdvancedCameraSystem
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
if(bTimeToSend)
|
|
{
|
|
// to clamp the angles (up/down)
|
|
pAdvCamSystem->ProcessKeys(m_PlayerProcessingCmd);
|
|
|
|
// used for sending ordered reliable data over the unreliable connection (slow but never stalls, used for scoreboard)
|
|
stm.Write(m_bLazyChannelState);
|
|
|
|
stm.Write(false); // random seed (do not sync)
|
|
|
|
// write the player processing cmd
|
|
m_PlayerProcessingCmd.Write(stm,pBitStream,true);
|
|
stm.Write(false); // no vehicle data
|
|
stm.Write(false); // client pos (used for spectators)
|
|
|
|
SendUnreliableMsg(XCLIENTMSG_PLAYERPROCESSINGCMD,m_Snapshot.GetReliableStream(),true); // with size
|
|
|
|
m_Snapshot.Reset();
|
|
}
|
|
m_PlayerProcessingCmd.Reset();
|
|
}
|
|
}
|
|
|
|
const char *CXClient::GetMsgName( XCLIENTMSG inValue )
|
|
{
|
|
switch(inValue)
|
|
{
|
|
#define ADDNAME(name) case XCLIENTMSG_##name: return(#name);
|
|
ADDNAME(UNKNOWN)
|
|
ADDNAME(PLAYERPROCESSINGCMD)
|
|
ADDNAME(TEXT)
|
|
ADDNAME(JOINTEAMREQUEST)
|
|
ADDNAME(CALLVOTE)
|
|
ADDNAME(VOTE)
|
|
ADDNAME(KILL)
|
|
ADDNAME(CMD)
|
|
ADDNAME(RATE)
|
|
ADDNAME(ENTSOFFSYNC)
|
|
#undef ADDNAME
|
|
default: assert(0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void CXClient::DrawNetStats()
|
|
{
|
|
int iRoundtripInMS = m_pIClient->GetPing()*2;
|
|
float fIncomingKbPerSec,fOutgoingKbPerSec;
|
|
DWORD nIncomingPacketsPerSec,nOutgoingPacketsPerSec;
|
|
m_pIClient->GetBandwidth(fIncomingKbPerSec,fOutgoingKbPerSec,nIncomingPacketsPerSec,nOutgoingPacketsPerSec);
|
|
unsigned int lost = m_pIClient->GetPacketsLostCount();
|
|
unsigned int ulost = m_pIClient->GetUnreliablePacketsLostCount();
|
|
IRenderer *pRen=m_pGame->m_pSystem->GetIRenderer();
|
|
pRen->TextToScreen(10,70,"Roundtrip [%dms] LOST [%d] ULOST [%d] DISCARDED[%d]",iRoundtripInMS,lost,ulost,m_nDiscardedPackets);
|
|
|
|
float fPacketSize=(20+8)*8.0f/1024.0f; // 20bytes IP + 8bytes UDP in kBit
|
|
|
|
pRen->TextToScreen(10,75,"BANDWIDTH IN=%.2f/%.2f Kbits/sec (%d) OUT=%.2f/%.2f Kbits/sec (%d)",
|
|
fIncomingKbPerSec, fIncomingKbPerSec+fPacketSize*nIncomingPacketsPerSec, nIncomingPacketsPerSec,
|
|
fOutgoingKbPerSec, fOutgoingKbPerSec+fPacketSize*nOutgoingPacketsPerSec, nOutgoingPacketsPerSec);
|
|
|
|
#ifndef REDUCED_FOR_PUBLIC_RELEASE
|
|
pRen->TextToScreen(0,78,"Packets produced but might not be sent:");
|
|
|
|
static DWORD sResetCount=0;
|
|
|
|
bool bNewDataArrived = m_NetStats.GetResetCount()!=sResetCount;
|
|
|
|
sResetCount=m_NetStats.GetResetCount();
|
|
|
|
for(int i=0;;i++)
|
|
{
|
|
DWORD dwRelCount,dwUnrelCount,dwItem;
|
|
size_t nBitSize;
|
|
|
|
if(!m_NetStats.GetStats(i,dwItem,dwRelCount,dwUnrelCount,nBitSize))
|
|
break;
|
|
|
|
pRen->TextToScreen(10,78+(i+1)*3.0f,"(R:%d U:%d Bits:%d) %s",dwRelCount,dwUnrelCount,nBitSize,GetMsgName((XSERVERMSG)dwItem));
|
|
|
|
if(bNewDataArrived)
|
|
m_pLog->Log("Client (R:%d U:%d Bits:%d) %s",dwRelCount,dwUnrelCount,nBitSize,GetMsgName((XSERVERMSG)dwItem));
|
|
}
|
|
|
|
if(bNewDataArrived)
|
|
m_pLog->Log("-------<netstats end>n");
|
|
#endif
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::OnMapChanged()
|
|
{
|
|
m_bMapConnecting = true;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::OnMapChangedReally()
|
|
{
|
|
m_bMapConnecting = false;
|
|
|
|
// [marcio] reseting the movie system here stop any cutscene the begins imediately
|
|
// after the game starts.
|
|
// loading first checkpoint in:
|
|
// Factory
|
|
// Carrier
|
|
//
|
|
//m_pGame->GetSystem()->GetIMovieSystem()->Reset();
|
|
|
|
// [marco] save the first checkpoint in single player game
|
|
// after the client has been connected, ID set etc. etc.
|
|
// do NOT save if this map was already loaded from a checkpoint saved game!
|
|
if (!m_pGame->IsMultiplayer() && !m_pGame->m_bMapLoadedFromCheckpoint)
|
|
{
|
|
m_pLog->Log("\001 Saving first checkpoint");
|
|
IAISystem *pAISystem = m_pGame->GetSystem()->GetAISystem();
|
|
if (pAISystem)
|
|
{
|
|
if (pAISystem->GetAutoBalanceInterface())
|
|
{
|
|
pAISystem->GetAutoBalanceInterface()->Checkpoint();
|
|
pAISystem->GetAutoBalanceInterface()->SetAllowedDeathCount(2);
|
|
}
|
|
}
|
|
|
|
ITagPoint *pRespawn;
|
|
pRespawn=m_pGame->GetTagPoint("Respawn0");
|
|
if (pRespawn)
|
|
{
|
|
Vec3 vPos,vAngles;
|
|
pRespawn->GetPos(vPos);
|
|
pRespawn->GetAngles(vAngles);
|
|
char buf[1024];
|
|
sprintf(buf, "checkpoint_%s_%s_1", m_pGame->g_LevelName->GetString(), m_pGame->m_pServer->m_GameContext.strMission.c_str());
|
|
m_pGame->Save( buf, &vPos,&vAngles,true );
|
|
}
|
|
IInput *pInput=m_pGame->GetSystem()->GetIInput();
|
|
if(pInput)
|
|
pInput->GetIKeyboard()->ClearKeyState();
|
|
}
|
|
|
|
m_pScriptSystem->BeginCall("ClientStuff", "OnMapChange");
|
|
m_pScriptSystem->PushFuncParam(m_pClientStuff);
|
|
m_pScriptSystem->EndCall();
|
|
|
|
if (!m_pGame->IsMultiplayer() && !m_pGame->m_bMapLoadedFromCheckpoint)
|
|
{
|
|
_SmartScriptObject pMissionScript(m_pScriptSystem);
|
|
m_pScriptSystem->GetGlobalValue("Mission", pMissionScript);
|
|
|
|
if (((IScriptObject *)pMissionScript) != 0)
|
|
{
|
|
HSCRIPTFUNCTION temp=0;
|
|
bool bRes=pMissionScript->GetValue( "OnMapChange",temp );
|
|
temp=0;
|
|
if (bRes)
|
|
{
|
|
m_pScriptSystem->BeginCall("Mission", "OnMapChange");
|
|
m_pScriptSystem->PushFuncParam((IScriptObject*)pMissionScript);
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::SendReliable(CStream &stm)
|
|
{
|
|
m_NetStats.AddPacket(XCLIENTMSG_UNIDENTIFIED,stm.GetSize(),true);
|
|
|
|
m_pIClient->SendReliable(stm);
|
|
|
|
|
|
#ifdef NET_PACKET_LOGGING
|
|
// debugging
|
|
{
|
|
FILE *out=fopen("c:/temp/ClientOutPackets.txt","a");
|
|
|
|
if(out)
|
|
{
|
|
size_t size=stm.GetSize();
|
|
BYTE *p=stm.GetPtr();
|
|
|
|
fprintf(out,"Rel Ptr:%p Bits:%4d %s %s ",this,(int)size,"UNIDENTIFIED","");
|
|
|
|
for(DWORD i=0;i<(size+7)/8;i++)
|
|
{
|
|
int iH=p[i]>>4;
|
|
int iL=p[i]&0xf;
|
|
|
|
char cH = iH<10?iH+'0':iH-10+'A';
|
|
char cL = iL<10?iL+'0':iL-10+'A';
|
|
|
|
fputc(cH,out);
|
|
fputc(cL,out);
|
|
}
|
|
|
|
fprintf(out,"\n");
|
|
|
|
fclose(out);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::SendUnreliable(CStream &stm)
|
|
{
|
|
m_NetStats.AddPacket(XCLIENTMSG_UNIDENTIFIED,stm.GetSize(),false);
|
|
|
|
m_pIClient->SendUnreliable(stm);
|
|
|
|
|
|
#ifdef NET_PACKET_LOGGING
|
|
// debugging
|
|
{
|
|
FILE *out=fopen("c:/temp/ClientOutPackets.txt","a");
|
|
|
|
if(out)
|
|
{
|
|
size_t size=stm.GetSize();
|
|
BYTE *p=stm.GetPtr();
|
|
|
|
fprintf(out,"Unrel Ptr:%p Bits:%4d %s %s ",this,(int)size,"UNIDENTIFIED","");
|
|
|
|
for(DWORD i=0;i<(size+7)/8;i++)
|
|
{
|
|
int iH=p[i]>>4;
|
|
int iL=p[i]&0xf;
|
|
|
|
char cH = iH<10?iH+'0':iH-10+'A';
|
|
char cL = iL<10?iL+'0':iL-10+'A';
|
|
|
|
fputc(cH,out);
|
|
fputc(cL,out);
|
|
}
|
|
|
|
fprintf(out,"\n");
|
|
|
|
fclose(out);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
size_t CXClient::SendReliableMsg(XCLIENTMSG msg, CStream &stm)
|
|
{
|
|
CStream istm;
|
|
istm.Write(msg);
|
|
istm.Write(stm);
|
|
m_pIClient->SendReliable(istm);
|
|
|
|
m_NetStats.AddPacket(msg,istm.GetSize(),true);
|
|
|
|
|
|
#ifdef NET_PACKET_LOGGING
|
|
// debugging
|
|
{
|
|
FILE *out=fopen("c:/temp/ClientOutPackets.txt","a");
|
|
|
|
if(out)
|
|
{
|
|
size_t size=istm.GetSize();
|
|
BYTE *p=istm.GetPtr();
|
|
|
|
fprintf(out,"Rel Ptr:%p Bits:%4d %s %s ",this,(int)size,CXClient::GetMsgName(msg),"");
|
|
|
|
for(DWORD i=0;i<(size+7)/8;i++)
|
|
{
|
|
int iH=p[i]>>4;
|
|
int iL=p[i]&0xf;
|
|
|
|
char cH = iH<10?iH+'0':iH-10+'A';
|
|
char cL = iL<10?iL+'0':iL-10+'A';
|
|
|
|
fputc(cH,out);
|
|
fputc(cL,out);
|
|
}
|
|
|
|
fprintf(out,"\n");
|
|
|
|
fclose(out);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
return istm.GetSize();
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
size_t CXClient::SendUnreliableMsg(XCLIENTMSG msg, CStream &stm, const bool bWithSize )
|
|
{
|
|
CStream istm;
|
|
istm.Write(msg);
|
|
|
|
if(bWithSize)
|
|
istm.WritePkd((short)stm.GetSize()); // sub packet size (without packet id and size itself)
|
|
|
|
istm.Write(stm);
|
|
m_pIClient->SendUnreliable(istm);
|
|
|
|
m_NetStats.AddPacket(msg,istm.GetSize(),false);
|
|
|
|
|
|
#ifdef NET_PACKET_LOGGING
|
|
// debugging
|
|
{
|
|
FILE *out=fopen("c:/temp/ClientOutPackets.txt","a");
|
|
|
|
if(out)
|
|
{
|
|
size_t size=istm.GetSize();
|
|
BYTE *p=istm.GetPtr();
|
|
|
|
fprintf(out,"Unrel Ptr:%p Bits:%4d %s %s ",this,(int)size,CXClient::GetMsgName(msg),"");
|
|
|
|
for(DWORD i=0;i<(size+7)/8;i++)
|
|
{
|
|
int iH=p[i]>>4;
|
|
int iL=p[i]&0xf;
|
|
|
|
char cH = iH<10?iH+'0':iH-10+'A';
|
|
char cL = iL<10?iL+'0':iL-10+'A';
|
|
|
|
fputc(cH,out);
|
|
fputc(cL,out);
|
|
}
|
|
|
|
fprintf(out,"\n");
|
|
|
|
fclose(out);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return istm.GetSize();
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
bool CXClient::IsReady()
|
|
{
|
|
return m_pIClient->IsReady();
|
|
}
|
|
|
|
|
|
|
|
EntityId CXClient::GetPlayerId() const
|
|
{
|
|
return m_wPlayerID;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::SetPlayerID( EntityId wPlayerID )
|
|
{
|
|
m_wPlayerID=wPlayerID;
|
|
IEntity *pPlayer = 0;
|
|
|
|
if(m_pISystem)
|
|
pPlayer=m_pISystem->GetEntity(wPlayerID);
|
|
|
|
if(pPlayer)
|
|
m_pScriptSystem->SetGlobalValue("_localplayer",pPlayer->GetScriptObject());
|
|
else
|
|
m_pScriptSystem->SetGlobalToNull("_localplayer");
|
|
|
|
if(pPlayer)
|
|
m_pGame->SetCurrentUI(m_pGame->m_pUIHud);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::UpdateISystem()
|
|
{
|
|
SAFE_RELEASE(m_pISystem);
|
|
|
|
// create the system interface
|
|
if(m_pGame->IsServer())
|
|
{
|
|
m_pISystem = new CXSystemDummy(m_pGame,m_pGame->m_pLog); // Dummy interface if this game is client/server
|
|
TRACE("DUMMY SYSTEM");
|
|
m_bLocalHost = true;
|
|
}
|
|
else
|
|
{
|
|
m_pISystem = new CXSystemClient(m_pGame,m_pGame->m_pLog); // Client interface if this game is only client
|
|
TRACE("CLIENT SYSTEM");
|
|
m_bLocalHost = false;
|
|
m_pGame->GetSystem()->GetIEntitySystem()->SetSink(this);
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerMoveLeft(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_MOVE_LEFT);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerMoveRight(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_MOVE_RIGHT);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerMoveForward(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_MOVE_FORWARD);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerMoveBackward(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_MOVE_BACKWARD);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerJump(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_JUMP);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerMoveMode(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_MOVEMODE);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerMoveModeToggle(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_MOVEMODE_TOGGLE);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerAimToggle(float fValue,XActivationEvent ae)
|
|
{
|
|
IEntity *pEntity=m_pEntitySystem->GetEntity(m_wPlayerID);
|
|
|
|
if (pEntity)
|
|
{
|
|
IEntityContainer *pContainer=pEntity->GetContainer();
|
|
|
|
if(pContainer)
|
|
{
|
|
CPlayer *pPlayer;
|
|
|
|
pContainer->QueryContainerInterface(CIT_IPLAYER, (void**) &pPlayer);
|
|
|
|
if (pPlayer)
|
|
pEntity->SendScriptEvent(ScriptEvent_ZoomToggle, (!pPlayer->m_stats.aiming)?1:2);
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// move mode double click
|
|
void CXClient::TriggerMoveMode2(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_MOVEMODE2);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerLeanLeft(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_LEANLEFT);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerLeanRight(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_LEANRIGHT);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerHoldBreath(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_HOLDBREATH);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerFireMode(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_FIREMODE);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerFire0(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_FIRE0);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerFireCancel(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_FIRECANCEL);
|
|
}
|
|
|
|
void CXClient::TriggerFireGrenade(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_FIRE_GRENADE);
|
|
}
|
|
|
|
void CXClient::TriggerFlashlight(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_FLASHLIGHT);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerChangeView(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_CHANGE_VIEW);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerVehicleBoost(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_VEHICLE_BOOST);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerReload(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_RELOAD);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerUse(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_USE);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerTurnLR(float fValue,XActivationEvent ae)
|
|
{
|
|
float fFovMul = 1.0f;
|
|
IEntity *pPlayerEnt = m_pISystem->GetEntity( m_wPlayerID );
|
|
if (pPlayerEnt)
|
|
{
|
|
|
|
IEntityCamera *pCam = pPlayerEnt->GetCamera();
|
|
if (pCam)
|
|
{
|
|
fFovMul = (float) (pCam->GetFov() / 1.5707963267948966192313216916398);
|
|
}
|
|
}
|
|
m_PlayerProcessingCmd.GetDeltaAngles()[ROLL] -= fValue*fFovMul;
|
|
m_PlayerProcessingCmd.AddAction(ACTION_TURNLR);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerTurnUD(float fValue,XActivationEvent ae)
|
|
{
|
|
float fFovMul = 1.0f;
|
|
IEntity *pPlayerEnt = m_pISystem->GetEntity( m_wPlayerID );
|
|
if (pPlayerEnt)
|
|
{
|
|
|
|
IEntityCamera *pCam = pPlayerEnt->GetCamera();
|
|
if (pCam)
|
|
{
|
|
fFovMul = float(pCam->GetFov() / 1.5707963267948966192313216916398);
|
|
}
|
|
//RESET RECOIL RETURN
|
|
IEntityContainer *pCnt=pPlayerEnt->GetContainer();
|
|
if(pCnt){
|
|
CPlayer *pP=NULL;
|
|
pCnt->QueryContainerInterface(CIT_IPLAYER,(void **)&pP);
|
|
if(pP){
|
|
pP->m_fRecoilXDelta=0;
|
|
}
|
|
}
|
|
}
|
|
m_PlayerProcessingCmd.GetDeltaAngles()[YAW] += fValue*fFovMul;
|
|
m_PlayerProcessingCmd.AddAction(ACTION_TURNUD);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerWalk(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_WALK);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
void CXClient::TriggerRunSprint(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_RUNSPRINT);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerNextWeapon(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_NEXT_WEAPON);
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerPrevWeapon(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction(ACTION_PREV_WEAPON);
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerWeapon0(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction( ACTION_WEAPON_0 );
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerWeapon1(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction( ACTION_WEAPON_1 );
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerWeapon2(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction( ACTION_WEAPON_2 );
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerWeapon3(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction( ACTION_WEAPON_3 );
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerWeapon4(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction( ACTION_WEAPON_4 );
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
/*void CXClient::TriggerWeapon5(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction( ACTION_WEAPON_5 );
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerWeapon6(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction( ACTION_WEAPON_6 );
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerWeapon7(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction( ACTION_WEAPON_7 );
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerWeapon8(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction( ACTION_WEAPON_8 );
|
|
}
|
|
*/
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::CycleGrenade(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction( ACTION_CYCLE_GRENADE );
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::TriggerDropWeapon(float fValue,XActivationEvent ae)
|
|
{
|
|
m_PlayerProcessingCmd.AddAction( ACTION_DROPWEAPON );
|
|
}
|
|
|
|
|
|
void CXClient::TriggerItem0(float fValue,XActivationEvent ae)
|
|
{
|
|
IEntity *pEntity=m_pEntitySystem->GetEntity(m_wPlayerID);
|
|
if(pEntity)
|
|
pEntity->SendScriptEvent(ScriptEvent_ItemActivated, 0);
|
|
}
|
|
|
|
void CXClient::TriggerItem1(float fValue,XActivationEvent ae)
|
|
{
|
|
IEntity *pEntity=m_pEntitySystem->GetEntity(m_wPlayerID);
|
|
if(pEntity)
|
|
pEntity->SendScriptEvent(ScriptEvent_ItemActivated, 1);
|
|
}
|
|
|
|
void CXClient::TriggerItem2(float fValue,XActivationEvent ae)
|
|
{
|
|
IEntity *pEntity=m_pEntitySystem->GetEntity(m_wPlayerID);
|
|
if(pEntity)
|
|
pEntity->SendScriptEvent(ScriptEvent_ItemActivated, 2);
|
|
}
|
|
|
|
void CXClient::TriggerItem3(float fValue,XActivationEvent ae)
|
|
{
|
|
IEntity *pEntity=m_pEntitySystem->GetEntity(m_wPlayerID);
|
|
if(pEntity)
|
|
pEntity->SendScriptEvent(ScriptEvent_ItemActivated, 3);
|
|
}
|
|
|
|
void CXClient::TriggerZoomToggle(float fValue,XActivationEvent ae)
|
|
{
|
|
IEntity *pEntity=m_pEntitySystem->GetEntity(m_wPlayerID);
|
|
if(pEntity)
|
|
{
|
|
|
|
pEntity->SendScriptEvent(ScriptEvent_ZoomToggle, (ae==etPressing?1:0));
|
|
}
|
|
}
|
|
|
|
void CXClient::TriggerZoomIn(float fValue,XActivationEvent ae)
|
|
{
|
|
IEntity *pEntity=m_pEntitySystem->GetEntity(m_wPlayerID);
|
|
if(pEntity)
|
|
pEntity->SendScriptEvent(ScriptEvent_ZoomIn, 0);
|
|
}
|
|
|
|
void CXClient::TriggerZoomOut(float fValue,XActivationEvent ae)
|
|
{
|
|
IEntity *pEntity=m_pEntitySystem->GetEntity(m_wPlayerID);
|
|
if(pEntity)
|
|
pEntity->SendScriptEvent(ScriptEvent_ZoomOut, 0);
|
|
}
|
|
|
|
void CXClient::TriggerConcentration(float fValue,XActivationEvent ae)
|
|
{
|
|
IEntity *pEntity=m_pEntitySystem->GetEntity(m_wPlayerID);
|
|
IEntityContainer *pContainer=pEntity->GetContainer();
|
|
if(pContainer)
|
|
{
|
|
CPlayer *pPlayer;
|
|
pContainer->QueryContainerInterface(CIT_IPLAYER, (void**) &pPlayer);
|
|
if (pPlayer)
|
|
pPlayer->m_stats.concentration=true;
|
|
}
|
|
}
|
|
|
|
void CXClient::TriggerQuickLoad(float fValue,XActivationEvent ae)
|
|
{
|
|
if (m_pGame->IsQuicksaveAllowed())
|
|
m_pGame->SendMessage("LoadGame");
|
|
}
|
|
|
|
void CXClient::TriggerQuickSave(float fValue,XActivationEvent ae)
|
|
{
|
|
ICVar *g_LevelStated = GetISystem()->GetIConsole()->GetCVar("g_LevelStated");
|
|
if (!g_LevelStated->GetIVal())
|
|
{
|
|
if (m_pGame->IsQuicksaveAllowed())
|
|
m_pGame->SendMessage("SaveGame");
|
|
}
|
|
}
|
|
|
|
void CXClient::TriggerMessageMode(float fValue,XActivationEvent ae)
|
|
{
|
|
m_pGame->m_pSystem->GetIConsole()->ExecuteString("messagemode", 0);
|
|
}
|
|
|
|
void CXClient::TriggerMessageMode2(float fValue,XActivationEvent ae)
|
|
{
|
|
m_pGame->m_pSystem->GetIConsole()->ExecuteString("messagemode2", 0);
|
|
}
|
|
|
|
void CXClient::TriggerScreenshot(float fValue, XActivationEvent ae)
|
|
{
|
|
m_pGame->m_pSystem->GetIConsole()->ExecuteString("r_GetScreenShot 1", 0);
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// Client parser.
|
|
|
|
//#define DEBUG_SNAPSHOT
|
|
bool CXClient::ParseIncomingStream(CStream &stm)
|
|
{
|
|
// this is an incoming message for the client - it should not be processed on a server
|
|
|
|
bool bRet = false;
|
|
static int lastSuccessfulPacketID=-1;
|
|
XSERVERMSG msg=0;
|
|
//m_lstUpdatedEntities.clear();
|
|
|
|
m_lstGarbageEntities.clear();
|
|
//TRACE("--BEGIN---ParseIncomingStream--------------");
|
|
|
|
do
|
|
{
|
|
if(!stm.ReadPkd(msg))
|
|
return false;
|
|
#ifdef DEBUG_SNAPSHOT
|
|
TRACE("SERVER MESSAGE\n");
|
|
TRACE(">> STREAM size=%04d readpos=%04d",stm.GetSize(),stm.GetReadPos());
|
|
#endif
|
|
switch(msg)
|
|
{
|
|
////////////////////////////////////////////
|
|
//RELIABLE MESSAGES
|
|
case XSERVERMSG_SETTEAM:
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_SETTEAM\n");
|
|
#endif
|
|
OnServerMsgSetTeam(stm);
|
|
break;
|
|
case XSERVERMSG_ADDTEAM:
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_ADDTEAM\n");
|
|
#endif
|
|
OnServerMsgAddTeam(stm);
|
|
break;
|
|
case XSERVERMSG_REMOVETEAM:
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_REMOVETEAM\n");
|
|
#endif
|
|
OnServerMsgRemoveTeam(stm);
|
|
break;
|
|
case XSERVERMSG_REQUESTSCRIPTHASH:
|
|
OnServerMsgRequestScriptHash(stm);
|
|
break;
|
|
case XSERVERMSG_SETTEAMSCORE:
|
|
OnServerMsgSetTeamScore(stm);
|
|
break;
|
|
case XSERVERMSG_SETTEAMFLAGS:
|
|
OnServerMsgSetTeamFlags(stm);
|
|
break;
|
|
case XSERVERMSG_TEXT:
|
|
#ifdef DEBUG_SNAPSHOT
|
|
TRACE("XSERVERMSG_TEXT\n");
|
|
#endif
|
|
OnServerMsgText(stm);
|
|
break;
|
|
case XSERVERMSG_SETPLAYER:
|
|
//#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_SETPLAYER\n");
|
|
//#endif
|
|
OnServerMsgSetPlayer(stm);
|
|
break;
|
|
case XSERVERMSG_ADDENTITY:
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_ADDENTITY\n");
|
|
#endif
|
|
OnServerMsgAddEntity(stm);
|
|
break;
|
|
case XSERVERMSG_REMOVEENTITY:
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_REMOVEENTITY\n");
|
|
#endif
|
|
OnServerMsgRemoveEntity(stm);
|
|
break;
|
|
case XSERVERMSG_SETENTITYNAME:
|
|
//#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_SETENTITYNAME");
|
|
//#endif
|
|
OnServerMsgSetEntityName(stm);
|
|
break;
|
|
case XSERVERMSG_SETPLAYERSCORE:
|
|
NET_TRACE("<<NET>>XSERVERMSG_SETPLAYERSCORE");
|
|
OnServerMsgSetPlayerScore(stm);
|
|
break;
|
|
case XSERVERMSG_SETENTITYSTATE:
|
|
NET_TRACE("<<NET>>XSERVERMSG_SETENTITYSTATE");
|
|
OnServerMsgSetEntityState(stm);
|
|
break;
|
|
case XSERVERMSG_BINDENTITY:
|
|
NET_TRACE("<<NET>>XSERVERMSG_BINDENTITY");
|
|
OnServerMsgBindEntity(stm);
|
|
break;
|
|
case XSERVERMSG_SCOREBOARD:
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_SCOREBOARD\n");
|
|
#endif
|
|
{
|
|
short size;
|
|
|
|
if(!stm.ReadPkd(size)) // sub packet size
|
|
return false;
|
|
|
|
size_t readpos=stm.GetReadPos();
|
|
|
|
OnServerMsgScoreBoard(stm);
|
|
|
|
assert(stm.GetReadPos()==readpos+size); // just for testing
|
|
|
|
stm.Seek(readpos+size); // jump over it in the case the packet wasn't processable
|
|
}
|
|
break;
|
|
case XSERVERMSG_SETGAMESTATE:
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_SETGAMESTATE\n");
|
|
#endif
|
|
OnServerMsgGameState(stm);
|
|
break;
|
|
/* case XSERVERMSG_OBITUARY:
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_OBITUARY\n");
|
|
#endif
|
|
OnServerMsgObituary(stm);
|
|
break;
|
|
*/ case XSERVERMSG_TEAMS:
|
|
NET_TRACE("<<NET>>XSERVERMSG_TEAMS\n");
|
|
m_pISystem->ReadTeams(stm);
|
|
break;
|
|
case XSERVERMSG_CMD:
|
|
OnServerMsgCmd(stm);
|
|
break;
|
|
case XSERVERMSG_SYNCVAR:
|
|
OnServerMsgSyncVar(stm);
|
|
break;
|
|
case XSERVERMSG_AISTATE:
|
|
OnServerMsgSyncAIState(stm);
|
|
break;
|
|
////////////////////////////////////////////
|
|
//UNRELIABLE MESSAGES(are discarded by the local host)
|
|
case XSERVERMSG_CLIENTSTRING:
|
|
if(!OnServerMsgClientString(stm))
|
|
return false;
|
|
case XSERVERMSG_UPDATEENTITY:
|
|
if(m_bLocalHost)
|
|
return true;
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_UPDATEENTITY\n");
|
|
#endif
|
|
if(!OnServerMsgUpdateEntity(stm))
|
|
return false;
|
|
break;
|
|
case XSERVERMSG_TIMESTAMP:
|
|
if(m_bLocalHost)
|
|
return true;
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>XSERVERMSG_TIMESTAMP\n");
|
|
#endif
|
|
if(!OnServerMsgTimeStamp(stm))
|
|
{
|
|
NET_TRACE("<<NET>>OLD PACKET DISCARDED");
|
|
m_nDiscardedPackets++;
|
|
return false;
|
|
}
|
|
break;
|
|
case XSERVERMSG_EVENTSCHEDULE:
|
|
if(m_bLocalHost)
|
|
return true;
|
|
if (!OnServerMsgEventSchedule(stm))
|
|
return false;
|
|
break;
|
|
|
|
|
|
default:
|
|
m_pLog->LogError("lastSuccessfulPacketID=%i currentPacketID=%i - wrong data chunk.", (int)lastSuccessfulPacketID, (int)msg);
|
|
assert(0);
|
|
return false;
|
|
break;
|
|
}
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>><< STREAM size=%04d readpos=%04d",stm.GetSize(),stm.GetReadPos());
|
|
#endif
|
|
|
|
} while(!stm.EOS());
|
|
|
|
// only needed in SP (cause problems in MP)
|
|
if(!m_lstGarbageEntities.empty())
|
|
{
|
|
EntityIdListItor itor=m_lstGarbageEntities.begin();
|
|
while(itor!=m_lstGarbageEntities.end())
|
|
{
|
|
m_pISystem->RemoveEntity(*itor);
|
|
++itor;
|
|
}
|
|
m_lstGarbageEntities.clear();
|
|
}
|
|
|
|
if(!m_lstUpdatedEntities.empty())
|
|
{
|
|
EntityListItor itor=m_lstUpdatedEntities.begin();
|
|
for(; itor!=m_lstUpdatedEntities.end(); ++itor)
|
|
if ((*itor)->GetPhysics())
|
|
(*itor)->GetPhysics()->PostSetStateFromSnapshot();
|
|
|
|
// update the world here
|
|
if (m_iPhysicalWorldTime)
|
|
m_pGame->AdvanceReceivedEntities(m_iPhysicalWorldTime);
|
|
//m_iPhysicalWorldTime = 0;
|
|
|
|
pe_params_flags pf;
|
|
pf.flagsAND = ~pef_update;
|
|
for(itor=m_lstUpdatedEntities.begin(); itor!=m_lstUpdatedEntities.end(); )
|
|
{
|
|
if ((*itor)->GetPhysics())
|
|
{
|
|
(*itor)->GetPhysics()->GetParams(&pf);
|
|
(*itor)->GetPhysics()->SetParams(&pf);
|
|
if (!(pf.flags & pef_checksum_outofsync))
|
|
{
|
|
itor = m_lstUpdatedEntities.erase(itor);
|
|
continue;
|
|
}
|
|
}
|
|
++itor;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_SNAPSHOT
|
|
NET_TRACE("<<NET>>--END-----ParseIncomingStream--------------");
|
|
#endif
|
|
lastSuccessfulPacketID=msg;
|
|
return bRet;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_SETPLAYER
|
|
bool CXClient::OnServerMsgSetPlayer(CStream &stm)
|
|
{
|
|
m_wPlayerID = INVALID_WID;
|
|
|
|
EntityId id;
|
|
Vec3 v3Angles;
|
|
VERIFY_COOKIE(stm);
|
|
|
|
if(!stm.Read(id))
|
|
return false;
|
|
if(!stm.Read(v3Angles))
|
|
return false;
|
|
|
|
VERIFY_COOKIE(stm);
|
|
IEntity *pEntity = m_pISystem->GetEntity(id);
|
|
|
|
if(pEntity)
|
|
{
|
|
IEntityContainer *pCnt;
|
|
CPlayer *pPlayer = NULL;
|
|
|
|
SetPlayerID(id);
|
|
pEntity->SetAngles(v3Angles);
|
|
pCnt=pEntity->GetContainer();
|
|
|
|
if(pCnt)
|
|
{
|
|
pCnt->QueryContainerInterface(CIT_IPLAYER,(void **) &pPlayer);
|
|
|
|
if(pPlayer)
|
|
{
|
|
m_pLog->Log("SET PLAYER [%d]",id);
|
|
|
|
//m_bFirstPerson = true;
|
|
m_pGame->SetViewMode(!pPlayer->m_bFirstPersonLoaded);
|
|
|
|
// make sure that the key state of the input is cleared at this point to prevent the
|
|
// player from shooting because he clicked to respawn
|
|
// IInput *pInput=m_pGame->GetSystem()->GetIInput();
|
|
// if(pInput)
|
|
// pInput->GetIKeyboard()->ClearKeyState();
|
|
|
|
//Initialize various stuff like Hud etc...
|
|
|
|
// m_pLog->Log("CLIENT SET` PLAYER : %d - %s - Pos : \n", pEntity->GetId(), pEntity->GetName());
|
|
|
|
int tempweapon = pPlayer->m_stats.weapon;
|
|
pPlayer->SelectWeapon(-1);
|
|
pPlayer->SelectWeapon(tempweapon);
|
|
|
|
// call OnSetPlayer whenever the localplayer is spawned and set
|
|
m_pScriptSystem->BeginCall("ClientStuff", "OnSetPlayer");
|
|
m_pScriptSystem->PushFuncParam(m_pClientStuff);
|
|
m_pScriptSystem->EndCall();
|
|
|
|
if (m_bMapConnecting)
|
|
OnMapChangedReally();
|
|
}
|
|
else m_pLog->Log("SET PLAYER [%d]b",id);
|
|
}
|
|
else m_pLog->Log("SET PLAYER [%d] failed1",id);
|
|
}
|
|
else m_pLog->Log("SET PLAYER [%d] failed2",id);
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_SETTEAM
|
|
bool CXClient::OnServerMsgSetTeam(CStream &stm)
|
|
{
|
|
EntityId EntId;
|
|
BYTE nTeamId;
|
|
VERIFY_COOKIE(stm);
|
|
stm.Read(EntId);
|
|
stm.Read(nTeamId);
|
|
VERIFY_COOKIE(stm);
|
|
m_pISystem->SetTeam(EntId, (int)nTeamId);
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_ADDTEAM
|
|
bool CXClient::OnServerMsgAddTeam(CStream &stm)
|
|
{
|
|
string sTeamName;
|
|
BYTE nTeamId;
|
|
VERIFY_COOKIE(stm);
|
|
stm.Read(sTeamName);
|
|
stm.Read(nTeamId);
|
|
VERIFY_COOKIE(stm);
|
|
m_pISystem->AddTeam(sTeamName.c_str(), (int)nTeamId);
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_REMOVETEAM
|
|
bool CXClient::OnServerMsgRemoveTeam(CStream &stm)
|
|
{
|
|
BYTE nTeamId;
|
|
stm.Read(nTeamId);
|
|
m_pISystem->RemoveTeam(nTeamId);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
inline void CalcNCombineHash( const unsigned int indwValue, unsigned int &inoutHash )
|
|
{
|
|
inoutHash^=(inoutHash%600011) + (inoutHash/600011) + indwValue;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_REQUESTSCRIPTHASH
|
|
bool CXClient::OnServerMsgRequestScriptHash(CStream &stm)
|
|
{
|
|
IBitStream *pBitStream = m_pGame->GetIBitStream();
|
|
|
|
char szPath[256];
|
|
char szKey[256];
|
|
|
|
u32 dwHash;
|
|
EntityId entity=INVALID_WID;
|
|
|
|
if(!pBitStream->ReadBitStream(stm,entity,eEntityId)) // e.g. INVALID_WID for globals, otherwise it's and entity
|
|
return false;
|
|
if(!pBitStream->ReadBitStream(stm,szPath,255,eASCIIText)) // e.g. "cnt.myTable"
|
|
return false;
|
|
if(!pBitStream->ReadBitStream(stm,szKey,255,eASCIIText)) // e.g. "luaFunc1" or ""
|
|
return false;
|
|
if(!pBitStream->ReadBitStream(stm,dwHash,eDoNotCompress)) // start hash
|
|
return false;
|
|
|
|
// debug
|
|
// m_pLog->Log("OnServerMsgRequestScriptHash '%s' '%s'",szPath,szKey);
|
|
|
|
// find the specified root -------------------
|
|
/*
|
|
IScriptSystem *pScriptSystem=m_pGame->GetScriptSystem();
|
|
IScriptObject *pRoot;
|
|
|
|
if(entity==INVALID_WID)
|
|
{
|
|
// global
|
|
pRoot=pScriptSystem->GetGlobalObject();
|
|
}
|
|
else
|
|
{
|
|
// relative to a entity
|
|
IEntity *pEntity=m_pISystem->GetEntity(entity);
|
|
|
|
pRoot=pEntity->GetScriptObject();
|
|
}
|
|
|
|
if(!pRoot)
|
|
return false;
|
|
|
|
// apply the path -----------------------------
|
|
|
|
IScriptObject *pPath=m_pScriptSystem->CreateEmptyObject();
|
|
|
|
if(!pRoot->GetValueRecursive(szPath,pPath)) // is modifying the given Hash
|
|
{
|
|
pRoot->Release();
|
|
return false;
|
|
}
|
|
|
|
// --------------------------------------------
|
|
|
|
if(*szKey)
|
|
{
|
|
unsigned int *pCode;
|
|
int iSize;
|
|
|
|
if(pPath->GetFuncData(szKey,pCode,iSize)) // get function data
|
|
if(pCode) // it's a lua function
|
|
{
|
|
for(int i=0;i<iSize;i++)
|
|
CalcNCombineHash(*pCode++,dwHash);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::map<string,unsigned int> Sorter;
|
|
|
|
todo: Sorter is needed because lua table don't have a fixed order
|
|
|
|
// the whole table
|
|
pPath->BeginIteration();
|
|
while(pPath->MoveNext())
|
|
{
|
|
unsigned int *pCode;
|
|
int iSize;
|
|
|
|
if(pPath->GetCurrentFuncData(pCode,iSize)) // get function data
|
|
if(pCode) // it's a lua function
|
|
{
|
|
unsigned int dwLocalHash=0;
|
|
|
|
for(int i=0;i<iSize;i++)
|
|
CalcNCombineHash(*pCode++,dwLocalHash);
|
|
|
|
// debugging
|
|
{
|
|
// char *szKey;
|
|
// pPath->GetCurrentKey(szKey);
|
|
|
|
// assert(szKey);
|
|
|
|
// m_pGame->m_pSystem->GetILog()->Log("GetCurrentFuncData hash=%p '%s' size=%d",dwLocalHash,szKey,iSize);
|
|
}
|
|
|
|
CalcNCombineHash(dwLocalHash,dwHash);
|
|
}
|
|
}
|
|
pPath->EndIteration();
|
|
}
|
|
|
|
// pPath->Release(); todo?
|
|
// pRoot->Release(); todo?
|
|
*/
|
|
|
|
// send back the information -----------------
|
|
// SendScriptHashResponse(dwHash);
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_SETTEAMSCORE
|
|
bool CXClient::OnServerMsgSetTeamScore(CStream &stm)
|
|
{
|
|
BYTE cTeamId;
|
|
short nScore;
|
|
VERIFY_COOKIE(stm);
|
|
stm.Read(cTeamId);
|
|
stm.Read(nScore);
|
|
VERIFY_COOKIE(stm);
|
|
m_pISystem->SetTeamScore(cTeamId,nScore);
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_SETTEAMSCORE
|
|
bool CXClient::OnServerMsgSetTeamFlags(CStream &stm)
|
|
{
|
|
BYTE cTeamId;
|
|
int nFlags;
|
|
VERIFY_COOKIE(stm);
|
|
stm.Read(cTeamId);
|
|
stm.ReadPkd(nFlags);
|
|
VERIFY_COOKIE(stm);
|
|
m_pISystem->SetTeamFlags(cTeamId,nFlags);
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_SETENTITYSTATE
|
|
bool CXClient::OnServerMsgSetEntityState(CStream &stm)
|
|
{
|
|
IBitStream *pBitStream = m_pGame->GetIBitStream(); // compression helper
|
|
|
|
EntityId id;
|
|
unsigned char cState;
|
|
IEntity *pEntity;
|
|
VERIFY_COOKIE(stm);
|
|
pBitStream->ReadBitStream(stm,id,eEntityId);
|
|
stm.Read(cState);
|
|
VERIFY_COOKIE(stm);
|
|
|
|
// in SP or if you play on the server we don't need to set the state
|
|
if(m_pGame->IsMultiplayer() && !m_bLocalHost)
|
|
{
|
|
pEntity=m_pISystem->GetEntity(id);
|
|
|
|
if(pEntity && (pEntity->GetStateIdx()!=cState))
|
|
pEntity->GotoState(cState);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_BINDENTITY
|
|
bool CXClient::OnServerMsgBindEntity(CStream &stm)
|
|
{
|
|
// this is an incoming message for the client - it should not be processed on a server
|
|
|
|
EntityId idParent;
|
|
EntityId idChild;
|
|
unsigned char cParam;
|
|
IEntity *pParent,*pChild;
|
|
bool bBindUnbind;
|
|
Vec3 vParent,vChild;
|
|
stm.Read(idParent);
|
|
stm.Read(idChild);
|
|
stm.Read(cParam);
|
|
stm.Read(bBindUnbind);
|
|
stm.Read(vParent);
|
|
stm.Read(vChild);
|
|
|
|
if(m_pGame->IsMultiplayer())
|
|
{
|
|
pParent=m_pISystem->GetEntity(idParent);
|
|
pChild=m_pISystem->GetEntity(idChild);
|
|
if(pParent && pChild)
|
|
{
|
|
if(bBindUnbind)
|
|
pParent->Bind(idChild,cParam,true); // bClientOnly=true
|
|
else
|
|
pParent->Unbind(idChild,cParam,true); // bClientOnly=true
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_SETPLAYERSCORE
|
|
bool CXClient::OnServerMsgSetPlayerScore(CStream &stm)
|
|
{
|
|
short nScore=0;
|
|
// short nFlags=0;
|
|
EntityId id=0;
|
|
VERIFY_COOKIE(stm);
|
|
stm.Read(id);
|
|
stm.Read(nScore);
|
|
// stm.Read(nFlags);
|
|
VERIFY_COOKIE(stm);
|
|
IEntity *pEntity=m_pISystem->GetEntity(id);
|
|
|
|
if(pEntity)
|
|
{
|
|
IEntityContainer *pC=pEntity->GetContainer();
|
|
if(pC)
|
|
{
|
|
CPlayer *pPlayer=NULL;
|
|
pC->QueryContainerInterface(CIT_IPLAYER,(void **) &pPlayer);
|
|
if(pPlayer)
|
|
{
|
|
pPlayer->m_stats.score=nScore;
|
|
// pPlayer->m_stats.pflags=nFlags;
|
|
m_pScriptSystem->GetGlobalValue("ClientStuff",m_pClientStuff);
|
|
_HScriptFunction pFunc(m_pScriptSystem);
|
|
if(pFunc=m_pScriptSystem->GetFunctionPtr("ClientStuff","OnSetPlayerScore")){
|
|
m_pScriptSystem->BeginCall(pFunc);
|
|
m_pScriptSystem->PushFuncParam(m_pClientStuff);
|
|
m_pScriptSystem->PushFuncParam(pEntity->GetScriptObject());
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_SETGAMESTATE
|
|
bool CXClient::OnServerMsgGameState(CStream &stm)
|
|
{
|
|
stm.Read(m_nGameState);
|
|
stm.Read(m_nGameLastTime);
|
|
|
|
m_fGameLastTimeReceived = m_pGame->m_pSystem->GetITimer()->GetCurrTime();
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_SCOREBOARD
|
|
bool CXClient::OnServerMsgScoreBoard(CStream &stmScoreBoard)
|
|
{
|
|
CScriptObjectStream stmScript;
|
|
|
|
stmScript.Create(m_pScriptSystem);
|
|
stmScript.Attach(&stmScoreBoard);
|
|
|
|
bool bContinue;
|
|
|
|
m_pScriptSystem->BeginCall("ClientStuff", "ResetScores");
|
|
m_pScriptSystem->PushFuncParam(m_pClientStuff);
|
|
m_pScriptSystem->EndCall();
|
|
|
|
while(stmScoreBoard.Read(bContinue) && bContinue)
|
|
{
|
|
m_pScriptSystem->BeginCall("ClientStuff", "SetPlayerScore");
|
|
m_pScriptSystem->PushFuncParam(m_pClientStuff);
|
|
m_pScriptSystem->PushFuncParam(stmScript.GetScriptObject());
|
|
m_pScriptSystem->EndCall();
|
|
};
|
|
|
|
m_pScriptSystem->BeginCall("ClientStuff", "ShowScoreBoard");
|
|
m_pScriptSystem->PushFuncParam(m_pClientStuff);
|
|
m_pScriptSystem->PushFuncParam(1);
|
|
m_pScriptSystem->EndCall();
|
|
|
|
m_fLastScoreBoardTime = m_pGame->m_pSystem->GetITimer()->GetCurrTime();
|
|
|
|
return true;
|
|
};
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_COMMAND
|
|
bool CXClient::OnServerMsgText(CStream &stm)
|
|
{
|
|
TextMessage pTextMessage;
|
|
pTextMessage.Read(stm);
|
|
|
|
IEntitySystem *pEntitySystem = m_pGame->GetSystem()->GetIEntitySystem();
|
|
|
|
string szText = pTextMessage.m_sText;
|
|
string szCmdName;
|
|
string szSenderName;
|
|
|
|
// if(pTextMessage.stmPayload.Read(szText))
|
|
{
|
|
// if uiSender is 0, it's a message from the server
|
|
IEntity *pSender=m_pISystem->GetEntity(pTextMessage.uiSender);
|
|
|
|
if(pSender)
|
|
{
|
|
szSenderName = pSender->GetName();
|
|
|
|
// public message
|
|
if (pTextMessage.cMessageType == CMD_SAY)
|
|
{
|
|
szCmdName = "say";
|
|
}
|
|
// team-only message
|
|
else if (pTextMessage.cMessageType == CMD_SAY_TEAM)
|
|
{
|
|
szCmdName = "sayteam";
|
|
}
|
|
// private player-to-player message
|
|
else if (pTextMessage.cMessageType == CMD_SAY_ONE)
|
|
{
|
|
szCmdName = "sayone";
|
|
}
|
|
else
|
|
{
|
|
szCmdName = "";
|
|
}
|
|
}
|
|
|
|
if (!szText.size())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
HSCRIPTFUNCTION pScriptFunction = m_pScriptSystem->GetFunctionPtr("ClientStuff", "OnTextMessage");
|
|
|
|
if (pScriptFunction)
|
|
{
|
|
m_pScriptSystem->ReleaseFunc(pScriptFunction);
|
|
|
|
_SmartScriptObject pClientStuff(m_pScriptSystem, true);
|
|
|
|
m_pScriptSystem->GetGlobalValue("ClientStuff", *pClientStuff);
|
|
|
|
m_pScriptSystem->BeginCall("ClientStuff", "OnTextMessage");
|
|
m_pScriptSystem->PushFuncParam(pClientStuff);
|
|
m_pScriptSystem->PushFuncParam(szCmdName.c_str());
|
|
m_pScriptSystem->PushFuncParam(szSenderName.c_str());
|
|
m_pScriptSystem->PushFuncParam(szText.c_str());
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
string szHudMessage;
|
|
|
|
if (szCmdName == "sayone")
|
|
{
|
|
szHudMessage = "$4[$1" + szSenderName + "$4]$9 " + szText;
|
|
}
|
|
else if (szCmdName == "sayteam")
|
|
{
|
|
szHudMessage = "$4[$1" + szSenderName + "$4]$3 " + szText;
|
|
}
|
|
else if (szCmdName == "say")
|
|
{
|
|
szHudMessage = "$4[$1" + szSenderName + "$4]$1 " + szText;
|
|
}
|
|
else
|
|
{
|
|
szHudMessage = szText;
|
|
}
|
|
|
|
{
|
|
wstring szEnglishLocalized;
|
|
|
|
m_pGame->m_StringTableMgr.Localize(szHudMessage,szEnglishLocalized,true); // localize to english
|
|
|
|
std::vector<char> tmp;
|
|
tmp.resize(szEnglishLocalized.size()+1);
|
|
|
|
sprintf (&tmp[0], "%S", szEnglishLocalized.c_str());
|
|
|
|
m_pGame->m_pLog->LogToConsole("%s",&tmp[0]); // needed for console printout of \callvote response
|
|
}
|
|
|
|
AddHudMessage(szHudMessage.c_str(), pTextMessage.fLifeTime);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_ADDENTITY
|
|
bool CXClient::OnServerMsgAddEntity(CStream &stm)
|
|
{
|
|
CEntityDesc ed;
|
|
|
|
ed.Read(m_pGame->GetIBitStream(),stm);
|
|
|
|
IEntity *pEntity = m_pISystem->SpawnEntity(ed);
|
|
NET_TRACE("<<NET>> XSERVERMSG_ADDENTITY %d",ed.id);
|
|
|
|
if(m_pGame->IsMultiplayer())
|
|
{
|
|
if(pEntity)
|
|
{
|
|
IEntityContainer *pEntCont=pEntity->GetContainer();
|
|
|
|
if(pEntCont)
|
|
pEntCont->Update();
|
|
}
|
|
else
|
|
{
|
|
m_pLog->Log("OnServerMsgAddEntity entity was 0"); // remove soon
|
|
}
|
|
}
|
|
|
|
// Tell the client in lua that an entity has spawned
|
|
if (pEntity && pEntity->GetScriptObject())
|
|
{
|
|
//Timur, Look ups by name in lua must be replaced with table reference.
|
|
IScriptSystem *pSS = m_pGame->GetScriptSystem();
|
|
_SmartScriptObject pClientStuff(pSS,true);
|
|
if(pSS->GetGlobalValue("ClientStuff",pClientStuff))
|
|
{
|
|
pSS->BeginCall("ClientStuff","OnSpawnEntity");
|
|
pSS->PushFuncParam(pClientStuff);
|
|
m_pScriptSystem->PushFuncParam(pEntity->GetScriptObject());
|
|
pSS->EndCall();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_REMOVEENTITY
|
|
bool CXClient::OnServerMsgRemoveEntity(CStream &stm)
|
|
{
|
|
EntityId id;
|
|
stm.Read(id);
|
|
#ifdef _DEBUG
|
|
NET_TRACE("<<NET>>CXClient::OnServerMsgRemoveEntity %04d",id);
|
|
#endif // _DEBUG
|
|
NET_TRACE("<<NET>> XSERVERMSG_REMOVEENTITY %d",id);
|
|
if(id==m_wPlayerID)
|
|
{
|
|
SetPlayerID(INVALID_WID);
|
|
}
|
|
|
|
if(m_pGame->IsMultiplayer())
|
|
m_pISystem->RemoveEntity(id); // MP: remove it right now
|
|
else
|
|
m_lstGarbageEntities.push_back(id); // SP: remove it later
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_UPDATEENTITY
|
|
bool CXClient::OnServerMsgUpdateEntity(CStream &stm)
|
|
{
|
|
IBitStream *pBitStream = m_pGame->GetIBitStream(); // compression helper
|
|
|
|
EntityId id;
|
|
|
|
pBitStream->ReadBitStream(stm,id,eEntityId);
|
|
// stm.Read(id);
|
|
|
|
//TRACE("XSERVERMSG_UPDATEENTITY [%d]",id);
|
|
IEntity *ent = m_pISystem->GetEntity(id);
|
|
|
|
if(ent)
|
|
{
|
|
if(!ent->Read(stm,m_bIgnoreSnapshot))
|
|
{
|
|
m_pLog->Log("WARNING ENTITY [%d] error reading from the snapshot!!",id);
|
|
return false;
|
|
}
|
|
|
|
if (!m_bIgnoreSnapshot)
|
|
{
|
|
//if the entity is the player of this client
|
|
//the localhost override the angles
|
|
if(ent->GetId()==m_wPlayerID && !ent->IsBound())
|
|
{
|
|
ent->SetAngles(m_PlayerProcessingCmd.GetDeltaAngles(),false,false);
|
|
}
|
|
else if (ent->GetPhysics())
|
|
{ // the player will update her physics herself (to preserve perfect client time-slice based simuklation)
|
|
// the rest will be updated to match physics time later in ParseIncomingStream
|
|
pe_params_flags pf;
|
|
pf.flagsOR = pef_update;
|
|
m_lstUpdatedEntities.push_back(ent);
|
|
ent->GetPhysics()->GetParams(&pf);
|
|
if (!(pf.flags & pef_checksum_received))
|
|
ent->GetPhysics()->SetParams(&pf);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NET_TRACE("<<NET>> ENTITY [%d] UPDATED BUT BOT SPAWNED",id);
|
|
GameWarning( "ENTITY [%d] Updated but not spawned!!",id );
|
|
return false;
|
|
}
|
|
VERIFY_COOKIE_NO(stm,28);
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_TIMESTAMP
|
|
bool CXClient::OnServerMsgTimeStamp(CStream &stm)
|
|
{
|
|
int iPhysicalTime,iPrevWorldTime=m_iPhysicalWorldTime;
|
|
IPhysicalWorld *pWorld = m_pGame->GetSystem()->GetIPhysicalWorld();
|
|
stm.Read(iPhysicalTime);
|
|
stm.Read(m_iPhysicalWorldTime);
|
|
|
|
if(stm.GetStreamVersion()<PATCH1_SAVEVERSION) // to be backward compatible with old samegames
|
|
{
|
|
BYTE seed;
|
|
stm.Read(seed);
|
|
// m_pISystem->SetRandomSeed(seed);
|
|
}
|
|
|
|
float fDelta = (m_iPhysicalWorldTime-iPrevWorldTime)*pWorld->GetPhysVars()->timeGranularity;
|
|
if (fDelta>-2.0f && fDelta<0)
|
|
{
|
|
m_bIgnoreSnapshot = true;
|
|
m_iPhysicalWorldTime = iPrevWorldTime;
|
|
}
|
|
else
|
|
{
|
|
m_bIgnoreSnapshot = false;
|
|
if (!m_bLocalHost)
|
|
{
|
|
pWorld->SetiSnapshotTime(iPhysicalTime,0);
|
|
pWorld->SetiSnapshotTime(m_iPhysicalWorldTime,1);
|
|
pWorld->SetiSnapshotTime(m_pGame->SnapTime(m_iPhysicalWorldTime),2);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_EVENTSCHEDULE
|
|
bool CXClient::OnServerMsgEventSchedule(CStream &stm)
|
|
{
|
|
m_pGame->ReadScheduledEvents(stm);
|
|
return true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_SETENTITYNAME
|
|
bool CXClient::OnServerMsgSetEntityName(CStream &stm)
|
|
{
|
|
EntityId id;
|
|
string sName;
|
|
VERIFY_COOKIE(stm);
|
|
if(!stm.Read(id))return false;
|
|
if(!stm.Read(sName))return false;
|
|
VERIFY_COOKIE(stm);
|
|
IEntity *pEntity=m_pISystem->GetEntity(id);
|
|
if(pEntity)
|
|
{
|
|
pEntity->SetName(sName.c_str());
|
|
NET_TRACE("<<NET>>SET Entity NAME =\"%s\"",sName.c_str());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_CMD
|
|
bool CXClient::OnServerMsgCmd(CStream &stm)
|
|
{
|
|
if(!m_pClientStuff)
|
|
return true;
|
|
|
|
string cmd;
|
|
bool bExtra;
|
|
unsigned char cUserByte;
|
|
Vec3 vNormal,vPos;
|
|
EntityId id;
|
|
|
|
stm.Read(cmd);
|
|
|
|
stm.Read(bExtra);
|
|
if(bExtra)
|
|
{
|
|
{
|
|
bool bPos;
|
|
|
|
stm.Read(bPos);
|
|
|
|
if(bPos)
|
|
{
|
|
CStreamData_WorldPos tmp(vPos);
|
|
stm.ReadPkd(tmp);
|
|
}
|
|
else
|
|
vPos=Vec3(0,0,0);
|
|
}
|
|
|
|
{
|
|
bool bNormal;
|
|
|
|
stm.Read(bNormal);
|
|
|
|
if(bNormal)
|
|
{
|
|
CStreamData_Normal tmp(vNormal);
|
|
stm.ReadPkd(tmp);
|
|
}
|
|
else
|
|
vNormal=Vec3(0,0,0);
|
|
}
|
|
stm.ReadPkd(id);
|
|
stm.ReadPkd(cUserByte);
|
|
}
|
|
|
|
m_pScriptSystem->BeginCall("ClientStuff","OnServerCmd");
|
|
m_pScriptSystem->PushFuncParam(m_pClientStuff);
|
|
m_pScriptSystem->PushFuncParam(cmd.c_str());
|
|
if(bExtra)
|
|
{
|
|
m_sopMsgPos.Set(vPos);
|
|
m_sopMsgNormal.Set(vNormal);
|
|
m_pScriptSystem->PushFuncParam(m_sopMsgPos);
|
|
m_pScriptSystem->PushFuncParam(m_sopMsgNormal);
|
|
m_pScriptSystem->PushFuncParam(id);
|
|
m_pScriptSystem->PushFuncParam(cUserByte);
|
|
}
|
|
// NET_TRACE("<<NET>>COMMAND RECEIVED [%s]",cmd.c_str());
|
|
m_pScriptSystem->EndCall();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CXClient::OnServerMsgClientString(CStream &stm)
|
|
{
|
|
m_fLastClientStringTime=m_pTimer->GetCurrTime();
|
|
return stm.Read(m_sClientString);
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
// XSERVERMSG_SYNCVAR
|
|
bool CXClient::OnServerMsgSyncVar(CStream &stm)
|
|
{
|
|
string name,val;
|
|
stm.Read(name);
|
|
stm.Read(val);
|
|
m_pISystem->SetVariable(name.c_str(),val.c_str());
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CXClient::OnServerMsgSyncAIState(CStream &stm)
|
|
{
|
|
int nDummy;
|
|
stm.Read(nDummy);
|
|
|
|
// [marco] petar do the stuff here after you read the packet
|
|
// from the stream
|
|
|
|
return (true);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CXClient::SendTextMessage(TextMessage &tm)
|
|
{
|
|
CStream stm;
|
|
tm.uiSender=m_wPlayerID;
|
|
tm.Write(stm);
|
|
SendReliableMsg(XCLIENTMSG_TEXT,stm);
|
|
}
|
|
|
|
void CXClient::SetBitsPerSecond( const unsigned int dwBitsPerSecond )
|
|
{
|
|
CStream stm;
|
|
|
|
unsigned char cVar=0;
|
|
|
|
stm.Write(cVar);
|
|
stm.Write(dwBitsPerSecond); // cVar=0
|
|
|
|
SendReliableMsg(XCLIENTMSG_RATE,stm);
|
|
}
|
|
|
|
|
|
void CXClient::SetUpdateRate( const unsigned int dwUpdatesPerSec )
|
|
{
|
|
CStream stm;
|
|
|
|
unsigned char cVar=1;
|
|
|
|
stm.Write(cVar);
|
|
stm.Write(dwUpdatesPerSec); // cVar=1
|
|
|
|
SendReliableMsg(XCLIENTMSG_RATE,stm);
|
|
}
|
|
|
|
|
|
void CXClient::SendCommand(const char *sCmd)
|
|
{
|
|
CStream stm;
|
|
stm.Write(sCmd);
|
|
SendReliableMsg(XCLIENTMSG_CMD,stm);
|
|
}
|
|
|
|
|
|
|
|
//true
|
|
bool FrontOfLine(float Ax,float Ay,float Bx,float By,float xt,float yt)
|
|
{
|
|
float s=((Ay-yt)*(Bx-Ax)-(Ax-xt)*(By-Ay));
|
|
|
|
if (s>=0)
|
|
{
|
|
//front
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
//back
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//-------------------------------
|
|
// LINE A LINE B
|
|
// x1,y1\ /x2,y2
|
|
// \ /
|
|
// O
|
|
// / \
|
|
// x3,y3/ \x4,y4
|
|
//----------------------------------
|
|
void CXClient::SoundEvent(EntityId idSrc,Vec3 &pos,float fRadius,float fThreat)
|
|
{
|
|
if(!m_wPlayerID)
|
|
return;
|
|
IEntity *pPlayer=m_pEntitySystem->GetEntity(m_wPlayerID);
|
|
if(!pPlayer)
|
|
return;
|
|
Vec3 ppos=pPlayer->GetPos();
|
|
float fDistance2=GetSquaredDistance(pos,ppos)-(fRadius*fRadius);
|
|
//the player isn't bothered by his own sounds, but we wanna show them in the radar
|
|
//if (m_wPlayerID==idSrc)
|
|
{
|
|
float fSoundEventRadius=cl_sound_event_radius->GetFVal();
|
|
if (fDistance2<(fSoundEventRadius*fSoundEventRadius))
|
|
{
|
|
SSoundInfo SoundInfo;
|
|
SoundInfo.nEntityId=idSrc;
|
|
SoundInfo.Pos=pos;
|
|
SoundInfo.fRadius=fRadius;
|
|
SoundInfo.fThread=fThreat;
|
|
SoundInfo.fDistance2=fDistance2;
|
|
SoundInfo.fTimeout=cl_sound_event_timeout->GetFVal();
|
|
m_lstSounds.push_back(SoundInfo);
|
|
}
|
|
//return;
|
|
}
|
|
float x1=-1000+ppos.x,y1=-1000+ppos.y;
|
|
float x2=1000+ppos.x,y2=-1000+ppos.y;
|
|
float x3=-1000+ppos.x,y3=1000+ppos.y;
|
|
float x4=1000+ppos.x,y4=1000+ppos.y;
|
|
bool bLineA;
|
|
bool bLineB;
|
|
float fMaxDistance=cl_sound_detection_max_distance->GetFVal();
|
|
float fMinDistance=cl_sound_detection_min_distance->GetFVal();
|
|
if((fDistance2<(fMaxDistance*fMaxDistance))
|
|
&& (fDistance2>(fMinDistance*fMinDistance)))
|
|
{
|
|
Vec3 vAng=pPlayer->GetAngles();
|
|
float fCos=(float)cos_tpl(-DEG2RAD(vAng.z));
|
|
float fSin=(float)sin_tpl(-DEG2RAD(vAng.z));
|
|
pos-=ppos;
|
|
float fSoundX=(pos.x*fCos) - (pos.y*fSin);
|
|
float fSoundY=(pos.x*fSin) + (pos.y*fCos);
|
|
fSoundX+=ppos.x;
|
|
fSoundY+=ppos.y;
|
|
bLineA=FrontOfLine(x1,y1,x4,y4,fSoundX,fSoundY);
|
|
bLineB=FrontOfLine(x2,y2,x3,y3,fSoundX,fSoundY);
|
|
if(bLineA)
|
|
{
|
|
if(bLineB)
|
|
{
|
|
//LEFT
|
|
//left
|
|
m_fLeftSound+=1;
|
|
//::OutputDebugString("left\n");
|
|
if(m_fLeftSound>1)
|
|
m_fLeftSound=1;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
//FRONT!!
|
|
//front
|
|
m_fFrontSound+=1;
|
|
//::OutputDebugString("front\n");
|
|
if(m_fFrontSound>1)
|
|
m_fFrontSound=1;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(bLineB)
|
|
{
|
|
//BACK
|
|
//back
|
|
m_fBackSound+=1;
|
|
//::OutputDebugString("back\n");
|
|
if(m_fBackSound>1)
|
|
m_fBackSound=1;
|
|
|
|
}
|
|
else
|
|
{
|
|
//RIGHT!!
|
|
m_fRightSound+=1;
|
|
//right
|
|
//::OutputDebugString("right\n");
|
|
if(m_fRightSound>1)
|
|
m_fRightSound=1;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CXClient::SetEntityCamera( const SCameraParams &CameraParams )
|
|
{
|
|
if (m_CameraParams)
|
|
*m_CameraParams = CameraParams;
|
|
}
|
|
|
|
void CXClient::AddHudMessage(const char *sMessage,float lifetime,bool bHighPriority)
|
|
{
|
|
_SmartScriptObject pHud(m_pScriptSystem,true);
|
|
const char *sfunc="AddMessage";
|
|
|
|
if(m_pScriptSystem->GetGlobalValue("Hud",pHud))
|
|
{
|
|
if(bHighPriority){
|
|
sfunc="AddCenterMessage";
|
|
}
|
|
m_pScriptSystem->BeginCall("Hud",sfunc);
|
|
m_pScriptSystem->PushFuncParam(pHud);
|
|
m_pScriptSystem->PushFuncParam(sMessage);
|
|
m_pScriptSystem->PushFuncParam(lifetime);
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
}
|
|
|
|
void CXClient:: AddHudSubtitle(const char *sMessage, float lifetime)
|
|
{
|
|
_SmartScriptObject pHud(m_pScriptSystem,true);
|
|
const char *sfunc="AddSubtitle";
|
|
|
|
if(m_pScriptSystem->GetGlobalValue("Hud",pHud))
|
|
{
|
|
m_pScriptSystem->BeginCall("Hud",sfunc);
|
|
m_pScriptSystem->PushFuncParam(pHud);
|
|
m_pScriptSystem->PushFuncParam(sMessage);
|
|
m_pScriptSystem->PushFuncParam(lifetime);
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
}
|
|
|
|
void CXClient:: ResetSubtitles(void)
|
|
{
|
|
_SmartScriptObject pHud(m_pScriptSystem,true);
|
|
const char *sfunc="ResetSubtitles";
|
|
|
|
if(m_pScriptSystem->GetGlobalValue("Hud",pHud))
|
|
{
|
|
m_pScriptSystem->BeginCall("Hud",sfunc);
|
|
m_pScriptSystem->PushFuncParam(pHud);
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
}
|
|
|
|
void CXClient::LoadingError(const char *szError)
|
|
{
|
|
// m_pLog->Log("HIDE CONSOLE");
|
|
if (m_pGame->IsMultiplayer())
|
|
m_pGame->GetSystem()->GetIRenderer()->ClearColorBuffer(Vec3(0,0,0));
|
|
m_pGame->GetSystem()->GetIConsole()->ResetProgressBar(0);
|
|
m_pGame->m_pSystem->GetIConsole()->ShowConsole(false);
|
|
m_pGame->m_pSystem->GetIConsole()->SetScrollMax(600/2);
|
|
|
|
m_pScriptSystem->BeginCall("Game", "OnLoadingError");
|
|
m_pScriptSystem->PushFuncParam(m_pGame->GetScriptObject());
|
|
m_pScriptSystem->PushFuncParam(szError);
|
|
m_pScriptSystem->EndCall();
|
|
}
|
|
|
|
unsigned int CXClient::GetTimeoutCompensation()
|
|
{
|
|
if (m_nGameState == CGS_INTERMISSION)
|
|
{
|
|
if (m_pGame->cl_loadtimeout->GetIVal() < 5)
|
|
{
|
|
return 5000;
|
|
}
|
|
|
|
return (unsigned int)(m_pGame->cl_loadtimeout->GetFVal() * 1000.0f);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CXClient::LazyChannelAcknowledge()
|
|
{
|
|
m_bLazyChannelState=!m_bLazyChannelState;
|
|
}
|
|
|
|
bool CXClient::GetLazyChannelState()
|
|
{
|
|
return m_bLazyChannelState;
|
|
}
|