Generated Content Workflow
This guide explains what to regenerate after changing Engine or game sources, what is authoritative, and how to review generated output without editing it by hand.
Source paths inspected
BuildTools/Init.cmakeBuildTools/cmake/ProjectInterface.jsonBuildTools/cmake/stages/Codegen.cmakeBuildTools/cmake/stages/ScriptsAndBaking.cmakeBuildTools/codegen.pyBuildTools/docs_metadata.pyBuildTools/docs_contract_diff.pyBuildTools/docs_validate.pySource/Tools/MetadataBaker.cppExamples/MinimalProject/CMakeLists.txtExamples/MinimalMultiplayer/CMakeLists.txt
Classify the output first
FOnline has three distinct generated layers:
| Layer | Typical output | Owning input |
|---|---|---|
| Configure/code generation | build-tree GeneratedSource/, generated native bindings and internal config |
CMake project interface, C++ tags/templates, project options |
| Resource baking | Baking/, Resources/, ServerResources/, PlatformBinaries/, Cache/ |
.fomain resource packs, scripts, prototypes, maps, assets, metadata tags |
| Documentation generation | Docs/generated/, _data/docs-site.json, search/AI artifacts |
source-backed interface models and Docs/documentation-manifest.json |
Generated output is evidence, not an editing surface. Fix the source annotation, interface model, project config, generator, or authored asset, then regenerate.
Configure and generate native sources
The embedding project calls the staged BuildTools pipeline:
StartProjectGeneration()
RegisterProjectOptions()
AddThirdPartyLibraries()
RegisterEngineSources()
SetupCodeGeneration()
BuildCoreLibraries()
BuildApplications()
SetupScriptsAndBaking()
BuildPackages()
FinalizeProjectGeneration()
SetupCodeGeneration() consumes Engine and project native sources, code-generation tags, templates, and project options. ForceCodeGeneration is the dependency used by script compilation and baking targets, so stale native metadata cannot be hidden behind an unrelated incremental resource bake.
Reconfigure after changing CMake options, source registration, stage hooks, generated templates, or the Engine pin. Build the smallest target that compiles the affected generated source.
Compile scripts
For AngelScript projects:
cmake --build <build-dir> --config RelWithDebInfo --target CompileAngelScript
Format authored scripts through the wrapper described in AngelScript Style and Refactoring before compilation. A generated .fos failure is fixed in its owning metadata, generator, or authored source and then regenerated; the derived file is not a manual edit target.
BuildTools invokes the generated ASCompiler with:
-ApplyConfig <project .fomain> -ApplySubConfig NONE
This validates the master project contract instead of a convenient development overlay. A project may add focused script/test targets, but should keep the master compile route green.
For Managed C# projects:
cmake --build <build-dir> --config RelWithDebInfo --target CompileManagedScripts
This runs the standalone ManagedScriptBaker after ForceCodeGeneration, emits target API files plus .gen.csproj/.gen.sln, and compiles the configured assemblies without performing a full resource bake. The real delivery gate remains BakeResources or ForceBakeResources: the Managed baker writes target-specific assemblies and the prepared ManagedRuntime/ payload into the selected pack. Fix generated C# at its C++ metadata, configuration, CoreScripts, analyzer, or baker owner and regenerate; do not hand-edit .gen.cs. See Managed C# Scripting.
Bake resources
Run the normal incremental route first:
cmake --build <build-dir> --config RelWithDebInfo --target BakeResources
Use the forced route when the input graph changed:
cmake --build <build-dir> --config RelWithDebInfo --target ForceBakeResources
A forced bake is appropriate after changing:
- resource-pack directories, explicit files, include/exclude patterns, recipients, or baker lists;
- baker behavior or a baked binary schema;
- language set/order or text fallback policy;
- prototype/map migrations or identity rules;
- generated metadata tags, entity/property layouts, remotes, enums, fixed/value/ref types;
- output paths or platform binary composition;
- an incremental-cache bug or missing dependency.
Do not routinely delete the whole workspace. Preserve logs and failed outputs long enough to diagnose ownership, then remove only documented disposable directories.
Understand metadata outputs
MetadataBaker parses project script tags and emits side-specific metadata such as:
Baking/Metadata/Metadata.fometa-server
Baking/Metadata/Metadata.fometa-client
The pair is consumed by runtime dynamic metadata registration and can also generate a project-owned remote-call catalog:
python Engine/BuildTools/docs_metadata.py \
--metadata Baking/Metadata/Metadata.fometa-server \
--metadata Baking/Metadata/Metadata.fometa-client \
--write
Both sides must agree on every paired remote call, including its MaxBytes and MaxCollectionSize structural limits. Every record carries a mandatory Limits trailer, with zeroes when limits are omitted. Do not reconstruct that catalog by parsing .fos or .cs with a second grammar; the baked metadata is authoritative.
Metadata changes can affect persistence, network synchronization, script bindings, content validation, and save compatibility even when native C++ compiles. Review the generated model and run a real bake plus the narrow runtime/test route.
Regenerate documentation contracts
Each checked interface owns its generator. Run the affected generator with --write, then verify all outputs:
python BuildTools/docs_diagrams.py --write
python BuildTools/docs_screenshots.py --write
python BuildTools/docs_reference.py --write
python BuildTools/docs_snippets.py --write --external
python BuildTools/docs_description_translations.py --write
python BuildTools/docs_localization.py --write
python BuildTools/docs_site.py --write
python BuildTools/docs_ai_eval.py --write
python BuildTools/docs_ai_delivery.py --write
python BuildTools/docs_validate.py
Focused format/CLI/CMake generators are listed in Generated API and Metadata. docs_validate.py checks byte-for-byte freshness; it is not a replacement for the focused semantic test.
For a source/API change, compare against the base revision:
python BuildTools/docs_contract_diff.py \
--baseline-git-ref <base> \
--current-dir Docs/generated \
--dispositions Docs/contract-change-dispositions.json \
--write \
--enforce
Complete the required owner, migration, release-note, and compatibility dispositions. Never edit generated JSON merely to silence the comparator.
Dependency order
Use this order when a change crosses layers:
- update source contracts, project configuration, authored content, and tests;
- reconfigure and regenerate native sources;
- compile native targets and scripts;
- bake resources and side-specific metadata;
- run focused native/content/runtime tests;
- regenerate canonical documentation models, source-owned diagrams and screenshot catalogs, and Markdown projections;
- regenerate example and snippet inventories, localization status, then route, site, search, AI-evaluation, and AI-delivery artifacts;
- run aggregate documentation validation and contract diff;
- inspect the final diff for unexpected generated churn.
Later steps may consume hashes or inventories from earlier ones. Running site/AI generation before canonical pages are current can produce internally consistent but stale delivery artifacts.
Review generated changes
Review the input and output together:
- generated symbols should trace to a source tag/template;
- generated settings/options should trace to their runtime-consumed interface;
- baked files should trace to exactly one resource pack and baker;
- side-specific metadata should agree where a contract is paired;
- removed IDs need migration and compatibility review;
- unrelated mass churn usually indicates a path, ordering, line-ending, toolchain, or non-determinism problem.
Generated artifacts should be deterministic for the same inputs. Run the generator twice or use its --check mode to prove this before committing.
Recovery
| Failure | Recovery |
|---|---|
| Generated source does not compile | Fix the source tag/template or project registration, reconfigure, then rebuild |
| Script compiler and runtime disagree | Ensure every enabled backend uses the same config, Engine revision, and fresh generated metadata; for Managed also inspect the target assembly and ManagedRuntime/ payload |
Formatter changes T?, a cast/template form, or a named argument |
Use the Engine-aware wrapper from AngelScript Style and Refactoring, not raw clang-format |
| Metadata sides disagree | Fix paired declarations and rebake both sides |
| Incremental resources stay stale | Run ForceBakeResources; inspect pack selection and baker dependency tracking |
Documentation --check fails |
Run the named generator with --write, then inspect why source changed |
| Contract diff reports a break | Restore compatibility or add the exact reviewed disposition; do not hide the model delta |
| Site/search/AI output changes unexpectedly | Regenerate canonical pages first, then delivery artifacts in dependency order |
Update discipline
Every Engine or embedding-project update is a generation-bearing change. Record old/new revisions, audit the complete range, identify affected generated layers, regenerate in dependency order, and update owning docs/tests in the same work. A green native build alone is not evidence that scripts, resources, metadata, documentation, or compatibility outputs are current.