]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - host.c
Revert "Make cdda optional, server does not need to play music" because it
[xonotic/darkplaces.git] / host.c
diff --git a/host.c b/host.c
index d316fcc4e193201a6666b0e10765b4a1678e69f0..0b97a4547183e3c6675ca0bf4ed550aa38ead26c 100644 (file)
--- a/host.c
+++ b/host.c
@@ -66,11 +66,13 @@ cvar_t cl_maxphysicsframesperserverframe = {0, "cl_maxphysicsframesperserverfram
 cvar_t host_speeds = {0, "host_speeds","0", "reports how much time is used in server/graphics/sound"};
 cvar_t host_maxwait = {0, "host_maxwait","1000", "maximum sleep time requested from the operating system in millisecond. Larger sleeps will be done using multiple host_maxwait length sleeps. Lowering this value will increase CPU load, but may help working around problems with accuracy of sleep times."};
 cvar_t cl_minfps = {CVAR_SAVE, "cl_minfps", "40", "minimum fps target - while the rendering performance is below this, it will drift toward lower quality"};
-cvar_t cl_minfps_fade = {CVAR_SAVE, "cl_minfps_fade", "0.2", "how fast the quality adapts to varying framerate"};
+cvar_t cl_minfps_fade = {CVAR_SAVE, "cl_minfps_fade", "1", "how fast the quality adapts to varying framerate"};
 cvar_t cl_minfps_qualitymax = {CVAR_SAVE, "cl_minfps_qualitymax", "1", "highest allowed drawdistance multiplier"};
 cvar_t cl_minfps_qualitymin = {CVAR_SAVE, "cl_minfps_qualitymin", "0.25", "lowest allowed drawdistance multiplier"};
-cvar_t cl_minfps_qualitypower = {CVAR_SAVE, "cl_minfps_qualitypower", "4", "raises quality value to a power of itself, higher values make quality drop more sharply in relation to framerate"};
-cvar_t cl_minfps_qualityscale = {CVAR_SAVE, "cl_minfps_qualityscale", "0.5", "multiplier for quality"};
+cvar_t cl_minfps_qualitymultiply = {CVAR_SAVE, "cl_minfps_qualitymultiply", "0.2", "multiplier for quality changes in quality change per second render time (1 assumes linearity of quality and render time)"};
+cvar_t cl_minfps_qualityhysteresis = {CVAR_SAVE, "cl_minfps_qualityhysteresis", "0.05", "reduce all quality increments by this to reduce flickering"};
+cvar_t cl_minfps_qualitystepmax = {CVAR_SAVE, "cl_minfps_qualitystepmax", "0.1", "maximum quality change in a single frame"};
+cvar_t cl_minfps_force = {0, "cl_minfps_force", "0", "also apply quality reductions in timedemo/capturevideo"};
 cvar_t cl_maxfps = {CVAR_SAVE, "cl_maxfps", "0", "maximum fps cap, 0 = unlimited, if game is running faster than this it will wait before running another frame (useful to make cpu time available to other programs)"};
 cvar_t cl_maxfps_alwayssleep = {0, "cl_maxfps_alwayssleep","1", "gives up some processing time to other applications each frame, value in milliseconds, disabled if cl_maxfps is 0"};
 cvar_t cl_maxidlefps = {CVAR_SAVE, "cl_maxidlefps", "20", "maximum fps cap when the game is not the active window (makes cpu time available to other programs"};
@@ -85,6 +87,9 @@ cvar_t developer_entityparsing = {0, "developer_entityparsing", "0", "prints det
 cvar_t timestamps = {CVAR_SAVE, "timestamps", "0", "prints timestamps on console messages"};
 cvar_t timeformat = {CVAR_SAVE, "timeformat", "[%Y-%m-%d %H:%M:%S] ", "time format to use on timestamped console messages"};
 
+cvar_t sessionid = {CVAR_READONLY, "sessionid", "", "ID of the current session (use the -sessionid parameter to set it); this is always either empty or begins with a dot (.)"};
+cvar_t locksession = {0, "locksession", "0", "Lock the session? 0 = no, 1 = yes and abort on failure, 2 = yes and continue on failure"};
+
 /*
 ================
 Host_AbortCurrentFrame
@@ -92,8 +97,12 @@ Host_AbortCurrentFrame
 aborts the current host frame and goes on with the next one
 ================
 */
+void Host_AbortCurrentFrame(void) DP_FUNC_NORETURN;
 void Host_AbortCurrentFrame(void)
 {
+       // in case we were previously nice, make us mean again
+       Sys_MakeProcessMean();
+
        longjmp (host_abortframe, 1);
 }
 
@@ -234,8 +243,10 @@ static void Host_InitLocal (void)
        Cvar_RegisterVariable (&cl_minfps_fade);
        Cvar_RegisterVariable (&cl_minfps_qualitymax);
        Cvar_RegisterVariable (&cl_minfps_qualitymin);
-       Cvar_RegisterVariable (&cl_minfps_qualitypower);
-       Cvar_RegisterVariable (&cl_minfps_qualityscale);
+       Cvar_RegisterVariable (&cl_minfps_qualitystepmax);
+       Cvar_RegisterVariable (&cl_minfps_qualityhysteresis);
+       Cvar_RegisterVariable (&cl_minfps_qualitymultiply);
+       Cvar_RegisterVariable (&cl_minfps_force);
        Cvar_RegisterVariable (&cl_maxfps);
        Cvar_RegisterVariable (&cl_maxfps_alwayssleep);
        Cvar_RegisterVariable (&cl_maxidlefps);
@@ -466,9 +477,9 @@ void SV_DropClient(qboolean crash)
                        buf.data = bufdata;
                        buf.maxsize = sizeof(bufdata);
                        MSG_WriteByte(&buf, svc_disconnect);
-                       NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, false);
-                       NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, false);
-                       NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, false);
+                       NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false);
+                       NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false);
+                       NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false);
                }
        }
 
@@ -657,11 +668,11 @@ void Host_Main(void)
        double wait;
        int pass1, pass2, pass3, i;
        char vabuf[1024];
+       qboolean playing;
 
        Host_Init();
 
        realtime = 0;
-       dirtytime = Sys_DirtyTime();
        for (;;)
        {
                if (setjmp(host_abortframe))
@@ -696,14 +707,15 @@ void Host_Main(void)
                        svs.perf_acc_realtime += deltacleantime;
 
                        // Look for clients who have spawned
+                       playing = false;
                        for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
-                               if(host_client->spawned)
+                               if(host_client->begun)
                                        if(host_client->netconnection)
-                                               break;
-                       if(i == svs.maxclients)
+                                               playing = true;
+                       if(sv.time < 10)
                        {
-                               // Nobody is looking? Then we won't do timing...
-                               // Instead, reset it to zero
+                               // don't accumulate time for the first 10 seconds of a match
+                               // so things can settle
                                svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0;
                        }
                        else if(svs.perf_acc_realtime > 5)
@@ -717,7 +729,8 @@ void Host_Main(void)
                                        svs.perf_offset_sdev = sqrt(svs.perf_acc_offset_squared / svs.perf_acc_offset_samples - svs.perf_offset_avg * svs.perf_offset_avg);
                                }
                                if(svs.perf_lost > 0 && developer_extra.integer)
-                                       Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
+                                       if(playing) // only complain if anyone is looking
+                                               Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf)));
                                svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0;
                        }
                }
@@ -755,13 +768,11 @@ void Host_Main(void)
                // otherwise we execute them on client frames
                if (sv.active ? sv_timer > 0 : cl_timer > 0)
                {
-                       SV_LockThreadMutex();
                        // process console commands
 //                     R_TimeReport("preconsole");
                        CL_VM_PreventInformationLeaks();
-                       Cbuf_Execute();
+                       Cbuf_Frame();
 //                     R_TimeReport("console");
-                       SV_UnlockThreadMutex();
                }
 
                //Con_Printf("%6.0f %6.0f\n", cl_timer * 1000000.0, sv_timer * 1000000.0);
@@ -836,20 +847,15 @@ void Host_Main(void)
                                advancetime = sv_timer;
                        else if (cl.islocalgame && !sv_fixedframeratesingleplayer.integer)
                        {
-                               // synchronize to the client frametime, but no less than 10ms and no more than sys_ticrate
-                               advancetime = bound(0.01, cl_timer, sys_ticrate.value);
-                               framelimit = cl_maxphysicsframesperserverframe.integer;
-                               aborttime = realtime + 0.1;
+                               // synchronize to the client frametime, but no less than 10ms and no more than 100ms
+                               advancetime = bound(0.01, cl_timer, 0.1);
                        }
                        else
                        {
                                advancetime = sys_ticrate.value;
                                // listen servers can run multiple server frames per client frame
-                               if (cls.state == ca_connected)
-                               {
-                                       framelimit = cl_maxphysicsframesperserverframe.integer;
-                                       aborttime = realtime + 0.1;
-                               }
+                               framelimit = cl_maxphysicsframesperserverframe.integer;
+                               aborttime = Sys_DirtyTime() + 0.1;
                        }
                        if(slowmo.value > 0 && slowmo.value < 1)
                                advancetime = min(advancetime, 0.1 / slowmo.value);
@@ -858,7 +864,7 @@ void Host_Main(void)
 
                        if(advancetime > 0)
                        {
-                               offset = Sys_DirtyTime() - realtime;if (offset < 0 || offset >= 1800) offset = 0;
+                               offset = Sys_DirtyTime() - dirtytime;if (offset < 0 || offset >= 1800) offset = 0;
                                offset += sv_timer;
                                ++svs.perf_acc_offset_samples;
                                svs.perf_acc_offset += offset;
@@ -893,7 +899,7 @@ void Host_Main(void)
                        SV_SendClientMessages();
 
                        if (sv.paused == 1 && realtime > sv.pausedstart && sv.pausedstart > 0) {
-                               prog->globals.generic[OFS_PARM0] = realtime - sv.pausedstart;
+                               prog->globals.fp[OFS_PARM0] = realtime - sv.pausedstart;
                                PRVM_serverglobalfloat(time) = sv.time;
                                prog->ExecuteProgram(prog, PRVM_serverfunction(SV_PausedTic), "QC function SV_PausedTic is missing");
                        }
@@ -919,7 +925,7 @@ void Host_Main(void)
                {
                        R_TimeReport("---");
                        Collision_Cache_NewFrame();
-                       R_TimeReport("collisioncache");
+                       R_TimeReport("photoncache");
                        // decide the simulation time
                        if (cls.capturevideo.active)
                        {
@@ -955,13 +961,15 @@ void Host_Main(void)
                                if (cls.demopaused)
                                        clframetime = 0;
                        }
+                       else
+                       {
+                               // host_framerate overrides all else
+                               if (host_framerate.value)
+                                       clframetime = host_framerate.value;
 
-                       // host_framerate overrides all else
-                       if (host_framerate.value)
-                               clframetime = host_framerate.value;
-
-                       if (cl.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused)))
-                               clframetime = 0;
+                               if (cl.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused)))
+                                       clframetime = 0;
+                       }
 
                        if (cls.timedemo)
                                clframetime = cl.realframetime = cl_timer;
@@ -1075,6 +1083,65 @@ qboolean sys_nostdout = false;
 
 extern qboolean host_stuffcmdsrun;
 
+static qfile_t *locksession_fh = NULL;
+static qboolean locksession_run = false;
+static void Host_InitSession(void)
+{
+       int i;
+       Cvar_RegisterVariable(&sessionid);
+       Cvar_RegisterVariable(&locksession);
+
+       // load the session ID into the read-only cvar
+       if ((i = COM_CheckParm("-sessionid")) && (i + 1 < com_argc))
+       {
+               char vabuf[1024];
+               if(com_argv[i+1][0] == '.')
+                       Cvar_SetQuick(&sessionid, com_argv[i+1]);
+               else
+                       Cvar_SetQuick(&sessionid, va(vabuf, sizeof(vabuf), ".%s", com_argv[i+1]));
+       }
+}
+void Host_LockSession(void)
+{
+       if(locksession_run)
+               return;
+       locksession_run = true;
+       if(locksession.integer != 0 && !COM_CheckParm("-readonly"))
+       {
+               char vabuf[1024];
+               char *p = va(vabuf, sizeof(vabuf), "%slock%s", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string);
+               FS_CreatePath(p);
+               locksession_fh = FS_SysOpen(p, "wl", false);
+               // TODO maybe write the pid into the lockfile, while we are at it? may help server management tools
+               if(!locksession_fh)
+               {
+                       if(locksession.integer == 2)
+                       {
+                               Con_Printf("WARNING: session lock %s could not be acquired. Please run with -sessionid and an unique session name. Continuing anyway.\n", p);
+                       }
+                       else
+                       {
+                               Sys_Error("session lock %s could not be acquired. Please run with -sessionid and an unique session name.\n", p);
+                       }
+               }
+       }
+}
+void Host_UnlockSession(void)
+{
+       if(!locksession_run)
+               return;
+       locksession_run = false;
+
+       if(locksession_fh)
+       {
+               FS_Close(locksession_fh);
+               // NOTE: we can NOT unlink the lock here, as doing so would
+               // create a race condition if another process created it
+               // between our close and our unlink
+               locksession_fh = NULL;
+       }
+}
+
 /*
 ====================
 Host_Init
@@ -1163,12 +1230,18 @@ static void Host_Init (void)
        dpsnprintf (engineversion, sizeof (engineversion), "%s %s %s", gamename, os, buildstring);
        Con_Printf("%s\n", engineversion);
 
+       // initialize process nice level
+       Sys_InitProcessNice();
+
        // initialize ixtable
        Mathlib_Init();
 
        // initialize filesystem (including fs_basedir, fs_gamedir, -game, scr_screenshot_name)
        FS_Init();
 
+       // register the cvars for session locking
+       Host_InitSession();
+
        // must be after FS_Init
        Crypto_Init();
        Crypto_Init_Commands();
@@ -1229,7 +1302,7 @@ static void Host_Init (void)
        }
 
        // put up the loading image so the user doesn't stare at a black screen...
-       SCR_BeginLoadingPlaque();
+       SCR_BeginLoadingPlaque(true);
 
        if (cls.state != ca_dedicated)
        {
@@ -1274,7 +1347,7 @@ static void Host_Init (void)
 
        if (!sv.active && !cls.demoplayback && !cls.connect_trying)
        {
-               Cbuf_AddText("togglemenu\n");
+               Cbuf_AddText("togglemenu 1\n");
                Cbuf_Execute();
        }
 
@@ -1357,7 +1430,10 @@ void Host_Shutdown(void)
        Sys_Shutdown();
        Log_Close();
        Crypto_Shutdown();
-       FS_Shutdown();
+
+       Host_UnlockSession();
+
+       S_Shutdown();
        Con_Shutdown();
        Memory_Shutdown();
 }