# Servers and addons

A server naming what it uses, and why it can never name where to get it

Source: https://socketsvc.vercel.app/addons/servers
A server can say which addons it runs. They appear on your **Addons** tab under "This server uses", with an install button for anything you are missing.

```yaml title="plugins/SocketSVC/config.yml"
addons:
  uses:
    - cinema
    - walkie-talkie
```

`/ssvc-server reload` applies a change without reconnecting anybody; `/ssvc-server status` lists what is being advertised. See [server configuration](/server/configuration#telling-clients-what-you-use).

## Ids only

<Callout type="warn" title="A server names an addon. It can never say where to download it from">
  This is the rule the whole feature rests on. A server sends an **id**; your client looks that id up in the index **you** configured and downloads from there.

  A server handing your game a jar location would be remote code execution with a progress bar — so the message a server sends is a space-separated list of ids, and an id cannot contain `/` or `:`. There is nowhere in the format to put a URL, which is a stronger guarantee than a promise not to read one.
</Callout>

An id a server asks for that your index does not offer shows as **Not in your index**, rather than as a button that cannot work. Where to get it is not the server's to say.

## Nothing is required

Voice works whether or not you install any of it. The only thing you miss is whatever those addons do.

## Required addons

A server can go one step further and mark an addon as **required**:

```yaml title="plugins/SocketSVC/config.yml"
addons:
  required:
    - cinema
```

When you connect without it, your client downloads it from **your own** index, switches it on, and tells you in chat. If you have it but your index has a newer build, it is updated the same way, so a required addon keeps up with the server. If you already have it but switched it off, it is switched back on, and chat says that too. On the Addons tab the row reads *required by this server*.

Nothing about where the code comes from changes: it is still your index, and an id your index does not offer is reported in chat rather than fetched from anywhere else. If you would rather press the button yourself, turn off **Install what a server requires** on the Addons tab — chat then tells you what the server wants and leaves the rest to you.

There is still **no switch that refuses you** for lacking an addon. Refusing players is what [`require-client`](/server/configuration#requiring-the-client-mod) is for, and it is about the voice mod itself.

## A mod cannot arrive in time

An **addon** a server asks for can be switched on as soon as it downloads.

A **mod** cannot load until you restart, so the session that offered it goes without — and the row says so rather than implying otherwise. Install it, finish playing, and it is there next time.

## Removing one a server uses

Allowed, at any time. That feature stops working for you and nothing else changes; the next time you join you are offered it again.

## Addons that run on the server

Some features have a server half as well. Those ship as **server addon jars**: plain Java against `com.socketsvc.api.addon`, dropped in SocketSVC's own `addons/` folder.

```text
plugins/SocketSVC/addons/socketsvc-addon-cinema-server-0.2.0.jar
plugins/SocketSVC/addons/cinema.yml
```

**One jar for every platform.** A server addon never touches a Bukkit type, a Minecraft type or a loader type, so the same file runs on Paper, Fabric, NeoForge and Forge. That is the whole reason SocketSVC has a loader for them rather than four plugins that do the same thing.

They load at startup and again on `/ssvc-server reload`, which re-reads the folder — so adding or deleting one needs no restart. They are deliberately **not** hot-swapped mid-session the way client addons are: the client can toggle an addon because the only thing watching is that player, while a server addon holds state other people are connected to.

An addon that fails to load is reported and skipped, and `/ssvc-server status` names it along with why. The server still starts and the other addons still load: nothing dropped in that folder can stop players getting in.

### What one is handed

```java title="ExampleServerAddon.java"
public final class ExampleServerAddon implements SocketSvcServerAddon {
    @Override public void onEnable(ServerAddonContext context) {
        String greeting = context.config().getString("greeting", "hello");
        context.command((caller, args) -> List.of(greeting + " " + caller.name()
            + (caller.isPlayer() ? " at " + caller.x() + "," + caller.z() : "")));
    }

    @Override public void onDisable() { }
}
```

| | |
| --- | --- |
| `config()` | The addon's own `addons/<id>.yml`, as typed getters. Its own file rather than a block in `config.yml`: an addon you delete should take its settings with it. |
| `dataDirectory()` | A directory of its own, for anything that is not configuration. |
| `command(handler)` | Reached as `/ssvc-server addon <id> ...`, behind `socketsvc.admin.addon`. Words in, lines out — SocketSVC owns the command and dispatches into it, because a plain jar cannot register one with Bukkit or Brigadier. The handler is also given **who ran it and where they are standing**, so a command can mean "here" instead of asking for three numbers off the debug overlay. Implement `complete` on it for tab completion past your id. |
| `configFile()` | The `addons/<id>.yml` your config came from. Commands that change what a config file describes have to write them back, or every change is lost on restart. |
| `screens()` | The screen and timecode sync. It lives in SocketSVC because the screens ride the voice status channel and the playhead has to be re-sent on the relay's own schedule; defining screens and driving them is what an addon does with it. See [Cinema](/addons/cinema). |
| `log(message)` | The server log, prefixed with the addon's id. |

The manifest is the same `socketsvc.addon.json` a client addon carries, with `"side": "server"`:

```json title="socketsvc.addon.json"
{
  "kind": "addon",
  "side": "server",
  "id": "example",
  "name": "Example",
  "version": "1.0.0",
  "main": "com.example.ExampleServerAddon"
}
```

Compile against `com.socketsvc:socketsvc-server-mod-api` with `compileOnly` and never shade it. SocketSVC's own classloader is the addon's parent and already has the API; a shipped copy would load a second one inside the addon's loader and fail every cast across the boundary.