---
name: fusion-router
description: Make, fix or extend a Fusion router (routers/<id>/router.toml, router.lua, or a game plugin on Fusion's guest SDK) for any game, or bring a passthrough mod (a SkyCraft port, "Minecraft in <game>") into Fusion. Use for "add <game> to Fusion", "port my mod to Fusion", "fix <game>'s router after an update", "add a block to <game>'s router".
---

# Fusion routers

A **router** puts one game into Fusion as **blocks** (its World, its NPCs, a character) that
players combine with other games' blocks. Fusion runs every game hidden, draws them together
from its own camera, and passes collision, entities and input between them. A router is a
folder `routers/<id>/`:
- `router.toml`: the blocks, how the game starts, how it's set up. Most of a router is this file.
- `router.lua` (kits only): what data can't say, e.g. a menu to click through.
- `MODLOG.md` (what changed, why) and `notes.md` (gotchas for the next person).

## Pick the path (run `fusion-cli router recon <game folder>` first)

| The game | Path | Read |
|---|---|---|
| Unreal 4/5 | Unreal kit: data + a little Lua | [`unreal.md`](https://steonmod.com/docs/agent-unreal) |
| Unity IL2CPP (`GameAssembly.dll`) | Unity kit: data + a little Lua | [`unity.md`](https://steonmod.com/docs/agent-unity) |
| Unity Mono, Bethesda, Source, anything with your own plugin/DLL, open source | your plugin or program speaks Fusion through the guest SDK (C# `FusionGuest.cs`, C/C++ `fusion_guest.h`, Rust) | [`sdk.md`](https://steonmod.com/docs/agent-sdk) |
| Minecraft | already in Fusion (`minecraft.player`, `minecraft.mobs`) | |

**Porting a passthrough mod** (a SkyCraft port, "Minecraft in <game>"): run
`fusion-cli port <mod folder | owner/repo>` first and follow the `PORT.md` it writes. Don't read
the mod's repository: `PORT.md` sorts every file (delete: Fusion does it; keep: the mod's
knowledge of the game, with the lines that touch the game), and the port already has a router
draft, a scenario and a plugin template (`FusionPort.cs` / `fusion_port.cpp`). The game becomes
a World that draws from Fusion's camera; Minecraft is Fusion's `minecraft.player`.

## The loop

1. **Look first.** A mod to port: `fusion-cli port <mod>` (above). A game: `fusion-cli router recon <game folder>`: engine, path, anti-cheat, the build's
   hash, and whether a router exists. If one exists, improve it, never make a second:
   `fusion-cli router get <id> --out work/<id>`, then `fusion-cli router propose work/<id> --message "..."`.
   After a game update: `fusion-cli game diff <old dump> <new dump> --router routers/<id>`.
2. **Start.** `fusion-cli router new <id> --name "<Name>" --kit unreal|unity|sdk (--steam-app N | --exe <path>)`.
3. **Ask the game, don't grep dumps.** Game running (kit installed), Fusion closed:
   `fusion-cli game find <text> --game-id <id>`, `... classes [text]`, `... objects <Class>`,
   `... inspect <object>`; Unity also `... lua "<code>"`. A test or simulated game:
   `<Game>.exe --help`.
4. **Write the data**, then Lua or plugin code only for what data can't do.
5. **Check.** `fusion-cli router check routers/<id>`: a few lines, each failure with its fix; exit
   code 0 = pass. `--live`: the running game's kit tries the router.
6. **Measure.** `fusion-cli router conform routers/<id> --start`: starts the game, checks every
   port it gives (picture frames and lag behind Fusion's camera, collision, entities), requests
   it can't do, and sleep/wake. Publishing needs a pass.
7. **Play it** with a scenario (below): `fusion-cli check-scenario scenarios/<file>.toml`.
8. **Write it down.** A line in `MODLOG.md`; gotchas in `notes.md` (what you saw → cause → fix),
   with the game build that worked.

`fusion-cli where` prints where Fusion's docs, kits, SDK files and routers are.

## router.toml essentials

Every field: Fusion's [`docs/block-manifest.md`](https://steonmod.com/docs/block-manifest). What's easy to get wrong:
- Ids are lowercase (`a-z0-9_-`); block ids start with the router id: `mygame.world`.
- `units`: Unreal `{ length = "cm", up_axis = "z", handedness = "left" }`; Unity
  `{ length = "m", up_axis = "y", handedness = "left" }`; SDK programs send Fusion's space already:
  `{ length = "m", up_axis = "y" }`.
- Launch: `steam_app = N`, or `exe` + `args`. Paths start with a placeholder: `{game}` (the game's
  folder), `{fusion}`, `{tools}` (Fusion's programs), `{router}`, `%ENV%`. No relative paths, no
  `..`. A game outside Steam needs `[router.detect] paths = [...]`.
- SDK programs find Fusion by their discovery id: the router id, or `[router.link] game_id`.
- Blocks: `kind` (`world`, `character`, `npc_group`, `items`, `system`), `gives` (`layer:color+depth`,
  `collision`, `entities`, `pose`), `needs` (`collision`, `input`), `actions`, `cost`. One World
  per scenario; a block that isn't a World plays in Fusion's playground. Kits do a block's work
  only if the block gives that port.
- `[router.setup]`: requirement checks and copy steps players run with one click (examples in
  [`unreal.md`](https://steonmod.com/docs/agent-unreal), [`sdk.md`](https://steonmod.com/docs/agent-sdk)).
- `[router.anticheat]`: only for a game's own official anti-cheat-off mode.

## A scenario (what players press Play on)

```toml
[scenario]
name = "Minecraft in My Game"
description = "Play as the Minecraft player in My Game's world."

[[block]]
use = "mygame.world"

[[block]]
use = "minecraft.player"
```

## Rules

- Data before Lua before code. Something every game on an engine needs belongs in the kit, not
  a router: say so in `notes.md`.
- Try against a test or simulated game first, the real game last (it takes minutes to start).
- After 3 identical failures, stop: write what you know in `MODLOG.md` and change approach.
- Never focus a game window or send it input while a person is using the PC. Stop processes by
  id, never by name.
- Single-player and offline only. Never touch anti-cheat, online modes or copy protection.
- Never put game files, extracted assets, decompiled code or memory addresses in a router: the
  publish check refuses them. Reading the player's own install at runtime for names and lists is
  fine (`[[block.content]]`).
- No Nintendo or Take-Two games.

## Reference (read only what you need)

- [`unreal.md`](https://steonmod.com/docs/agent-unreal), [`unity.md`](https://steonmod.com/docs/agent-unity), [`sdk.md`](https://steonmod.com/docs/agent-sdk): one per path, with the data, the Lua or SDK calls, an example.
- `example-unreal.router.toml` + `example-unreal.router.lua`: a complete Unreal router.
- `example-unity.router.toml`: a Unity router.
- `example-sdk.router.toml`: a router for a plugin on the guest SDK, with its one-click setup.
  (The examples are made-up games: they pass `router check`, but there's no game to run them.)
- Fusion's `docs/` (`fusion-cli where`): [`making-routers.md`](https://steonmod.com/docs/making-routers) (overview), [`porting.md`](https://steonmod.com/docs/porting),
  [`router-api.md`](https://steonmod.com/docs/router-api), [`block-manifest.md`](https://steonmod.com/docs/block-manifest), [`guest-sdk.md`](https://steonmod.com/docs/guest-sdk), [`protocol.md`](https://steonmod.com/docs/protocol).
