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

745 lines
18 KiB
C
Raw Normal View History

2011-05-09 22:00:00 +02:00
/*
sv_init.c - server initialize operations
Copyright (C) 2009 Uncle Mike
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 3 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.
*/
2007-06-21 22:00:00 +02:00
2008-06-09 22:00:00 +02:00
#include "common.h"
2007-06-21 22:00:00 +02:00
#include "server.h"
2010-04-02 22:00:00 +02:00
int SV_UPDATE_BACKUP = SINGLEPLAYER_BACKUP;
2007-10-03 22:00:00 +02:00
server_static_t svs; // persistant server info
2008-12-26 22:00:00 +01:00
svgame_static_t svgame; // persistant game info
2007-10-03 22:00:00 +02:00
server_t sv; // local server
2007-09-16 22:00:00 +02:00
2011-04-05 22:00:00 +02:00
int SV_ModelIndex( const char *filename )
2007-06-21 22:00:00 +02:00
{
2011-04-05 22:00:00 +02:00
char name[64];
2011-04-17 22:00:00 +02:00
int i;
2010-10-26 22:00:00 +02:00
2011-04-05 22:00:00 +02:00
if( !filename || !filename[0] )
2010-10-26 22:00:00 +02:00
return 0;
2011-04-17 22:00:00 +02:00
if( *filename == '!' ) filename++;
Q_strncpy( name, filename, sizeof( name ));
COM_FixSlashes( name );
2011-04-05 22:00:00 +02:00
2010-10-26 22:00:00 +02:00
for( i = 1; i < MAX_MODELS && sv.model_precache[i][0]; i++ )
{
2011-03-09 22:00:00 +01:00
if( !Q_stricmp( sv.model_precache[i], name ))
2010-10-26 22:00:00 +02:00
return i;
}
if( i == MAX_MODELS )
{
Host_Error( "SV_ModelIndex: MAX_MODELS limit exceeded\n" );
return 0;
}
// register new model
2011-03-09 22:00:00 +01:00
Q_strncpy( sv.model_precache[i], name, sizeof( sv.model_precache[i] ));
2010-10-26 22:00:00 +02:00
if( sv.state != ss_loading )
{
// send the update to everyone
BF_WriteByte( &sv.reliable_datagram, svc_modelindex );
BF_WriteUBitLong( &sv.reliable_datagram, i, MAX_MODEL_BITS );
BF_WriteString( &sv.reliable_datagram, name );
}
return i;
2007-06-21 22:00:00 +02:00
}
2011-04-05 22:00:00 +02:00
int SV_SoundIndex( const char *filename )
2007-06-21 22:00:00 +02:00
{
2011-04-05 22:00:00 +02:00
char name[64];
2011-04-17 22:00:00 +02:00
int i;
2010-10-26 22:00:00 +02:00
2011-04-17 22:00:00 +02:00
// don't precache sentence names!
2011-04-05 22:00:00 +02:00
if( !filename || !filename[0] || filename[0] == '!' )
2010-10-26 22:00:00 +02:00
return 0;
2011-04-17 22:00:00 +02:00
Q_strncpy( name, filename, sizeof( name ));
COM_FixSlashes( name );
2011-04-05 22:00:00 +02:00
2010-10-26 22:00:00 +02:00
for( i = 1; i < MAX_SOUNDS && sv.sound_precache[i][0]; i++ )
{
2011-03-09 22:00:00 +01:00
if( !Q_stricmp( sv.sound_precache[i], name ))
2010-10-26 22:00:00 +02:00
return i;
}
if( i == MAX_SOUNDS )
{
Host_Error( "SV_SoundIndex: MAX_SOUNDS limit exceeded\n" );
return 0;
}
// register new sound
2011-03-09 22:00:00 +01:00
Q_strncpy( sv.sound_precache[i], name, sizeof( sv.sound_precache[i] ));
2010-10-26 22:00:00 +02:00
if( sv.state != ss_loading )
{
// send the update to everyone
2011-02-13 22:00:00 +01:00
BF_WriteByte( &sv.reliable_datagram, svc_soundindex );
2010-10-26 22:00:00 +02:00
BF_WriteUBitLong( &sv.reliable_datagram, i, MAX_SOUND_BITS );
BF_WriteString( &sv.reliable_datagram, name );
}
return i;
2008-12-15 22:00:00 +01:00
}
2011-04-05 22:00:00 +02:00
int SV_EventIndex( const char *filename )
2008-12-15 22:00:00 +01:00
{
2011-04-05 22:00:00 +02:00
char name[64];
2011-04-17 22:00:00 +02:00
int i;
2010-10-26 22:00:00 +02:00
2011-04-05 22:00:00 +02:00
if( !filename || !filename[0] )
2010-10-26 22:00:00 +02:00
return 0;
2011-04-17 22:00:00 +02:00
Q_strncpy( name, filename, sizeof( name ));
COM_FixSlashes( name );
2011-04-05 22:00:00 +02:00
2010-10-28 22:00:00 +02:00
for( i = 1; i < MAX_EVENTS && sv.event_precache[i][0]; i++ )
2010-10-26 22:00:00 +02:00
{
2011-03-09 22:00:00 +01:00
if( !Q_stricmp( sv.event_precache[i], name ))
2010-10-26 22:00:00 +02:00
return i;
}
2010-10-28 22:00:00 +02:00
if( i == MAX_EVENTS )
2010-10-26 22:00:00 +02:00
{
2010-10-28 22:00:00 +02:00
Host_Error( "SV_EventIndex: MAX_EVENTS limit exceeded\n" );
2010-10-26 22:00:00 +02:00
return 0;
}
2010-10-28 22:00:00 +02:00
// register new event
2011-03-09 22:00:00 +01:00
Q_strncpy( sv.event_precache[i], name, sizeof( sv.event_precache[i] ));
2010-10-26 22:00:00 +02:00
2010-10-28 22:00:00 +02:00
if( sv.state != ss_loading )
{
// send the update to everyone
BF_WriteByte( &sv.reliable_datagram, svc_eventindex );
BF_WriteUBitLong( &sv.reliable_datagram, i, MAX_EVENT_BITS );
BF_WriteString( &sv.reliable_datagram, name );
}
2007-06-21 22:00:00 +02:00
2010-10-28 22:00:00 +02:00
return i;
2009-11-23 22:00:00 +01:00
}
2011-04-05 22:00:00 +02:00
int SV_GenericIndex( const char *filename )
2009-11-23 22:00:00 +01:00
{
2011-04-05 22:00:00 +02:00
char name[64];
2011-04-17 22:00:00 +02:00
int i;
2010-10-28 22:00:00 +02:00
2011-04-05 22:00:00 +02:00
if( !filename || !filename[0] )
2010-10-28 22:00:00 +02:00
return 0;
2011-04-17 22:00:00 +02:00
Q_strncpy( name, filename, sizeof( name ));
COM_FixSlashes( name );
2011-04-05 22:00:00 +02:00
2010-10-28 22:00:00 +02:00
for( i = 1; i < MAX_CUSTOM && sv.files_precache[i][0]; i++ )
{
2011-03-09 22:00:00 +01:00
if( !Q_stricmp( sv.files_precache[i], name ))
2010-10-28 22:00:00 +02:00
return i;
}
if( i == MAX_CUSTOM )
{
Host_Error( "SV_GenericIndex: MAX_RESOURCES limit exceeded\n" );
return 0;
}
if( sv.state != ss_loading )
{
// g-cont. can we downloading resources in-game ? need testing
Host_Error( "SV_PrecacheGeneric: ( %s ). Precache can only be done in spawn functions.", name );
return 0;
}
// register new generic resource
2011-03-09 22:00:00 +01:00
Q_strncpy( sv.files_precache[i], name, sizeof( sv.files_precache[i] ));
2010-10-28 22:00:00 +02:00
return i;
2009-11-23 22:00:00 +01:00
}
2010-12-08 22:00:00 +01:00
/*
================
SV_EntityScript
get entity script for current map
================
*/
2011-03-02 22:00:00 +01:00
char *SV_EntityScript( void )
2010-12-08 22:00:00 +01:00
{
string entfilename;
2011-03-02 22:00:00 +01:00
char *ents;
2011-10-14 22:00:00 +02:00
size_t ft1, ft2;
2010-12-08 22:00:00 +01:00
if( !sv.worldmodel )
return NULL;
// check for entfile too
2011-03-09 22:00:00 +01:00
Q_strncpy( entfilename, sv.worldmodel->name, sizeof( entfilename ));
2010-12-08 22:00:00 +01:00
FS_StripExtension( entfilename );
FS_DefaultExtension( entfilename, ".ent" );
2011-10-14 22:00:00 +02:00
// make sure what entity patch is never than bsp
ft1 = FS_FileTime( sv.worldmodel->name, false );
ft2 = FS_FileTime( entfilename, true );
if( ft2 != -1 )
2010-12-08 22:00:00 +01:00
{
2011-10-14 22:00:00 +02:00
if( ft1 > ft2 )
{
MsgDev( D_INFO, "^1Entity patch is older than bsp. Ignored.\n", entfilename );
}
2011-10-28 22:00:00 +02:00
else if(( ents = FS_LoadFile( entfilename, NULL, true )) != NULL )
2011-10-14 22:00:00 +02:00
{
MsgDev( D_INFO, "^2Read entity patch:^7 %s\n", entfilename );
return ents;
}
2010-12-08 22:00:00 +01:00
}
2011-03-02 22:00:00 +01:00
// use internal entities
return sv.worldmodel->entities;
2010-12-08 22:00:00 +01:00
}
2007-06-21 22:00:00 +02:00
/*
================
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
================
*/
2008-11-15 22:00:00 +01:00
void SV_CreateBaseline( void )
2007-06-21 22:00:00 +02:00
{
2009-11-28 22:00:00 +01:00
edict_t *pEdict;
2010-10-09 22:00:00 +02:00
int e;
2007-06-21 22:00:00 +02:00
2010-10-09 22:00:00 +02:00
for( e = 0; e < svgame.numEntities; e++ )
2007-06-21 22:00:00 +02:00
{
2010-10-09 22:00:00 +02:00
pEdict = EDICT_NUM( e );
2010-04-09 22:00:00 +02:00
if( !SV_IsValidEdict( pEdict )) continue;
2010-08-15 22:00:00 +02:00
SV_BaselineForEntity( pEdict );
2009-01-04 22:00:00 +01:00
}
2010-10-19 22:00:00 +02:00
// create the instanced baselines
svgame.dllFuncs.pfnCreateInstancedBaselines();
2007-06-21 22:00:00 +02:00
}
2011-01-11 22:00:00 +01:00
/*
================
SV_FreeOldEntities
remove immediate entities
================
*/
void SV_FreeOldEntities( void )
{
edict_t *ent;
int i;
// at end of frame kill all entities which supposed to it
for( i = svgame.globals->maxClients + 1; i < svgame.numEntities; i++ )
{
ent = EDICT_NUM( i );
if( ent->free ) continue;
if( ent->v.flags & FL_KILLME )
SV_FreeEdict( ent );
}
// decrement svgame.numEntities if the highest number entities died
2011-04-05 22:00:00 +02:00
for( ; EDICT_NUM( svgame.numEntities - 1 )->free; svgame.numEntities-- );
2011-01-11 22:00:00 +01:00
}
2009-09-28 22:00:00 +02:00
/*
================
SV_ActivateServer
activate server on changed map, run physics
================
*/
void SV_ActivateServer( void )
{
2011-01-02 22:00:00 +01:00
int i, numFrames;
2010-06-20 22:00:00 +02:00
2010-03-28 22:00:00 +02:00
if( !svs.initialized )
return;
2010-10-26 22:00:00 +02:00
// custom muzzleflashes
pfnPrecacheModel( "sprites/muzzleflash.spr" );
pfnPrecacheModel( "sprites/muzzleflash1.spr" );
pfnPrecacheModel( "sprites/muzzleflash2.spr" );
pfnPrecacheModel( "sprites/muzzleflash3.spr" );
// rocket flare
pfnPrecacheModel( "sprites/animglow01.spr" );
// ricochet sprite
pfnPrecacheModel( "sprites/richo1.spr" );
2009-09-28 22:00:00 +02:00
// Activate the DLL server code
2010-08-15 22:00:00 +02:00
svgame.dllFuncs.pfnServerActivate( svgame.edicts, svgame.numEntities, svgame.globals->maxClients );
2009-09-28 22:00:00 +02:00
2010-08-30 22:00:00 +02:00
// create a baseline for more efficient communications
SV_CreateBaseline();
2010-08-18 22:00:00 +02:00
2012-05-20 22:00:00 +02:00
// check and count all files that marked by user as unmodified (typically is a player models etc)
sv.num_consistency_resources = SV_TransferConsistencyInfo();
2011-04-05 22:00:00 +02:00
// send serverinfo to all connected clients
2010-10-07 22:00:00 +02:00
for( i = 0; i < sv_maxclients->integer; i++ )
{
if( svs.clients[i].state >= cs_connected )
{
Netchan_Clear( &svs.clients[i].netchan );
2010-10-14 22:00:00 +02:00
svs.clients[i].delta_sequence = -1;
2010-10-07 22:00:00 +02:00
}
}
2011-01-02 22:00:00 +01:00
numFrames = (sv.loadgame) ? 1 : 2;
2011-01-31 22:00:00 +01:00
if( !sv.loadgame || svgame.globals->changelevel )
host.frametime = 0.1f;
2011-01-03 22:00:00 +01:00
2011-02-22 22:00:00 +01:00
// GoldSrc rules
2012-05-20 22:00:00 +02:00
// NOTE: this stuff is breaking sound from func_rotating in multiplayer
2011-03-07 22:00:00 +01:00
// e.g. ambience\boomer.wav on snark_pit.bsp
2011-02-22 22:00:00 +01:00
numFrames *= sv_maxclients->integer;
2011-01-02 22:00:00 +01:00
// run some frames to allow everything to settle
for( i = 0; i < numFrames; i++ )
2011-01-09 22:00:00 +01:00
{
2011-01-02 22:00:00 +01:00
SV_Physics();
2011-01-09 22:00:00 +01:00
}
2009-09-28 22:00:00 +02:00
2009-11-10 22:00:00 +01:00
// invoke to refresh all movevars
2011-03-10 22:00:00 +01:00
Q_memset( &svgame.oldmovevars, 0, sizeof( movevars_t ));
2012-05-20 22:00:00 +02:00
svgame.globals->changelevel = false; // changelevel ends here
2009-11-10 22:00:00 +01:00
2009-11-25 22:00:00 +01:00
// setup hostflags
sv.hostflags = 0;
2009-09-28 22:00:00 +02:00
// tell what kind of server has been started.
if( svgame.globals->maxClients > 1 )
{
MsgDev( D_INFO, "%i player server started\n", svgame.globals->maxClients );
2012-05-17 22:00:00 +02:00
Cvar_Reset( "clockwindow" );
2009-09-28 22:00:00 +02:00
}
else
{
2012-05-17 22:00:00 +02:00
// clear the ugly moving delay in singleplayer
Cvar_SetFloat( "clockwindow", 0.0f );
2009-09-28 22:00:00 +02:00
MsgDev( D_INFO, "Game started\n" );
}
2011-03-31 22:00:00 +02:00
if( host.type == HOST_DEDICATED )
2011-04-05 22:00:00 +02:00
{
2011-03-31 22:00:00 +02:00
Mod_FreeUnused ();
2011-04-05 22:00:00 +02:00
}
2010-04-12 22:00:00 +02:00
sv.state = ss_active;
2010-02-09 22:00:00 +01:00
physinfo->modified = true;
2012-08-29 22:00:00 +02:00
sv.changelevel = false;
2010-06-20 22:00:00 +02:00
sv.paused = false;
2010-04-12 22:00:00 +02:00
Host_SetServerState( sv.state );
2011-07-07 22:00:00 +02:00
if( sv_maxclients->integer > 1 && public_server->integer )
{
MsgDev( D_INFO, "Add your server, to master server list\n" );
Master_Add( );
}
2009-09-28 22:00:00 +02:00
}
/*
================
SV_DeactivateServer
2010-11-19 22:00:00 +01:00
deactivate server, free edicts, strings etc
2009-09-28 22:00:00 +02:00
================
*/
void SV_DeactivateServer( void )
{
2010-04-02 22:00:00 +02:00
int i;
2012-12-18 21:00:00 +01:00
if( !svs.initialized || sv.state == ss_dead )
return;
2010-04-09 22:00:00 +02:00
2010-03-22 22:00:00 +01:00
sv.state = ss_dead;
2009-09-28 22:00:00 +02:00
2010-10-17 22:00:00 +02:00
SV_FreeEdicts ();
2011-04-18 22:00:00 +02:00
SV_ClearPhysEnts ();
2010-11-19 22:00:00 +01:00
Mem_EmptyPool( svgame.stringspool );
2010-03-30 22:00:00 +02:00
2009-09-28 22:00:00 +02:00
svgame.dllFuncs.pfnServerDeactivate();
2012-03-24 21:00:00 +01:00
for( i = 0; i < sv_maxclients->integer; i++ )
2010-04-02 22:00:00 +02:00
{
2010-10-14 22:00:00 +02:00
// release client frames
2011-04-05 22:00:00 +02:00
if( svs.clients[i].frames )
Mem_Free( svs.clients[i].frames );
svs.clients[i].frames = NULL;
2010-04-02 22:00:00 +02:00
}
2009-09-28 22:00:00 +02:00
svgame.globals->maxEntities = GI->max_edicts;
svgame.globals->maxClients = sv_maxclients->integer;
2010-08-15 22:00:00 +02:00
svgame.numEntities = svgame.globals->maxClients + 1; // clients + world
2011-04-05 22:00:00 +02:00
svgame.globals->startspot = 0;
2009-09-28 22:00:00 +02:00
svgame.globals->mapname = 0;
}
/*
================
SV_LevelInit
Spawn all entities
================
*/
2010-10-26 22:00:00 +02:00
void SV_LevelInit( const char *pMapName, char const *pOldLevel, char const *pLandmarkName, qboolean loadGame )
2009-09-28 22:00:00 +02:00
{
2010-03-25 22:00:00 +01:00
if( !svs.initialized )
return;
2010-03-24 22:00:00 +01:00
if( loadGame )
2009-09-28 22:00:00 +02:00
{
2010-03-24 22:00:00 +01:00
if( !SV_LoadGameState( pMapName, 1 ))
{
2010-12-08 22:00:00 +01:00
SV_SpawnEntities( pMapName, SV_EntityScript( ));
2010-03-24 22:00:00 +01:00
}
if( pOldLevel )
{
SV_LoadAdjacentEnts( pOldLevel, pLandmarkName );
}
2011-01-03 22:00:00 +01:00
if( sv_newunit->integer )
{
SV_ClearSaveDir();
}
2009-09-28 22:00:00 +02:00
}
2010-03-24 22:00:00 +01:00
else
2009-09-28 22:00:00 +02:00
{
2010-03-28 22:00:00 +02:00
svgame.dllFuncs.pfnResetGlobalState();
2010-12-08 22:00:00 +01:00
SV_SpawnEntities( pMapName, SV_EntityScript( ));
2011-01-03 22:00:00 +01:00
svgame.globals->frametime = 0.0f;
2012-08-14 22:00:00 +02:00
if( sv_newunit->integer )
{
SV_ClearSaveDir();
}
2009-09-28 22:00:00 +02:00
}
2010-03-24 22:00:00 +01:00
2011-01-03 22:00:00 +01:00
// always clearing newunit variable
Cvar_SetFloat( "sv_newunit", 0 );
2011-01-02 22:00:00 +01:00
2012-12-18 21:00:00 +01:00
// relese all intermediate entities
2010-03-24 22:00:00 +01:00
SV_FreeOldEntities ();
2009-09-28 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
/*
================
SV_SpawnServer
Change the server to a new map, taking all connected
clients along with it.
================
*/
2010-10-26 22:00:00 +02:00
qboolean SV_SpawnServer( const char *mapname, const char *startspot )
2007-06-21 22:00:00 +02:00
{
2010-10-31 22:00:00 +01:00
int i, current_skill;
2010-10-26 22:00:00 +02:00
qboolean loadgame, paused;
2012-08-29 22:00:00 +02:00
qboolean background, changelevel;
2007-06-21 22:00:00 +02:00
2011-02-22 22:00:00 +01:00
// save state
loadgame = sv.loadgame;
background = sv.background;
2012-08-29 22:00:00 +02:00
changelevel = sv.changelevel;
2011-02-22 22:00:00 +01:00
paused = sv.paused;
2010-03-28 22:00:00 +02:00
if( sv.state == ss_dead )
2009-09-28 22:00:00 +02:00
SV_InitGame(); // the game is just starting
2012-12-16 21:00:00 +01:00
else if( !sv_maxclients->modified )
Cmd_ExecuteString( "latch\n", src_command );
else MsgDev( D_ERROR, "SV_SpawnServer: while 'maxplayers' was modified.\n" );
2009-09-28 22:00:00 +02:00
2013-10-19 22:00:00 +02:00
sv_maxclients->modified = false;
deathmatch->modified = false;
teamplay->modified = false;
coop->modified = false;
2010-03-25 22:00:00 +01:00
if( !svs.initialized )
return false;
2011-04-05 22:00:00 +02:00
svgame.globals->changelevel = false; // will be restored later if needed
2010-06-17 22:00:00 +02:00
svs.timestart = Sys_DoubleTime();
2007-07-23 22:00:00 +02:00
svs.spawncount++; // any partially connected client will be restarted
2010-04-02 22:00:00 +02:00
if( startspot )
{
2010-07-17 22:00:00 +02:00
MsgDev( D_INFO, "Spawn Server: %s [%s]\n", mapname, startspot );
2010-04-02 22:00:00 +02:00
}
else
{
2010-07-17 22:00:00 +02:00
MsgDev( D_INFO, "Spawn Server: %s\n", mapname );
2010-04-02 22:00:00 +02:00
}
2009-09-28 22:00:00 +02:00
2007-06-21 22:00:00 +02:00
sv.state = ss_dead;
2008-08-02 22:00:00 +02:00
Host_SetServerState( sv.state );
2011-03-10 22:00:00 +01:00
Q_memset( &sv, 0, sizeof( sv )); // wipe the entire per-level structure
2007-06-21 22:00:00 +02:00
2009-09-28 22:00:00 +02:00
// restore state
2010-03-28 22:00:00 +02:00
sv.paused = paused;
2009-09-28 22:00:00 +02:00
sv.loadgame = loadgame;
2011-02-22 22:00:00 +01:00
sv.background = background;
2012-08-29 22:00:00 +02:00
sv.changelevel = changelevel;
2010-10-09 22:00:00 +02:00
sv.time = 1.0f; // server spawn time it's always 1.0 second
2011-01-31 22:00:00 +01:00
svgame.globals->time = sv.time;
2010-06-20 22:00:00 +02:00
2009-11-25 22:00:00 +01:00
// initialize buffers
2010-10-09 22:00:00 +02:00
BF_Init( &sv.datagram, "Datagram", sv.datagram_buf, sizeof( sv.datagram_buf ));
BF_Init( &sv.reliable_datagram, "Datagram R", sv.reliable_datagram_buf, sizeof( sv.reliable_datagram_buf ));
2010-08-04 22:00:00 +02:00
BF_Init( &sv.multicast, "Multicast", sv.multicast_buf, sizeof( sv.multicast_buf ));
BF_Init( &sv.signon, "Signon", sv.signon_buf, sizeof( sv.signon_buf ));
2011-04-05 22:00:00 +02:00
BF_Init( &sv.spectator_datagram, "Spectator Datagram", sv.spectator_buf, sizeof( sv.spectator_buf ));
2007-06-21 22:00:00 +02:00
// leave slots at start for clients only
2009-09-25 22:00:00 +02:00
for( i = 0; i < sv_maxclients->integer; i++ )
2007-06-21 22:00:00 +02:00
{
// needs to reconnect
2008-08-02 22:00:00 +02:00
if( svs.clients[i].state > cs_connected )
2007-06-21 22:00:00 +02:00
svs.clients[i].state = cs_connected;
}
2009-09-28 22:00:00 +02:00
// make cvars consistant
2010-10-31 22:00:00 +01:00
if( Cvar_VariableInteger( "coop" )) Cvar_SetFloat( "deathmatch", 0 );
2010-04-02 22:00:00 +02:00
current_skill = (int)(Cvar_VariableValue( "skill" ) + 0.5f);
current_skill = bound( 0, current_skill, 3 );
2009-09-28 22:00:00 +02:00
2010-10-31 22:00:00 +01:00
Cvar_SetFloat( "skill", (float)current_skill );
2009-09-28 22:00:00 +02:00
2014-05-17 22:00:00 +02:00
if( sv.background )
{
// tell the game parts about background state
2011-02-22 22:00:00 +01:00
Cvar_FullSet( "sv_background", "1", CVAR_READ_ONLY );
2014-05-17 22:00:00 +02:00
Cvar_FullSet( "cl_background", "1", CVAR_READ_ONLY );
}
else
{
Cvar_FullSet( "sv_background", "0", CVAR_READ_ONLY );
Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY );
}
2011-02-22 22:00:00 +01:00
2010-04-02 22:00:00 +02:00
// make sure what server name doesn't contain path and extension
FS_FileBase( mapname, sv.name );
if( startspot )
2011-03-09 22:00:00 +01:00
Q_strncpy( sv.startspot, startspot, sizeof( sv.startspot ));
2009-09-28 22:00:00 +02:00
else sv.startspot[0] = '\0';
2011-03-09 22:00:00 +01:00
Q_snprintf( sv.model_precache[1], sizeof( sv.model_precache[0] ), "maps/%s.bsp", sv.name );
2011-04-18 22:00:00 +02:00
Mod_LoadWorld( sv.model_precache[1], &sv.checksum, false );
2011-02-20 22:00:00 +01:00
sv.worldmodel = Mod_Handle( 1 ); // get world pointer
2007-06-21 22:00:00 +02:00
2010-10-18 22:00:00 +02:00
for( i = 1; i < sv.worldmodel->numsubmodels; i++ )
2007-06-21 22:00:00 +02:00
{
2011-03-09 22:00:00 +01:00
Q_sprintf( sv.model_precache[i+1], "*%i", i );
2010-12-08 22:00:00 +01:00
Mod_RegisterModel( sv.model_precache[i+1], i+1 );
2007-06-21 22:00:00 +02:00
}
2009-09-28 22:00:00 +02:00
// precache and static commands can be issued during map initialization
2007-09-06 22:00:00 +02:00
sv.state = ss_loading;
2010-04-02 22:00:00 +02:00
2008-01-13 22:00:00 +01:00
Host_SetServerState( sv.state );
2010-03-24 22:00:00 +01:00
2010-04-02 22:00:00 +02:00
// clear physics interaction links
SV_ClearWorld();
2010-08-15 22:00:00 +02:00
// tell dlls about new level started
svgame.dllFuncs.pfnParmsNewLevel();
2010-03-24 22:00:00 +01:00
return true;
2007-06-21 22:00:00 +02:00
}
/*
==============
SV_InitGame
A brand new game has been started
==============
*/
2008-07-17 22:00:00 +02:00
void SV_InitGame( void )
2007-06-21 22:00:00 +02:00
{
2010-03-24 22:00:00 +01:00
edict_t *ent;
int i;
2007-09-17 22:00:00 +02:00
2007-11-21 22:00:00 +01:00
if( svs.initialized )
2007-06-21 22:00:00 +02:00
{
// cause any connected clients to reconnect
2011-04-08 22:00:00 +02:00
Q_strncpy( host.finalmsg, "Server restarted", MAX_STRING );
2007-11-21 22:00:00 +01:00
SV_Shutdown( true );
2007-06-21 22:00:00 +02:00
}
else
{
2008-12-26 22:00:00 +01:00
// init game after host error
if( !svgame.hInstance )
2010-03-25 22:00:00 +01:00
{
2010-10-21 22:00:00 +02:00
if( !SV_LoadProgs( GI->game_dll ))
2010-03-28 22:00:00 +02:00
{
2010-10-21 22:00:00 +02:00
MsgDev( D_ERROR, "SV_InitGame: can't initialize %s\n", GI->game_dll );
2010-03-25 22:00:00 +01:00
return; // can't loading
2010-03-28 22:00:00 +02:00
}
2010-03-25 22:00:00 +01:00
}
2009-11-03 22:00:00 +01:00
2007-06-21 22:00:00 +02:00
// make sure the client is down
2007-11-14 22:00:00 +01:00
CL_Drop();
2007-06-21 22:00:00 +02:00
}
2012-12-16 21:00:00 +01:00
// now apply latched commands
Cmd_ExecuteString( "latch\n", src_command );
2009-09-17 22:00:00 +02:00
if( Cvar_VariableValue( "coop" ) && Cvar_VariableValue ( "deathmatch" ) && Cvar_VariableValue( "teamplay" ))
2007-06-21 22:00:00 +02:00
{
2010-04-02 22:00:00 +02:00
MsgDev( D_WARN, "Deathmatch, Teamplay and Coop set, defaulting to Deathmatch\n");
2010-08-20 22:00:00 +02:00
Cvar_FullSet( "coop", "0", CVAR_LATCH );
Cvar_FullSet( "teamplay", "0", CVAR_LATCH );
2007-06-21 22:00:00 +02:00
}
// dedicated servers are can't be single player and are usually DM
// so unless they explicity set coop, force it to deathmatch
2008-07-06 22:00:00 +02:00
if( host.type == HOST_DEDICATED )
2007-06-21 22:00:00 +02:00
{
2012-12-16 21:00:00 +01:00
if( !Cvar_VariableValue( "coop" ) && !Cvar_VariableValue( "teamplay" ))
2010-08-20 22:00:00 +02:00
Cvar_FullSet( "deathmatch", "1", CVAR_LATCH );
2007-06-21 22:00:00 +02:00
}
// init clients
2009-01-09 22:00:00 +01:00
if( Cvar_VariableValue( "deathmatch" ) || Cvar_VariableValue( "teamplay" ))
2007-06-21 22:00:00 +02:00
{
2009-09-25 22:00:00 +02:00
if( sv_maxclients->integer <= 1 )
2011-01-03 22:00:00 +01:00
Cvar_FullSet( "maxplayers", "8", CVAR_LATCH );
2010-03-24 22:00:00 +01:00
else if( sv_maxclients->integer > MAX_CLIENTS )
2011-01-03 22:00:00 +01:00
Cvar_FullSet( "maxplayers", "32", CVAR_LATCH );
2007-06-21 22:00:00 +02:00
}
2008-07-31 22:00:00 +02:00
else if( Cvar_VariableValue( "coop" ))
2007-06-21 22:00:00 +02:00
{
2009-09-25 22:00:00 +02:00
if( sv_maxclients->integer <= 1 || sv_maxclients->integer > 4 )
2011-01-03 22:00:00 +01:00
Cvar_FullSet( "maxplayers", "4", CVAR_LATCH );
2007-06-21 22:00:00 +02:00
}
2008-07-31 22:00:00 +02:00
else
2007-06-21 22:00:00 +02:00
{
2008-07-31 22:00:00 +02:00
// non-deathmatch, non-coop is one player
2011-01-03 22:00:00 +01:00
Cvar_FullSet( "maxplayers", "1", CVAR_LATCH );
2007-06-21 22:00:00 +02:00
}
2010-04-02 22:00:00 +02:00
svgame.globals->maxClients = sv_maxclients->integer;
SV_UPDATE_BACKUP = ( svgame.globals->maxClients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
2009-09-25 22:00:00 +02:00
svs.clients = Z_Malloc( sizeof( sv_client_t ) * sv_maxclients->integer );
2010-10-15 22:00:00 +02:00
svs.num_client_entities = sv_maxclients->integer * SV_UPDATE_BACKUP * 64;
svs.packet_entities = Z_Malloc( sizeof( entity_state_t ) * svs.num_client_entities );
2009-09-24 22:00:00 +02:00
svs.baselines = Z_Malloc( sizeof( entity_state_t ) * GI->max_edicts );
2007-06-21 22:00:00 +02:00
2010-04-02 22:00:00 +02:00
// client frames will be allocated in SV_DirectConnect
2010-01-30 22:00:00 +01:00
// init network stuff
NET_Config(( sv_maxclients->integer > 1 ));
2009-01-09 22:00:00 +01:00
// copy gamemode into svgame.globals
2009-09-24 22:00:00 +02:00
svgame.globals->deathmatch = Cvar_VariableInteger( "deathmatch" );
svgame.globals->teamplay = Cvar_VariableInteger( "teamplay" );
svgame.globals->coop = Cvar_VariableInteger( "coop" );
2009-01-09 22:00:00 +01:00
2007-06-21 22:00:00 +02:00
// heartbeats will always be sent to the id master
2008-06-30 22:00:00 +02:00
svs.last_heartbeat = MAX_HEARTBEAT; // send immediately
2010-03-24 22:00:00 +01:00
// set client fields on player ents
for( i = 0; i < svgame.globals->maxClients; i++ )
{
// setup all the clients
ent = EDICT_NUM( i + 1 );
SV_InitEdict( ent );
svs.clients[i].edict = ent;
}
2010-03-25 22:00:00 +01:00
2012-04-25 22:00:00 +02:00
// get actual movevars
SV_UpdateMovevars( true );
2010-08-15 22:00:00 +02:00
svgame.numEntities = svgame.globals->maxClients + 1; // clients + world
2010-03-25 22:00:00 +01:00
svs.initialized = true;
2008-12-15 22:00:00 +01:00
}
2010-10-26 22:00:00 +02:00
qboolean SV_Active( void )
2008-12-15 22:00:00 +01:00
{
return svs.initialized;
2009-11-03 22:00:00 +01:00
}
2010-03-27 22:00:00 +01:00
void SV_ForceError( void )
{
2010-06-17 22:00:00 +02:00
// this is only for singleplayer testing
2010-03-27 22:00:00 +01:00
if( sv_maxclients->integer != 1 ) return;
sv.write_bad_message = true;
}
2010-07-22 22:00:00 +02:00
void SV_InitGameProgs( void )
{
2011-02-22 22:00:00 +01:00
if( svgame.hInstance ) return; // already loaded
2010-07-22 22:00:00 +02:00
// just try to initialize
2010-10-21 22:00:00 +02:00
SV_LoadProgs( GI->game_dll );
2010-07-22 22:00:00 +02:00
}
2011-03-13 22:00:00 +01:00
void SV_FreeGameProgs( void )
{
if( svs.initialized ) return; // server is active
2011-04-05 22:00:00 +02:00
// unload progs (free cvars and commands)
2011-03-13 22:00:00 +01:00
SV_UnloadProgs();
}
2010-10-26 22:00:00 +02:00
qboolean SV_NewGame( const char *mapName, qboolean loadGame )
2010-03-25 22:00:00 +01:00
{
2010-04-24 22:00:00 +02:00
if( !loadGame )
{
if( !SV_MapIsValid( mapName, GI->sp_entity, NULL ))
2011-04-05 22:00:00 +02:00
return false;
2012-02-08 21:00:00 +01:00
SV_ClearSaveDir ();
2012-08-07 22:00:00 +02:00
SV_Shutdown( true );
}
else
{
S_StopAllSounds ();
SV_DeactivateServer ();
2010-04-24 22:00:00 +02:00
}
2010-04-20 22:00:00 +02:00
sv.loadgame = loadGame;
2011-02-26 22:00:00 +01:00
sv.background = false;
2012-08-29 22:00:00 +02:00
sv.changelevel = false;
2010-03-25 22:00:00 +01:00
if( !SV_SpawnServer( mapName, NULL ))
return false;
SV_LevelInit( mapName, NULL, NULL, loadGame );
2010-06-17 22:00:00 +02:00
sv.loadgame = loadGame;
2010-03-25 22:00:00 +01:00
SV_ActivateServer();
if( sv.state != ss_active )
return false;
return true;
2007-09-16 22:00:00 +02:00
}