MetaCore/Source/MetaCoreScene/Private/MetaCoreRuntimeLifecycle.cpp

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