# Package files and the content browser

BUILD.md step 4.6. Code: `crates/fusion-core/src/content.rs` (format, sources, resolution,
install), `crates/fusion-godot/src/content.rs` (`FusionContent`), `godot/scripts/content_browser.gd`.

## A package file

A package file is one file ending in `.fusion`. It's a plain zip, so anyone can open it and look
inside. It holds `package.toml` and any mix of these:

| Path inside | What it is | Installed to (while developing) |
|---|---|---|
| `routers/<id>/...` | a router folder (`router.toml` + its Lua files) | `routers/<id>/` |
| `scenarios/<file>.toml` | a scenario (or an Experience) | `scenarios/` |
| `scenarios/<file>.png` | that scenario's cover picture | `scenarios/`, next to it |
| `addons/<name>/...` | a Lua addon (needs `init.lua`) | `godot/addons_dev/<name>/` |
| `devices/<type>.lua` | a Device template | `godot/devices/` |
| `thumbnail.png` | its picture in the browser | (not installed) |
| `signature.toml` | who signed it ([`trust.md`](https://steonmod.com/docs/trust)) | (not installed) |

Anything else is refused, and so are paths with `..` or a drive letter. A package unpacks to at
most 512 MB.

```toml
# package.toml
[package]
id = "zombie-arena"          # lowercase, digits, - and _; the same id replaces the old copy
name = "Zombie Arena"
version = "1.0.0"
author = "Ali"               # optional
description = "..."          # optional
requires = ["vein"]          # optional: routers it needs beyond what its scenarios use
```

Routers inside must load (`router.toml` checks, its id matches its folder), scenarios must parse.

## What it needs

A package's needs come from what's inside it, never from a list of games:
- every router whose blocks its scenarios use;
- every Device type its scenarios place;
- every addon its scenarios list (`addons = [...]`);
- the routers in `requires`.

Each need is met by what's **installed**, by the package **itself**, or by **another package
file** a source offers. That one is installed first, after its own needs. A need nobody has
blocks the install and says so in plain words.

The **ownership check** uses My Games: for every router the package needs (except Fusion's own),
is its game on this PC? "You own 1 of the 2 games this needs (not Farm Game)". Routers in the
package count too, so a friend learns which of the games they have before installing anything.
Not owning a game doesn't block installing: the scenario just shows as unplayable until they get
it.

## Installing

For each piece:
- **already installed** (same files): nothing is written;
- **installed before by this same package**: replaced (reinstall or update);
- a **different one with the same name**: a scenario gets a free name (`arena-2.toml`); a router,
  addon or Device template that's already there is **kept** (yours wins), and the browser says so.

Every file written is recorded with its sha256 in `%LOCALAPPDATA%/Fusion/packages/installed.toml`.
If a write fails halfway, what was written is taken back.

**Uninstall** removes what the package installed, except:
- files changed since (for example a scenario edited in the builder): kept, and named;
- pieces another installed package needs: that package keeps them.

## Sources

Content comes from **sources** behind one interface (`content::Source`: `list`, `fetch`):
- **Files on this PC** (`FileSource`): every `*.fusion` in the Downloads folder, plus files the
  player opens or drops on Fusion's window. The first source, always available.
- **Content hubs** (`hub::HubSource`, step 6.3, ADR 0005): each hub in Settings is a static folder
  (`index.toml` signed by Fusion, `packages/`). Fusion checks the index's signature, downloads
  each package into `%LOCALAPPDATA%/Fusion/cache/hubs/<hub>/`, and checks its sha256, size and
  signer against the index. The newest version of each package is listed. Hub operators publish
  with `fusion-cli hub add HUB PACKAGE --key OFFICIAL.key`. A router goes on a hub only with a
  passing **conformance report** for its current files (`conformance.toml`, saved by
  `fusion-cli router conform`; any change to the router means running the tests again).
  Sharing a scenario as a file with friends doesn't need one.
- The Steam Workshop (8.3) comes later, as one more source.

## Versions

Every version installed is kept in `%LOCALAPPDATA%/Fusion/packages/archive/<id>/`. **Roll back**
(in Content, under Installed) reinstalls the version before the current one and keeps the package
at it (**Keep this version** / **Allow updates**): a kept package isn't offered newer versions.
Versions compare as numbers (1.10 is newer than 1.9).

## Sharing a scenario

Main menu → **Share** next to a scenario (or on an Experience's cover) saves it as one package
file with every router it uses (except Fusion's own), the Device templates it places and the
addons it lists, so it installs on a PC that has none of them. An Experience's cover picture goes
with it and is also the package's picture; otherwise the package's picture is the one Fusion took
the last time the scenario was played (5 s after every game showed;
`user://thumbnails/<scenario>.png`). The browser calls a scenario with an `[experience]` table an
"Experience". If it's installed under a free name (`arena-2.toml`), its cover follows
(`arena-2.png`).

## Not yet

- Signatures, tiers and the publish check are in [`trust.md`](https://steonmod.com/docs/trust) (step 6.1): packages carry
  `signature.toml`, Share signs with the player's own key and refuses game files.
- Double-clicking a `.fusion` file doesn't open Fusion (needs the installer, 6.4).
- Kits (native files) can't travel in a package; a router's setup recipe still uses Fusion's own.
- No version ranges: a router that's installed meets a need whatever its version.
