Cleaning up
This commit is contained in:
parent
7f7a9434a7
commit
ed1827bf04
454
.hidden/.gitignore
vendored
454
.hidden/.gitignore
vendored
@ -1,454 +0,0 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# Tye
|
||||
.tye/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
##
|
||||
## Visual studio for Mac
|
||||
##
|
||||
|
||||
|
||||
# globs
|
||||
Makefile.in
|
||||
*.userprefs
|
||||
*.usertasks
|
||||
config.make
|
||||
config.status
|
||||
aclocal.m4
|
||||
install-sh
|
||||
autom4te.cache/
|
||||
*.tar.gz
|
||||
tarballs/
|
||||
test-results/
|
||||
|
||||
# Mac bundle stuff
|
||||
*.dmg
|
||||
*.app
|
||||
|
||||
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
##
|
||||
## Visual Studio Code
|
||||
##
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
@ -1,34 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SessionZero.Shared", "src\SessionZero.Shared\SessionZero.Shared.csproj", "{86CD0D66-D47D-41DA-B857-F8371AC6E6A9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SessionZero.Client", "src\SessionZero.Client\SessionZero.Client.csproj", "{A6455219-BBF2-4A67-B13C-449249083703}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SessionZero.Server", "src\SessionZero.Server\SessionZero.Server.csproj", "{54824F5A-0499-4BC9-AC8E-88E943C66256}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "szpack", "tools\szpack\szpack.csproj", "{70FDB950-CAE6-4C38-A476-3FC10BFCF6E6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{86CD0D66-D47D-41DA-B857-F8371AC6E6A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{86CD0D66-D47D-41DA-B857-F8371AC6E6A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{86CD0D66-D47D-41DA-B857-F8371AC6E6A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{86CD0D66-D47D-41DA-B857-F8371AC6E6A9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A6455219-BBF2-4A67-B13C-449249083703}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A6455219-BBF2-4A67-B13C-449249083703}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A6455219-BBF2-4A67-B13C-449249083703}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A6455219-BBF2-4A67-B13C-449249083703}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{54824F5A-0499-4BC9-AC8E-88E943C66256}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{54824F5A-0499-4BC9-AC8E-88E943C66256}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{54824F5A-0499-4BC9-AC8E-88E943C66256}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{54824F5A-0499-4BC9-AC8E-88E943C66256}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{70FDB950-CAE6-4C38-A476-3FC10BFCF6E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{70FDB950-CAE6-4C38-A476-3FC10BFCF6E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{70FDB950-CAE6-4C38-A476-3FC10BFCF6E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{70FDB950-CAE6-4C38-A476-3FC10BFCF6E6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@ -1,354 +0,0 @@
|
||||
# **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.
|
||||
@ -1,2 +0,0 @@
|
||||
Samples:
|
||||
- This folder will include sample datapacks
|
||||
@ -1,15 +0,0 @@
|
||||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="SessionZero.Client.App"
|
||||
xmlns:local="using:SessionZero.Client"
|
||||
RequestedThemeVariant="Default">
|
||||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
|
||||
|
||||
<Application.DataTemplates>
|
||||
<local:ViewLocator/>
|
||||
</Application.DataTemplates>
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
@ -1,47 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Data.Core;
|
||||
using Avalonia.Data.Core.Plugins;
|
||||
using System.Linq;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using SessionZero.Client.ViewModels;
|
||||
using SessionZero.Client.Views;
|
||||
|
||||
namespace SessionZero.Client;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
|
||||
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
|
||||
DisableAvaloniaDataAnnotationValidation();
|
||||
desktop.MainWindow = new MainWindow
|
||||
{
|
||||
DataContext = new MainWindowViewModel(),
|
||||
};
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
|
||||
private void DisableAvaloniaDataAnnotationValidation()
|
||||
{
|
||||
// Get an array of plugins to remove
|
||||
var dataValidationPluginsToRemove =
|
||||
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
|
||||
|
||||
// remove each entry found
|
||||
foreach (var plugin in dataValidationPluginsToRemove)
|
||||
{
|
||||
BindingPlugins.DataValidators.Remove(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 172 KiB |
@ -1,21 +0,0 @@
|
||||
using Avalonia;
|
||||
using System;
|
||||
|
||||
namespace SessionZero.Client;
|
||||
|
||||
sealed class Program
|
||||
{
|
||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||
// yet and stuff might break.
|
||||
[STAThread]
|
||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.WithInterFont()
|
||||
.LogToTrace();
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\"/>
|
||||
<AvaloniaResource Include="Assets\**"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.3.6"/>
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.3.6"/>
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.6"/>
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.6"/>
|
||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.6">
|
||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SessionZero.Shared\SessionZero.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using SessionZero.Client.ViewModels;
|
||||
|
||||
namespace SessionZero.Client;
|
||||
|
||||
public class ViewLocator : IDataTemplate
|
||||
{
|
||||
public Control? Build(object? param)
|
||||
{
|
||||
if (param is null)
|
||||
return null;
|
||||
|
||||
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
|
||||
var type = Type.GetType(name);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return (Control)Activator.CreateInstance(type)!;
|
||||
}
|
||||
|
||||
return new TextBlock { Text = "Not Found: " + name };
|
||||
}
|
||||
|
||||
public bool Match(object? data)
|
||||
{
|
||||
return data is ViewModelBase;
|
||||
}
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
namespace SessionZero.Client.ViewModels;
|
||||
|
||||
public partial class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
public string Greeting { get; } = "Welcome to Avalonia!";
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace SessionZero.Client.ViewModels;
|
||||
|
||||
public class ViewModelBase : ObservableObject
|
||||
{
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="using:SessionZero.Client.ViewModels"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SessionZero.Client.Views.MainWindow"
|
||||
x:DataType="vm:MainWindowViewModel"
|
||||
Icon="/Assets/avalonia-logo.ico"
|
||||
Title="SessionZero.Client">
|
||||
|
||||
<Design.DataContext>
|
||||
<!-- This only sets the DataContext for the previewer in an IDE,
|
||||
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
|
||||
<vm:MainWindowViewModel/>
|
||||
</Design.DataContext>
|
||||
|
||||
<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
|
||||
</Window>
|
||||
@ -1,11 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace SessionZero.Client.Views;
|
||||
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<!-- This manifest is used on Windows only.
|
||||
Don't remove it as it might cause problems with window transparency and embedded controls.
|
||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||
<assemblyIdentity version="1.0.0.0" name="SessionZero.Client.Desktop"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on
|
||||
and is designed to work with. Uncomment the appropriate elements
|
||||
and Windows will automatically select the most compatible environment. -->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
@ -1,41 +0,0 @@
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.MapOpenApi();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
var summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
app.MapGet("/weatherforecast", () =>
|
||||
{
|
||||
var forecast = Enumerable.Range(1, 5).Select(index =>
|
||||
new WeatherForecast
|
||||
(
|
||||
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
|
||||
Random.Shared.Next(-20, 55),
|
||||
summaries[Random.Shared.Next(summaries.Length)]
|
||||
))
|
||||
.ToArray();
|
||||
return forecast;
|
||||
})
|
||||
.WithName("GetWeatherForecast");
|
||||
|
||||
app.Run();
|
||||
|
||||
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
|
||||
{
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:5227",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "https://localhost:7090;http://localhost:5227",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.7"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@ -1,6 +0,0 @@
|
||||
@SessionZero.Server_HostAddress = http://localhost:5227
|
||||
|
||||
GET {{SessionZero.Server_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
@ -1,8 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
namespace SessionZero.Shared.Models;
|
||||
|
||||
public class CharacterTemplate : TemplateBase
|
||||
{
|
||||
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
namespace SessionZero.Shared.Models;
|
||||
|
||||
/// <summary>
|
||||
/// The model for a datapack (used for the szpack.json file).
|
||||
/// </summary>
|
||||
public class Datapack
|
||||
{
|
||||
public required Guid Id { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public required string Version { get; set; }
|
||||
public required string Author { get; set; }
|
||||
public required string License { get; set; }
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public required DateTime CreatedAt { get; set; }
|
||||
public required string SessionZeroVersion { get; set; }
|
||||
|
||||
public List<DatapackDependency> Dependencies { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a dependency of a datapack.
|
||||
/// </summary>
|
||||
public class DatapackDependency
|
||||
{
|
||||
public required Guid Id { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public required string Version { get; set; }
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
using SessionZero.Shared.Schema;
|
||||
|
||||
namespace SessionZero.Shared.Models;
|
||||
|
||||
public class Dataset : SzObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Arbitrary string used to identify the dataset type (e.g. "items", "quests", "npcs", etc.).
|
||||
/// </summary>
|
||||
public required string DatasetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The entries in the dataset.
|
||||
/// </summary>
|
||||
public required Dictionary<string, DatasetEntry> Entries { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a FieldValue from the dataset using a dot-separated path.
|
||||
/// Format: [EntryName].[FieldName] or [EntryName].[GroupName].[FieldName]
|
||||
/// </summary>
|
||||
/// <param name="fieldName">The dot-separated path to the field.</param>
|
||||
/// <returns>The FieldValue if found, otherwise null.</returns>
|
||||
public FieldValue? GetField(string fieldName)
|
||||
{
|
||||
var split = fieldName.Split('.');
|
||||
|
||||
// Path must contain at least EntryName.FieldName (length 2)
|
||||
if (split.Length < 2 || split.Length > 3)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var entryName = split[0];
|
||||
if (!Entries.TryGetValue(entryName, out var entry))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (split.Length == 2)
|
||||
{
|
||||
// Format: EntryName.FieldName (Top-level field)
|
||||
var fName = split[1];
|
||||
|
||||
if (entry.TopLevelFields is null) return null;
|
||||
|
||||
return entry.TopLevelFields.TryGetValue(fName, out var value) ? value : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Format: EntryName.GroupName.FieldName
|
||||
var groupName = split[1];
|
||||
var fName = split[2];
|
||||
|
||||
if (entry.Groups is null) return null;
|
||||
|
||||
var dataGroup = entry.Groups.FirstOrDefault(g => g.Name == groupName);
|
||||
|
||||
if (dataGroup is null || dataGroup.Fields is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return dataGroup.Fields.TryGetValue(fName, out var value) ? value : null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a FieldValue in the dataset using a dot-separated path.
|
||||
/// Format: [EntryName].[FieldName] or [EntryName].[GroupName].[FieldName]
|
||||
/// </summary>
|
||||
/// <param name="fieldName">The dot-separated path to the field.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
/// <returns>True if the value was set, false otherwise</returns>
|
||||
public static bool SetField(string fieldName, FieldValue value)
|
||||
{
|
||||
// TODO: Implementation for SetField
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
using SessionZero.Shared.Schema;
|
||||
|
||||
namespace SessionZero.Shared.Models;
|
||||
|
||||
public class SessionTemplate : TemplateBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Reference to the required Character Template for character creation in this session.
|
||||
/// </summary>
|
||||
public required CharacterTemplateLink CharacterTemplateLink { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of required Datasets that this session template depends on
|
||||
/// (datapack ids must be present in the DatapackDependency list in the datapack object)
|
||||
/// </summary>
|
||||
public required List<DatasetLink> RequiredDatasets { get; set; } = new();
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
namespace SessionZero.Shared.Models;
|
||||
|
||||
public class SzObject
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public required string SzType { get; set; }
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public string Icon { get; set; } = string.Empty;
|
||||
public required string Version { get; set; }
|
||||
public required string SchemaVersion { get; set; }
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
using SessionZero.Shared.Schema;
|
||||
|
||||
namespace SessionZero.Shared.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for templates.
|
||||
/// </summary>
|
||||
public class TemplateBase : SzObject
|
||||
{
|
||||
public required List<TemplateSection> Sections { get; set; } = new();
|
||||
}
|
||||
@ -1,120 +0,0 @@
|
||||
namespace SessionZero.Shared.Schema;
|
||||
|
||||
/// <summary>
|
||||
/// Valid types for fields.
|
||||
/// </summary>
|
||||
public enum FieldType
|
||||
{
|
||||
Text,
|
||||
MultiText,
|
||||
Number,
|
||||
Boolean,
|
||||
Formula,
|
||||
List
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a list of allowed values for a field with type List.
|
||||
/// </summary>
|
||||
public class SzListType
|
||||
{
|
||||
// NOTE: Only one of these lists should be allowed
|
||||
public List<string>? AllowedDatasetTypes { get; set; }
|
||||
public List<DatasetLink>? AllowedDatasetIds { get; set; }
|
||||
public string? CustomValues { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a formula field.
|
||||
/// </summary>
|
||||
public class SzFormulaType
|
||||
{
|
||||
// TODO: Implement a way to parse formulas
|
||||
public string? Formula { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to link a dataset in other data or template objects.
|
||||
/// </summary>
|
||||
public class DatasetLink
|
||||
{
|
||||
public required Guid DatapackId { get; set; }
|
||||
public required string DatasetId { get; set; }
|
||||
public required string Version { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to link a character template in other template objects.
|
||||
/// </summary>
|
||||
public class CharacterTemplateLink
|
||||
{
|
||||
public required Guid DatapackId { get; set; }
|
||||
public required string TemplateId { get; set; }
|
||||
public required string Version { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a field value.
|
||||
/// </summary>
|
||||
public class FieldValue
|
||||
{
|
||||
public required FieldType Type { get; set; }
|
||||
public required object Value { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a group of fields in a dataset.
|
||||
/// </summary>
|
||||
public class DataGroup
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public required Dictionary<string, FieldValue> Fields { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a dataset entry used in datasets.
|
||||
/// </summary>
|
||||
public class DatasetEntry
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public string Icon { get; set; } = string.Empty;
|
||||
|
||||
public Dictionary<string, FieldValue>? TopLevelFields { get; set; } = new();
|
||||
public List<DataGroup>? Groups { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a section in a template that houses multiple groups.
|
||||
/// </summary>
|
||||
public class TemplateSection
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public required List<TemplateGroup> Groups { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a group of fields in a template.
|
||||
/// </summary>
|
||||
public class TemplateGroup
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public required List<TemplateFieldDefinition>? Fields { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a field definition in a template
|
||||
/// (Does not hold actual field values as templates are meant to be filled in upon instance creation).
|
||||
/// </summary>
|
||||
public class TemplateFieldDefinition
|
||||
{
|
||||
public required string Id { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public required FieldType Type { get; set; }
|
||||
public object? DefaultValue { get; set; }
|
||||
public DatasetLink? DatasetLink { get; set; }
|
||||
}
|
||||
@ -1,172 +0,0 @@
|
||||
using System.Text.Json;
|
||||
using SessionZero.Shared.Models;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace SessionZero.Shared.Services;
|
||||
|
||||
public static class DatapackService
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Datapack model with required metadata.
|
||||
/// </summary>
|
||||
/// <param name="name">The display name of the datapack.</param>
|
||||
/// <param name="version">The initial version string (e.g., "1.0.0").</param>
|
||||
/// <param name="author">The pack creator's name.</param>
|
||||
/// <param name="license">The license (e.g., "CC-BY-SA-4.0").</param>
|
||||
/// <returns>A fully initialized Datapack model.</returns>
|
||||
public static Datapack CreateEmptyDatapack(string name, string version, string author, string license)
|
||||
{
|
||||
return new Datapack
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = name,
|
||||
Version = version,
|
||||
Author = author,
|
||||
License = license,
|
||||
Description = String.Empty,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
SessionZeroVersion = "0.0.1",
|
||||
Dependencies = new()
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes a Datapack model and saves it to a file named 'szpack.json'
|
||||
/// inside a new subdirectory named after the datapack's slug.
|
||||
/// </summary>
|
||||
/// <param name="datapack">The Datapack object to save.</param>
|
||||
/// <param name="parentDirectoryPath">The directory where the new datapack folder will be created.</param>
|
||||
/// <returns>The full path to the created szpack.json file.</returns>
|
||||
public static async Task<string> SaveDatapackMetadataAsync(Datapack datapack, string parentDirectoryPath)
|
||||
{
|
||||
var packDirectoryName = datapack.Name.ToLower().Replace(' ', '-').Trim();
|
||||
var packRootDirectory = Path.Combine(parentDirectoryPath, packDirectoryName);
|
||||
|
||||
Directory.CreateDirectory(packRootDirectory);
|
||||
|
||||
var filePath = Path.Combine(packRootDirectory, "szpack.json");
|
||||
|
||||
var jsonString = JsonSerializer.Serialize(datapack, JsonOptions);
|
||||
await File.WriteAllTextAsync(filePath, jsonString);
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes an SzObject (Dataset, Template, etc.) and saves it to a file.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object, must inherit from SzObject.</typeparam>
|
||||
/// <param name="szObject">The object to save.</param>
|
||||
/// <param name="directoryPath">The specific subdirectory (e.g., 'datasets') within the datapack root.</param>
|
||||
/// <returns>The full path to the created JSON file.</returns>
|
||||
public static async Task<string> SaveSzObjectAsync<T>(T szObject, string directoryPath) where T : SzObject
|
||||
{
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
|
||||
var fileName = $"{szObject.Id}.json";
|
||||
var filePath = Path.Combine(directoryPath, fileName);
|
||||
var jsonString = JsonSerializer.Serialize(szObject, JsonOptions);
|
||||
await File.WriteAllTextAsync(filePath, jsonString);
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines and creates the standard directory structure for a SessionZero datapack.
|
||||
/// </summary>
|
||||
/// <param name="rootPath">The root directory path of the new datapack.</param>
|
||||
/// <returns>A dictionary containing the standard folder names and their absolute paths.</returns>
|
||||
public static Dictionary<string, string> CreateDatapackDirectoryStructure(string rootPath)
|
||||
{
|
||||
var structure = new Dictionary<string, string>
|
||||
{
|
||||
{ "datasets", Path.Combine(rootPath, "datasets") },
|
||||
{ "character_templates", Path.Combine(rootPath, "characters") },
|
||||
{ "session_templates", Path.Combine(rootPath, "sessions") },
|
||||
{ "media", Path.Combine(rootPath, "media") },
|
||||
{ "images", Path.Combine(rootPath, "media", "images") }
|
||||
};
|
||||
|
||||
foreach (var path in structure.Values)
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
return structure;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compresses a datapack directory into a .szpack zip archive.
|
||||
/// </summary>
|
||||
/// <param name="sourceDirectoryPath">The path to the datapack's root directory.</param>
|
||||
/// <param name="outputFilePath">The full path and filename for the output .szpack file.</param>
|
||||
public static void PackDatapack(string sourceDirectoryPath, string outputFilePath)
|
||||
{
|
||||
if (!Directory.Exists(sourceDirectoryPath))
|
||||
{
|
||||
throw new DirectoryNotFoundException($"Source directory not found: {sourceDirectoryPath}");
|
||||
}
|
||||
|
||||
if (File.Exists(outputFilePath))
|
||||
{
|
||||
File.Delete(outputFilePath);
|
||||
}
|
||||
|
||||
ZipFile.CreateFromDirectory(sourceDirectoryPath, outputFilePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts a .szpack zip archive into a target directory.
|
||||
/// </summary>
|
||||
/// <param name="sourceFilePath">The path to the .szpack file.</param>
|
||||
/// <param name="destinationDirectoryPath">The directory where the contents will be extracted.</param>
|
||||
public static void UnpackDatapack(string sourceFilePath, string destinationDirectoryPath)
|
||||
{
|
||||
if (!File.Exists(sourceFilePath))
|
||||
{
|
||||
throw new FileNotFoundException($"Datapack file not found: {sourceFilePath}");
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(destinationDirectoryPath);
|
||||
|
||||
ZipFile.ExtractToDirectory(sourceFilePath, destinationDirectoryPath, overwriteFiles: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes and loads the core Datapack metadata (szpack.json) from a directory.
|
||||
/// </summary>
|
||||
/// <param name="datapackRootPath">The path to the datapack's root directory.</param>
|
||||
/// <returns>A Datapack model containing the metadata.</returns>
|
||||
/// <exception cref="FileNotFoundException">Thrown if szpack.json is not found.</exception>
|
||||
/// <exception cref="JsonException">Thrown if deserialization fails.</exception>
|
||||
public static async Task<Datapack> LoadDatapackMetadataAsync(string datapackRootPath)
|
||||
{
|
||||
var filePath = Path.Combine(datapackRootPath, "szpack.json");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
throw new FileNotFoundException($"The required metadata file 'szpack.json' was not found in: {datapackRootPath}", filePath);
|
||||
}
|
||||
|
||||
var jsonString = await File.ReadAllTextAsync(filePath);
|
||||
|
||||
var datapack = JsonSerializer.Deserialize<Datapack>(jsonString, JsonOptions);
|
||||
|
||||
if (datapack is null)
|
||||
{
|
||||
throw new JsonException($"Failed to deserialize szpack.json from {filePath}. The file may be corrupt or invalid.");
|
||||
}
|
||||
|
||||
return datapack;
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@ -1,45 +0,0 @@
|
||||
using SessionZero.Shared.Models;
|
||||
|
||||
namespace SessionZero.Shared.Validation;
|
||||
|
||||
public static class DatapackValidator
|
||||
{
|
||||
public static List<string> ValidateDatapack(Datapack datapack)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
|
||||
if (datapack.Id == Guid.Empty) errors.Add("Datapack 'Id' is required and must not be an empty GUID.");
|
||||
|
||||
ValidateRequiredString(errors, datapack.Name, nameof(datapack.Name));
|
||||
ValidateRequiredString(errors, datapack.Version, nameof(datapack.Version));
|
||||
ValidateRequiredString(errors, datapack.Author, nameof(datapack.Author));
|
||||
ValidateRequiredString(errors, datapack.License, nameof(datapack.License));
|
||||
ValidateRequiredString(errors, datapack.SessionZeroVersion, nameof(datapack.SessionZeroVersion));
|
||||
|
||||
if (datapack.CreatedAt == DateTime.MinValue) errors.Add("Datapack 'CreatedAt' is required and must not be an empty DateTime.");
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
public static List<string> ValidateSzObject(SzObject szObject)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
var objectName = szObject.Id;
|
||||
|
||||
ValidateRequiredString(errors, szObject.Id, $"{objectName}'s Id");
|
||||
ValidateRequiredString(errors, szObject.Name, $"{objectName}'s Name");
|
||||
ValidateRequiredString(errors, szObject.SzType, $"{objectName}'s SzType");
|
||||
ValidateRequiredString(errors, szObject.Version, $"{objectName}'s Version");
|
||||
ValidateRequiredString(errors, szObject.SchemaVersion, $"{objectName}'s SchemaVersion");
|
||||
|
||||
// 2. Validate Icon path format (optional/future: e.g., only allows alphanumeric + slashes + extension)
|
||||
// For now, we'll only check if it's not null, which is done by the property definition in SzObject.
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
private static void ValidateRequiredString(List<string> errors, string? value, string fieldName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value)) errors.Add($"'{fieldName}' is required and must not be empty.");
|
||||
}
|
||||
}
|
||||
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* WARNING:
|
||||
* This tool was created by an LLM based on the SessionZero shared lib project, therefore it is subject to errors and does not reflect the architecture of the SessionZero project.
|
||||
* It was created to be used as a quick and dirty validation tool for the szpack format.
|
||||
*/
|
||||
|
||||
using SessionZero.Shared.Models;
|
||||
using SessionZero.Shared.Services;
|
||||
using Spectre.Console;
|
||||
using Spectre.Console.Cli;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace SessionZero.Tools.Packer;
|
||||
|
||||
// Settings class defines the command-line arguments
|
||||
public class CreateSettings : CommandSettings
|
||||
{
|
||||
[CommandArgument(0, "<name>")]
|
||||
[Description("The display name of the datapack (e.g., 'My Fantasy Spells').")]
|
||||
public required string Name { get; init; }
|
||||
|
||||
[CommandArgument(1, "[author]")]
|
||||
[Description("The author's name.")]
|
||||
[DefaultValue("Test Author")]
|
||||
public string Author { get; init; } = "Test Author";
|
||||
|
||||
[CommandOption("-o|--output")]
|
||||
[Description("The parent directory where the new pack folder will be created.")]
|
||||
[DefaultValue(".")]
|
||||
public string Output { get; init; } = Environment.CurrentDirectory;
|
||||
}
|
||||
|
||||
public class CreateCommand : AsyncCommand<CreateSettings>
|
||||
{
|
||||
public override async Task<int> ExecuteAsync([NotNull] CommandContext context, [NotNull] CreateSettings settings, CancellationToken cancellationToken)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"\n[bold white on blue] --- Creating Datapack: '{settings.Name}' --- [/]");
|
||||
|
||||
try
|
||||
{
|
||||
// 1. Create the top-level model and save szpack.json
|
||||
var newPack = DatapackService.CreateEmptyDatapack(settings.Name, "1.0.0", settings.Author, "MIT");
|
||||
var szpackPath = await DatapackService.SaveDatapackMetadataAsync(newPack, settings.Output);
|
||||
var packRootDirectory = Path.GetDirectoryName(szpackPath)!;
|
||||
|
||||
AnsiConsole.MarkupLine($"[green]✅ Created metadata file at: {szpackPath}[/]");
|
||||
|
||||
// 2. Create the standard directory structure
|
||||
var structure = DatapackService.CreateDatapackDirectoryStructure(packRootDirectory);
|
||||
AnsiConsole.MarkupLine($"[green]✅ Created standard directories at: {packRootDirectory}[/]");
|
||||
|
||||
// 3. Create and save test objects
|
||||
await CreateTestObjects(packRootDirectory, structure);
|
||||
|
||||
AnsiConsole.MarkupLine("\n[bold]Creation Complete![/] Use 'szpack pack' to compress it.");
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"\n[bold white on red]❌ ERROR:[/] Failed to create datapack. Details: {ex.Message}");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method for creating test objects (copied from previous Program.cs)
|
||||
private static async Task CreateTestObjects(string rootPath, Dictionary<string, string> structure)
|
||||
{
|
||||
// ... (Test object creation logic remains the same, ensure you have the necessary usings in this file)
|
||||
|
||||
// --- Test object creation logic (omitted for brevity, assume the previous logic is here) ---
|
||||
var testDataset = new Dataset { /* ... test data ... */ Id = "basic-attributes", Name = "Basic Character Attributes", SzType = "Dataset", Version = "1.0.0", SchemaVersion = "1.0.0", DatasetType = "Attribute", Entries = new() };
|
||||
var dsPath = await DatapackService.SaveSzObjectAsync(testDataset, structure["datasets"]);
|
||||
AnsiConsole.MarkupLine($" -> Saved Test Dataset: [yellow]{Path.GetFileName(dsPath)}[/]");
|
||||
|
||||
var testCharTemplate = new CharacterTemplate { /* ... test data ... */ Id = "default-char-sheet", Name = "Default Character Template", SzType = "Template", Version = "1.0.0", SchemaVersion = "1.0.0", Sections = new() };
|
||||
var charPath = await DatapackService.SaveSzObjectAsync(testCharTemplate, structure["character_templates"]);
|
||||
AnsiConsole.MarkupLine($" -> Saved Test Character Template: [yellow]{Path.GetFileName(charPath)}[/]");
|
||||
|
||||
var testSessionTemplate = new SessionTemplate
|
||||
{
|
||||
/* ... test data ... */ Id = "basic-encounter",
|
||||
Name = "Basic Encounter Template",
|
||||
SzType = "Template",
|
||||
Version = "1.0.0",
|
||||
SchemaVersion = "1.0.0",
|
||||
CharacterTemplateLink = new()
|
||||
{
|
||||
DatapackId = Guid.Empty,
|
||||
TemplateId = testCharTemplate.Id,
|
||||
Version = testCharTemplate.Version
|
||||
},
|
||||
RequiredDatasets = new()
|
||||
{
|
||||
new()
|
||||
{
|
||||
DatapackId = Guid.Empty,
|
||||
DatasetId = testDataset.Id,
|
||||
Version = testDataset.Version
|
||||
}
|
||||
},
|
||||
Sections = new()
|
||||
};
|
||||
var sessionPath = await DatapackService.SaveSzObjectAsync(testSessionTemplate, structure["session_templates"]);
|
||||
AnsiConsole.MarkupLine($" -> Saved Test Session Template: [yellow]{Path.GetFileName(sessionPath)}[/]");
|
||||
}
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* WARNING:
|
||||
* This tool was created by an LLM based on the SessionZero shared lib project, therefore it is subject to errors and does not reflect the architecture of the SessionZero project.
|
||||
* It was created to be used as a quick and dirty validation tool for the szpack format.
|
||||
*/
|
||||
|
||||
using SessionZero.Shared.Services;
|
||||
using Spectre.Console;
|
||||
using Spectre.Console.Cli;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace SessionZero.Tools.Packer;
|
||||
|
||||
public class PackSettings : CommandSettings
|
||||
{
|
||||
[CommandArgument(0, "<input>")]
|
||||
[Description("The root directory of the datapack to pack.")]
|
||||
public required string Input { get; init; }
|
||||
}
|
||||
|
||||
public class PackCommand : Command<PackSettings>
|
||||
{
|
||||
public override int Execute([NotNull] CommandContext context, [NotNull] PackSettings settings, CancellationToken cancellationToken)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"\n[bold white on blue] --- Packing Datapack: {settings.Input} --- [/]");
|
||||
try
|
||||
{
|
||||
var packDirectoryName = new DirectoryInfo(settings.Input).Name;
|
||||
var outputFilePath = Path.Combine(Path.GetDirectoryName(settings.Input) ?? Environment.CurrentDirectory, $"{packDirectoryName}.szpack");
|
||||
|
||||
DatapackService.PackDatapack(settings.Input, outputFilePath);
|
||||
|
||||
AnsiConsole.MarkupLine($"[green]✅ Successfully created archive: {outputFilePath}[/]");
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"\n[bold white on red]❌ ERROR:[/] Failed to pack datapack. Details: {ex.Message}");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* WARNING:
|
||||
* This tool was created by an LLM based on the SessionZero shared lib project, therefore it is subject to errors and does not reflect the architecture of the SessionZero project.
|
||||
* It was created to be used as a quick and dirty validation tool for the szpack format.
|
||||
*/
|
||||
|
||||
using Spectre.Console.Cli;
|
||||
|
||||
namespace SessionZero.Tools.Packer;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
static int Main(string[] args)
|
||||
{
|
||||
var app = new CommandApp();
|
||||
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.SetApplicationName("szpack");
|
||||
|
||||
config.AddCommand<CreateCommand>("create")
|
||||
.WithDescription("Creates a new datapack directory with test objects.");
|
||||
|
||||
config.AddCommand<PackCommand>("pack")
|
||||
.WithDescription("Compresses a datapack directory into a .szpack file.");
|
||||
|
||||
config.AddCommand<UnpackCommand>("unpack")
|
||||
.WithDescription("Extracts a .szpack file and displays its metadata.");
|
||||
|
||||
// Optional: Set a default command if no command is specified
|
||||
// config.SetDefaultCommand<HelpCommand>();
|
||||
});
|
||||
|
||||
return app.Run(args);
|
||||
}
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* WARNING:
|
||||
* This tool was created by an LLM based on the SessionZero shared lib project, therefore it is subject to errors and does not reflect the architecture of the SessionZero project.
|
||||
* It was created to be used as a quick and dirty validation tool for the szpack format.
|
||||
*/
|
||||
|
||||
using SessionZero.Shared.Services;
|
||||
using Spectre.Console;
|
||||
using Spectre.Console.Cli;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace SessionZero.Tools.Packer;
|
||||
|
||||
public class UnpackSettings : CommandSettings
|
||||
{
|
||||
[CommandArgument(0, "<input>")]
|
||||
[Description("The path to the .szpack file.")]
|
||||
public required string Input { get; init; }
|
||||
|
||||
[CommandOption("-o|--output")]
|
||||
[Description("The directory where the pack will be extracted.")]
|
||||
[DefaultValue("unpacked")]
|
||||
public string Output { get; init; } = "unpacked";
|
||||
}
|
||||
|
||||
public class UnpackCommand : AsyncCommand<UnpackSettings>
|
||||
{
|
||||
public override async Task<int> ExecuteAsync([NotNull] CommandContext context, [NotNull] UnpackSettings settings, CancellationToken cancellationToken)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"\n[bold white on blue] --- Unpacking Datapack: {settings.Input} --- [/]");
|
||||
try
|
||||
{
|
||||
// Unpack the archive
|
||||
DatapackService.UnpackDatapack(settings.Input, settings.Output);
|
||||
AnsiConsole.MarkupLine($"[green]✅ Successfully unpacked archive to: {settings.Output}[/]");
|
||||
|
||||
// Load and display the core data
|
||||
var datapack = await DatapackService.LoadDatapackMetadataAsync(settings.Output);
|
||||
|
||||
AnsiConsole.MarkupLine("\n[bold]--- Datapack Info (szpack.json) ---[/]");
|
||||
AnsiConsole.MarkupLine($"[yellow]ID:[/]\t\t{datapack.Id}");
|
||||
AnsiConsole.MarkupLine($"[yellow]Name:[/]\t{datapack.Name}");
|
||||
AnsiConsole.MarkupLine($"[yellow]Version:[/]\t{datapack.Version}");
|
||||
AnsiConsole.MarkupLine($"[yellow]Author:[/]\t{datapack.Author}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"\n[bold white on red]❌ ERROR:[/] Failed to unpack or load datapack. Details: {ex.Message}");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
# SZPACK CLI Tool
|
||||
|
||||
## ***WARNING:***
|
||||
This tool was created by an LLM based on the SessionZero shared lib project, therefore it is subject to errors and does not reflect the architecture of the SessionZero project.
|
||||
It was created to be used as a quick and dirty validation tool for the szpack format.
|
||||
|
||||
## Usage
|
||||
* `szpack create <name>`: Creates a sample datapack directory with a given name
|
||||
* `szpack pack <directory>`: Packs a datapack directory into a szpack file (must be a valid datapack)
|
||||
* `szpack unpack <name.szpack>`: Unpacks a .szpack file into a datapack directory and displays some metadata
|
||||
@ -1,19 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\SessionZero.Shared\SessionZero.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Spectre.Console" Version="0.52.1-preview.0.5" />
|
||||
<PackageReference Include="Spectre.Console.Cli" Version="0.52.1-preview.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@ -1,2 +0,0 @@
|
||||
Planned tools:
|
||||
- szpack: a cli tool for validating and packing szpack archives
|
||||
Loading…
Reference in New Issue
Block a user