mirror of
https://git.code.sf.net/p/quake/newtree
synced 2025-06-02 18:11:12 +00:00
Initial revision
This commit is contained in:
commit
d859383680
169 changed files with 86447 additions and 0 deletions
411
source/sv_init.c
Normal file
411
source/sv_init.c
Normal file
|
@ -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");
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue