X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=sv_main.c;h=52156cfe76af2d69eb6133080bf082d1a76e6b15;hb=refs%2Fheads%2Fbones_was_here%2Fnet_s4;hp=05134680cb1e4473a666aa3b4a45dd3fcd4fb1bc;hpb=1dfb76a50d855048ba125cbea61489d39535e7f4;p=xonotic%2Fdarkplaces.git diff --git a/sv_main.c b/sv_main.c index 05134680..52156cfe 100644 --- a/sv_main.c +++ b/sv_main.c @@ -76,7 +76,8 @@ cvar_t sv_checkforpacketsduringsleep = {CF_SERVER, "sv_checkforpacketsduringslee cvar_t sv_clmovement_enable = {CF_SERVER, "sv_clmovement_enable", "1", "whether to allow clients to use cl_movement prediction, which can cause choppy movement on the server which may annoy other players"}; cvar_t sv_clmovement_minping = {CF_SERVER, "sv_clmovement_minping", "0", "if client ping is below this time in milliseconds, then their ability to use cl_movement prediction is disabled for a while (as they don't need it)"}; cvar_t sv_clmovement_minping_disabletime = {CF_SERVER, "sv_clmovement_minping_disabletime", "1000", "when client falls below minping, disable their prediction for this many milliseconds (should be at least 1000 or else their prediction may turn on/off frequently)"}; -cvar_t sv_clmovement_inputtimeout = {CF_SERVER, "sv_clmovement_inputtimeout", "0.2", "when a client does not send input for this many seconds, force them to move anyway (unlike QuakeWorld)"}; +cvar_t sv_clmovement_inputtimeout = {CF_SERVER, "sv_clmovement_inputtimeout", "0.1", "when a client does not send input for this many seconds (max 0.1), force them to move anyway (unlike QuakeWorld)"}; +cvar_t sv_clmovement_inputtimeout_strict = {CF_SERVER, "sv_clmovement_inputtimeout_strict", "1", "prevent lagaporting (in other players' perspectives) and speeding up (in lagging player's perspective) when inputtimeout is exceeded"}; cvar_t sv_cullentities_nevercullbmodels = {CF_SERVER, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"}; cvar_t sv_cullentities_pvs = {CF_SERVER, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; cvar_t sv_cullentities_stats = {CF_SERVER, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"}; @@ -147,8 +148,8 @@ cvar_t sv_sound_watersplash = {CF_SERVER, "sv_sound_watersplash", "misc/h2ohit1. cvar_t sv_stepheight = {CF_SERVER | CF_NOTIFY, "sv_stepheight", "18", "how high you can step up (TW_SV_STEPCONTROL extension)"}; cvar_t sv_stopspeed = {CF_SERVER | CF_NOTIFY, "sv_stopspeed","100", "how fast you come to a complete stop"}; cvar_t sv_wallfriction = {CF_SERVER | CF_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"}; -cvar_t sv_wateraccelerate = {CF_SERVER, "sv_wateraccelerate", "-1", "rate at which a player accelerates to sv_maxspeed while in the air, if less than 0 the sv_accelerate variable is used instead"}; -cvar_t sv_waterfriction = {CF_SERVER | CF_NOTIFY, "sv_waterfriction","-1", "how fast you slow down, if less than 0 the sv_friction variable is used instead"}; +cvar_t sv_wateraccelerate = {CF_SERVER, "sv_wateraccelerate", "-1", "rate at which a player accelerates to sv_maxspeed while in water, if less than 0 the sv_accelerate variable is used instead"}; +cvar_t sv_waterfriction = {CF_SERVER | CF_NOTIFY, "sv_waterfriction","-1", "how fast you slow down in water, if less than 0 the sv_friction variable is used instead"}; cvar_t sv_warsowbunny_airforwardaccel = {CF_SERVER, "sv_warsowbunny_airforwardaccel", "1.00001", "how fast you accelerate until you reach sv_maxspeed"}; cvar_t sv_warsowbunny_accel = {CF_SERVER, "sv_warsowbunny_accel", "0.1585", "how fast you accelerate until after reaching sv_maxspeed (it gets harder as you near sv_warsowbunny_topspeed)"}; cvar_t sv_warsowbunny_topspeed = {CF_SERVER, "sv_warsowbunny_topspeed", "925", "soft speed limit (can get faster with rjs and on ramps)"}; @@ -205,6 +206,8 @@ cvar_t halflifebsp = {CF_SERVER, "halflifebsp", "0", "indicates the current map cvar_t sv_mapformat_is_quake2 = {CF_SERVER, "sv_mapformat_is_quake2", "0", "indicates the current map is q2bsp format (useful to know because of different entity behaviors, .frame on submodels and other things)"}; cvar_t sv_mapformat_is_quake3 = {CF_SERVER, "sv_mapformat_is_quake3", "0", "indicates the current map is q2bsp format (useful to know because of different entity behaviors)"}; +cvar_t sv_writepicture_quality = {CF_SERVER | CF_ARCHIVE, "sv_writepicture_quality", "10", "WritePicture quality offset (higher means better quality, but slower)"}; + server_t sv; server_static_t svs; @@ -432,30 +435,6 @@ static void SV_AreaStats_f(cmd_state_t *cmd) World_PrintAreaStats(&sv.world, "server"); } -static qbool SV_CanSave(void) -{ - prvm_prog_t *prog = SVVM_prog; - if(SV_IsLocalServer() == 1) - { - // singleplayer checks - if ((svs.clients[0].active && PRVM_serveredictfloat(svs.clients[0].edict, deadflag))) - { - Con_Print("Can't savegame with a dead player\n"); - return false; - } - - if(host.hook.CL_Intermission && host.hook.CL_Intermission()) - { - Con_Print("Can't save in intermission.\n"); - return false; - } - } - else - Con_Print(CON_WARN "Warning: saving a multiplayer game may have strange results when restored (to properly resume, all players must join in the same player slots and then the game can be reloaded).\n"); - return true; - -} - static void SV_ServerOptions (void) { int i; @@ -575,6 +554,7 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_clmovement_minping); Cvar_RegisterVariable (&sv_clmovement_minping_disabletime); Cvar_RegisterVariable (&sv_clmovement_inputtimeout); + Cvar_RegisterVariable (&sv_clmovement_inputtimeout_strict); Cvar_RegisterVariable (&sv_cullentities_nevercullbmodels); Cvar_RegisterVariable (&sv_cullentities_pvs); Cvar_RegisterVariable (&sv_cullentities_stats); @@ -705,12 +685,15 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_mapformat_is_quake2); Cvar_RegisterVariable (&sv_mapformat_is_quake3); + Cvar_RegisterVariable (&sv_writepicture_quality); + SV_InitOperatorCommands(); - host.hook.SV_CanSave = SV_CanSave; + host.hook.SV_Shutdown = SV_Shutdown; sv_mempool = Mem_AllocPool("server", 0, NULL); SV_ServerOptions(); + Cvar_Callback(&sv_netport); } static void SV_SaveEntFile_f(cmd_state_t *cmd) @@ -910,11 +893,6 @@ void SV_SendServerinfo (client_t *client) client->movesequence = 0; client->movement_highestsequence_seen = 0; memset(&client->movement_count, 0, sizeof(client->movement_count)); -#ifdef NUM_PING_TIMES - for (i = 0;i < NUM_PING_TIMES;i++) - client->ping_times[i] = 0; - client->num_pings = 0; -#endif client->ping = 0; // allow the client some time to send his keepalives, even if map loading took ages @@ -1377,7 +1355,7 @@ SV_ModelIndex */ int SV_ModelIndex(const char *s, int precachemode) { - int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) ? 256 : MAX_MODELS); + int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS); char filename[MAX_QPATH]; if (!s || !*s) return 0; @@ -1440,7 +1418,7 @@ SV_SoundIndex */ int SV_SoundIndex(const char *s, int precachemode) { - int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) ? 256 : MAX_SOUNDS); + int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP) ? 256 : MAX_SOUNDS); char filename[MAX_QPATH]; if (!s || !*s) return 0; @@ -1796,15 +1774,6 @@ void SV_SpawnServer (const char *map) if(sv.active) { - client_t *client; - for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++) - { - if (client->netconnection) - { - MSG_WriteByte(&client->netconnection->message, svc_stufftext); - MSG_WriteString(&client->netconnection->message, "reconnect\n"); - } - } World_End(&sv.world); if(PRVM_serverfunction(SV_Shutdown)) { @@ -1847,8 +1816,23 @@ void SV_SpawnServer (const char *map) // // tell all connected clients that we are going to a new level // - if (!sv.active) + if (sv.active) + { + client_t *client; + for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++) + { + if (client->netconnection) + { + MSG_WriteByte(&client->netconnection->message, svc_stufftext); + MSG_WriteString(&client->netconnection->message, "reconnect\n"); + } + } + } + else + { + // open server port NetConn_OpenServerPorts(true); + } // // make cvars consistant @@ -2077,10 +2061,12 @@ void SV_Shutdown(void) prvm_prog_t *prog = SVVM_prog; int i; - Con_DPrintf("SV_Shutdown\n"); + SV_LockThreadMutex(); if (!sv.active) - return; + goto end; + + Con_DPrintf("SV_Shutdown\n"); NetConn_Heartbeat(2); NetConn_Heartbeat(2); @@ -2109,8 +2095,8 @@ void SV_Shutdown(void) // memset(&sv, 0, sizeof(sv)); memset(svs.clients, 0, svs.maxclients*sizeof(client_t)); - - cl.islocalgame = false; +end: + SV_UnlockThreadMutex(); } ///////////////////////////////////////////////////// @@ -2268,7 +2254,7 @@ static qbool SVVM_load_edict(prvm_prog_t *prog, prvm_edict_t *ent) static void SV_VM_Setup(void) { prvm_prog_t *prog = SVVM_prog; - PRVM_Prog_Init(prog, &cmd_server); + PRVM_Prog_Init(prog, cmd_local); // allocate the mempools // TODO: move the magic numbers/constants into #defines [9/13/2006 Black] @@ -2462,14 +2448,44 @@ static void SV_CheckTimeouts(void) // never timeout loopback connections for (i = (host_isclient.integer ? 1 : 0), host_client = &svs.clients[i]; i < svs.maxclients; i++, host_client++) { - if (host_client->netconnection && host.realtime > host_client->netconnection->timeout) + if (!host_client->netconnection) + continue; + + if (host.realtime > host_client->netconnection->timeout) { - Con_Printf("Client \"%s\" connection timed out\n", host_client->name); + if (host_client->begun) + SV_BroadcastPrintf("Client \"%s\" connection timed out\n", host_client->name); + else + Con_Printf("Client \"%s\" connection timed out\n", host_client->name); + SV_DropClient(false); } + else + { + // bones_was_here: if sync physics ran this frame due to expired inputtimeout, + // advance cmd.time to prevent warping caused by running sync AND async physics + if (host_client->clmovement_inputtimeout == -666 && sv_clmovement_inputtimeout_strict.integer) + host_client->cmd.time = min(host_client->cmd.time + sv.frametime, sv.time); + + // let other players know when someone has a connection problem + if (host.realtime - host_client->netconnection->lastMessageTime >= bound(sv.frametime, sv_clmovement_inputtimeout.value, 0.1)) + host_client->ping += sv.frametime; + } } } +/* +================== +SV_TimeReport + +Returns a time report string, for example for +================== +*/ +const char *SV_TimingReport(char *buf, size_t buflen) +{ + return va(buf, buflen, "%.1f%% CPU, %.2f%% lost, offset avg %.1fms, max %.1fms, sdev %.1fms", svs.perf_cpuload * 100, svs.perf_lost * 100, svs.perf_offset_avg * 1000, svs.perf_offset_max * 1000, svs.perf_offset_sdev * 1000); +} + extern cvar_t host_maxwait; extern cvar_t host_framerate; extern cvar_t cl_maxphysicsframesperserverframe; @@ -2480,9 +2496,6 @@ double SV_Frame(double time) char vabuf[1024]; qbool playing = false; - if(!sv.active) - return 0; - if (!svs.threaded) { svs.perf_acc_sleeptime = host.sleeptime; @@ -2506,7 +2519,7 @@ double SV_Frame(double time) } if(svs.perf_lost > 0 && developer_extra.integer && playing) // only complain if anyone is looking - Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); + Con_DPrintf("Server can't keep up: %s\n", SV_TimingReport(vabuf, sizeof(vabuf))); } if(svs.perf_acc_realtime > 5 || sv.time < 10) @@ -2525,8 +2538,11 @@ double SV_Frame(double time) * Receive packets on each main loop iteration, as the main loop may * be undersleeping due to select() detecting a new packet */ - NetConn_ServerFrame(); - SV_CheckTimeouts(); + if (sv.active) + { + NetConn_ServerFrame(); + SV_CheckTimeouts(); + } } /* @@ -2545,7 +2561,7 @@ double SV_Frame(double time) sv_timer = 0.1; } - if (sv_timer > 0 && !svs.threaded) + if (sv.active && sv_timer > 0 && !svs.threaded) { /* * Execute one or more server frames, with an upper limit on how much @@ -2699,7 +2715,7 @@ static int SV_ThreadFunc(void *voiddata) } if(svs.perf_lost > 0 && developer_extra.integer) if(playing) - Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); + Con_DPrintf("Server can't keep up: %s\n", SV_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; }