This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/server/sv_init.c

699 lines
18 KiB
C
Raw Normal View History

2007-06-21 22:00:00 +02:00
/*
Copyright (C) 1997-2001 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 "engine.h"
#include "server.h"
server_static_t svs; // persistant server info
server_t sv; // local server
2007-09-16 22:00:00 +02:00
#define REQFIELDS (sizeof(reqfields) / sizeof(prvm_fieldvars_t))
prvm_fieldvars_t reqfields[] =
{
{0, 1, "classname"},
{1, 1, "globalname"},
{2, 2, "modelindex"},
{3, 3, "origin"},
{6, 3, "angles"},
{9, 3, "velocity"},
{12, 3, "avelocity"},
{15, 3, "post_origin"},
{18, 3, "post_angles"},
{21, 3, "post_velocity"},
{24, 3, "post_avelocity"},
{27, 3, "origin_offset"},
{30, 3, "angles_offset"},
{33, 2, "bouncetype"},
{34, 2, "movetype"},
{35, 2, "solid"},
{36, 3, "absmin"},
{39, 3, "absmax"},
{42, 3, "mins"},
{45, 3, "maxs"},
{48, 3, "size"},
{51, 4, "chain"},
{52, 1, "model"},
{53, 2, "frame"},
{54, 2, "sequence"},
{55, 2, "renderfx"},
{56, 2, "effects"},
{57, 2, "skin"},
{58, 2, "body"},
{59, 1, "weaponmodel"},
{60, 2, "weaponframe"},
{61, 6, "use"},
{62, 6, "touch"},
{63, 6, "think"},
{64, 6, "blocked"},
{65, 6, "activate"},
{66, 6, "walk"},
{67, 6, "jump"},
{68, 6, "duck"},
{69, 2, "flags"},
{70, 2, "aiflags"},
{71, 2, "spawnflags"},
{72, 4, "groundentity"},
{73, 2, "nextthink"},
{74, 2, "takedamage"},
{75, 2, "health"},
{76, 2, "frags"},
{77, 2, "weapon"},
{78, 2, "items"},
{79, 1, "target"},
{80, 1, "parent"},
{81, 1, "targetname"},
{82, 4, "aiment"},
{83, 4, "goalentity"},
{84, 3, "punchangle"},
{87, 2, "deadflag"},
{88, 3, "view_ofs"},
{91, 2, "button0"},
{92, 2, "button1"},
{93, 2, "button2"},
{94, 2, "impulse"},
{95, 2, "fixangle"},
{96, 3, "v_angle"},
{99, 2, "idealpitch"},
{100, 1, "netname"},
{101, 4, "enemy"},
{102, 2, "colormap"},
{103, 2, "team"},
{104, 2, "max_health"},
{105, 2, "teleport_time"},
{106, 2, "armortype"},
{107, 2, "armorvalue"},
{108, 2, "waterlevel"},
{109, 2, "watertype"},
{110, 2, "ideal_yaw"},
{111, 2, "yaw_speed"},
{112, 2, "dmg_take"},
{113, 2, "dmg_save"},
{114, 4, "dmg_inflictor"},
{115, 4, "owner"},
{116, 3, "movedir"},
{119, 1, "message"},
{120, 2, "sounds"},
{121, 1, "noise"},
{122, 1, "noise1"},
{123, 1, "noise2"},
{124, 1, "noise3"},
{125, 2, "jumpup"},
{126, 2, "jumpdn"},
{127, 4, "movetarget"},
{128, 2, "mass"},
{129, 2, "density"},
{130, 2, "gravity"},
{131, 2, "dmg"},
{132, 2, "dmgtime"},
{133, 2, "speed"}
};
2007-06-21 22:00:00 +02:00
/*
================
SV_FindIndex
================
*/
2007-09-16 22:00:00 +02:00
int SV_FindIndex (const char *name, int start, int end, bool create)
2007-06-21 22:00:00 +02:00
{
int i;
2007-09-16 22:00:00 +02:00
if (!name || !name[0]) return 0;
2007-06-21 22:00:00 +02:00
2007-09-16 22:00:00 +02:00
for (i = 1; i < end && sv.configstrings[start+i][0]; i++)
if(!strcmp(sv.configstrings[start+i], name))
2007-06-21 22:00:00 +02:00
return i;
2007-09-16 22:00:00 +02:00
if(!create) return 0;
2007-06-21 22:00:00 +02:00
2007-09-16 22:00:00 +02:00
if (i == end)
{
MsgWarn ("SV_FindIndex: %d out range [%d - %d]\n", start, end );
2007-06-21 22:00:00 +02:00
return 0;
2007-09-16 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
2007-09-16 22:00:00 +02:00
// register new resource
2007-09-06 22:00:00 +02:00
strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i]));
2007-06-21 22:00:00 +02:00
if (sv.state != ss_loading)
2007-08-19 22:00:00 +02:00
{
// send the update to everyone
2007-06-21 22:00:00 +02:00
SZ_Clear (&sv.multicast);
2007-08-19 22:00:00 +02:00
MSG_Begin(svc_configstring);
2007-06-21 22:00:00 +02:00
MSG_WriteShort (&sv.multicast, start+i);
2007-09-16 22:00:00 +02:00
MSG_WriteString (&sv.multicast, (char *)name);
2007-08-19 22:00:00 +02:00
MSG_Send(MSG_ALL_R, vec3_origin, NULL );
2007-06-21 22:00:00 +02:00
}
2007-09-06 22:00:00 +02:00
2007-06-21 22:00:00 +02:00
return i;
}
2007-09-16 22:00:00 +02:00
int SV_ModelIndex (const char *name)
2007-06-21 22:00:00 +02:00
{
return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true);
}
2007-09-16 22:00:00 +02:00
int SV_SoundIndex (const char *name)
2007-06-21 22:00:00 +02:00
{
return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true);
}
2007-09-16 22:00:00 +02:00
int SV_ImageIndex (const char *name)
2007-06-21 22:00:00 +02:00
{
return SV_FindIndex (name, CS_IMAGES, MAX_IMAGES, true);
}
/*
================
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)
{
2007-09-06 22:00:00 +02:00
edict_t *svent;
2007-09-16 22:00:00 +02:00
int entnum;
2007-06-21 22:00:00 +02:00
2007-09-16 22:00:00 +02:00
for (entnum = 1; entnum < prog->num_edicts ; entnum++)
2007-06-21 22:00:00 +02:00
{
2007-09-16 22:00:00 +02:00
svent = PRVM_EDICT_NUM(entnum);
if (svent->priv.sv->free) continue;
if (!svent->priv.sv->s.modelindex && !svent->priv.sv->s.sound && !svent->priv.sv->s.effects)
2007-09-05 22:00:00 +02:00
continue;
2007-09-16 22:00:00 +02:00
svent->priv.sv->s.number = entnum;
2007-09-02 22:00:00 +02:00
2007-09-06 22:00:00 +02:00
//
2007-06-21 22:00:00 +02:00
// take current state as baseline
2007-09-06 22:00:00 +02:00
//
2007-09-16 22:00:00 +02:00
VectorCopy (svent->priv.sv->s.origin, svent->priv.sv->s.old_origin);
sv.baselines[entnum] = svent->priv.sv->s;
2007-06-21 22:00:00 +02:00
}
}
/*
=================
SV_CheckForSavegame
=================
*/
2007-07-23 22:00:00 +02:00
void SV_CheckForSavegame (char *savename )
2007-06-21 22:00:00 +02:00
{
2007-09-06 22:00:00 +02:00
int i;
2007-07-23 22:00:00 +02:00
char name[MAX_SYSPATH];
2007-06-21 22:00:00 +02:00
2007-06-25 22:00:00 +02:00
if (sv_noreload->value) return;
if (Cvar_VariableValue ("deathmatch")) return;
2007-07-23 22:00:00 +02:00
if (!savename) return;
2007-06-21 22:00:00 +02:00
2007-07-23 22:00:00 +02:00
sprintf (name, "save/%s.bin", savename );
if(!FS_FileExists(name))
{
Msg("can't find %s\n", savename );
return;
}
2007-06-21 22:00:00 +02:00
SV_ClearWorld ();
// get configstrings and areaportals
2007-07-23 22:00:00 +02:00
SV_ReadLevelFile ( savename );
2007-09-06 22:00:00 +02:00
if (!sv.loadgame)
2007-09-11 22:00:00 +02:00
{
// coming back to a level after being in a different
2007-09-06 22:00:00 +02:00
// level, so run it for ten seconds
// rlava2 was sending too many lightstyles, and overflowing the
// reliable data. temporarily changing the server state to loading
// prevents these from being passed down.
server_state_t previousState; // PGM
previousState = sv.state; // PGM
sv.state = ss_loading; // PGM
2007-09-11 22:00:00 +02:00
for (i = 0; i < 100; i++) SV_RunFrame();
2007-09-06 22:00:00 +02:00
sv.state = previousState; // PGM
}
2007-06-21 22:00:00 +02:00
}
/*
================
SV_SpawnServer
Change the server to a new map, taking all connected
clients along with it.
================
*/
2007-07-23 22:00:00 +02:00
void SV_SpawnServer (char *server, char *spawnpoint, char *savename, server_state_t serverstate, bool attractloop, bool loadgame)
2007-06-21 22:00:00 +02:00
{
2007-09-06 22:00:00 +02:00
uint i, checksum;
2007-09-16 22:00:00 +02:00
edict_t *ent;
2007-06-21 22:00:00 +02:00
2007-07-23 22:00:00 +02:00
if (attractloop) Cvar_Set ("paused", "0");
2007-06-21 22:00:00 +02:00
2007-07-23 22:00:00 +02:00
Msg("------- Server Initialization -------\n");
2007-09-03 22:00:00 +02:00
MsgDev (D_INFO, "SpawnServer: %s\n", server);
2007-06-21 22:00:00 +02:00
if (sv.demofile) FS_Close (sv.demofile);
2007-07-23 22:00:00 +02:00
svs.spawncount++; // any partially connected client will be restarted
2007-06-21 22:00:00 +02:00
sv.state = ss_dead;
Com_SetServerState (sv.state);
// wipe the entire per-level structure
memset (&sv, 0, sizeof(sv));
svs.realtime = 0;
sv.loadgame = loadgame;
sv.attractloop = attractloop;
// save name for levels that don't set message
strcpy (sv.configstrings[CS_NAME], server);
if (Cvar_VariableValue ("deathmatch"))
{
sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value);
pm_airaccelerate = sv_airaccelerate->value;
}
else
{
strcpy(sv.configstrings[CS_AIRACCEL], "0");
pm_airaccelerate = 0;
}
SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf));
strcpy (sv.name, server);
2007-09-16 22:00:00 +02:00
SV_VM_Begin();
2007-06-21 22:00:00 +02:00
// leave slots at start for clients only
2007-09-16 22:00:00 +02:00
for (i = 0; i<maxclients->value ; i++)
2007-06-21 22:00:00 +02:00
{
// needs to reconnect
if (svs.clients[i].state > cs_connected)
svs.clients[i].state = cs_connected;
svs.clients[i].lastframe = -1;
}
2007-09-09 22:00:00 +02:00
sv.time = 1.0f;
2007-09-06 22:00:00 +02:00
strcpy (sv.name, server);
strcpy (sv.configstrings[CS_NAME], server);
2007-06-21 22:00:00 +02:00
if (serverstate != ss_game)
{
sv.models[1] = CM_LoadMap ("", false, &checksum); // no real map
}
else
{
2007-09-06 22:00:00 +02:00
sprintf (sv.configstrings[CS_MODELS+1], "maps/%s.bsp", server);
2007-06-21 22:00:00 +02:00
sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum);
}
2007-08-11 22:00:00 +02:00
sprintf (sv.configstrings[CS_MAPCHECKSUM],"%i", checksum);
2007-06-21 22:00:00 +02:00
// clear physics interaction links
SV_ClearWorld ();
2007-06-25 22:00:00 +02:00
for (i = 1; i < CM_NumInlineModels(); i++)
2007-06-21 22:00:00 +02:00
{
2007-06-25 22:00:00 +02:00
sprintf(sv.configstrings[CS_MODELS+1+i], "*%i", i);
2007-06-21 22:00:00 +02:00
sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]);
}
2007-09-06 22:00:00 +02:00
//
2007-09-04 22:00:00 +02:00
// spawn the rest of the entities on the map
2007-09-06 22:00:00 +02:00
//
2007-09-02 22:00:00 +02:00
2007-09-06 22:00:00 +02:00
// precache and static commands can be issued during
// map initialization
sv.state = ss_loading;
Com_SetServerState (sv.state);
2007-09-02 22:00:00 +02:00
2007-09-16 22:00:00 +02:00
ent = PRVM_EDICT_NUM(0);
prog->protect_world = false;
memset (ent->progs.sv, 0, prog->progs->entityfields * 4);
ent->priv.sv->free = false;
ent->progs.sv->model = PRVM_SetEngineString(sv.configstrings[CS_MODELS]);
ent->progs.sv->modelindex = 1; // world model
ent->progs.sv->solid = SOLID_BSP;
ent->progs.sv->movetype = MOVETYPE_PUSH;
prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
// spawn the rest of the entities on the map
sv.edicts = (edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(edict_t *));
sv.clients = (gclient_t *)PRVM_Alloc(maxclients->value * sizeof(gclient_t));
*prog->time = sv.time = 1.0;
// serverflags are for cross level information (sigils)
//prog->globals.server->serverflags = svs.serverflags;
// we need to reset the spawned flag on all connected clients here so that
// their thinks don't run during startup (before PutClientInServer)
// we also need to set up the client entities now
// and we need to set the ->edict pointers to point into the progs edicts
for (i = 0, sv_client = svs.clients; i < maxclients->value; i++, sv_client++)
{
sv_client->state = cs_connected;
sv_client->edict = PRVM_EDICT_NUM(i + 1);
sv_client->edict->priv.sv->client = sv.clients + i;
ent->priv.sv->s.number = i + 1;
memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd));
PRVM_ED_ClearEdict(sv_client->edict);
}
2007-09-06 22:00:00 +02:00
// load and spawn all other entities
SV_SpawnEntities ( sv.name, CM_EntityString(), spawnpoint );
// run two frames to allow everything to settle
SV_RunFrame ();
SV_RunFrame ();
2007-06-21 22:00:00 +02:00
2007-09-04 22:00:00 +02:00
// all precaches are complete
sv.state = serverstate;
Com_SetServerState (sv.state);
2007-06-21 22:00:00 +02:00
// create a baseline for more efficient communications
SV_CreateBaseline ();
2007-09-06 22:00:00 +02:00
// check for a savegame
SV_CheckForSavegame ( savename );
2007-06-21 22:00:00 +02:00
// set serverinfo variable
Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET);
2007-07-28 22:00:00 +02:00
Msg ("-------------------------------------\n");
2007-09-16 22:00:00 +02:00
SV_VM_End();
2007-06-21 22:00:00 +02:00
}
/*
==============
SV_InitGame
A brand new game has been started
==============
*/
void SV_InitGame (void)
{
2007-09-16 22:00:00 +02:00
char idmaster[32];
2007-06-21 22:00:00 +02:00
if (svs.initialized)
{
// cause any connected clients to reconnect
SV_Shutdown ("Server restarted\n", true);
}
else
{
// make sure the client is down
CL_Drop ();
SCR_BeginLoadingPlaque ();
}
// get any latched variable changes (maxclients, etc)
Cvar_GetLatchedVars ();
svs.initialized = true;
if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch"))
{
2007-07-28 22:00:00 +02:00
Msg("Deathmatch and Coop both set, disabling Coop\n");
2007-06-21 22:00:00 +02:00
Cvar_FullSet ("coop", "0", CVAR_SERVERINFO | CVAR_LATCH);
}
// dedicated servers are can't be single player and are usually DM
// so unless they explicity set coop, force it to deathmatch
2007-09-06 22:00:00 +02:00
if (dedicated->value)
2007-06-21 22:00:00 +02:00
{
2007-09-06 22:00:00 +02:00
if (!Cvar_VariableValue ("coop"))
Cvar_FullSet ("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH);
2007-06-21 22:00:00 +02:00
}
// init clients
if (Cvar_VariableValue ("deathmatch"))
{
2007-09-06 22:00:00 +02:00
if (maxclients->value <= 1)
Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
else if (maxclients->value > MAX_CLIENTS)
Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
2007-06-21 22:00:00 +02:00
}
else if (Cvar_VariableValue ("coop"))
{
2007-09-06 22:00:00 +02:00
if (maxclients->value <= 1 || maxclients->value > 4)
Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
2007-06-21 22:00:00 +02:00
}
else // non-deathmatch, non-coop is one player
{
2007-09-06 22:00:00 +02:00
Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
2007-06-21 22:00:00 +02:00
}
svs.spawncount = rand();
2007-09-06 22:00:00 +02:00
svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value);
svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);
2007-06-21 22:00:00 +02:00
// init network stuff
2007-09-06 22:00:00 +02:00
NET_Config ( (maxclients->value > 1) );
2007-06-21 22:00:00 +02:00
// heartbeats will always be sent to the id master
2007-09-09 22:00:00 +02:00
svs.last_heartbeat = -99999.0f; // send immediately
2007-08-11 22:00:00 +02:00
sprintf(idmaster, "192.246.40.37:%i", PORT_MASTER);
2007-06-21 22:00:00 +02:00
NET_StringToAdr (idmaster, &master_adr[0]);
2007-09-06 22:00:00 +02:00
// init game
SV_InitGameProgs ();
2007-06-21 22:00:00 +02:00
}
/*
======================
SV_Map
the full syntax is:
map [*]<map>$<startspot>+<nextserver>
command from the console or progs.
Map can also be a.cin, .pcx, or .dm2 file
Nextserver is used to allow a cinematic to play, then proceed to
another level:
map tram.cin+jail_e3
======================
*/
2007-07-23 22:00:00 +02:00
void SV_Map (bool attractloop, char *levelstring, char *savename, bool loadgame)
2007-06-21 22:00:00 +02:00
{
char *ch;
2007-07-23 22:00:00 +02:00
int l;
char level[MAX_QPATH], spawnpoint[MAX_QPATH];
const char *ext = FS_FileExtension(levelstring);
2007-06-21 22:00:00 +02:00
sv.loadgame = loadgame;
sv.attractloop = attractloop;
if (sv.state == ss_dead && !sv.loadgame) SV_InitGame ();// the game is just starting
strcpy (level, levelstring);
// if there is a + in the map, set nextserver to the remainder
ch = strstr(level, "+");
if (ch)
{
*ch = 0;
2007-07-23 22:00:00 +02:00
Cvar_Set ("nextserver", va("gamemap \"%s\"", ch + 1));
2007-06-21 22:00:00 +02:00
}
2007-07-23 22:00:00 +02:00
else Cvar_Set ("nextserver", "");
2007-06-21 22:00:00 +02:00
//ZOID special hack for end game screen in coop mode
2007-08-01 22:00:00 +02:00
if (Cvar_VariableValue ("coop") && !strcasecmp(level, "victory.pcx"))
2007-06-21 22:00:00 +02:00
Cvar_Set ("nextserver", "gamemap \"*base1\"");
// if there is a $, use the remainder as a spawnpoint
ch = strstr(level, "$");
if (ch)
{
*ch = 0;
2007-07-23 22:00:00 +02:00
strcpy (spawnpoint, ch + 1);
2007-06-21 22:00:00 +02:00
}
2007-07-23 22:00:00 +02:00
else spawnpoint[0] = 0;
2007-06-21 22:00:00 +02:00
// skip the end-of-unit flag if necessary
2007-07-23 22:00:00 +02:00
if (level[0] == '*') strcpy (level, level+1);
2007-06-21 22:00:00 +02:00
l = strlen(level);
2007-07-23 22:00:00 +02:00
if (!strcmp(ext, "cin"))
2007-06-21 22:00:00 +02:00
{
2007-07-23 22:00:00 +02:00
SCR_BeginLoadingPlaque (); // for local system
2007-06-21 22:00:00 +02:00
SV_BroadcastCommand ("changing\n");
2007-07-23 22:00:00 +02:00
SV_SpawnServer (level, spawnpoint, NULL, ss_cinematic, attractloop, loadgame);
2007-06-21 22:00:00 +02:00
}
2007-07-23 22:00:00 +02:00
else if (!strcmp(ext, "dm2"))
2007-06-21 22:00:00 +02:00
{
2007-07-23 22:00:00 +02:00
SCR_BeginLoadingPlaque (); // for local system
2007-06-21 22:00:00 +02:00
SV_BroadcastCommand ("changing\n");
2007-07-23 22:00:00 +02:00
SV_SpawnServer (level, spawnpoint, NULL, ss_demo, attractloop, loadgame);
2007-06-21 22:00:00 +02:00
}
2007-07-23 22:00:00 +02:00
else if (!strcmp(ext, "pcx"))
2007-06-21 22:00:00 +02:00
{
2007-07-23 22:00:00 +02:00
SCR_BeginLoadingPlaque (); // for local system
2007-06-21 22:00:00 +02:00
SV_BroadcastCommand ("changing\n");
2007-07-23 22:00:00 +02:00
SV_SpawnServer (level, spawnpoint, NULL, ss_pic, attractloop, loadgame);
2007-06-21 22:00:00 +02:00
}
else
{
2007-07-23 22:00:00 +02:00
SCR_BeginLoadingPlaque (); // for local system
2007-06-21 22:00:00 +02:00
SV_BroadcastCommand ("changing\n");
SV_SendClientMessages ();
2007-07-23 22:00:00 +02:00
SV_SpawnServer (level, spawnpoint, savename, ss_game, attractloop, loadgame);
2007-06-21 22:00:00 +02:00
Cbuf_CopyToDefer ();
}
SV_BroadcastCommand ("reconnect\n");
}
2007-09-16 22:00:00 +02:00
void SV_VM_BeginIncreaseEdicts(void)
{
int i;
edict_t *ent;
if(sv.edicts) PRVM_Free( sv.edicts );
sv.edicts = (edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
// links don't survive the transition, so unlink everything
for (i = 0, ent = prog->edicts; i < prog->max_edicts; i++, ent++)
{
if (!ent->priv.sv->free) SV_UnlinkEdict(prog->edicts + i); //free old entity
memset(&ent->priv.sv->clusternums, 0, sizeof(ent->priv.sv->clusternums));
}
SV_ClearWorld();
}
void SV_VM_EndIncreaseEdicts(void)
{
int i;
edict_t *ent;
for (i = 0, ent = prog->edicts; i < prog->max_edicts; i++, ent++)
{
// link every entity except world
if (!ent->priv.sv->free) SV_LinkEdict(ent);
}
}
void SV_VM_InitEdict(edict_t *e)
{
SV_InitEdict( e );
}
void SV_VM_FreeEdict(edict_t *e)
{
SV_UnlinkEdict(e); // unlink from world bsp
SV_FreeEdict( e );
}
void SV_VM_CountEdicts( void )
{
int i;
edict_t *ent;
int active = 0, models = 0, solid = 0, step = 0;
for (i = 0; i < prog->num_edicts; i++)
{
ent = PRVM_EDICT_NUM(i);
if (ent->priv.sv->free)
continue;
active++;
if (ent->progs.sv->solid) solid++;
if (ent->progs.sv->model) models++;
if (ent->progs.sv->movetype == MOVETYPE_STEP) step++;
}
Msg("num_edicts:%3i\n", prog->num_edicts);
Msg("active :%3i\n", active);
Msg("view :%3i\n", models);
Msg("touch :%3i\n", solid);
Msg("step :%3i\n", step);
}
bool SV_VM_LoadEdict(edict_t *ent)
{
int current_skill = (int)Cvar_VariableValue ("skill");
// remove things from different skill levels or deathmatch
if(Cvar_VariableValue ("deathmatch"))
{
if (((int)ent->progs.sv->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
{
return false;
}
}
else if ((current_skill <= 0 && ((int)ent->progs.sv->spawnflags & SPAWNFLAG_NOT_EASY )) || (current_skill == 1 && ((int)ent->progs.sv->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (current_skill >= 2 && ((int)ent->progs.sv->spawnflags & SPAWNFLAG_NOT_HARD )))
{
return false;
}
return true;
}
void SV_VM_Setup( void )
{
PRVM_Begin;
PRVM_InitProg( PRVM_SERVERPROG );
// allocate the mempools
// TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
prog->progs_mempool = Mem_AllocPool("Server Progs" );
prog->builtins = vm_sv_builtins;
prog->numbuiltins = vm_sv_numbuiltins;
prog->max_edicts = 512;
prog->limit_edicts = MAX_EDICTS;
prog->reserved_edicts = maxclients->value;
prog->edictprivate_size = sizeof(sv_edict_t);
prog->name = "server";
prog->extensionstring = "";
prog->loadintoworld = true;
prog->begin_increase_edicts = SV_VM_BeginIncreaseEdicts;
prog->end_increase_edicts = SV_VM_EndIncreaseEdicts;
prog->init_edict = SV_VM_InitEdict;
prog->free_edict = SV_VM_FreeEdict;
prog->count_edicts = SV_VM_CountEdicts;
prog->load_edict = SV_VM_LoadEdict;
prog->init_cmd = VM_Cmd_Init;
prog->reset_cmd = VM_Cmd_Reset;
prog->error_cmd = VM_Error;
// TODO: add a requiredfuncs list (ask LH if this is necessary at all)
PRVM_LoadProgs( "server.dat", 0, NULL, REQFIELDS, reqfields );
PRVM_End;
}
void SV_VM_Begin(void)
{
PRVM_Begin;
PRVM_SetProg( PRVM_SERVERPROG );
*prog->time = sv.time;
}
void SV_VM_End(void)
{
PRVM_End;
}