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