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"
|
|
|
|
|
2007-10-03 22:00:00 +02:00
|
|
|
server_static_t svs; // persistant server info
|
|
|
|
server_t sv; // local server
|
2007-09-16 22:00:00 +02:00
|
|
|
|
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
|
|
|
{
|
2007-09-28 22:00:00 +02:00
|
|
|
int i = 0;
|
2007-06-21 22:00:00 +02:00
|
|
|
|
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++)
|
2008-01-13 22:00:00 +01:00
|
|
|
if(!com.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)
|
|
|
|
{
|
2007-09-28 22:00:00 +02:00
|
|
|
MsgWarn ("SV_FindIndex: %d out of 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-09-28 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
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-09-29 22:00:00 +02:00
|
|
|
int SV_DecalIndex (const char *name)
|
|
|
|
{
|
|
|
|
return SV_FindIndex (name, CS_DECALS, MAX_DECALS, true);
|
|
|
|
}
|
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
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
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;
|
2007-10-03 22:00:00 +02:00
|
|
|
if (!svent->progs.sv->modelindex && !svent->progs.sv->noise3 && !svent->progs.sv->effects)
|
2007-09-05 22:00:00 +02:00
|
|
|
continue;
|
2007-09-18 22:00:00 +02:00
|
|
|
svent->priv.sv->serialnumber = 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-18 22:00:00 +02:00
|
|
|
VectorCopy (svent->progs.sv->origin, svent->progs.sv->old_origin);
|
|
|
|
SV_UpdateEntityState( svent );
|
|
|
|
|
2007-09-16 22:00:00 +02:00
|
|
|
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-11-18 22:00:00 +01:00
|
|
|
sv.loadgame = true; // predicting state
|
2007-06-21 22:00:00 +02:00
|
|
|
|
2007-11-18 22:00:00 +01:00
|
|
|
if(sv_noreload->value) sv.loadgame = false;
|
|
|
|
if(Cvar_VariableValue("deathmatch")) sv.loadgame = false;
|
|
|
|
if(!savename) sv.loadgame = false;
|
|
|
|
if(!FS_FileExists(va("save/%s", savename )))
|
|
|
|
sv.loadgame = false;
|
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-11-17 22:00:00 +01:00
|
|
|
void SV_SpawnServer (char *server, char *savename, sv_state_t serverstate )
|
2007-06-21 22:00:00 +02:00
|
|
|
{
|
2007-09-06 22:00:00 +02:00
|
|
|
uint i, checksum;
|
2007-06-21 22:00:00 +02:00
|
|
|
|
2008-05-20 22:00:00 +02:00
|
|
|
if( serverstate == ss_cinematic ) Cvar_Set ("paused", "0");
|
2007-06-21 22:00:00 +02:00
|
|
|
|
2007-11-08 22:00:00 +01:00
|
|
|
Msg("SpawnServer [%s]\n", server );
|
2007-06-21 22:00:00 +02:00
|
|
|
|
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;
|
2007-11-17 22:00:00 +01:00
|
|
|
Host_SetServerState(sv.state);
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
// wipe the entire per-level structure
|
|
|
|
memset (&sv, 0, sizeof(sv));
|
|
|
|
svs.realtime = 0;
|
|
|
|
|
|
|
|
// save name for levels that don't set message
|
|
|
|
strcpy (sv.configstrings[CS_NAME], server);
|
2008-05-24 22:00:00 +02:00
|
|
|
if( Cvar_VariableValue ("deathmatch") )
|
|
|
|
com.sprintf( sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value );
|
|
|
|
else com.strcpy( sv.configstrings[CS_AIRACCEL], "0" );
|
2007-06-21 22:00:00 +02:00
|
|
|
|
2007-11-17 22:00:00 +01:00
|
|
|
SZ_Init(&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf));
|
2008-05-24 22:00:00 +02:00
|
|
|
com.strcpy( sv.name, server );
|
2007-06-21 22:00:00 +02:00
|
|
|
|
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-17 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
|
|
|
|
2007-11-08 22:00:00 +01:00
|
|
|
strcpy(sv.name, server);
|
|
|
|
FS_FileBase(server, sv.configstrings[CS_NAME]);
|
2007-06-21 22:00:00 +02:00
|
|
|
|
2008-05-22 22:00:00 +02:00
|
|
|
if (serverstate != ss_active)
|
2007-06-21 22:00:00 +02:00
|
|
|
{
|
2008-01-17 22:00:00 +01:00
|
|
|
sv.models[1] = pe->BeginRegistration( "", false, &checksum); // no real map
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-01-13 22:00:00 +01:00
|
|
|
sprintf(sv.configstrings[CS_MODELS+1], "maps/%s", server);
|
2008-01-15 22:00:00 +01:00
|
|
|
sv.models[1] = pe->BeginRegistration(sv.configstrings[CS_MODELS+1], false, &checksum);
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
2008-01-13 22:00:00 +01:00
|
|
|
sprintf(sv.configstrings[CS_MAPCHECKSUM], "%i", checksum);
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
// clear physics interaction links
|
2008-01-13 22:00:00 +01:00
|
|
|
SV_ClearWorld();
|
2007-06-21 22:00:00 +02:00
|
|
|
|
2008-01-15 22:00:00 +01:00
|
|
|
for (i = 1; i < pe->NumBmodels(); i++)
|
2007-06-21 22:00:00 +02:00
|
|
|
{
|
2008-01-13 22:00:00 +01:00
|
|
|
sprintf( sv.configstrings[CS_MODELS+1+i], "*%i", i );
|
2008-01-15 22:00:00 +01:00
|
|
|
sv.models[i+1] = pe->RegisterModel(sv.configstrings[CS_MODELS+1+i] );
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
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;
|
2008-01-13 22:00:00 +01:00
|
|
|
Host_SetServerState( sv.state );
|
2007-09-02 22:00:00 +02:00
|
|
|
|
2007-11-18 22:00:00 +01:00
|
|
|
// check for a savegame
|
|
|
|
SV_CheckForSavegame( savename );
|
|
|
|
|
2008-05-22 22:00:00 +02:00
|
|
|
if( serverstate == ss_active )
|
2008-05-18 22:00:00 +02:00
|
|
|
{
|
2008-05-20 22:00:00 +02:00
|
|
|
// ignore ents for cinematic servers
|
2008-05-18 22:00:00 +02:00
|
|
|
if(sv.loadgame) SV_ReadLevelFile( savename );
|
|
|
|
else SV_SpawnEntities ( sv.name, pe->GetEntityString());
|
|
|
|
}
|
2007-09-06 22:00:00 +02:00
|
|
|
|
|
|
|
// run two frames to allow everything to settle
|
2007-11-18 22:00:00 +01:00
|
|
|
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;
|
2007-11-14 22:00:00 +01:00
|
|
|
Host_SetServerState (sv.state);
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
// create a baseline for more efficient communications
|
|
|
|
SV_CreateBaseline ();
|
|
|
|
|
|
|
|
// set serverinfo variable
|
2007-11-29 22:00:00 +01:00
|
|
|
Cvar_FullSet("mapname", sv.name, CVAR_SERVERINFO | CVAR_INIT);
|
2008-01-15 22:00:00 +01:00
|
|
|
pe->EndRegistration(); // free unused models
|
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-17 22:00:00 +02:00
|
|
|
char i, idmaster[32];
|
|
|
|
edict_t *ent;
|
|
|
|
|
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
|
2007-11-30 22:00:00 +01:00
|
|
|
com.strncpy( host.finalmsg, "Server restarted\n", MAX_STRING );
|
2007-11-21 22:00:00 +01:00
|
|
|
SV_Shutdown( true );
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// make sure the client is down
|
2007-11-14 22:00:00 +01:00
|
|
|
CL_Drop();
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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-11-04 22:00:00 +01:00
|
|
|
svs.clients = Z_Malloc (sizeof(client_state_t)*maxclients->value);
|
2007-09-06 22:00:00 +02:00
|
|
|
svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
|
|
|
|
svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);
|
2007-09-17 22:00:00 +02:00
|
|
|
svs.gclients = Z_Malloc(sizeof(gclient_t)*maxclients->value);
|
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
|
2008-05-20 22:00:00 +02:00
|
|
|
SV_InitServerProgs();
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
|
|
SV_VM_Begin();
|
|
|
|
|
|
|
|
for (i = 0; i < maxclients->value; i++)
|
|
|
|
{
|
|
|
|
ent = PRVM_EDICT_NUM(i + 1);
|
2007-09-18 22:00:00 +02:00
|
|
|
ent->priv.sv->serialnumber = i + 1;
|
2007-09-17 22:00:00 +02:00
|
|
|
svs.clients[i].edict = ent;
|
|
|
|
memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
|
|
|
|
}
|
|
|
|
|
|
|
|
SV_VM_End();
|
2007-09-16 22:00:00 +02:00
|
|
|
}
|