From 5e255d7a33f03f4b2d543c72c4401e13f6ecc9d5 Mon Sep 17 00:00:00 2001 From: Mario Date: Sat, 3 Mar 2018 23:39:22 +1000 Subject: [PATCH] Bring back the FPS counter in the scoreboard --- qcsrc/client/hud/panel/scoreboard.qc | 17 +++++++++++++++- qcsrc/client/view.qc | 30 ++++++++++++++++++++++++++++ qcsrc/common/net_linked.qh | 2 ++ qcsrc/common/scores.qh | 2 ++ qcsrc/common/stats.qh | 5 +++++ qcsrc/lib/net.qh | 9 +++++++++ qcsrc/server/client.qc | 7 +++++++ qcsrc/server/scores.qc | 22 ++++++++++++++++++++ qcsrc/server/scores.qh | 8 ++++++++ qcsrc/server/scores_rules.qc | 3 +++ xonotic-server.cfg | 2 ++ 11 files changed, 106 insertions(+), 1 deletion(-) diff --git a/qcsrc/client/hud/panel/scoreboard.qc b/qcsrc/client/hud/panel/scoreboard.qc index 200f5b2c5..f914df7dd 100644 --- a/qcsrc/client/hud/panel/scoreboard.qc +++ b/qcsrc/client/hud/panel/scoreboard.qc @@ -309,6 +309,7 @@ void Cmd_Scoreboard_Help() LOG_INFO(_("^3ping^7 Ping time")); LOG_INFO(_("^3pl^7 Packet loss")); LOG_INFO(_("^3elo^7 Player ELO")); + LOG_INFO(_("^3fps^7 Player FPS")); LOG_INFO(_("^3kills^7 Number of kills")); LOG_INFO(_("^3deaths^7 Number of deaths")); LOG_INFO(_("^3suicides^7 Number of suicides")); @@ -359,7 +360,7 @@ void Cmd_Scoreboard_Help() // otherwise the previous exclusive rule warns anyway // e.g. -teams,rc,cts,lms/kills ?+rc/kills #define SCOREBOARD_DEFAULT_COLUMNS \ -"ping pl name |" \ +"ping pl fps name |" \ " -teams,rc,cts,inv,lms/kills +ft,tdm/kills ?+rc,inv/kills" \ " -teams,lms/deaths +ft,tdm/deaths" \ " +tdm/sum" \ @@ -464,6 +465,7 @@ void Cmd_Scoreboard_SetFields(int argc) case "elo": sbt_field[sbt_num_fields] = SP_ELO; break; case "dmg": case "damage": sbt_field[sbt_num_fields] = SP_DMG; break; case "dmgtaken": case "damagetaken": sbt_field[sbt_num_fields] = SP_DMGTAKEN; break; + case "fps": sbt_field[sbt_num_fields] = SP_FPS; break; default: { FOREACH(Scores, true, { @@ -679,6 +681,19 @@ string Scoreboard_GetField(entity pl, PlayerScoreField field) } } + case SP_FPS: + { + float fps = pl.(scores(SP_FPS)); + if(fps == 0) + { + sbt_field_rgb = '1 1 1'; + return ((pl.ping == 0) ? _("N/A") : "..."); // if 0 ping, either connecting or bot (either case can't show proper score) + } + //sbt_field_rgb = HUD_Get_Num_Color(fps, 200); + sbt_field_rgb = '1 0 0' + '0 1 1' * (bound(0, fps, 60) / 60); + return ftos(fps); + } + case SP_DMG: case SP_DMGTAKEN: return sprintf("%.1f k", pl.(scores(field)) / 1000); diff --git a/qcsrc/client/view.qc b/qcsrc/client/view.qc index 9bfa8db9a..dd184bee9 100644 --- a/qcsrc/client/view.qc +++ b/qcsrc/client/view.qc @@ -370,6 +370,35 @@ STATIC_INIT(viewmodel) { viewmodels[slot] = new(viewmodel); } +float showfps_prevfps; +float showfps_prevfps_time; +int showfps_framecounter; + +void fpscounter_update() +{ + if(!STAT(SHOWFPS)) + return; + + float currentTime = gettime(GETTIME_REALTIME); + showfps_framecounter += 1; + if(currentTime - showfps_prevfps_time > STAT(SHOWFPS)) + { + showfps_prevfps = showfps_framecounter/(currentTime - showfps_prevfps_time); + showfps_framecounter = 0; + showfps_prevfps_time = currentTime; + + int channel = MSG_C2S; + WriteHeader(channel, fpsreport); + WriteShort(channel, bound(0, rint(showfps_prevfps), 65535)); // prevent insane fps values + } +} + +STATIC_INIT(fpscounter_init) +{ + float currentTime = gettime(GETTIME_REALTIME); + showfps_prevfps_time = currentTime; // we must initialize it to avoid an instant low frame sending +} + void Porto_Draw(entity this); STATIC_INIT(Porto) { @@ -1866,6 +1895,7 @@ void CSQC_UpdateView(entity this, float w, float h) TargetMusic_Advance(); Fog_Force(); + fpscounter_update(); if(drawtime == 0) drawframetime = 0.01666667; // when we don't know fps yet, we assume 60fps diff --git a/qcsrc/common/net_linked.qh b/qcsrc/common/net_linked.qh index 7b69ad503..657e76171 100644 --- a/qcsrc/common/net_linked.qh +++ b/qcsrc/common/net_linked.qh @@ -55,3 +55,5 @@ REGISTER_NET_LINKED(ENT_CLIENT_SPAWNEVENT) REGISTER_NET_LINKED(ENT_CLIENT_WALL) #include + +REGISTER_NET_C2S(fpsreport) diff --git a/qcsrc/common/scores.qh b/qcsrc/common/scores.qh index 476d0dbba..377a78077 100644 --- a/qcsrc/common/scores.qh +++ b/qcsrc/common/scores.qh @@ -39,6 +39,8 @@ REGISTER_SP(FRAGS); REGISTER_SP(ELO); +REGISTER_SP(FPS); + // TODO: move to common mutators REGISTER_SP(RACE_TIME); diff --git a/qcsrc/common/stats.qh b/qcsrc/common/stats.qh index db681315a..648ef60e8 100644 --- a/qcsrc/common/stats.qh +++ b/qcsrc/common/stats.qh @@ -121,6 +121,11 @@ REGISTER_STAT(ENTRAP_ORB_ALPHA, float) REGISTER_STAT(ITEMSTIME, int, autocvar_sv_itemstime) REGISTER_STAT(KILL_TIME, float) +#ifdef SVQC +float autocvar_sv_showfps = 5; +#endif +REGISTER_STAT(SHOWFPS, float, autocvar_sv_showfps) + #ifdef SVQC bool autocvar_g_ctf_leaderboard; #endif diff --git a/qcsrc/lib/net.qh b/qcsrc/lib/net.qh index b1f5326a9..fe2952e2c 100644 --- a/qcsrc/lib/net.qh +++ b/qcsrc/lib/net.qh @@ -304,6 +304,11 @@ MACRO_END if (g_buf) strunzone(g_buf); g_buf = strzone(tmp); } + void WriteShort(int to, int b) + { + WriteByte(to, (b >> 8) & 0xFF); + WriteByte(to, b & 0xFF); + } #elif defined(SVQC) int ReadByte() { @@ -311,6 +316,10 @@ MACRO_END ydec_single(g_buf, ret); return ret; } + int ReadShort() + { + return (ReadByte() << 8) | (ReadByte()); + } void WriteByte(int to, int b); #endif diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index 5a199e06d..e898e74e8 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -2833,3 +2833,10 @@ void PM_UpdateButtons(entity this, entity store) store.v_angle = this.v_angle; store.movement = this.movement; } + +NET_HANDLE(fpsreport, bool) +{ + int fps = ReadShort(); + PlayerScore_Set(sender, SP_FPS, fps); + return true; +} diff --git a/qcsrc/server/scores.qc b/qcsrc/server/scores.qc index c9948660e..3f1db4290 100644 --- a/qcsrc/server/scores.qc +++ b/qcsrc/server/scores.qc @@ -353,6 +353,28 @@ float PlayerScore_Add(entity player, PlayerScoreField scorefield, float score) return s.(scores(scorefield)); } +float PlayerScore_Set(entity player, PlayerScoreField scorefield, float score) +{ + if(!scores_initialized) return 0; // FIXME remove this when everything uses this system + entity s = CS(player).scorekeeper; + if(!s) + { + if(game_stopped) + return 0; + LOG_WARN("Setting score of unknown player!"); + return 0; + } + + float oldscore = s.(scores(scorefield)); + if(oldscore == score) + return oldscore; + + if(scores_label(scorefield) != "") + s.SendFlags |= (2 ** (scorefield.m_id % 16)); + s.(scores(scorefield)) = score; + return s.(scores(scorefield)); +} + float PlayerTeamScore_Add(entity player, PlayerScoreField pscorefield, float tscorefield, float score) { float r; diff --git a/qcsrc/server/scores.qh b/qcsrc/server/scores.qh index e2a57f43f..ad4061966 100644 --- a/qcsrc/server/scores.qh +++ b/qcsrc/server/scores.qh @@ -24,6 +24,14 @@ void PlayerScore_Detach(entity player); */ float PlayerScore_Add(entity player, PlayerScoreField scorefield, float score); +/** + * Sets the player's score to the score parameter. + * NEVER call this if PlayerScore_Attach has not been called yet! + * Means: FIXME make players unable to join the game when not called ClientConnect yet. + * Returns the new (or old if unchanged) score. + */ +float PlayerScore_Set(entity player, PlayerScoreField scorefield, float score); + /** * \brief Returns the player's score. * \param[in] player Player to inspect. diff --git a/qcsrc/server/scores_rules.qc b/qcsrc/server/scores_rules.qc index 8d87407e6..64c94001f 100644 --- a/qcsrc/server/scores_rules.qc +++ b/qcsrc/server/scores_rules.qc @@ -55,6 +55,9 @@ void ScoreRules_basics(int teams, float sprio, float stprio, float score_enabled ScoreInfo_SetLabel_PlayerScore(SP_DMG, "dmg", 0); ScoreInfo_SetLabel_PlayerScore(SP_DMGTAKEN, "dmgtaken", SFL_LOWER_IS_BETTER); ScoreInfo_SetLabel_PlayerScore(SP_ELO, "elo", 0); + + if(STAT(SHOWFPS)) + ScoreInfo_SetLabel_PlayerScore(SP_FPS, "fps", 0); } void ScoreRules_basics_end() { diff --git a/xonotic-server.cfg b/xonotic-server.cfg index 7b6504d51..8f1457a03 100644 --- a/xonotic-server.cfg +++ b/xonotic-server.cfg @@ -555,3 +555,5 @@ set sv_simple_items 1 "allow or forbid client use of simple items" set sv_showspectators 1 "Show who's spectating who in the player info panel when client has cl_showspectators on. Shouldn't be used on competitive servers, also disable when watching a suspected cheater" set sv_damagetext 2 "<= 0: disabled, >= 1: visible to spectators, >= 2: visible to attacker, >= 3: all players see everyone's damage" + +set sv_showfps 5 "Show player's FPS counters in the scoreboard. This setting acts as a delay in seconds between updates" -- 2.39.2