Unreleased
Added
Runner.start_link(held: true)keeps the level unloaded untilRunner.load/1; a client that subscribes before then is sent the serverdata when the level loads.QuakeServer.Source.replacements/0(optional): program functions the game runs itself, by name. The server's program has them replaced (QuakeC.Progs.replace/2) andQuakeServer.Builtins.call/3runs the game's function when the program calls one.QuakeServer.World.bounds/2: the box linking an entity would give it now.FTE's
setposandnoclipconsole commands for the player (QuakeServer.Cheats).Runner.take/1gives the level's map.QuakeServer.Animation: the animation of the entities a program sends itself (frameas the sequence,frame1time, the server's time asanimtime, and the framerateframe1timemoves at), sampled each server frame and sent to the player in each packet'sanimationwhen the player lacks it, as GoldSrc's engine carriessequence,frame,animtimeandframerate.QuakeServer.Network.held/2gives the entities a player holds.FTE's key bindings:
QuakeServer.Keys(FTE's key numbers and names, modifiers, and the QuakeC key codes), the console'sbind,in_bind,bindlevel,unbindandunbindall(QuakeServer.Console.Bindings), the bindings kept in the console variable table (QuakeServer.Cvars.binding/3,put_binding/5,bindings/1,bindmaps/1,put_bindmaps/2) and written bycfg_savewhilecfg_save_bindsis set.The console's
setinfoblob, and console commands a menu program takes in itsm_consolecommand.QuakeServer.Cvars.put_engine_default/3, as FTE'sCvar_SetEngineDefault.The engine variables
cfg_save_binds,con_maxlines,com_protocolname,fs_basepath,fs_gamepathandfs_homepath.FTE's common builtins the server lacked, under FTE's server numbers: recoding (
QuakeServer.Extensions.Encoding:strconv224,strlennocol476,strdecolorize477,crc16494,uri_escape510,uri_unescape511,argescape295,digest_hex639,digest_ptr,base64encode,base64decode,ftou,utof), memory as bytes (Memory:createbuffer,memrealloc,memcmp,memstrsize), JSON (Json:json_parseand thejson_get_readers,json_free,js_run_script), files (Files:fwrite,search_getfilemtime,search_fopen,fcopy650,frename651,fexists653,rmtree654), string buffers (Buffers:buf_copy463,buf_sort464,buf_loadfile535,buf_writefile536,bufstr_find537), entity text (EntityText:generateentitydata,writetofile606,parseentitydata613,loadfromdata529,loadfromfile530,find_list,entityprotection),abort211 andcheckcommand294 (Control), and the network (Web:uri_get513 anduri_post,netaddress_resolve625,sendpacket242). Replies touri_getreachURI_Get_Callbackat the start of a server frame (QuakeServer.Extensions.Web.run/1).QuakeServer.Markup: text with FTE's markup reduced to what it shows.QuakeServer.Extensions.Store:entry/3,put_entry/4,new_handle/1,write/3,remove/2,written?/2,modified/2,buffer_size/1.The
:inets,:ssland:public_keyapplications start with the server.QuakeServer.Runneracknowledges the client's commands: a command'ssequenceis set as the program'sinput_sequenceand sent back with every packet after it runs (FTE'sPEXT2_PREDINFOlast_sequence, 0 when the program does not run its players' commands); a command's integermsecis used as given.The
cl_netfpsengine variable.The server modules that were in ElixirQuake, loading through
QuakeServer.Source.FTE program support:
CheckSpawnspawning,init/initents,SV_RunClientCommand, a console, entity networking (QuakeServer.Network), multicast packets, and about 170 extension builtins (QuakeServer.Extensions).Server.open/2, a bare world for client programs; options:builtins,:budget,:hull,:inhibit,:coords,:data_dir,:trace.QuakeServer.Pmove, QuakeWorld player movement forrunstandardplayerphysics;openportal,getlight, colouredlightstyle,getlightstyle,getlightstylergb,getsurfacepointattribute, server polygons (R_BeginPolygonand the rest) and thephysics_builtins (no rigid-body engine).Pushers turn by
avelocity, swinging and turning what they carry (a client getsfixangle2); brush models with angles collide turned.SOLID_BSPTRIGGER(22): triggers shaped by their brush model;Q.trigger?/1,Q.brush?/1.customphysics: an entity holding a function there has it run each frame in place of its move type.changelevel(map, startspot)(QuakeServer.Extensions.Levels, and the console'schangelevel map startspot);Server.start/2options:startspotand:written;Server.resume/3for a level kept from before.Models.share/2: a client world uses its server's model numbers, its own models numbered below zero.Pushers move and turn as FTE's (
Physics.Push,Physics.PushTurn): riders are moved by setting and testing their spot, the clock advances only when the push went through, and a pusher its think moved is pushed that far.QuakeServer.Runner: a level in its own process on its own clock, a physics frame once the cvarsv_mintic(0.013) has passed, as long as has passed up tosv_maxtic(0.1), following level changes; thinks repeat within a frame undersv_gameplayfix_multiplethinks(on). A client takes the world when it is ready (Runner.snapshot/1), as FTE sends a client its snapshot.Server.release/1; the runner releases the levels it drops.search_beginkeeps the game files a pattern matches for the server's life.FTE's console variables (
QuakeServer.Cvars): one ETS table any number of processes read and write without waiting on each other, so a server, its client program and its menu share one set as FTE's single process does (Server.start/2andopen/2option:cvar_table). FTE's flags (archive, user and server info, read only, map, renderer and video latches, not from server, private, ...), defaults and engine defaults, second names, descriptions,Q_atof/Q_atoivalues, the engine's checks onr_meshpitch,r_meshroll,fovandviewsize,cvar_lockdefaults,cvar_purgedefaults,cvar_resettodefaults_*,cvarreset, latching andCvar_LockFromServer.QuakeServer.Cvars.Engine: the engine variables FTE registers that the server, the client and FreeHL's programs and configs name, with FTE's defaults, flags, descriptions and second names (maxplayersforsv_playerslots,loadas8bitfors_loadas8bit, ...).QuakeServer.Autocvars: a program'sautocvar_globals follow their variables, made with the global's value when missing, as FTE'sPR_AutoCvar, for server, client and menu programs alike;:serverinfoand:userinfovariables are a server's info keys and its players'.Server.exec_opts/1brings a program up to date before each call.The console's variable commands as FTE's:
setwith the rest of the line as value and//description,seta,setfl,set_tp,toggle name [a [b]],inc, a variable's name printing its value, default and latch,cvarreset,vid_reload,vid_restart;execwith FTE's rules (config.cfgsuperseded by an earlierdefault.cfg,fte.cfgafter it,cvar_lockdefaultsafterdefault.cfg,name.cfgforname);cfg_save,cfg_save_ifmodified; aliases kept with the variables; unknown commands reported only whilecl_warncmdis set;Console.run/3optionfrom: :serverfor commands a server sends.Cvar builtins as FTE's:
cvarmakes a missing variable whilepr_autocreatecvarsis set and answerspr_checkextensionandhalflifebsp;cvar_stringgives a latched value;cvar_setrefuses:notfromservervariables;registercvartakes DarkPlaces flags;cvar_typegives FTE's bits;cvar_defstring,cvar_description,buf_cvarlist(517) andcvars_haveunsaved.QuakeServer.Sourcecallbackdepth/1, where a file is in the search order.
Changed
checkbuiltinasks the program's own builtins module whether it knows a builtin.- A server that ends (
QuakeServer.Runner) no longer counts as running in the console variable table. Server.cvar/2reads a value as FTE'sQ_atof(a 32-bit float);Server.put_cvar/3sets as FTE'sCvar_Setand writes a number asCvar_SetValuedoes. A server's own table registers the engine variables; the defaults the server used to keep in itself are the engine list's.Server.release/1frees a table the server made itself.execno longer looks undercfg/for a file it cannot find;setsandsetuare gone, as FTE has neither.
Fixed
ftoswrites a fraction as FTE'sQ_ftoa(every significant digit of the 32-bit float, no padding) andvtosas'%f %f %f'; they wrote Quake's%5.1f, so a value such as 0.75 became0.8, and the numbers FreeHL writes into cvars, info keys and save files lost their fractions.pr_brokenfloatconvertbrings back%5.1fforftos.randomis FTE's: steps of 1/32768 offset by half a step (never 0 or 1), scaled by one argument or spanning two; it ignored its arguments and could return 0.findradiusis FTE's: an optional field to chain through, entities withsolid0 found when their flags holdFL_FINDABLE_NONSOLID(16384), and the cvarssv_gameplayfix_blowupfallenzombiesandsv_gameplayfix_findradiusdistancetobox.aimis FTE's: off (straight alongv_forward) whilesv_aimis 1 or more, the shot from the shooter'sview_ofsheight rather than Quake's fixed 20 units, and teammates skipped underteamplay.objerrorprintsProgram error:with its arguments joined, removesselfand stops every running function, as FTE's does; it went on running the caller.breakpointprintsbreak statementanddprintprints whiledeveloperis set, as FTE's do; both did nothing.setmodelsizes the entity by FTE's rule: always for a world submodel, for any model when the program is not a QuakeWorld one orsv_gameplayfix_setmodelsize_qwis set, and otherwise only for a found model that is not a Quake alias model.MOVETYPE_FOLLOWturns the follower's offset with itspunchangleand the leader's angles scaled byr_meshpitchandr_meshroll, as FTE'sWPhys_Physics_Followdoes.The move types FTE runs that the server left still: 13 (
H2PUSHPULL) moves as a pusher, 14 (H2SWIM) and 33 (FLY_WORLDONLY) as tossed things without gravity (33 as a walking player for the player), and 32 (PHYSICS) thinks and is relinked.Monster steps, walking and getting unstuck use FTE's step height (
QuakeServer.Physics.step_size/1):pm_stepheight, 18 while it is empty.Coordinates in eighths and angles in 256ths of a turn are rounded half away from zero, as FTE's
MSG_ToCoordandMSG_WriteAngle8write them; they were cut toward zero.vectoanglesis FTE's (QuakeServer.Angles.vectoangles/3): angles keep their fractions of a degree,upgives the roll, and pitch and roll followr_meshpitchandr_meshroll; it gave whole degrees, as Quake's does. With FTE'ssv_minticof 0 a frame lasts a few milliseconds, and FreeHL's monsters turn less than a degree a frame, so a turn was lost to the whole degree each frame: Barney in c0a0e stopped halfway down the walkway once his heading was 5 degrees off his route, gave up the route there and played his door sequences on the spot. He now walks to the tram button and to the retina scanner and opens the doors there.Entity references in a file carried to the next level follow Half-Life's level transition rule (GoldSrc, the HLSDK's
CSaveRestoreBuffer) instead of FreeHL's under FTE (QuakeServer.EntityTable): each written file keeps an entity table of its{}blocks (the entity that wrote each), carried with the written files (server option:entity_tables), and while the program reads a carried fileedict_numgives the entity a block was restored into for an entity that was carried, keeps the world and player slots, and gives the world for any other number. FreeHL's c0a0a no longer has the tram's timer from c0a0 take over the entity of the narration's trigger: the tram gets a fresh timer, keeps moving, andtride/c0a0_tr_dest.wavplays.externvalue,isfunction,callfunctionand function keys find0:nameas FTE'sED_FindFunctiondoes, so a level brought back keeps its entities' functions.Numbers in text are read as C reads them (
QuakeServer.TextNumbers):stofand the otheratofreadings take.3,-.5,+1, hex and C white space, giving a 32-bit float; entity keys are read as FTE'sED_ParseEpairreads them (strtodfor floats and each vector word,strtolbase 0 for integer and entity fields)..3read as 0, so FreeHL'sc0a0fired thestart_titlestrigger_auto (delay .3) at once and the tram left 0.3 seconds before FTE's.stovstops at the first word that is not a number and at a closing', as FTE'sPF_stov.getentityfieldstringis FTE's: values asPR_UglyValueStringwrites them (functions as0:name) and FTE's left-out fields; function keys read0:nameas FTE does.New entities get
drawflags96, as FTE spawns them.checkpvs(240) decides as FTE'sPF_checkpvs: from the leaves recorded when the entity was last linked, not its box as it stands; an entity never linked is not seen, one in more than 32 leaves always is (QuakeServer.Visibility.in_pvs?/3). FreeHL's level change fromc0a0toc0a0anow carries the fourscripted_sequences and the train, as under FTE, instead of sixteenpath_tracks.QuakeServer.Visibility.pvs/2takes a point on a node's plane to the back side, as FTE'sClusterForPointdoes.Server.start/2runs FTE'sSV_SpawnServersteps in its order: the info keysmapname,*cheats,*bspversionand*startspotbefore the program loads (an empty one removed, not kept empty);init(-1)at time 0 on fresh memory, before the model list and the world entity; the world's box (mins,maxs,absmin,absmax); the player slots' entities allocated from the start;time1, andcoopordeathmatchfrom their cvars, beforeinitents; the world's angles cleared and the level's name taken from itsmessage(ext.levelname) after spawning; themapkey set after the settle frames. Option:serverinfocarries the server's info keys from level to level, as FTE's server info lasts.Server.connect/3is FTE'sSV_SetUpClientEdictandSV_Begin_Core: the player gets its name from its info keys (Playerby default),clientcolors,gravity,maxspeed,movetypenoclip and no frags;ClientConnectis given 1 for a client running a client program (optioncsqc: true);oldoriginfollowsorigin; a program running its players' commands runs one empty command;parm_stringis set and carried with the spawn parameters. A NetQuake program's player entity is not cleared on connecting but on leaving.Server.save_spawn_parms/1is FTE'sSV_SaveSpawnparms: the player's parameters go back into the globals beforeSetChangeParms, andparm_stringandserverflagsare carried (serverflagswas not carried by the runner).change_parms/1uses it.Server.disconnect/1: FTE'sSV_DespawnClient, run (ClientDisconnect) on a level kept for its landmark, as FTE'sSV_SaveLevelCachedoes.A level left through a landmark is kept as FTE's level cache keeps it: a program with
SV_PerformSaveandSV_PerformLoad(FreeHL) has the level saved in FTE's format (Server.save_level/1, afterClientDisconnect) and, on a return, started afresh with the save's console variables and restored by the program (Server.load_level/2, the world relinked and the saved time taken up); the level was kept in memory as it stood and the program's own save and restore never ran.Store.open_buffer/4,Store.open_output/3andStore.output/3hand the program FTE's engine files. Another program's level is still kept as it stands;Server.resume/2brings it back asSV_LoadLevelCachedoes: the star keys again, the server's current info keys under the level's,serverflagsandtime.The runner follows FTE's listen server: a level starts without the player and stays paused (the clock held at 1.5) until its client begins (
Runner.begin/3, after the client sent{:serverdata, …}has loaded); the view set on beginning is the player'sanglesunderfixangle, elsev_angle, with roll. A level change sends the reliable messages still queued as a last packet before{:changing, map}, and carries the player's info keys. Its levels share one console variable table (the:cvar_tableoption, or one of its own) instead of replaying the console commands given before into each new level, which repeated achangeleveltyped at the console forever. The client's server info comes in the serverdata (FTE'sfullserverinfo, withoutmapname) instead of a stuffed command in the first packet.QuakeServer.Signon: static entities (makestatic), static sounds (ambientsound) and the player's info keys are sent to the client before it begins, as FTE'ssvc_spawnstatic,svc_spawnstaticsoundandsvc_updateuserinfo; they were kept on the server and never sent.Players are sent the server's sound list and particle effect list, and what is added to them later (
QuakeServer.Precaches, fromQuakeServer.Network.frame/2), as FTE's signon and delayed precaches send them.pointparticlesandtrailparticlesgo to the players that may hear them as FTE'ssvcfte_pointparticles,svcfte_pointparticles1andsvcfte_trailparticles, besides the server's events.getsoundindexadds a sound not on the list unless asked only to look it up.QuakeServer.Builtins.Write.coord/2andcoords/2: coordinates asWriteCoordwrites them.serverkeyjoins its arguments, gives null for an empty value, and answers FTE's engine keys (Settings.server_key/2).A level change sends the client
{:changing, map}first.Sounds start as FTE starts them (
QuakeServer.Sounds): a sound message in the players' packets, reliable for brush entities, to everyone when reliable or unattenuated, to the players that may hear it otherwise;soundtakes FTE's pitch, flags and offset arguments and a QuakeWorld program's reliable channel bit;pointsoundtoo.Changes to the server's info keys reach the players (
svc_serverinfo), and each level starts by sending them all (fullserverinfo).Light style colours reach the client with the styles.
A server-side pose takes all five bone controllers and both sub-blends as floats.
The console's
sky namesets the sky drawn.QuakeServer.Runnerpushes each packet to its subscribed client (subscribe/2) and hands events, the player's eye and view angles over in a table (handoff/1,take/1), so neither the client nor the game waits on a busy server.processmodeleventsis FTE's: a looping sequence's events come round every cycle, events fire from the base time up to but not including the target, and nothing fires when the two are equal.Entity delivery is FTE's:
SendFlagsare kept every server frame and cleared after, updates go out with each packet a player is sent, entities never sent or sent back into sight get every bit,PVSF_NOREMOVEkeeps an entity on the client, and the player may see what FTE'sSV_Snapshot_BuildQ1lets through: the fat PVS (leaves within 8 units of the eye), leaves recorded when an entity is linked,PVSF_USEPHSnever culled on Half-Life maps or without a PHS,EF_NODEPTHTEST,tag_entityroots,viewmodelforclient,customizeentityforclient,nodrawtoclient,drawonlytoclientand dimensions.multicastreaches only the players FTE sends to (PVS, PHS within 1024 units or by the PHS,msg_entity,dimension_send), reliably or in the datagram, and a packet carries the reliable messages before the entity updates and the datagram after.bprintandsprintread a QuakeWorld program's print level before the text, join every text argument, and reach the player assvc_print;centerprintkeeps the last one for the next packet.Entities spawn with
dimension_see,dimension_seen,dimension_solidanddimension_hitatdimension_default(255), andVersionanduniquespawnidset;dimension_sendstarts atdimension_default.Freeing an entity clears
pvsflagsandSendEntity(andclassnamefor a QuakeWorld program) and is refused for the world, a player or an entity already free.Every brush model is traced with the hull FTE chooses (
World.choose_hull/2, the default:hull).route_calculateis FTE's: the waypoints are read once a level, the start and end waypoints are those whose radius holds the point or that it can see through the world, the node list ends with the entity's place and starts with the destination flaggedLF_DESTINATION, a route with no path still gives the destination and the start, and the callback runs at the start of the next frame.A trace that starts inside one entity is still stopped by the next thing in its way, as FTE combines its traces; it was taken whole from the entity it started in.
A pusher tests what it carries as if it were not solid by setting
solidand putting it back, as FTE does, and an entity it nudges moves an eighth of a unit once.A tossed, bouncing or flying entity on the ground keeps what its think did.
tokenizefinds the end of a word without testing each character against a list.An entity's
solidis read when it is traced or touched, not when it was last linked.All 64 spawn parameters are carried between levels, each in its own place.
fopenof a name withoutdata/readsdata/namefirst, thenname.externvalueandexternsettake program numbers 0 to -3 and names spread over several arguments, return vectors whole, and&namegives a global's address.World.stuck?countsallsolidand tests non-solid and trigger entities against brush models only.