327 lines
9.7 KiB
C++
327 lines
9.7 KiB
C++
#include "MetaCoreScene/MetaCoreRuntimeLifecycle.h"
|
|
|
|
#include <algorithm>
|
|
#include <exception>
|
|
#include <unordered_set>
|
|
|
|
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<MetaCoreRuntimeLifecycleDescriptor>& descriptors
|
|
) {
|
|
std::size_t registeredCount = 0;
|
|
for (const MetaCoreRuntimeLifecycleDescriptor& descriptor : descriptors) {
|
|
if (RegisterDescriptor(descriptor)) {
|
|
++registeredCount;
|
|
}
|
|
}
|
|
return registeredCount;
|
|
}
|
|
|
|
const std::vector<MetaCoreRuntimeLifecycleDescriptor>& 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<MetaCoreId> 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<MetaCoreId>& objectIds,
|
|
ErrorSink errorSink
|
|
) {
|
|
if (!Running_ || objectIds.empty()) {
|
|
return;
|
|
}
|
|
|
|
std::vector<MetaCoreId> affectedObjectIds;
|
|
std::unordered_set<MetaCoreId> deduplicatedObjectIds;
|
|
for (const MetaCoreId objectId : objectIds) {
|
|
if (objectId == 0 || deduplicatedObjectIds.contains(objectId)) {
|
|
continue;
|
|
}
|
|
|
|
const std::vector<MetaCoreId> 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<MetaCoreId> 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<MetaCoreId> 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<MetaCoreRuntimeLifecycleDescriptor>& MetaCoreRuntimeLifecycleRegistry::GetDescriptors() const {
|
|
return Descriptors_;
|
|
}
|
|
|
|
MetaCoreRuntimeLifecycleRegistry& MetaCoreGetRuntimeLifecycleRegistry() {
|
|
static MetaCoreRuntimeLifecycleRegistry registry;
|
|
return registry;
|
|
}
|
|
|
|
} // namespace MetaCore
|