mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-27 15:24:56 +00:00
various changes
This commit is contained in:
@@ -1,119 +1,125 @@
|
||||
#include <atomic>
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <SDL3/SDL_main.h>
|
||||
|
||||
#include "app/service_based_app.hpp"
|
||||
#include "services/impl/app/command_line_service.hpp"
|
||||
#include "services/impl/config/json_config_writer_service.hpp"
|
||||
#include "services/impl/diagnostics/logger_service.hpp"
|
||||
#include "services/impl/platform/platform_service.hpp"
|
||||
#include "services/interfaces/diagnostics/logger_service.hpp"
|
||||
#include "services/interfaces/i_logger.hpp"
|
||||
|
||||
namespace sdl3cpp::app {
|
||||
std::atomic<bool> g_signalReceived{false};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void SignalHandler(int signal) {
|
||||
if (signal == SIGINT || signal == SIGTERM) {
|
||||
sdl3cpp::app::g_signalReceived.store(true);
|
||||
}
|
||||
}
|
||||
|
||||
void SetupSignalHandlers() {
|
||||
std::signal(SIGINT, SignalHandler);
|
||||
std::signal(SIGTERM, SignalHandler);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#include "services/interfaces/workflow/workflow_executor.hpp"
|
||||
#include "services/interfaces/workflow/workflow_step_registry.hpp"
|
||||
#include "services/interfaces/workflow_registrar.hpp"
|
||||
#include "services/interfaces/workflow/workflow_definition_parser.hpp"
|
||||
#include "services/interfaces/workflow/workflow_app_init_step.hpp"
|
||||
#include "services/interfaces/workflow/workflow_load_workflow_step.hpp"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
SDL_SetMainReady();
|
||||
SetupSignalHandlers();
|
||||
|
||||
try {
|
||||
auto startupLogger = std::make_shared<sdl3cpp::services::impl::LoggerService>();
|
||||
auto platformService = std::make_shared<sdl3cpp::services::impl::PlatformService>(startupLogger);
|
||||
sdl3cpp::services::impl::CommandLineService commandLineService(startupLogger, platformService);
|
||||
sdl3cpp::services::CommandLineOptions options = commandLineService.Parse(argc, argv);
|
||||
// Parse command line (inline)
|
||||
std::string gamePackage = "standalone_cubes";
|
||||
std::string bootstrapPackage = "bootstrap_mac";
|
||||
std::filesystem::path projectRoot = std::filesystem::current_path();
|
||||
|
||||
sdl3cpp::services::LogLevel logLevel = options.traceEnabled
|
||||
? sdl3cpp::services::LogLevel::TRACE
|
||||
: sdl3cpp::services::LogLevel::INFO;
|
||||
sdl3cpp::app::ServiceBasedApp app(options.runtimeConfig, logLevel);
|
||||
app.ConfigureLogging(logLevel, true, "sdl3_app.log");
|
||||
|
||||
auto logger = app.GetLogger();
|
||||
if (logger) {
|
||||
logger->Info("Application starting");
|
||||
logger->TraceVariable("config.width", static_cast<int>(options.runtimeConfig.width));
|
||||
logger->TraceVariable("config.height", static_cast<int>(options.runtimeConfig.height));
|
||||
logger->TraceVariable("config.projectRoot", options.runtimeConfig.projectRoot.string());
|
||||
logger->TraceVariable("config.windowTitle", options.runtimeConfig.windowTitle);
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string arg = argv[i];
|
||||
if (arg == "--game" && i + 1 < argc) {
|
||||
gamePackage = argv[++i];
|
||||
} else if (arg == "--bootstrap" && i + 1 < argc) {
|
||||
bootstrapPackage = argv[++i];
|
||||
} else if (arg == "--project-root" && i + 1 < argc) {
|
||||
projectRoot = argv[++i];
|
||||
}
|
||||
}
|
||||
|
||||
if (options.seedOutput || options.saveDefaultJson) {
|
||||
sdl3cpp::services::impl::JsonConfigWriterService configWriter(logger);
|
||||
if (options.seedOutput) {
|
||||
configWriter.WriteConfig(options.runtimeConfig, *options.seedOutput);
|
||||
}
|
||||
if (options.saveDefaultJson) {
|
||||
if (auto configDir = platformService->GetUserConfigDirectory()) {
|
||||
configWriter.WriteConfig(options.runtimeConfig, *configDir / "default_runtime.json");
|
||||
} else {
|
||||
throw std::runtime_error("Unable to determine platform config directory");
|
||||
// Create logger
|
||||
auto logger = std::make_shared<sdl3cpp::services::impl::LoggerService>();
|
||||
logger->EnableConsoleOutput(false);
|
||||
std::filesystem::path logPath = projectRoot / "sdl3_app.log";
|
||||
logger->SetOutputFile(logPath.string());
|
||||
|
||||
// Create workflow infrastructure
|
||||
auto registry = std::make_shared<sdl3cpp::services::impl::WorkflowStepRegistry>();
|
||||
auto registrar = std::make_unique<sdl3cpp::services::impl::WorkflowRegistrar>(logger);
|
||||
registrar->RegisterSteps(registry);
|
||||
|
||||
// Register application lifecycle steps
|
||||
registry->RegisterStep(std::make_shared<sdl3cpp::services::impl::WorkflowAppInitStep>(logger));
|
||||
registry->RegisterStep(std::make_shared<sdl3cpp::services::impl::WorkflowLoadWorkflowStep>(logger));
|
||||
|
||||
auto executor = std::make_shared<sdl3cpp::services::impl::WorkflowExecutor>(registry, logger);
|
||||
|
||||
// Register executor-dependent steps (control.loop.while, workflow.execute)
|
||||
registrar->RegisterExecutorSteps(registry, executor);
|
||||
|
||||
// Create context with CLI arguments
|
||||
sdl3cpp::services::WorkflowContext appContext;
|
||||
appContext.Set("game_package", gamePackage);
|
||||
appContext.Set("bootstrap_package", bootstrapPackage);
|
||||
appContext.Set("project_root", projectRoot.string());
|
||||
appContext.Set("max_frames", 600.0);
|
||||
|
||||
// Load package.json to get defaultWorkflow
|
||||
std::filesystem::path packageJsonPath = projectRoot / "packages" / gamePackage / "package.json";
|
||||
std::string defaultWorkflow = "workflows/main.json"; // fallback
|
||||
|
||||
if (std::filesystem::exists(packageJsonPath)) {
|
||||
std::ifstream packageFile(packageJsonPath);
|
||||
if (packageFile.is_open()) {
|
||||
try {
|
||||
nlohmann::json packageJson;
|
||||
packageFile >> packageJson;
|
||||
if (packageJson.contains("defaultWorkflow")) {
|
||||
defaultWorkflow = packageJson["defaultWorkflow"].get<std::string>();
|
||||
logger->Info("Loaded package.json, defaultWorkflow: " + defaultWorkflow);
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
logger->Warn("Failed to parse package.json: " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app.Run();
|
||||
} catch (const std::runtime_error& e) {
|
||||
std::string errorMsg = e.what();
|
||||
// For early errors before app is created, we can't use service logger
|
||||
// Fall back to console output
|
||||
std::cerr << "Runtime error: " << errorMsg << std::endl;
|
||||
|
||||
// Check if this is a timeout/hang error - show simpler message for these
|
||||
bool isTimeoutError = errorMsg.find("timeout") != std::string::npos ||
|
||||
errorMsg.find("Launch timeout") != std::string::npos ||
|
||||
errorMsg.find("Swapchain recreation loop") != std::string::npos;
|
||||
|
||||
if (!isTimeoutError) {
|
||||
// For non-timeout errors, show full error dialog
|
||||
SDL_ShowSimpleMessageBox(
|
||||
SDL_MESSAGEBOX_ERROR,
|
||||
"Application Error",
|
||||
errorMsg.c_str(),
|
||||
nullptr);
|
||||
} else {
|
||||
// For timeout errors, the console output already has diagnostic info
|
||||
// Just show a brief dialog
|
||||
std::string briefMsg = "Application failed to launch. Check console output for details.";
|
||||
SDL_ShowSimpleMessageBox(
|
||||
SDL_MESSAGEBOX_ERROR,
|
||||
"Launch Failed",
|
||||
briefMsg.c_str(),
|
||||
nullptr);
|
||||
// Load and execute the default workflow
|
||||
std::filesystem::path mainWorkflowPath = projectRoot / "packages" / gamePackage / defaultWorkflow;
|
||||
if (!std::filesystem::exists(mainWorkflowPath)) {
|
||||
logger->Error("Workflow not found: " + mainWorkflowPath.string());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
|
||||
logger->Info("Loading workflow: " + mainWorkflowPath.string());
|
||||
sdl3cpp::services::impl::WorkflowDefinitionParser parser(logger);
|
||||
auto mainWorkflow = parser.ParseFile(mainWorkflowPath);
|
||||
|
||||
// Load workflow variables into context
|
||||
for (const auto& [name, var] : mainWorkflow.variables) {
|
||||
if (var.defaultValue.empty()) continue;
|
||||
if (var.type == "number") {
|
||||
try {
|
||||
appContext.Set(name, std::stod(var.defaultValue));
|
||||
} catch (...) {}
|
||||
} else if (var.type == "string") {
|
||||
appContext.Set(name, var.defaultValue);
|
||||
} else if (var.type == "bool") {
|
||||
appContext.Set(name, var.defaultValue == "true");
|
||||
} else {
|
||||
appContext.Set(name, var.defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
logger->Info("Executing main workflow (" + std::to_string(mainWorkflow.steps.size()) + " steps)");
|
||||
executor->Execute(mainWorkflow, appContext);
|
||||
|
||||
logger->Info("===== APPLICATION COMPLETE =====");
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
// For early errors before app is created, we can't use service logger
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
SDL_ShowSimpleMessageBox(
|
||||
SDL_MESSAGEBOX_ERROR,
|
||||
"Application Error",
|
||||
e.what(),
|
||||
nullptr);
|
||||
std::cerr << "Fatal error: " << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user