286 lines
7.1 KiB
C++
286 lines
7.1 KiB
C++
// NetEntityInfo.cpp: implementation of the CNetEntityInfo class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "NetEntityInfo.h"
|
|
#include "XPlayer.h"
|
|
#include "XVehicle.h"
|
|
#include "XSystemBase.h"
|
|
#include <ITimer.h>
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CNetEntityInfo::CNetEntityInfo()
|
|
{
|
|
m_pEntity=0;
|
|
m_fLastUpdate=0;
|
|
m_pTimer=NULL;
|
|
m_nScore=0;
|
|
m_cState=0;
|
|
m_dwBitSizeEstimate=40; // inital guessed value
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CNetEntityInfo::CNetEntityInfo(const CNetEntityInfo& nei)
|
|
{
|
|
m_pEntity=nei.m_pEntity;
|
|
m_fLastUpdate=nei.m_fLastUpdate;
|
|
m_pTimer=nei.m_pTimer;
|
|
m_nPriority=nei.m_nPriority;
|
|
m_nScore=nei.m_nScore;
|
|
m_cState=nei.m_cState;
|
|
m_ecsClone=nei.m_ecsClone;
|
|
m_dwBitSizeEstimate=nei.m_dwBitSizeEstimate;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CNetEntityInfo::CNetEntityInfo(CXServerSlot *pServerSlot,ITimer *pTimer,IEntity* pEntity)
|
|
{
|
|
m_pEntity=pEntity;
|
|
m_fLastUpdate=0;
|
|
m_pTimer=pTimer;
|
|
m_nScore=0;
|
|
m_cState=0;
|
|
m_ecsClone.m_v3Angles.Set(1E10f,1E10f,1E10f);
|
|
m_ecsClone.m_pServerSlot=pServerSlot;
|
|
m_dwBitSizeEstimate=40; // inital guessed value
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CNetEntityInfo::~CNetEntityInfo()
|
|
{
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CNetEntityInfo::Write( CXServer *pServer, CStream &stm)
|
|
{
|
|
assert(pServer);
|
|
|
|
bool bRes;
|
|
m_ecsClone.m_fWriteStepBack = GetXServerSlot()->GetPlayerWriteStepBack();
|
|
m_ecsClone.m_bOffSync = GetXServerSlot()->IsEntityOffSync(m_pEntity->GetId());
|
|
|
|
size_t dwPos = stm.GetSize();
|
|
|
|
bRes=m_pEntity->Write(stm,&m_ecsClone);
|
|
|
|
m_dwBitSizeEstimate = 5+9 + (uint32)(stm.GetSize()-dwPos); // 5 for XSERVERMSG_UPDATEENTITY, 9 for EntityId
|
|
|
|
return bRes;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CNetEntityInfo::Reset()
|
|
{
|
|
m_fLastUpdate=m_pTimer->GetCurrTime();
|
|
|
|
CXServer *pServer = GetXServerSlot()->GetServer();
|
|
|
|
if(pServer->m_pGame->GetMyPlayer())
|
|
if((pServer->sv_netstats->GetIVal() > 1) &&
|
|
(pServer->GetServerSlotByEntityId(pServer->m_pGame->GetMyPlayer()->GetId()) == GetXServerSlot()))
|
|
{
|
|
int i;
|
|
|
|
if(GetISystem()->GetIEntitySystem()->IsDynamicEntityId(m_pEntity->GetId()))
|
|
i=(int)(0xffff-m_pEntity->GetId());
|
|
else
|
|
i=1000-(int)(m_pEntity->GetId());
|
|
|
|
if(i>=1000)i=1000-1; // clamp in max range
|
|
if(i<0)i=0; // clamp in min range
|
|
|
|
GetXServerSlot()->GetServer()->m_NetStats.AddToSumGraph(i, 1);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
uint32 CNetEntityInfo::CalcEstimatedSize()
|
|
{
|
|
return m_dwBitSizeEstimate;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CNetEntityInfo::Update(Vec3d v3dViewer)
|
|
{
|
|
FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );
|
|
|
|
CXServer *pServer = GetXServerSlot()->GetServer();
|
|
|
|
IBitStream *pBitStream = pServer->m_pGame->GetIBitStream(); // compression helper
|
|
|
|
m_nPriority=1; // lowest update level
|
|
|
|
if(!m_pEntity)
|
|
{
|
|
assert(m_pEntity);
|
|
// ::OutputDebugString("Warning invalid CNetEntityInfo!!\n");
|
|
// m_bNeedUpdate=false;
|
|
m_nPriority=0; // no update at all
|
|
return;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
unsigned char cState=(unsigned char)m_pEntity->GetStateIdx();
|
|
|
|
if(!m_pEntity->IsStateClientside() // state changes need sync
|
|
&& m_cState!=cState) // state has changed
|
|
{
|
|
// send it to the client
|
|
CStream stm;
|
|
//if there were no previous state - this is the first time state is set
|
|
bool bFirstTime = (m_cState==0);
|
|
m_cState=cState;
|
|
WRITE_COOKIE(stm);
|
|
pBitStream->WriteBitStream(stm,(EntityId)m_pEntity->GetId(),eEntityId);
|
|
// stm.Write((EntityId)m_pEntity->GetId());
|
|
ASSERT(m_pEntity->IsInState(cState));
|
|
stm.Write(cState);
|
|
WRITE_COOKIE(stm);
|
|
GetXServerSlot()->SendReliableMsg(XSERVERMSG_SETENTITYSTATE,stm,false,m_pEntity->GetName());
|
|
//we need to know if this is the first time - then make it execute OnBind on client
|
|
if(bFirstTime)
|
|
m_pEntity->SinkRebind( GetXServerSlot()->GetServer() );
|
|
}
|
|
|
|
if(m_pEntity->IsGarbage())
|
|
{
|
|
m_nPriority=0; // no update at all
|
|
return;
|
|
}
|
|
|
|
/////////////////////////////////////////////////
|
|
if(!m_pEntity->GetNetPresence())
|
|
{
|
|
m_nPriority=0; // no update at all
|
|
return;
|
|
}
|
|
|
|
bool bLocalPlayer = GetXServerSlot()->GetPlayerId()==m_pEntity->GetId();
|
|
|
|
/////////////////////////////////////////////////
|
|
if(bLocalPlayer)
|
|
m_nPriority+=1000000;
|
|
|
|
|
|
IEntityContainer *pC=m_pEntity->GetContainer();
|
|
|
|
m_ecsClone.m_bSyncAngles = true;
|
|
m_ecsClone.m_bSyncYAngle = true;
|
|
m_ecsClone.m_bLocalplayer = bLocalPlayer; // different from earlier method (was only true for a Player, not for spectators)
|
|
|
|
Vec3d v3This=m_pEntity->GetPos();
|
|
|
|
// lower priority for more distant entities
|
|
{
|
|
float fDistance2=0;
|
|
|
|
if(!IsEquivalent(v3dViewer,v3This))
|
|
fDistance2 = (v3dViewer-(const Vec3d)v3This).len2();
|
|
|
|
float fVisibleRadius2=500*500;
|
|
|
|
if(fDistance2>fVisibleRadius2)
|
|
m_nPriority=100; // almost no udate
|
|
else
|
|
m_nPriority+=(unsigned int)cry_sqrtf(fVisibleRadius2-fDistance2);
|
|
}
|
|
|
|
// container gets the change to change the m_nPriority
|
|
if(pC)
|
|
pC->OnEntityNetworkUpdate(GetXServerSlot()->GetPlayerId(),v3dViewer,m_nPriority,m_ecsClone);
|
|
|
|
if(!m_nPriority)
|
|
return; // no update at all
|
|
|
|
CPlayer *pPlayer=0;
|
|
|
|
if(pC)
|
|
pC->QueryContainerInterface(CIT_IPLAYER,(void **)&pPlayer);
|
|
|
|
if(pPlayer)
|
|
{
|
|
//if is the slot's player
|
|
if(bLocalPlayer)
|
|
{
|
|
if(pPlayer->m_stats.score!=m_nScore)
|
|
{
|
|
CStream stm;
|
|
|
|
m_nScore=pPlayer->m_stats.score;
|
|
WRITE_COOKIE(stm);
|
|
stm.Write(m_pEntity->GetId());
|
|
stm.Write(m_nScore);
|
|
WRITE_COOKIE(stm);
|
|
GetXServerSlot()->SendReliableMsg(XSERVERMSG_SETPLAYERSCORE,stm,true);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_nUpdateNumber==0)
|
|
{
|
|
m_nPriority=0x0000FFFF;
|
|
m_nUpdateNumber++;
|
|
return;
|
|
}
|
|
|
|
m_nUpdateNumber++;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
float CNetEntityInfo::GetTimeAffectedPriority()
|
|
{
|
|
float fCurrentTime = m_pTimer->GetCurrTime();
|
|
float fDeltaTime=fCurrentTime-m_fLastUpdate;
|
|
|
|
if(fDeltaTime<0)
|
|
{
|
|
m_fLastUpdate=fCurrentTime; // timer was reseted
|
|
fDeltaTime=0;
|
|
}
|
|
|
|
return (float)m_nPriority*fDeltaTime;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
float CNetEntityInfo::GetDistanceTo( const Vec3d &vPos )
|
|
{
|
|
assert(m_pEntity);
|
|
|
|
if(!m_pEntity)
|
|
return 0;
|
|
|
|
Vec3d v3This=m_pEntity->GetPos();
|
|
|
|
return (vPos-(const Vec3d)v3This).len2();
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CNetEntityInfo::operator ==(EntityId id) const
|
|
{
|
|
if(!m_pEntity)
|
|
return false;
|
|
if(m_pEntity->GetId()==id)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CXServerSlot *CNetEntityInfo::GetXServerSlot()
|
|
{
|
|
return m_ecsClone.m_pServerSlot;
|
|
} |