va_list argptr;
va_start (argptr,error);
- vsprintf (hosterrorstring1,error,argptr);
+ dpvsnprintf (hosterrorstring1,sizeof(hosterrorstring1),error,argptr);
va_end (argptr);
Con_Printf("Host_Error: %s\n", hosterrorstring1);
void Host_InitLocal (void)
{
Host_InitCommands ();
-
+
Cmd_AddCommand("saveconfig", Host_SaveConfig_f);
Cvar_RegisterVariable (&host_framerate);
// dedicated servers initialize the host but don't parse and set the
// config.cfg cvars
- if (host_initialized && cls.state != ca_dedicated)
+ // LordHavoc: save a config only after Host_Frame finished the first frame
+ if (host_initialized && host_loopactive && cls.state != ca_dedicated)
{
- f = FS_Open ("config.cfg", "w", false);
+ f = FS_Open ("config.cfg", "wb", false, false);
if (!f)
{
Con_Print("Couldn't write config.cfg.\n");
char msg[4096];
va_start(argptr,fmt);
- vsnprintf(msg,sizeof(msg),fmt,argptr);
+ dpvsnprintf(msg,sizeof(msg),fmt,argptr);
va_end(argptr);
SV_ClientPrint(msg);
}
if (sv_echobprint.integer && cls.state == ca_dedicated)
- Sys_Print(msg);
+ Con_Print(msg);
}
/*
char msg[4096];
va_start(argptr,fmt);
- vsnprintf(msg,sizeof(msg),fmt,argptr);
+ dpvsnprintf(msg,sizeof(msg),fmt,argptr);
va_end(argptr);
SV_BroadcastPrint(msg);
char string[1024];
va_start(argptr,fmt);
- vsprintf(string, fmt,argptr);
+ dpvsnprintf(string, sizeof(string), fmt, argptr);
va_end(argptr);
MSG_WriteByte(&host_client->message, svc_stufftext);
int i;
Con_Printf("Client \"%s\" dropped\n", host_client->name);
- // send any final messages (don't check for errors)
+ // make sure edict is not corrupt (from a level change for example)
+ host_client->edict = EDICT_NUM(host_client - svs.clients + 1);
+
if (host_client->netconnection)
{
// free the client (the body stays around)
MSG_WriteByte(&host_client->message, svc_disconnect);
NetConn_SendUnreliableMessage(host_client->netconnection, &host_client->message);
}
-
// break the net connection
NetConn_Close(host_client->netconnection);
host_client->netconnection = NULL;
+ }
- // LordHavoc: don't call QC if server is dead (avoids recursive
- // Host_Error in some mods when they run out of edicts)
- if (sv.active && 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
- int saveSelf = pr_global_struct->self;
- pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
- PR_ExecuteProgram(pr_global_struct->ClientDisconnect, "QC function ClientDisconnect is missing");
- pr_global_struct->self = saveSelf;
- }
+ // call qc ClientDisconnect function
+ // LordHavoc: don't call QC if server is dead (avoids recursive
+ // Host_Error in some mods when they run out of edicts)
+ if (host_client->active && sv.active && 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
+ int saveSelf = pr_global_struct->self;
+ pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
+ PR_ExecuteProgram(pr_global_struct->ClientDisconnect, "QC function ClientDisconnect is missing");
+ pr_global_struct->self = saveSelf;
}
// remove leaving player from scoreboard
- // clear a fields that matter to DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS, and also frags
- ED_ClearEdict(host_client->edict);
//host_client->edict->v->netname = PR_SetString(host_client->name);
//if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
// val->_float = 0;
EntityFrame4_FreeDatabase(host_client->entitydatabase4);
if (host_client->entitydatabase5)
EntityFrame5_FreeDatabase(host_client->entitydatabase5);
+
+ if (sv.active)
+ {
+ // clear a fields that matter to DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS, and also frags
+ ED_ClearEdict(host_client->edict);
+ }
+
// clear the client struct (this sets active to false)
memset(host_client, 0, sizeof(*host_client));
double timecap, timeleft;
realtime += time;
- if (sys_ticrate.value < 0.01 || sys_ticrate.value > 0.1)
+ if (sys_ticrate.value < 0.00999 || sys_ticrate.value > 0.10001)
Cvar_SetValue("sys_ticrate", bound(0.01, sys_ticrate.value, 0.1));
if (slowmo.value < 0)
Cvar_SetValue("slowmo", 0);
timeleft = (oldrealtime - realtime) + timecap;
if (timeleft > 0)
{
+ int msleft;
// don't totally hog the CPU
- if (timeleft >= 0.03)
- Sys_Sleep((int)(timeleft * 1000) - 10);
+ if (cls.state == ca_dedicated)
+ {
+ // if dedicated, try to use as little cpu as possible by waiting
+ // just a little longer than necessary
+ // (yes this means it doesn't quite keep up with the framerate)
+ msleft = (int)ceil(timeleft * 1000);
+ }
+ else
+ {
+ // if not dedicated, try to hit exactly a steady framerate by not
+ // sleeping the full amount
+ msleft = (int)floor(timeleft * 1000);
+ }
+ if (msleft > 0)
+ Sys_Sleep(msleft);
return false;
}
if (host_framerate.value)
host_frametime = host_framerate.value;
+ // never run a frame longer than 1 second
+ if (host_frametime > 1)
+ host_frametime = 1;
+
cl.frametime = host_frametime;
return true;
*/
void Host_ServerFrame (void)
{
- double advancetime;
- static double frametimetotal = 0, lastservertime = 0;
- frametimetotal += host_frametime;
- // LordHavoc: cap server at sys_ticrate in networked games
- if (frametimetotal < 0.001 || (!cl.islocalgame && cls.state == ca_connected && sv.active && ((realtime - lastservertime) < sys_ticrate.value)))
+ // never run more than 5 frames at a time as a sanity limit
+ int framecount, framelimit = 5;
+ double advancetime, newtime;
+ if (!sv.active)
+ return;
+ newtime = Sys_DoubleTime();
+ // if this is the first frame of a new server, ignore the huge time difference
+ if (!sv.timer)
+ sv.timer = newtime;
+ // if we're already past the new time, don't run a frame
+ // (does not happen if cl.islocalgame)
+ if (sv.timer > newtime)
return;
- lastservertime = realtime;
-
- // set the time and clear the general datagram
- SV_ClearDatagram();
-
// run the world state
// don't allow simulation to run too fast or too slow or logic glitches can occur
- while (frametimetotal > 0)
+ for (framecount = 0;framecount < framelimit && sv.timer < newtime;framecount++)
{
- advancetime = min(frametimetotal, sys_ticrate.value);
- frametimetotal = frametimetotal - advancetime;
+ if (cl.islocalgame)
+ advancetime = min(newtime - sv.timer, sys_ticrate.value);
+ else
+ advancetime = sys_ticrate.value;
+ sv.timer += advancetime;
// only advance time if not paused
// the game also pauses in singleplayer when menu or console is used
- if (!sv.paused && (!cl.islocalgame || (key_dest == key_game && !key_consoleactive)))
- sv.frametime = advancetime;
- else
+ sv.frametime = advancetime * slowmo.value;
+ if (sv.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive)))
sv.frametime = 0;
pr_global_struct->frametime = sv.frametime;
+ // set the time and clear the general datagram
+ SV_ClearDatagram();
+
// check for network packets to the server each world step incase they
// come in midframe (particularly if host is running really slow)
NetConn_ServerFrame();
// move things around and think unless paused
if (sv.frametime)
SV_Physics();
- }
- // send all messages to the clients
- SV_SendClientMessages();
+ // send all messages to the clients
+ SV_SendClientMessages();
- // send an heartbeat if enough time has passed since the last one
- NetConn_Heartbeat(0);
+ // send an heartbeat if enough time has passed since the last one
+ NetConn_Heartbeat(0);
+ }
+ // if we fell behind too many frames just don't worry about it
+ if (sv.timer < newtime)
+ sv.timer = newtime;
}
static double time2 = 0;
static double time3 = 0;
int pass1, pass2, pass3;
- usercmd_t cmd; // Used for receiving input
if (setjmp(host_abortserver))
return; // something bad happened, or the server disconnected
IN_Commands();
// Collect input into cmd
- IN_ProcessMove(&cmd);
+ IN_ProcessMove();
// process console commands
Cbuf_Execute();
// if running the server locally, make intentions now
if (cls.state == ca_connected && sv.active)
- CL_SendCmd(&cmd);
+ CL_SendCmd();
//-------------------
//
// if running the server remotely, send intentions now after
// the incoming messages have been read
if (!sv.active)
- CL_SendCmd(&cmd);
+ CL_SendCmd();
CL_ReadFromServer();
}
if (cls.state != ca_dedicated)
{
VID_Open();
+ CDAudio_Startup();
+ CL_InitTEnts (); // We must wait after sound startup to load tent sounds
SCR_BeginLoadingPlaque();
MR_Init();
}
+ // set up the default startmap_sp and startmap_dm aliases, mods can
+ // override these
+ if (gamemode == GAME_NEHAHRA)
+ {
+ Cbuf_InsertText ("alias startmap_sp \"map nehstart\"\n");
+ Cbuf_InsertText ("alias startmap_dm \"map nehstart\"\n");
+ }
+ else if (gamemode == GAME_TRANSFUSION)
+ {
+ Cbuf_InsertText ("alias startmap_sp \"map e1m1\"\n");
+ Cbuf_InsertText ("alias startmap_dm \"map bb1\"\n");
+ }
+ else if (gamemode == GAME_NEXUIZ)
+ {
+ Cbuf_InsertText ("alias startmap_sp \"map nexdm01\"\n");
+ Cbuf_InsertText ("alias startmap_dm \"map nexdm01\"\n");
+ }
+ else
+ {
+ Cbuf_InsertText ("alias startmap_sp \"map start\"\n");
+ Cbuf_InsertText ("alias startmap_dm \"map start\"\n");
+ }
+
// stuff it again so the first host frame will execute it again, this time
// in its entirety
if (gamemode == GAME_TEU)
else
Cbuf_InsertText("exec quake.rc\n");
+ Cbuf_Execute();
+ Cbuf_Execute();
+ Cbuf_Execute();
+
if (!sv.active && (cls.state == ca_dedicated || COM_CheckParm("-listen")))
- {
- if (gamemode == GAME_TRANSFUSION)
- Cbuf_InsertText ("map bb1\n");
- else if (gamemode == GAME_NEXUIZ)
- Cbuf_InsertText ("map nexdm01\n");
- else
- Cbuf_InsertText ("map start\n");
- }
+ Cbuf_InsertText ("startmap_dm\n");
// check for special benchmark mode
// COMMANDLINEOPTION: Client: -benchmark <demoname> runs a timedemo and quits, results of any timedemo can be found in gamedir/benchmark.log (for example id1/benchmark.log)
i = COM_CheckParm("-benchmark");
- if (i && i + 1 < com_argc)
+ if (i && i + 1 < com_argc && !sv.active)
Cbuf_InsertText(va("timedemo %s\n", com_argv[i + 1]));
+ if (!sv.active && !cls.demoplayback && !cls.connect_trying)
+ Cbuf_InsertText("togglemenu\n");
+
Cbuf_Execute();
// We must wait for the log_file cvar to be initialized to start the log
// AK shutdown PRVM
// AK hmm, no PRVM_Shutdown(); yet
+ CL_Video_Shutdown();
Host_SaveConfig_f();
CDAudio_Shutdown ();
+ S_Terminate ();
NetConn_Shutdown ();
+ PR_Shutdown ();
+ Cbuf_Shutdown ();
if (cls.state != ca_dedicated)
{
VID_Shutdown();
}
+ Cmd_Shutdown();
+ CL_Shutdown();
Sys_Shutdown();
Log_Close ();
+ COM_Shutdown ();
+ Memory_Shutdown();
}