QuakeServer.Cvars (quake_server v0.1.0)

Copy Markdown View Source

FTE's console variables: one table every process of a game reads and writes, the server, its client program and its menu alike, as FTE's single process has one set.

cvars = QuakeServer.Cvars.new()
QuakeServer.Cvars.register(cvars, "sv_gravity", "800")
{:ok, _prints} = QuakeServer.Cvars.set(cvars, "sv_gravity", "600")
QuakeServer.Cvars.value(cvars, "sv_gravity")
#=> 600.0

The table is an ETS table belonging to the process that called new/0; it lives as long as that process and delete/1 frees it sooner. Reads never wait on another process. Names are matched without regard to ASCII case, and a variable registered with an :alias answers to both names.

A variable holds its value as text (string), with value the text read as FTE's Q_atof reads it (a 32-bit float) and ival as Q_atoi reads it. Each has a default (the value cvarreset gives back) and, for one the engine registers, the engine's own default.

Flags are FTE's (flags/0): :archive (written by cfg_save, set by seta), :userinfo and :serverinfo (the value is the player's or the server's info key of the same name), :noset (read only), :maplatch (a change while a server runs waits for the next map), :rendererlatch and :videolatch (a change while the renderer is up waits for vid_reload or vid_restart), :notfromserver (no program or server may set it), :nounsafeexpand (no program may read it), :usercreated (made by a config or a program rather than the engine) and the rest of FTE's.

Every change is stamped and counts up the table's generation (generation/1), so a program's autocvar_ globals and a server's info keys follow it (QuakeServer.Autocvars).

The table also holds what FTE keeps beside its cvars: whether a server or a renderer is running (put_running/3), whether an archived variable changed since the last save (unsaved?/1), the directory configs are written to (home/1), the console aliases (command_alias/2) and the key bindings with their bind maps (binding/3, bindmaps/1).

Summary

Functions

Give name the flags flags besides its own; nothing when there is no such variable.

Give every variable with any of the flags flags (one flag or a list) its latched value, as FTE's Cvar_ApplyLatches, and with clear: true take those flags off them all. Returns how many had a latched value.

The variables as FTE's cfg_save writes them (Cvar_WriteVariables): the archived ones, or with all? every one but cl_warncmd; never read only or :nosave ones. Each group is headed by a // group line; an engine variable is written as name "value", one a config or program made as seta or set, with its description after // at the next multiple of eight columns (at least 24), each of its lines so.

Text read as a number, as FTE's Q_atof: a 32-bit float.

Text read as a whole number, as FTE's Q_atoi.

The key binding of key number keynum in modifier state modifier (0 to 15, as QuakeServer.Keys numbers them) as {command, level}, or nil when it is unbound.

Every key binding as {keynum, modifier, command, level}, by key number then modifier.

The two modifier states key presses read their bindings from (FTE's key_bindmaps), {0, 0} at first.

The bitmask of flag names names.

Text read as a number, as C's atof: leading spaces, a sign, digits, a point and an exponent; a 32-bit float.

The console alias name's commands, or nil when there is none.

Every console alias as {name, commands}, sorted by name.

Free the table; it may not be used after.

Whether there is a variable name.

The variable name, or nil when there is none.

Whether cvar has flag name.

FTE's flag bits by name.

A number as FTE's Cvar_SetValue writes it: six decimals, trailing zeros and point dropped.

How many changes the table has seen; it counts up with every change.

The variable name, made when there is none, as FTE's Cvar_Get2: one that is there takes on :userinfo and :serverinfo from flags; one made is created by a config or a program (:usercreated) with default as its value and default and the other flags. A name with a quote, ^, $, ; or whitespace in it, or an empty one, makes nothing: nil. Options: :description, :group (default "Custom variables").

The directory cfg_save writes configs to and exec reads them from first, or nil.

The variables flagged :serverinfo or :userinfo, as {name, stamp}.

Every variable, sorted by name.

Every variable's default becomes its value, unless read only or a cheat (FTE's cvar_lockdefaults).

The server takes the variable over, as FTE's Cvar_LockFromServer: it is set to value past its latches and flagged :serveroverride, its own value kept as the latched one to come back to (apply_latches/3 with :serveroverride).

A new, empty table belonging to the calling process.

Every engine variable's default goes back to the engine's (FTE's cvar_purgedefaults); values stay.

Bind key number keynum in modifier state modifier to command at restriction level, or unbind it with nil; either way the configuration counts as changed (unsaved?/1).

Set the two modifier states key presses read their bindings from.

Make console alias name run commands, as FTE's alias command.

Make value variable name's engine default, as FTE's Cvar_SetEngineDefault: its default follows when it was the engine's; its value is left as it is. Nothing when there is no such variable.

Use directory as the place configs are written to and read from first.

Mark whether a server (:server) or the renderer (:renderer) is running, for the latching flags.

Register an engine variable, as FTE's Cvar_Register: one not there is made with default as its value, its default and its engine default; one a config or a program made first becomes the engine's, keeping its value (its latched one, if any) and its :archive flag; one the engine registered already is left as it is.

Take the flags flags off name; nothing when there is no such variable.

Set back to their defaults the variables whose names match pattern (* and ? wildcards; * or nil is every one), as FTE's cvarreset. Options: :group (only variables of a group matching it), alt: true (second names match too), :exclude (flag names; variables with any are left). :noreset variables are left, as are read only ones when every variable is reset. Returns the lines printed.

The defaults of engine variables go back to the engine's, as FTE's cvar_resettodefaults_*: :all, :saved (archived only) or :unsaved; read only and :noreset variables are left.

Whether a server (:server) or the renderer (:renderer) is running.

Mark the archived variables saved.

The server's info keys from its :serverinfo variables: every one with a value.

Set name to value (nil for its default), as FTE's Cvar_Set: a read-only variable is refused; a variable latched by its flags keeps value for later (a :maplatch one while a server runs, a :rendererlatch or :videolatch one while the renderer is up); otherwise the value changes, any latched value is dropped, and an engine variable's own check runs (r_meshpitch and r_meshroll become 1 or -1, fov at least 10, viewsize 30 to 120).

The change stamp of name, or nil when there is no such variable.

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

Whether an archived variable changed since the last save (FTE's cvars_haveunsaved).

The player's info keys from the :userinfo variables: every one with a value.

The value of name as a number, 0.0 when there is no such variable.

Types

flag()

@type flag() ::
  :archive
  | :userinfo
  | :serverinfo
  | :noset
  | :maplatch
  | :notfromserver
  | :usercreated
  | :cheat
  | :semicheat
  | :rendererlatch
  | :serveroverride
  | :renderercallback
  | :nounsafeexpand
  | :rulesetlatch
  | :shadersystem
  | :tellgamecode
  | :configdefault
  | :nosave
  | :noreset
  | :teamplaytaint
  | :watched
  | :videolatch
  | :warnonchange
  | :rendereroverride

t()

@type t() :: %QuakeServer.Cvars{
  generation: :atomics.atomics_ref(),
  release: boolean(),
  table: :ets.tid()
}

Functions

add_flags(cvars, name, flags)

@spec add_flags(t(), String.t(), [flag()]) :: :ok

Give name the flags flags besides its own; nothing when there is no such variable.

apply_latches(cvars, flags, opts \\ [])

@spec apply_latches(t(), flag() | [flag()], keyword()) :: non_neg_integer()

Give every variable with any of the flags flags (one flag or a list) its latched value, as FTE's Cvar_ApplyLatches, and with clear: true take those flags off them all. Returns how many had a latched value.

archive_text(cvars, all? \\ false)

@spec archive_text(t(), boolean()) :: String.t()

The variables as FTE's cfg_save writes them (Cvar_WriteVariables): the archived ones, or with all? every one but cl_warncmd; never read only or :nosave ones. Each group is headed by a // group line; an engine variable is written as name "value", one a config or program made as seta or set, with its description after // at the next multiple of eight columns (at least 24), each of its lines so.

atof(text)

@spec atof(String.t()) :: float()

Text read as a number, as FTE's Q_atof: a 32-bit float.

atoi(text)

@spec atoi(String.t()) :: integer()

Text read as a whole number, as FTE's Q_atoi.

binding(cvars, keynum, modifier)

@spec binding(t(), integer(), non_neg_integer()) :: {String.t(), integer()} | nil

The key binding of key number keynum in modifier state modifier (0 to 15, as QuakeServer.Keys numbers them) as {command, level}, or nil when it is unbound.

bindings(cvars)

@spec bindings(t()) :: [{integer(), non_neg_integer(), String.t(), integer()}]

Every key binding as {keynum, modifier, command, level}, by key number then modifier.

bindmaps(cvars)

@spec bindmaps(t()) :: {non_neg_integer(), non_neg_integer()}

The two modifier states key presses read their bindings from (FTE's key_bindmaps), {0, 0} at first.

bits(names)

@spec bits([flag()]) :: non_neg_integer()

The bitmask of flag names names.

c_atof(text)

@spec c_atof(String.t()) :: float()

Text read as a number, as C's atof: leading spaces, a sign, digits, a point and an exponent; a 32-bit float.

command_alias(cvars, name)

@spec command_alias(t(), String.t()) :: String.t() | nil

The console alias name's commands, or nil when there is none.

command_aliases(cvars)

@spec command_aliases(t()) :: [{String.t(), String.t()}]

Every console alias as {name, commands}, sorted by name.

delete(cvars)

@spec delete(t()) :: :ok

Free the table; it may not be used after.

exists?(cvars, name)

@spec exists?(t(), String.t()) :: boolean()

Whether there is a variable name.

fetch(cvars, name)

@spec fetch(t(), String.t()) :: QuakeServer.Cvars.Cvar.t() | nil

The variable name, or nil when there is none.

flag?(cvar, name)

@spec flag?(QuakeServer.Cvars.Cvar.t(), flag()) :: boolean()

Whether cvar has flag name.

flags()

@spec flags() :: %{required(flag()) => pos_integer()}

FTE's flag bits by name.

format_number(value)

@spec format_number(number()) :: String.t()

A number as FTE's Cvar_SetValue writes it: six decimals, trailing zeros and point dropped.

generation(cvars)

@spec generation(t()) :: non_neg_integer()

How many changes the table has seen; it counts up with every change.

get(cvars, name, default, flags \\ [], opts \\ [])

@spec get(t(), String.t(), String.t(), [flag()], keyword()) ::
  QuakeServer.Cvars.Cvar.t() | nil

The variable name, made when there is none, as FTE's Cvar_Get2: one that is there takes on :userinfo and :serverinfo from flags; one made is created by a config or a program (:usercreated) with default as its value and default and the other flags. A name with a quote, ^, $, ; or whitespace in it, or an empty one, makes nothing: nil. Options: :description, :group (default "Custom variables").

home(cvars)

@spec home(t()) :: Path.t() | nil

The directory cfg_save writes configs to and exec reads them from first, or nil.

info_stamps(cvars)

@spec info_stamps(t()) :: [{String.t(), integer()}]

The variables flagged :serverinfo or :userinfo, as {name, stamp}.

list(cvars)

@spec list(t()) :: [QuakeServer.Cvars.Cvar.t()]

Every variable, sorted by name.

lock_defaults(cvars)

@spec lock_defaults(t()) :: :ok

Every variable's default becomes its value, unless read only or a cheat (FTE's cvar_lockdefaults).

lock_from_server(cvars, name, value)

@spec lock_from_server(t(), String.t(), String.t()) :: :ok

The server takes the variable over, as FTE's Cvar_LockFromServer: it is set to value past its latches and flagged :serveroverride, its own value kept as the latched one to come back to (apply_latches/3 with :serveroverride).

new()

@spec new() :: t()

A new, empty table belonging to the calling process.

purge_defaults(cvars)

@spec purge_defaults(t()) :: :ok

Every engine variable's default goes back to the engine's (FTE's cvar_purgedefaults); values stay.

put_binding(cvars, keynum, modifier, command, level)

@spec put_binding(t(), integer(), non_neg_integer(), String.t() | nil, integer()) ::
  :ok

Bind key number keynum in modifier state modifier to command at restriction level, or unbind it with nil; either way the configuration counts as changed (unsaved?/1).

put_bindmaps(cvars, arg)

@spec put_bindmaps(t(), {non_neg_integer(), non_neg_integer()}) :: :ok

Set the two modifier states key presses read their bindings from.

put_command_alias(cvars, name, commands)

@spec put_command_alias(t(), String.t(), String.t()) :: :ok

Make console alias name run commands, as FTE's alias command.

put_engine_default(cvars, name, value)

@spec put_engine_default(t(), String.t(), String.t()) :: :ok

Make value variable name's engine default, as FTE's Cvar_SetEngineDefault: its default follows when it was the engine's; its value is left as it is. Nothing when there is no such variable.

put_home(cvars, directory)

@spec put_home(t(), Path.t()) :: :ok

Use directory as the place configs are written to and read from first.

put_running(cvars, what, running?)

@spec put_running(t(), :server | :renderer, boolean()) :: :ok

Mark whether a server (:server) or the renderer (:renderer) is running, for the latching flags.

register(cvars, name, default, opts \\ [])

@spec register(t(), String.t(), String.t(), keyword()) :: QuakeServer.Cvars.Cvar.t()

Register an engine variable, as FTE's Cvar_Register: one not there is made with default as its value, its default and its engine default; one a config or a program made first becomes the engine's, keeping its value (its latched one, if any) and its :archive flag; one the engine registered already is left as it is.

Options: :flags (a list of flag/0), :alias, :description, :group.

remove_flags(cvars, name, flags)

@spec remove_flags(t(), String.t(), [flag()]) :: :ok

Take the flags flags off name; nothing when there is no such variable.

reset(cvars, pattern, opts \\ [])

@spec reset(t(), String.t() | nil, keyword()) :: [String.t()]

Set back to their defaults the variables whose names match pattern (* and ? wildcards; * or nil is every one), as FTE's cvarreset. Options: :group (only variables of a group matching it), alt: true (second names match too), :exclude (flag names; variables with any are left). :noreset variables are left, as are read only ones when every variable is reset. Returns the lines printed.

reset_defaults(cvars, which)

@spec reset_defaults(t(), :all | :saved | :unsaved) :: :ok

The defaults of engine variables go back to the engine's, as FTE's cvar_resettodefaults_*: :all, :saved (archived only) or :unsaved; read only and :noreset variables are left.

running?(cvars, what)

@spec running?(t(), :server | :renderer) :: boolean()

Whether a server (:server) or the renderer (:renderer) is running.

saved(cvars)

@spec saved(t()) :: :ok

Mark the archived variables saved.

serverinfo(cvars)

@spec serverinfo(t()) :: %{required(String.t()) => String.t()}

The server's info keys from its :serverinfo variables: every one with a value.

set(cvars, name, value, opts \\ [])

@spec set(t(), String.t(), String.t() | nil, keyword()) ::
  {:ok, [String.t()]} | {:error, :missing}

Set name to value (nil for its default), as FTE's Cvar_Set: a read-only variable is refused; a variable latched by its flags keeps value for later (a :maplatch one while a server runs, a :rendererlatch or :videolatch one while the renderer is up); otherwise the value changes, any latched value is dropped, and an engine variable's own check runs (r_meshpitch and r_meshroll become 1 or -1, fov at least 10, viewsize 30 to 120).

{:ok, lines} gives the lines FTE prints about it (latching while cl_warncmd is set, read only); {:error, :missing} when there is no such variable. Option force: true sets past the latches and :noset.

stamp(cvars, name)

@spec stamp(t(), String.t()) :: integer() | nil

The change stamp of name, or nil when there is no such variable.

string(cvars, name)

@spec string(t(), String.t()) :: String.t()

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

unsaved?(cvars)

@spec unsaved?(t()) :: boolean()

Whether an archived variable changed since the last save (FTE's cvars_haveunsaved).

userinfo(cvars)

@spec userinfo(t()) :: %{required(String.t()) => String.t()}

The player's info keys from the :userinfo variables: every one with a value.

value(cvars, name)

@spec value(t(), String.t()) :: float()

The value of name as a number, 0.0 when there is no such variable.