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).
Summary
Types
What a player carries from level to level: the 64 spawn parameters, parm1 first, and the program's parm_string.
Functions
Move the host clock (clock) on by seconds; physics frames catch up to it.
Run the program's function name as it stands.
The spawn parameters the player carries to the next level (save_spawn_parms/1's parms).
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.
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).
The value of console variable name as a number (FTE's value), 0.0 when there is no such variable.
Whether there is a console variable name.
The value of console variable name as text, "" when there is no such variable.
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.
The events of the frames since the last drain, oldest first, and the server without them.
Add an event for the client.
The options every call into the program takes: the server's budget and trace, and
QuakeServer.Autocvars.sync/1 run before the call.
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.
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.
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.
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.
The name of player entity: its name info key, Player without one (FTE's name default).
Print lines to the console, each as a {:print, :notify, line} event.
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).
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.
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 QuakeC function value function with self and other set, at the server's time.
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.
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.
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.
Whether the program saves and restores a level itself (SV_PerformSave and SV_PerformLoad).
Set self, other and time for a call into the program.
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.
Types
What a player carries from level to level: the 64 spawn parameters, parm1 first, and the program's parm_string.
@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() }
Functions
Move the host clock (clock) on by seconds; physics frames catch up to it.
Run the program's function name as it stands.
The spawn parameters the player carries to the next level (save_spawn_parms/1's parms).
@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.
@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).
The value of console variable name as a number (FTE's value), 0.0 when there is no such variable.
Whether there is a console variable name.
The value of console variable name as text, "" when there is no such variable.
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.
The events of the frames since the last drain, oldest first, and the server without them.
Add an event for the client.
The options every call into the program takes: the server's budget and trace, and
QuakeServer.Autocvars.sync/1 run before the call.
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.
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.
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.
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.
@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 to the console, each as a {:print, :notify, line} event.
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).
@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.
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.
@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 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.
@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.
@spec saved_level(String.t()) :: %{ cvars: %{required(String.t()) => 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.
Whether the program saves and restores a level itself (SV_PerformSave and SV_PerformLoad).
@spec set_globals(t(), non_neg_integer(), non_neg_integer()) :: t()
Set self, other and time for a call into the program.
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'sQuakeServer.Sourcemodule (required); the program functions itsreplacements/0names run as the game's functions (QuakeServer.Builtins.call/3):builtins— the module whosecall/3runs the program's builtins, defaultQuakeServer.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 ofsizemoves through in a brush model, defaultQuakeServer.World.choose_hull/2:inhibit—fun(spawnflags, skill), true for a map entity to leave out, defaultQuakeServer.Q.skill_inhibited?/2; a program withCheckSpawnfilters 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— theQuakeServer.Cvarstable of console variables to use, shared with whatever else holds it; default a table of the server's own, freed byrelease/1. FTE's engine variables are registered in it (QuakeServer.Cvars.Engine), its:maplatchvariables take their latched values, and it is marked as having a server running. The skill option setsskill; without one a blankskillbecomes 1.:cvars— console variables to set in the table, name to text or number, assetsets 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; seeQuakeServer.Builtins.Write:startspot— the landmark name the last level'schangelevelgave, put in the program'sstartspotglobal once the entities have spawned and settled:written— the files the program wrote on earlier levels, name to bytes (the host'sext.writtenof the last level):entity_tables— the entity tables of those files (the host'sext.entity_tablesof the last level), by which the program'sedict_numtranslates the entity numbers it reads from them; seeQuakeServer.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.