aboutsummaryrefslogtreecommitdiffstats
path: root/QW/server/sv_init.c
diff options
context:
space:
mode:
authorTravis Bradshaw <travis.bradshaw@idsoftware.com>2012-01-31 14:32:09 -0600
committerTravis Bradshaw <travis.bradshaw@idsoftware.com>2012-01-31 14:32:09 -0600
commit0023db327bc1db00068284b70e1db45857aeee35 (patch)
tree01dd8366d20bd674741cfe8ceb069d82a2e33973 /QW/server/sv_init.c
downloadquake-pum-0023db327bc1db00068284b70e1db45857aeee35.tar.gz
The Quake sources as originally release under the GPL license on December 21, 1999
Diffstat (limited to 'QW/server/sv_init.c')
-rw-r--r--QW/server/sv_init.c411
1 files changed, 411 insertions, 0 deletions
diff --git a/QW/server/sv_init.c b/QW/server/sv_init.c
new file mode 100644
index 0000000..cd58d23
--- /dev/null
+++ b/QW/server/sv_init.c
@@ -0,0 +1,411 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "qwsvdef.h"
+
+server_static_t svs; // persistant server info
+server_t sv; // local server
+
+char localmodels[MAX_MODELS][5]; // inline model names for precache
+
+char localinfo[MAX_LOCALINFO_STRING+1]; // local game info
+
+/*
+================
+SV_ModelIndex
+
+================
+*/
+int SV_ModelIndex (char *name)
+{
+ int i;
+
+ if (!name || !name[0])
+ return 0;
+
+ for (i=0 ; i<MAX_MODELS && sv.model_precache[i] ; i++)
+ if (!strcmp(sv.model_precache[i], name))
+ return i;
+ if (i==MAX_MODELS || !sv.model_precache[i])
+ SV_Error ("SV_ModelIndex: model %s not precached", name);
+ return i;
+}
+
+/*
+================
+SV_FlushSignon
+
+Moves to the next signon buffer if needed
+================
+*/
+void SV_FlushSignon (void)
+{
+ if (sv.signon.cursize < sv.signon.maxsize - 512)
+ return;
+
+ if (sv.num_signon_buffers == MAX_SIGNON_BUFFERS-1)
+ SV_Error ("sv.num_signon_buffers == MAX_SIGNON_BUFFERS-1");
+
+ sv.signon_buffer_size[sv.num_signon_buffers-1] = sv.signon.cursize;
+ sv.signon.data = sv.signon_buffers[sv.num_signon_buffers];
+ sv.num_signon_buffers++;
+ sv.signon.cursize = 0;
+}
+
+/*
+================
+SV_CreateBaseline
+
+Entity baselines are used to compress the update messages
+to the clients -- only the fields that differ from the
+baseline will be transmitted
+================
+*/
+void SV_CreateBaseline (void)
+{
+ int i;
+ edict_t *svent;
+ int entnum;
+
+ for (entnum = 0; entnum < sv.num_edicts ; entnum++)
+ {
+ svent = EDICT_NUM(entnum);
+ if (svent->free)
+ continue;
+ // create baselines for all player slots,
+ // and any other edict that has a visible model
+ if (entnum > MAX_CLIENTS && !svent->v.modelindex)
+ continue;
+
+ //
+ // create entity baseline
+ //
+ VectorCopy (svent->v.origin, svent->baseline.origin);
+ VectorCopy (svent->v.angles, svent->baseline.angles);
+ svent->baseline.frame = svent->v.frame;
+ svent->baseline.skinnum = svent->v.skin;
+ if (entnum > 0 && entnum <= MAX_CLIENTS)
+ {
+ svent->baseline.colormap = entnum;
+ svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl");
+ }
+ else
+ {
+ svent->baseline.colormap = 0;
+ svent->baseline.modelindex =
+ SV_ModelIndex(PR_GetString(svent->v.model));
+ }
+
+ //
+ // flush the signon message out to a seperate buffer if
+ // nearly full
+ //
+ SV_FlushSignon ();
+
+ //
+ // add to the message
+ //
+ MSG_WriteByte (&sv.signon,svc_spawnbaseline);
+ MSG_WriteShort (&sv.signon,entnum);
+
+ MSG_WriteByte (&sv.signon, svent->baseline.modelindex);
+ MSG_WriteByte (&sv.signon, svent->baseline.frame);
+ MSG_WriteByte (&sv.signon, svent->baseline.colormap);
+ MSG_WriteByte (&sv.signon, svent->baseline.skinnum);
+ for (i=0 ; i<3 ; i++)
+ {
+ MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]);
+ MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]);
+ }
+ }
+}
+
+
+/*
+================
+SV_SaveSpawnparms
+
+Grabs the current state of the progs serverinfo flags
+and each client for saving across the
+transition to another level
+================
+*/
+void SV_SaveSpawnparms (void)
+{
+ int i, j;
+
+ if (!sv.state)
+ return; // no progs loaded yet
+
+ // serverflags is the only game related thing maintained
+ svs.serverflags = pr_global_struct->serverflags;
+
+ for (i=0, host_client = svs.clients ; i<MAX_CLIENTS ; i++, host_client++)
+ {
+ if (host_client->state != cs_spawned)
+ continue;
+
+ // needs to reconnect
+ host_client->state = cs_connected;
+
+ // call the progs to get default spawn parms for the new client
+ pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
+ PR_ExecuteProgram (pr_global_struct->SetChangeParms);
+ for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
+ host_client->spawn_parms[j] = (&pr_global_struct->parm1)[j];
+ }
+}
+
+/*
+================
+SV_CalcPHS
+
+Expands the PVS and calculates the PHS
+(Potentially Hearable Set)
+================
+*/
+void SV_CalcPHS (void)
+{
+ int rowbytes, rowwords;
+ int i, j, k, l, index, num;
+ int bitbyte;
+ unsigned *dest, *src;
+ byte *scan;
+ int count, vcount;
+
+ Con_Printf ("Building PHS...\n");
+
+ num = sv.worldmodel->numleafs;
+ rowwords = (num+31)>>5;
+ rowbytes = rowwords*4;
+
+ sv.pvs = Hunk_Alloc (rowbytes*num);
+ scan = sv.pvs;
+ vcount = 0;
+ for (i=0 ; i<num ; i++, scan+=rowbytes)
+ {
+ memcpy (scan, Mod_LeafPVS(sv.worldmodel->leafs+i, sv.worldmodel),
+ rowbytes);
+ if (i == 0)
+ continue;
+ for (j=0 ; j<num ; j++)
+ {
+ if ( scan[j>>3] & (1<<(j&7)) )
+ {
+ vcount++;
+ }
+ }
+ }
+
+
+ sv.phs = Hunk_Alloc (rowbytes*num);
+ count = 0;
+ scan = sv.pvs;
+ dest = (unsigned *)sv.phs;
+ for (i=0 ; i<num ; i++, dest += rowwords, scan += rowbytes)
+ {
+ memcpy (dest, scan, rowbytes);
+ for (j=0 ; j<rowbytes ; j++)
+ {
+ bitbyte = scan[j];
+ if (!bitbyte)
+ continue;
+ for (k=0 ; k<8 ; k++)
+ {
+ if (! (bitbyte & (1<<k)) )
+ continue;
+ // or this pvs row into the phs
+ // +1 because pvs is 1 based
+ index = ((j<<3)+k+1);
+ if (index >= num)
+ continue;
+ src = (unsigned *)sv.pvs + index*rowwords;
+ for (l=0 ; l<rowwords ; l++)
+ dest[l] |= src[l];
+ }
+ }
+
+ if (i == 0)
+ continue;
+ for (j=0 ; j<num ; j++)
+ if ( ((byte *)dest)[j>>3] & (1<<(j&7)) )
+ count++;
+ }
+
+ Con_Printf ("Average leafs visible / hearable / total: %i / %i / %i\n"
+ , vcount/num, count/num, num);
+}
+
+unsigned SV_CheckModel(char *mdl)
+{
+ byte stackbuf[1024]; // avoid dirtying the cache heap
+ byte *buf;
+ unsigned short crc;
+// int len;
+
+ buf = (byte *)COM_LoadStackFile (mdl, stackbuf, sizeof(stackbuf));
+ crc = CRC_Block(buf, com_filesize);
+// for (len = com_filesize; len; len--, buf++)
+// CRC_ProcessByte(&crc, *buf);
+
+ return crc;
+}
+
+/*
+================
+SV_SpawnServer
+
+Change the server to a new map, taking all connected
+clients along with it.
+
+This is only called from the SV_Map_f() function.
+================
+*/
+void SV_SpawnServer (char *server)
+{
+ edict_t *ent;
+ int i;
+
+ Con_DPrintf ("SpawnServer: %s\n",server);
+
+ SV_SaveSpawnparms ();
+
+ svs.spawncount++; // any partially connected client will be
+ // restarted
+
+ sv.state = ss_dead;
+
+ Mod_ClearAll ();
+ Hunk_FreeToLowMark (host_hunklevel);
+
+ // wipe the entire per-level structure
+ memset (&sv, 0, sizeof(sv));
+
+ sv.datagram.maxsize = sizeof(sv.datagram_buf);
+ sv.datagram.data = sv.datagram_buf;
+ sv.datagram.allowoverflow = true;
+
+ sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
+ sv.reliable_datagram.data = sv.reliable_datagram_buf;
+
+ sv.multicast.maxsize = sizeof(sv.multicast_buf);
+ sv.multicast.data = sv.multicast_buf;
+
+ sv.master.maxsize = sizeof(sv.master_buf);
+ sv.master.data = sv.master_buf;
+
+ sv.signon.maxsize = sizeof(sv.signon_buffers[0]);
+ sv.signon.data = sv.signon_buffers[0];
+ sv.num_signon_buffers = 1;
+
+ strcpy (sv.name, server);
+
+ // load progs to get entity field count
+ // which determines how big each edict is
+ PR_LoadProgs ();
+
+ // allocate edicts
+ sv.edicts = Hunk_AllocName (MAX_EDICTS*pr_edict_size, "edicts");
+
+ // leave slots at start for clients only
+ sv.num_edicts = MAX_CLIENTS+1;
+ for (i=0 ; i<MAX_CLIENTS ; i++)
+ {
+ ent = EDICT_NUM(i+1);
+ svs.clients[i].edict = ent;
+//ZOID - make sure we update frags right
+ svs.clients[i].old_frags = 0;
+ }
+
+ sv.time = 1.0;
+
+ strcpy (sv.name, server);
+ sprintf (sv.modelname,"maps/%s.bsp", server);
+ sv.worldmodel = Mod_ForName (sv.modelname, true);
+ SV_CalcPHS ();
+
+ //
+ // clear physics interaction links
+ //
+ SV_ClearWorld ();
+
+ sv.sound_precache[0] = pr_strings;
+
+ sv.model_precache[0] = pr_strings;
+ sv.model_precache[1] = sv.modelname;
+ sv.models[1] = sv.worldmodel;
+ for (i=1 ; i<sv.worldmodel->numsubmodels ; i++)
+ {
+ sv.model_precache[1+i] = localmodels[i];
+ sv.models[i+1] = Mod_ForName (localmodels[i], false);
+ }
+
+ //check player/eyes models for hacks
+ sv.model_player_checksum = SV_CheckModel("progs/player.mdl");
+ sv.eyes_player_checksum = SV_CheckModel("progs/eyes.mdl");
+
+ //
+ // spawn the rest of the entities on the map
+ //
+
+ // precache and static commands can be issued during
+ // map initialization
+ sv.state = ss_loading;
+
+ ent = EDICT_NUM(0);
+ ent->free = false;
+ ent->v.model = PR_SetString(sv.worldmodel->name);
+ ent->v.modelindex = 1; // world model
+ ent->v.solid = SOLID_BSP;
+ ent->v.movetype = MOVETYPE_PUSH;
+
+ pr_global_struct->mapname = PR_SetString(sv.name);
+ // serverflags are for cross level information (sigils)
+ pr_global_struct->serverflags = svs.serverflags;
+
+ // run the frame start qc function to let progs check cvars
+ SV_ProgStartFrame ();
+
+ // load and spawn all other entities
+ ED_LoadFromFile (sv.worldmodel->entities);
+
+ // look up some model indexes for specialized message compression
+ SV_FindModelNumbers ();
+
+ // all spawning is completed, any further precache statements
+ // or prog writes to the signon message are errors
+ sv.state = ss_active;
+
+ // run two frames to allow everything to settle
+ host_frametime = 0.1;
+ SV_Physics ();
+ SV_Physics ();
+
+ // save movement vars
+ SV_SetMoveVars();
+
+ // create a baseline for more efficient communications
+ SV_CreateBaseline ();
+ sv.signon_buffer_size[sv.num_signon_buffers-1] = sv.signon.cursize;
+
+ Info_SetValueForKey (svs.info, "map", sv.name, MAX_SERVERINFO_STRING);
+ Con_DPrintf ("Server spawned.\n");
+}
+