diff options
Diffstat (limited to 'QW/server/sv_init.c')
| -rw-r--r-- | QW/server/sv_init.c | 411 |
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"); +} + |
