#include "MetaCoreScene/MetaCoreRuntimeLifecycle.h" #include #include #include namespace MetaCore { void MetaCoreRuntimeLifecycleExecutor::ClearDescriptors() { Descriptors_.clear(); StartedComponents_.clear(); Running_ = false; ElapsedTimeSeconds_ = 0.0F; } bool MetaCoreRuntimeLifecycleExecutor::RegisterDescriptor(MetaCoreRuntimeLifecycleDescriptor descriptor) { if (descriptor.TypeId.empty() || !descriptor.HasComponent) { return false; } const auto iterator = std::find_if( Descriptors_.begin(), Descriptors_.end(), [&](const MetaCoreRuntimeLifecycleDescriptor& registeredDescriptor) { return registeredDescriptor.TypeId == descriptor.TypeId; } ); if (iterator != Descriptors_.end()) { return false; } Descriptors_.push_back(std::move(descriptor)); return true; } std::size_t MetaCoreRuntimeLifecycleExecutor::RegisterDescriptors( const std::vector& descriptors ) { std::size_t registeredCount = 0; for (const MetaCoreRuntimeLifecycleDescriptor& descriptor : descriptors) { if (RegisterDescriptor(descriptor)) { ++registeredCount; } } return registeredCount; } const std::vector& MetaCoreRuntimeLifecycleExecutor::GetDescriptors() const { return Descriptors_; } void MetaCoreRuntimeLifecycleExecutor::EnterScene(MetaCoreScene& scene, ErrorSink errorSink) { StartedComponents_.clear(); ElapsedTimeSeconds_ = 0.0F; Running_ = true; InvokeStartForNewComponents(scene, errorSink); } void MetaCoreRuntimeLifecycleExecutor::TickScene(MetaCoreScene& scene, float deltaSeconds, ErrorSink errorSink) { if (!Running_) { return; } const float sanitizedDeltaSeconds = std::max(deltaSeconds, 0.0F); InvokeStartForNewComponents(scene, errorSink); const std::vector objectIds = scene.BuildHierarchyPreorder(); for (const MetaCoreRuntimeLifecycleDescriptor& descriptor : Descriptors_) { if (!descriptor.OnUpdate) { continue; } for (const MetaCoreId objectId : objectIds) { MetaCoreGameObject gameObject = scene.FindGameObject(objectId); if (!gameObject || !descriptor.HasComponent(gameObject)) { continue; } const std::string key = BuildLifecycleKey(objectId, descriptor.TypeId); if (!StartedComponents_.contains(key)) { continue; } try { descriptor.OnUpdate(scene, gameObject, sanitizedDeltaSeconds); } catch (const std::exception& exception) { ReportException(errorSink, "OnUpdate", descriptor, objectId, exception); } catch (...) { ReportUnknownException(errorSink, "OnUpdate", descriptor, objectId); } } } ElapsedTimeSeconds_ += sanitizedDeltaSeconds; } void MetaCoreRuntimeLifecycleExecutor::NotifyGameObjectsWillBeDestroyed( MetaCoreScene& scene, const std::vector& objectIds, ErrorSink errorSink ) { if (!Running_ || objectIds.empty()) { return; } std::vector affectedObjectIds; std::unordered_set deduplicatedObjectIds; for (const MetaCoreId objectId : objectIds) { if (objectId == 0 || deduplicatedObjectIds.contains(objectId)) { continue; } const std::vector subtreeObjectIds = scene.GetSubtreeObjectIds(objectId); if (subtreeObjectIds.empty()) { continue; } for (const MetaCoreId subtreeObjectId : subtreeObjectIds) { if (deduplicatedObjectIds.insert(subtreeObjectId).second) { affectedObjectIds.push_back(subtreeObjectId); } } } for (const MetaCoreId objectId : affectedObjectIds) { for (const MetaCoreRuntimeLifecycleDescriptor& descriptor : Descriptors_) { (void)InvokeDestroyForStartedComponent(scene, descriptor, objectId, errorSink); } } } void MetaCoreRuntimeLifecycleExecutor::NotifyComponentWillBeRemoved( MetaCoreScene& scene, MetaCoreId objectId, std::string_view componentTypeId, ErrorSink errorSink ) { if (!Running_ || objectId == 0 || componentTypeId.empty()) { return; } const auto iterator = std::find_if( Descriptors_.begin(), Descriptors_.end(), [&](const MetaCoreRuntimeLifecycleDescriptor& descriptor) { return descriptor.TypeId == componentTypeId; } ); if (iterator == Descriptors_.end()) { return; } (void)InvokeDestroyForStartedComponent(scene, *iterator, objectId, errorSink); } void MetaCoreRuntimeLifecycleExecutor::ExitScene(MetaCoreScene& scene, ErrorSink errorSink) { if (!Running_) { return; } const std::vector objectIds = scene.BuildHierarchyPreorder(); for (const MetaCoreRuntimeLifecycleDescriptor& descriptor : Descriptors_) { for (const MetaCoreId objectId : objectIds) { (void)InvokeDestroyForStartedComponent(scene, descriptor, objectId, errorSink); } } StartedComponents_.clear(); Running_ = false; ElapsedTimeSeconds_ = 0.0F; } bool MetaCoreRuntimeLifecycleExecutor::IsRunning() const { return Running_; } float MetaCoreRuntimeLifecycleExecutor::GetElapsedTimeSeconds() const { return ElapsedTimeSeconds_; } std::string MetaCoreRuntimeLifecycleExecutor::BuildLifecycleKey( MetaCoreId objectId, std::string_view componentTypeId ) const { return std::to_string(objectId) + ":" + std::string(componentTypeId); } void MetaCoreRuntimeLifecycleExecutor::InvokeStartForNewComponents( MetaCoreScene& scene, const ErrorSink& errorSink ) { const std::vector objectIds = scene.BuildHierarchyPreorder(); for (const MetaCoreRuntimeLifecycleDescriptor& descriptor : Descriptors_) { for (const MetaCoreId objectId : objectIds) { MetaCoreGameObject gameObject = scene.FindGameObject(objectId); if (!gameObject || !descriptor.HasComponent(gameObject)) { continue; } const std::string key = BuildLifecycleKey(objectId, descriptor.TypeId); if (StartedComponents_.contains(key)) { continue; } StartedComponents_.insert(key); if (!descriptor.OnStart) { continue; } try { descriptor.OnStart(scene, gameObject); } catch (const std::exception& exception) { ReportException(errorSink, "OnStart", descriptor, objectId, exception); } catch (...) { ReportUnknownException(errorSink, "OnStart", descriptor, objectId); } } } } bool MetaCoreRuntimeLifecycleExecutor::InvokeDestroyForStartedComponent( MetaCoreScene& scene, const MetaCoreRuntimeLifecycleDescriptor& descriptor, MetaCoreId objectId, const ErrorSink& errorSink ) { if (descriptor.TypeId.empty() || objectId == 0) { return false; } const std::string key = BuildLifecycleKey(objectId, descriptor.TypeId); if (!StartedComponents_.contains(key)) { return false; } MetaCoreGameObject gameObject = scene.FindGameObject(objectId); if (!gameObject || !descriptor.HasComponent(gameObject)) { StartedComponents_.erase(key); return false; } if (descriptor.OnDestroy) { try { descriptor.OnDestroy(scene, gameObject); } catch (const std::exception& exception) { ReportException(errorSink, "OnDestroy", descriptor, objectId, exception); } catch (...) { ReportUnknownException(errorSink, "OnDestroy", descriptor, objectId); } } StartedComponents_.erase(key); return true; } void MetaCoreRuntimeLifecycleExecutor::ReportException( const ErrorSink& errorSink, std::string_view phase, const MetaCoreRuntimeLifecycleDescriptor& descriptor, MetaCoreId objectId, const std::exception& exception ) const { if (!errorSink) { return; } errorSink(MetaCoreRuntimeLifecycleError{ std::string(phase), descriptor.TypeId, objectId, exception.what() }); } void MetaCoreRuntimeLifecycleExecutor::ReportUnknownException( const ErrorSink& errorSink, std::string_view phase, const MetaCoreRuntimeLifecycleDescriptor& descriptor, MetaCoreId objectId ) const { if (!errorSink) { return; } errorSink(MetaCoreRuntimeLifecycleError{ std::string(phase), descriptor.TypeId, objectId, "unknown exception" }); } void MetaCoreRuntimeLifecycleRegistry::Clear() { Descriptors_.clear(); } bool MetaCoreRuntimeLifecycleRegistry::RegisterDescriptor(MetaCoreRuntimeLifecycleDescriptor descriptor) { if (descriptor.TypeId.empty() || !descriptor.HasComponent) { return false; } const auto iterator = std::find_if( Descriptors_.begin(), Descriptors_.end(), [&](const MetaCoreRuntimeLifecycleDescriptor& registeredDescriptor) { return registeredDescriptor.TypeId == descriptor.TypeId; } ); if (iterator != Descriptors_.end()) { return false; } Descriptors_.push_back(std::move(descriptor)); return true; } const std::vector& MetaCoreRuntimeLifecycleRegistry::GetDescriptors() const { return Descriptors_; } MetaCoreRuntimeLifecycleRegistry& MetaCoreGetRuntimeLifecycleRegistry() { static MetaCoreRuntimeLifecycleRegistry registry; return registry; } } // namespace MetaCore