Skip to content
k-mods.com

Patching (type: cdo)

The property-patch document type. Covers how patches, target selectors, and modifiers fit together, plus where the deep-dive pages live.

This document type runs at the CDOChanges stage, after GameTags, Assets, and Localization, and before any content-generation stage. Its entries live under the patches key as a sequence. YAML changes are loaded on the next session start.

This is the workhorse document type. It edits any reflected property on any class default object or object instance in the game: items, recipes, buildings, schematics, research trees, KAPI/RRDA data assets, your own generated content, anything. Everything else this framework does (content creation, data assets, sink points) either patches through this same mechanism internally or exists alongside it.

A type: cdo document is just a patches: list. Each entry needs at least one target selector (target:, allAssetsOfClass:, or an ofClass: scope with filters such as matchTag:, matchName:, producedIn:, where:), optional modifiers, and a properties: list describing the actual edits. The example below halves mManufactoringDuration on the iron ingot recipe:

type: cdo
patches:
- # ---- one or more selectors are accepted; prefer one clear selector ----
target: /Game/FactoryGame/Recipes/Smelter/Recipe_IngotIron.Recipe_IngotIron_C
# target: also accepts a sequence of paths, patching every entry with the same properties:
# OR: allAssetsOfClass: ...
# OR: ofClass: ... + filters (matchTag / matchName / producedIn / ingredient / product / where)
# ---- modifiers (all optional) ----
applyToSubclasses: false
applyToSpawnedActors: false
# ---- the ops ----
properties:
- path: mManufactoringDuration
op: multiply
value: 0.5

Each entry needs at least one selector and a non-empty properties: list. The current implementation accumulates matches when selectors are combined, but one selector per entry is easier to audit. One document can hold any number of patch entries.

Use full asset object paths for hard-reference properties such as TArray<TObjectPtr<UStaticMesh>>. A YAML sequence replaces the array; string allowlists remain ordinary strings. For example, with Periodic Madness installed:

type: cdo
patches:
- target: /Script/PeriodicMadness.PMCleanerSettings
properties:
- path: mStaticMeshesCleanlist
value:
- /Game/FactoryGame/Resource/RawResources/Nodes/ResourceNode_OreIron_01.ResourceNode_OreIron_01

KDataForge keeps hard references added to permanent native defaults alive across garbage collection and session changes. These assets remain resident until the game exits, even if a later edit removes them from the array. No YAML opt-in or class declaration change is needed. After upgrading from a build where inspecting these arrays crashed, fully restart the game before loading the pack again.

An ordinary properties: entry can replace an array of instanced UObject references. Write each array entry as a map with class: and optional nested properties:. KDataForge creates the instance as a subobject of the patched target, then applies the nested property operations. This works for any compatible instanced object array, including schematic dependencies and unlocks.

Because set is the default operation, the following patch replaces the complete mSchematicDependencies array on every target. It does not append to existing dependencies:

type: cdo
patches:
- target:
- /RSS/Schematics/Flat/Sink_RSS_Flat_Belt.Sink_RSS_Flat_Belt_C
- /RSS/Schematics/Flat/Sink_RSS_Flat_Ceiling.Sink_RSS_Flat_Ceiling_C
properties:
- path: mSchematicDependencies
value:
- class: /Game/FactoryGame/AvailabilityDependencies/BP_SchematicPurchasedDependency.BP_SchematicPurchasedDependency_C
properties:
- path: mSchematics
value:
- /SatisfactoryPlus/Content/SchematicManager/Schematics/Milestones/T1/Schematic_SF+_T1_0.Schematic_SF+_T1_0_C
- path: mRequireAllSchematicsToBePurchased
value: true
- path: mDependenciesBlocksSchematicAccess
value: true

class: must resolve to a concrete subclass compatible with the array element type. For example, mUnlocks accepts FGUnlock subclasses and mSchematicDependencies accepts FGAvailabilityDependency subclasses. The nested properties: use the same paths and operations as a top-level CDO patch.

The four things you need to know, and where they’re documented

Section titled “The four things you need to know, and where they’re documented”

Writing a patch entry means answering four separate questions. Each one is covered by its own page rather than duplicated here: what to target, what operation to apply, how to write the value for the property’s type, and how to address nested/array/map properties in the path itself.

ConcernPage
Selecting what to patch: class path, object path, allAssetsOfClass:, ofClass: scope filters (matchTag:, matchName:, producedIn:/ingredient:/product:, where:), applyToSubclasses:, applyToSpawnedActors:, the bare class-name shortcutTargeting
What you can do to a value: all 22 operations and which property kinds accept themOperations
How to write a value: every property kind’s YAML form (bool, numerics, enums, strings, FText, object/class/soft refs, structs, arrays/sets/maps, gameplay tags)Property Types
The path grammar: array indices, map keys, struct/object dereference, authored-name matchingYAML Schema → Property Paths

Two curated example galleries put all of the above together for real FactoryGame classes: Balancing (recipes, items, resources, schematics, research, categories) and Power & Machines (buildables, power, extractors, pipelines, runtime actor patches).

An unsupported op×type combination, an unresolvable path, or a target that matches nothing all produce diagnostics. The specific patch entry is skipped, but the rest of the document, and every other document, still applies. Run /kdf report after any change to confirm exactly what was patched and see every warning/error in one place.

Before the first write to a property path on an object, KDataForge records its original text value. The in-game editor uses it for diffing, undo, and changes-only export. The YAML pipeline runs once during initialization and exposes no general reload or document-revert operation.

Runtime actor patches are a separate boundary. They apply operations directly to every matching instance and do not preserve player-modified or save-restored values through snapshot comparison.

  • A patch “did nothing” and there’s no error: check matchTag/where/producedIn/allAssetsOfClass selectors first. A selector that matches zero objects only warns (/kdf report). It doesn’t fail the document, and it’s an easy typo to miss because nothing looks broken until you actually check.
  • Not sure which of the three target selectors to reach for? Targeting → Choosing a selector has a quick lookup table.