+ prvm_prog_t *prog = SVVM_prog;
+ qboolean playing = false;
+ double sv_timer = 0;
+ double sv_deltarealtime, sv_oldrealtime, sv_realtime;
+ double wait;
+ int i;
+ char vabuf[1024];
+ sv_realtime = Sys_DirtyTime();
+ while (!svs.threadstop)
+ {
+ // FIXME: we need to handle Host_Error in the server thread somehow
+// if (setjmp(sv_abortframe))
+// continue; // something bad happened in the server game
+
+ sv_oldrealtime = sv_realtime;
+ sv_realtime = Sys_DirtyTime();
+ sv_deltarealtime = sv_realtime - sv_oldrealtime;
+ if (sv_deltarealtime < 0 || sv_deltarealtime >= 1800) sv_deltarealtime = 0;
+
+ sv_timer += sv_deltarealtime;
+
+ svs.perf_acc_realtime += sv_deltarealtime;
+
+ // at this point we start doing real server work, and must block on any client activity pertaining to the server (such as executing SV_SpawnServer)
+ SV_LockThreadMutex();
+
+ // Look for clients who have spawned
+ playing = false;
+ if (sv.active)
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
+ if(host_client->begun)
+ if(host_client->netconnection)
+ playing = true;
+ if(sv.time < 10)
+ {
+ // 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)
+ {
+ svs.perf_cpuload = 1 - svs.perf_acc_sleeptime / svs.perf_acc_realtime;
+ svs.perf_lost = svs.perf_acc_lost / svs.perf_acc_realtime;
+ if(svs.perf_acc_offset_samples > 0)
+ {
+ svs.perf_offset_max = svs.perf_acc_offset_max;
+ svs.perf_offset_avg = svs.perf_acc_offset / svs.perf_acc_offset_samples;
+ 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)
+ if(playing)
+ 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;
+ }
+
+ // get new packets
+ if (sv.active)
+ NetConn_ServerFrame();
+
+ // if the accumulators haven't become positive yet, wait a while
+ wait = sv_timer * -1000000.0;
+ if (wait >= 1)
+ {
+ double time0, delta;
+ SV_UnlockThreadMutex(); // don't keep mutex locked while sleeping
+ if (host_maxwait.value <= 0)
+ wait = min(wait, 1000000.0);
+ else
+ wait = min(wait, host_maxwait.value * 1000.0);
+ if(wait < 1)
+ wait = 1; // because we cast to int
+ time0 = Sys_DirtyTime();
+ Sys_Sleep((int)wait);
+ delta = Sys_DirtyTime() - time0;if (delta < 0 || delta >= 1800) delta = 0;
+ svs.perf_acc_sleeptime += delta;
+ continue;
+ }
+
+ if (sv.active && sv_timer > 0)
+ {
+ // execute one server frame
+ double advancetime;
+ float offset;
+
+ if (sys_ticrate.value <= 0)
+ advancetime = min(sv_timer, 0.1); // don't step more than 100ms
+ else
+ advancetime = sys_ticrate.value;
+
+ if(advancetime > 0)
+ {
+ offset = sv_timer + (Sys_DirtyTime() - sv_realtime); // LordHavoc: FIXME: I don't understand this line
+ ++svs.perf_acc_offset_samples;
+ svs.perf_acc_offset += offset;
+ svs.perf_acc_offset_squared += offset * offset;
+ if(svs.perf_acc_offset_max < offset)
+ svs.perf_acc_offset_max = offset;
+ }
+
+ // only advance time if not paused
+ // the game also pauses in singleplayer when menu or console is used
+ sv.frametime = advancetime * slowmo.value;
+ if (host_framerate.value)
+ sv.frametime = host_framerate.value;
+ if (sv.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused)))
+ sv.frametime = 0;
+
+ sv_timer -= advancetime;