123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- /*
- 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");
- }
|