**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>
308 lines
8.8 KiB
Markdown
308 lines
8.8 KiB
Markdown
# 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
|