696 lines · 15.0 KB · C
RawDownload
// host.c -- coordinates spawning and killing of local servers #include <stdlib.h>#include <stdarg.h>#include "quakedef.h"#include "r_shared.h"#include "r_local.h" /* * A server can allways be started, even if the system started out as a client * to a remote system. * A client can NOT be started if the system started as a dedicated server. * Memory is cleared / released when a server or client begins, not when they end. */ quakeparms_t host_parms; bool host_initialized; // true if into command execution double host_frametime;double host_time;double realtime; // without any filtering or boundingdouble oldrealtime; // last frame runint host_framecount; int host_hunklevel; int minimum_memory; client_t *host_client; // current client jmp_buf host_abortserver; uint8_t *host_basepal;uint8_t *host_colormap; cvar_t host_framerate = {"host_framerate","0"}; // set for slow motioncvar_t host_speeds = {"host_speeds","0"}; // set for running timescvar_t sys_ticrate = {"sys_ticrate","0.05"};cvar_t serverprofile = {"serverprofile","0"};cvar_t fraglimit = {"fraglimit","0",false,true};cvar_t timelimit = {"timelimit","0",false,true};cvar_t teamplay = {"teamplay","0",false,true};cvar_t samelevel = {"samelevel","0"};cvar_t noexit = {"noexit","0",false,true};cvar_t developer = {"developer","0"};cvar_t skill = {"skill","1"}; // 0 - 3cvar_t deathmatch = {"deathmatch","0"}; // 0, 1, or 2cvar_t coop = {"coop","0"}; // 0 or 1cvar_t pausable = {"pausable","1"};cvar_t temp1 = {"temp1","0"}; voidHost_EndGame(char *message, ...){	va_list argptr;	char string[1024]; 	va_start(argptr,message);	vsprintf(string,message,argptr);	va_end(argptr);	Con_DPrintf("Host_EndGame: %s\n",string); 	if (sv.active)		Host_ShutdownServer(false); 	if (cls.state == ca_dedicated)		Sys_Error("Host_EndGame: %s\n",string); // dedicated servers exit 	if (cls.demonum != -1)		CL_NextDemo();	else		CL_Disconnect(); 	longjmp(host_abortserver, 1);} voidHost_Error(char *error, ...){	va_list argptr;	char string[1024];	static bool inerror = false; 	if (inerror)		Sys_Error("Host_Error: recursively entered");	inerror = true; 	SCR_EndLoadingPlaque(); // reenable screen updates 	va_start(argptr,error);	vsprintf(string,error,argptr);	va_end(argptr);	Con_Printf("Host_Error: %s\n",string); 	if (sv.active)		Host_ShutdownServer(false); 	if (cls.state == ca_dedicated)		Sys_Error("Host_Error: %s\n",string); // dedicated servers exit 	CL_Disconnect();	cls.demonum = -1; 	inerror = false; 	longjmp(host_abortserver, 1);} static voidHost_FindMaxClients(void){	int i; 	svs.maxclients = 1; 	i = COM_CheckParm("-dedicated");	if (i) {		cls.state = ca_dedicated;		svs.maxclients = i == com_argc-1 ? 8 : strtol(com_argv[i+1], NULL, 0);	} else {		cls.state = ca_disconnected;	} 	i = COM_CheckParm("-listen");	if (i) {		if (cls.state == ca_dedicated)			Sys_Error("Only one of -dedicated or -listen can be specified");		if (i != com_argc-1)			svs.maxclients = atoi(com_argv[i+1]);		else			svs.maxclients = 8;	}	if (svs.maxclients < 1)		svs.maxclients = 8;	else if (svs.maxclients > MAX_SCOREBOARD)		svs.maxclients = MAX_SCOREBOARD; 	svs.maxclientslimit = svs.maxclients;	if (svs.maxclientslimit < 4)		svs.maxclientslimit = 4;	svs.clients = Hunk_AllocName(svs.maxclientslimit*sizeof(client_t), "clients"); 	if (svs.maxclients > 1)		Cvar_SetValue("deathmatch", 1.0);	else		Cvar_SetValue("deathmatch", 0.0);} static voidHost_InitLocal(void){	Host_InitCommands(); 	Cvar_RegisterVariable(&host_framerate);	Cvar_RegisterVariable(&host_speeds);	Cvar_RegisterVariable(&sys_ticrate);	Cvar_RegisterVariable(&serverprofile);	Cvar_RegisterVariable(&fraglimit);	Cvar_RegisterVariable(&timelimit);	Cvar_RegisterVariable(&teamplay);	Cvar_RegisterVariable(&samelevel);	Cvar_RegisterVariable(&noexit);	Cvar_RegisterVariable(&skill);	Cvar_RegisterVariable(&developer);	Cvar_RegisterVariable(&deathmatch);	Cvar_RegisterVariable(&coop);	Cvar_RegisterVariable(&pausable);	Cvar_RegisterVariable(&temp1); 	Host_FindMaxClients(); 	host_time = 1.0; // so a think at time 0 won't get called} static voidHost_WriteConfiguration(void){	FILE *f; 	// dedicated servers initialize the host but don't parse and set the	// config.cfg cvars	if (host_initialized && cls.state != ca_dedicated) {		f = fopen(va("%s/config.cfg",com_gamedir), "w");		if (!f) {			Con_Printf("Couldn't write config.cfg.\n");			return;		} 		Key_WriteBindings(f);		Cvar_WriteVariables(f); 		fclose(f);	}} voidSV_ClientPrintf(char *fmt, ...){	va_list argptr;	char string[1024]; 	va_start(argptr,fmt);	vsprintf(string, fmt,argptr);	va_end(argptr); 	MSG_WriteByte(&host_client->message, svc_print);	MSG_WriteString(&host_client->message, string);} voidSV_BroadcastPrintf(char *fmt, ...){	va_list argptr;	char string[1024];	int i; 	va_start(argptr,fmt);	vsprintf(string, fmt,argptr);	va_end(argptr); 	for (i = 0 ; i < svs.maxclients; i++) {		if (svs.clients[i].active && svs.clients[i].spawned) {			MSG_WriteByte(&svs.clients[i].message, svc_print);			MSG_WriteString(&svs.clients[i].message, string);		}	}} voidHost_ClientCommands(char *fmt, ...){	va_list argptr;	char string[1024]; 	va_start(argptr,fmt);	vsprintf(string, fmt,argptr);	va_end(argptr); 	MSG_WriteByte(&host_client->message, svc_stufftext);	MSG_WriteString(&host_client->message, string);} voidSV_DropClient(bool crash){	client_t *client;	int saveSelf;	int i; 	if (!crash) {		// send any final messages(don't check for errors)		if (NET_CanSendMessage(host_client->netconnection)) {			MSG_WriteByte(&host_client->message, svc_disconnect);			NET_SendMessage(host_client->netconnection, &host_client->message);		} 		if (host_client->edict && host_client->spawned) {			// call the prog function for removing a client			// this will set the body to a dead frame, among other things			saveSelf = pr_global_struct->self;			pr_global_struct->self = EDICT_TO_PROG(host_client->edict);			PR_ExecuteProgram(pr_global_struct->ClientDisconnect);			pr_global_struct->self = saveSelf;		} 		Sys_Printf("Client %s removed\n",host_client->name);	} 	// break the net connection	NET_Close(host_client->netconnection);	host_client->netconnection = NULL; 	// free the client(the body stays around)	host_client->active = false;	host_client->name[0] = 0;	host_client->old_frags = -999999;	net_activeconnections--; 	// send notification to all clients	for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++) {		if (!client->active)			continue;		MSG_WriteByte(&client->message, svc_updatename);		MSG_WriteByte(&client->message, host_client - svs.clients);		MSG_WriteString(&client->message, "");		MSG_WriteByte(&client->message, svc_updatefrags);		MSG_WriteByte(&client->message, host_client - svs.clients);		MSG_WriteShort(&client->message, 0);		MSG_WriteByte(&client->message, svc_updatecolors);		MSG_WriteByte(&client->message, host_client - svs.clients);		MSG_WriteByte(&client->message, 0);	}} voidHost_ShutdownServer(bool crash){	int i;	int count;	sizebuf_t buf;	uint8_t message[4];	double start; 	if (!sv.active)		return; 	sv.active = false; // stop all client sounds immediately	if (cls.state == ca_connected)		CL_Disconnect(); 	// flush any pending messages - like the score!!!	start = Sys_FloatTime();	do {		count = 0;		for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) {			if (host_client->active && host_client->message.cursize) {				if (NET_CanSendMessage(host_client->netconnection)) {					NET_SendMessage(host_client->netconnection, &host_client->message);					SZ_Clear(&host_client->message);				} else {					NET_GetMessage(host_client->netconnection);					count++;				}			}		}		if (Sys_FloatTime() - start > 3.0)			break;	} while (count); 	// make sure all the clients know we're disconnecting	buf.data = message;	buf.maxsize = 4;	buf.cursize = 0;	MSG_WriteByte(&buf, svc_disconnect);	count = NET_SendToAll(&buf, 5);	if (count)		Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count); 	for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) {		if (host_client->active)			SV_DropClient(crash);	} 	//	// clear structures	//	memset(&sv, 0, sizeof(sv));	memset(svs.clients, 0, svs.maxclientslimit*sizeof(client_t));} voidHost_ClearMemory(void){	Con_DPrintf("Clearing memory\n");	D_FlushCaches();	Mod_ClearAll();	if (host_hunklevel)		Hunk_FreeToLowMark(host_hunklevel); 	cls.signon = 0;	memset(&sv, 0, sizeof(sv));	memset(&cl, 0, sizeof(cl));} static boolHost_FilterTime(float time){	realtime += time; 	if (!cls.timedemo && realtime - oldrealtime < 1.0/72.0)		return false; // framerate is too high 	host_frametime = realtime - oldrealtime;	oldrealtime = realtime; 	if (host_framerate.value > 0) {		host_frametime = host_framerate.value;	} else {		// don't allow really long or short frames		if (host_frametime > 0.1)			host_frametime = 0.1;		if (host_frametime < 0.001)			host_frametime = 0.001;	} 	return true;} voidHost_GetConsoleCommands(void){	char *cmd; 	while (1) {		cmd = Sys_ConsoleInput();		if (!cmd)			break;		Cbuf_AddText(cmd);	}} voidHost_ServerFrame(void){	// run the world state	pr_global_struct->frametime = host_frametime; 	// set the time and clear the general datagram	SV_ClearDatagram(); 	// check for new clients	SV_CheckForNewClients(); 	// read client messages	SV_RunClients(); 	// move things around and think	// always pause in single player if in console or menus	if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )		SV_Physics(); 	// send all messages to the clients	SV_SendClientMessages();} static void_Host_Frame(float time){	static double time1 = 0;	static double time2 = 0;	static double time3 = 0;	int pass1, pass2, pass3; 	if (setjmp(host_abortserver) )		return; // something bad happened, or the server disconnected 	// keep the random time dependent	rand(); 	// decide the simulation time	if (!Host_FilterTime(time))		return; // don't run too fast, or packets will flood out 	// get new key events	Sys_SendKeyEvents(); 	// allow mice or other external controllers to add commands	IN_Commands(); 	// process console commands	Cbuf_Execute(); 	NET_Poll(); 	// if running the server locally, make intentions now	if (sv.active)		CL_SendCmd(); 	// server operations 	// check for commands typed to the host	Host_GetConsoleCommands(); 	if (sv.active)		Host_ServerFrame(); 	// client operations 	// if running the server remotely, send intentions now after	// the incoming messages have been read	if (!sv.active)		CL_SendCmd(); 	host_time += host_frametime; 	// fetch results from server	if (cls.state == ca_connected)		CL_ReadFromServer(); 	// update video	if (host_speeds.value)		time1 = Sys_FloatTime(); 	SCR_UpdateScreen(); 	if (host_speeds.value)		time2 = Sys_FloatTime(); 	if (cls.signon == SIGNONS) {		S_Update(r_origin, vpn, vright, vup);		CL_DecayLights();	} else {		S_Update(vec3_origin, vec3_origin, vec3_origin, vec3_origin);	} 	CDAudio_Update(); 

Lines 1–500 of 696.

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