Refactor: Replace JSON with IDataNode abstraction in all interfaces
Major architectural improvement to decouple interfaces from JSON implementation: **New Abstractions:** - Created IDataValue interface for type-safe data access - All interfaces now use IDataNode instead of nlohmann::json - Enables future backend flexibility (JSON, MessagePack, etc.) **Updated Interfaces:** - ISerializable: serialize() returns IDataNode, deserialize() takes IDataNode - IModule: process(), getState(), setState(), getHealthStatus() use IDataNode - IIO: Message struct and publish() use IDataNode - ITaskScheduler: scheduleTask() and getCompletedTask() use IDataNode - IModuleSystem: queryModule() uses IDataNode - IEngine: Removed JSON dependency - IDataNode: getData(), setData(), queryByProperty() use IDataValue **Benefits:** - Clean separation between interface and implementation - No JSON leakage into public APIs - Easier testing and mocking - Potential for multiple backend implementations - Better encapsulation and abstraction **Note:** Concrete implementations still use JSON internally - this is an interface-only refactoring for better architecture. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e1cfa4513e
commit
c01e00559b
@ -43,6 +43,11 @@ if(GROVE_BUILD_IMPLEMENTATIONS)
|
||||
GroveEngine::core
|
||||
)
|
||||
|
||||
# If imgui is available from parent project, link it
|
||||
if(TARGET imgui_backends)
|
||||
target_link_libraries(grove_impl PUBLIC imgui_backends)
|
||||
endif()
|
||||
|
||||
add_library(GroveEngine::impl ALIAS grove_impl)
|
||||
endif()
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "IDataNode.h"
|
||||
#include <string>
|
||||
|
||||
using json = nlohmann::json;
|
||||
#include <memory>
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
@ -19,8 +18,8 @@ public:
|
||||
|
||||
const std::string& getInstanceId() const { return instance_id; }
|
||||
|
||||
virtual json serialize() const = 0;
|
||||
virtual void deserialize(const json& data) = 0;
|
||||
virtual std::unique_ptr<IDataNode> serialize() const = 0;
|
||||
virtual void deserialize(const IDataNode& data) = 0;
|
||||
|
||||
protected:
|
||||
void registerForSerialization();
|
||||
|
||||
@ -4,18 +4,16 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "IDataValue.h"
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
/**
|
||||
* @brief Interface for a single node in the data tree
|
||||
*
|
||||
* Each node can have:
|
||||
* - Children nodes (tree navigation)
|
||||
* - Its own data blob (JSON)
|
||||
* - Its own data blob (IDataValue)
|
||||
* - Properties accessible by name with type safety
|
||||
*/
|
||||
class IDataNode {
|
||||
@ -112,12 +110,12 @@ public:
|
||||
*
|
||||
* Example:
|
||||
* // Find all tanks with armor > 150
|
||||
* queryByProperty("armor", [](const json& val) {
|
||||
* return val.is_number() && val.get<int>() > 150;
|
||||
* queryByProperty("armor", [](const IDataValue& val) {
|
||||
* return val.isNumber() && val.asInt() > 150;
|
||||
* });
|
||||
*/
|
||||
virtual std::vector<IDataNode*> queryByProperty(const std::string& propName,
|
||||
const std::function<bool(const json&)>& predicate) = 0;
|
||||
const std::function<bool(const IDataValue&)>& predicate) = 0;
|
||||
|
||||
// ========================================
|
||||
// NODE'S OWN DATA
|
||||
@ -125,9 +123,9 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Get this node's data blob
|
||||
* @return JSON data or empty JSON if no data
|
||||
* @return Data value or null if no data
|
||||
*/
|
||||
virtual json getData() const = 0;
|
||||
virtual std::unique_ptr<IDataValue> getData() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if this node has data
|
||||
@ -137,9 +135,9 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Set this node's data
|
||||
* @param data JSON data to set
|
||||
* @param data Data to set
|
||||
*/
|
||||
virtual void setData(const json& data) = 0;
|
||||
virtual void setData(std::unique_ptr<IDataValue> data) = 0;
|
||||
|
||||
// ========================================
|
||||
// TYPED DATA ACCESS BY PROPERTY NAME
|
||||
|
||||
43
include/grove/IDataValue.h
Normal file
43
include/grove/IDataValue.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
/**
|
||||
* @brief Interface for data values - abstracts underlying data format
|
||||
*
|
||||
* This allows IDataNode to work with values without exposing JSON directly.
|
||||
* Concrete implementations can use JSON, MessagePack, or any other format.
|
||||
*/
|
||||
class IDataValue {
|
||||
public:
|
||||
virtual ~IDataValue() = default;
|
||||
|
||||
// Type checking
|
||||
virtual bool isNull() const = 0;
|
||||
virtual bool isBool() const = 0;
|
||||
virtual bool isNumber() const = 0;
|
||||
virtual bool isString() const = 0;
|
||||
virtual bool isArray() const = 0;
|
||||
virtual bool isObject() const = 0;
|
||||
|
||||
// Value access with defaults
|
||||
virtual bool asBool(bool defaultValue = false) const = 0;
|
||||
virtual int asInt(int defaultValue = 0) const = 0;
|
||||
virtual double asDouble(double defaultValue = 0.0) const = 0;
|
||||
virtual std::string asString(const std::string& defaultValue = "") const = 0;
|
||||
|
||||
// Array/Object access
|
||||
virtual size_t size() const = 0;
|
||||
virtual std::unique_ptr<IDataValue> get(size_t index) const = 0;
|
||||
virtual std::unique_ptr<IDataValue> get(const std::string& key) const = 0;
|
||||
virtual bool has(const std::string& key) const = 0;
|
||||
|
||||
// Serialization
|
||||
virtual std::string toString() const = 0;
|
||||
};
|
||||
|
||||
} // namespace warfactory
|
||||
@ -2,15 +2,13 @@
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
// Forward declarations to avoid circular dependencies
|
||||
namespace warfactory {
|
||||
class IModuleSystem;
|
||||
class IIO;
|
||||
}
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
enum class EngineType {
|
||||
|
||||
@ -3,9 +3,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
#include <memory>
|
||||
#include "IDataNode.h"
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
@ -24,7 +23,7 @@ struct SubscriptionConfig {
|
||||
|
||||
struct Message {
|
||||
std::string topic;
|
||||
json data;
|
||||
std::unique_ptr<IDataNode> data;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
@ -55,9 +54,9 @@ public:
|
||||
/**
|
||||
* @brief Publish message to a topic
|
||||
* @param topic Topic name (e.g., "player:123", "economy:prices")
|
||||
* @param message JSON message data
|
||||
* @param message Message data
|
||||
*/
|
||||
virtual void publish(const std::string& topic, const json& message) = 0;
|
||||
virtual void publish(const std::string& topic, std::unique_ptr<IDataNode> message) = 0;
|
||||
|
||||
/**
|
||||
* @brief Subscribe to topic pattern (high-frequency)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <memory>
|
||||
#include "IDataNode.h"
|
||||
#include "ITaskScheduler.h"
|
||||
|
||||
@ -10,8 +10,6 @@ namespace warfactory {
|
||||
class IIO;
|
||||
}
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
|
||||
@ -43,13 +41,13 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Process game logic
|
||||
* @param input JSON input from other modules or the module system
|
||||
* @param input Data input from other modules or the module system
|
||||
*
|
||||
* This is the core method where all module logic is implemented.
|
||||
* Modules communicate via IIO pub/sub and can delegate tasks via ITaskScheduler.
|
||||
* Must handle state properly through getState/setState for hot-reload.
|
||||
*/
|
||||
virtual void process(const json& input) = 0;
|
||||
virtual void process(const IDataNode& input) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set module configuration (replaces initialize)
|
||||
@ -70,9 +68,9 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Get detailed health status of the module
|
||||
* @return JSON health report with status, metrics, and diagnostics
|
||||
* @return Health report with status, metrics, and diagnostics
|
||||
*/
|
||||
virtual json getHealthStatus() = 0;
|
||||
virtual std::unique_ptr<IDataNode> getHealthStatus() = 0;
|
||||
|
||||
/**
|
||||
* @brief Cleanup and shutdown the module
|
||||
@ -84,24 +82,24 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Get current module state for hot-reload support
|
||||
* @return JSON representation of all module state
|
||||
* @return Data representation of all module state
|
||||
*
|
||||
* Critical for hot-reload functionality. Must serialize all internal
|
||||
* state that needs to be preserved when the module is replaced.
|
||||
* The returned JSON should be sufficient to restore the module to
|
||||
* The returned data should be sufficient to restore the module to
|
||||
* its current state via setState().
|
||||
*/
|
||||
virtual json getState() = 0;
|
||||
virtual std::unique_ptr<IDataNode> getState() = 0;
|
||||
|
||||
/**
|
||||
* @brief Restore module state after hot-reload
|
||||
* @param state JSON state previously returned by getState()
|
||||
* @param state State previously returned by getState()
|
||||
*
|
||||
* Called after module replacement to restore the previous state.
|
||||
* Must be able to reconstruct all internal state from the JSON
|
||||
* Must be able to reconstruct all internal state from the data
|
||||
* to ensure seamless hot-reload without game disruption.
|
||||
*/
|
||||
virtual void setState(const json& state) = 0;
|
||||
virtual void setState(const IDataNode& state) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get module type identifier
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "ITaskScheduler.h"
|
||||
|
||||
// Forward declarations to avoid circular dependencies
|
||||
@ -11,8 +10,6 @@ namespace warfactory {
|
||||
class IIO;
|
||||
}
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
enum class ModuleSystemType {
|
||||
@ -76,14 +73,14 @@ public:
|
||||
/**
|
||||
* @brief Query a specific module directly
|
||||
* @param name Name of the module to query
|
||||
* @param input JSON input to send to the module
|
||||
* @return JSON response from the module
|
||||
* @param input Input data to send to the module
|
||||
* @return Response data from the module
|
||||
*
|
||||
* This provides direct access to module functionality for debugging,
|
||||
* testing, or administrative purposes. The query bypasses normal
|
||||
* execution flow and calls the module's process() method directly.
|
||||
*/
|
||||
virtual json queryModule(const std::string& name, const json& input) = 0;
|
||||
virtual std::unique_ptr<IDataNode> queryModule(const std::string& name, const IDataNode& input) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get module system type identifier
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
#include "IDataNode.h"
|
||||
#include <memory>
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
@ -10,8 +9,8 @@ class ISerializable {
|
||||
public:
|
||||
virtual ~ISerializable() = default;
|
||||
|
||||
virtual json serialize() const = 0;
|
||||
virtual void deserialize(const json& data) = 0;
|
||||
virtual std::unique_ptr<IDataNode> serialize() const = 0;
|
||||
virtual void deserialize(const IDataNode& data) = 0;
|
||||
};
|
||||
|
||||
} // namespace warfactory
|
||||
@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
#include <memory>
|
||||
#include "IDataNode.h"
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
@ -43,26 +42,28 @@ public:
|
||||
/**
|
||||
* @brief Schedule a task for execution
|
||||
* @param taskType Type of task (e.g., "pathfinding", "market_analysis", "belt_optimization")
|
||||
* @param taskData JSON data for the task
|
||||
* @param taskData Data for the task
|
||||
*
|
||||
* Example usage:
|
||||
* ```cpp
|
||||
* // TankModule delegates pathfinding
|
||||
* scheduler->scheduleTask("pathfinding", {
|
||||
* auto taskData = createDataNode({
|
||||
* {"start", {x: 100, y: 200}},
|
||||
* {"target", {x: 500, y: 600}},
|
||||
* {"unit_id", "tank_001"}
|
||||
* });
|
||||
* scheduler->scheduleTask("pathfinding", std::move(taskData));
|
||||
*
|
||||
* // ProductionModule delegates belt calculation
|
||||
* scheduler->scheduleTask("belt_optimization", {
|
||||
* auto beltData = createDataNode({
|
||||
* {"factory_id", "main_base"},
|
||||
* {"item_type", "iron_plate"},
|
||||
* {"throughput_target", 240}
|
||||
* });
|
||||
* scheduler->scheduleTask("belt_optimization", std::move(beltData));
|
||||
* ```
|
||||
*/
|
||||
virtual void scheduleTask(const std::string& taskType, const json& taskData) = 0;
|
||||
virtual void scheduleTask(const std::string& taskType, std::unique_ptr<IDataNode> taskData) = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if completed tasks are available
|
||||
@ -75,7 +76,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Pull and consume one completed task
|
||||
* @return Task result JSON. Task is removed from completed queue.
|
||||
* @return Task result data. Task is removed from completed queue.
|
||||
*
|
||||
* Example results:
|
||||
* ```cpp
|
||||
@ -96,7 +97,7 @@ public:
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
virtual json getCompletedTask() = 0;
|
||||
virtual std::unique_ptr<IDataNode> getCompletedTask() = 0;
|
||||
};
|
||||
|
||||
} // namespace warfactory
|
||||
@ -1,4 +1,4 @@
|
||||
#include <warfactory/DebugEngine.h>
|
||||
#include <grove/DebugEngine.h>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include <warfactory/EngineFactory.h>
|
||||
#include <grove/EngineFactory.h>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
#include <warfactory/IOFactory.h>
|
||||
#include <grove/IOFactory.h>
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <functional>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
|
||||
// Include implemented transports
|
||||
#include <warfactory/IntraIO.h>
|
||||
#include <warfactory/IntraIOManager.h>
|
||||
#include <grove/IntraIO.h>
|
||||
#include <grove/IntraIOManager.h>
|
||||
// Forward declarations for future implementations
|
||||
// #include "LocalIO.h"
|
||||
// #include "NetworkIO.h"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include "warfactory/ImGuiUI.h"
|
||||
#include <grove/ImGuiUI.h>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#include <warfactory/IntraIO.h>
|
||||
#include <warfactory/IntraIOManager.h>
|
||||
#include <grove/IntraIO.h>
|
||||
#include <grove/IntraIOManager.h>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#include <warfactory/IntraIOManager.h>
|
||||
#include <warfactory/IntraIO.h>
|
||||
#include <grove/IntraIOManager.h>
|
||||
#include <grove/IntraIO.h>
|
||||
#include <stdexcept>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include <warfactory/ModuleFactory.h>
|
||||
#include <grove/ModuleFactory.h>
|
||||
#include <filesystem>
|
||||
#include <dlfcn.h>
|
||||
#include <algorithm>
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
#include <warfactory/ModuleSystemFactory.h>
|
||||
#include <grove/ModuleSystemFactory.h>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
|
||||
// Include implemented systems
|
||||
#include <warfactory/SequentialModuleSystem.h>
|
||||
#include <grove/SequentialModuleSystem.h>
|
||||
// Forward declarations for future implementations
|
||||
// #include "ThreadedModuleSystem.h"
|
||||
// #include "ThreadPoolModuleSystem.h"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include "warfactory/ResourceRegistry.h"
|
||||
#include <grove/ResourceRegistry.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace warfactory {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include <warfactory/SequentialModuleSystem.h>
|
||||
#include <grove/SequentialModuleSystem.h>
|
||||
#include <stdexcept>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user