mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-24 21:55:09 +00:00
386 lines
18 KiB
C++
386 lines
18 KiB
C++
#include "service_based_app.hpp"
|
|
#include "events/event_bus.hpp"
|
|
#include "events/i_event_bus.hpp"
|
|
#include "services/interfaces/i_window_service.hpp"
|
|
#include "services/interfaces/i_graphics_service.hpp"
|
|
#include "services/interfaces/i_application_loop_service.hpp"
|
|
#include "services/interfaces/i_lifecycle_service.hpp"
|
|
#include "services/impl/json_config_service.hpp"
|
|
#include "services/impl/lifecycle_service.hpp"
|
|
#include "services/impl/application_loop_service.hpp"
|
|
#include "services/impl/render_coordinator_service.hpp"
|
|
#include "services/impl/platform_service.hpp"
|
|
#include "services/impl/sdl_window_service.hpp"
|
|
#include "services/impl/sdl_input_service.hpp"
|
|
#include "services/impl/vulkan_device_service.hpp"
|
|
#include "services/impl/swapchain_service.hpp"
|
|
#include "services/impl/pipeline_service.hpp"
|
|
#include "services/impl/buffer_service.hpp"
|
|
#include "services/impl/render_command_service.hpp"
|
|
#include "services/impl/graphics_service.hpp"
|
|
#include "services/impl/vulkan_graphics_backend.hpp"
|
|
#include "services/impl/script_engine_service.hpp"
|
|
#include "services/impl/scene_script_service.hpp"
|
|
#include "services/impl/shader_script_service.hpp"
|
|
#include "services/impl/render_graph_script_service.hpp"
|
|
#include "services/impl/gui_script_service.hpp"
|
|
#include "services/impl/audio_command_service.hpp"
|
|
#include "services/impl/physics_bridge_service.hpp"
|
|
#include "services/impl/mesh_service.hpp"
|
|
#include "services/impl/scene_service.hpp"
|
|
#include "services/impl/gui_renderer_service.hpp"
|
|
#include "services/impl/sdl_audio_service.hpp"
|
|
#include "services/impl/vulkan_gui_service.hpp"
|
|
#include "services/impl/bullet_physics_service.hpp"
|
|
#include "services/impl/crash_recovery_service.hpp"
|
|
#include "services/impl/logger_service.hpp"
|
|
#include "services/interfaces/i_platform_service.hpp"
|
|
#include <iostream>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
|
|
namespace sdl3cpp::app {
|
|
|
|
ServiceBasedApp::ServiceBasedApp(services::RuntimeConfig runtimeConfig, services::LogLevel logLevel)
|
|
: runtimeConfig_(std::move(runtimeConfig)) {
|
|
// Register logger service first
|
|
registry_.RegisterService<services::ILogger, services::impl::LoggerService>();
|
|
logger_ = registry_.GetService<services::ILogger>();
|
|
if (logger_) {
|
|
logger_->SetLevel(logLevel);
|
|
}
|
|
|
|
logger_->Trace("ServiceBasedApp", "ServiceBasedApp", "scriptPath=" + runtimeConfig_.scriptPath.string(), "constructor starting");
|
|
|
|
try {
|
|
logger_->Info("ServiceBasedApp::ServiceBasedApp: Setting up SDL");
|
|
SetupSDL();
|
|
logger_->Info("ServiceBasedApp::ServiceBasedApp: Registering services");
|
|
RegisterServices();
|
|
|
|
// Get and initialize crash recovery service
|
|
crashRecoveryService_ = registry_.GetService<services::ICrashRecoveryService>();
|
|
if (crashRecoveryService_) {
|
|
crashRecoveryService_->Initialize();
|
|
}
|
|
|
|
logger_->Info("ServiceBasedApp::ServiceBasedApp: Resolving lifecycle services");
|
|
|
|
lifecycleService_ = registry_.GetService<services::ILifecycleService>();
|
|
applicationLoopService_ = registry_.GetService<services::IApplicationLoopService>();
|
|
renderCoordinatorService_ = registry_.GetService<services::IRenderCoordinatorService>();
|
|
|
|
logger_->Info("ServiceBasedApp::ServiceBasedApp: constructor completed");
|
|
} catch (const std::exception& e) {
|
|
if (logger_) {
|
|
logger_->Error("ServiceBasedApp::ServiceBasedApp: Failed to initialize ServiceBasedApp: " + std::string(e.what()));
|
|
} else {
|
|
// Fallback to console if logger not available
|
|
std::cerr << "ServiceBasedApp::ServiceBasedApp: Failed to initialize ServiceBasedApp: " << e.what() << std::endl;
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
|
|
ServiceBasedApp::~ServiceBasedApp() {
|
|
logger_->Trace("ServiceBasedApp", "~ServiceBasedApp", "", "Entering");
|
|
|
|
// Shutdown crash recovery service
|
|
if (crashRecoveryService_) {
|
|
crashRecoveryService_->Shutdown();
|
|
}
|
|
|
|
renderCoordinatorService_.reset();
|
|
applicationLoopService_.reset();
|
|
lifecycleService_.reset();
|
|
|
|
logger_->Trace("ServiceBasedApp", "~ServiceBasedApp", "", "Exiting");
|
|
}
|
|
|
|
void ServiceBasedApp::Run() {
|
|
logger_->Trace("ServiceBasedApp", "Run", "", "Entering");
|
|
|
|
try {
|
|
// Initialize all services
|
|
lifecycleService_->InitializeAll();
|
|
|
|
// Create the window
|
|
auto windowService = registry_.GetService<services::IWindowService>();
|
|
auto configService = registry_.GetService<services::IConfigService>();
|
|
if (windowService) {
|
|
services::WindowConfig config;
|
|
if (configService) {
|
|
config.width = configService->GetWindowWidth();
|
|
config.height = configService->GetWindowHeight();
|
|
config.title = configService->GetWindowTitle();
|
|
config.mouseGrab = configService->GetMouseGrabConfig();
|
|
} else {
|
|
config.width = runtimeConfig_.width;
|
|
config.height = runtimeConfig_.height;
|
|
config.title = runtimeConfig_.windowTitle;
|
|
config.mouseGrab = runtimeConfig_.mouseGrab;
|
|
}
|
|
config.resizable = true;
|
|
windowService->CreateWindow(config);
|
|
}
|
|
|
|
// Initialize graphics after window is created
|
|
auto graphicsService = registry_.GetService<services::IGraphicsService>();
|
|
if (graphicsService && windowService) {
|
|
services::GraphicsConfig graphicsConfig;
|
|
if (configService) {
|
|
graphicsConfig.deviceExtensions = configService->GetDeviceExtensions();
|
|
} else {
|
|
graphicsConfig.deviceExtensions = {"VK_KHR_swapchain"};
|
|
}
|
|
graphicsConfig.enableValidationLayers = false;
|
|
graphicsService->InitializeDevice(windowService->GetNativeHandle(), graphicsConfig);
|
|
graphicsService->InitializeSwapchain();
|
|
}
|
|
|
|
// Initialize GUI service after graphics
|
|
auto guiService = registry_.GetService<services::IGuiService>();
|
|
auto vulkanDeviceService = registry_.GetService<services::IVulkanDeviceService>();
|
|
auto swapchainService = registry_.GetService<services::ISwapchainService>();
|
|
if (guiService && vulkanDeviceService && swapchainService) {
|
|
guiService->Initialize(vulkanDeviceService->GetDevice(),
|
|
vulkanDeviceService->GetPhysicalDevice(),
|
|
swapchainService->GetSwapchainImageFormat(),
|
|
swapchainService->GetRenderPass(),
|
|
runtimeConfig_.scriptPath.parent_path());
|
|
}
|
|
|
|
// Run the main application loop with crash recovery
|
|
if (crashRecoveryService_) {
|
|
bool success = crashRecoveryService_->ExecuteWithTimeout(
|
|
[this]() { applicationLoopService_->Run(); },
|
|
30000, // 30 second timeout for the main loop
|
|
"Main Application Loop"
|
|
);
|
|
|
|
if (!success) {
|
|
logger_->Warn("ServiceBasedApp::Run: Main loop timed out, attempting recovery");
|
|
if (crashRecoveryService_->AttemptRecovery()) {
|
|
logger_->Info("ServiceBasedApp::Run: Recovery successful, restarting main loop");
|
|
applicationLoopService_->Run(); // Try again
|
|
}
|
|
}
|
|
} else {
|
|
// Fallback if no crash recovery service
|
|
applicationLoopService_->Run();
|
|
}
|
|
|
|
// Shutdown all services
|
|
lifecycleService_->ShutdownAll();
|
|
|
|
logger_->Trace("ServiceBasedApp", "Run", "", "Exiting");
|
|
|
|
} catch (const std::exception& e) {
|
|
logger_->Error("ServiceBasedApp::Run: Application error: " + std::string(e.what()));
|
|
|
|
// Attempt recovery on exception
|
|
if (crashRecoveryService_ && crashRecoveryService_->AttemptRecovery()) {
|
|
logger_->Info("ServiceBasedApp::Run: Recovered from exception");
|
|
} else {
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ServiceBasedApp::ConfigureLogging(services::LogLevel level, bool enableConsole, const std::string& outputFile) {
|
|
if (logger_) {
|
|
logger_->SetLevel(level);
|
|
logger_->EnableConsoleOutput(enableConsole);
|
|
if (!outputFile.empty()) {
|
|
logger_->SetOutputFile(outputFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ServiceBasedApp::SetupSDL() {
|
|
logger_->Trace("ServiceBasedApp", "SetupSDL", "", "Entering");
|
|
|
|
// SDL initialization is handled by the window service
|
|
// Don't initialize SDL here to avoid double initialization
|
|
|
|
logger_->Trace("ServiceBasedApp", "SetupSDL", "", "Exiting");
|
|
}
|
|
|
|
void ServiceBasedApp::RegisterServices() {
|
|
logger_->Trace("ServiceBasedApp", "RegisterServices", "", "Entering");
|
|
|
|
// Logger service already registered in constructor
|
|
|
|
// Crash recovery service (needed early for crash detection)
|
|
registry_.RegisterService<services::ICrashRecoveryService, services::impl::CrashRecoveryService>(
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Lifecycle service
|
|
registry_.RegisterService<services::ILifecycleService, services::impl::LifecycleService>(
|
|
registry_,
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Platform service (needed for SDL error enrichment)
|
|
registry_.RegisterService<services::IPlatformService, services::impl::PlatformService>(
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Event bus (needed by window service)
|
|
registry_.RegisterService<events::IEventBus, events::EventBus>();
|
|
|
|
// Configuration service
|
|
registry_.RegisterService<services::IConfigService, services::impl::JsonConfigService>(
|
|
registry_.GetService<services::ILogger>(), runtimeConfig_);
|
|
|
|
// Window service
|
|
registry_.RegisterService<services::IWindowService, services::impl::SdlWindowService>(
|
|
registry_.GetService<services::ILogger>(),
|
|
registry_.GetService<services::IPlatformService>(),
|
|
registry_.GetService<events::IEventBus>());
|
|
|
|
// Input service
|
|
registry_.RegisterService<services::IInputService, services::impl::SdlInputService>(
|
|
registry_.GetService<events::IEventBus>(),
|
|
registry_.GetService<services::IConfigService>(),
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Audio service (needed before script bindings execute)
|
|
registry_.RegisterService<services::IAudioService, services::impl::SdlAudioService>(
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Script bridge services
|
|
registry_.RegisterService<services::IMeshService, services::impl::MeshService>(
|
|
registry_.GetService<services::IConfigService>(),
|
|
registry_.GetService<services::ILogger>());
|
|
registry_.RegisterService<services::IPhysicsBridgeService, services::impl::PhysicsBridgeService>(
|
|
registry_.GetService<services::ILogger>());
|
|
registry_.RegisterService<services::IAudioCommandService, services::impl::AudioCommandService>(
|
|
registry_.GetService<services::IConfigService>(),
|
|
registry_.GetService<services::IAudioService>(),
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Script engine service (shared Lua runtime)
|
|
registry_.RegisterService<services::IScriptEngineService, services::impl::ScriptEngineService>(
|
|
runtimeConfig_.scriptPath,
|
|
registry_.GetService<services::ILogger>(),
|
|
registry_.GetService<services::IMeshService>(),
|
|
registry_.GetService<services::IAudioCommandService>(),
|
|
registry_.GetService<services::IPhysicsBridgeService>(),
|
|
registry_.GetService<services::IInputService>(),
|
|
registry_.GetService<services::IWindowService>(),
|
|
registry_.GetService<services::IConfigService>(),
|
|
runtimeConfig_.luaDebug);
|
|
|
|
// Script-facing services
|
|
registry_.RegisterService<services::ISceneScriptService, services::impl::SceneScriptService>(
|
|
registry_.GetService<services::IScriptEngineService>(),
|
|
registry_.GetService<services::ILogger>());
|
|
registry_.RegisterService<services::IShaderScriptService, services::impl::ShaderScriptService>(
|
|
registry_.GetService<services::IScriptEngineService>(),
|
|
registry_.GetService<services::ILogger>());
|
|
registry_.RegisterService<services::IRenderGraphScriptService, services::impl::RenderGraphScriptService>(
|
|
registry_.GetService<services::IScriptEngineService>(),
|
|
registry_.GetService<services::IConfigService>(),
|
|
registry_.GetService<services::ILogger>());
|
|
logger_->Trace("ServiceBasedApp", "RegisterServices",
|
|
"Registered render graph script service");
|
|
registry_.RegisterService<services::IGuiScriptService, services::impl::GuiScriptService>(
|
|
registry_.GetService<services::IScriptEngineService>(),
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Connect input service to GUI script service for GUI input processing
|
|
auto inputService = registry_.GetService<services::IInputService>();
|
|
auto guiScriptService = registry_.GetService<services::IGuiScriptService>();
|
|
if (inputService && guiScriptService) {
|
|
inputService->SetGuiScriptService(guiScriptService.get());
|
|
}
|
|
|
|
// Vulkan device service
|
|
registry_.RegisterService<services::IVulkanDeviceService, services::impl::VulkanDeviceService>(
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Swapchain service
|
|
registry_.RegisterService<services::ISwapchainService, services::impl::SwapchainService>(
|
|
registry_.GetService<services::IVulkanDeviceService>(),
|
|
registry_.GetService<events::IEventBus>(),
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Pipeline service
|
|
registry_.RegisterService<services::IPipelineService, services::impl::PipelineService>(
|
|
registry_.GetService<services::IVulkanDeviceService>(),
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Buffer service
|
|
registry_.RegisterService<services::IBufferService, services::impl::BufferService>(
|
|
registry_.GetService<services::IVulkanDeviceService>(),
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// GUI renderer service (needed by render command service and GUI service)
|
|
registry_.RegisterService<services::IGuiRendererService, services::impl::GuiRendererService>(
|
|
registry_.GetService<services::ILogger>(),
|
|
registry_.GetService<services::IBufferService>());
|
|
logger_->Trace("ServiceBasedApp", "RegisterServices",
|
|
"Registered GUI renderer service before render command service");
|
|
|
|
// Render command service
|
|
registry_.RegisterService<services::IRenderCommandService, services::impl::RenderCommandService>(
|
|
registry_.GetService<services::IVulkanDeviceService>(),
|
|
registry_.GetService<services::ISwapchainService>(),
|
|
registry_.GetService<services::IPipelineService>(),
|
|
registry_.GetService<services::IBufferService>(),
|
|
registry_.GetService<services::IGuiRendererService>(),
|
|
std::static_pointer_cast<services::impl::JsonConfigService>(registry_.GetService<services::IConfigService>()),
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Graphics service (facade)
|
|
registry_.RegisterService<services::IGraphicsService, services::impl::GraphicsService>(
|
|
registry_.GetService<services::ILogger>(),
|
|
std::make_shared<services::impl::VulkanGraphicsBackend>(
|
|
registry_.GetService<services::IVulkanDeviceService>(),
|
|
registry_.GetService<services::ISwapchainService>(),
|
|
registry_.GetService<services::IRenderCommandService>(),
|
|
registry_.GetService<services::IPipelineService>(),
|
|
registry_.GetService<services::IBufferService>(),
|
|
registry_.GetService<services::ILogger>()),
|
|
registry_.GetService<services::IWindowService>());
|
|
|
|
// Scene service
|
|
registry_.RegisterService<services::ISceneService, services::impl::SceneService>(
|
|
registry_.GetService<services::ISceneScriptService>(),
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// GUI service
|
|
registry_.RegisterService<services::IGuiService, services::impl::VulkanGuiService>(
|
|
registry_.GetService<services::ILogger>(),
|
|
registry_.GetService<services::IGuiRendererService>());
|
|
|
|
// Physics service
|
|
registry_.RegisterService<services::IPhysicsService, services::impl::BulletPhysicsService>(
|
|
registry_.GetService<services::ILogger>());
|
|
|
|
// Render coordinator service
|
|
registry_.RegisterService<services::IRenderCoordinatorService, services::impl::RenderCoordinatorService>(
|
|
registry_.GetService<services::ILogger>(),
|
|
registry_.GetService<services::IGraphicsService>(),
|
|
registry_.GetService<services::ISceneScriptService>(),
|
|
registry_.GetService<services::IShaderScriptService>(),
|
|
registry_.GetService<services::IRenderGraphScriptService>(),
|
|
registry_.GetService<services::IGuiScriptService>(),
|
|
registry_.GetService<services::IGuiService>(),
|
|
registry_.GetService<services::ISceneService>());
|
|
|
|
// Application loop service
|
|
registry_.RegisterService<services::IApplicationLoopService, services::impl::ApplicationLoopService>(
|
|
registry_.GetService<services::ILogger>(),
|
|
registry_.GetService<services::IWindowService>(),
|
|
registry_.GetService<events::IEventBus>(),
|
|
registry_.GetService<services::IInputService>(),
|
|
registry_.GetService<services::IPhysicsService>(),
|
|
registry_.GetService<services::ISceneService>(),
|
|
registry_.GetService<services::IRenderCoordinatorService>(),
|
|
registry_.GetService<services::IAudioService>());
|
|
|
|
logger_->Trace("ServiceBasedApp", "RegisterServices", "", "Exiting");
|
|
}
|
|
|
|
} // namespace sdl3cpp::app
|