Skip to content
k-mods.com

From Live Editor Edits to a Shareable Pack

You tweaked values in /kdf editor to see what feels right. Now turn that into a real YAML pack that survives a restart and that you can hand to other people.

You opened /kdf editor, found a recipe or item, dragged a slider, and typed a new number. It felt right immediately. That said, nothing you just did is saved anywhere yet. This tutorial covers the one step between “it works right now” and “it still works next time I launch the game” (or “my friend can install it too”): exporting.

Every editable property row has an OP menu. It contains only operations accepted by that property’s runtime type, using the same validation as a YAML properties: entry. Numeric fields offer arithmetic and clamp; arrays offer insertion, removal, ordering, replacement, duplication, and deduplication; strings and containers expose their applicable append/prepend/remove/clear operations. copy and move are available for every property.

Choosing an operation opens an argument form containing only fields that operation needs:

  • value accepts a normal KDataForge YAML scalar, sequence, or map;
  • clamp asks for min and max;
  • indexed array operations ask for index and, for swap, with;
  • copy and move ask for a from property path on the same object;
  • clear, sort, unique, and reverse need no arguments.

Apply changes the live object immediately. Invalid YAML, an unsupported value, or an out-of-range index leaves the property unchanged and reports the op-engine error. Undo and Redo also remove and restore the corresponding export entry; move restores both source and destination. Use the inspector search to filter fields by property name, full path, or reflected type. The Ops side tab shows the ordered operation sequence currently queued for the selected object.

Both buttons sit in the editor’s inspector panel, and both call the same underlying export, ExportObjectToYaml. They differ in a single flag, bDiffOnly, and that flag changes what ends up in the file.

Export Diff prefers the ordered operations authored in the editor for the selected object. An add, multiply, append, remove_at, copy, or other operation therefore remains that operation in YAML instead of being flattened into a final set. Direct value editing is recorded as set. If no editor-authored operation exists, Diff falls back to properties with a vanilla snapshot recorded during this session. Either way, untouched properties stay absent and continue tracking vanilla or whatever other patches apply to them.

Export Full includes every reflected property on the class that is not deprecated, transient, or editor-only. This is broader than the normal Unreal “editable” surface: fields without EditDefaultsOnly/EditAnywhere can still be exported if they are reflected FProperty members. The file is large: the reflected surface of the class, frozen at its current value. The risk is that any vanilla default you never meant to touch gets written into your pack at today’s value. If the base game changes that default later, your pack silently overrides the update.

Use Export Diff almost always. The “diff” here really means “session-changed,” not “changed-vs-file-on-disk”. A property counts as changed the moment any op, whether a live edit or an earlier-loaded YAML patch, first touches it in the current session. That’s because this is when FKDFVanillaCache::RecordSnapshot fires, since the first write wins. Properties you only looked at in the inspector never get a snapshot and never show up in a Diff export.

Both buttons write to the same place:

<ProjectDir>/DataForge/exported/<ObjectName>.cdo.yml

This is a source-hardcoded editor staging path. The editor creates DataForge/exported/ automatically when needed. <ProjectDir> is Unreal’s project directory, which is the FactoryGame/ project directory in a packaged game.

<ObjectName> is Selected->GetName(). For the common case of editing a recipe, item, or schematic class (its CDO), that name is the engine’s synthetic default-object name. A patch to Recipe_IngotIron_C’s CDO therefore exports as Default__Recipe_IngotIron_C.cdo.yml, not Recipe_IngotIron.cdo.yml. You don’t need to rename it: KDataForge doesn’t care what the file is called, only what’s inside it.

<ProjectDir>/DataForge/exported/ sits under a scanner-recognized DataForge root, so a freshly exported file can be discovered on the next session start.

That’s not a reason to leave it there, though. exported/ is a scratch folder the editor writes into every time you click the button, so exports from unrelated sessions and experiments pile up there with no grouping and no ref:. Handing a file to someone else means handing them something self-contained: its own folder, its own pack.yml with a stable ref: (the save-persistence contract), not your personal working directory.

Before shipping, create a proper author pack and move the file into it:

<your-mod>/DataForge/
pack.yml
Default__Recipe_IngotIron_C.cdo.yml <-- moved from <ProjectDir>/DataForge/exported/
pack.yml
ref: MyTweaks
name: My Tweaks
version: 1.0.0

The exported file is already valid type: cdo YAML. For the common case of one specific class and one specific patch, you don’t need to touch it at all. You’d hand-edit it when you want to broaden what it applies to:

  • Swap target: /Game/.../Recipe_IngotIron.Recipe_IngotIron_C for allAssetsOfClass: /Game/.../Recipe_IngotIron.Recipe_IngotIron_C if you want the patch to also reach subclasses or every asset resolving to that class, not just the one CDO you had selected.
  • Add applyToSubclasses: true alongside target: for the same broadening effect without switching selector kind.
  • Add applyToSpawnedActors: true if this is a buildable and you also want already-placed instances (not just newly spawned ones) to pick up the change. See Targeting for the full selector/modifier reference, and Patching (type: cdo) for the patch shape.

Switch the editor from Runtime to Packs to work on files instead of live objects. The left pane groups every discovered YAML file below its owning pack.yml. Nested packs are separate: the deepest pack.yml owns a file. Files with invalid YAML remain selectable and open directly in Raw mode so you can repair them.

The New pack action creates exactly:

<ProjectDir>/Mods/DataForge/<pack-name>/pack.yml

Pack names and document names accept letters, digits, _, and -. Existing files are never overwritten. Select a pack, choose a document type, enter a file name, and click Create. The type list covers every KDataForge root handler: cdo, gametag, asset, localization, class, item, resource, building, unlock, recipe, schematic, research, dataasset, curve, sinkpoints, resourcenode, and sublevel.

Each file has two editing surfaces:

  • Form exposes every YAML map, sequence, scalar, and null node. Select a node to replace its complete YAML fragment, add a map member or sequence item, or remove it. Scalar values can also be edited inline. The guided controls provide context-sensitive field and sequence-entry templates for every KDataForge document type. Class-valued rows use a searchable class picker filtered to the expected base class; it includes loaded native classes and Blueprint classes known to the asset registry. Once a target, class, or parent is selected, property-path rows can be chosen from inherited reflected fields, including nested struct and array paths. Operation choices are filtered against the resolved property type, while enum and boolean values offer valid presets. Selecting a properties or where sequence also offers ready-made entries for fields on the resolved class.
  • Raw YAML edits the exact file text, including comments and formatting. Switching back to Form first validates and parses the text. Invalid YAML stays in Raw mode with an error message.

Raw edits keep their exact text until a Form mutation occurs. A Form mutation serializes the parsed document again, so comments, quoting choices, and custom whitespace can be normalized or removed. Use Raw mode when those details matter.

Save validates YAML syntax and required document shape, writes a temporary file, then replaces the destination atomically. A failed validation or write leaves the previous file intact. Unsaved changes block file/pack switching and closing until you save or explicitly discard them. Save does not apply semantic changes by itself: use /kdf reload for live-safe updates, or restart for content registrations and other startup-only stages.

The Create panel: drafting new content instead of hand-writing YAML

Section titled “The Create panel: drafting new content instead of hand-writing YAML”

The editor’s CREATE section, below the YAML preview, drafts brand-new content: item, resource, building, recipe, schematic, research, unlock, dataasset, or a generic class, without you typing a document by hand. Pick a kind, type an Id, pick a parent class (or class: for dataasset), optionally pick a registerAs: target for generic class drafts, and click Create.

This writes a starting-point document to:

<ProjectDir>/DataForge/created/<Id>.<Kind>.yml

Create the DataForge/created/ directory before using the action. This is also a staging directory, not the canonical shipping location.

For example, MySuperIngot.item.yml. It’s a skeleton: type:, the plural entries key (items:/recipes:/schematics:/research:/unlocks:/assets:/classes:), and one entry with id: and parent: (or class:). There’s no properties: yet. You still add those by hand, same as in Item + Icon + Recipe + Tier-1 Unlock, just starting from a correctly-shaped file instead of a blank one.

Create writes a draft file; it does not apply the draft to the running session. Every kind, including dataasset, is loaded from YAML on the next session start. The status message shows the written path and reminds you to restart. created/ is a scratch area, so move the finished draft into a real pack before relying on it long-term.

Worked scenario: retuning a recipe’s craft time

Section titled “Worked scenario: retuning a recipe’s craft time”
  1. Open chat, type /kdf editor.

  2. Switch to the Recipes category, search for the recipe you want (e.g. the Super Ingot recipe from the item/recipe/schematic tutorial), and select it. Browser rows show content icons when available: item/building icons, schematic and research-tree icons, recipe product icons, and direct icon properties such as mSmallIcon or mIcon.

  3. In the inspector tree, find mManufactoringDuration and commit a new value, say 2.0 instead of 4.0. The change applies immediately. Go build one and confirm it’s actually faster.

  4. Click Export Diff. Because mManufactoringDuration is the only property you touched on this object this session, the exported file is short:

    type: cdo
    patches:
    - target: /KDataForge/Gen/KDFSample.Gen_KDFSample_Recipe_SuperIngot
    properties:
    - path: mManufactoringDuration
    value: 2.0
  5. Check the status bar. It read Exported to <ProjectDir>/DataForge/exported/Default__Gen_KDFSample_Recipe_SuperIngot.cdo.yml (or similar, matching the generated class’s CDO name).

  6. Create <your-mod>/DataForge/pack.yml (ref: MyTweaks) if you don’t already have a pack folder, and move the exported file in next to it.

  7. Restart the game. The recipe still takes 2 seconds: same value, now coming from a real pack file instead of a session-only edit, applied through the identical type: cdo pipeline as before.

If you’d clicked Export Full instead, the file would list every reflected, non-deprecated, non-transient, non-editor-only property of the recipe class: ingredients, product, produced-in, display name, and possibly internal reflected fields too. Each value is frozen at its current value, not just the duration. That’s usually more than you want to ship.

  • Exported file has an empty properties: list or almost nothing under Diff mode. Diff only includes properties that were actually written this session on that specific object. Browsing or inspecting a value without committing an edit never creates a snapshot, so it never shows up. Double-check you selected the same object you edited, and that you actually committed a value, not just opened the row.
  • I edited something, then undid it, then exported, and the property still shows up. The vanilla snapshot is recorded on first write and never cleared by Undo. Diff mode checks “was this property ever touched this session”, not “does it currently differ from vanilla”. So a touched-then-reverted property can still appear in the export, just with its value back at vanilla. This is harmless, it’s a no-op patch, but worth knowing if the file looks odd.
  • Export/Create button seems to do nothing. Check the status bar text at the bottom of the editor window. Both actions always set it: green for success (with the exact file path), or red for failure (Nothing selected, Could not write <path>, etc.). It’s easy to miss because it’s small, not because the click didn’t register.
  • Can’t find the exported/created file. It is under the source-hardcoded <ProjectDir>/DataForge/exported/ or <ProjectDir>/DataForge/created/ staging directory. The legacy created/ directory must already exist. The Packs workspace creates its own Mods/DataForge/<pack-name>/ directory. Move legacy staging files into a real pack before shipping.
  • Form mode rejects the file. Switch to Raw YAML and repair the syntax. Form requires pack.yml to contain one map, and every normal YAML document root to be a map. Runtime-specific semantic errors are reported when KDataForge loads or reloads the file.
  • New item/recipe/schematic from Create still isn’t there. Create only writes a draft. Move it into a real pack and restart the session. The SML content registry freezes at world begin play.
  • Export Full includes fields from Non-UPROPERTY / Internal. The current UI label is misleading. Those rows are still reflected FProperty members; they only lack Unreal’s normal edit flag or category metadata. Export Full may include them unless they are deprecated, transient, or editor-only.

Getting Started covers pack roots, /kdf report, session restarts, and the same debug format used for editor-originated operations. The separate UE Editor Integration workflow uses the WITH_EDITOR-only KDF.ApplyToAssets command to change Unreal Editor assets; it is not the in-game /kdf editor described here. Every export uses the Patching (type: cdo) document shape. To fill a Create-panel draft’s properties: from scratch, follow Item + Icon + Recipe + Tier-1 Unlock.