void CAreaManager::Unregister(CArea const* const pArea) { // Remove the area reference from the entity's area cache. m_mapAreaCache.erase_if(SRemoveIfNoAreasLeft(pArea, m_apAreas, m_apAreas.size())); // Also remove the area reference itself. TAreaPointers::iterator IterAreas(m_apAreas.begin()); TAreaPointers::const_iterator const IterAreasEnd(m_apAreas.end()); for (; IterAreas != IterAreasEnd; ++IterAreas) { if (pArea == (*IterAreas)) { m_apAreas.erase(IterAreas); break; } } if (m_apAreas.empty()) { stl::free_container(m_apAreas); } m_bAreasDirty = true; }
bool CAreaManager::QueryAreas(EntityId const nEntityID, Vec3 const& rPos, SAreaManagerResult *pResults, int nMaxResults, int& rNumResults) { rNumResults = 0; if (pResults) { // Make sure the area grid is recompiled, if needed, before accessing it UpdateDirtyAreas(); uint32 numAreas = 0; TAreaPointers const& rAreasAtPos(m_areaGrid.GetAreas(rPos)); TAreaPointers::const_iterator IterAreas(rAreasAtPos.begin()); TAreaPointers::const_iterator const IterAreasEnd(rAreasAtPos.end()); for (; IterAreas != IterAreasEnd; ++IterAreas) { CArea* const pArea = *IterAreas; #if defined(DEBUG_AREAMANAGER) CheckArea(pArea); #endif // DEBUG_AREAMANAGER // check if Area is hidden IEntity const* const pAreaEntity = m_pEntitySystem->GetEntity(pArea->GetEntityID()); if (pAreaEntity && !pAreaEntity->IsHidden()) { Vec3 Closest3d(ZERO); float const fGreatestFadeDistance = pArea->GetGreatestFadeDistance(); // This is optimized internally and might not recalculate but rather retrieve the cached data. float const fDistanceSq = pArea->CalcPointNearDistSq(nEntityID, rPos, Closest3d, false); bool const bIsPointWithin = (pArea->CalcPosType(nEntityID, rPos, false) == AREA_POS_TYPE_2DINSIDE_ZINSIDE); bool const isNear = ((fDistanceSq > 0.0f) && (fDistanceSq < fGreatestFadeDistance*fGreatestFadeDistance)); if (isNear || bIsPointWithin) { // still have room to put it in? if (rNumResults == nMaxResults) return false; // found area that should go into the results pResults[rNumResults].pArea = pArea; pResults[rNumResults].fDistanceSq = fDistanceSq; pResults[rNumResults].vPosOnHull = Closest3d; pResults[rNumResults].bInside = bIsPointWithin; pResults[rNumResults].bNear = isNear; ++rNumResults; } } } return true; } return false; }
bool CAreaManager::QueryAudioAreas(Vec3 const& rPos, SAudioAreaInfo *pResults, size_t const nMaxResults, size_t& rNumResults) { rNumResults = 0; if (pResults != NULL) { // Make sure the area grid is recompiled, if needed, before accessing it UpdateDirtyAreas(); uint32 numAreas = 0; TAreaPointers const& rAreasAtPos(m_areaGrid.GetAreas(rPos)); TAreaPointers::const_iterator IterAreas(rAreasAtPos.begin()); TAreaPointers::const_iterator const IterAreasEnd(rAreasAtPos.end()); for (; IterAreas != IterAreasEnd; ++IterAreas) { CArea* const pArea = *IterAreas; #if defined(DEBUG_AREAMANAGER) if (!stl::find(m_apAreas, pArea)) { CryFatalError("<AreaManager>: area in entity-area-cache not found in overall areas list!"); } #endif // DEBUG_AREAMANAGER // check if Area is hidden IEntity const* const pAreaEntity = m_pEntitySystem->GetEntity(pArea->GetEntityID()); if (pAreaEntity && !pAreaEntity->IsHidden()) { size_t const nAttachedEntities = pArea->GetEntityAmount(); if (nAttachedEntities > 0) { for (size_t iEntity = 0; iEntity < nAttachedEntities; ++iEntity) { IEntity const* const pEntity = gEnv->pEntitySystem->GetEntity(pArea->GetEntityByIdx(iEntity)); if (pEntity != NULL) { IEntityAudioProxy const* const pAudioProxy = (IEntityAudioProxy*)pEntity->GetProxy(ENTITY_PROXY_AUDIO); if (pAudioProxy != NULL) { TAudioEnvironmentID const nEnvironmentID = pAudioProxy->GetEnvironmentID(); float const fEnvironmentFadeDistance = pAudioProxy->GetEnvironmentFadeDistance(); if (nEnvironmentID != INVALID_AUDIO_ENVIRONMENT_ID) { // This is optimized internally and might not recalculate but rather retrieve the cached data. bool const bIsPointWithin = (pArea->CalcPosType(INVALID_ENTITYID, rPos, false) == AREA_POS_TYPE_2DINSIDE_ZINSIDE); float fEnvironmentAmount = 0.0f; if (!bIsPointWithin && (fEnvironmentFadeDistance > 0.0f)) { Vec3 Closest3d(ZERO); float const fDistance = sqrt_tpl(pArea->CalcPointNearDistSq(INVALID_ENTITYID, rPos, Closest3d, false)); if (fDistance <= fEnvironmentFadeDistance) { fEnvironmentAmount = 1.0f - (fDistance/fEnvironmentFadeDistance); } } else { fEnvironmentAmount = 1.0f; } if (fEnvironmentAmount > 0.0f) { // still have room to put it in? if (rNumResults == nMaxResults) return false; // found area that should go into the results pResults[rNumResults].pArea = pArea; pResults[rNumResults].fEnvironmentAmount = fEnvironmentAmount; pResults[rNumResults].nEnvironmentID = nEnvironmentID; pResults[rNumResults].nEnvProvidingEntityID = pEntity->GetId(); ++rNumResults; } } } } } } } } return true; } return false; }
void CAreaManager::UpdateEntity(Vec3 const& rPos, IEntity const* const pEntity) { EntityId const nEntityID = pEntity->GetId(); SAreasCache* pAreaCache = GetAreaCache(nEntityID); // Create a new area cache if necessary. if (pAreaCache == NULL) { pAreaCache = MakeAreaCache(nEntityID); } assert(pAreaCache != NULL); // Audio listeners and moving entities affected by environment changes need to update more often // to ensure smooth fading. uint32 const nExtendedFlags = pEntity->GetFlagsExtended(); float const fPosDelta = ((nExtendedFlags & ENTITY_FLAG_EXTENDED_AUDIO_LISTENER) != 0) || ((nExtendedFlags & ENTITY_FLAG_EXTENDED_NEEDS_MOVEINSIDE) != 0) ? 0.01f : CVar::es_EntityUpdatePosDelta; if (pAreaCache != NULL && !rPos.IsEquivalent(pAreaCache->vLastUpdatePos, fPosDelta)) { pAreaCache->vLastUpdatePos = rPos; // First mark all cache entries that as if they are not in the grid. TAreaCacheVector::iterator Iter(pAreaCache->aoAreas.begin()); TAreaCacheVector::const_iterator IterEnd(pAreaCache->aoAreas.end()); for (; Iter != IterEnd; ++Iter) { SAreaCacheEntry& rAreaCacheEntry = (*Iter); CArea* const pArea = rAreaCacheEntry.pArea; #if defined(DEBUG_AREAMANAGER) if (!stl::find(m_apAreas, pArea)) { CryFatalError("<AreaManager>: area in entity-area-cache not found in overall areas list!"); } #endif // DEBUG_AREAMANAGER rAreaCacheEntry.bInGrid = false; // Now pre-calculate position data. pArea->InvalidateCachedAreaData(nEntityID); pArea->CalcPosType(nEntityID, rPos); } TAreaPointers const& rAreasAtPos(m_areaGrid.GetAreas(rPos)); TAreaPointers::const_iterator IterAreas(rAreasAtPos.begin()); TAreaPointers::const_iterator const IterAreasEnd(rAreasAtPos.end()); for (; IterAreas != IterAreasEnd; ++IterAreas) { // Mark cache entries as if they are in the grid. CArea* const pArea = *IterAreas; SAreaCacheEntry* pAreaCacheEntry = NULL; if (pAreaCache->GetCacheEntry(pArea, &pAreaCacheEntry)) { // cppcheck-suppress nullPointer pAreaCacheEntry->bInGrid = true; } else { // if they are not yet in the cache, add them pAreaCache->aoAreas.push_back(SAreaCacheEntry(pArea, false, false)); pArea->OnAddedToAreaCache(pEntity); } #if defined(DEBUG_AREAMANAGER) if (!stl::find(m_apAreas, pArea)) { CryFatalError("<AreaManager>: area in entity-area-cache not found in overall areas list!"); } #endif // DEBUG_AREAMANAGER } // Go through all cache entries and process the areas. Iter = pAreaCache->aoAreas.begin(); IterEnd = pAreaCache->aoAreas.end(); for (; Iter != IterEnd; ++Iter) { SAreaCacheEntry& rAreaCacheEntry = (*Iter); CArea* const pArea = rAreaCacheEntry.pArea; #if defined(DEBUG_AREAMANAGER) if (!stl::find(m_apAreas, pArea)) { CryFatalError("<AreaManager>: area in entity-area-cache not found in overall areas list!"); } #endif // DEBUG_AREAMANAGER // check if Area is hidden IEntity const* const pAreaEntity = m_pEntitySystem->GetEntity(pArea->GetEntityID()); bool bIsHidden = (pAreaEntity && pAreaEntity->IsHidden()); // area was just hidden if (bIsHidden && pArea->IsActive()) { pArea->LeaveArea(pEntity); pArea->LeaveNearArea(pEntity); rAreaCacheEntry.bNear = false; rAreaCacheEntry.bInside = false; pArea->SetActive(false); continue; } // area was just unhidden if (!bIsHidden && !pArea->IsActive()) { // ProcessArea will take care of properly setting cache entry data. rAreaCacheEntry.bNear = false; rAreaCacheEntry.bInside = false; pArea->SetActive(true); } // We process only for active areas in which grid we are. // Areas in our cache in which grid we are not get removed down below anyhow. if (pArea->IsActive()) { ProcessArea(pArea, rAreaCacheEntry, pAreaCache, rPos, pEntity); } } // Go through all areas again and send accumulated events. (needs to be done in a separate step) Iter = pAreaCache->aoAreas.begin(); for (; Iter != IterEnd; ++Iter) { SAreaCacheEntry& rAreaCacheEntry = (*Iter); CArea* const pArea = rAreaCacheEntry.pArea; #if defined(DEBUG_AREAMANAGER) if (!stl::find(m_apAreas, pArea)) { CryFatalError("<AreaManager>: area in entity-area-cache not found in overall areas list!"); } #endif // DEBUG_AREAMANAGER pArea->SendCachedEventsFor(nEntityID); } // Remove all entries in the cache which are no longer in the grid. if (!pAreaCache->aoAreas.empty()) { pAreaCache->aoAreas.erase(std::remove_if(pAreaCache->aoAreas.begin(), pAreaCache->aoAreas.end(), SIsNotInGrid(pEntity, m_apAreas, m_apAreas.size())), pAreaCache->aoAreas.end()); } if (pAreaCache->aoAreas.empty()) { DeleteAreaCache(nEntityID); } } }