# Unity routers (Fusion's Unity kit)

For Unity games built with **IL2CPP** (a `GameAssembly.dll` next to the game's exe). The kit is a
MelonLoader mod plus `fusion_unity.dll`. Unity **Mono** games (a `<Game>_Data/Managed` folder,
BepInEx 5, OWML) aren't on the kit yet: use your own plugin with the C# SDK ([`sdk.md`](https://steonmod.com/docs/agent-sdk)).

What the kit does by itself, with no router code:
- draws the world from Fusion's camera with depth: it finds the camera that really draws the
  world (games often render a hidden world camera themselves) and moves it to Fusion's camera
  while it renders, then gives the game its camera back. On Direct3D 11 the picture goes to
  Fusion on the GPU (about 1 frame behind Fusion's camera); otherwise it's read back;
- opens `bind.map` once the game has booted, waits for the world, and puts Fusion's origin on
  the ground under the game's own view;
- traces collision around Fusion's camera (if a block gives `collision`);
- lists NPCs (if a block gives `entities`): your `bind.entity` rules, or anything with a
  `NavMeshAgent`; spawns copies of loaded prefabs; teleports the player; `remove`, `set_health`,
  `move_to`, `stop`;
- keeps the game running when it isn't the window in front.

Not yet on the Unity kit: playing as the game's character, `player_follows_camera`.

## Data: `[block.bind]`

```toml
[block.bind]
map = "Level01"                  # the scene to open once the game has booted
camera = "Main Camera"           # the camera whose picture reaches the screen (default: the main 3D camera)
player = "PlayerController"      # a component class on the player (default: the GameObject tagged Player)

[[block.bind.entity]]            # on a block that gives entities; one rule per kind
class = "BaseAi"                 # a component's class name
kind = "animal"
name = "Animal"
health = "m_CurrentHP"           # field paths on that component
max_health = "m_MaxHP"
spawn = "WILDLIFE_Wolf"          # a prefab or object the game has loaded, by name, or a Resources path
```

## Lua: `router.lua`

The same `Router.block` and sandbox as on Unreal. `Game.*` reaches the game's objects through
Il2CppInterop reflection:
- `o.field`, `o.field = v`, `o:Method(...)` on any component (`panel:IsEnabled()`,
  `ai.m_CurrentHP`); `o.gameObject.name` follows properties; `list[1]` reads an element (from 1);
  enums arrive as their names (`"Wolf"`); positions are `{ X, Y, Z }` in Unity's meters.
- Unity adds `Game.static(class, name)` (a static field or property, e.g. a singleton's
  `m_Instance`, or a function calling a static method), `Game.load_scene(name)`,
  `Game.component(o, class)`, `Game.position(o)`, `Game.members(o)` (what an object has).
- `Game.find(name)` finds a GameObject or component by name; `Game.class(name)` is what to spawn.
- No player controllers or console: `Game.controller()` is nil, `Game.console()` false.

Try every line on the running game before writing it down:
`fusion-cli game lua "Game.find('Panel_MainMenu'):IsEnabled()" --game-id <id>`.

The usual job for Lua on Unity is getting from the boot screen into a world through the game's
own menu functions, one step per call of `enter` (twice a second), and never touching the
player's own saves:

```lua
Router.block "mygame.world" {
    enter = function()
        local menu = Game.find("Panel_MainMenu")
        if menu and menu:IsEnabled() then
            menu:OnNewGame()             -- the same function the game's button calls
        end
    end,
}
```

## Installing the kit (v0)

The kit's mod is built against the game's own MelonLoader files, so for now it goes into a game
with `kits\unity\install.ps1 -Game <id>` (MelonLoader installed, the game started once with it,
the game closed), not one-click setup. Logs: `UserData\FusionKit\fusion_kit.log`.

## Gotchas

- Don't click into MelonLoader's console window while the game runs: Windows' console selection
  pauses the game (`--melonloader.hideconsole` hides it).
- A copied prefab may need the game's own spawner to come alive: a Lua `spawn` can call it.
- Games that render the world several times a frame (an SSAO pass with a wider view) can give
  depth that doesn't match the picture; conformance says so.
- Example: `example-unity.router.toml` (a made-up game in the shape of a real router: a world and
  its wildlife).
