Skip to content

Code Generation

Games use config data to shape every mechanic and gameplay experience. A designer builds a config file with typed fields, and a programmer writes code to mirror every single one. It is the same routine every time: going through a design file, adapting each field name, picking a matching type, moving to the next file — and starting over when the design iterates.

Archmage ends that loop with an elegant code generation pipeline. Reusing the exact same config files for data export, it generates clean, strongly typed code across your target languages.

Powered by a rich, unified type system across spreadsheets and tree-structured data, every config file becomes a code contract. Design changes then flow directly into your codebase: a designer adds or modifies a field, and its code model absorbs it automatically — eliminating back-and-forth discussions and leaving no room for misunderstanding.

As a result, programmers update config models and code boilerplate — such as HeroTable, GameCfg — with just one Archmage command.

Terminal window
archmage struct -t json-cs -o ./Conf "configs/*.xlsx" "configs/*.yaml"

Archmage provides SDKs for different programming languages, bringing config loading down to a few lines of code — get started with C# or Go.

  1. Discover — Archmage scans for spreadsheets and tree-structured data files matching the specified paths or patterns.

    Archmage also provides advanced table resolvers: an index table allows a single Excel file to export multiple worksheets, while a virtual table allows several regular tables to act as a unified logical table.

  2. Build Type Tree — Archmage parses input files to extract data types and establish the underlying type tree. Here, the pubtype option assigns explicit type names to enclosing objects, enabling type sharing across files.

  3. Prune — Archmage applies filters to trim structural nodes from the type tree.

  4. Generate — Archmage renders templates into strongly typed code, builds a ConfigAtlas, and prepares artifacts.

  5. Write — Archmage writes the generated code, the ConfigAtlas, and all artifacts to the output directory.

Enum type code is generated by archmage enum, not by archmage struct. To link the two steps, pass the same enum definition files via the --enum-files CLI flag when running archmage struct. This allows every enum field in your config code to resolve to its type.

A template decides what the generated code looks like. Built-in templates target Go and C#, plus a variant for Unity Editor. --template selects one of these or takes a file path to a custom template. Where the template alone is not sufficient, --overrides applies additional template fragments — for example, cs-unity-vector replaces the standard vector types with Unity’s.

Regular tables, property sheets, tree-structured data files, and virtual tables are all config sources. Each config source yields a top-level type in a separate generated file. For each regular table, Archmage additionally emits a dedicated ID type for ease of use (see Config ID).

DescSpell nameBase powerTime between castsBound rune
Namenamepowercooldownrune
Typel10nintdurationref@spell-rune
101Fireball451m30spyroblast
102Frost Nova3045sdeep-freeze
// Code generated by (shadop.dev) archmage. DO NOT EDIT.
public partial struct SpellCfgId
{
public long Value;
public readonly SpellCfg Cfg => ConfigAtlas.Instance.SpellTable[Value]!;
}
public partial class SpellTable : Dictionary<SpellCfgId, SpellCfg> { }
public partial class SpellCfg
{
[JsonProperty("id")] public SpellCfgId Id { get; set; }
[JsonProperty("name")] public L10n Name { get; set; }
[JsonProperty("power")] public long Power { get; set; }
[JsonProperty("cooldown")] public Duration Cooldown { get; set; }
[JsonProperty("rune")] public XRef<SpellRuneCfgId, SpellRuneCfg> Rune { get; set; }
}

ConfigAtlas is the hub of the generated code — an umbrella type with one field per config source. Typically, a single instance is active at runtime, acting as the global store for all config data.

// Code generated by (shadop.dev) archmage. DO NOT EDIT.
public partial class ConfigAtlas
{
public static ConfigAtlas Instance = null!;
public AtlasExtension Extension { get; private set; }
public GameCfg GameCfg { get; set; }
public SpellRuneTable SpellRuneTable { get; set; }
public SpellTable SpellTable { get; set; }
// ... one field per config source
}

The Archmage SDK fills the ConfigAtlas for you: it reads atlas.json, loads every file listed there, and binds every cross-table reference.

AtlasExtension is your custom extension of ConfigAtlas. It is generated by Archmage as an empty stub and will never be regenerated.

// This file will not be regenerated. Safe to edit.
public partial class AtlasExtension
{
// Put your config extensions here.
public void OnLoaded(ConfigAtlas atlas)
{
// Initialize your config extensions here.
}
}

The Archmage SDK invokes AtlasExtension.OnLoaded after all configs are loaded and all references are resolved. At this point, atlas is fully initialized and ready to use for indexes, derived values, and complex validations.

Version information is collected when --semver or --vcs is set. --semver specifies the semantic version for this build. --vcs resolves version control information from the current working directory, a specific repository path, or a custom file. Archmage embeds this info in the generated code and additionally writes it to version.json in the output directory.

At runtime, CodeVersion identifies the config version the code was built from, while DataVersion identifies the version the loaded data was exported from. Comparing the two reveals any version difference between code and data.

Archmage provides a wide range of flags for code generation, including essential settings, filtering options, data-type defaults, template overrides, and name suffix controls.

For the complete list of flags, see archmage struct.