Type: class
Generating classes of any kind from YAML, any parent (C++ or Blueprint), optional content registration via registerAs, and where the preset types stop and this escape hatch begins.
This type runs first in the Items stage at priority 50, ahead of unlock, item, resource,
and building. Later generation types can therefore use a custom generated class as their parent,
and recipe, schematic, and research can reference it. Changes load during session
initialization, so restart after editing YAML. Its entries key is classes.
There is no default parent, so every entry must set parent: explicitly. There is no required base class either: every parent works, whether native C++ or Blueprint. Register-only mode (class:) is not supported; use id: instead, and register existing classes via Type: recipe, schematic, or research.
The preset types (item, resource, building, unlock, recipe, schematic, research) remain the recommended, ergonomic forms. They pick the right parent, stage priority, and registration for you. class is the escape hatch for everything else: equipment descriptors, vehicle descriptors, item and schematic categories, FGUnlock subclasses, custom classes from other mods gated behind hasMod, reparented buildables, and any other class kind KDataForge has no preset for.
type: classdebug: true # optional log every applied op (see Getting Started → Debugging)classes: - id: MyCustomThing parent: /Script/FactoryGame.FGEquipmentDescriptor # ANY class: native C++ or /Game/...Thing_C registerAs: recipe # OPTIONAL: recipe | schematic | research queues SML content # registration for kinds that need it; omit for everything else properties: - path: mDisplayName value: My Equipment # cdo-style op entries applied to the new class's CDOEverything that holds for the preset generation types holds here too:
- Same save-stable identity: package
/KDataForge/Gen/<PackRef>, classGen_<PackRef>_<Id>. Reference it elsewhere as/KDataForge/Gen/<PackRef>.Gen_<PackRef>_<Id>. The global manifest, tombstone reconstruction, andredirects:inpack.ymlall apply. - Layout-copy constraint: the generated class copies the parent’s layout exactly, with no new reflected properties and no new components. All variation lives in the CDO defaults that
properties:sets. registerAs:is only for the three kinds SML’sUModContentRegistrytracks:recipe,schematic, andresearch. If you generate one of those throughclassinstead of the preset type, set it so registration is queued. Everything else, such as descriptors, categories, and unlocks, just needs to exist and be referenced.
Example 1: an equipment descriptor from a C++ parent
Section titled “Example 1: an equipment descriptor from a C++ parent”type: classclasses: - id: Desc_MyGadget parent: /Script/FactoryGame.FGEquipmentDescriptor properties: - path: mDisplayName value: key: MyGadget_Name ns: MyPack source: Portable Gadget - path: mStackSize value: SS_ONE # equipment is conventionally non-stacking - path: mEquipmentClass value: /Game/FactoryGame/Equipment/JetPack/Equip_JetPack.Equip_JetPack_CThe result is a real UFGEquipmentDescriptor subclass, usable in recipes, schematics, and sinkpoints like any other descriptor. Because of the layout-copy constraint, mEquipmentClass has to point at an existing equipment actor, here the jetpack. You are re-parametrising existing equipment behaviour, not writing new equipment logic.
Example 2: a build-menu / item category
Section titled “Example 2: a build-menu / item category”There is no preset type for categories, which makes them the textbook class use case:
type: classclasses: - id: Cat_MyPackParts parent: /Script/FactoryGame.FGItemCategory properties: - path: mDisplayName value: key: Cat_MyPackParts_Name ns: MyPack source: MyPack Parts - path: mMenuPriority value: 999Point generated items at it from the same pack. The Items stage guarantees the category class exists before any later stage references it. Within the stage, include: orders documents when one Items-stage document needs another:
type: iteminclude: - my-category.class.yml # the category must generate before this item references ititems: - id: MySuperGadgetPart properties: - path: mCategory value: /KDataForge/Gen/MyPack.Gen_MyPack_Cat_MyPackPartsExample 3: a modded parent class, gated behind hasMod
Section titled “Example 3: a modded parent class, gated behind hasMod”Any loaded mod’s classes work as parents. Gate the document so it is skipped cleanly (Info diagnostic) when the mod is missing:
type: classconditions: hasMod: FicsitFarmingclasses: - id: Desc_MyCustomCrop parent: /Game/FicsitFarming/Descriptors/Crops/Desc_Berry.Desc_Berry_C # Blueprint parent properties: - path: mDisplayName value: My Custom CropregisterAs: (generating a registered kind through class)
Section titled “registerAs: (generating a registered kind through class)”If you generate a recipe, schematic, or research class via class, for example because you want a specific modded subclass as the parent, queue its registration with registerAs:. It does exactly what the preset type’s default register: true does:
type: classclasses: - id: Recipe_MySpecial parent: /Game/SomeMod/Recipes/Recipe_SpecialBase.Recipe_SpecialBase_C registerAs: recipe # queued into UModContentRegistry before the freeze properties: - path: mDisplayName value: My Special RecipeTroubleshooting
Section titled “Troubleshooting”- “parent is required”: unlike the preset types,
classhas no default parent. Every entry needs an explicitparent:. - “My generated recipe/schematic never shows up”: you generated it via
classwithoutregisterAs:. Only the preset types register automatically.classregisters nothing unless you ask. - Wanting new components, meshes, or logic: not possible. See the layout-copy constraint above and the honest scope callout in A Complete Building.
- Preset-type pages for the ergonomic forms: Type: item, Type: recipe, Type: schematic, Type: building.
