#include "server.h"
server_static_t svs; server_t sv;
int SV_FindIndex(char *name, int start, int max, bool create) {
int i;
if(!name || !name[0])
return 0;
for(i = 1; i < max && sv.configstrings[start + i][0]; i++)
if(!strcmp(sv.configstrings[start + i], name))
return i;
if(!create)
return 0;
if(i == max)
Com_Error(ERR_DROP, "*Index: overflow");
strncpy(sv.configstrings[start + i], name, sizeof(sv.configstrings[i]));
if(sv.state != ss_loading) { SZ_Clear(&sv.multicast);
MSG_WriteChar(&sv.multicast, svc_configstring);
MSG_WriteShort(&sv.multicast, start + i);
MSG_WriteString(&sv.multicast, name);
SV_Multicast(CMODEL_A, vec3_origin, MULTICAST_ALL_R);
}
return i;
}
int SV_ModelIndex(char *name) {
return SV_FindIndex(name, CS_MODELS + CMODEL_COUNT, MAX_MODELS - CMODEL_COUNT, true) + CMODEL_COUNT;
}
int SV_SoundIndex(char *name) { return SV_FindIndex(name, CS_SOUNDS, MAX_SOUNDS, true); }
int SV_ImageIndex(char *name) { return SV_FindIndex(name, CS_IMAGES, MAX_IMAGES, true); }
void SV_CreateBaseline(void) {
edict_t *svent;
int entnum;
for(entnum = 1; entnum < ge->num_edicts; entnum++) {
svent = EDICT_NUM(entnum);
if(!svent->inuse)
continue;
if(!svent->s.modelindex && !svent->s.sound && !svent->s.effects)
continue;
svent->s.number = entnum;
VectorCopy(svent->s.origin, svent->s.old_origin);
sv.baselines[entnum] = svent->s;
}
}
void SV_CheckForSavegame(void) {
char name[MAX_OSPATH];
FILE *f;
int i;
if(sv_noreload->value)
return;
if(Cvar_VariableValue("deathmatch"))
return;
Com_sprintf(name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
f = fopen(name, "rb");
if(!f)
return;
fclose(f);
SV_ClearWorld(CMODEL_A);
SV_ClearWorld(CMODEL_B);
SV_ClearWorld(CMODEL_C);
SV_ReadLevelFile();
if(!sv.loadgame) {
server_state_t previousState;
previousState = sv.state; sv.state = ss_loading; for(i = 0; i < 100; i++)
ge->RunFrame();
sv.state = previousState; }
}
void SV_SpawnServer(char *server, char *spawnpoint, server_state_t serverstate, bool attractloop, bool loadgame) {
int i;
unsigned checksum;
if(attractloop)
Cvar_Set("paused", "0");
Com_Printf("------- Server Initialization -------\n");
Com_DPrintf("SpawnServer: %s\n", server);
if(sv.demofile)
fclose(sv.demofile);
svs.spawncount++; sv.state = ss_dead;
Com_SetServerState(sv.state);
memset(&sv, 0, sizeof(sv));
svs.realtime = 0;
sv.loadgame = loadgame;
sv.attractloop = attractloop;
strcpy(sv.configstrings[CS_NAME], server);
if(Cvar_VariableValue("deathmatch")) {
sprintf(sv.configstrings[CS_AIRACCEL], sizeof(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);
for(i = 0; i < maxclients->value; i++) {
if(svs.clients[i].state > cs_connected)
svs.clients[i].state = cs_connected;
svs.clients[i].lastframe = -1;
}
sv.time = 1000;
strcpy(sv.name, server);
strcpy(sv.configstrings[CS_NAME], server);
if(serverstate != ss_game) {
sv.models[CMODEL_A][0] = CM_LoadMap(CMODEL_A, "", false, &checksum); } else {
Com_sprintf(sv.configstrings[CS_MODELS + 1], sizeof(sv.configstrings[CS_MODELS + 1]), "maps/%s.bsp", server);
sv.models[CMODEL_A][0] = CM_LoadMap(CMODEL_A, sv.configstrings[CS_MODELS + 1], false, &checksum);
}
Com_sprintf(sv.configstrings[CS_MODELS + 1], sizeof(sv.configstrings[CS_MODELS + 1]), "maps/%s.bsp;%i", server,
checksum);
SV_ClearWorld(CMODEL_A);
SV_ClearWorld(CMODEL_B);
SV_ClearWorld(CMODEL_C);
for(i = 1; i < CM_NumInlineModels(CMODEL_A); i++) {
char inline_name[6];
sprintf(inline_name, sizeof(inline_name), "*%i", i);
sv.models[CMODEL_A][i] = CM_InlineModel(CMODEL_A, inline_name);
}
sv.state = ss_loading;
Com_SetServerState(sv.state);
ge->SpawnEntities(CMODEL_A, sv.name, CM_EntityString(CMODEL_A), spawnpoint);
ge->RunFrame();
ge->RunFrame();
sv.state = serverstate;
Com_SetServerState(sv.state);
SV_CreateBaseline();
SV_CheckForSavegame();
Cvar_FullSet("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET);
Com_Printf("-------------------------------------\n");
}
void SV_InitGame(void) {
int i;
edict_t *ent;
char idmaster[32];
if(svs.initialized) {
SV_Shutdown("Server restarted\n", true);
} else {
CL_Drop();
SCR_BeginLoadingPlaque();
}
Cvar_GetLatchedVars();
svs.initialized = true;
if(Cvar_VariableValue("coop") && Cvar_VariableValue("deathmatch")) {
Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
Cvar_FullSet("coop", "0", CVAR_SERVERINFO | CVAR_LATCH);
}
if(dedicated->value) {
if(!Cvar_VariableValue("coop"))
Cvar_FullSet("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH);
}
if(Cvar_VariableValue("deathmatch")) {
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);
} else if(Cvar_VariableValue("coop")) {
if(maxclients->value <= 1 || maxclients->value > 4)
Cvar_FullSet("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
#ifdef COPYPROTECT
if(!sv.attractloop && !dedicated->value)
Sys_CopyProtect();
#endif
} else {
Cvar_FullSet("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
#ifdef COPYPROTECT
if(!sv.attractloop)
Sys_CopyProtect();
#endif
}
svs.spawncount = rand();
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);
NET_Config((maxclients->value > 1));
svs.last_heartbeat = -99999; Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER);
NET_StringToAdr(idmaster, &master_adr[0]);
SV_InitGameProgs();
for(i = 0; i < maxclients->value; i++) {
ent = EDICT_NUM(i + 1);
ent->s.number = i + 1;
svs.clients[i].edict = ent;
memset(&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
}
}
void SV_Map(bool attractloop, char *levelstring, bool loadgame) {
char level[MAX_QPATH];
char *ch;
int l;
char spawnpoint[MAX_QPATH];
sv.loadgame = loadgame;
sv.attractloop = attractloop;
if(sv.state == ss_dead && !sv.loadgame)
SV_InitGame();
strcpy(level, levelstring);
ch = strstr(level, "+");
if(ch) {
*ch = 0;
Cvar_Set("nextserver", va("gamemap \"%s\"", ch + 1));
} else
Cvar_Set("nextserver", "");
if(Cvar_VariableValue("coop") && !Q_stricmp(level, "victory.pcx"))
Cvar_Set("nextserver", "gamemap \"*base1\"");
ch = strstr(level, "$");
if(ch) {
*ch = 0;
strcpy(spawnpoint, ch + 1);
} else
spawnpoint[0] = 0;
if(level[0] == '*')
strcpy(level, level + 1);
l = strlen(level);
if(l > 4 && !strcmp(level + l - 4, ".cin")) {
SCR_BeginLoadingPlaque(); SV_BroadcastCommand("changing\n");
SV_SpawnServer(level, spawnpoint, ss_cinematic, attractloop, loadgame);
} else if(l > 4 && !strcmp(level + l - 4, ".dm2")) {
SCR_BeginLoadingPlaque(); SV_BroadcastCommand("changing\n");
SV_SpawnServer(level, spawnpoint, ss_demo, attractloop, loadgame);
} else if(l > 4 && !strcmp(level + l - 4, ".pcx")) {
SCR_BeginLoadingPlaque(); SV_BroadcastCommand("changing\n");
SV_SpawnServer(level, spawnpoint, ss_pic, attractloop, loadgame);
} else {
SCR_BeginLoadingPlaque(); SV_BroadcastCommand("changing\n");
SV_SendClientMessages();
SV_SpawnServer(level, spawnpoint, ss_game, attractloop, loadgame);
Cbuf_CopyToDefer();
}
SV_BroadcastCommand("reconnect\n");
}