mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2024-11-10 15:31:39 +00:00
cebef615e5
Before, "gamekey" was the special case, now "textmode" is. We are now more precise about when we activate "textmode", e.g. we only do this when the console, messagemode, or a textfield in the menu are active. The trigger for doing this was this line on the "SDL_StartTextInput" page of the SDL2 wiki: "On some platforms using this function activates the screen keyboard.". Although we currenly support no such platform, it's good te be prepared, and what we do now is more correct anyway. git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1066 af15c1b1-3010-417e-b628-4374ebc0bcbd
938 lines
21 KiB
C
938 lines
21 KiB
C
/*
|
|
Copyright (C) 1996-2001 Id Software, Inc.
|
|
Copyright (C) 2002-2009 John Fitzgibbons and others
|
|
Copyright (C) 2007-2008 Kristian Duske
|
|
Copyright (C) 2010-2014 QuakeSpasm developers
|
|
|
|
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.
|
|
|
|
*/
|
|
// host.c -- coordinates spawning and killing of local servers
|
|
|
|
#include "quakedef.h"
|
|
#include "bgmusic.h"
|
|
#include <setjmp.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;
|
|
|
|
qboolean host_initialized; // true if into command execution
|
|
|
|
double host_frametime;
|
|
double realtime; // without any filtering or bounding
|
|
double oldrealtime; // last frame run
|
|
|
|
int host_framecount;
|
|
|
|
int host_hunklevel;
|
|
|
|
int minimum_memory;
|
|
|
|
client_t *host_client; // current client
|
|
|
|
jmp_buf host_abortserver;
|
|
|
|
byte *host_colormap;
|
|
|
|
cvar_t host_framerate = {"host_framerate","0",CVAR_NONE}; // set for slow motion
|
|
cvar_t host_speeds = {"host_speeds","0",CVAR_NONE}; // set for running times
|
|
cvar_t host_maxfps = {"host_maxfps", "72", CVAR_ARCHIVE}; //johnfitz
|
|
cvar_t host_timescale = {"host_timescale", "0", CVAR_NONE}; //johnfitz
|
|
cvar_t max_edicts = {"max_edicts", "2048", CVAR_ARCHIVE}; //johnfitz
|
|
|
|
cvar_t sys_ticrate = {"sys_ticrate","0.05",CVAR_NONE}; // dedicated server
|
|
cvar_t serverprofile = {"serverprofile","0",CVAR_NONE};
|
|
|
|
cvar_t fraglimit = {"fraglimit","0",CVAR_NOTIFY|CVAR_SERVERINFO};
|
|
cvar_t timelimit = {"timelimit","0",CVAR_NOTIFY|CVAR_SERVERINFO};
|
|
cvar_t teamplay = {"teamplay","0",CVAR_NOTIFY|CVAR_SERVERINFO};
|
|
cvar_t samelevel = {"samelevel","0",CVAR_NONE};
|
|
cvar_t noexit = {"noexit","0",CVAR_NOTIFY|CVAR_SERVERINFO};
|
|
cvar_t skill = {"skill","1",CVAR_NONE}; // 0 - 3
|
|
cvar_t deathmatch = {"deathmatch","0",CVAR_NONE}; // 0, 1, or 2
|
|
cvar_t coop = {"coop","0",CVAR_NONE}; // 0 or 1
|
|
|
|
cvar_t pausable = {"pausable","1",CVAR_NONE};
|
|
|
|
cvar_t developer = {"developer","0",CVAR_NONE};
|
|
|
|
cvar_t temp1 = {"temp1","0",CVAR_NONE};
|
|
|
|
cvar_t devstats = {"devstats","0",CVAR_NONE}; //johnfitz -- track developer statistics that vary every frame
|
|
|
|
devstats_t dev_stats, dev_peakstats;
|
|
overflowtimes_t dev_overflows; //this stores the last time overflow messages were displayed, not the last time overflows occured
|
|
|
|
/*
|
|
================
|
|
Max_Edicts_f -- johnfitz
|
|
================
|
|
*/
|
|
static void Max_Edicts_f (cvar_t *var)
|
|
{
|
|
//TODO: clamp it here?
|
|
if (cls.state == ca_connected || sv.active)
|
|
Con_Printf ("Changes to max_edicts will not take effect until the next time a map is loaded.\n");
|
|
}
|
|
|
|
/*
|
|
================
|
|
Host_EndGame
|
|
================
|
|
*/
|
|
void Host_EndGame (const char *message, ...)
|
|
{
|
|
va_list argptr;
|
|
char string[1024];
|
|
|
|
va_start (argptr,message);
|
|
q_vsnprintf (string, sizeof(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);
|
|
}
|
|
|
|
/*
|
|
================
|
|
Host_Error
|
|
|
|
This shuts down both the client and server
|
|
================
|
|
*/
|
|
void Host_Error (const char *error, ...)
|
|
{
|
|
va_list argptr;
|
|
char string[1024];
|
|
static qboolean inerror = false;
|
|
|
|
if (inerror)
|
|
Sys_Error ("Host_Error: recursively entered");
|
|
inerror = true;
|
|
|
|
SCR_EndLoadingPlaque (); // reenable screen updates
|
|
|
|
va_start (argptr,error);
|
|
q_vsnprintf (string, sizeof(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;
|
|
cl.intermission = 0; //johnfitz -- for errors during intermissions (changelevel with no map found, etc.)
|
|
|
|
inerror = false;
|
|
|
|
longjmp (host_abortserver, 1);
|
|
}
|
|
|
|
/*
|
|
================
|
|
Host_FindMaxClients
|
|
================
|
|
*/
|
|
void Host_FindMaxClients (void)
|
|
{
|
|
int i;
|
|
|
|
svs.maxclients = 1;
|
|
|
|
i = COM_CheckParm ("-dedicated");
|
|
if (i)
|
|
{
|
|
cls.state = ca_dedicated;
|
|
if (i != (com_argc - 1))
|
|
{
|
|
svs.maxclients = Q_atoi (com_argv[i+1]);
|
|
}
|
|
else
|
|
svs.maxclients = 8;
|
|
}
|
|
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 = Q_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 = (struct client_s *) Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients");
|
|
|
|
if (svs.maxclients > 1)
|
|
Cvar_SetQuick (&deathmatch, "1");
|
|
else
|
|
Cvar_SetQuick (&deathmatch, "0");
|
|
}
|
|
|
|
void Host_Version_f (void)
|
|
{
|
|
Con_Printf ("Quake Version %1.2f\n", VERSION);
|
|
Con_Printf ("QuakeSpasm Version %1.2f.%d\n", QUAKESPASM_VERSION, QUAKESPASM_VER_PATCH);
|
|
Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
|
|
}
|
|
|
|
/* cvar callback functions : */
|
|
void Host_Callback_Notify (cvar_t *var)
|
|
{
|
|
if (sv.active)
|
|
SV_BroadcastPrintf ("\"%s\" changed to \"%s\"\n", var->name, var->string);
|
|
}
|
|
|
|
/*
|
|
=======================
|
|
Host_InitLocal
|
|
======================
|
|
*/
|
|
void Host_InitLocal (void)
|
|
{
|
|
Cmd_AddCommand ("version", Host_Version_f);
|
|
|
|
Host_InitCommands ();
|
|
|
|
Cvar_RegisterVariable (&host_framerate);
|
|
Cvar_RegisterVariable (&host_speeds);
|
|
Cvar_RegisterVariable (&host_maxfps); //johnfitz
|
|
Cvar_RegisterVariable (&host_timescale); //johnfitz
|
|
|
|
Cvar_RegisterVariable (&max_edicts); //johnfitz
|
|
Cvar_SetCallback (&max_edicts, Max_Edicts_f);
|
|
Cvar_RegisterVariable (&devstats); //johnfitz
|
|
|
|
Cvar_RegisterVariable (&sys_ticrate);
|
|
Cvar_RegisterVariable (&sys_throttle);
|
|
Cvar_RegisterVariable (&serverprofile);
|
|
|
|
Cvar_RegisterVariable (&fraglimit);
|
|
Cvar_RegisterVariable (&timelimit);
|
|
Cvar_RegisterVariable (&teamplay);
|
|
Cvar_SetCallback (&fraglimit, Host_Callback_Notify);
|
|
Cvar_SetCallback (&timelimit, Host_Callback_Notify);
|
|
Cvar_SetCallback (&teamplay, Host_Callback_Notify);
|
|
Cvar_RegisterVariable (&samelevel);
|
|
Cvar_RegisterVariable (&noexit);
|
|
Cvar_SetCallback (&noexit, Host_Callback_Notify);
|
|
Cvar_RegisterVariable (&skill);
|
|
Cvar_RegisterVariable (&developer);
|
|
Cvar_RegisterVariable (&coop);
|
|
Cvar_RegisterVariable (&deathmatch);
|
|
|
|
Cvar_RegisterVariable (&pausable);
|
|
|
|
Cvar_RegisterVariable (&temp1);
|
|
|
|
Host_FindMaxClients ();
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
Host_WriteConfiguration
|
|
|
|
Writes key bindings and archived cvars to config.cfg
|
|
===============
|
|
*/
|
|
void Host_WriteConfiguration (void)
|
|
{
|
|
FILE *f;
|
|
|
|
// dedicated servers initialize the host but don't parse and set the
|
|
// config.cfg cvars
|
|
if (host_initialized & !isDedicated)
|
|
{
|
|
f = fopen (va("%s/config.cfg", com_gamedir), "w");
|
|
if (!f)
|
|
{
|
|
Con_Printf ("Couldn't write config.cfg.\n");
|
|
return;
|
|
}
|
|
|
|
VID_SyncCvars (); //johnfitz -- write actual current mode to config file, in case cvars were messed with
|
|
|
|
Key_WriteBindings (f);
|
|
Cvar_WriteVariables (f);
|
|
|
|
//johnfitz -- extra commands to preserve state
|
|
fprintf (f, "vid_restart\n");
|
|
if (in_mlook.state & 1) fprintf (f, "+mlook\n");
|
|
//johnfitz
|
|
|
|
fclose (f);
|
|
|
|
//johnfitz -- also save fitzquake.rc
|
|
#if 0
|
|
f = fopen (va("%s/fitzquake.rc", GAMENAME), "w"); //always save in id1
|
|
if (!f)
|
|
{
|
|
Con_Printf ("Couldn't write fitzquake.rc.\n");
|
|
return;
|
|
}
|
|
|
|
Cvar_WriteVariables (f);
|
|
fprintf (f, "vid_restart\n");
|
|
if (in_mlook.state & 1) fprintf (f, "+mlook\n");
|
|
|
|
fclose (f);
|
|
#endif
|
|
//johnfitz
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
SV_ClientPrintf
|
|
|
|
Sends text across to be displayed
|
|
FIXME: make this just a stuffed echo?
|
|
=================
|
|
*/
|
|
void SV_ClientPrintf (const char *fmt, ...)
|
|
{
|
|
va_list argptr;
|
|
char string[1024];
|
|
|
|
va_start (argptr,fmt);
|
|
q_vsnprintf (string, sizeof(string), fmt,argptr);
|
|
va_end (argptr);
|
|
|
|
MSG_WriteByte (&host_client->message, svc_print);
|
|
MSG_WriteString (&host_client->message, string);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
SV_BroadcastPrintf
|
|
|
|
Sends text to all active clients
|
|
=================
|
|
*/
|
|
void SV_BroadcastPrintf (const char *fmt, ...)
|
|
{
|
|
va_list argptr;
|
|
char string[1024];
|
|
int i;
|
|
|
|
va_start (argptr,fmt);
|
|
q_vsnprintf (string, sizeof(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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Host_ClientCommands
|
|
|
|
Send text over to the client to be executed
|
|
=================
|
|
*/
|
|
void Host_ClientCommands (const char *fmt, ...)
|
|
{
|
|
va_list argptr;
|
|
char string[1024];
|
|
|
|
va_start (argptr,fmt);
|
|
q_vsnprintf (string, sizeof(string), fmt, argptr);
|
|
va_end (argptr);
|
|
|
|
MSG_WriteByte (&host_client->message, svc_stufftext);
|
|
MSG_WriteString (&host_client->message, string);
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
SV_DropClient
|
|
|
|
Called when the player is getting totally kicked off the host
|
|
if (crash = true), don't bother sending signofs
|
|
=====================
|
|
*/
|
|
void SV_DropClient (qboolean crash)
|
|
{
|
|
int saveSelf;
|
|
int i;
|
|
client_t *client;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
Host_ShutdownServer
|
|
|
|
This only happens at the end of a game, not between levels
|
|
==================
|
|
*/
|
|
void Host_ShutdownServer(qboolean crash)
|
|
{
|
|
int i;
|
|
int count;
|
|
sizebuf_t buf;
|
|
byte 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_DoubleTime();
|
|
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_DoubleTime() - 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.0);
|
|
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)); // ServerSpawn already do this by Host_ClearMemory
|
|
memset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t));
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
Host_ClearMemory
|
|
|
|
This clears all the memory used by both the client and server, but does
|
|
not reinitialize anything.
|
|
================
|
|
*/
|
|
void Host_ClearMemory (void)
|
|
{
|
|
Con_DPrintf ("Clearing memory\n");
|
|
D_FlushCaches ();
|
|
Mod_ClearAll ();
|
|
/* host_hunklevel MUST be set at this point */
|
|
Hunk_FreeToLowMark (host_hunklevel);
|
|
cls.signon = 0;
|
|
memset (&sv, 0, sizeof(sv));
|
|
memset (&cl, 0, sizeof(cl));
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
//
|
|
// Host Frame
|
|
//
|
|
//==============================================================================
|
|
|
|
/*
|
|
===================
|
|
Host_FilterTime
|
|
|
|
Returns false if the time is too short to run a frame
|
|
===================
|
|
*/
|
|
qboolean Host_FilterTime (float time)
|
|
{
|
|
float maxfps; //johnfitz
|
|
|
|
realtime += time;
|
|
|
|
//johnfitz -- max fps cvar
|
|
maxfps = CLAMP (10.0, host_maxfps.value, 1000.0);
|
|
if (!cls.timedemo && realtime - oldrealtime < 1.0/maxfps)
|
|
return false; // framerate is too high
|
|
//johnfitz
|
|
|
|
host_frametime = realtime - oldrealtime;
|
|
oldrealtime = realtime;
|
|
|
|
//johnfitz -- host_timescale is more intuitive than host_framerate
|
|
if (host_timescale.value > 0)
|
|
host_frametime *= host_timescale.value;
|
|
//johnfitz
|
|
else if (host_framerate.value > 0)
|
|
host_frametime = host_framerate.value;
|
|
else // don't allow really long or short frames
|
|
host_frametime = CLAMP (0.001, host_frametime, 0.1); //johnfitz -- use CLAMP
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
===================
|
|
Host_GetConsoleCommands
|
|
|
|
Add them exactly as if they had been typed at the console
|
|
===================
|
|
*/
|
|
void Host_GetConsoleCommands (void)
|
|
{
|
|
const char *cmd;
|
|
|
|
if (!isDedicated)
|
|
return; // no stdin necessary in graphical mode
|
|
|
|
while (1)
|
|
{
|
|
cmd = Sys_ConsoleInput ();
|
|
if (!cmd)
|
|
break;
|
|
Cbuf_AddText (cmd);
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
Host_ServerFrame
|
|
==================
|
|
*/
|
|
void Host_ServerFrame (void)
|
|
{
|
|
int i, active; //johnfitz
|
|
edict_t *ent; //johnfitz
|
|
|
|
// 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 ();
|
|
|
|
//johnfitz -- devstats
|
|
if (cls.signon == SIGNONS)
|
|
{
|
|
for (i=0, active=0; i<sv.num_edicts; i++)
|
|
{
|
|
ent = EDICT_NUM(i);
|
|
if (!ent->free)
|
|
active++;
|
|
}
|
|
if (active > 600 && dev_peakstats.edicts <= 600)
|
|
Con_Warning ("%i edicts exceeds standard limit of 600.\n", active);
|
|
dev_stats.edicts = active;
|
|
dev_peakstats.edicts = q_max(active, dev_peakstats.edicts);
|
|
}
|
|
//johnfitz
|
|
|
|
// send all messages to the clients
|
|
SV_SendClientMessages ();
|
|
}
|
|
|
|
/*
|
|
==================
|
|
Host_Frame
|
|
|
|
Runs all active servers
|
|
==================
|
|
*/
|
|
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
|
|
Key_UpdateForDest ();
|
|
IN_UpdateInputMode ();
|
|
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 ();
|
|
|
|
// fetch results from server
|
|
if (cls.state == ca_connected)
|
|
CL_ReadFromServer ();
|
|
|
|
// update video
|
|
if (host_speeds.value)
|
|
time1 = Sys_DoubleTime ();
|
|
|
|
SCR_UpdateScreen ();
|
|
|
|
CL_RunParticles (); //johnfitz -- seperated from rendering
|
|
|
|
if (host_speeds.value)
|
|
time2 = Sys_DoubleTime ();
|
|
|
|
// update audio
|
|
BGM_Update(); // adds music raw samples and/or advances midi driver
|
|
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();
|
|
|
|
if (host_speeds.value)
|
|
{
|
|
pass1 = (time1 - time3)*1000;
|
|
time3 = Sys_DoubleTime ();
|
|
pass2 = (time2 - time1)*1000;
|
|
pass3 = (time3 - time2)*1000;
|
|
Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n",
|
|
pass1+pass2+pass3, pass1, pass2, pass3);
|
|
}
|
|
|
|
host_framecount++;
|
|
|
|
}
|
|
|
|
void Host_Frame (float time)
|
|
{
|
|
double time1, time2;
|
|
static double timetotal;
|
|
static int timecount;
|
|
int i, c, m;
|
|
|
|
if (!serverprofile.value)
|
|
{
|
|
_Host_Frame (time);
|
|
return;
|
|
}
|
|
|
|
time1 = Sys_DoubleTime ();
|
|
_Host_Frame (time);
|
|
time2 = Sys_DoubleTime ();
|
|
|
|
timetotal += time2 - time1;
|
|
timecount++;
|
|
|
|
if (timecount < 1000)
|
|
return;
|
|
|
|
m = timetotal*1000/timecount;
|
|
timecount = 0;
|
|
timetotal = 0;
|
|
c = 0;
|
|
for (i = 0; i < svs.maxclients; i++)
|
|
{
|
|
if (svs.clients[i].active)
|
|
c++;
|
|
}
|
|
|
|
Con_Printf ("serverprofile: %2i clients %2i msec\n", c, m);
|
|
}
|
|
|
|
/*
|
|
====================
|
|
Host_Init
|
|
====================
|
|
*/
|
|
void Host_Init (void)
|
|
{
|
|
if (standard_quake)
|
|
minimum_memory = MINIMUM_MEMORY;
|
|
else minimum_memory = MINIMUM_MEMORY_LEVELPAK;
|
|
|
|
if (COM_CheckParm ("-minmemory"))
|
|
host_parms->memsize = minimum_memory;
|
|
|
|
if (host_parms->memsize < minimum_memory)
|
|
Sys_Error ("Only %4.1f megs of memory available, can't execute game", host_parms->memsize / (float)0x100000);
|
|
|
|
com_argc = host_parms->argc;
|
|
com_argv = host_parms->argv;
|
|
|
|
Memory_Init (host_parms->membase, host_parms->memsize);
|
|
Cbuf_Init ();
|
|
Cmd_Init ();
|
|
LOG_Init (host_parms);
|
|
Cvar_Init (); //johnfitz
|
|
COM_Init ();
|
|
COM_InitFilesystem ();
|
|
Host_InitLocal ();
|
|
W_LoadWadFile (); //johnfitz -- filename is now hard-coded for honesty
|
|
if (cls.state != ca_dedicated)
|
|
{
|
|
Key_Init ();
|
|
Con_Init ();
|
|
}
|
|
PR_Init ();
|
|
Mod_Init ();
|
|
NET_Init ();
|
|
SV_Init ();
|
|
|
|
Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
|
|
Con_Printf ("%4.1f megabyte heap\n", host_parms->memsize/ (1024*1024.0));
|
|
|
|
if (cls.state != ca_dedicated)
|
|
{
|
|
host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp", NULL);
|
|
if (!host_colormap)
|
|
Sys_Error ("Couldn't load gfx/colormap.lmp");
|
|
|
|
V_Init ();
|
|
Chase_Init ();
|
|
M_Init ();
|
|
ExtraMaps_Init (); //johnfitz
|
|
Modlist_Init (); //johnfitz
|
|
VID_Init ();
|
|
IN_Init ();
|
|
TexMgr_Init (); //johnfitz
|
|
Draw_Init ();
|
|
SCR_Init ();
|
|
R_Init ();
|
|
S_Init ();
|
|
CDAudio_Init ();
|
|
BGM_Init();
|
|
Sbar_Init ();
|
|
CL_Init ();
|
|
}
|
|
|
|
Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
|
|
host_hunklevel = Hunk_LowMark ();
|
|
|
|
host_initialized = true;
|
|
Con_Printf ("\n========= Quake Initialized =========\n\n");
|
|
|
|
if (cls.state != ca_dedicated)
|
|
{
|
|
Cbuf_InsertText ("exec quake.rc\n");
|
|
// johnfitz -- in case the vid mode was locked during vid_init, we can unlock it now.
|
|
// note: two leading newlines because the command buffer swallows one of them.
|
|
Cbuf_AddText ("\n\nvid_unlock\n");
|
|
}
|
|
|
|
if (cls.state == ca_dedicated)
|
|
{
|
|
Cbuf_AddText ("exec autoexec.cfg\n");
|
|
Cbuf_AddText ("stuffcmds");
|
|
Cbuf_Execute ();
|
|
if (!sv.active)
|
|
Cbuf_AddText ("map start\n");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
Host_Shutdown
|
|
|
|
FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better
|
|
to run quit through here before the final handoff to the sys code.
|
|
===============
|
|
*/
|
|
void Host_Shutdown(void)
|
|
{
|
|
static qboolean isdown = false;
|
|
|
|
if (isdown)
|
|
{
|
|
printf ("recursive shutdown\n");
|
|
return;
|
|
}
|
|
isdown = true;
|
|
|
|
// keep Con_Printf from trying to update the screen
|
|
scr_disabled_for_loading = true;
|
|
|
|
Host_WriteConfiguration ();
|
|
|
|
NET_Shutdown ();
|
|
|
|
if (cls.state != ca_dedicated)
|
|
{
|
|
if (con_initialized)
|
|
History_Shutdown ();
|
|
BGM_Shutdown();
|
|
CDAudio_Shutdown ();
|
|
S_Shutdown ();
|
|
IN_Shutdown ();
|
|
VID_Shutdown();
|
|
}
|
|
|
|
LOG_Close ();
|
|
}
|
|
|