////////////////////////////////////////////////////////////////////// // // 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 #include #include "EntitySystem.h" #include "EntityIt.h" #include #include #include "Entity.h" #include #include #include #include #include #include // 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( " 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 &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 &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); //<> 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; }