What a sync writes as data
The assets and gameplay tags every sync writes without a compile — the payload, the indexes, the stores, the string tables, the manifest.
All documentation — The generated assets and code
Start here
Concepts
Authoring for a build
Playing a story
The generated assets and code
The plugin and sync
Every sync writes data: assets the editor loads and gameplay tags a Blueprint picks from a tree. None of it needs a compile, which is what lets a writer sync twenty times a day while the programmer keeps working. The typed C++ layer on the next page is what a schema change adds on top; this page is the floor a project always has.
Where it lands
Under the content root set in Project Settings → Plugins → TaleShard — /Game/TaleShard/ by
default — in a Generated/ folder the sync owns. Everything in it is regenerated on every sync and
swept when it is no longer produced; put nothing of your own there.
| Asset | What it is |
|---|---|
| the payload | runtime.json as a TaleShardPayload asset: the resolved story the session plays. A TaleShard Story actor picks it up by itself when the project has only one; otherwise assign it there or on the TaleShard Player component. It names the entity index the same sync wrote, which is how a session finds the index without one being wired in |
| one entity store per definition | the entity rows of that definition, keyed by code, with every field value as a story value. A variable reference holds the variable’s script name (Health, or combat.hp when scoped), the name a script reads it by |
| the entity index | every entity across every definition, by id and by code tag |
| one table store per spreadsheet | TS_Table_<Code>, a TaleShardTableStore: the sheet’s columns and its rows, each row’s cells keyed by column code as story values. Written for every sheet, typed or free-form; a free-form sheet has no data table, so this is where its cells arrive |
| the enum, command, variable, board and node-type indexes | what the project declares, each by id and by tag — the keyed floor the typed layer is a view over |
| the media index | where every synced media file landed, by id and by code. Media files are imported as real textures and sounds beside it |
| one string table per language | the project’s own UI strings, keyed by the language code |
| the manifest | what this sync wrote and from which schema; the sweep’s authority for the folder |
The tags
Every code in the project becomes a gameplay tag under TaleShard., written to
Config/Tags/TaleShardGenerated.ini in your project:
| Set | Tag |
|---|---|
| node types | TaleShard.NodeType.<Code> |
| fields | TaleShard.Field.<Code> |
| repeaters | TaleShard.Repeater.<Code> |
| entities | TaleShard.Entity.<Code> |
| enums and their options | TaleShard.Enum.<Enum>.<Option> |
| variables | TaleShard.Variable.<Code>, or TaleShard.Variable.<Context>.<Code> for a scoped one |
| commands | TaleShard.Command.<Code> |
| boards | TaleShard.Board.<Code> |
| media | TaleShard.Media.<Code> |
A segment is the code sanitised: letters, digits and underscores survive, anything else is dropped,
and a code left with nothing becomes _. The sync notes a segment it had to change in its
diagnostics, unless all it dropped was spaces: a board named The Dock becomes TheDock silently. Two codes that differ only in case are one tag — a
gameplay tag is a name, and names compare without case — so the sync reports the collision and the
first declared wins.
TaleShard does not let a project hold such a pair, of any kind. It compares two codes of one kind
with every character that is not a letter or digit removed and case ignored, so gold, Gold and
go_ld are one code: it refuses the second, and renames the later one of a pair already in a
project when the project is opened. A pair can still arrive — two people creating gold and Gold
at the same moment, or a project synced without being opened since — and the sync then reports
each clashing group as code-clash (warning), naming the codes and the fix: open the project in
TaleShard, then sync again. A pair that differs only through a context’s prefix (act1.alarm beside
act1Alarm) is never renamed automatically; its warning says to rename one of them in TaleShard.
Variables are handled differently: a sync keeps two variables whose codes differ only in case as
two variables, each with a tag of its own. Of such variables, the first by id keeps its code and
each later one takes <Code>_2, <Code>_3 and so on (skipping a code another variable already
holds) — TaleShard.Variable.gold and TaleShard.Variable.Gold_2. The sync reports each renamed
tag, and the variable index keys the variable by that same numbered code (its IndexCode). An
entity’s variable reference holds the code a script reads (Gold), not that index key, so look a
numbered variable up in the index by its id or by Gold_2.
The tags are why a Blueprint never types a string: a handler’s Node Type, a Find Field, a Register Command and a Get Variable all take a tag from the picker, and a code renamed in the editor is a tag gone from the tree after the next sync, visible in every Blueprint that held it.
What a content change does
A line edited, an entity’s field changed, a translation added, a board rewired: the payload and the stores are rewritten and nothing else happens. No tag changes, no C++ is generated, and a running Play-In-Editor session is untouched until it next loads the payload.
What a schema change adds
A field, an enum option, a command parameter, a node type, a variable: the tags change to match, the TaleShard Blueprint nodes’ menus follow, and — when C++ is generated — the typed layer is regenerated. That is the next page.
A Blueprint that uses a name the sync removed, or a field whose type it changed, is reported in the
sync window (BP001) and compiled, so a removed name shows as an error on the node that used it —
see diagnostics.
The report
Every sync ends with a report in the Sync window and the Output Log: what was written, what was swept, what was refused and why. A payload the plugin cannot read — a format version newer than the plugin, a malformed file — refuses the whole sync rather than writing half a folder, because a half-generated project loads and is indistinguishable from a whole one.