Concepts

A collection is three things

A class. class_name Relic extends Resource, in the collection's folder: res://data/relics/relic.gd. Every field is an @export with hints. The members the plugin manages sit between #region DaelokBase and #endregion, and a hash of that region is kept, so the plugin knows when it was edited by hand. Whatever sits outside the region is yours and is never touched. A generated class is not @tool, so none of your code runs inside the editor.

A folder of entries. One .tres file an entry, named by its key: frog_idol.tres. The editor alone writes them, so every file keeps its UID; a change of key renames the file, and the UID goes with it. An entry that has no key yet is Relic_0001.tres.

A metadata file. res://.daelokbase/schemas/Relic.json, for what a script cannot say:

key what it holds
folder where the entries live, in it and the folders under it
key_field, label_field the field that names a file, and the field lists show
fields every managed field with its kind and options (below)
retired fields taken out of the form but kept in the class and the files
layout the form's arrangement, as the Layout tab builds it
canvas_pin [x, y] where the collection's box is pinned on the canvas, or null
preview_scene the scene the Stage shows the entry in
color an html colour for the collection; empty means one hashed from the name
generated_hash the hash of the region as last written
adopted true for a class you wrote by hand

The .daelokbase folder carries a .gdignore: nothing in it is imported, and nothing in it reaches an exported build. Keep it in version control.

Nesting

A collection nests under another when its folder sits inside the other's (res://data/items/weapons/ under res://data/items/), or, failing that, when its class extends the other's. The tree, the canvas and the counts follow that. Each collection's entries are the files of its own class in its folder and the folders under it: ItemsDb.all() gives the items in res://data/items/ and below, and the weapons there belong to WeaponsDb, being of their own class.

Fields and their kinds

A field is a variable with a kind. The kind decides the export line the designer writes and the editor the form uses.

kind the export line notes
string @export var x: String = ""
bbcode @export_multiline var x: String = "" the Stage draws it with a RichTextLabel
number @export var x: float = 0.0, or int; with limits @export_range(min, max, step, "suffix:kg") int when whole; an open end gets or_greater
boolean @export var x: bool = false
enum @export_enum("A", "B") var x: String = "A" stores the option's text
texture @export var x: Texture2D with h_frames, v_frames, fps and pixel_art in the metadata the Stage plays it as a spritesheet
audio @export var x: AudioStream
array @export var x: Array[String] = []; also of float, int, Texture2D, AudioStream min_items and max_items are checked by the validator
id @export var x: StringName = &"" the key, filled in by the id mode
reference, hard @export var x: OtherClass holds the other entry itself
reference, soft @export var x: StringName = &"" holds the other entry's key, picked from a list, checked by the validator
group @export var rows: Array[RelicEffects] = [] a Repeating Group: rows of a row class of its own

Keys, labels and id modes

The key field names the file and is what soft references and loaders look up. The label field is what lists show; without one, the key is shown, and without a key, the file's name. An id field has a mode:

  • manual: you type it. Until you do, the file is Relic_0001.tres.
  • slug: made from another field, with a separator and a prefix: r-frog-idol.
  • increment: the next number after the highest so far, with a prefix and padding: relic_013.
  • uuid: a version 4 uuid.

Groups

A group is a Repeating Group: a field that holds rows, each row an instance of a row class written beside the collection's class (ItemsStatEffects for the stat_effects of Items). The rows are inline sub-resources of the entry's file, so an entry stays one file. A group's columns are the fields of its row class; they are edited on the Schema tab under the group, and a change to them is a migration over every row of every entry.

References

A hard reference holds the other entry, as Godot resources refer to each other. A soft one holds the other entry's key as a StringName: it survives renames and needs nothing loaded. Both are picked from a list in the form, drawn as arcs on the canvas, and counted in an entry's Used by on the Stage. The validator flags a soft reference whose key the target no longer has.

Retiring

A field you take out is retired, not deleted. It stays in the class as an @export_storage member, hidden from the form and the table but with its data kept in every file, and its values are also written to res://.daelokbase/retired/<Class>.csv, one line per entry. Purge retired removes it from the class and the files for good; the CSV stays.

Snapshots

Before the plugin rewrites a class or a number of entry files (a schema change, a purge, an import of rows) it copies the class script, its metadata, its retired CSV and the entry files to res://.daelokbase/snapshots/<Class>/<time>/, with a manifest. Revert on the Schema tab puts the latest snapshot back and uses it up; the one before it is next. The last ten are kept. None of this goes through Ctrl+Z: a schema change reaches many files, and a Ctrl+Z meant for something else must not undo it.

What reaches a build

The classes, the entries and the loader, plain project files. The .daelokbase folder and the addon do not. Nothing at runtime depends on the plugin.