Editing and Validation
Use code and visual YAML editing, class lookup, Problems, and recovery.
Edit YAML
Section titled “Edit YAML”Open Explorer and editor to browse project files, create a YAML document or folder, and edit
source in the code editor. File → New document lists supported KDataForge document types.
Tabs show open files and error counts. Use Catalog for one reflected class path or Array
catalog to review a replacement for a list. Rename ID (F2) previews generated IDs and
affected project references before applying. Save with Ctrl+S; Save all is Ctrl+Alt+S.
Visual editor offers typed fields for a selected YAML document and a live YAML preview. Its class pickers use the bound reflection archive. Multi-document files have document tabs. If a YAML construct cannot be represented safely in the form, the editor asks you to open Code editor and leaves source unchanged. Raw YAML remains the source of truth in both modes.
For pack configuration, choose File → New document
and the type Config. The dialog adds the required .config.yml ending when it is missing (and
refuses that ending for any other type) and starts the file from a skeleton with a slider and a
checkbox. The Document template list offers Config category class, which creates the
UFGCategory subclass that groups the fields. The Visual editor shows the category and fields
of a config document, quotes values that start with {, and leaves typed references such as
cfg:balance.ironSpeed unquoted. See
Configuration, references and templates.
Both editors detect when the disk version changes after a file was opened. Compare or reload before overwriting it. A recoverable unsaved buffer appears under Recovery; see Operations and releases.
When opening a Visual editor link or switching projects, the requested file is checked against the current project’s refreshed file list. A missing file or folder target falls back to the first YAML file; a project without YAML opens no document. Project-bound Code and Visual views accept existing files only when their resolved physical paths stay inside the project root. Symlinks and junctions pointing inside that root are supported; outside or unresolved targets are refused.
Pack manager → Documents also edits YAML inline with Monaco, using the file’s actual native URI and the same dirty buffer as the full editor. Save writes explicitly; Revert returns to the current loaded baseline, which advances to the saved text after a successful Save. Open file in editor keeps the latest changes unsaved. See Projects and Packs for conflict handling and other supported text files. Inline YAML reuses completion, hover, signature help, definitions, semantic highlighting, and diagnostics from the existing language server. These results require the enabled, ready language-server module. Text editing remains available when it is disabled; the enabled linter module provides explicit lint runs.
Native code suggestions
Section titled “Native code suggestions”In the standalone Code-OSS editor, Ctrl+Space opens live suggestions at the cursor. A
property path: uses the current patch’s target and inherited reflected fields. A target
list offers fields with matching names and types on every selected class. Already used
fields stay selectable, sort after unused fields and show in use, line … for the current
patch. This also works while the next YAML value is incomplete.
The suggestion list shows property names and C++ types. Its adjacent details panel shows the declaring class, exported description and units when available, supported operation chips, and a YAML value example. The source heading uses the bound datapack’s actual name. Missing reflection metadata stays absent. Class lists containing more than 200 matches request fresh results as you refine the text.
| Action | Result |
|---|---|
Enter | Insert the selected field |
Tab on a reflected field that supports set | Insert the field and add op: set if no sibling operation exists |
| Click an operation chip | Insert the field with that operation; replace an existing simple sibling operation while preserving its quotes and comment |
Ctrl+Z | Undo the field and operation together |
Ctrl+Space | Request suggestions for the current field, operation, class reference or supported value |
For example, open a cdo document and use the bound archive to select a recipe target:
type: cdopatches: - target: /Game/FactoryGame/Recipes/Packager/Recipe_PackagedSulfuricAcid.Recipe_PackagedSulfuricAcid_C properties: - path: mManufactoringDuration op: multiply value: 0.5 - path: mPlace the cursor after the final m, press Ctrl+Space, then choose mProduct. Enter
inserts its name; Tab adds op: set; its append chip inserts op: append. Add the
actual value before enabling the pack. The details example explains the value shape and
is not a default copied from the class. The exported game field above is spelled
mManufactoringDuration; use names from your bound archive.
Inline badges show verified field types and exported units, and class references can show
friendly names. Hover a property badge for its exported description, declaring class and
common operations. Missing target metadata suppresses a badge, and an unresolvable nested
path does not display the root property’s type as its leaf type. A real lint error can show
an inline quick-fix button; for example multipy can offer Change to multiply. The
valid multiply operation is supported.
Browse a class reference
Section titled “Browse a class reference”In the full native code editor, a Catalog chip appears beside supported class-reference
values when Catalog and the language server are enabled and current metadata is available.
This includes scalar or list target values, ofClass, allAssetsOfClass, generated-class
parent values, and reflected class properties such as mProducedIn array entries.
Click the chip to browse classes appropriate to that value and review insertion. Ctrl+Space
uses the same class constraints for completion; inserting a match replaces the current value.
Moving the cursor alone does not request suggestions.
The destination determines the class family: a building’s inheritance parent uses a building
descriptor, while a recipe’s mProducedIn uses a buildable actor. Abstract inheritance parents
remain selectable; fields requiring concrete classes exclude them. Missing or conflicting
reflection metadata does not create a guessed picker or class constraint. Bind the correct
datapack before relying on these results. The Pack Documents inline view does not promise
Catalog chips, rename, or code actions.
Validate
Section titled “Validate”For Wwise sounds, create a sound document or use the Wwise sound
wizard. Visual editor exposes sound ID/file plus optional name, description, category and subcategory
fields for generated volume controls. The shared linter checks these fields and the actual recording’s
PCM16 WAV header, mono/stereo channels, sample rate, file size and pack containment. Sound IDs
participate in definition lookup and renaming, including ADA’s mAudioEvent references. See the
complete ADA voice-over pack.
The language server reports live diagnostics while editing. Open Problems to filter by file, active pack, severity, source, or search text. Group results by file, code, or severity; select a diagnostic to jump to its source. Supported quick fixes appear on the selected diagnostic.
Quick fix in Problems requests a fix for the selected diagnostic and previews the exact YAML change. Choose Apply to update the buffer, then save explicitly. Changing the selected diagnostic cancels a pending fix or review. A changed project, file, or source text invalidates the preview; run Quick fix again. Fixes touching multiple files require review in Code editor.
Use Run lint in Problems for a complete project check. You can restart the language server there and export the displayed diagnostics as text, JSON, GitHub annotations, or SARIF. Set lint trigger, debounce, schema paths, and warning policy under Settings → Language server. A successful local lint is followed by an in-game test of the enabled pack; runtime behavior depends on installed mods and game data.
With no bound .kdfdata, schema checks still work. Reflected class, property, and default-value
checks report missing or limited metadata instead of inventing values. See
Datapacks and Codex.
Configuration, references and templates
Section titled “Configuration, references and templates”The editor understands pack configuration: the
config document type, cfg: references, {prefix:body} templates and config: conditions. It
knows every field of your pack and every pack in the project, so it can complete, explain and check
them while you type. Field ids, providers, keys and operators work from your files alone. Classes,
properties, functions, assets and game settings come from a bound
reflection export; without one those lists stay
empty and the editor does not guess.
Completion
Section titled “Completion”Completion opens as you type :, a space, ., {, (, , or a quote. Matches that fit the
destination come first, then conversions, and your own pack’s items before other packs’. Lists that
could hold thousands of entries stop at 200 and refine as you keep typing.
| Where the cursor is | What is offered |
|---|---|
The value of an operation (value, min, max, index, with, including members nested in a struct, list or map value) or a where: operand | cfg:<id> for every field whose type fits the destination property (a boolean field for a bool, any number field for a float, a list field for a set, …), cfg:<Pack>:<id> for fitting fields of other packs, and the stubs cfg:, session:, ags:, option:. Fields that would only convert lossily are not offered. When the destination is unknown, every field is listed. |
After cfg: | The fitting ids of your pack, then the other packs as Pack: entries. After cfg:Pack: the ids of that pack. |
After session:, ags:, option: | Setting ids from the settings index, filtered by the destination type. session: lists session settings and advanced game settings, ags: the advanced game settings, option: the local game options. |
In a string, after { | All 14 providers with a short description, pre-pass providers first |
After {cfg: | Field ids, then Pack: entries. After {session:, {ags:, {option: the setting ids. |
After {item:, {resource:, {building:, {recipe:, {schematic:, {research:, {category: | Concrete classes below the provider’s base class, and the classes your project generates below it |
After {class: | Every class, including function libraries, and the classes your pack generates |
After {dataasset:, {asset: | Your project’s generated assets (data assets for dataasset, every generated asset for asset) and the assets of the export’s asset index |
After {<provider>:<target>: | The target’s properties, with their type and a cold or newActors tag where it applies, and its callable functions as Name(a: T) -> R, marked (implicit class) or (implicit object) when KDataForge passes that argument itself. A function with parameters inserts Name( and opens the parameter hints. |
Inside Name( | Enum names, true and false, or class paths for the active parameter |
After path: of an operation | The properties of the patch target, and after a dot the members of a struct or object property. Top-level properties show their kind and a cold or newActors tag, see below. |
After category: in a config document | UFGCategory subclasses and the category classes your project generates |
Inside config: | Field ids and settings, operators, and option values (see below) |
| Keys and values of a config document | Document keys, the keys of each field (they depend on the field’s type), tooltip and option keys, values for type, valueType, apply, display, multiple and multiline, and for default: true and false for a boolean, the option values for a select |
When a template is the whole value, members whose type does not fit the destination sort last.
In a config: expression the editor reads the left operand and offers what can follow it.
Operators are filtered by its type: a list offers contains; a boolean or string offers ==,
!= (a string also in); a number offers all comparisons and in; && and || are always
available. After a comparison it offers ids that fit, the option values of a select field, and
true or false for a boolean. String literals are written with the quote that suits the YAML
style of the value.
Hover and signature help
Section titled “Hover and signature help”Hover shows a card for:
- a field id, in
cfg:,{cfg:}, an expression, or theidof the field’s own definition: name, type and value type, hot or cold, description, tooltip, default, range, options, limits, category, pack and file; - a setting id (
session:,ags:,option:): display name, value type, tooltip, default, range, options, whether it is session-wide and relevant for dedicated servers, and its source; - an operation
path:: the property with its type, the class it is declared in, and its reload classification with the reason; - a template provider prefix, a target class, and a member (property or function with flags and whether it is callable);
- a class in
category:,parent:,class:,target:,ofClass:orallAssetsOfClass:.
While you type the arguments of a template function, the signature help (opened by ( and ,)
shows Name(a: T, b: U) -> R and highlights the active parameter. A parameter that KDataForge
fills in for you is left out and mentioned in the note. On an op: value the signature help shows
what the operation needs.
Go to definition and references
Section titled “Go to definition and references”Go to definition on a config id in a cfg: reference, a {cfg:} template or a config:
expression jumps to the fields[].id of its *.config.yml, also across packs
(cfg:<pack>:<id>). Find references, started on a reference or on the id of a field,
lists every use in the project. Config ids cannot be renamed with Rename ID, which is only
available for generated ids; change the definition and its uses together.
Cold properties and hot values
Section titled “Cold properties and hot values”Some properties do not update live, see cold properties. The editor reads the classification from the reflection export and its cold-property catalog:
| Situation | Diagnostic |
|---|---|
An operation path: targets a cold or newActors property | property.cold, information by default, with the reason |
| A hot config value (typed reference or template) feeds such an operation | config.hot-into-cold-property (warning) |
| A hot field sits where only load-time values apply | config.hot-in-cold-stage, config.hot-in-condition (warnings) |
A newActors property is not flagged when the patch sets applyToSpawnedActors: true, or when the
document is not a cdo patch (it generates a class, so no actor exists yet). Choose how property.cold appears per project in .kdf-editor.toml:
[lint]coldProperties = "info" # the default; "hint" shows it as a hint, "off" hides itQuick fixes
Section titled “Quick fixes”| Diagnostic | Fix offered |
|---|---|
template.unquoted-start, config.expression-quote | Wrap the value in quotes |
config.case-mismatch | Change to the exact spelling of the field id |
config.unknown-id | Change to the closest existing field id (one fix per near match) |
config.unknown-pack | Change the pack to the closest pack in the project |
setting.unknown-id | Change to the closest setting id of the settings index |
template.unknown-provider | Change the provider to the registered prefix that is one edit away |
The full list of diagnostics is on Lint Your Pack.
Format and inspect
Section titled “Format and inspect”Edit → Format document formats the active buffer through the enabled formatter. Configure
Prettier and optional format-on-save under Settings → Editor; the Prettier provider must be
available. The status panel checks global prettier, npm, Deno, and Bun. The install action uses
one explicit global install command and asks for confirmation before running it. Format-on-save
supports per-project YAML-only, Docs-only, and All supported text trust profiles. YAML
semantic guard is enabled by default: every YAML document is parsed before and after formatting,
and changed data or invalid output keeps the original buffer. File scope does not sandbox trusted
workspace Prettier plugins or configuration. Formatting then saves through the normal file hash
check; newer typed text is not overwritten by a delayed formatter result. Codex browses
classes, hierarchy, properties, and references from reflection data. Its optional catalog-usage
scan locates class paths in saved project YAML.
Affected elements
Section titled “Affected elements”Implementation checkpoint: selector fixes have passed focused Rust checks and real-archive queries; native GUI confirmation for the current bundled host is pending. Exports without reflection metadata produce Limited previews even when individual matches are definite. Missing defaults, reference metadata or asset coverage can leave candidates Possible; an empty preview cannot prove that no runtime targets exist.
Click Affected (crosshair icon) beside Format to inspect the current entry. The same
Affected elements section appears at the bottom of Inspector. Enable the bundled
Affected Elements module and bind a project .kdfdata archive.
The list uses the current unsaved YAML entry at the cursor. Results show exported names, paths, sources and selection reasons. Icons come from the bound archive; recipe rows use the exported product icon. Missing PNGs show an explicit fallback icon. Click a row to open class information. The full view supports search and paged results.
For example, this patch changes manufacturing duration of recipes produced in an Oil Refinery:
type: cdopatches: - producedIn: /Game/FactoryGame/Buildable/Factory/OilRefinery/Build_OilRefinery.Build_OilRefinery_C properties: - path: mManufactoringDuration op: multiply value: 0.5Place the cursor inside the patch, then click Affected. Results are matching recipes.
Exact names and counts depend on the bound game/mod export. Multiple values in one filter such as
producedIn, ingredient or product are alternatives; different filter keys must all match.
Direct target entries are added to filtered selection. applyToSubclasses includes exported
descendants.
matchName filters an existing candidate scope; it does not create one. For example, pair it with
ofClass to search a class family; ofClass alone selects nothing. Patterns containing / match
object paths, while other patterns match class/object names. Matching ignores case and supports
* and ? wildcards. Arrays of patterns are alternatives.
Preview supports CDO targets and recipe filters, matchName, common where comparisons,
allAssetsOfClass, existing content class entries and recipe/schematic/research removal rules.
Possible marks missing defaults, unresolved reference types, asset instance defaults or runtime
conditions. Owned gameplay tags can come from runtime interfaces, so matchTag stays Possible.
Generated content and live actor instances cannot be enumerated from an export. Syntax errors
clear previous results. Disabled modules, missing data and unsupported entries explain their state.
Earlier pack changes and runtime conditions can change selection beyond the exported defaults. The view initially queries up to 500 candidates, can load up to 2,000, and shows matched/possible totals when the visible list is capped.
Recipe names follow the game rule: mDisplayName is used when mDisplayNameOverride is true;
otherwise the first product’s item name is used. If the export cannot resolve that name, including
an unresolved LOCTABLE entry, the row falls back to its class name and keeps the class path as its
stable identity. Native-host confirmation of the recipe-name correction is pending.
