// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. #include "EngineService.h" #include "Engine/Core/Log.h" #include "Engine/Core/Collections/Array.h" #include "Engine/Core/Collections/Sorting.h" #include static bool CompareEngineServices(EngineService* const& a, EngineService* const& b) { return a->Order < b->Order; } #define DEFINE_ENGINE_SERVICE_EVENT(name) \ void EngineService::name() { } \ void EngineService::On##name() \ { \ ZoneScoped; \ auto& services = GetServices(); \ for (int32 i = 0; i < services.Count(); i++) \ services[i]->name(); \ } #define DEFINE_ENGINE_SERVICE_EVENT_INVERTED(name) \ void EngineService::name() { } \ void EngineService::On##name() \ { \ ZoneScoped; \ auto& services = GetServices(); \ for (int32 i = 0; i < services.Count(); i++) \ services[i]->name(); \ } DEFINE_ENGINE_SERVICE_EVENT(FixedUpdate); DEFINE_ENGINE_SERVICE_EVENT(Update); DEFINE_ENGINE_SERVICE_EVENT(LateUpdate); DEFINE_ENGINE_SERVICE_EVENT(LateFixedUpdate); DEFINE_ENGINE_SERVICE_EVENT(Draw); DEFINE_ENGINE_SERVICE_EVENT_INVERTED(BeforeExit); EngineService::EngineServicesArray& EngineService::GetServices() { static EngineServicesArray Services; return Services; } void EngineService::Sort() { auto& services = GetServices(); Sorting::QuickSort(services.Get(), services.Count(), &CompareEngineServices); } EngineService::EngineService(const Char* name, int32 order) { Name = name; Order = order; auto& services = GetServices(); services.Add(this); if (services.First()->IsInitialized) Sort(); } bool EngineService::Init() { return false; } void EngineService::OnInit() { ZoneScoped; Sort(); // Init services from front to back auto& services = GetServices(); for (int32 i = 0; i < services.Count(); i++) { const auto service = services[i]; const StringView name(service->Name); #if TRACY_ENABLE ZoneScoped; int32 nameBufferLength = 0; Char nameBuffer[100]; for (int32 j = 0; j < name.Length(); j++) if (name[j] != ' ') nameBuffer[nameBufferLength++] = name[j]; Platform::MemoryCopy(nameBuffer + nameBufferLength, TEXT("::Init"), 7 * sizeof(Char)); nameBufferLength += 7; ZoneName(nameBuffer, nameBufferLength); #endif LOG(Info, "Initialize {0}...", name); service->IsInitialized = true; if (service->Init()) { Platform::Fatal(String::Format(TEXT("Failed to initialize {0}."), name)); } } LOG(Info, "Engine services are ready!"); } void EngineService::Dispose() { } void EngineService::OnDispose() { ZoneScoped; // Dispose services from back to front auto& services = GetServices(); for (int32 i = services.Count() - 1; i >= 0; i--) { const auto service = services[i]; if (service->IsInitialized) { #if TRACY_ENABLE ZoneScoped; const StringView name(service->Name); int32 nameBufferLength = 0; Char nameBuffer[100]; for (int32 j = 0; j < name.Length(); j++) if (name[j] != ' ') nameBuffer[nameBufferLength++] = name[j]; Platform::MemoryCopy(nameBuffer + nameBufferLength, TEXT("::Dispose"), 10 * sizeof(Char)); nameBufferLength += 10; ZoneName(nameBuffer, nameBufferLength); #endif service->IsInitialized = false; service->Dispose(); } } }