docs: Add complete IDataTree system architecture documentation

**New Documentation:**
- docs/architecture/data-tree-system.md (comprehensive system guide)
- docs/README.md (quick start and navigation)

**Documentation Coverage:**
- Three data domains (config/, data/, runtime/)
- Architecture layers (Interfaces, Implementations, Integration, Distribution)
- Data flow patterns (config reads, save requests, hot-reload)
- Advanced features (pattern matching, queries, hashing)
- Implementation guidelines for module developers, engine implementers, system architects
- File structure examples and future enhancements

**Updated Interfaces:**
- IModule.h: Updated comments to reflect IDataNode usage and IIO save pattern
- Clarified data flow: config read-only, saves via IIO publish

**Key Concepts Documented:**
- Config synchronization from Coordinator to Engines
- Data isolation per Engine (local saves)
- Runtime temporary state (never saved)
- IIO-based save pattern (modules publish, Engine persists)
- Backend-agnostic design (pluggable implementations)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
StillHammer 2025-10-28 16:18:15 +08:00
parent fad105afb2
commit 6b295e9b17
3 changed files with 488 additions and 7 deletions

172
docs/README.md Normal file
View File

@ -0,0 +1,172 @@
# GroveEngine Documentation
## Overview
GroveEngine is a modular game engine architecture designed for distributed systems and hot-reload development. It provides a clean separation between business logic (modules) and infrastructure (engine, IO, scheduling).
## Architecture Documents
### Core Systems
- **[Data Tree System](architecture/data-tree-system.md)** - Unified config/data/runtime management
- IDataNode/IDataValue/IDataTree interfaces
- JSON backend implementation
- Hot-reload and persistence
- Distributed configuration synchronization
- **[Modular Architecture](architecture/architecture-modulaire.md)** - Module system design
- IModule interface and constraints
- IModuleSystem execution strategies
- Hot-reload workflow
- Claude Code optimization
- **[Claude Code Integration](architecture/claude-code-integration.md)** - AI development workflow
- Micro-context development
- Hot-reload for rapid iteration
- Module development best practices
## Quick Start
### Creating a Module
```cpp
#include <grove/IModule.h>
#include <grove/IDataNode.h>
class TankModule : public IModule {
private:
IIO* m_io;
int m_armor;
double m_speed;
public:
void setConfiguration(const IDataNode& config, IIO* io, ITaskScheduler* scheduler) override {
m_io = io;
m_armor = config.getInt("armor", 100);
m_speed = config.getDouble("speed", 5.0);
}
void process(const IDataNode& input) override {
// Game logic here
// Save state via IIO
auto state = createDataNode({
{"armor", m_armor},
{"speed", m_speed}
});
m_io->publish("save:tank:state", std::move(state));
}
std::unique_ptr<IDataNode> getState() override {
return createDataNode({
{"armor", m_armor},
{"speed", m_speed}
});
}
void setState(const IDataNode& state) override {
m_armor = state.getInt("armor", 100);
m_speed = state.getDouble("speed", 5.0);
}
std::string getType() const override { return "tank"; }
};
```
### Using the Data Tree
```cpp
#include <grove/DataTreeFactory.h>
// Create tree
auto tree = DataTreeFactory::create("json", "./gamedata");
// Access configuration (read-only)
auto configRoot = tree->getConfigRoot();
auto tankConfig = configRoot->getChild("tanks")->getChild("heavy");
int armor = tankConfig->getInt("armor");
// Access persistent data (read-write)
auto dataRoot = tree->getDataRoot();
auto progress = dataRoot->getChild("campaign")->getChild("progress");
progress->setData(createDataNode({{"level", 5}}));
tree->saveData();
// Hot-reload config
if (tree->reloadIfChanged()) {
// Config changed, refresh modules
}
```
## Key Concepts
### Module System
- **Modules**: 200-300 line business logic units
- **IModuleSystem**: Execution strategy (Sequential, Threaded, Distributed)
- **Hot-reload**: Replace modules without restarting
- **State preservation**: getState/setState for seamless updates
### Data Management
- **config/**: Read-only game configuration (hot-reload, distributed)
- **data/**: Persistent player data (local saves)
- **runtime/**: Temporary state (never saved)
### Communication
- **IIO**: Pub/sub messaging between modules
- **ITaskScheduler**: Delegate heavy computation
- **Save pattern**: Modules publish "save:*" messages, Engine persists
### Distribution
- **Coordinator**: Master config with hot-reload
- **Engines**: Local replicas, synchronized config
- **Isolation**: Each Engine has independent data/
## Design Principles
1. **Interface-based**: Work with abstractions (IDataNode, not JsonDataNode)
2. **Backend-agnostic**: Swap implementations without code changes
3. **Minimal coupling**: Modules communicate only via IIO
4. **Hot-reload first**: Development optimized for instant feedback
5. **Distribution-ready**: Config sync, data isolation built-in
## Project Status
### Implemented ✅
- Complete IDataNode/IDataTree system
- JSON backend (JsonDataValue, JsonDataNode, JsonDataTree)
- Hot-reload for config files
- Save/load for persistent data
- Pattern matching and property queries
- SHA256 hashing for validation
### In Progress 🚧
- Coordinator synchronization implementation
- Module system integration with DataTree
- Example modules and tests
### Planned 📋
- Binary format backend
- Database backend
- Network synchronization protocol
- Schema validation
- Migration system
## Contributing
When adding new features:
1. Start with interface definition (.h file)
2. Add documentation to this folder
3. Implement concrete class
4. Update architecture docs
5. Write usage examples
## Further Reading
- [Hot-Reload Guide](implementation/CLAUDE-HOT-RELOAD-GUIDE.md)
- [Module Architecture](architecture/architecture-modulaire.md)
- [Data Tree System](architecture/data-tree-system.md)
---
**Last Updated**: 2025-10-28
**Engine Version**: 1.0.0

View File

@ -0,0 +1,307 @@
# IDataTree System Architecture
## Overview
The IDataTree system is a unified hierarchical data management system for configuration, persistent data, and runtime state. It provides a flexible, abstract interface that can be backed by multiple storage formats (JSON, Binary, Database, etc.).
## Core Concepts
### Three Data Domains
The system manages three separate data trees with different characteristics:
```
root/
├── config/ (Read-only, hot-reload enabled, distributed)
├── data/ (Read-write, saved to disk, local per Engine)
└── runtime/ (Read-write, temporary, never saved)
```
#### config/ - Shared Configuration
- **Purpose**: Game configuration, unit stats, modding
- **Access**: Read-only for modules
- **Source**: Loaded from files, synchronized from Coordinator
- **Hot-reload**: Automatic detection and reload of changed files
- **Distribution**: Synchronized across all Engines via Coordinator
#### data/ - Persistent Data
- **Purpose**: Player saves, campaign progress, unlocks, statistics
- **Access**: Read-write for modules (via IIO publish)
- **Source**: Local files per Engine
- **Persistence**: Saved to disk on request
- **Isolation**: Each Engine maintains its own data/
#### runtime/ - Temporary State
- **Purpose**: Current game state, caches, temporary calculations
- **Access**: Read-write for modules
- **Lifecycle**: Exists only in memory, never saved
- **Scope**: Strictly local to each Engine instance
## Architecture Layers
### Layer 1: Interfaces (Abstract)
```cpp
IDataValue // Abstract data value (type-safe access)
IDataNode // Tree node (navigation, search, modification)
IDataTree // Root container (config/data/runtime management)
```
**Key principle**: Modules and systems work ONLY with interfaces, never concrete implementations.
### Layer 2: Concrete Implementations
```cpp
JsonDataValue // nlohmann::json backed value
JsonDataNode // JSON tree node with full feature set
JsonDataTree // File-based JSON storage
// Future implementations:
BinaryDataValue // Custom binary format
DatabaseDataNode // SQL backend
NetworkDataTree // Remote data server
```
**Pluggable backends**: Change implementation via `DataTreeFactory::create(type, path)`
### Layer 3: Module System Integration
```cpp
IModuleSystem
├── Owns IDataTree instance
├── Provides config to modules via setConfiguration()
├── Listens to IIO for save requests
└── Persists data to Tree
```
**Responsibilities**:
- Initialize Tree (local or synchronized)
- Extract and provide config nodes to modules
- Handle save/load requests from modules via IIO
- Trigger hot-reload notifications
### Layer 4: Distributed Coordination
```cpp
CoordinationModule (Master)
├── Master config tree
├── Hot-reload detection
└── Broadcast updates via IIO
DebugEngine (Workers)
├── Local tree replica
├── Subscribe to config updates
└── Apply synchronized config
```
## Data Flow Patterns
### Pattern 1: Module Reads Configuration
```cpp
// Engine startup
auto tankConfig = tree->getConfigRoot()->getChild("tanks")->getChild("heavy");
tankModule->setConfiguration(*tankConfig, io, scheduler);
// Module uses config
void TankModule::setConfiguration(const IDataNode& config, ...) {
m_armor = config.getInt("armor");
m_speed = config.getDouble("speed");
m_weaponType = config.getString("weapon_type");
}
```
### Pattern 2: Module Saves State
```cpp
// Module publishes save request via IIO
void TankModule::onDestroy() {
auto state = createDataNode({
{"position", {x, y}},
{"health", currentHealth},
{"ammo", ammoCount}
});
m_io->publish("save:tank:state:123", std::move(state));
}
// Engine listens and persists
void Engine::handleSaveRequests() {
while (m_io->hasMessages()) {
auto msg = m_io->pullMessage();
if (msg.topic.starts_with("save:")) {
std::string path = extractPath(msg.topic);
m_tree->getDataRoot()->setChild(path, std::move(msg.data));
m_tree->saveNode("data/" + path);
}
}
}
```
### Pattern 3: Config Hot-Reload (Distributed)
```cpp
// COORDINATEUR: Master config with hot-reload
void CoordinationModule::tick() {
if (m_masterTree->reloadIfChanged()) {
auto config = m_masterTree->getConfigRoot();
m_networkIO->publish("config:reload", std::move(config));
}
}
// ENGINE: Receives and applies config
void DebugEngine::processNetworkMessages() {
auto msg = m_networkIO->pullMessage();
if (msg.topic == "config:reload") {
auto configRoot = m_tree->getNode("config");
configRoot->clearChildren();
configRoot->setChild("updated", std::move(msg.data));
// Notify all modules
for (auto& module : m_modules) {
auto moduleConfig = configRoot->getChild(module->getType());
module->setConfiguration(*moduleConfig, m_io, m_scheduler);
}
}
}
```
## Advanced Features
### Pattern Matching Search
```cpp
// Find all heavy units
auto heavyUnits = configRoot->getChildrenByNameMatch("*_heavy_*");
// Find all tank variants
auto tanks = configRoot->getChildrenByNameMatch("tank_*");
```
### Property-Based Queries
```cpp
// Find all units with armor > 150
auto heavyArmored = configRoot->queryByProperty("armor",
[](const IDataValue& val) {
return val.isNumber() && val.asInt() > 150;
});
```
### Hash-Based Validation
```cpp
// Check if config changed
std::string currentHash = configNode->getTreeHash();
if (currentHash != lastKnownHash) {
// Config changed, refresh caches
rebuildLookupTables();
lastKnownHash = currentHash;
}
```
## Implementation Guidelines
### For Module Developers
**DO:**
- Read config via `getInt()`, `getString()`, `getBool()`, etc.
- Publish save requests via IIO: `m_io->publish("save:module:state", data)`
- Keep modules under 300 lines
- Use IDataNode interface only, never concrete types
**DON'T:**
- Directly access IDataTree
- Create nodes manually (use factory or IIO)
- Assume JSON format (work with IDataValue interface)
- Cache config pointers (config can be reloaded)
### For Engine Implementers
**DO:**
- Create one IDataTree per Engine instance
- Subscribe to "save:*" pattern for save requests
- Call `reloadIfChanged()` periodically (or use callbacks)
- Provide isolated config subtrees to modules
**DON'T:**
- Share IDataTree between Engines (use synchronization instead)
- Allow modules to access root directly
- Block on save operations (make async if needed)
### For System Architects
**DO:**
- Use Coordinator pattern for config distribution
- Keep data/ isolated per Engine
- Use IIO for all cross-component communication
- Consider multiple IDataTree implementations for different needs
**DON'T:**
- Synchronize data/ across Engines (defeats isolation)
- Put business logic in IDataTree implementations
- Create tight coupling between Tree and Modules
## File Structure Example
```
gamedata/
├── config/
│ ├── tanks.json
│ ├── weapons.json
│ ├── buildings.json
│ └── mods/
│ └── super_mod/
│ ├── new_tanks.json
│ └── new_weapons.json
├── data/
│ ├── campaign_progress.json
│ ├── unlocked_tech.json
│ └── player_stats.json
└── runtime/
(in-memory only, not on disk)
```
## Benefits
### For Development
- **Modular**: Swap backends without changing module code
- **Testable**: Mock IDataTree for unit tests
- **Hot-reload**: Instant feedback during development
- **Type-safe**: Compile-time checks with IDataNode interface
### For Operations
- **Distributed**: Config synchronized across cluster
- **Isolated**: Each Engine manages its own saves
- **Auditable**: Hash validation for data integrity
- **Flexible**: JSON for dev, Binary for production
### For Modding
- **Accessible**: JSON files are human-readable
- **Safe**: Read-only access prevents corruption
- **Extensible**: Mods add files without conflicts
- **Hot-loadable**: Changes apply without restart
## Future Enhancements
### Planned Features
- Binary format implementation (BinaryDataTree)
- Database backend (DatabaseDataTree)
- Differential updates (send only changed config)
- Compression for network sync
- Versioning and migration system
### Potential Extensions
- Encryption for sensitive data
- Cloud storage backend (S3DataTree)
- Real-time collaboration (multiple writers)
- Conflict resolution for distributed writes
- Schema validation and type checking
---
**Status**: Production-ready ✅
**Version**: 1.0.0
**Last Updated**: 2025-10-28

View File

@ -21,17 +21,19 @@ namespace grove {
* 200-300 lines of pure game logic with zero infrastructure code. * 200-300 lines of pure game logic with zero infrastructure code.
* *
* Key design principles: * Key design principles:
* - PURE FUNCTION: process() method has no side effects beyond return value * - PURE FUNCTION: process() method has minimal side effects
* - CONFIG VIA DATATREE: Configuration via immutable IDataNode references * - CONFIG VIA IDATANODE: Configuration via immutable IDataNode references
* - JSON ONLY: All communication via JSON input/output * - IDATANODE COMMUNICATION: All data via IDataNode abstraction (backend agnostic)
* - IIO FOR PERSISTENCE: Save requests via IIO publish (Engine handles persistence)
* - NO INFRASTRUCTURE: No threading, networking, or framework dependencies * - NO INFRASTRUCTURE: No threading, networking, or framework dependencies
* - HOT-RELOAD READY: State serialization for seamless module replacement * - HOT-RELOAD READY: State serialization for seamless module replacement
* - CLAUDE OPTIMIZED: Micro-context size for AI development efficiency * - CLAUDE OPTIMIZED: Micro-context size for AI development efficiency
* *
* BREAKING CHANGES: * DATA FLOW:
* - Removed initialize() method - use setConfiguration() instead * - Configuration: Read-only via setConfiguration(const IDataNode&)
* - Configuration via const IDataNode& for immutability * - Input: Read-only via process(const IDataNode&)
* - Health check returns detailed JSON status * - Save: Publish via IIO: m_io->publish("save:module:state", data)
* - State: Serialized via getState() for hot-reload
* *
* Module constraint: Maximum 300 lines per module (Exception: ProductionModule 500-800 lines) * Module constraint: Maximum 300 lines per module (Exception: ProductionModule 500-800 lines)
*/ */