SteonMod
View as Markdown


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 gamePathRead
Unreal 4/5Unreal kit: data + a little Luaunreal.md
Unity IL2CPP (GameAssembly.dll)Unity kit: data + a little Luaunity.md
Unity Mono, Bethesda, Source, anything with your own plugin/DLL, open sourceyour plugin or program speaks Fusion through the guest SDK (C# FusionGuest.cs, C/C++ fusion_guest.h, Rust)sdk.md
Minecraftalready in Fusion (minecraft.player, minecraft.mobs)

Porting a passthrough mod (SkyCraft port, a ReShade or WebSocket bridge): the game becomes a World guest that draws from Fusion's camera; Minecraft is Fusion's minecraft.player. Keep the mod's knowledge of the game; delete its link, its Minecraft fork, its compositing, its frame sync and its installer. Part-by-part table: sdk.md, "Porting".

The loop

  1. Look first. 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. 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, sdk.md).
  • [router.anticheat]: only for a game's own official anti-cheat-off mode.

A scenario (what players press Play on)

[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, unity.md, sdk.md: 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 (overview), porting.md, router-api.md, block-manifest.md, guest-sdk.md, protocol.md.