Table of Contents

Contributor Architecture

For people working on Concord itself. If you're writing a normal mod, you can skip this.

Layers

Concord is split into layers so mod authors get a small API while the runtime work stays isolated.

Layer Current project Job
Detour Concord.Detour Redirect a game method to a generated wrapper
Emit Concord.Emit Build the generated wrapper method
Model Planned Concord.Model Track owners, ordering, apply, and unpatch state
Public API Planned Concord Expose Patcher, Apply<TPatch>(), PatchAll, and reverse patches
Generator Planned Concord.Generators Validate patch templates at build time

How composition works today

WrapperComposer.Compose does the current low-level work:

  1. Resolve async and iterator methods to generated MoveNext methods.
  2. Clone the original body into a pristine method.
  3. Copy the original body into a wrapper spine.
  4. Copy injection bodies into the wrapper.
  5. Lower marker calls like CallbackInfo.Cancel().
  6. Remap shadow fields to real target fields.
  7. Emit the wrapper method.

The result is a ComposeResult: Wrapper is the generated method to install as the detour replacement, and PristineClone is a clean clone of the original method body.

Detour layer

IDetourBackend is the interface Concord uses to install a wrapper. The default is MonoModDetourBackend, which sits on top of MonoMod.Core. IDetourHandle.Dispose() undoes and disposes the detour. That's the foundation for real unpatching.

Emit layer

BodyCopier owns most of the IL-copying mechanics: cloning original instructions and exception handlers, remapping target arguments, mapping template shadow fields to target fields, lowering callback markers into wrapper locals, splicing around injections, and inserting or wrapping call-site injections.

Invalid shapes fail with ConcordEmitException and a stable CONCxxx code. These codes should stay stable. Users and tests will rely on them.

The rule

When adding a new user-facing feature, keep the beginner API simple first. Internals can be as complex as they need to be, but a mod author's patch should still read like normal C#.