Code Generator¶
This page documents the current Fora-only code generation flow in SimGe.
It explains: - which generator classes participate in a Fora run - which settings change the generated output - which metric-driven strategies are available - when each strategy becomes active
This document does not cover legacy RACoN / HLA 1.3 / HLA 1516e generators.

The generated code viewer for a federate (here ChatFdApp). After a generation run, SimGe opens the produced C# files for read-only review — each generated file is a tab along the bottom — and you can copy (Ctrl+C) or export (Ctrl+E) the source. Generation is configured in the project's Code Generator settings (see Project Structure & Settings) and summarized in a per-federate report afterwards.
Scope¶
The Fora generator is selected when:
CodeGeneratorSettings.RtiLibraryType = HLA2025_Fora
The entry point is:
SimGe.Application/CodeGenerator/CodeGeneratorManager.cs
The main execution path is:
- metric analysis is computed for the federate SOM
- per-class
ClassGenStrategyobjects are derived - base Fora generators run
- optional metric-driven variant generators run
Main Flow¶
For a Fora generation run, CCodeGeneratorManager.generateFora(...) currently emits:
CSimMngrClassGenerator_ForaCFederateClassGenerator_ForaCFederateManualClassGeneratorCSomClassGenerator_ForaCModelsGenerator_ForaCHlaCodecGenerator_ForaCEncoderGenerator_ForaCDecoderGenerator_ForaCEntityGenerator_ForaCDatatypeGeneratorCTagsGeneratorCGeneratedReadmeGenerator_Fora
If metric-driven variants are enabled, it also emits:
CSpecializedCodecGenerator_ForaCDeltaTrackerGenerator_Fora
Planned: Service-Driven Generation¶
A planned Fora enhancement is to synchronize generated code with the OMT Services usage table.
Target behavior:
- generate service-related boilerplate only when the corresponding service is marked
Used - reduce unused lifecycle/helper code in
SimulationManagerBase.simge.cs - reduce unused callback scaffolding in the generated Fora federate base where possible
Constraint:
- methods required by the Fora interfaces will still need to exist for type compliance; planning focuses on suppressing extra wrappers, helpers, and optional boilerplate around unused services
Generated Structure¶
Typical Fora output is organized like this:
Generated/
Core/
[Federate]Base.simge.cs
SimulationManagerBase.simge.cs
Som/
FederateSom.simge.cs
Models/
Models.simge.cs
HlaCodec.simge.cs
Encoder.simge.cs
Decoder.simge.cs
Datatypes.simge.cs
Tags.simge.cs
SpecializedCodecs/
[Class]Codec.simge.cs
Delta/
[Class]DeltaTracker.simge.cs
Entities/
IEntityProxy.simge.cs
[Class]Entity.simge.g.cs
Entities/
[Class]Entity.cs
SimulationManager.cs
[Federate].cs
README.generated.md
Notes:
Generated/is machine-owned and may be overwritten on regeneration.Entities/[Class]Entity.csandSimulationManager.csare user scaffolds.SpecializedCodecs/andDelta/appear only when metric-driven variants are active and applicable.README.generated.mdis emitted at the federate output root and summarizes the generated API surface, target compatibility, metric-strategy decisions, and regeneration guidance.
Generated API Summary README¶
For each Fora federate output, SimGe writes:
README.generated.md
The README is generated into the same root folder as SimulationManager.cs, [Federate].cs, and the Generated/ tree. For example:
It is intended for simulation developers who need to understand the generated integration surface without reading every generated C# file.
The README includes:
- generation provenance: output path, timestamp, SimGe version, target, HLA version, namespace root
- Fora API profile: the committed
ForaClientApiProfile.jsonprofile ID, minimum/testedFora.Clientversion, required package, API namespace surface, SDK assemblies that provide that surface, and .NET/C# target expectations. If generated code is placed near a target.csproj, the README also reports the resolved target project version as secondary validation metadata. - generated vs scaffold file ownership
- metric-based generation settings and emitted variant status
- per-object-class strategy results, including hotspot, periodic, critical, specialized-codec, delta-tracker, and critical-wrapper decisions
- analytical synthesis diagnostics such as
CG1010 - object-class API summary: generated model, entity wrapper, registration helper, lifecycle events, and attributes
- interaction-class API summary: DTO, sender helper, receive event, and parameters
- DDM dimension handles
- generated datatype and codec/converter summary
- recommended extension points in
SimulationManager.csand[Federate].cs - regeneration notes for syncing the output into a target Fora application
The README is regenerated on each run and should be treated as generated documentation, not hand-edited source.
SimGe does not require Fora.Client as a NuGet dependency in order to generate code. The generator reports the embedded Fora API profile it was authored and tested against. End-user projects must reference a compatible Fora.Client package or project when compiling the generated code.
Fora Contract Validation¶
For Fora generation runs, SimGe validates the generator's intended Fora.Client usage against the bundled API contract snapshot before reporting success.
The validation answers this question:
Do the Fora service and codec calls emitted by this generator still exist with the expected signatures in the targeted Fora API snapshot?
The current validator checks:
- 36 generated Fora service-call shapes, including lifecycle, handle resolution, publish/subscribe, object registration, encoded update/send helpers, advisory switches, late-join attribute-value requests, and cleanup
- 28 generated
Fora.Encoding.HlaPrimitivescodec-call shapes - the configured
Fora.Clientcontract snapshot recorded byForaClientApiProfile.json
The result is shown in the code-generation report, for example:
FORA CONTRACT VALIDATION
INFO [CG1020] Fora.Client API contract validation passed (36 service call(s), 28 codec call(s)).
If the bundled contract snapshot is missing, generation is not blocked; the validator reports NotRun so the missing validation is visible. If a required API member or signature does not match, SimGe reports a CG1021 issue so generator/Fora compatibility can be fixed before relying on the generated code.
Internally, generated Fora service-call emission is routed through ForaClientCallWriter. This keeps the generator templates from scattering raw Fora.Client method strings across many files. The writer is not the API source of truth; the bundled DLL metadata snapshot remains the validation source of truth.
Settings¶
The most important Fora settings are in:
SimGe.Application/CodeGenerator/CodeGeneratorSettings.cs
Core Selector¶
| Setting | Meaning |
|---|---|
RtiLibraryType = HLA2025_Fora |
activates the Fora generator path |
Metric-Driven Settings¶
| Setting | Default | Effect |
|---|---|---|
EnableMetricDrivenVariants |
false |
turns metric-driven generator branches on |
SaturationThreshold |
0.6 |
hotspot threshold used by MetricEngine |
DispersionThreshold |
1.0 |
extra hotspot threshold based on relative payload |
EmitDispatchTable |
true |
allows generated dispatch-table branches when metric mode is enabled |
Important behavior:
- if
EnableMetricDrivenVariants = false, SimGe stays on the legacy Fora generation path - dispatch-table output is now also gated by
EnableMetricDrivenVariants
Metric Pipeline¶
The current Fora metric path is:
MetricAnalysisService.Analyze(...)MetricEngine.Compute(...)ClassGenStrategy.FromSnapshot(...)
Shared Metric Source¶
The generator no longer uses a fully separate placeholder metric model.
The code generation layer now derives its class snapshots from the same shared analysis family used by dashboard statistics:
SimGe.Model/Helpers/Metrics/MetricAnalysisCore.csSimGe.Model/Helpers/Metrics/MetricAnalysisService.csSimGe.Model/Helpers/Metrics/MetricAnalysisResult.cs
This reduces drift between dashboard interpretation and code generation decisions.
Current Strategy Inputs¶
ClassGenStrategy currently carries:
IsHotspotIsAnemicIsCriticalIsPopulationGatedIsPeriodicIsConditionalIsStaticEmitSpecializedCodecEmitDeltaTracker
Derived outputs today are:
EmitSpecializedCodec = EnableMetricDrivenVariants && IsHotspotEmitDeltaTracker = EnableMetricDrivenVariants && IsHotspot && IsPeriodic
Strategy Matrix¶
This is the current Fora behavior.
| Condition | Result |
|---|---|
EnableMetricDrivenVariants = false |
no specialized codec files, no delta tracker files, no metric-driven dispatch tables |
IsHotspot = true |
encoder/decoder may delegate to a specialized codec |
IsHotspot = true and class is an Object Class |
CSpecializedCodecGenerator_Fora emits Generated/Models/SpecializedCodecs/[Class]Codec.simge.cs |
IsHotspot = true and IsPeriodic = true and class is an Object Class |
CDeltaTrackerGenerator_Fora emits Generated/Models/Delta/[Class]DeltaTracker.simge.cs |
IsCritical = true |
generated SimulationManagerBase wraps register/update helpers in a try/catch and calls OnCriticalFault(...) |
EmitDispatchTable = true and metric mode is enabled |
generated federate and decoder include dispatch-table branches |
Runtime Interpretation of Metric-Driven Variants¶
Metric-driven variants are intended to affect runtime behavior, not only generated-file organization. Their current implementation has the following exact boundaries:
| Variant | Runtime value | Current limitation |
|---|---|---|
| Specialized codecs | Hotspot Object Class encode/decode calls delegate to a class-specific codec with explicit per-attribute statements and exact-capacity dictionaries. | Generated only for Object Classes; Interaction Classes still use the normal generated encoder/decoder methods. |
| Delta trackers | Periodic hotspot Object Classes receive a GetDelta(...) helper that compares consecutive DTO snapshots and returns a partial DTO containing changed attributes. |
The default UpdateAsync(...) method does not automatically compute a delta. Scenario code must call GetDelta(...) and then pass the returned partial DTO to the update path. |
| Dispatch tables | Metric mode can emit dictionary-backed dispatch helpers where the generator has table-based routing support. | This is not a universal replacement for every generated callback branch; some ambassador dispatchers still use explicit class-handle checks. |
| Critical wrappers | Critical Object Class registration and update helpers call OnCriticalFault(...) inside generated try/catch wrappers and then rethrow. |
The wrapper is limited to generated object registration/update helpers. |
Therefore the feature is implemented, but performance claims should be read as generated runtime strategy potential rather than benchmark evidence. Actual speedup or bandwidth reduction depends on the FOM shape, update frequency, payload sizes, subscriber topology, and whether scenario code uses the generated delta helper for periodic hotspot objects.
Current Generator Behaviors¶
CEncoderGenerator_Fora¶
Behavior:
- always emits interaction encoders
- always emits object encoders
- if strategy says
EmitSpecializedCodec, object encode methods delegate to[Class]Codec.Encode(...)
Current scope:
- specialized delegation is applied to Object Classes
- interaction classes still use normal generated encode logic
CDecoderGenerator_Fora¶
Behavior:
- always emits interaction decoders
- always emits object-family dispatch methods
- if strategy says
EmitSpecializedCodec, object decode methods delegate to[Class]Codec.Decode(...) - if metric mode is enabled and
EmitDispatchTable = true, object-family dispatch methods use generated dispatch dictionaries
CEntityGenerator_Fora¶
Behavior:
- always emits generated entity proxy partials
- always emits user scaffold entity files
- if strategy says
EmitDeltaTracker, entity proxy includes a delta-tracking hook
Important fix:
- the delta hook is now gated by
EmitDeltaTracker, not merely byIsPeriodic - this prevents generated entities from referencing tracker classes that were never emitted
CSimMngrClassGenerator_Fora¶
Behavior:
- always emits generated
SimulationManagerBase - always emits
SimulationManager.csscaffold - if strategy says
IsCritical, generated register/update helpers wrap their body intry/catch
Current critical hook:
protected virtual void OnCriticalFault(string className, Exception ex)
Generated SimulationManagerBase.simge.cs API & Lifecycle¶
The generated SimulationManagerBase defines the IEEE 1516-2025 async federation lifecycle. Its key API components include:
1. Configuration Properties¶
RtiAddress: The connection address for the RTI.FederationName: The name of the target federation execution.FederateName&FederateType: Identifiers for the federate execution.FomPath: Path to the single FDD/FOM XML file (defaults to the project's generated FOM).FomModules: A list of modular FOM paths (IReadOnlyList<string>). When populated, it triggers the multi-module federation creation.
2. The RunAsync Orchestration¶
The simulation execution is started by calling the sealed RunAsync(CancellationToken ct). The federation creation step is executed conditionally:
- If FomModules has elements, it invokes CreateFederationExecutionAsync(FederationName, FomModules, ct).
- If FomModules is empty, it falls back to CreateFederationExecutionAsync(FederationName, FomPath, ct).
This design makes the federate multi-module aware at runtime: the scenario driver simply sets the FomModules list with the ordered module file paths (base-first) prior to calling RunAsync(). Once the federation is created with all FDD modules, the join execution works automatically without further changes.
3. Virtual Hook OnPublishAndSubscribeAsync¶
The generator emits a virtual method containing all default publish and subscribe calls derived from the SOM design:
protected virtual async Task OnPublishAndSubscribeAsync(CancellationToken ct)
This method can be overridden in the user subclass SimulationManager.cs to customize, extend, or defer P/S logic at runtime.
4. Register Methods¶
The base class exposes type-safe registration methods for object classes, such as Register[Class]Async (e.g., RegisterHumanAsync). These methods register object instances with the RTI and return the corresponding generated entity wrapper.
CFederateClassGenerator_Fora¶
Behavior:
- emits the generated federate ambassador base
- if metric mode is enabled and
EmitDispatchTable = true, emits the generated_dispatchNamestable
CSpecializedCodecGenerator_Fora¶
Behavior:
- emits one file per hotspot Object Class
- inlines attribute encode/decode logic for that class
Current scope:
- Object Classes only
- no specialized interaction codec generator exists at the moment
CDeltaTrackerGenerator_Fora¶
Behavior:
- emits one file per periodic hotspot Object Class
- compares successive DTO snapshots
- returns a partial delta DTO containing changed attributes only
Current scope:
- Object Classes only
CGeneratedReadmeGenerator_Fora¶
Behavior:
- emits
README.generated.mdat the federate output root - summarizes the generated object classes, interaction classes, dimensions, datatypes, helper APIs, and extension points
- records Fora target compatibility using the resolved
Fora.Clientversion when available and the generated code's actual Fora namespaces - records metric-driven settings and per-class strategy outcomes
- includes analytical synthesis diagnostics collected during the generation run
Current scope:
- Fora target only
- generated after the source files so it can document the final strategy/diagnostic state of the run
Current Scope Limits¶
The current Fora metric-driven implementation is intentionally narrower than the full strategy model.
Object Classes vs Interaction Classes¶
Metric snapshots are computed for both OC and IC domains, but variant file generation is currently limited to Object Classes:
CSpecializedCodecGenerator_ForaacceptsCOmtOCCDeltaTrackerGenerator_ForaacceptsCOmtOCgenerateMetricVariants(...)iterates only overCOmtOC
Practical result:
- an Interaction Class can still be classified as a hotspot in strategy output
- but SimGe does not currently emit a specialized interaction codec file for it
Delta Tracker Requirements¶
A delta tracker is generated only when all of these are true:
- metric mode is enabled
- the class is classified as a hotspot
- the class is classified as periodic
- the class is an Object Class
Dispatch Tables¶
Dispatch-table generation is not global by default anymore.
It requires:
EnableMetricDrivenVariants = trueEmitDispatchTable = true
Practical Examples¶
Standard Fora Generation¶
Use this when you want predictable generated code without metric-driven specialization:
RtiLibraryType = HLA2025_ForaEnableMetricDrivenVariants = false
Expected result:
- normal
Encoder.simge.cs - normal
Decoder.simge.cs - no
SpecializedCodecs/ - no
Delta/
Hotspot Object Class¶
Use this when a class has high payload concentration and you want a tighter encode/decode path:
EnableMetricDrivenVariants = true- class is classified as
IsHotspot = true
Expected result:
[Class]Codec.simge.csis generated- object encode/decode methods delegate to it
Periodic Hotspot Object Class¶
Use this when a frequently updated object should emit smaller partial DTO updates:
EnableMetricDrivenVariants = trueIsHotspot = trueIsPeriodic = true
Expected result:
[Class]Codec.simge.cs[Class]DeltaTracker.simge.cs- generated entity includes
GetDelta(...)
Critical Object Class¶
Use this when a class is marked with critical semantics and you want generated manager helpers to expose failures cleanly:
EnableMetricDrivenVariants = trueIsCritical = true
Expected result:
- generated register/update helper wraps operation in
try/catch OnCriticalFault(className, ex)is invoked before rethrow
Files to Inspect¶
For the current implementation, these are the most relevant files:
SimGe.Application/CodeGenerator/CodeGeneratorManager.csSimGe.Application/CodeGenerator/CodeGeneratorSettings.csSimGe.Application/CodeGenerator/ClassGenStrategy.csSimGe.Application/CodeGenerator/Metrics/MetricEngine.csSimGe.Application/CodeGenerator/ClassCodeGen_Encoder_Fora.csSimGe.Application/CodeGenerator/ClassCodeGen_Decoder_Fora.csSimGe.Application/CodeGenerator/ClassCodeGen_Entity_Fora.csSimGe.Application/CodeGenerator/ClassCodeGen_SimMngr_Fora.csSimGe.Application/CodeGenerator/ClassCodeGen_FdGen_Fora.csSimGe.Application/CodeGenerator/ClassCodeGen_SpecializedCodec_Fora.csSimGe.Application/CodeGenerator/ClassCodeGen_DeltaTracker_Fora.csSimGe.Application/CodeGenerator/ClassCodeGen_GeneratedReadme_Fora.csSimGe.Application/CodeGenerator/Fora/ForaClientApiProfile.jsonSimGe.Application/CodeGenerator/Fora/ForaClientApiProfile.csSimGe.Application/CodeGenerator/Fora/Contract/ForaClientCallCatalog.csSimGe.Application/CodeGenerator/Fora/Contract/ForaClientApiContractValidator.csSimGe.Application/CodeGenerator/Fora/Writing/ForaClientCallWriter.csSimGe.Application/CodeGenerator/Fora/ApiContract/tools/Update-ForaClientApiProfile.ps1tools/Update-ForaClientApiProfile.cmdtools/Update-ForaClientApiContractSnapshot.ps1tools/Update-ForaClientApiContractSnapshot.cmdSimGe.Model/Helpers/Metrics/MetricAnalysisCore.csSimGe.Model/Helpers/Metrics/MetricAnalysisService.cs
Summary¶
The current Fora code generator has two operating modes:
- standard Fora generation
- metric-driven Fora generation
Metric-driven mode currently affects:
- object encoder/decoder delegation
- object delta tracking
- generated dispatch-table branches
- critical-class manager wrappers
The most important present limitation is that specialized metric-driven file generation is currently Object Class only, even though the metric analysis also evaluates Interaction Classes.
Updated July 6, 2026, 01:55:00