# `QuakeServer.Server`
[🔗](https://github.com/jaman/quake_server/blob/v0.1.0/lib/quake_server/server.ex#L1)

A running level of a QuakeC game: the program and its entities, the map, the models and
sounds it has asked for, and what happened this frame for a client to show.

    server = QuakeServer.Server.start("e1m1", source: MyGame.Source, skill: 1)
    server = QuakeServer.Server.connect(server)
    server = QuakeServer.Server.frame(server, 1 / 60, command)
    {events, server} = QuakeServer.Server.drain(server)

A command is `%{forward:, side:, up:, angles: {pitch, yaw, roll}, attack:, jump:,
impulse:}`, the moves in units a second and the angles in degrees. For a program that
runs its players' commands itself (`QuakeServer.Physics.Command`) it is `%{forward:,
side:, up:, angles:, buttons:, impulse:}`.

Entity 0 is the world, entity 1 the player (`slots` is how many entities after the world
are player slots: 1 for a level, 0 for a client program's world). The player slots'
entities are in use from the level's start, as FTE allocates them; the player is in the
game from `connect/3` until `disconnect/1` (`parms` is `nil` while it is not).

# `command`

```elixir
@type command() :: %{
  forward: number(),
  side: number(),
  up: number(),
  angles: {number(), number(), number()},
  attack: boolean(),
  jump: boolean(),
  impulse: non_neg_integer()
}
```

# `spawn_parms`

```elixir
@type spawn_parms() :: %{parms: [number()], string: String.t() | nil}
```

What a player carries from level to level: the 64 spawn parameters, `parm1` first, and the program's `parm_string`.

# `t`

```elixir
@type t() :: %QuakeServer.Server{
  ambients: term(),
  area: term(),
  bsp: term(),
  budget: term(),
  builtins: term(),
  changelevel: term(),
  changelevel_startspot: term(),
  check: term(),
  clock: term(),
  command: term(),
  console: term(),
  coords: term(),
  count: term(),
  cvars: term(),
  data_dir: term(),
  edicts: term(),
  events: term(),
  ext: term(),
  frametime: term(),
  hull: term(),
  inhibit: term(),
  leaves: term(),
  lightstyles: term(),
  links: term(),
  map: term(),
  messages: term(),
  model_names: term(),
  models: term(),
  parms: term(),
  qc: term(),
  replacements: term(),
  serverflags: term(),
  skill: term(),
  slots: term(),
  sound_names: term(),
  source: term(),
  statics: term(),
  time: term(),
  trace: term(),
  versions: term()
}
```

# `advance`

```elixir
@spec advance(t(), number()) :: t()
```

Move the host clock (`clock`) on by `seconds`; physics frames catch up to it.

# `call_named`

```elixir
@spec call_named(t(), String.t()) :: t()
```

Run the program's function `name` as it stands.

# `change_parms`

```elixir
@spec change_parms(t()) :: [float()] | nil
```

The spawn parameters the player carries to the next level (`save_spawn_parms/1`'s `parms`).

# `client_command`

```elixir
@spec client_command(t(), non_neg_integer(), map()) :: t()
```

Run a player's command as it arrives, for a program that runs its players' commands
itself (`QuakeServer.Physics.Command`), at the host clock (`clock`); a program that
does not has `command` kept for its frames instead.

# `connect`

```elixir
@spec connect(t(), spawn_parms() | [number()] | nil, keyword()) :: t()
```

Bring the player in, as FTE does when its client begins (`SV_SetUpClientEdict`, then
`SV_Begin_Core`), carrying `parms` from the last level (`save_spawn_parms/1`, or the
bare list of 64), or with the program's `SetNewParms` run for fresh ones when `nil`.
The player's entity is cleared (not for a NetQuake program, CRC 5927), named by the
player's `name` info key (`Player` without one), and given its entity number as
`colormap`, `16 × topcolor + bottomcolor` as `clientcolors` (each 0 outside 0 to 13),
`gravity` 1, `maxspeed` the cvar `sv_maxspeed`, `movetype` noclip and no frags. The
spawn parameters go into the `parm*` globals and `parm_string`; `ClientConnect` runs
with its argument 1 when option `:csqc` is true (the client runs a client program),
0 otherwise, then `PutClientInServer`, each with `self` the player and `time` the
server's; `oldorigin` becomes `origin`; and a program that runs its players' commands
runs one empty command (no time, no moves, the angles the player's `v_angle`).

# `cvar`

```elixir
@spec cvar(t(), String.t()) :: float()
```

The value of console variable `name` as a number (FTE's `value`), 0.0 when there is no such variable.

# `cvar?`

```elixir
@spec cvar?(t(), String.t()) :: boolean()
```

Whether there is a console variable `name`.

# `cvar_string`

```elixir
@spec cvar_string(t(), String.t()) :: String.t()
```

The value of console variable `name` as text, `""` when there is no such variable.

# `disconnect`

```elixir
@spec disconnect(t()) :: t()
```

Take the player out of the level, as FTE's `SV_DespawnClient` does to a level it keeps:
`ClientDisconnect` runs with `self` the player, a NetQuake program's player entity is
cleared, the player's `frags` become 0 and the player is no longer in the game.

# `drain`

```elixir
@spec drain(t()) :: {[term()], t()}
```

The events of the frames since the last drain, oldest first, and the server without them.

# `emit`

```elixir
@spec emit(t(), term()) :: t()
```

Add an event for the client.

# `exec_opts`

```elixir
@spec exec_opts(t()) :: keyword()
```

The options every call into the program takes: the server's budget and trace, and
`QuakeServer.Autocvars.sync/1` run before the call.

# `frame`

```elixir
@spec frame(t(), number(), command()) :: t()
```

Run one physics frame of `seconds` (`QuakeServer.Physics.frame/1`), `command` being the
player's latest for a program that does not run its players' commands itself: the
routes asked for before are handed to their callbacks
(`QuakeServer.Extensions.Routes.run/1`), the replies to `uri_get` that have come to
`URI_Get_Callback` (`QuakeServer.Extensions.Web.run/1`), the console's queued commands run, then every
entity, and the physics clock (`time`) moves on by `seconds`. How long a frame should
be is the caller's choice; FTE runs them as `QuakeServer.Runner` does.

# `keeping_self`

```elixir
@spec keeping_self(t(), (t() -&gt; t())) :: t()
```

Run `call` (a function of the server) and put `self` and `other` back as they were, as
a builtin that calls back into the program must.

# `load_level`

```elixir
@spec load_level(t(), String.t()) :: t()
```

Restore onto a freshly started level the save `text` of `save_level/1`, as FTE's
`SV_LoadLevelCache`: the program's `SV_PerformLoad(file, entities, slots)` reads the
text after its `moddata` line, every entity is linked into the world again, and the
physics time, the host clock and `time` become the saved time.

# `open`

```elixir
@spec open(String.t(), keyword()) :: t()
```

Load map `name` with its world entity and the source's program, spawning nothing else
and calling no hooks: the world a client program (FTE's CSQC) runs in. Takes
`start/2`'s options; its console variable table is not marked as having a server
running and its latched variables stay latched.

# `player_name`

```elixir
@spec player_name(t(), pos_integer()) :: String.t()
```

The name of player `entity`: its `name` info key, `Player` without one (FTE's `name` default).

# `print_lines`

```elixir
@spec print_lines(t(), [String.t()]) :: t()
```

Print `lines` to the console, each as a `{:print, :notify, line}` event.

# `put_cvar`

```elixir
@spec put_cvar(t(), String.t(), String.t() | number()) :: t()
```

Set console variable `name` to `value`, text or a number (written as FTE's
`Cvar_SetValue` writes one), as FTE's `Cvar_Set` (`QuakeServer.Cvars.set/4`); a name
there is no variable for is made, as a config or program makes one. What FTE prints
about it is printed, and the server's own `autocvar_` globals and info keys follow at
once (`QuakeServer.Autocvars.sync/1`).

# `release`

```elixir
@spec release(t()) :: :ok
```

Free the level's program memory (`QuakeC.release/1`) and a console variable table the
server made itself; the server may not be used after.

# `resume`

```elixir
@spec resume(t(), keyword()) :: t()
```

Bring back a level left by a `changelevel` with a landmark, as it was left, as FTE's
`SV_LoadLevelCache` brings one back: the change it asked for is forgotten; the info
keys of option `:serverinfo` (the server's as they stand) are taken under the level's
own and the star keys of `start/2` set again for option `:startspot`; the program's
`serverflags` global becomes option `:serverflags`, `time` the level's physics time and
`startspot` the landmark; its written files become option `:written` and their entity
tables option `:entity_tables`. Connect the player to it next.

# `run`

```elixir
@spec run(t(), integer(), non_neg_integer(), non_neg_integer()) :: t()
```

Run QuakeC function value `function` with `self` and `other` set, at the server's time.

# `save_level`

```elixir
@spec save_level(t()) :: {String.t(), t()}
```

Save the level for a return through a landmark, as FTE's `SV_SaveLevelCache` saves one
for a program that saves itself: the player is taken out (`disconnect/1`), and the
text is FTE's: the version (515), a comment (the level's name and kills, 39
characters, spaces as `_`), `vmmode`, the cvars `skill`, `deathmatch`, `coop` and
`teamplay`, `time` and `map`, then `moddata` and what the program's
`SV_PerformSave(file, entities, slots)` writes to the file it is given,
`saves/<map>.lvc`. Returns the text and the server.

# `save_spawn_parms`

```elixir
@spec save_spawn_parms(t()) :: %{
  parms: [float()] | nil,
  string: String.t() | nil,
  serverflags: float()
}
```

What the level change carries, as FTE's `SV_SaveSpawnparms` takes it: the player's
spawn parameters go back into the `parm*` globals and `parm_string`, the program's
`SetChangeParms` runs with `self` the player, and the globals are read into `parms` and
`string`; with no player in the game both are `nil`. `serverflags` is the program's
global.

# `saved_level`

```elixir
@spec saved_level(String.t()) :: %{
  cvars: %{required(String.t()) =&gt; String.t()},
  time: float(),
  map: String.t(),
  moddata: binary(),
  at: non_neg_integer()
}
```

The preamble of a save from `save_level/1`: the console variables it sets, its time,
its map, and its program data with the place its `moddata` line ends.

# `saves_levels?`

```elixir
@spec saves_levels?(t()) :: boolean()
```

Whether the program saves and restores a level itself (`SV_PerformSave` and `SV_PerformLoad`).

# `set_globals`

```elixir
@spec set_globals(t(), non_neg_integer(), non_neg_integer()) :: t()
```

Set `self`, `other` and `time` for a call into the program.

# `start`

```elixir
@spec start(String.t(), keyword()) :: t()
```

Load map `name` and spawn its entities, as a fresh level, in the order of FTE's
`SV_SpawnServer`: the info keys `mapname`, `*cheats` (`ON` while the cvar `sv_cheats`
is set), `*bspversion` (`30` for a Half-Life map) and `*startspot` are set (an empty
one removed); the program is loaded, its `dimension_send` defaulted, and its `init`
called with `-1` at `time` 0; the model list is the world and its submodels; the world
entity is set up (its model, `solid` bsp, `movetype` push, its box) and the player slots'
entities allocated; the globals `mapname`, `serverflags`, `time` (1), and `coop` (when
the cvar `coop` is set) or else `deathmatch` are set; `initents` runs; a QuakeWorld
program (CRC 54730) has `StartFrame` run at time 0; the map's entities spawn; the
world's angles are cleared and the level's name taken from its `message`
(`ext.levelname`); two physics frames of a tenth of a second run from time 1, leaving
the host clock at 1.3; then the info key `map` is set and the `startspot` global.

## Options

  * `:source` — the game's `QuakeServer.Source` module (required); the program
    functions its `replacements/0` names run as the game's functions
    (`QuakeServer.Builtins.call/3`)
  * `:builtins` — the module whose `call/3` runs the program's builtins, default
    `QuakeServer.Builtins`
  * `:budget` — how many statements one call into the program may run, default 100 000
  * `:trace` — a function given the name of every QuakeC function the program enters,
    default none
  * `:hull` — `fun(hulls, size)` choosing the hull a box of `size` moves through in a
    brush model, default `QuakeServer.World.choose_hull/2`
  * `:inhibit` — `fun(spawnflags, skill)`, true for a map entity to leave out, default
    `QuakeServer.Q.skill_inhibited?/2`; a program with `CheckSpawn` filters its own

A program defining `init` has it called with `-1` once its memory is fresh, and one
defining `initents` has that called before the map's entities spawn.
  * `:skill` — 0 (easy) to 3 (nightmare), default 1
  * `:serverflags` — carried from level to level (the episode runes), default 0
  * `:cvar_table` — the `QuakeServer.Cvars` table of console variables to use, shared
    with whatever else holds it; default a table of the server's own, freed by
    `release/1`. FTE's engine variables are registered in it (`QuakeServer.Cvars.Engine`),
    its `:maplatch` variables take their latched values, and it is marked as having a
    server running. The skill option sets `skill`; without one a blank `skill` becomes 1.
  * `:cvars` — console variables to set in the table, name to text or number, as `set`
    sets them
  * `:data_dir` — the directory the program's written files (`data/…`) are kept in;
    without one they last as long as the server
  * `:coords` — `:short` (Quake's) or `:float`, how messages carry coordinates and
    angles; see `QuakeServer.Builtins.Write`
  * `:startspot` — the landmark name the last level's `changelevel` gave, put in the
    program's `startspot` global once the entities have spawned and settled
  * `:written` — the files the program wrote on earlier levels, name to bytes (the
    host's `ext.written` of the last level)
  * `:entity_tables` — the entity tables of those files (the host's
    `ext.entity_tables` of the last level), by which the program's `edict_num`
    translates the entity numbers it reads from them; see `QuakeServer.EntityTable`
  * `:serverinfo` — the server's info keys as the last level left them, kept under
    the keys this level sets, as FTE keeps its server info from level to level

A `changelevel` asked for during play leaves the map in `changelevel` and the
landmark, when one was given, in `changelevel_startspot`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
