/// Remove a layer from this world. /// /// @param[in] pLayer Layer to remove. /// /// @return True if the layer was removed successfully, false if not. /// /// @see AddLayer() bool World::RemoveLayer( Layer* pLayer ) { HELIUM_ASSERT( pLayer ); // Make sure the layer is part of this world. if( pLayer->GetWorld().Get() != this ) { HELIUM_TRACE( TRACE_ERROR, TXT( "World::RemoveLayer(): Layer \"%s\" is not part of world \"%s\".\n" ), *pLayer->GetPath().ToString(), *GetPath().ToString() ); return false; } // Detach all entities in the layer. size_t entityCount = pLayer->GetEntityCount(); for( size_t entityIndex = 0; entityIndex < entityCount; ++entityIndex ) { Entity* pEntity = pLayer->GetEntity( entityIndex ); HELIUM_ASSERT( pEntity ); pEntity->Detach(); } // Remove the layer from the layer list and clear out all references back to this world. size_t index = pLayer->GetWorldIndex(); HELIUM_ASSERT( index < m_layers.GetSize() ); pLayer->ClearWorldInfo(); m_layers.RemoveSwap( index ); // Update the index of the layer which has been moved to fill the layer list entry we just removed. size_t layerCount = m_layers.GetSize(); if( index < layerCount ) { Layer* pMovedLayer = m_layers[ index ]; HELIUM_ASSERT( pMovedLayer ); HELIUM_ASSERT( pMovedLayer->GetWorldIndex() == layerCount ); pMovedLayer->SetWorldIndex( index ); } return true; }
/// Update all worlds for the current frame. void WorldManager::Update() { // Update the world time. UpdateTime(); // Perform the entity pre-update. m_updatePhase = UPDATE_PHASE_PRE; { JobContext::Spawner< 1 > entityUpdateSpawner; JobContext* pContext = entityUpdateSpawner.Allocate(); HELIUM_ASSERT( pContext ); WorldManagerUpdate< EntityPreUpdate >* pJob = pContext->Create< WorldManagerUpdate< EntityPreUpdate > >(); HELIUM_ASSERT( pJob ); WorldManagerUpdate< EntityPreUpdate >::Parameters& rParameters = pJob->GetParameters(); rParameters.pspWorlds = m_worlds.GetData(); rParameters.worldCount = m_worlds.GetSize(); } // Perform the entity post-update. m_updatePhase = UPDATE_PHASE_POST; { JobContext::Spawner< 1 > entityUpdateSpawner; JobContext* pContext = entityUpdateSpawner.Allocate(); HELIUM_ASSERT( pContext ); WorldManagerUpdate< EntityPostUpdate >* pJob = pContext->Create< WorldManagerUpdate< EntityPostUpdate > >(); HELIUM_ASSERT( pJob ); WorldManagerUpdate< EntityPostUpdate >::Parameters& rParameters = pJob->GetParameters(); rParameters.pspWorlds = m_worlds.GetData(); rParameters.worldCount = m_worlds.GetSize(); } // Perform the entity synchronous update. m_updatePhase = UPDATE_PHASE_SYNCHRONOUS; size_t worldCount = m_worlds.GetSize(); for( size_t worldIndex = 0; worldIndex < worldCount; ++worldIndex ) { World* pWorld = m_worlds[ worldIndex ]; HELIUM_ASSERT( pWorld ); size_t layerCount = pWorld->GetLayerCount(); for( size_t layerIndex = 0; layerIndex < layerCount; ++layerIndex ) { Layer* pLayer = pWorld->GetLayer( layerIndex ); HELIUM_ASSERT( pLayer ); size_t entityCount = pLayer->GetEntityCount(); for( size_t entityIndex = 0; entityIndex < entityCount; ++entityIndex ) { Entity* pEntity = pLayer->GetEntity( entityIndex ); HELIUM_ASSERT( pEntity ); bool bNeedsSynchronousUpdate = pEntity->NeedsSynchronousUpdate(); uint32_t deferredWorkFlags = pEntity->GetDeferredWorkFlags(); if( !bNeedsSynchronousUpdate && !deferredWorkFlags ) { continue; } if( deferredWorkFlags & Entity::DEFERRED_WORK_FLAG_DESTROY ) { pLayer->DestroyEntity( pEntity ); --entityIndex; // Only the current entity should be destroyed; entity destruction should not trigger the // immediate creation or destruction of other entities. --entityCount; HELIUM_ASSERT( pLayer->GetEntityCount() == entityCount ); continue; } // Entity::NeedsSynchronousUpdate() also checks the deferred work flags. if( bNeedsSynchronousUpdate /*deferredWorkFlags & Entity::DEFERRED_WORK_FLAG_UPDATE*/ ) { pEntity->SynchronousUpdate( m_frameDeltaSeconds ); // Update the entity count in case a new entity was created during the synchronous update. entityCount = pLayer->GetEntityCount(); HELIUM_ASSERT( entityIndex < entityCount ); // Update the deferred work flags and reassess entity destruction after the synchronous update. deferredWorkFlags = pEntity->GetDeferredWorkFlags(); if( deferredWorkFlags & Entity::DEFERRED_WORK_FLAG_DESTROY ) { pLayer->DestroyEntity( pEntity ); --entityIndex; // Only the current entity should be destroyed; entity destruction should not trigger the // immediate creation or destruction of other entities. --entityCount; HELIUM_ASSERT( pLayer->GetEntityCount() == entityCount ); continue; } } if( deferredWorkFlags & Entity::DEFERRED_WORK_FLAG_REATTACH ) { pEntity->Detach(); pEntity->Attach(); // Entities should only be spawned during the synchronous update call, so the count should not // have changed as a result of reattachment. HELIUM_ASSERT( pLayer->GetEntityCount() == entityCount ); } pEntity->ClearDeferredWorkFlags(); } } } m_updatePhase = UPDATE_PHASE_INVALID; // Update the graphics scene for each world. for( size_t worldIndex = 0; worldIndex < worldCount; ++worldIndex ) { World* pWorld = m_worlds[ worldIndex ]; HELIUM_ASSERT( pWorld ); pWorld->UpdateGraphicsScene(); } }