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>
340 lines
11 KiB
C++
340 lines
11 KiB
C++
#pragma once
|
|
|
|
#include <nlohmann/json.hpp>
|
|
#include <string>
|
|
#include <functional>
|
|
|
|
namespace grove {
|
|
|
|
using json = nlohmann::json;
|
|
|
|
// ========================================
|
|
// ENUMS FOR TYPE SAFETY
|
|
// ========================================
|
|
|
|
/**
|
|
* @brief Data types for UI display
|
|
*/
|
|
enum class DataType {
|
|
ECONOMY,
|
|
MAP,
|
|
INVENTORY,
|
|
CONSOLE,
|
|
PERFORMANCE,
|
|
COMPANIES,
|
|
ALERTS,
|
|
PRODUCTION,
|
|
LOGISTICS,
|
|
PLAYER,
|
|
SETTINGS,
|
|
DEBUG,
|
|
CUSTOM // For extending with string fallback
|
|
};
|
|
|
|
/**
|
|
* @brief Request types from UI
|
|
*/
|
|
enum class RequestType {
|
|
GET_PRICES,
|
|
GET_CHUNK,
|
|
MOVE_PLAYER,
|
|
SAVE_GAME,
|
|
LOAD_GAME,
|
|
CLOSE_WINDOW,
|
|
FOCUS_WINDOW,
|
|
UPDATE_SETTINGS,
|
|
EXECUTE_COMMAND,
|
|
CUSTOM // For extending with string fallback
|
|
};
|
|
|
|
/**
|
|
* @brief Event/message levels
|
|
*/
|
|
enum class EventLevel {
|
|
INFO,
|
|
SUCCESS,
|
|
WARNING,
|
|
ERROR,
|
|
DEBUG,
|
|
TRACE
|
|
};
|
|
|
|
/**
|
|
* @brief Dock types for window management
|
|
*/
|
|
enum class DockType {
|
|
DOCK, // Standard dockable panel
|
|
SPLIT, // Horizontal/vertical split
|
|
TABBED, // Tabbed container
|
|
FLOATING // Floating window
|
|
};
|
|
|
|
/**
|
|
* @brief Dock positions
|
|
*/
|
|
enum class DockPosition {
|
|
LEFT,
|
|
RIGHT,
|
|
TOP,
|
|
BOTTOM,
|
|
CENTER,
|
|
TAB // Add as tab to parent
|
|
};
|
|
|
|
/**
|
|
* @brief Split orientations
|
|
*/
|
|
enum class Orientation {
|
|
HORIZONTAL,
|
|
VERTICAL
|
|
};
|
|
|
|
/**
|
|
* @brief Pure Generic UI Interface - Type-safe with enums
|
|
*/
|
|
class IUI {
|
|
public:
|
|
virtual ~IUI() = default;
|
|
|
|
// ========================================
|
|
// LIFECYCLE
|
|
// ========================================
|
|
|
|
virtual void initialize(const json& config) = 0;
|
|
virtual bool update() = 0;
|
|
virtual void shutdown() = 0;
|
|
|
|
// ========================================
|
|
// GENERIC DATA FLOW - ENUM VERSIONS
|
|
// ========================================
|
|
|
|
/**
|
|
* @brief Display data with type-safe enum
|
|
* @param dataType Enum data type
|
|
* @param data JSON with content + optional window config:
|
|
* {
|
|
* "content": {...}, // Actual data to display
|
|
* "window": { // Window configuration (optional)
|
|
* "id": "window_id",
|
|
* "title": "Window Title",
|
|
* "parent": "parent_dock_id",
|
|
* "dock": "left|right|top|bottom|center|tab",
|
|
*
|
|
* // SIZE SYSTEM - Hybrid percentage + absolute constraints
|
|
* "size": {"width": "20%", "height": 300}, // Target: 20% of parent width, 300px height
|
|
* "size": {"width": 400, "height": "50%"}, // Target: 400px width, 50% of parent height
|
|
* "size": {"width": "30%", "height": "40%"}, // Target: 30% width, 40% height
|
|
*
|
|
* "min_size": {"width": 200, "height": 150}, // ABSOLUTE minimum in pixels (always respected)
|
|
* "max_size": {"width": 800, "height": "80%"}, // Maximum: 800px width OR 80% of parent (whichever smaller)
|
|
*
|
|
* "position": {"x": 100, "y": 50},
|
|
* "floating": false,
|
|
* "resizable": true,
|
|
* "closeable": true,
|
|
* "collapsible": false
|
|
* }
|
|
* }
|
|
*/
|
|
virtual void showData(DataType dataType, const json& data) = 0;
|
|
|
|
/**
|
|
* @brief Display custom data type (fallback to string)
|
|
* @param customType Custom data type name
|
|
* @param data JSON data
|
|
*/
|
|
virtual void showDataCustom(const std::string& customType, const json& data) = 0;
|
|
|
|
/**
|
|
* @brief Handle user request with type-safe enum
|
|
* @param requestType Enum request type
|
|
* @param callback Function to call when request happens
|
|
*/
|
|
virtual void onRequest(RequestType requestType, std::function<void(const json&)> callback) = 0;
|
|
|
|
/**
|
|
* @brief Handle custom request type (fallback to string)
|
|
* @param customType Custom request type name
|
|
* @param callback Function to call when request happens
|
|
*/
|
|
virtual void onRequestCustom(const std::string& customType, std::function<void(const json&)> callback) = 0;
|
|
|
|
/**
|
|
* @brief Show event with type-safe level
|
|
* @param level Event level enum
|
|
* @param message Human readable text
|
|
*/
|
|
virtual void showEvent(EventLevel level, const std::string& message) = 0;
|
|
|
|
// ========================================
|
|
// WINDOW MANAGEMENT - ENUM VERSIONS
|
|
// ========================================
|
|
|
|
/**
|
|
* @brief Create dock with type-safe enums
|
|
* @param dockId Unique dock identifier
|
|
* @param type Dock type enum
|
|
* @param position Dock position enum
|
|
* @param config Additional configuration:
|
|
* {
|
|
* "parent": "parent_dock_id", // Parent dock (optional)
|
|
*
|
|
* // HYBRID SIZE SYSTEM
|
|
* "size": {"width": "25%", "height": 200}, // Target: 25% of parent width, 200px height
|
|
* "min_size": {"width": 200, "height": 100}, // ABSOLUTE minimum pixels (overrides percentage)
|
|
* "max_size": {"width": "50%", "height": 600}, // Maximum: 50% of parent OR 600px (whichever smaller)
|
|
*
|
|
* "orientation": "horizontal", // For SPLIT type
|
|
* "collapsible": true, // Can be collapsed
|
|
* "resizable": true, // Can be resized
|
|
* "tabs": true // Enable tabbed interface
|
|
* }
|
|
*/
|
|
virtual void createDock(const std::string& dockId, DockType type, DockPosition position, const json& config = {}) = 0;
|
|
|
|
/**
|
|
* @brief Create split dock with orientation
|
|
* @param dockId Unique dock identifier
|
|
* @param orientation Split orientation
|
|
* @param config Additional configuration:
|
|
* {
|
|
* "parent": "parent_dock_id", // Parent dock (optional)
|
|
* "size": {"width": 300, "height": 200}, // Initial size
|
|
* "min_size": {"width": 100, "height": 50}, // Minimum split size in pixels
|
|
* "max_size": {"width": 1000, "height": 800}, // Maximum split size in pixels
|
|
* "split_ratio": 0.5, // Split ratio (0.0 to 1.0)
|
|
* "min_panel_size": 80, // Minimum size for each panel in split
|
|
* "resizable": true // Can be resized by dragging splitter
|
|
* }
|
|
*/
|
|
virtual void createSplit(const std::string& dockId, Orientation orientation, const json& config = {}) = 0;
|
|
|
|
/**
|
|
* @brief Close window or dock
|
|
* @param windowId Window/dock ID to close
|
|
*/
|
|
virtual void closeWindow(const std::string& windowId) = 0;
|
|
|
|
/**
|
|
* @brief Focus window
|
|
* @param windowId Window ID to focus
|
|
*/
|
|
virtual void focusWindow(const std::string& windowId) = 0;
|
|
|
|
// ========================================
|
|
// GENERIC STATE
|
|
// ========================================
|
|
|
|
virtual json getState() const = 0;
|
|
virtual void setState(const json& state) = 0;
|
|
|
|
// ========================================
|
|
// CONVENIENCE METHODS WITH ENUMS
|
|
// ========================================
|
|
|
|
void info(const std::string& message) {
|
|
showEvent(EventLevel::INFO, message);
|
|
}
|
|
|
|
void success(const std::string& message) {
|
|
showEvent(EventLevel::SUCCESS, message);
|
|
}
|
|
|
|
void warning(const std::string& message) {
|
|
showEvent(EventLevel::WARNING, message);
|
|
}
|
|
|
|
void error(const std::string& message) {
|
|
showEvent(EventLevel::ERROR, message);
|
|
}
|
|
|
|
void debug(const std::string& message) {
|
|
showEvent(EventLevel::DEBUG, message);
|
|
}
|
|
};
|
|
|
|
// ========================================
|
|
// ENUM TO STRING CONVERSIONS (for implementations)
|
|
// ========================================
|
|
|
|
/**
|
|
* @brief Convert DataType enum to string (for implementations that need strings)
|
|
*/
|
|
constexpr const char* toString(DataType type) {
|
|
switch (type) {
|
|
case DataType::ECONOMY: return "economy";
|
|
case DataType::MAP: return "map";
|
|
case DataType::INVENTORY: return "inventory";
|
|
case DataType::CONSOLE: return "console";
|
|
case DataType::PERFORMANCE: return "performance";
|
|
case DataType::COMPANIES: return "companies";
|
|
case DataType::ALERTS: return "alerts";
|
|
case DataType::PRODUCTION: return "production";
|
|
case DataType::LOGISTICS: return "logistics";
|
|
case DataType::PLAYER: return "player";
|
|
case DataType::SETTINGS: return "settings";
|
|
case DataType::DEBUG: return "debug";
|
|
case DataType::CUSTOM: return "custom";
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
constexpr const char* toString(RequestType type) {
|
|
switch (type) {
|
|
case RequestType::GET_PRICES: return "get_prices";
|
|
case RequestType::GET_CHUNK: return "get_chunk";
|
|
case RequestType::MOVE_PLAYER: return "move_player";
|
|
case RequestType::SAVE_GAME: return "save_game";
|
|
case RequestType::LOAD_GAME: return "load_game";
|
|
case RequestType::CLOSE_WINDOW: return "close_window";
|
|
case RequestType::FOCUS_WINDOW: return "focus_window";
|
|
case RequestType::UPDATE_SETTINGS: return "update_settings";
|
|
case RequestType::EXECUTE_COMMAND: return "execute_command";
|
|
case RequestType::CUSTOM: return "custom";
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
constexpr const char* toString(EventLevel level) {
|
|
switch (level) {
|
|
case EventLevel::INFO: return "info";
|
|
case EventLevel::SUCCESS: return "success";
|
|
case EventLevel::WARNING: return "warning";
|
|
case EventLevel::ERROR: return "error";
|
|
case EventLevel::DEBUG: return "debug";
|
|
case EventLevel::TRACE: return "trace";
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
constexpr const char* toString(DockType type) {
|
|
switch (type) {
|
|
case DockType::DOCK: return "dock";
|
|
case DockType::SPLIT: return "split";
|
|
case DockType::TABBED: return "tabbed";
|
|
case DockType::FLOATING: return "floating";
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
constexpr const char* toString(DockPosition pos) {
|
|
switch (pos) {
|
|
case DockPosition::LEFT: return "left";
|
|
case DockPosition::RIGHT: return "right";
|
|
case DockPosition::TOP: return "top";
|
|
case DockPosition::BOTTOM: return "bottom";
|
|
case DockPosition::CENTER: return "center";
|
|
case DockPosition::TAB: return "tab";
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
constexpr const char* toString(Orientation orient) {
|
|
switch (orient) {
|
|
case Orientation::HORIZONTAL: return "horizontal";
|
|
case Orientation::VERTICAL: return "vertical";
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
} // namespace grove
|