From 4796dcb93f1fe0af19c747e036060f02640da42c Mon Sep 17 00:00:00 2001 From: div0 Date: Wed, 23 Dec 2009 09:06:58 +0000 Subject: [PATCH] improved networking of ping and packet loss, now updates every 3 sec and distributes the bandwidth over multiple packets git-svn-id: svn://svn.icculus.org/nexuiz/trunk@8449 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/Makefile | 4 ++++ data/defaultNexuiz.cfg | 1 - data/qcsrc/client/Main.qc | 21 +++++++++++++++++ data/qcsrc/client/main.qh | 2 ++ data/qcsrc/client/sbar.qc | 30 +++++++++++------------- data/qcsrc/common/constants.qh | 1 + data/qcsrc/server/extensions.qh | 9 ++++++++ data/qcsrc/server/g_world.qc | 41 +++++++++++++++++++++++++++++++++ 8 files changed, 91 insertions(+), 18 deletions(-) diff --git a/data/Makefile b/data/Makefile index 961004f5f..105e74ebf 100644 --- a/data/Makefile +++ b/data/Makefile @@ -104,3 +104,7 @@ logupdate: .PHONY: logvupdate logvupdate: cd .. && svn log -r HEAD:BASE -v && svn up + +.PHONY: testcase +testcase: + cd qcsrc/testcase && $(FTEQCC) $(FTEQCCFLAGS) $(FTEQCCFLAGS_CSPROGS) -DTESTCASE="$$TESTCASE" diff --git a/data/defaultNexuiz.cfg b/data/defaultNexuiz.cfg index e343b7e3b..033c00249 100644 --- a/data/defaultNexuiz.cfg +++ b/data/defaultNexuiz.cfg @@ -1325,7 +1325,6 @@ seta sbar_scoreboard_highlight 1 "enable highlighting for rows and columns in th seta sbar_scoreboard_highlight_alpha 0.10 "highlight alpha value (depends on sbar_scoreboard_highlight 1)" seta sbar_scoreboard_highlight_alpha_self 0.25 "self highlight alpha value" seta sbar_hudselector 1 "0 = health/armor positions flipped, 1 = default hud layout, 2 = combined health and armor display" -seta sbar_pingrefreshinterval 10 "refesh interval of ping display in the scoreboard: range 1 - 60 (In seconds)" seta sbar_showcurrentammo 0 "0 = show all ammo types, 1 = show only the ammo type of the current weapon" seta sbar_showweaponicons 1 "1 = show icons of weapons that you have" seta sbar_timer_increment 0 "1 = show elapsed time on the timer" diff --git a/data/qcsrc/client/Main.qc b/data/qcsrc/client/Main.qc index 05cc74745..6c17f5127 100644 --- a/data/qcsrc/client/Main.qc +++ b/data/qcsrc/client/Main.qc @@ -290,6 +290,9 @@ void Playerchecker_Think() if not(e) playerslots[i] = e = spawn(); e.sv_entnum = i; + e.ping = 0; + e.ping_packetloss = 0; + e.ping_movementloss = 0; //e.gotscores = 0; // we might already have the scores... SetTeam(e, GetPlayerColor(i)); // will not hurt; later updates come with Sbar_UpdatePlayerTeams RegisterPlayer(e); @@ -1064,6 +1067,20 @@ void Net_TeamNagger() teamnagger = 1; } +void Net_ReadPingPLReport() +{ + float e, pi, pl, ml; + e = ReadByte(); + pi = ReadShort(); + pl = ReadByte(); + ml = ReadByte(); + if not(playerslots[e]) + return; + playerslots[e].ping = pi; + playerslots[e].ping_packetloss = pl / 255.0; + playerslots[e].ping_movementloss = ml / 255.0; +} + // CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer. // You must ALWAYS first acquire the temporary ID, which is sent as a byte. // Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event. @@ -1109,6 +1126,10 @@ float CSQC_Parse_TempEntity() case TE_CSQC_LIGHTNINGARC: Net_ReadLightningarc(); bHandled = true; + break; + case TE_CSQC_PINGPLREPORT: + Net_ReadPingPLReport(); + bHandled = true; break; default: // No special logic for this temporary entity; return 0 so the engine can handle it diff --git a/data/qcsrc/client/main.qh b/data/qcsrc/client/main.qh index 4f84ee8bc..1bd0512e6 100644 --- a/data/qcsrc/client/main.qh +++ b/data/qcsrc/client/main.qh @@ -158,3 +158,5 @@ float g_weaponswitchdelay; float calledhooks; #define HOOK_START 1 #define HOOK_END 2 + +.float ping, ping_packetloss, ping_movementloss; diff --git a/data/qcsrc/client/sbar.qc b/data/qcsrc/client/sbar.qc index e6b775ced..55d90987f 100644 --- a/data/qcsrc/client/sbar.qc +++ b/data/qcsrc/client/sbar.qc @@ -694,7 +694,7 @@ float sbar_field_icon2_alpha; string Sbar_GetField(entity pl, float field) { float tmp, num, denom, f; - string str, str2; + string str; sbar_field_rgb = '1 1 1'; sbar_field_icon0 = ""; sbar_field_icon1 = ""; @@ -710,23 +710,25 @@ string Sbar_GetField(entity pl, float field) case SP_PING: if not(pl.gotscores) return "\x8D\x8D\x8D"; // >>> sign - str = getplayerkey(pl.sv_entnum, "ping"); - if(str == "0") + //str = getplayerkey(pl.sv_entnum, "ping"); + f = pl.ping; + if(f == 0) return "N/A"; - tmp = max(0, min(220, stof(str)-80)) / 220; + tmp = max(0, min(220, f-80)) / 220; sbar_field_rgb = '1 1 1' - '0 1 1'*tmp; - return str; + return ftos(f); case SP_PL: if not(pl.gotscores) return "N/A"; - str = getplayerkey(pl.sv_entnum, "pl"); - str2 = getplayerkey(pl.sv_entnum, "movementloss"); - if(str == "0" && (str2 == "0" || str2 == "")) + f = pl.ping_packetloss; + tmp = pl.ping_movementloss; + if(f == 0 && tmp == 0) return ""; - tmp = bound(0, stof(str) / 20 + stof(str2) / 4, 1); // 20% is REALLY BAD pl - if not(str2 == "0" || str2 == "") - str = strcat(str, "~", str2); + str = ftos(ceil(f * 100)); + if(tmp != 0) + str = strcat(str, "~", ftos(ceil(tmp * 100))); + tmp = bound(0, f / 0.2 + tmp / 0.04, 1); // 20% is REALLY BAD pl sbar_field_rgb = '1 0.5 0.5' - '0 0.5 0.5'*tmp; return str; @@ -1237,7 +1239,6 @@ vector Sbar_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size) return pos; } -float lastpingstime; float scoreboard_bottom; float sbar_scoreboard_fade_alpha; float sbar_woulddrawscoreboard_prev; @@ -1279,11 +1280,6 @@ void Sbar_DrawScoreboard() vector rgb, pos, tmp; entity pl, tm; - if(time > lastpingstime + bound(1, cvar_or("sbar_pingrefreshinterval", 10), 60)) { - localcmd("pings\n"); - lastpingstime = time; - } - sbwidth = Sbar_GetWidth(6.5 * sbar_fontsize_y); xmin = 0.5 * (vid_conwidth - sbwidth); diff --git a/data/qcsrc/common/constants.qh b/data/qcsrc/common/constants.qh index a199dc045..b5f397033 100644 --- a/data/qcsrc/common/constants.qh +++ b/data/qcsrc/common/constants.qh @@ -52,6 +52,7 @@ const float TE_CSQC_ZCURVEPARTICLES = 103; const float TE_CSQC_NEXGUNBEAMPARTICLE = 104; const float TE_CSQC_LIGHTNINGARC = 105; const float TE_CSQC_TEAMNAGGER = 106; +const float TE_CSQC_PINGPLREPORT = 107; const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder const float RACE_NET_CHECKPOINT_CLEAR = 1; diff --git a/data/qcsrc/server/extensions.qh b/data/qcsrc/server/extensions.qh index 6a8c82690..fb03ed84f 100644 --- a/data/qcsrc/server/extensions.qh +++ b/data/qcsrc/server/extensions.qh @@ -1403,6 +1403,15 @@ float MF_TRACER3 = 128; // purple trail //description: //continuously updated field indicating client's ping (based on average of last 16 packet time differences). +//DP_SV_PING_PACKETLOSS +//idea: LordHavoc +//darkplaces implementation: LordHavoc +//field definitions: +.float ping_packetloss; +.float ping_movementloss; +//description: +//continuously updated field indicating client's packet loss, and movement loss (i.e. packet loss affecting player movement). + //DP_SV_POINTPARTICLES //idea: Spike //darkplaces implementation: LordHavoc diff --git a/data/qcsrc/server/g_world.qc b/data/qcsrc/server/g_world.qc index 466c7b693..f6fa61fe8 100644 --- a/data/qcsrc/server/g_world.qc +++ b/data/qcsrc/server/g_world.qc @@ -1,3 +1,43 @@ +entity pingplreport; +void PingPLReport_Think() +{ + float delta; + entity e; + + delta = 3 / maxclients; + if(delta < sys_frametime) + delta = 0; + self.nextthink = time + delta; + + e = edict_num(self.cnt + 1); + if(clienttype(e) == CLIENTTYPE_REAL) + { + WriteByte(MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT); + WriteByte(MSG_BROADCAST, self.cnt); + WriteShort(MSG_BROADCAST, max(1, e.ping)); + WriteByte(MSG_BROADCAST, ceil(e.ping_packetloss * 255)); + WriteByte(MSG_BROADCAST, ceil(e.ping_movementloss * 255)); + } + else + { + WriteByte(MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT); + WriteByte(MSG_BROADCAST, self.cnt); + WriteShort(MSG_BROADCAST, 0); + WriteByte(MSG_BROADCAST, 0); + WriteByte(MSG_BROADCAST, 0); + } + self.cnt = mod(self.cnt + 1, maxclients); +} +void PingPLReport_Spawn() +{ + pingplreport = spawn(); + pingplreport.classname = "pingplreport"; + pingplreport.think = PingPLReport_Think; + pingplreport.nextthink = time; +} + float SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS = 1; string redirection_target; float world_initialized; @@ -639,6 +679,7 @@ void spawnfunc_worldspawn (void) ClientInit_Spawn(); RandomSeed_Spawn(); + PingPLReport_Spawn(); localcmd("\n_sv_hook_gamestart ", GetGametype(), ";"); -- 2.39.2