9.4 KiB
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
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:
- Create a System
- Define a character template
- Define data templates
- Create a Dataset (owned by a System)
- Reference the owning system for available templates
- Create data instances based on the available templates
- Create a Game
- Install a System
- Install the datasets that belong to that system
- Install plugins (future feature, not covered in this spec)
- Create a character from the system's character template
File Specifications
Namespaces and IDs
There are 3 "namespaces" in the sz data pipeline: system, dataset, and data group in that order.
Author is just metadata, so it's not part of the ID chain. Author lives as a field inside system.sz and dataset.sz.
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.
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.
.szt and .szo files are identified by their file name.
Scope rules:
- A
system_idis unique across everything installed locally. - A
dataset_idis unique within its owning system. Two different systems can each have a dataset calledhomebrewwith 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
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->0boolean->falseoption-> unset / no selectionlist-> 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 noarmor.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
.szofile, the file on disk stays as-is until something explicitly saves it.
System
Holds:
- Character Template
- 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:
author.system_name/
- system.sz
- icon.png
- character_template.szt
- templates/
- weapon.szt
Example system.sz file
id = "szcore"
display_name = "SZ Core System"
version = "1.0"
author = "sz"
description = """
A simple core system to base others off of
"""
Example character_template.szt file
template_type = "character"
author = "sz"
[fields.name]
type = "text"
required = true
default_value = "Character 1"
[fields.player_name]
type = "text"
required = false
[fields.level]
type = "number"
required = true
default_value = 1
[fields.race]
type = "option"
required = true
option_type = "data"
data_source = ["races"]
[fields.class]
type = "option"
option_type = "text"
data_source = ["ranger", "fighter", "wizard"]
required = true
[fields.status.is_dead]
type = "boolean"
required = true
default_value = false
[fields.stats.str]
type = "number"
required = true
default_value = 0
[fields.stats.modifiers.str]
type = "formula"
formula = '(stats.str - 10) / 2'
[fields.inventory]
type = "list"
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"]
[fields.spells]
type = "list"
list_type = "text"
data_source = ["fireball", "mage_hand"]
[fields.equipped_weapon]
type = "option"
option_type = "data"
data_source = ["weapons"]
[fields.stats.damage] # NOTE: Formulas are not implemented yet so this will resolve to a 0
type = "formula"
formula = 'equipped_weapon.calculated_damage'
Example data template file weapon.szt
# The data type eg. "item" is pulled from the file name, and can be anything
template_type = "data"
author = "sz"
[fields.id]
type = "text"
required = true
[fields.display_name]
type = "text"
required = true
[fields.value]
type = "number"
required = true
default_value = 1
[fields.base_damage]
type = "number"
required = true
default_value = 1
[fields.skill]
type = "text"
required = true
default_value = "str"
[fields.calculated_damage] # NOTE: Formulas are not implemented yet so this will resolve to a 0
type = "formula"
formula = 'base_damage + $PLAYER.stats.modifiers.{skill}'
# TODO: syntax for this still needs to be figured out.
# $PLAYER is a special variable that gets the current character of the owning player within a session.
# 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 {} syntax, may need to rework the formula type entirely.
Datasets
Holds:
- Reference to the owning System and its templates
- Data Instances
Example Directory structure
author.dataset_name/
- dataset.sz
- icons/
- dataset.png
- weapon/
- sword.png
- data/
- weapon/
- sword.szo
Example dataset.sz file
id = "szcore_data"
system_id = "szcore"
system_version = "1.0"
author = "sz"
Example data instance file sword.szo (uses the weapon template from the owning system)
author = "sz"
[fields.id]
value = "sword"
[fields.display_name]
value = "Sword"
[fields.value]
value = 100
[fields.base_damage]
value = 10
[fields.skill]
value = "str"
# this field is calculated based on the template's formula. resolves to 0 until the formula system exists.
[fields.calculated_damage]
value = 0
Games
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:
- System
- Datasets
- Plugins
- Player Data
- Character Instances
- Gamestate/Data
Example directory structure:
game_name/
- game.sz
- system/
- system.sz
- datasets/
- dataset_a/
- dataset_b/
- plugins/
- (plugins will be defined in the future)
- player_data/
- player_name/
- player.sz
- characters/
- character1.szo // An actual Character instance using the System's template
- game_data/
- (various game related data...)
Example game.sz file
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 inweapon.sztabove