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.