438 lines · 9.9 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <stdio.h>#include "dat.h"#include "fns.h" server_static_t	svs;				// persistant server infoserver_t		sv;					// local server /*================SV_FindIndex ================*/int SV_FindIndex (char *name, int start, int max, qboolean 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)	{	// send the update to everyone		SZ_Clear (&sv.multicast);		MSG_WriteChar (&sv.multicast, svc_configstring);		MSG_WriteShort (&sv.multicast, start+i);		MSG_WriteString (&sv.multicast, name);		SV_Multicast (vec3_origin, MULTICAST_ALL_R);	} 	return i;}  int SV_ModelIndex (char *name){	return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true);} 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);}  /*================SV_CreateBaseline Entity baselines are used to compress the update messagesto the clients -- only the fields that differ from thebaseline will be transmitted================*/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; 		//		// take current state as baseline		//		VectorCopy (svent->s.origin, svent->s.old_origin);		sv.baselines[entnum] = svent->s;	}}  /*=================SV_CheckForSavegame=================*/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;		// no savegame 	fclose (f); 	SV_ClearWorld (); 	// get configstrings and areaportals	SV_ReadLevelFile (); 	if (!sv.loadgame)	{	// coming back to a level after being in a different		// 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		for (i=0 ; i<100 ; i++)			ge->RunFrame (); 		sv.state = previousState;				// PGM	}}  /*================SV_SpawnServer Change the server to a new map, taking all connectedclients along with it. ================*/void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean 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++;		// any partially connected client will be							// restarted	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); 	// leave slots at start for clients only	for (i=0 ; i<maxclients->value ; i++)	{		// needs to reconnect		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[1] = CM_LoadMap ("", false, &checksum);	// no real map	}	else	{		Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]),			"maps/%s.bsp", server);		sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum);	}	Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]),		"%i", checksum); 	//	// clear physics interaction links	//	SV_ClearWorld ();		for (i=1 ; i< CM_NumInlineModels() ; i++)	{		Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]),			"*%i", i);		sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]);	} 	//	// spawn the rest of the entities on the map	//	 	// precache and static commands can be issued during	// map initialization	sv.state = ss_loading;	Com_SetServerState (sv.state); 	// load and spawn all other entities	ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint ); 	// run two frames to allow everything to settle	ge->RunFrame ();	ge->RunFrame (); 	// all precaches are complete	sv.state = serverstate;	Com_SetServerState (sv.state);		// create a baseline for more efficient communications	SV_CreateBaseline (); 	// check for a savegame	SV_CheckForSavegame (); 	// set serverinfo variable	Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET); 	Com_Printf ("-------------------------------------\n");} /*==============SV_InitGame A brand new game has been started==============*/void SV_InitGame (void){	int		i;	edict_t	*ent; 	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"))	{		Com_Printf("Deathmatch and Coop both set, disabling Coop\n");		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	if (dedicated->value)	{		if (!Cvar_VariableValue ("coop"))			Cvar_FullSet ("deathmatch", "1",  CVAR_SERVERINFO | CVAR_LATCH);	} 	// init clients	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);	}	else	// non-deathmatch, non-coop is one player	{		Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);	} 	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); 	// init network stuff	NET_Config ( (maxclients->value > 1) ); 	// heartbeats will always be sent to the id master	svs.last_heartbeat = -99999;		// send immediately 	// init game	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));	}}  /*======================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 fileNextserver is used to allow a cinematic to play, then proceed toanother level: 	map tram.cin+jail_e3======================*/void SV_Map (qboolean attractloop, char *levelstring, qboolean 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 ();	// 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;			Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1));	}	else		Cvar_Set ("nextserver", ""); 	//ZOID special hack for end game screen in coop mode	if (Cvar_VariableValue ("coop") && !cistrcmp(level, "victory.pcx"))		Cvar_Set ("nextserver", "gamemap \"*base1\""); 	// if there is a $, use the remainder as a spawnpoint	ch = strstr(level, "$");	if (ch)	{		*ch = 0;		strcpy (spawnpoint, ch+1);	}	else		spawnpoint[0] = 0; 	// skip the end-of-unit flag if necessary	if (level[0] == '*')		strcpy (level, level+1); 	l = strlen(level);	if (l > 4 && !strcmp (level+l-4, ".cin") )	{		SCR_BeginLoadingPlaque ();			// for local system		SV_BroadcastCommand ("changing\n");		SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame);	}	else if (l > 4 && !strcmp (level+l-4, ".dm2") )	{		SCR_BeginLoadingPlaque ();			// for local system		SV_BroadcastCommand ("changing\n");		SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame);	}	else if (l > 4 && !strcmp (level+l-4, ".pcx") )	{		SCR_BeginLoadingPlaque ();			// for local system		SV_BroadcastCommand ("changing\n");		SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame);	}	else	{		SCR_BeginLoadingPlaque ();			// for local system		SV_BroadcastCommand ("changing\n");		SV_SendClientMessages ();		SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame);		Cbuf_CopyToDefer ();	} 	SV_BroadcastCommand ("reconnect\n");}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t