Cleaned up the whole szds doc; fixed some discrepencies and made the whole thing cleaner
This commit is contained in:
138
szds.md
138
szds.md
@@ -1,44 +1,80 @@
|
|||||||
# SessionZero Data System
|
# SessionZero Data System
|
||||||
|
|
||||||
|
The formula system is not implemented yet. The `formula` type is reserved in the type system, but it does nothing right now. Formula fields resolve to `0` until the formula system exists.
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
Data is separated into 3 main chunks: systems, games, and datasets. Each of these work together but hold varying information.
|
Data is separated into 3 main chunks: systems, games, and datasets. Each of these work together but hold varying information.
|
||||||
|
|
||||||
|
A system owns its datasets. A dataset always belongs to a system, even if the dataset folder gets pulled out, archived, and installed somewhere else later.
|
||||||
|
|
||||||
|
A game installs exactly one system. That system's datasets are what get installed into the game.
|
||||||
|
|
||||||
The flow goes as such:
|
The flow goes as such:
|
||||||
|
|
||||||
1. Create a System
|
1. Create a System
|
||||||
i. Define a character template
|
- Define a character template
|
||||||
ii. Define data templates
|
- Define data templates
|
||||||
2. Create a Dataset
|
2. Create a Dataset (owned by a System)
|
||||||
i. Reference an existing system for available templates
|
- Reference the owning system for available templates
|
||||||
ii. Create data instances based on the available templates
|
- Create data instances based on the available templates
|
||||||
3. Create a Game
|
3. Create a Game
|
||||||
i. 'Install' an existing system
|
- Install a System
|
||||||
ii. 'Install' various datasets that use the same system
|
- Install the datasets that belong to that system
|
||||||
iii. Install plugins (future feature)
|
- Install plugins (future feature, not covered in this spec)
|
||||||
iv. Create a character from the system template
|
- Create a character from the system's character template
|
||||||
|
|
||||||
## File Specifications
|
## File Specifications
|
||||||
|
|
||||||
### Namespaces and IDs
|
### Namespaces and IDs
|
||||||
|
|
||||||
There are 4 "namespaces" in the sz data pipeline: author, system, dataset, and 'template group' (working name, but essentially is the data type, which are grouped by folders in a dataset), in that order.
|
There are 3 "namespaces" in the sz data pipeline: system, dataset, and data group in that order.
|
||||||
|
|
||||||
Namespaces are accessed with a trailing `:`, ex. the 'szcore' system, made by 'sz', would be `sz:szcore`.
|
Author is just metadata, so it's not part of the ID chain. Author lives as a field inside `system.sz` and `dataset.sz`.
|
||||||
|
|
||||||
All .sz, .szt, and .szo files are given IDs based on the file name when loaded into the local database, and must be unique to their scope.
|
Namespaces are accessed with a trailing `:`, ex. the weapon data group inside the `szcore_data` dataset inside the `szcore` system is `szcore:szcore_data:weapon`.
|
||||||
|
|
||||||
For instance, a data template in the `szcore` system with the file name `item.szt` will be identified as `szcore:item`.
|
IDs for top level files (`system.sz`, `dataset.sz`) come from the `id` field declared inside that file, not the folder name. Folder naming (`author.system_name/`) is a human-readable convention for organizing files on disk, it has no effect on ID resolution.
|
||||||
|
|
||||||
And a data instance in a dataset called `data` with the name `item/coin.szo` (with the `item` template, designated by the folder name) will be identified in the database as `sz:szcore:data:item:coin`.
|
`.szt` and `.szo` files are identified by their file name.
|
||||||
|
|
||||||
Top level .sz files (system.sz, dataset.sz, and game.sz) are identified by the parent folder, for instance a system named `sz.szcore/` will be identified as `sz:szcore`.
|
Scope rules:
|
||||||
|
- A `system_id` is unique across everything installed locally.
|
||||||
|
- A `dataset_id` is unique within its owning system. Two different systems can each have a dataset called `homebrew` with no conflict, since the system segment disambiguates them.
|
||||||
|
- A `data group` (folder name/template name) is unique within its system (for templates) or within its dataset (for data, since it mirrors the data group it belongs to).
|
||||||
|
|
||||||
|
Full resolution path example:
|
||||||
|
|
||||||
|
A data instance in the `szcore_data` dataset (owned by the `szcore` system), inside the `weapon/` folder, named `sword.szo`, resolves as:
|
||||||
|
|
||||||
|
`szcore:szcore_data:weapon:sword`
|
||||||
|
|
||||||
|
`dataset.sz` carries a `system_version` field. It pins the dataset to a specific system version. It's not enforced yet, but it's there so datasets authored now don't end up missing a version pin once versioning is enforced.
|
||||||
|
|
||||||
|
Systems and datasets only exist inside a game right now. A local library that holds systems and datasets outside of any specific game (so they don't need to be duplicated across games) is planned, but not part of this spec yet. When it's added, it will keep the same `system_id:dataset_id` shape, so nothing needs to be re-identified when it moves from library to installed-in-a-game.
|
||||||
|
|
||||||
### Fields
|
### Fields
|
||||||
|
|
||||||
A field is found within a data object, defined by a template.
|
A field is found within a data object, defined by a template.
|
||||||
|
|
||||||
---
|
Types: `text`, `number`, `boolean`, `option`, `list`, `formula`.
|
||||||
|
|
||||||
|
Every type has an enforced default value if one isn't set on the template. If the template author doesn't set `default_value`, it falls back to the type's zero-value:
|
||||||
|
- `text` -> `""`
|
||||||
|
- `number` -> `0`
|
||||||
|
- `boolean` -> `false`
|
||||||
|
- `option` -> unset / no selection
|
||||||
|
- `list` -> empty list
|
||||||
|
|
||||||
|
`formula` fields cannot have a `default_value`, since they're computed, not stored. They resolve to `0` until the formula system is implemented.
|
||||||
|
|
||||||
|
### Resolution & Validation Behavior
|
||||||
|
|
||||||
|
Rules for what happens when a dataset's data doesn't cleanly match the currently installed system's templates.
|
||||||
|
|
||||||
|
- **data group has no matching template in the system** (ex. a dataset has an `armor/` folder but the installed system has no `armor.szt`): a warning is logged, and that group's data is skipped.
|
||||||
|
- **Instance has a field the template no longer defines**: the field is stripped on load.
|
||||||
|
- **Template has a required field the instance doesn't define** (ex. a field got added to the template after the instance was authored): the default value is loaded in at runtime. This does not write back into the `.szo` file, the file on disk stays as-is until something explicitly saves it.
|
||||||
|
|
||||||
## System
|
## System
|
||||||
|
|
||||||
@@ -46,6 +82,8 @@ Holds:
|
|||||||
- Character Template
|
- Character Template
|
||||||
- Data templates
|
- Data templates
|
||||||
|
|
||||||
|
The character template is different from a regular data template. There's only ever one per system, it lives at the system root (not inside `templates/`), and datasets cannot use it. It's only ever used to create a character inside a game.
|
||||||
|
|
||||||
Example Directory Structure:
|
Example Directory Structure:
|
||||||
```text
|
```text
|
||||||
author.system_name/
|
author.system_name/
|
||||||
@@ -113,8 +151,8 @@ type = "formula"
|
|||||||
formula = '(stats.str - 10) / 2'
|
formula = '(stats.str - 10) / 2'
|
||||||
|
|
||||||
[fields.inventory]
|
[fields.inventory]
|
||||||
type = "list" #
|
type = "list"
|
||||||
list_type = "data" # If a list type is `data` then the list_data_source becomes a list of data sources in which the list can pull from, otherwise you can use `number` or `text` for literal values
|
list_type = "data" # if a list type is `data`, data_source becomes a list of data groups the list can pull from. otherwise use `number` or `text` for literal values
|
||||||
data_source = ["items", "weapons"]
|
data_source = ["items", "weapons"]
|
||||||
|
|
||||||
[fields.spells]
|
[fields.spells]
|
||||||
@@ -127,13 +165,12 @@ type = "option"
|
|||||||
option_type = "data"
|
option_type = "data"
|
||||||
data_source = ["weapons"]
|
data_source = ["weapons"]
|
||||||
|
|
||||||
[fields.stats.damage]
|
[fields.stats.damage] # NOTE: Formulas are not implemented yet so this will resolve to a 0
|
||||||
type = "formula"
|
type = "formula"
|
||||||
formula = 'equipped_weapon.calculated_damage'
|
formula = 'equipped_weapon.calculated_damage'
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Example data template file `weapon.szt`:
|
Example data template file `weapon.szt`
|
||||||
```toml
|
```toml
|
||||||
# The data type eg. "item" is pulled from the file name, and can be anything
|
# The data type eg. "item" is pulled from the file name, and can be anything
|
||||||
template_type = "data"
|
template_type = "data"
|
||||||
@@ -150,35 +187,32 @@ required = true
|
|||||||
[fields.value]
|
[fields.value]
|
||||||
type = "number"
|
type = "number"
|
||||||
required = true
|
required = true
|
||||||
default_value = 1.0
|
default_value = 1
|
||||||
|
|
||||||
[fields.base_damage]
|
[fields.base_damage]
|
||||||
type = "number"
|
type = "number"
|
||||||
required = true
|
required = true
|
||||||
default_value = 1.0
|
default_value = 1
|
||||||
|
|
||||||
[fields.skill]
|
[fields.skill]
|
||||||
type = "text"
|
type = "text"
|
||||||
required = true
|
required = true
|
||||||
default_value = "str"
|
default_value = "str"
|
||||||
|
|
||||||
[fields.calculated_damage]
|
[fields.calculated_damage] # NOTE: Formulas are not implemented yet so this will resolve to a 0
|
||||||
type = "formula"
|
type = "formula"
|
||||||
formula = 'base_damage + $PLAYER.stats.modifiers.{skill}'
|
formula = 'base_damage + $PLAYER.stats.modifiers.{skill}'
|
||||||
# TODO: Need to figure out the syntax for this;
|
# TODO: syntax for this still needs to be figured out.
|
||||||
# $PLAYER should be a special variable that gets the current character of the owning player within a session,
|
# $PLAYER is a special variable that gets the current character of the owning player within a session.
|
||||||
# and the local `skill` variable needs to be evaluated as a string value (so it will look for `$PLAYER.stats.modifiers.str` as a number).
|
# the local `skill` variable needs to be evaluated as a string value (so it looks for `$PLAYER.stats.modifiers.str` as a number).
|
||||||
# Not sure about the {} as the syntax though, maybe I should rework the formula type entirely
|
# not sure about the {} syntax, may need to rework the formula type entirely.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Datasets
|
## Datasets
|
||||||
|
|
||||||
Holds:
|
Holds:
|
||||||
- Reference to a System and its templates
|
- Reference to the owning System and its templates
|
||||||
- Data Instance
|
- Data Instances
|
||||||
|
|
||||||
Example Directory structure
|
Example Directory structure
|
||||||
```text
|
```text
|
||||||
@@ -197,10 +231,11 @@ Example `dataset.sz` file
|
|||||||
```toml
|
```toml
|
||||||
id = "szcore_data"
|
id = "szcore_data"
|
||||||
system_id = "szcore"
|
system_id = "szcore"
|
||||||
|
system_version = "1.0"
|
||||||
author = "sz"
|
author = "sz"
|
||||||
```
|
```
|
||||||
|
|
||||||
Example data instance file `sword.szo` (this would use the `szcore.weapon` template from the system defined in the dataset)
|
Example data instance file `sword.szo` (uses the `weapon` template from the owning system)
|
||||||
```toml
|
```toml
|
||||||
author = "sz"
|
author = "sz"
|
||||||
|
|
||||||
@@ -211,7 +246,7 @@ value = "sword"
|
|||||||
value = "Sword"
|
value = "Sword"
|
||||||
|
|
||||||
[fields.value]
|
[fields.value]
|
||||||
value = "100"
|
value = 100
|
||||||
|
|
||||||
[fields.base_damage]
|
[fields.base_damage]
|
||||||
value = 10
|
value = 10
|
||||||
@@ -219,22 +254,19 @@ value = 10
|
|||||||
[fields.skill]
|
[fields.skill]
|
||||||
value = "str"
|
value = "str"
|
||||||
|
|
||||||
# This field is calculated based on the template and its value will change automatically when recalculated
|
# this field is calculated based on the template's formula. resolves to 0 until the formula system exists.
|
||||||
[fields.calculated_damage]
|
[fields.calculated_damage]
|
||||||
value = "10"
|
value = 0
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Games
|
## Games
|
||||||
|
|
||||||
The Game type glues everything together.
|
The Game type glues everything together. A game installs exactly one system. Datasets live nested under that system, since they can't exist independent of it.
|
||||||
|
|
||||||
Holds:
|
Holds:
|
||||||
- System
|
- System
|
||||||
|
- Datasets
|
||||||
- Plugins
|
- Plugins
|
||||||
- Datasets
|
|
||||||
- Player Data
|
- Player Data
|
||||||
- Character Instances
|
- Character Instances
|
||||||
- Gamestate/Data
|
- Gamestate/Data
|
||||||
@@ -243,9 +275,13 @@ Example directory structure:
|
|||||||
```text
|
```text
|
||||||
game_name/
|
game_name/
|
||||||
- game.sz
|
- game.sz
|
||||||
|
- system/
|
||||||
|
- system.sz
|
||||||
|
- datasets/
|
||||||
|
- dataset_a/
|
||||||
|
- dataset_b/
|
||||||
- plugins/
|
- plugins/
|
||||||
- (plugins will be defined in the future)
|
- (plugins will be defined in the future)
|
||||||
- datasets/
|
|
||||||
- player_data/
|
- player_data/
|
||||||
- player_name/
|
- player_name/
|
||||||
- player.sz
|
- player.sz
|
||||||
@@ -257,5 +293,19 @@ game_name/
|
|||||||
|
|
||||||
Example `game.sz` file
|
Example `game.sz` file
|
||||||
```toml
|
```toml
|
||||||
|
id = "my_game"
|
||||||
|
owner = "my_username" # The username that owns this game instance, used for online games in the future but does nothing yet.
|
||||||
|
system_id = "szcore"
|
||||||
|
system_version = "1.0" # Does nothing yet.
|
||||||
|
game_type = "local" # Does nothing yet, but the options are: local, online.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Formula System
|
||||||
|
|
||||||
|
Not implemented yet. The `formula` type exists in the type system and templates can be authored with formula fields, but nothing evaluates them right now, they resolve to `0`.
|
||||||
|
|
||||||
|
Todo list for formulas:
|
||||||
|
- Scope model: what variables are reachable inside a formula (`self`, `$PLAYER`, others?)
|
||||||
|
- Grammar: real expression parser vs simple dot-path substitution
|
||||||
|
- Cycle detection between dependent formula fields
|
||||||
|
- The `$PLAYER.stats.modifiers.{skill}` interpolation syntax used in `weapon.szt` above
|
||||||
|
|||||||
Reference in New Issue
Block a user