Files
FC1/CryEntitySystem/EntitySystem.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

1097 lines
34 KiB
C++

//////////////////////////////////////////////////////////////////////
//
// Crytek CryENGINE Source code
//
// File:CEntitySystem.cpp
// Description: entity's management
//
// History:
// -March 07,2001:Originally created by Marco Corbetta
// -: modified by everyone
//
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <Cry_Math.h>
#include <list2.h>
#include "EntitySystem.h"
#include "EntityIt.h"
#include <CryPhysics.h>
#include <IScriptSystem.h>
#include "Entity.h"
#include <IRenderer.h>
#include <I3dengine.h>
#include <ILog.h>
#include <ITimer.h>
#include <ISystem.h>
#include <IGame.h> // IGame
#if defined(_DEBUG) && !defined(LINUX)
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
/*
#include "..\cry3dengine\statobj.h"
#include "file.h"
*/
//////////////////////////////////////////////////////////////////////////
// Global var.
//////////////////////////////////////////////////////////////////////////
bool gPrecacheResourcesMode = false;
//////////////////////////////////////////////////////////////////////
CEntitySystem::CEntitySystem(ISystem *pSystem)
{
m_bDynamicEntityIdMode=false;
m_eDefaultUpdateLevel = eUT_Always;
m_nGetEntityCounter=0;
m_pISystem=pSystem;
//m_pSink=NULL;
m_mapEntities.clear();
m_pScriptSystem=NULL;
m_pTimer = pSystem->GetITimer();
m_pCharacterIK = pSystem->GetIConsole()->CreateVariable("p_characterik","1",VF_CHEAT,
"Toggles character IK.\n"
"Usage: p_characterik [0/1]\n"
"Default is 1 (on). Set to 0 to disable inverse kinematics.");
m_pShowEntityBBox = pSystem->GetIConsole()->CreateVariable("es_bboxes","0",VF_CHEAT,//this console variable is repeated
"Toggles entity bounding boxes.\n"
"Usage: es_bboxes [0/1]\n"
"Default is 0 (off). Set to 1 to display bounding boxes.");
m_pShowHelpers = pSystem->GetIConsole()->CreateVariable("es_helpers","0",VF_CHEAT,
"Toggles helpers.\n"
"Usage: es_helpers [0/1]\n"
"Default is 0 (off). Set to 1 to display entity helpers.");
m_pProfileEntities = pSystem->GetIConsole()->CreateVariable("es_profileentities","0",VF_CHEAT,
"\n"
"Usage: \n"
"Default is 0 (off).");
m_pUpdateInvisibleCharacter = pSystem->GetIConsole()->CreateVariable("es_UpdateInvisibleCharacter","0",VF_CHEAT,
"\n"
"Usage: \n"
"Default is 0 (off).");
m_pUpdateBonePositions = pSystem->GetIConsole()->CreateVariable("es_UpdateBonePositions","1",VF_CHEAT,
"\n"
"Usage: \n"
"Default is 1 (on).");
m_pUpdateScript = pSystem->GetIConsole()->CreateVariable("es_UpdateScript","1",VF_CHEAT,
"\n"
"Usage: \n"
"Default is 1 (on).");
m_pUpdatePhysics = pSystem->GetIConsole()->CreateVariable("es_UpdatePhysics","1",VF_CHEAT,
"Toggles updating of entity physics.\n"
"Usage: es_UpdatePhysics [0/1]\n"
"Default is 1 (on). Set to 0 to prevent entity physics from updating.");
m_pUpdateAI = pSystem->GetIConsole()->CreateVariable("es_UpdateAI","1",VF_CHEAT,
"Toggles updating of AI entities.\n"
"Usage: es_UpdateAI [0/1]\n"
"Default is 1 (on). Set to 0 to prevent AI entities from updating.");
m_pUpdateEntities = pSystem->GetIConsole()->CreateVariable("es_UpdateEntities","1",VF_CHEAT,
"Toggles entity updating.\n"
"Usage: es_UpdateEntities [0/1]\n"
"Default is 1 (on). Set to 0 to prevent all entities from updating.");
m_pUpdateCollision= pSystem->GetIConsole()->CreateVariable("es_UpdateCollision","1",VF_CHEAT,
"Toggles updating of entity collisions.\n"
"Usage: es_UpdateCollision [0/1]\n"
"Default is 1 (on). Set to 0 to disable entity collision updating.");
m_pUpdateContainer= pSystem->GetIConsole()->CreateVariable("es_UpdateContainer","1",VF_CHEAT,
"\n"
"Usage: es_UpdateContainer [0/1]\n"
"Default is 1 (on).");
m_pUpdateTimer = pSystem->GetIConsole()->CreateVariable("es_UpdateTimer","1",VF_CHEAT,
"\n"
"Usage: es_UpdateTimer [0/1]\n"
"Default is 1 (on).");
m_pDebugTimer = pSystem->GetIConsole()->CreateVariable("es_DebugTimer","0",VF_CHEAT,
"\n"
"Usage: es_DebugTimer [0/1]\n"
"Default is 0 (on).");
m_pUpdateCamera = pSystem->GetIConsole()->CreateVariable("es_UpdateCamera","1",VF_CHEAT,
"Toggles camera updating.\n"
"Usage: es_UpdateCamera [0/1]\n"
"Default is 1 (on).");
m_pUpdateCollisionScript = pSystem->GetIConsole()->CreateVariable("es_UpdateCollisionScript","1",VF_CHEAT,
"\n"
"Usage: es_UpdateCollisionScript [0/1]\n"
"Default is 1 (on).");
m_pUpdateCoocooEgg = pSystem->GetIConsole()->CreateVariable("es_UpdateCoocooEgg","1",VF_CHEAT,
"\n"
"Usage: es_UpdateCoocooEgg [0/1]\n"
"Default is 1 (on).");
m_pPiercingCamera = pSystem->GetIConsole()->CreateVariable("es_PiercingCamera","0",VF_CHEAT,
"\n"
"Usage: es_PiercingCamera [0/1]\n"
"Default is 0 (off).");
m_pVisCheckForUpdate = pSystem->GetIConsole()->CreateVariable("es_VisCheckForUpdate","1",VF_CHEAT,
"\n"
"Usage: es_VisCheckForUpdate [0/1]\n"
"Default is 1 (on).");
m_pEntityBBoxes = pSystem->GetIConsole()->CreateVariable("es_bboxes","0",VF_CHEAT,//this console variable is repeated, which is the right one
"\n"
"Usage: es_bboxes [0/1]\n"
"Default is 0 (off).");
m_pEntityHelpers = pSystem->GetIConsole()->CreateVariable("es_helpers","0",VF_CHEAT,
"\n"
"Usage: es_helpers [0/1]\n"
"Default is 0 (off).");
m_pOnDemandPhysics = pSystem->GetIConsole()->CreateVariable("es_OnDemandPhysics","0",VF_CHEAT,
"\n"
"Usage: es_OnDemandPhysics [0/1]\n"
"Default is 1 (on).");
m_pMinImpulseVel = pSystem->GetIConsole()->CreateVariable("es_MinImpulseVel","0.0",VF_CHEAT,
"\n"
"Usage: es_MinImpulseVel 0.0\n"
"");
m_pImpulseScale = pSystem->GetIConsole()->CreateVariable("es_ImpulseScale","0.0",VF_CHEAT,
"\n"
"Usage: es_ImpulseScale 0.0\n"
"");
m_pMaxImpulseAdjMass = pSystem->GetIConsole()->CreateVariable("es_MaxImpulseAdjMass","2000.0",VF_CHEAT,
"\n"
"Usage: es_MaxImpulseAdjMass 2000.0\n"
"");
m_pSplashThreshold = pSystem->GetIConsole()->CreateVariable("es_SplashThreshold","1.0",VF_CHEAT,
"minimum instantaneous water resistance that is detected as a splash"
"Usage: es_SplashThreshold 200.0\n"
"");
m_pSplashTimeout = pSystem->GetIConsole()->CreateVariable("es_SplashTimeout","3.0",VF_CHEAT,
"minimum time interval between consecutive splashes"
"Usage: es_SplashTimeout 3.0\n"
"");
m_pHitCharacters = pSystem->GetIConsole()->CreateVariable("es_HitCharacters","1",0,
"specifies whether alive characters are affected by bullet hits (0 or 1)");
m_pHitDeadBodies = pSystem->GetIConsole()->CreateVariable("es_HitDeadBodies","1",0,
"specifies whether dead bodies are affected by bullet hits (0 or 1)");
m_pEnableCloth = pSystem->GetIConsole()->CreateVariable("es_EnableCloth","1",VF_DUMPTODISK,
"specifies whether cloth will be physicalized (0 or 1)");
m_pCharZOffsetSpeed = pSystem->GetIConsole()->CreateVariable("es_CharZOffsetSpeed","2.0",VF_DUMPTODISK,
"sets the character Z-offset change speed (in m/s), used for IK");
m_bClient=false;
m_bServer=false;
m_bTimersPause=false;
m_nStartPause=-1;
}
//////////////////////////////////////////////////////////////////////
CEntitySystem::~CEntitySystem()
{
//ShutDown();
}
//////////////////////////////////////////////////////////////////////
void CEntitySystem::InsertEntity( EntityId id, CEntity *pEntity )
{
EntityMap::iterator it;
assert( pEntity );
it = m_mapEntities.find(id);
if (it != m_mapEntities.end())
{
//assert(false);
m_pISystem->GetILog()->Log("ENTITY id=%d class=\"%s\" already spawned on this client...override",it->second->GetId(),it->second->GetEntityClassName());
}
// CConsole::Exit("CEntitySystem::InsertEntity - Entity already in map !");
m_mapEntities.insert( EntityMap::value_type(id, pEntity) );
}
//////////////////////////////////////////////////////////////////////
bool CEntitySystem::Init(ISystem *pSystem)
{
if (!pSystem) return false;
m_pISystem=pSystem;
//m_pSink=NULL;
m_lstSinks.clear();
m_mapEntities.clear();
m_pScriptSystem=pSystem->GetIScriptSystem();
m_pScriptSystem->SetGlobalValue("ScriptEvent_Activate", ScriptEvent_Activate);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Deactivate", ScriptEvent_Deactivate);
m_pScriptSystem->SetGlobalValue("ScriptEvent_FireModeChange", ScriptEvent_FireModeChange);
m_pScriptSystem->SetGlobalValue("ScriptEvent_DropItem", ScriptEvent_DropItem);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Reset", ScriptEvent_Reset);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Timer", ScriptEvent_Timer);
m_pScriptSystem->SetGlobalValue("ScriptEvent_StartAnimation", ScriptEvent_StartAnimation);
m_pScriptSystem->SetGlobalValue("ScriptEvent_AnimationKey", ScriptEvent_AnimationKey);
m_pScriptSystem->SetGlobalValue("ScriptEvent_EndAnimation", ScriptEvent_EndAnimation);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Respawn", ScriptEvent_Respawn);
m_pScriptSystem->SetGlobalValue("ScriptEvent_ItemActivated", ScriptEvent_ItemActivated);
m_pScriptSystem->SetGlobalValue("ScriptEvent_ZoomToggle", ScriptEvent_ZoomToggle);
m_pScriptSystem->SetGlobalValue("ScriptEvent_ZoomIn", ScriptEvent_ZoomIn);
m_pScriptSystem->SetGlobalValue("ScriptEvent_ZoomOut", ScriptEvent_ZoomOut);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Hit", ScriptEvent_Hit);
m_pScriptSystem->SetGlobalValue("ScriptEvent_WeaponReady",ScriptEvent_WeaponReady);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Reload",ScriptEvent_Reload);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Fire", ScriptEvent_Fire);
m_pScriptSystem->SetGlobalValue("ScriptEvent_StopFiring", ScriptEvent_StopFiring);
m_pScriptSystem->SetGlobalValue("ScriptEvent_FireCancel", ScriptEvent_FireCancel);
m_pScriptSystem->SetGlobalValue("ScriptEvent_FireGrenade", ScriptEvent_FireGrenade);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Command", ScriptEvent_Command);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Die", ScriptEvent_Die);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Land", ScriptEvent_Land);
m_pScriptSystem->SetGlobalValue("ScriptEvent_PhysCollision", ScriptEvent_PhysCollision);
m_pScriptSystem->SetGlobalValue("ScriptEvent_ViewModeChange", ScriptEvent_ViewModeChange);
m_pScriptSystem->SetGlobalValue("ScriptEvent_SelectWeapon",ScriptEvent_SelectWeapon);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Deafened", ScriptEvent_Deafened);
m_pScriptSystem->SetGlobalValue("ScriptEvent_CycleGrenade", ScriptEvent_CycleGrenade);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Use",ScriptEvent_Use);
m_pScriptSystem->SetGlobalValue("ScriptEvent_MeleeAttack",ScriptEvent_MeleeAttack);
m_pScriptSystem->SetGlobalValue("ScriptEvent_PhysicalizeOnDemand",ScriptEvent_PhysicalizeOnDemand);
m_pScriptSystem->SetGlobalValue("ScriptEvent_StanceChange",ScriptEvent_StanceChange);
m_pScriptSystem->SetGlobalValue("ScriptEvent_FlashLightSwitch", ScriptEvent_FlashLightSwitch);
m_pScriptSystem->SetGlobalValue("ScriptEvent_EnterWater", ScriptEvent_EnterWater);
m_pScriptSystem->SetGlobalValue("ScriptEvent_CycleVehiclePos", ScriptEvent_CycleVehiclePos);
m_pScriptSystem->SetGlobalValue("ScriptEvent_AllClear", ScriptEvent_AllClear);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Expression", ScriptEvent_Expression);
m_pScriptSystem->SetGlobalValue("ScriptEvent_InVehicleAnimation", ScriptEvent_InVehicleAnimation);
m_pScriptSystem->SetGlobalValue("ScriptEvent_InVehicleAmmo", ScriptEvent_InVehicleAmmo);
m_pScriptSystem->SetGlobalValue("ScriptEvent_ProcessCharacterEffects", ScriptEvent_ProcessCharacterEffects);
m_pScriptSystem->SetGlobalValue("ScriptEvent_Jump", ScriptEvent_Jump);
return true;
}
//////////////////////////////////////////////////////////////////////
void CEntitySystem::Release()
{
Reset();
delete this;
}
//////////////////////////////////////////////////////////////////////
void CEntitySystem::Reset()
{
// m_pISystem->GetILog()->Log("CEntitySystem::Reset()");
EntityMap::iterator it = m_mapEntities.begin();
while (it != m_mapEntities.end())
{
CEntity *ent = it->second;
if (ent)
{
ent->ShutDown();
delete ent;
}
m_mapEntities.erase( it );
it = m_mapEntities.begin();
}
m_EntityIDGenerator.Reset();
m_timersMap.clear();
}
//////////////////////////////////////////////////////////////////////
void CEntitySystem::SetSink( IEntitySystemSink *pSink )
{
if (pSink)
{
if (std::find(m_lstSinks.begin(),m_lstSinks.end(),pSink) == m_lstSinks.end())
m_lstSinks.push_back(pSink);
}
//m_pSink=pSink;
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::RemoveSink( IEntitySystemSink *pSink )
{
m_lstSinks.remove(pSink);
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::DeleteEntity( IEntity *entity )
{
FUNCTION_PROFILER( m_pISystem,PROFILE_ENTITY );
if (entity)
{
CEntity *ce = ((CEntity *)entity);
// CLog::LogToConsole( "Entity %s removed (%d,%s)",entity->GetClassName().c_str(),entity->GetId(),entity->GetName().c_str() );
ce->ShutDown();
int id = ce->GetId();
m_mapEntities.erase( id );
// m_pISystem->GetILog()->Log("CEntitySystem::DeleteEntity %d",id);
// [kirill] we keep list of entities visible in prev frame.
// make sure no delited entity is in the list
// not good to erase from list - can be chaged to vector - let's see
EntityVector::iterator prevListItr = std::find(m_vEntitiesInFrustrumPrevFrame.begin(), m_vEntitiesInFrustrumPrevFrame.end(), ce);
if(prevListItr != m_vEntitiesInFrustrumPrevFrame.end())
m_vEntitiesInFrustrumPrevFrame.erase( prevListItr );
// If the entity is bound, lets make sure that the ID is not reused before the parent has a chance to
// try to update it and discover that it is no longer present. The parent will then release the mark
// so it will be safely reused.
if (!entity->IsBound())
m_EntityIDGenerator.Remove(id);
delete (CEntity *)entity;
}
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::SetDynamicEntityIdMode( const bool bActivate )
{
m_bDynamicEntityIdMode=bActivate;
}
//load an entity from script,set position and add to the entity system
//////////////////////////////////////////////////////////////////////
IEntity* CEntitySystem::SpawnEntity( CEntityDesc &ed,bool bAutoInit )
{
FUNCTION_PROFILER( m_pISystem,PROFILE_ENTITY );
//GarbageCollectorCycle();
CEntity *pEntity =0;
{
//======== SPAWN NORMAL ENTITY
if (ed.id == 0)
{
ed.id = m_EntityIDGenerator.GetNewDynamic(); // get entity id and mark it
}
else if (ed.id < 0)
{
// If negative if, means comming from editor and needs static id.
ed.id = m_EntityIDGenerator.GetNewStatic(); // get entity id and mark it
}
else
{
if(m_pISystem->GetIGame()->GetModuleState(EGameMultiplayer))
{
RemoveEntity(ed.id,true);
// m_pISystem->GetILog()->Log("Entity %s [%d] updated",(const char*)ed.name,ed.id);
}
else
if (m_EntityIDGenerator.IsUsed(ed.id))
{
m_pISystem->Warning( VALIDATOR_MODULE_ENTITYSYSTEM,VALIDATOR_WARNING,0,0,"CEntitySystem::SpawnEntity Failed, Can't spawn %s. ID %d is used",
(const char*)ed.name,ed.id);
return 0;
}
m_EntityIDGenerator.Mark(ed.id);
}
IEntityContainer *pContainer=NULL;
// new entity
pEntity = new CEntity(this,m_pISystem,m_pScriptSystem);
pEntity->SetClassId(ed.ClassId);
//[PETAR] Set default update level
pEntity->SetUpdateVisLevel(m_eDefaultUpdateLevel);
// first, create appropriate container
pEntity->SetID(ed.id);
pEntity->SetNetPresence(ed.netPresence);
// if (m_pSink)
if (!m_lstSinks.empty())
{
for (SinkList::iterator si=m_lstSinks.begin();si!=m_lstSinks.end();si++)
(*si)->OnSpawnContainer(ed,pEntity);
}
if(pEntity->GetContainer())
{
pEntity->SetClassName(ed.className.c_str());
}
// put it into the entity map
InsertEntity( ed.id, pEntity);
if (!m_lstSinks.empty())
{
for (SinkList::iterator si=m_lstSinks.begin();si!=m_lstSinks.end();si++)
(*si)->OnSpawn(pEntity,ed);
}
if (bAutoInit)
{
if (!InitEntity( pEntity,ed ))
{
return NULL;
}
#ifdef _DEBUG
m_pISystem->GetILog()->LogToFile("Entity spawned %d %s (%f %f %f)",pEntity->GetId(),pEntity->GetEntityClassName(),ed.pos.x,ed.pos.y,ed.pos.z);
#endif
}
}
//add the entity in all clones mgr
/* EntityClonesMgrSetItor itor;
itor=m_setEntityClonesMgrs.begin();
while(itor!=m_setEntityClonesMgrs.end())
{
CEntityClonesMgr *pECM=(*itor);
pECM->AddEntity(pEntity);
++itor;
}*/
// Tell the client in lua that an entity has spawned
if (pEntity->GetScriptObject())
{
//Timur, Look ups by name in lua must be replaced with table reference.
IScriptSystem *pSS = GetScriptSystem();
_SmartScriptObject pClientStuff(pSS,true);
if(pSS->GetGlobalValue("ClientStuff",pClientStuff))
{
pSS->BeginCall("ClientStuff","OnSpawnEntity");
pSS->PushFuncParam(pClientStuff);
m_pScriptSystem->PushFuncParam(pEntity->GetScriptObject());
pSS->EndCall();
}
}
// set m_bHasEnvLighting flag for player and vehicles now to avoid calling virtual functions during rendering
void*pDummy=0;
if( pEntity->GetContainer() &&
( pEntity->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**)&pDummy) ||
pEntity->GetContainer()->QueryContainerInterface(CIT_IVEHICLE,(void**)&pDummy)))
pEntity->SetHasEnvLighting(true);
else
pEntity->SetHasEnvLighting(false);
return (IEntity*)pEntity;
}
//////////////////////////////////////////////////////////////////////////
bool CEntitySystem::InitEntity( IEntity* pEntity,CEntityDesc &ed )
{
assert( pEntity );
CEntity *pCEntity = (CEntity*)pEntity;
// initialize entity
if (!pCEntity->Init(ed))
{
DeleteEntity(pEntity);
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////
void CEntitySystem::RemoveEntity( EntityId entity,bool bRemoveNow )
{
/// m_pISystem->GetILog()->Log( "\001** Remove Entity Id %d %c",(int)entity,bRemoveNow?'t':'f' );
EntityMap::iterator it = m_mapEntities.find(entity);
// TRACE("Entity %d marked as garbage",entity);
CEntity *pEntity=NULL;
if (it != m_mapEntities.end())
{
pEntity = it->second;
if (!m_lstSinks.empty())
{
for (SinkList::iterator si=m_lstSinks.begin();si!=m_lstSinks.end();si++)
(*si)->OnRemove(pEntity);
}
pEntity->MarkAsGarbage();
if (bRemoveNow && pEntity->IsDestroyable())
DeleteEntity(pEntity);
}
/*
it = m_vStaticEntities.find(entity);
if (it != m_vStaticEntities.end())
{
pEntity = it->second;
// pEntity->MarkAsGarbage();
if (pEntity->IsDestroyable())
{
if (!pEntity->IsBound())
m_EntityIDGenerator.Remove(pEntity->GetId());
pEntity->ShutDown();
m_vStaticEntities.erase(it);
delete pEntity;
}
}
*/
//remove the entity in all clones mgr
/*if(pEntity)
{
EntityClonesMgrSetItor itor;
itor=m_setEntityClonesMgrs.begin();
while(itor!=m_setEntityClonesMgrs.end())
{
CEntityClonesMgr *pECM=(*itor);
pECM->RemoveEntity(pEntity);
++itor;
}
}*/
}
//////////////////////////////////////////////////////////////////////
IEntity* CEntitySystem::GetEntity( EntityId id )
{
m_nGetEntityCounter++;
EntityMap::iterator it = m_mapEntities.find(id);
if (it != m_mapEntities.end())
{
// Entity found.
return (IEntity*)(it->second);
}
/*
it = m_vStaticEntities.find(id);
if (it != m_vStaticEntities.end())
{
return (IEntity*) (it->second);
}
*/
// ASSERT(id==0); // if we have a valid id here, someone is using the id after deleting the ent
return NULL;
}
//////////////////////////////////////////////////////////////////////
EntityId CEntitySystem::FindEntity( const char *name ) const
{
EntityMap::const_iterator itor;
itor=m_mapEntities.begin();
while(itor!=m_mapEntities.end())
{
CEntity *ce = itor->second;
if (stricmp( ce->GetName(),name) == 0)
{
return ce->GetId();
}
++itor;
}
//CryWarning( "<CryEntitySystem> Entity %s not found",name );
// if you are here you are doing something wrong!!!!
// not in any case !
return 0; //not found
}
//////////////////////////////////////////////////////////////////////////
IEntity* CEntitySystem::GetEntity(const char *sEntityName)
{
if (!sEntityName || !sEntityName[0])
return 0; // no entity name specified
EntityMapItor itor=m_mapEntities.begin();
while(itor!=m_mapEntities.end())
{
CEntity *ce = itor->second;
if (stricmp( ce->GetName(),sEntityName) == 0)
{
return ce;
}
++itor;
}
return NULL;
}
//////////////////////////////////////////////////////////////////////
int CEntitySystem::GetNumEntities() const
{
return m_mapEntities.size();
}
//////////////////////////////////////////////////////////////////////
/*void CEntitySystem::GetEntities( std::vector<IEntity*> &vecEntities ) const
{
int i = 0;
if(m_mapEntities.empty())
{
vecEntities.clear();
return;
}
vecEntities.resize( m_mapEntities.size() );
for (EntityMap::const_iterator it = m_mapEntities.begin(); it != m_mapEntities.end(); ++it)
{
vecEntities[i++] = (IEntity*)(it->second);
}
}*/
//////////////////////////////////////////////////////////////////////
void CEntitySystem::GetEntitiesInRadius( const Vec3d &origin,float radius,std::vector<IEntity*> &entities,int physFlags ) const
{
assert(m_pISystem);
IPhysicalEntity **pList;
Vec3d bmin = origin - Vec3d(radius,radius,radius);
Vec3d bmax = origin + Vec3d(radius,radius,radius);
vectorf v_min, v_max;
v_min.x = bmin.x;
v_min.y = bmin.y;
v_min.z= bmin.z;
v_max.x = bmax.x;
v_max.y = bmax.y;
v_max.z= bmax.z;
int num = m_pISystem->GetIPhysicalWorld()->GetEntitiesInBox( v_min,v_max,pList,physFlags );
entities.resize( num );
for (int i = 0; i < num; i++)
{
IEntity *ce = (IEntity*)pList[i]->GetForeignData();
if (ce)
{
entities[i] = ce;
}
}
}
// update the entity
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::UpdateEntity(CEntity *ce,SEntityUpdateContext &ctx)
{
if (ce->m_bGarbage)
{
if (ce->IsDestroyable())
{
DeleteEntity(ce);
}
else
{ // [kirill] we must be in editor gamemode (Timur assures it wil newer happen in game)
// can't destroy entity - just hide it/remove physics
ce->DestroyPhysics();
ce->DrawObject(0);
ce->DrawCharacter(0,0);
}
return;
}
if (ce->m_bHidden)
return;
if (ce->m_bTrackable)
{
//if (ce->GetDrawFrame() == ctx.nFrameID)
//if (ce->m_nLastVisibleFrameID == ctx.nFrameID)
if (abs(int(ctx.nFrameID - ce->m_nLastVisibleFrameID)) < MAX_FRAME_ID_STEP_PER_FRAME)
m_vEntitiesInFrustrum.push_back(ce);
}
// Bound entites always updated by thier parents.
if (ce->m_bIsBound)
return;
if (ce->m_eUpdateVisLevel==eUT_PhysicsPostStep)
return;
//if (bUpdateEntities)
{
bool bNeedUpdate = (ce->m_bUpdate && !ce->m_bSleeping) || (ce->m_awakeCounter > 0);
if (bNeedUpdate)
{
ce->Update(ctx);
}
// If have childs.
if (ce->m_bUpdateBinds)
{
// If not updated.
ce->UpdateHierarchy( ctx );
}
}
}
//update the entity system
//////////////////////////////////////////////////////////////////////
void CEntitySystem::Update()
{
g_bProfilerEnabled = m_pISystem->GetIProfileSystem()->IsProfiling();
FUNCTION_PROFILER_FAST( m_pISystem,PROFILE_ENTITY,g_bProfilerEnabled );
//char strNumStatObjs[100];
//sprintf(strNumStatObjs," %d|Stat",(int)m_vStaticEntities.size() );
UpdateTimers();
{
m_vEntitiesInFrustrumPrevFrame.resize(0);
//m_vEntitiesInFrustrumPrevFrame.insert(m_vEntitiesInFrustrumPrevFrame.begin(), m_vEntitiesInFrustrum.begin(), m_vEntitiesInFrustrum.end());
m_vEntitiesInFrustrumPrevFrame = m_vEntitiesInFrustrum;
m_vEntitiesInFrustrum.resize(0);
}
CCamera Cam=m_pISystem->GetViewCamera();
Vec3d Min, Max;
EntityMap::iterator next;
int nRendererFrameID=0;
if(m_pISystem)
{
IRenderer *pRen=m_pISystem->GetIRenderer();
if(pRen)
nRendererFrameID=pRen->GetFrameID();
// nRendererFrameID=pRen->GetFrameUpdateID();
}
bool bUpdateEntities=m_pUpdateEntities->GetIVal()?true:false;
bool bProfileEntities = m_pProfileEntities->GetIVal() >= 1;
bool bProfileEntitiesToLog = m_pProfileEntities->GetIVal() == 2;
bool bProfileEntitiesAll = m_pProfileEntities->GetIVal() == 3;
float fStartTime = 0;
SEntityUpdateContext ctx;
ctx.nFrameID = nRendererFrameID;
ctx.pCamera = &Cam;
ctx.fCurrTime = m_pISystem->GetITimer()->GetCurrTime();
ctx.fFrameTime = m_pISystem->GetITimer()->GetFrameTime();
ctx.bProfileToLog = bProfileEntitiesToLog;
ctx.numVisibleEntities = 0;
ctx.numUpdatedEntities = 0;
ctx.fMaxViewDist = Cam.GetZMax();
ctx.fMaxViewDistSquared = ctx.fMaxViewDist*ctx.fMaxViewDist;
ctx.vCameraPos = Cam.GetPos();
if (!bProfileEntities)
{
for (EntityMap::iterator it = m_mapEntities.begin(); it != m_mapEntities.end();it = next)
{
next = it; next++;
CEntity *ce= it->second;
UpdateEntity(ce,ctx);
}
}
else
{
if (bProfileEntitiesToLog)
m_pISystem->GetILog()->Log( "\001================= Entity Update Times =================" );
char szProfInfo[256];
float colors[4]={1,1,1,1};
float colorsYellow[4]={1,1,0,1};
float colorsRed[4]={1,0,0,1};
int prevNumUpdated;
float fProfileStartTime;
for (EntityMap::iterator it = m_mapEntities.begin(); it != m_mapEntities.end();it = next)
{
next = it; next++;
CEntity *ce= it->second;
fProfileStartTime = m_pTimer->GetAsyncCurTime();
prevNumUpdated = ctx.numUpdatedEntities;
bool bGarbage = ce->m_bGarbage;
UpdateEntity(ce,ctx);
if (bGarbage)
continue;
if (prevNumUpdated != ctx.numUpdatedEntities || bProfileEntitiesAll)
{
float time = m_pTimer->GetAsyncCurTime() - fProfileStartTime;
if (time < 0)
time = 0;
if (bProfileEntitiesToLog)
GetISystem()->GetILog()->Log( "\001%.3f ms : %s (%s)",time*1000.0f,ce->GetName(),ce->GetEntityClassName() );
sprintf(szProfInfo,"%.3f ms : %s (%s)",time*1000.0f,ce->GetName(),ce->GetEntityClassName() );
//m_pISystem->GetIRenderer()->DrawLabel(ce->GetPos(),1,szProfInfo);
if (time > 0.5f)
m_pISystem->GetIRenderer()->DrawLabelEx(ce->GetPos(),1.1f,colorsYellow,true,true,szProfInfo);
else if (time > 1.0f)
m_pISystem->GetIRenderer()->DrawLabelEx(ce->GetPos(),1.5f,colorsRed,true,true,szProfInfo);
else
m_pISystem->GetIRenderer()->DrawLabelEx(ce->GetPos(),0.9f,colors,true,true,szProfInfo);
}
} //it
if (bProfileEntitiesToLog)
{
m_pISystem->GetILog()->Log( "\001================= Entity Update Times =================" );
m_pISystem->GetILog()->Log( "\001%d Entities Updated.",ctx.numUpdatedEntities );
m_pISystem->GetILog()->Log( "\001%d Visible Entities Updated.",ctx.numVisibleEntities );
m_pISystem->GetILog()->Log( "\001%d Active Entity Timers.",(int)m_timersMap.size() );
m_pISystem->GetILog()->Log( "\001%d Trackable Visible Entities.",(int)m_vEntitiesInFrustrum.size() );
m_pProfileEntities->Set(0);
}
sprintf(szProfInfo,"Entities Updated: %d",ctx.numUpdatedEntities );
m_pISystem->GetIRenderer()->Draw2dLabel( 10,10,1,colors,false,szProfInfo );
m_pISystem->GetITimer()->MeasureTime("REALEntUp");
}
m_nGetEntityCounter=0;
}
/*
void CEntitySystem::GarbageCollectorCycle()
{
EntityMap::iterator next;
for (EntityMap::iterator it = m_mapEntities.begin(); it != m_mapEntities.end();it = next)
{
next = it; next++;
CEntity *ce= it->second;
if (ce->IsGarbage() && ce->IsDestroyable())
{
ce->ShutDown();
m_EntityIDGenerator.Remove(ce->GetId());
delete ce;
EntityMap::iterator itTemp=it;
m_mapEntities.erase(itTemp); // map iterator doesn;t invalidate :)
continue;
}
}
}
*/
//////////////////////////////////////////////////////////////////////////
IEntityCamera * CEntitySystem::CreateEntityCamera()
{
CEntityCamera *pNew = new CEntityCamera;
pNew->Init(m_pISystem->GetIPhysicalWorld(),
m_pISystem->GetIRenderer()->GetWidth(),
m_pISystem->GetIRenderer()->GetHeight(), m_pISystem->GetIConsole());
return (IEntityCamera *) pNew;
};
//////////////////////////////////////////////////////////////////////////
IEntityIt *CEntitySystem::GetEntityIterator()
{
return (IEntityIt *) new CEntityItMap(&m_mapEntities);
}
//////////////////////////////////////////////////////////////////////////
IEntityIt *CEntitySystem::GetEntityInFrustrumIterator( bool bFromPrevFrame )
{
if(bFromPrevFrame )
return new CEntityItVec(&m_vEntitiesInFrustrumPrevFrame);
return new CEntityItVec(&m_vEntitiesInFrustrum);
}
/*IEntityClonesMgr *CEntitySystem::CreateEntityClonesMgr()
{
//CEntityClonesMgr *pECM=new CEntityClonesMgr(this);
//<<FIXME>> implement add all entities
//m_setEntityClonesMgrs.insert(pECM);
return NULL;
}*/
/*void CEntitySystem::RemoveEntityCloneMgr(CEntityClonesMgr *p)
{
//m_setEntityClonesMgrs.erase(p);
}*/
//////////////////////////////////////////////////////////////////////////
bool CEntitySystem::IsIDUsed(EntityId nID)
{
return m_EntityIDGenerator.IsUsed(nID);
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::ReleaseMark(unsigned int id)
{
m_EntityIDGenerator.Remove(id);
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::ResetEntities(void)
{
// call on reset for every entity
EntityMap::iterator it = m_mapEntities.begin();
while (it != m_mapEntities.end())
{
CEntity *ent = it->second;
if (ent)
{
ent->Reset();
ent->SendScriptEvent(ScriptEvent_Reset,0);
}
it++;
}
/*
it = m_mapEntities.begin();
while (it != m_mapEntities.end())
{
CEntity *ent = it->second;
if (ent)
{
ent->OnBindAI( 0 );
}
it++;
}
*/
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::GetMemoryStatistics(ICrySizer *pSizer)
{
unsigned nSize = sizeof(*this) + m_EntityIDGenerator.sizeofThis() - sizeof(m_EntityIDGenerator);
EntityMapItor itor;
for(itor=m_mapEntities.begin();itor!=m_mapEntities.end();++itor)
{
itor->second->GetMemoryStatistics(pSizer);
nSize += sizeof(*itor);
}
nSize += m_lstSinks.size() * sizeof(IEntitySystemSink*);
{
nSize += m_vEntitiesInFrustrum.size() * sizeof(m_vEntitiesInFrustrum[0]);
for (EntityVector::iterator it = m_vEntitiesInFrustrum.begin(); it != m_vEntitiesInFrustrum.end(); ++it)
(*it)->GetMemoryStatistics(pSizer);
}
pSizer->AddObject(this, nSize);
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::OnBind(EntityId id,EntityId child,unsigned char param)
{
if (!m_lstSinks.empty())
{
for (SinkList::iterator si=m_lstSinks.begin();si!=m_lstSinks.end();si++)
(*si)->OnBind(id,child,param);
}
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::OnUnbind(EntityId id,EntityId child,unsigned char param)
{
if (!m_lstSinks.empty())
{
for (SinkList::iterator si=m_lstSinks.begin();si!=m_lstSinks.end();si++)
(*si)->OnUnbind(id,child,param);
}
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::AddTimerEvent( int delayTimeMillis,SEntityTimerEvent &event )
{
int nCurrTimeMillis = FtoI(m_pISystem->GetITimer()->GetCurrTime() * 1000.0f);
int nTriggerTime = nCurrTimeMillis + delayTimeMillis;
m_timersMap.insert( EntityTimersMap::value_type(nTriggerTime,event) );
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::RemoveTimerEvent( EntityId id )
{
for (EntityTimersMap::iterator it = m_timersMap.begin(); it != m_timersMap.end(); ++it)
{
if (id == it->second.entityId)
{
// Remove this item.
m_timersMap.erase( it );
break;
}
}
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::PauseTimers(bool bPause,bool bResume)
{
m_bTimersPause=bPause;
if (bResume)
{
m_nStartPause=-1;
return; // just allow timers to be updated next time
}
if (m_pISystem->GetIGame())
{
if (m_pISystem->GetIGame()->GetModuleState(EGameMultiplayer))
return;
}
if (bPause)
{
// record when timers pause was called
m_nStartPause = FtoI(m_pISystem->GetITimer()->GetCurrTime() * 1000.0f);
}
else if (m_nStartPause>0)
{
// increase the timers by adding the delay time passed since when
// it was paused
int nCurrTimeMillis=FtoI(m_pISystem->GetITimer()->GetCurrTime() * 1000.0f);
int nAdditionalTriggerTime = nCurrTimeMillis-m_nStartPause;
EntityTimersMap::iterator it;
EntityTimersMap lstTemp;
for (it = m_timersMap.begin();it!=m_timersMap.end();it++)
{
lstTemp.insert( EntityTimersMap::value_type(it->first,it->second) );
} //it
m_timersMap.clear();
for (it = lstTemp.begin();it!=lstTemp.end();it++)
{
int nUpdatedTimer=it->first+nAdditionalTriggerTime;
m_timersMap.insert( EntityTimersMap::value_type(nUpdatedTimer,it->second) );
} //it
m_nStartPause=-1;
}
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::UpdateTimers()
{
if (m_timersMap.empty())
return;
if (m_pISystem->GetIGame())
{
if ((!m_pISystem->GetIGame()->GetModuleState(EGameMultiplayer)) && m_bTimersPause)
return;
}
int nCurrTimeMillis = FtoI(m_pISystem->GetITimer()->GetCurrTime() * 1000.0f);
// Iterate thru all matching timers.
EntityTimersMap::iterator first = m_timersMap.begin();
EntityTimersMap::iterator last = m_timersMap.upper_bound( nCurrTimeMillis );
if (last != first)
{
// Make a separate list, because OnTrigger call can modify original timers map.
m_currentTriggers.resize(0);
m_currentTriggers.reserve(10);
for (EntityTimersMap::iterator it = first; it != last; ++it)
{
m_currentTriggers.push_back(it->second);
}
// Delete these items from map.
m_timersMap.erase( first,last );
//////////////////////////////////////////////////////////////////////////
// Execute OnTrigger events.
for (int i = 0; i < (int)m_currentTriggers.size(); i++)
{
SEntityTimerEvent &event = m_currentTriggers[i];
// Trigger it.
CEntity *pEntity = (CEntity*)GetEntity( event.entityId );
if (pEntity)
{
// Silently kill trigger.
pEntity->m_nTimer = -1;
pEntity->OnTimer( event.timerId );
}
}
}
}
//////////////////////////////////////////////////////////////////////////
void CEntitySystem::SetPrecacheResourcesMode( bool bPrecaching )
{
gPrecacheResourcesMode = bPrecaching;
}