GroveEngine/src/ModuleSystemFactory.cpp
StillHammer fad105afb2 feat: Implement complete IDataNode/IDataTree system with JSON backend
Major feature: Unified config/data/runtime tree system

**New System Architecture:**
- Unified data tree for config, persistent data, and runtime state
- Three separate roots: config/ (read-only + hot-reload), data/ (read-write + save), runtime/ (temporary)
- Support for modding, saves, and hot-reload in single system

**Interfaces:**
- IDataValue: Abstract data value interface (type-safe access)
- IDataNode: Tree node with navigation, search, and modification
- IDataTree: Root container with config/data/runtime management

**Concrete Implementations:**
- JsonDataValue: nlohmann::json backed value
- JsonDataNode: Full tree navigation with pattern matching & queries
- JsonDataTree: File-based JSON storage with hot-reload

**Features:**
- Pattern matching search (wildcards support)
- Property-based queries with predicates
- SHA256 hashing for validation/sync
- Hot-reload for config/ directory
- Save operations for data/ persistence
- Read-only enforcement for config/

**API Changes:**
- All namespaces changed from 'warfactory' to 'grove'
- IDataTree: Added getConfigRoot(), getDataRoot(), getRuntimeRoot()
- IDataTree: Added saveData(), saveNode() for persistence
- IDataNode: Added setChild(), removeChild(), clearChildren()
- CMakeLists.txt: Added OpenSSL dependency for hashing

**Usage:**
```cpp
auto tree = DataTreeFactory::create("json", "./gamedata");
auto config = tree->getConfigRoot();     // Read-only game config
auto data = tree->getDataRoot();         // Player saves
auto runtime = tree->getRuntimeRoot();   // Temporary state

// Hot-reload config on file changes
if (tree->reloadIfChanged()) { /* refresh modules */ }

// Save player progress
data->setChild("progress", progressNode);
tree->saveData();
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 15:36:25 +08:00

239 lines
9.2 KiB
C++

#include <grove/ModuleSystemFactory.h>
#include <algorithm>
#include <thread>
#include <spdlog/sinks/stdout_color_sinks.h>
// Include implemented systems
#include <grove/SequentialModuleSystem.h>
// Forward declarations for future implementations
// #include "ThreadedModuleSystem.h"
// #include "ThreadPoolModuleSystem.h"
// #include "ClusterModuleSystem.h"
namespace grove {
std::unique_ptr<IModuleSystem> ModuleSystemFactory::create(const std::string& strategy) {
auto logger = getFactoryLogger();
logger->info("⚙️ ModuleSystemFactory: Creating strategy '{}'", strategy);
ModuleSystemType type = parseStrategy(strategy);
return create(type);
}
std::unique_ptr<IModuleSystem> ModuleSystemFactory::create(ModuleSystemType systemType) {
auto logger = getFactoryLogger();
std::string typeStr = strategyToString(systemType);
logger->info("⚙️ ModuleSystemFactory: Creating enum type '{}'", typeStr);
std::unique_ptr<IModuleSystem> moduleSystem;
switch (systemType) {
case ModuleSystemType::SEQUENTIAL:
logger->debug("🔧 Creating SequentialModuleSystem instance");
moduleSystem = std::make_unique<SequentialModuleSystem>();
logger->info("✅ SequentialModuleSystem created successfully");
break;
case ModuleSystemType::THREADED:
logger->debug("🔧 Creating ThreadedModuleSystem instance");
// TODO: Implement ThreadedModuleSystem
// moduleSystem = std::make_unique<ThreadedModuleSystem>();
logger->error("❌ ThreadedModuleSystem not yet implemented");
throw std::invalid_argument("ThreadedModuleSystem not yet implemented");
case ModuleSystemType::THREAD_POOL:
logger->debug("🔧 Creating ThreadPoolModuleSystem instance");
// TODO: Implement ThreadPoolModuleSystem
// moduleSystem = std::make_unique<ThreadPoolModuleSystem>();
logger->error("❌ ThreadPoolModuleSystem not yet implemented");
throw std::invalid_argument("ThreadPoolModuleSystem not yet implemented");
case ModuleSystemType::CLUSTER:
logger->debug("🔧 Creating ClusterModuleSystem instance");
// TODO: Implement ClusterModuleSystem
// moduleSystem = std::make_unique<ClusterModuleSystem>();
logger->error("❌ ClusterModuleSystem not yet implemented");
throw std::invalid_argument("ClusterModuleSystem not yet implemented");
default:
logger->error("❌ Unknown ModuleSystemType enum value: {}", static_cast<int>(systemType));
throw std::invalid_argument("Unknown ModuleSystemType enum value: " + std::to_string(static_cast<int>(systemType)));
}
logger->debug("🎯 ModuleSystem type verification: created system reports type '{}'",
strategyToString(moduleSystem->getType()));
return moduleSystem;
}
std::unique_ptr<IModuleSystem> ModuleSystemFactory::createFromConfig(const json& config) {
auto logger = getFactoryLogger();
logger->info("⚙️ ModuleSystemFactory: Creating from config");
logger->trace("📄 Config: {}", config.dump());
try {
if (!config.contains("strategy")) {
logger->error("❌ Config missing 'strategy' field");
throw std::invalid_argument("ModuleSystem config missing 'strategy' field");
}
std::string strategy = config["strategy"];
logger->info("📋 Config specifies strategy: '{}'", strategy);
// Create base ModuleSystem
auto moduleSystem = create(strategy);
// Apply additional configuration based on strategy type
auto systemType = moduleSystem->getType();
if (systemType == ModuleSystemType::THREAD_POOL) {
if (config.contains("thread_count")) {
int threadCount = config["thread_count"];
logger->info("🔧 Thread pool config: {} threads", threadCount);
// TODO: Apply thread count when ThreadPoolModuleSystem is implemented
}
if (config.contains("queue_size")) {
int queueSize = config["queue_size"];
logger->info("🔧 Thread pool config: queue size {}", queueSize);
// TODO: Apply queue size when ThreadPoolModuleSystem is implemented
}
}
if (config.contains("priority")) {
std::string priority = config["priority"];
logger->info("🔧 ModuleSystem priority: {}", priority);
// TODO: Apply priority settings when implementations support it
}
logger->info("✅ ModuleSystem created from config successfully");
return moduleSystem;
} catch (const json::exception& e) {
logger->error("❌ JSON parsing error in config: {}", e.what());
throw std::invalid_argument("Invalid JSON in ModuleSystem config: " + std::string(e.what()));
} catch (const std::exception& e) {
logger->error("❌ Error creating ModuleSystem from config: {}", e.what());
throw;
}
}
std::vector<std::string> ModuleSystemFactory::getAvailableStrategies() {
return {
"sequential",
"threaded",
"thread_pool",
"cluster"
};
}
bool ModuleSystemFactory::isStrategySupported(const std::string& strategy) {
try {
parseStrategy(strategy);
return true;
} catch (const std::invalid_argument&) {
return false;
}
}
ModuleSystemType ModuleSystemFactory::parseStrategy(const std::string& strategyStr) {
auto logger = getFactoryLogger();
std::string lowerStrategy = toLowercase(strategyStr);
logger->trace("🔍 Parsing strategy: '{}' -> '{}'", strategyStr, lowerStrategy);
if (lowerStrategy == "sequential") {
return ModuleSystemType::SEQUENTIAL;
} else if (lowerStrategy == "threaded") {
return ModuleSystemType::THREADED;
} else if (lowerStrategy == "thread_pool" || lowerStrategy == "threadpool" || lowerStrategy == "thread-pool") {
return ModuleSystemType::THREAD_POOL;
} else if (lowerStrategy == "cluster") {
return ModuleSystemType::CLUSTER;
} else {
logger->error("❌ Unknown strategy: '{}'", strategyStr);
auto availableStrategies = getAvailableStrategies();
std::string availableStr = "[";
for (size_t i = 0; i < availableStrategies.size(); ++i) {
availableStr += availableStrategies[i];
if (i < availableStrategies.size() - 1) availableStr += ", ";
}
availableStr += "]";
throw std::invalid_argument("Unknown strategy '" + strategyStr + "'. Available strategies: " + availableStr);
}
}
std::string ModuleSystemFactory::strategyToString(ModuleSystemType systemType) {
switch (systemType) {
case ModuleSystemType::SEQUENTIAL:
return "sequential";
case ModuleSystemType::THREADED:
return "threaded";
case ModuleSystemType::THREAD_POOL:
return "thread_pool";
case ModuleSystemType::CLUSTER:
return "cluster";
default:
return "unknown";
}
}
ModuleSystemType ModuleSystemFactory::getRecommendedStrategy(int targetFPS, int moduleCount, int cpuCores) {
auto logger = getFactoryLogger();
if (cpuCores == 0) {
cpuCores = detectCpuCores();
}
logger->debug("🎯 Recommending strategy for: {}fps, {} modules, {} cores",
targetFPS, moduleCount, cpuCores);
// Simple recommendation logic
if (moduleCount <= 1) {
logger->debug("💡 Single module -> SEQUENTIAL");
return ModuleSystemType::SEQUENTIAL;
} else if (moduleCount <= cpuCores && targetFPS <= 30) {
logger->debug("💡 Few modules, low FPS -> THREADED");
return ModuleSystemType::THREADED;
} else if (targetFPS > 30 || moduleCount > cpuCores) {
logger->debug("💡 High performance needs -> THREAD_POOL");
return ModuleSystemType::THREAD_POOL;
} else {
logger->debug("💡 Default fallback -> SEQUENTIAL");
return ModuleSystemType::SEQUENTIAL;
}
}
// Private helper methods
std::shared_ptr<spdlog::logger> ModuleSystemFactory::getFactoryLogger() {
static std::shared_ptr<spdlog::logger> logger = nullptr;
if (!logger) {
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_level(spdlog::level::debug);
logger = std::make_shared<spdlog::logger>("ModuleSystemFactory", console_sink);
logger->set_level(spdlog::level::debug);
logger->flush_on(spdlog::level::debug);
spdlog::register_logger(logger);
}
return logger;
}
std::string ModuleSystemFactory::toLowercase(const std::string& str) {
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(),
[](char c) { return std::tolower(c); });
return result;
}
int ModuleSystemFactory::detectCpuCores() {
int cores = std::thread::hardware_concurrency();
if (cores == 0) cores = 4; // Fallback
return cores;
}
} // namespace grove