Property Types
One working example for every supported property datatype, and the gotchas specific to each.
Every properties: entry inside a type: cdo patch (see Patching)
targets one reflected UE property, and the value: you write has to match that property’s kind.
KDataForge’s value codec recognizes each UE property class in turn: bool, enum, numeric, string,
object/class reference, struct, container. It only falls through to raw UE text-import for
anything it doesn’t special-case. This page walks through every kind it handles, in the order the
codec checks them, so you know exactly what YAML shape to reach for. Pair this with
Operations for what you can do to a value once
you’ve written it, and Targeting for picking what
object the patch applies to.
Booleans accept more than just true/false: yes/no and on/off (case-insensitive) and the
bare digits 1/0 all parse too, so you can match whichever style reads best in context:
- path: mCanBeDiscarded value: false # true/false, yes/no, on/off, 1/0int32 / uint8 / int64 (all integer widths)
Section titled “int32 / uint8 / int64 (all integer widths)”Every plain integer property takes a bare number, regardless of its bit width. You never need to worry about the exact C++ type:
- path: mResourceSinkPoints value: 500- path: mMenuPriority value: 42float / double
Section titled “float / double”Floating-point properties take a decimal number. Setting mManufactoringDuration to a fraction
halves the crafting time, since it’s read in seconds:
- path: mManufactoringDuration value: 2.5- path: mEnergyValue value: 300.0enum (typed enum class and TEnumAsByte)
Section titled “enum (typed enum class and TEnumAsByte)”Unreal exposes two enum styles: the typed enum class and the older TEnumAsByte (a numeric
property with an attached enum). Both are handled the same way. Write the value’s name, optionally
qualified with the enum’s own name, or its numeric ordinal:
- path: mForm value: RF_LIQUID # plain value name- path: mForm value: EResourceForm::RF_GAS # qualified form- path: mForm value: 2 # numeric value (the enum's underlying ordinal)- path: mStackSize value: SS_HUGE # EStackSize always use the name, not a raw countbitmask (int32/uint8 with BitmaskEnum metadata)
Section titled “bitmask (int32/uint8 with BitmaskEnum metadata)”Bitmask properties store several enum flags in one integer. Use a scalar for one flag and a YAML sequence for several flags:
- path: mParentTask value: Above- path: mParentTask value: - Above - LeftKDataForge also accepts an inline sequence, a |-joined string, or a raw pre-computed integer
mask. All named forms are Shipping-safe. Names are preferred because they remain readable:
- path: mParentTask value: - Above - Left- path: mParentTask value: "Above|Left"- path: mParentTask value: 3 # Above (1) | Left (2)FString
Section titled “FString”Plain reflected strings take a quoted scalar as-is, no escaping beyond normal YAML quoting rules:
- path: mSomeString value: 'Hello Ficsit'FName properties look identical to FString in YAML. The codec just wraps the text in an
FName before writing it. This matters for fields UE compares by name identity, like the
quick-switch group below, rather than by string content:
- path: mQuickSwitchGroup value: 'ingots'FText: plain (culture-invariant)
Section titled “FText: plain (culture-invariant)”A bare scalar for an FText property produces a culture-invariant literal text useful for
internal/debug strings, but not localizable. For anything player-facing, prefer the keyed form
below or route it through Localization:
- path: mDisplayName value: 'Better Iron Ingot'FText: localized (key/namespace/source)
Section titled “FText: localized (key/namespace/source)”Passing a map instead of a scalar creates a properly keyed, localizable FText instead of an
invariant literal. The key field is required, while ns and source are optional. A map containing
only source is invalid; use a scalar for culture-invariant text. This uses the
same runtime-safe construction path the localization system relies on:
- path: mDisplayName value: key: BetterIronIngot_Name ns: MyPack source: Better Iron IngotObject reference (hard)
Section titled “Object reference (hard)”Hard object references (UObject* properties) take a full asset or object path, resolved and
loaded immediately. Use none (or an empty string) to null one out:
- path: mCategory value: /Game/FactoryGame/Resource/ItemCategories/Cat_Ingots.Cat_Ingots_C- path: mSmallIcon value: /Game/FactoryGame/Resource/Parts/IronIngot/UI/IconDesc_IronIngot_64.IconDesc_IronIngot_64- path: mConveyorMesh value: none # null out a reference with none or ""Class reference (TSubclassOf)
Section titled “Class reference (TSubclassOf)”Class references also take a path, but the codec tries several forms in order before giving up:
- The path as given.
- The path with a
_Csuffix appended (Blueprint class paths are frequently written without it). - The asset-path-to-object-path expansion.
- For a bare name with no
/or.at all, a generated-content id from the current pack first, then from every loaded pack. - If no generated class matches, a search across every currently loaded class by short name (see
Targeting for the same shortcut applied to
target:).
- path: mOverriddenCategory value: /Game/FactoryGame/Resource/ItemCategories/Cat_Ingots.Cat_Ingots_C # BP class (`_C` auto-retried)- path: mClassToScanFor value: /Script/FactoryGame.FGBuildableResourceExtractor # native class- path: mProducedIn value: Recipe_MyGeneratedRecipe # generated-content id from this pack, if present- path: mFluidClass value: Desc_Water # bare-name shortcut for Desc_Water.Desc_Water_C see TargetingSoft references (TSoftObjectPtr / TSoftClassPtr)
Section titled “Soft references (TSoftObjectPtr / TSoftClassPtr)”The value is stored as a path string and never force-loads the target. The referenced asset only loads if and when the game actually needs it:
- path: mPersistentBigIcon value: /Game/FactoryGame/Resource/Parts/IronIngot/UI/IconDesc_IronIngot_256.IconDesc_IronIngot_256 # stored as a path, not loaded until the game needs itStruct: native text form
Section titled “Struct: native text form”For structs with a native text representation, like FLinearColor, FVector, FGuid, and
FGameplayTag, a plain scalar is parsed through that format. This is the same round-trip form the
editor’s “Copy” action produces:
- path: mFluidColor value: '(R=255,G=100,B=0,A=255)'Struct: map form (member names, Blueprint-authored names work too)
Section titled “Struct: map form (member names, Blueprint-authored names work too)”Any struct also accepts a YAML map keyed by member name. This is resolved through the same flexible member lookup used elsewhere, so Blueprint-authored display names work, not just the raw C++ field name. Each value is recursively converted through this same codec for that member’s type:
- path: mFluidColor value: R: 255 G: 100 B: 0 A: 255Struct: positional sequence form (members in declaration order)
Section titled “Struct: positional sequence form (members in declaration order)”A YAML sequence assigns struct members positionally, in C++ declaration order. This is handy for terse, well-known structs, like a color or vector, where the member order never changes:
- path: mScannerLightColor value: - 1.0 - 0.5 - 0.0 - 1.0Nested structs (any depth)
Section titled “Nested structs (any depth)”Struct members that are themselves structs recurse through the same map/sequence/scalar rules to arbitrary depth. Deeply nested data, like a struct inside a struct inside an array, reads and writes exactly like the flat cases above, just indented:
- path: mCustomScannableDetails value: ScannableType: STY_Default NewDetails: Range: 500TArray
Section titled “TArray”Setting a TArray property, the default set operation, empties the array and rebuilds it from
the given sequence element by element. The value you write always fully replaces whatever was
there before, rather than merging into it:
- path: mIngredients value: # `set` replaces the whole array - ItemClass: /Game/FactoryGame/Resource/RawResources/OreIron/Desc_OreIron.Desc_OreIron_C Amount: 2 - ItemClass: /Game/FactoryGame/Resource/RawResources/Coal/Desc_Coal.Desc_Coal_C Amount: 1Instanced UObject arrays
Section titled “Instanced UObject arrays”Arrays whose elements are instanced UObject references also use a sequence, but each element can
define a new instance with class: and nested properties:. KDataForge creates the instance as a
subobject of the patched target. With the default set op, the array is replaced rather than
merged:
- 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: trueThe class: must be a concrete subclass accepted by the array. For example, mUnlocks accepts
FGUnlock subclasses and mSchematicDependencies accepts FGAvailabilityDependency subclasses.
Nested entries use the same property paths and operations as top-level patch entries.
The same instanced-object entry shape also works with array append, prepend, and insert when
you want to add entries without replacing the whole array:
- path: mUnlocks op: append value: class: /Game/FactoryGame/Unlocks/BP_UnlockRecipe.BP_UnlockRecipe_C properties: - path: mRecipes value: - Recipe_MyGeneratedRecipeArray element access (index paths)
Section titled “Array element access (index paths)”Rather than replacing a whole array, a path can index straight into one element, and from there into that element’s own members. This lets you tweak a single ingredient’s amount without re-listing every other ingredient:
- path: mIngredients[0].Amount value: 3TSet properties also take a plain YAML sequence. Entries collapse if the type’s equality would
make them duplicates, since a set has no concept of ordering or repeated elements:
- path: mSubCategories # sets take sequences; duplicates collapse value: - /Game/FactoryGame/Resource/ItemCategories/SC_Smelted.SC_Smelted_CA TMap property takes a YAML map. Each key is converted through the map’s own key property type
before insertion, not just kept as a raw string. A bracketed key path lets you update a single
entry in place instead of replacing the whole map:
- path: mSomeMap value: Iron: 10 # keys converted through the map's key property type Copper: 20- path: mSomeMap["Iron"] # single-entry access via key path value: 15FGameplayTag
Section titled “FGameplayTag”A single gameplay tag is a struct with a native text importer under the hood, so it takes a plain dotted scalar just like any other native-text struct:
- path: mStatisticGameplayTag value: KMods.AlternateRecipeFGameplayTagContainer
Section titled “FGameplayTagContainer”A tag container takes a sequence of tags. As with arrays, the default set operation replaces the
whole container rather than adding to it. See Operations
for the append/prepend/remove/clear variants that mutate a container instead, and
Game Tags for registering your own tags before you
reference them:
- path: mGameplayTags value: # `set` replaces all tags - KMods.WikiExclude - MyPack.SpecialAnything else (fallback)
Section titled “Anything else (fallback)”Any reflected type not listed above still works. The codec falls back to UE’s own generic text import, so it accepts whatever text form the editor’s “Copy” action produces for that property. This holds even for exotic or third-party struct types this page doesn’t know about by name:
- path: mSomeExoticStruct value: '(InnerValue=3,Flags=(bEnabled=True))'Values from configuration, settings and templates
Section titled “Values from configuration, settings and templates”Any value: (and min: and max:) can come from pack configuration
or from the game itself instead of being a literal:
- path: mManufactoringDuration op: divide value: cfg:balance.ironSpeed # typed reference: the whole unquoted scalar- path: mDescription value: 'Smelts at {cfg:balance.ironSpeed}x speed' # template inside a string- path: mManufactoringDuration value: '{recipe:/Game/FactoryGame/Recipes/Smelter/Recipe_IngotIron.Recipe_IngotIron_C:mManufactoringDuration}'The first form inserts the field’s typed value, the second inserts text, and the third reads a property or calls a function on game data and keeps the result’s type because it is the whole value. Templates and Typed References covers the syntax. The value then goes through the codec of the destination property, so the type of the field must fit the property:
| Destination property | Config field that fits |
|---|---|
bool | boolean |
| integer types | number with an integer valueType (within range), or a numeric select |
float, double, and the operands of add, subtract, multiply, divide, min, max, clamp | any number |
FString | any text, or a string select |
FName | text with valueType string, name or tag |
FText | text with valueType string, text or name |
| enum | a string select whose option values are enum names, or a text field |
| class, soft class, object, soft object | text (the path as a string) |
FGameplayTag | text with valueType: tag |
FGameplayTagContainer | a multiple tag list |
array or set with set | a multiple field with matching elements |
array or set with append, prepend, insert, replace, remove | a single field of the element type |
| structs and maps as a whole | none; set the members one by one, each from its own field |
A lossy match, such as a decimal number into an integer property, is a warning in the editor
(config.type-mismatch); an impossible one is an error.
