355 lines
13 KiB
Markdown
355 lines
13 KiB
Markdown
# **SessionZero Design Document**
|
|
|
|
## **1. Introduction**
|
|
|
|
### **1.1 Purpose**
|
|
|
|
SessionZero is a free and open-source TTRPG companion app designed to streamline tabletop role-playing game management. It emphasizes flexibility, modularity, and federation through a **system-agnostic datapack format**, supporting both offline and self-hostable online play. The goal is to empower players and GMs with full control over their data, rulesets, and session management.
|
|
|
|
### **1.2 Scope**
|
|
|
|
The project will begin as a cross-platform desktop application (Windows and Linux), offering tools for creating and managing TTRPG data such as characters, datasets, templates, and sessions. The backend supports user accounts, a database for shared content (SessionZeroDB), and prepares for future federation capabilities. Phase 2 introduces federation, while Phase 3 focuses on mobile support and plugin extensibility.
|
|
|
|
### **1.3 Objectives**
|
|
|
|
* Provide a modular, open-source companion app for any TTRPG system.
|
|
* Implement a JSON-based datapack format for extensible content storage.
|
|
* Support both local use and self-hostable online instances.
|
|
* Create a foundation for future federation and mobile support.
|
|
|
|
## **2. System Overview**
|
|
|
|
SessionZero consists of three main layers:
|
|
|
|
1. **Frontend (Client):** Cross-platform desktop application (.NET Avalonia).
|
|
2. **Backend (Server):** ASP.NET backend managing user accounts, SessionZeroDB, and P2P connections.
|
|
3. **Datapack System:** A structured archive format for storing and sharing game data.
|
|
|
|
## **3. Technology Stack**
|
|
|
|
* **Core:** C# / .NET 9.0 (minimal API)
|
|
* **Client:** Avalonia UI (cross-platform desktop)
|
|
* **Database:** PostgreSQL (primary data store for shared/online content)
|
|
* **Offline/Local:** Local file storage, perhaps SQLite for local instances.
|
|
* **Networking:** WebSockets for real-time session updates; SignalR/gRPC considered for P2P/federation.
|
|
|
|
## **4. Core Data Concepts**
|
|
|
|
### **4.1 Datapack**
|
|
|
|
The top-level container (.szp file), bundling all system-specific data (templates, datasets, assets).
|
|
|
|
### **4.2 Template**
|
|
|
|
A reusable definition of a data structure (e.g., a **Character Template** defining character sheet fields, or a **Session Template** defining campaign structure).
|
|
|
|
### **4.3 Dataset**
|
|
|
|
A structured collection of external data records (e.g., a bestiary, a list of items, or spells).
|
|
|
|
### **4.4 Instance**
|
|
|
|
The runtime data created from a Template (e.g., "Aelric's Character Sheet" based on the "Fantasy Character" Template).
|
|
|
|
### **4.5 Schema**
|
|
|
|
Formal JSON Schemas used to validate the structure of Datapacks and their contents.
|
|
|
|
## **5. Datapack Specification**
|
|
|
|
A datapack is a self-contained archive (.szp) that holds all data and assets for a specific TTRPG system, module, or expansion. It serves as the foundation for SessionZero's extensible content model. Each pack can define **datasets**, **templates**, and optionally contain instance data (though instances are usually stored separately as save files). The structure emphasizes modularity, portability, and reliable dependency management between packs.
|
|
|
|
### **5.1 Directory Structure**
|
|
|
|
```text
|
|
pack-name/
|
|
├── szpack.json # Pack metadata and manifest
|
|
├── media/
|
|
│ └── images/ # Image assets (referenced by objects)
|
|
└── objects/
|
|
├── datasets/ # User-defined structured data (e.g. items, NPCs)
|
|
├── character-templates/ # Templates defining character structures
|
|
└── session-templates/ # Templates defining session/campaign structures
|
|
```
|
|
|
|
### **5.2 Pack Metadata (szpack.json)**
|
|
|
|
Each datapack contains a root metadata file that defines its identity, authorship, dependencies, and compatibility information. This structure aligns with the C# Datapack and DatapackDependency models.
|
|
```json
|
|
{
|
|
"id": "c9a3f9c8-8b8a-4f1f-9f3b-2d8c7f2c6c62",
|
|
"name": "Example Pack",
|
|
"version": "1.0.0",
|
|
"author": "UserName",
|
|
"license": "CC-BY-SA-4.0",
|
|
"description": "A fantasy setting datapack containing items and NPCs.",
|
|
"createdAt": "2025-10-15T00:00:00Z",
|
|
"sessionZeroVersion": "1.0.0",
|
|
"dependencies": [
|
|
{
|
|
"id": "c2e6d0a4-2a8f-4a51-b36e-9f8f2c7b1d11",
|
|
"name": "Core-Ruleset",
|
|
"version": "1.2.0"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### **5.3 Common Object Metadata**
|
|
|
|
Objects within the datapack (datasets, templates) inherit from **SzObject**. The **szType** field is required to identify the object type. **Image paths are relative to the media/images folder.**
|
|
```json
|
|
{
|
|
"id": "core-items",
|
|
"name": "Core Items",
|
|
"szType": "dataset",
|
|
"description": "A collection of basic weapons and armor.",
|
|
"icon": "core-items.png",
|
|
"version": "1.0.0",
|
|
"schemaVersion": "1.0.0"
|
|
}
|
|
```
|
|
|
|
*Note: The system resolves the icon field path (e.g., "core-items.png") to datapack/media/images/core-items.png.*
|
|
|
|
### **5.4 Dataset Objects**
|
|
|
|
Datasets are structured collections of data entries. The entry structure includes TopLevelFields and optional Groups of fields, aligning with the DatasetEntry C# model.
|
|
```json
|
|
{
|
|
"id": "core-items",
|
|
"szType": "dataset",
|
|
"datasetType": "items",
|
|
"name": "Core Items",
|
|
"description": "Weapons, armor, and consumables for the base ruleset.",
|
|
"version": "1.0.0",
|
|
"schemaVersion": "1.0.0",
|
|
"entries": {
|
|
"sword": {
|
|
"id": "sword",
|
|
"name": "Sword",
|
|
"description": "A basic weapon.",
|
|
"icon": "weapons/sword.png",
|
|
"topLevelFields": {
|
|
"damage": { "type": "Number", "value": 10 },
|
|
"weight": { "type": "Number", "value": 3 }
|
|
},
|
|
"groups": [
|
|
{
|
|
"id": "stats",
|
|
"name": "Stats",
|
|
"fields": {
|
|
"rarity": { "type": "Text", "value": "Common" }
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"potion": {
|
|
"id": "potion",
|
|
"name": "Healing Potion",
|
|
"description": "Restores a small amount of HP.",
|
|
"icon": "consumables/potion.png",
|
|
"topLevelFields": {
|
|
"healAmount": { "type": "Number", "value": 20 },
|
|
"consumable": { "type": "Boolean", "value": true }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
*Note: The field retrieval path is expected to be EntryName.FieldName or EntryName.GroupName.FieldName, matching the logic in Dataset.cs.*
|
|
|
|
### **5.5 Character Templates**
|
|
|
|
Character templates define the fields and structure for characters. Note the use of the specific **DatasetLink** object for list fields, requiring a Datapack ID, Dataset ID, and Version.
|
|
```json
|
|
{
|
|
"id": "default-character",
|
|
"szType": "character-template",
|
|
"name": "Generic Character",
|
|
"description": "A base character layout usable across multiple systems.",
|
|
"icon": "character.png",
|
|
"version": "1.0.0",
|
|
"schemaVersion": "1.0.0",
|
|
"sections": [
|
|
{
|
|
"id": "core",
|
|
"name": "Core Stats",
|
|
"groups": [
|
|
{
|
|
"id": "attributes",
|
|
"name": "Attributes",
|
|
"fields": [
|
|
{ "id": "strength", "name": "Strength", "type": "Number", "defaultValue": 10 },
|
|
{ "id": "dexterity", "name": "Dexterity", "type": "Number", "defaultValue": 10 },
|
|
{ "id": "intelligence", "name": "Intelligence", "type": "Number", "defaultValue": 10 }
|
|
]
|
|
},
|
|
{
|
|
"id": "inventory",
|
|
"name": "Inventory",
|
|
"fields": [
|
|
{
|
|
"id": "equipment",
|
|
"name": "Equipment",
|
|
"type": "List",
|
|
"datasetLink": {
|
|
"datapackId": "c9a3f9c8-8b8a-4f1f-9f3b-2d8c7f2c6c62",
|
|
"datasetId": "core-items",
|
|
"version": "1.0.0"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### **5.6 Session Templates**
|
|
|
|
Session templates are blueprints for setting up a campaign. This example uses **CharacterTemplateLink** and a list of **DatasetLink** objects for **RequiredDatasets** as defined in SessionTemplate.cs.
|
|
```json
|
|
{
|
|
"id": "basic-session",
|
|
"szType": "session-template",
|
|
"name": "Basic Fantasy Campaign",
|
|
"description": "A classic campaign setup with standard fantasy rules.",
|
|
"icon": "session.png",
|
|
"version": "1.0.0",
|
|
"schemaVersion": "1.0.0",
|
|
"characterTemplateLink": {
|
|
"datapackId": "c9a3f9c8-8b8a-4f1f-9f3b-2d8c7f2c6c62",
|
|
"templateId": "default-character",
|
|
"version": "1.0.0"
|
|
},
|
|
"requiredDatasets": [
|
|
{
|
|
"datapackId": "c9a3f9c8-8b8a-4f1f-9f3b-2d8c7f2c6c62",
|
|
"datasetId": "core-items",
|
|
"version": "1.0.0"
|
|
}
|
|
],
|
|
"sections": [
|
|
{
|
|
"id": "session-info",
|
|
"name": "Session Info",
|
|
"groups": [
|
|
{
|
|
"id": "details",
|
|
"name": "Details",
|
|
"fields": [
|
|
{ "id": "setting", "name": "Setting", "type": "Text", "defaultValue": "Thalindra" },
|
|
{ "id": "gmNotes", "name": "GM Notes", "type": "MultiText" }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### **5.7 Instances (Stored Separately)**
|
|
|
|
Instances, such as a specific character or a running campaign's state, are typically stored outside of the core, reusable datapacks but follow a similar structure, referencing a template.
|
|
```json
|
|
{
|
|
"szType": "character-instance",
|
|
"templateId": "default-character",
|
|
"name": "Aelric Stormhand",
|
|
"fields": {
|
|
"strength": 14,
|
|
"dexterity": 11,
|
|
"inventory": ["sword", "potion"]
|
|
}
|
|
}
|
|
```
|
|
|
|
### **5.8 Validation and Schema Versioning**
|
|
|
|
Formal, versioned JSON Schemas define the structure of szpack.json and core object types.
|
|
|
|
* Each object declares a **schemaVersion** (global versioning per SessionZero release).
|
|
* Validation tools confirm compliance before import/export.
|
|
* Internal references (DatasetLink, CharacterTemplateLink, etc.) are resolved within the pack automatically.
|
|
* External references are verified via dependencies in szpack.json.
|
|
|
|
**Session Datapack vs Templates:**
|
|
|
|
* **Session Template:** A reusable blueprint for campaign/session setup. Lives under objects/session-templates/.
|
|
* **Session Datapack:** The persisted, evolving state of an ongoing campaign. It is stored as a special pack and does not appear alongside normal content packs in the UI. Snapshots are versioned with timestamps. Export/import uses the same .szp format with a distinct type flag in szpack.json.
|
|
|
|
## **6. Networking & Synchronization**
|
|
|
|
### **6.1 Session Model**
|
|
|
|
A "Session" is a single game instance, hosted by a GM. It uses a centralized, shared document model (SessionZeroDB/PostgreSQL) with real-time updates pushed via WebSockets.
|
|
|
|
### **6.2 Data Flow**
|
|
|
|
1. **GM Action:** GM updates an NPC in their local client.
|
|
2. **Client:** Pushes the update to the server via API/WebSockets.
|
|
3. **Server:** Validates, commits to DB, and broadcasts the change to all connected players (including the GM).
|
|
4. **Players:** Receive the update and apply it to their local model.
|
|
|
|
### **6.3 Offline Mode**
|
|
|
|
The application supports full offline functionality, using local storage. When connectivity is restored, the system uses conflict-resolution logic (timestamp-based or operational transformation) to reconcile changes with the SessionZeroDB.
|
|
|
|
## **7. Federation**
|
|
|
|
### **7.1 Concept**
|
|
|
|
Federation allows different SessionZero instances (e.g., self-hosted servers) to share and discover content (Datapacks, public Datasets, Templates). This requires standardized APIs for content retrieval and identity verification.
|
|
|
|
### **7.2 Identity**
|
|
|
|
* Users have a unique global identifier (UID).
|
|
* Datapacks are identified by their UUID (id).
|
|
|
|
### **7.3 Data Sharing**
|
|
|
|
Publicly shared Datapacks are discoverable through a federation layer, allowing users to import content from other trusted servers.
|
|
|
|
## **8. Licensing**
|
|
|
|
### **8.1 Source Code License**
|
|
|
|
* **AGPL-3.0 (Affero General Public License):** Ensures open-source continuity and attribution, prevents uncredited commercial rebranding.
|
|
|
|
### **8.2 User Content License**
|
|
|
|
* **Creative Commons BY-SA 4.0:** Allows sharing and adaptation with attribution.
|
|
|
|
## **9. Development Phases**
|
|
|
|
### **Phase 1: Core Platform (MVP)**
|
|
|
|
* Client (UI, datapack editing, session management)
|
|
* Backend (accounts, SessionZeroDB, P2P prep)
|
|
* JSON datapack format implementation
|
|
|
|
### **Phase 2: Federation**
|
|
|
|
* Cross-server communication
|
|
* Access controls and search indexing
|
|
|
|
### **Phase 3: Mobile and Plugins**
|
|
|
|
* Cross-platform mobile apps
|
|
* Plugin and API extensibility
|
|
|
|
## **10. Testing & Quality**
|
|
|
|
* **Unit Tests:** Core services (DataPackService, StorageService, NetworkingService) with fixtures for characters/datasets/templates.
|
|
* **Schema Validation:** CI job validates sample packs against JSON Schemas (see section 5.8) and rejects PRs with invalid packs.
|
|
* **Integration Tests:** Import/export round-trips, dependency resolution, and session snapshot/recovery.
|
|
* **Compatibility Matrix:** Validate on Windows and Linux for net9.0; browser target smoke tests where applicable.
|
|
|
|
## **11. Accessibility & Internationalization**
|
|
|
|
* **Accessibility:** Keyboard navigation across all primary views, sufficient color contrast, focus indicators, and screen-reader-friendly labels.
|
|
* **Internationalization:** Resource-based localization for UI strings; UTF-8 throughout; prepare for RTL support; date/number formatting via invariant + locale-aware overlays.
|