Skip to content
k-mods.com

Getting Started

Build the smallest possible pack, confirm it loads, and learn the report, logging, and restart workflow.

Start here if you have never written a KDataForge pack before.

It walks through the smallest useful pack: one folder with two files. Along the way you’ll touch every piece of tooling you need on day one, including where files go, the /kdf chat commands, how to read the load report, debug logging, multiplayer, and the most common ways a fresh pack silently does nothing.

The Task Guides build on this shape to accomplish specific goals. Examples contains complete packs that combine several capabilities, while Features explains each capability.

Author packs under your mod’s canonical root:

<your-mod>/DataForge/
pack.yml
faster-smelting.cdo.yml

KDataForge starts its recursive scan at the Unreal project directory, which is FactoryGame/ in a packaged game. Up to six levels below that project root, it recognizes any directory named DataForge, the legacy name data-editor, or any directory that directly contains pack.yml. Names are case-insensitive. Every *.yml or *.yaml file below a detected root is a document, or several documents when separated with ---. See Multiple Documents Per File.

Detected roots may nest. A YAML file belongs only to its deepest enclosing root, so a nested pack is not also loaded by its parent. Heavy engine directories such as Content, Saved, Plugins, and Source are pruned during root discovery.

A pack.yml manifest is how a set of documents becomes a named, versioned unit instead of a pile of loose files.

It is optional. Without a manifest, the implicit pack ref and name come from the parent directory of the detected root. That fallback can change when a folder moves, so declare an explicit stable ref from day one. The ref is the save-persistence contract:

ref: MyFirstPack
name: My First Pack
version: 1.0.0

A type: cdo document patches properties directly on a class’s default object. Setting mManufactoringDuration to a fraction of its original value halves the crafting time. It’s a good first patch to try because the result is immediately visible in-game:

faster-smelting.cdo.yml
type: cdo
patches:
- target: /Game/FactoryGame/Recipes/Smelter/Recipe_IngotIron.Recipe_IngotIron_C
properties:
- path: mManufactoringDuration
op: multiply
value: 0.5

Start the game and iron ingots now smelt twice as fast.

The type: key is optional here. The .cdo.yml filename suffix would set the root type via the filename convention (<name>.<type>.yml), but an explicit type: always wins.

  • /kdf report: prints the load report, showing which packs and documents were found, what was applied, and every diagnostic (see below).
  • /kdf reload: restores KDataForge-touched reflected properties to their original session baseline, rescans every pack file (including edited configuration values files: hot values apply, cold values report “restart required”), then runs the normal deterministic stage pipeline again.
  • KDF.Reload: runs the same smart reload from a host or dedicated-server console.
  • /kdf sound PackRef Id: previews an imported Wwise sound on the local client. Console equivalent: KDF.Sound PackRef Id. See Wwise Sounds.

After editing a file, run /kdf reload, then use /kdf report to inspect the replacement load. Only the listen host, a dedicated-server administrator, or the server console may reload.

Reload does not blindly apply an add, append, or multiply operation on top of its previous result. Before re-applying files, KDataForge restores every touched top-level reflected property to the value captured before KDataForge first changed it this session. This also removes property changes from files deleted since the previous load. Invalid documents are skipped under normal diagnostic rules, so their old property effects are not retained.

Reload clears and rebuilds actor patches, lazy-class watches, content-removal rules, resource-node rules, registration queues, diagnostics, and patch history. Any open /kdf editor window closes because its undo history refers to the pre-reload state.

Some engine state cannot be reversed safely after world startup:

  • SML freezes recipe, schematic, research-tree, and sink-point registrations before BeginPlay. New, deleted, or re-registered entries need a session restart to change those live registries.
  • Content already removed by a remove: rule is not re-added when that rule disappears. Reload updates the rule set for later checks; restart the session to rebuild availability from startup.
  • Generated UObject identities, gameplay tags, and localization entries are process-lifetime state. Current files can update existing objects or strings, but deleting their definitions does not unload them. Restart to prove removal.
  • resourcenode reload rules apply immediately. Node destruction is server-authoritative and may create vanilla save tombstones; removing the rule cannot resurrect already destroyed nodes.
  • Reload is process-local. Multiplayer clients do not receive the host’s reload. Restart every process with the same pack set when changes must be multiplayer-consistent.

Prefer clicking over typing? /kdf editor opens the in-game editor. Runtime browses reflected objects, applies supported property operations live, and exports YAML. Packs browses files grouped by their owning pack.yml, creates packs below <ProjectDir>/Mods/DataForge/<pack-name>/, and edits every YAML node through Form or Raw YAML mode. Form mode includes schema-aware field/entry templates, filtered class selectors, reflected property paths, supported-operation choices, and enum/boolean presets. Save validates and writes atomically; /kdf reload applies live-safe file changes.

Diagnostics are never fatal. A broken file is skipped and the load continues. Each one carries a severity that tells you how much attention it deserves:

SeverityMeaningExample
InfoExpected skips, not printed by /kdf reportA document’s conditions: failed (mod not installed, version mismatch)
WarningTolerated problemsUnknown root type, duplicate pack ref
ErrorA file, document, or single patch was skippedMalformed YAML, target class not found, unsupported op×type combination

Every applied op can be traced with debug logging, and you get to choose how wide the net is cast: per document, per pack, or globally across every pack loaded.

Per document: add debug: true at the top level of any document type. Every applied op from that file logs:

faster-smelting.cdo.yml
type: cdo
debug: true
patches:
- target: /Game/FactoryGame/Recipes/Smelter/Recipe_IngotIron.Recipe_IngotIron_C
properties:
- path: mManufactoringDuration
op: multiply
value: 0.5

Per pack: add debug: true to pack.yml. Every document of the pack logs:

ref: MyFirstPack
name: My First Pack
version: 1.0.0
debug: true

Global: set the console variable KDF.Debug 1 (open the console with ~) or launch the game with -KDFDebug. Everything logs then, including ops originating from the in-game editor.

Each applied op produces one line at Log verbosity:

[KDF DEBUG] faster-smelting.cdo.yml: /Game/FactoryGame/Recipes/Smelter/Recipe_IngotIron.Recipe_IngotIron_C.mManufactoringDuration multiply : 2.000000 -> 1.000000

The format is <file>: <target path>.<property path> <op> : <pre value> -> <post value>. The pre/post pair is what makes it useful: you see exactly what a multiply or append actually did.

Where the log lives: in a packaged game the log file is %LOCALAPPDATA%\FactoryGame\Saved\Logs\FactoryGame.log. Search it for [KDF DEBUG].

KDataForge loads YAML independently in every game process. It does not negotiate pack checksums, reject mismatches, or stream applied operations from the server. Install the same pack set and versions on the dedicated server or host and on every client. The one thing the host does send to clients is the value of each pack configuration field, held in memory only.

The in-game editor’s live property changes are local to the process where they are made. Export those changes to YAML and distribute the resulting pack when they must be consistent for all players.

Most “nothing happened” reports trace back to one of a small handful of causes. Check these before assuming something is broken:

SymptomLikely cause / fix
File is ignored entirelyMissing type: key and the filename doesn’t follow the <name>.<type>.yml convention. Add one of the two
One document of a multi-document file is ignoredEvery document in a ----separated file needs its own type: key. The filename convention only works for single-document files, see Multiple Documents Per File
“class not found”Check the path form: cooked Blueprint asset classes use _C (/Game/....Asset.Asset_C, auto-retried if omitted), native classes use /Script/Module.Class, and KDataForge-generated classes use /KDataForge/Gen/<PackRef>.Gen_<PackRef>_<Id> with no _C. The short id: also works when unambiguous; see Generated Content Short Ids
Op rejected at load timeUnsupported op×type combination. Check the op table in the YAML Schema and the per-op examples in Operations
Data-asset instance not foundInstances (not classes) have no _C suffix, see Targeting
Change applied but not visible on placed buildingsSaves/archetypes override CDO values. Use a runtime actor patch (applyToSpawnedActors), see Buildings