# Loading & switching games

> Load registry releases or local projects, and switch games without disconnecting players.

A room runs one game at a time, but it doesn't have to be the same game all
day. A room can switch games while players stay connected, which is how a
room offers a choice of games or updates to a new release without kicking
anyone out.

## Where a game comes from

The `game` option of `Room.launch`, and `room.load`, accept three kinds of
source:

| `game` value             | Source                                                                       |
| ------------------------ | ---------------------------------------------------------------------------- |
| `"ns/slug@version"`      | a registry release, authorized by the room's credential and cached by digest |
| `{ path: "<dir>" }`      | a game project, built in memory exactly like `disko publish --dry-run`       |
| `{ path: "<file>.tgz" }` | a local archive, for example from `disko publish --dry-run --out`            |

Use a registry release in production. The two local forms are for
development and testing: they skip the registry and its access checks, and
ignore the `game` address in their `game.json`. All three go through the same
checks as publishing, so a game that loads locally will also publish.
Relative paths resolve from the current directory.

## Switching games

`room.load(game, options?)` replaces the running game with another. The switch
is all-or-nothing: the new game is fully prepared before it takes over, so if
anything goes wrong, nothing changes for the players.

```mermaid alt="room.load prepares the new game. If it loads, it replaces the old game and players stay connected while the new game starts fresh. If it fails, the old game keeps running and load rejects with a DiskoError."
flowchart LR
  load["room.load(next)"] --> prepare["Prepare the<br/>new game"]
  prepare -- "ready" --> swap["New game takes over;<br/>players stay connected"]
  prepare -- "fails" --> keep["Old game keeps running;<br/>load rejects"]
```

On success, `load` resolves to the new game's `{ reference, path, digest }`
once it's Ready. On failure it rejects with a `DiskoError` (`game_not_found`,
`game_removed`, `game_invalid`, `game_build_failed` or `game_start_failed`),
and the previous game keeps running:

```js title="room.js"
try {
  // Players stay connected; the new game starts fresh once it is Ready.
  const loaded = await room.load("gabriel/hockey@2.0.0");
  console.log(`now running ${loaded.reference} (${loaded.digest})`);
} catch (error) {
  if (!(error instanceof DiskoError)) {
    throw error;
  }

  // The previous game keeps running. `game_invalid` and `game_build_failed`
  // carry the problems.
  console.error(`switch failed: ${error.code}`, error.problems ?? []);
}
```

```js title="room.js"
// A local project directory, built in memory like `disko publish --dry-run`.
await room.load({ path: "../arena" });

// A local archive, for example from `disko publish --dry-run --out`.
await room.load({ path: "./arena-1.4.2.tgz" });
```

`options.players` sets the new game's name policy, as the `players` launch
option does for the first game. It does not carry over: without it, the new
game uses `{ name: "display" }`. `room.game` always describes the loaded game,
including the permissions it declares.

## Access and deprecation

A room can only load releases its owner is allowed to read, and that's
checked every time, so taking away access takes effect on the next load.

- A room re-authorizes every registry load, even from its cache. A private
  release the room's owner cannot read fails with `game_not_found`, the same
  as a missing one; a release taken down fails with `game_removed`.
- Revoking access never stops a room already running that game.
- A deprecated release loads normally; the warning appears in `game-loaded`
  and the log:

```js title="room.js"
room.on("game-loaded", ({ reference, deprecation }) => {
  if (deprecation !== null) {
    console.warn(`${reference} is deprecated: ${deprecation.message}`);
  }
});
```

See [Private games & sharing](/registry/private-games).
