# game global

> Lifecycle, players, permissions, events, chat and asset imports, generated from the shipped declarations.

Generated from the declarations in `@disko-game/build/types`, which editors
use for type checking. Types live in the `Disko` namespace, for example
`Disko.Player`. See [Players, teams & actions](/games/players-teams-actions)
for a guide.

## The `game` global

Lifecycle, players, permissions, events and chat.

```ts
declare const game: Disko.Game;
```

## Common types

### Disko.JsonValue

A JSON value, as carried by `game.emit` payloads.

```ts
type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
    readonly [key: string]: JsonValue;
};
```

### Disko.Vector

A point or vector in world units.

```ts
interface Vector {
    readonly x: number;
    readonly y: number;
}
```

### Disko.PackageAsset

An imported asset: `import puck from "./puck.png"`. Its `name` is the asset's package path. Every import of one path yields the same frozen object.

```ts
interface PackageAsset {
    readonly kind: "package-asset";
    readonly name: string;
}
```

### Disko.Subscription

Returned by `game.on`; `remove()` unsubscribes from the next turn.

```ts
interface Subscription {
    remove(): void;
}
```

## Players and actions

### Disko.Player

A connected player. The same object is returned for the same player.

```ts
interface Player {
    readonly id: number;
    readonly name: string;
    readonly controlledObject: Disc | null;
    play(): void;
    spectate(): void;
    control(disc: Disc): void;
    release(): void;
    setRadius(radius: number): void;
    setAvatar(avatar: string | PackageAsset | null): void;
    setAcceleration(value: number): void;
    setDamping(value: number): void;
    useActionSchema(schema: ActionSchema): void;
    isHolding(action: Action): boolean;
}
```

| Member | Description |
| --- | --- |
| `id` | Room-local identity, stable for the connection. |
| `name` | Display name under the room's name policy. |
| `controlledObject` | The disc this player controls, or `null`. |
| `play()` | Asks the engine to make this player a participant (`player-enter`). |
| `spectate()` | Moves this player to spectators (`player-exit`). |
| `control()` | Gives this player native movement control of a disc. |
| `release()` | Releases the controlled disc. |
| `setRadius()` | Sets the controlled disc's radius. |
| `setAvatar()` | Sets the controlled disc's avatar: text, an image asset, or `null`. |
| `setAcceleration()` | Movement acceleration per tick. |
| `setDamping()` | Movement damping per tick. |
| `useActionSchema()` | Selects the action schema this player's inputs use. |
| `isHolding()` | Whether the player currently holds an action of their schema. |

### Disko.ActionBehavior

Native behavior of an action, for example a kick.

```ts
interface ActionBehavior {
    readonly type: string;
    readonly parameters?: {
        readonly [name: string]: JsonValue;
    };
}
```

### Disko.Action

One declared action.

```ts
interface Action {
    readonly label: string | undefined;
    readonly behavior: ActionBehavior | null | undefined;
}
```

### Disko.ActionSchema

A set of actions a player can use; created during top-level evaluation.

```ts
interface ActionSchema {
    defineAction(options: {
        readonly label: string;
        readonly behavior?: ActionBehavior;
    }): Action;
}
```

## Permissions

### Disko.PermissionDefault

Who holds a permission when the room decides nothing: `"everyone"` (a normal player ability), `"restricted"` (no normal player; only the room grants it, such as to its admins), or `"owner"` (the connected player signed in with the room owner's account, never a guest).

```ts
type PermissionDefault = "everyone" | "restricted" | "owner";
```

### Disko.PermissionOptions

Options of `game.permission`.

```ts
interface PermissionOptions {
    readonly default: PermissionDefault;
    readonly label?: string;
}
```

| Member | Description |
| --- | --- |
| `default` | The declared default. |
| `label` | Shown to the room; defaults to the permission's name. |

### Disko.Permission

A declared permission, created by `game.permission` during top-level evaluation. Only handles returned by `game.permission` are accepted where a permission is expected.

```ts
interface Permission {
    readonly __permission: never;
    readonly name: string;
    readonly label: string;
    readonly default: PermissionDefault;
    setDefault(player: Player, allowed: boolean): void;
}
```

| Member | Description |
| --- | --- |
| `name` | 1-64 lowercase ASCII letters, digits, `-`, `_`, `.` or `:`, starting with a letter. |
| `setDefault()` | Sets the game-managed default for one player, applied after this turn commits: `game.can` observes it from the next turn, together with a `permission-change` event. Unavailable at top level. |

## Chat

### Disko.MessageSpan

One span of a structured chat message.

```ts
interface MessageSpan {
    readonly text: string;
    readonly color?: string;
    readonly weight?: "normal" | "bold";
    readonly style?: "normal" | "italic";
}
```

### Disko.Message

A structured chat message.

```ts
interface Message {
    readonly author?: Player;
    readonly content: string | readonly MessageSpan[];
    readonly sound?: "none" | "normal" | "notification";
}
```

## Events

### Disko.UiRequestEvent

A `ui-request` event: a player used a control with `ui.request`.

```ts
interface UiRequestEvent {
    readonly id: number;
    readonly event: string;
    readonly player: Player;
    readonly source: UiNode | undefined;
    readonly target: UiNode | undefined;
    readonly interaction: UiTrigger;
    readonly values: any;
    respond(output: UiNode | UiSwap | readonly UiSwap[]): void;
}
```

| Member | Description |
| --- | --- |
| `respond()` | Replies to the requesting control once: content placed at the request's target with its swap method, or explicit swaps. |

### Disko.TickEvent

The `tick` and `post-tick` turns, with the turn's events.

```ts
interface TickEvent<Phase extends "tick" | "post-tick"> {
    readonly tick: number;
    readonly phase: Phase;
    readonly events: readonly unknown[];
}
```

| Member | Description |
| --- | --- |
| `events` | The payloads of this turn's events, in delivery order. |

### Disko.GameEventMap

Events with a known payload.

```ts
interface GameEventMap {
    "player-join": {
        readonly player: Player;
        readonly displayName: string;
    };
    "player-leave": {
        readonly player: Player;
        readonly displayName: string;
    };
    "player-enter": {
        readonly player: Player;
        readonly controlledObject: Disc | null;
    };
    "player-exit": {
        readonly player: Player;
        readonly controlledObject: Disc | null;
    };
    start: {
        readonly generation: number;
    };
    stop: {
        readonly generation: number;
        readonly finalTick: number;
        readonly reason: "stopped" | "finished";
    };
    pause: {
        readonly generation: number;
        readonly tick: number;
    };
    resume: {
        readonly generation: number;
        readonly tick: number;
    };
    tick: TickEvent<"tick">;
    "post-tick": TickEvent<"post-tick">;
    "ui-request": UiRequestEvent;
    "action-press": {
        readonly player: Player;
        readonly action: Action;
    };
    "action-release": {
        readonly player: Player;
        readonly action: Action;
    };
    "before-action": {
        readonly player: Player;
        readonly action: Action;
        readonly controlledObject: Disc | null;
        cancel(): void;
    };
    action: {
        readonly player: Player;
        readonly action: Action;
        readonly controlledObject: Disc | null;
        readonly targets: readonly Disc[];
    };
    "sensor-enter": {
        readonly sensor: PhysicalObject | null;
        readonly object: PhysicalObject | null;
    };
    "sensor-leave": {
        readonly sensor: PhysicalObject | null;
        readonly object: PhysicalObject | null;
    };
    crossing: {
        readonly crossing: PhysicalObject | null;
        readonly object: Disc | null;
        readonly direction: "forward" | "backward";
        readonly position: Vector;
        readonly fraction: number;
    };
    "permission-change": {
        readonly player: Player;
        readonly permission: Permission;
        readonly allowed: boolean;
    };
}
```

| Member | Description |
| --- | --- |
| `"permission-change"` | A `game.can` value changed. Delivered after the change commits: immediately while ready or paused, at the next boundary while running. |

### Disko.GameEvent

The payload of an event: typed for the events in `GameEventMap`, `any` for events the room sends with `room.emit`.

```ts
type GameEvent<Name extends string> = Name extends keyof GameEventMap ? GameEventMap[Name] : any;
```

### Disko.Game

The `game` global: lifecycle, players, permissions, events and chat.

```ts
interface Game {
    readonly ui: Ui;
    readonly players: readonly Player[];
    on<Name extends string>(name: Name, handler: (event: GameEvent<Name>) => void): Subscription;
    createActionSchema(): ActionSchema;
    permission(name: string, options: PermissionOptions): Permission;
    can(player: Player, permission: Permission): boolean;
    send(message: string | Message): void;
    start(): void;
    stop(): void;
    pause(): void;
    resume(): void;
    finish(): void;
    playSound(sound: PackageAsset, options?: {
        readonly source?: Disc;
    }): void;
    emit(name: string, payload?: JsonValue): void;
}
```

| Member | Description |
| --- | --- |
| `ui` | The same object as the `ui` global. |
| `players` | Connected players, spectators included. |
| `on()` | Subscribes to an event, including those the room sends with `room.emit`; changes apply from the next turn. |
| `createActionSchema()` | Creates an action schema; only during top-level evaluation. |
| `permission()` | Declares a permission; only during top-level evaluation, at most 64 per game, each name once. |
| `can()` | Whether a player holds a permission in this turn. Every read in one turn observes the same decisions; a pending room decision reads as denied. |
| `send()` | Sends a chat message to the room. |
| `start()` | Asks the room to start a match. |
| `stop()` | Asks the room to stop the match. |
| `pause()` | Asks the room to pause the match. |
| `resume()` | Asks the room to resume the match. |
| `finish()` | Ends the match as finished. |
| `playSound()` | Plays an audio asset, optionally positioned at a disc. |
| `emit()` | Sends an event to the room host (`room.on("game:<name>")`). |

## Errors

### StaleHandleError

Thrown when a handle is used outside its lifetime: a physical object or HUD node after its match stopped, or a Menu node of a replaced game.

```ts
declare class StaleHandleError extends Error {
    readonly name: "StaleHandleError";
}
```

## Asset modules

Asset imports. The only form is a default import, `import puck from "./puck.png"`, whose value is the frozen `{ kind: "package-asset", name: "<package path>" }` reference.

| Module | Default export |
| --- | --- |
| `*.png` | `Disko.PackageAsset` |
| `*.jpg` | `Disko.PackageAsset` |
| `*.jpeg` | `Disko.PackageAsset` |
| `*.webp` | `Disko.PackageAsset` |
| `*.mp3` | `Disko.PackageAsset` |
| `*.ogg` | `Disko.PackageAsset` |
| `*.wav` | `Disko.PackageAsset` |
