]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'terencehill/survival_fixes' into 'master'
authorDr. Jaska <drjaska83@gmail.com>
Sat, 10 Jun 2023 19:26:50 +0000 (19:26 +0000)
committerDr. Jaska <drjaska83@gmail.com>
Sat, 10 Jun 2023 19:26:50 +0000 (19:26 +0000)
Survival: refactored code to prevent cheating and 2 minor fixes

See merge request xonotic/xonotic-data.pk3dir!1195

qcsrc/common/ent_cs.qc
qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc
qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc
qcsrc/common/gamemodes/gamemode/survival/cl_survival.qc
qcsrc/common/gamemodes/gamemode/survival/survival.qc
qcsrc/common/gamemodes/gamemode/survival/sv_survival.qc

index b84a98ca6d3c9d1f723eec988d7cb89bb2de9918..85119de08825c52ab9c6692d87d4d9a3eb9fd83b 100644 (file)
@@ -157,11 +157,6 @@ ENTCS_PROP(SOLID, true, sv_solid, solid, ENTCS_SET_NORMAL,
        { WriteByte(chan, ent.sv_solid); },
        { ent.sv_solid = ReadByte(); })
 
-// gamemode specific player survival status (independent of score and frags)
-ENTCS_PROP(SURVIVAL_STATUS, true, survival_status, survival_status, ENTCS_SET_NORMAL,
-       { WriteShort(chan, ent.survival_status); },
-       { ent.survival_status = ReadShort(); })
-
 #ifdef SVQC
 
        int ENTCS_PUBLICMASK = 0, ENTCS_PRIVATEMASK = 0;
index 7a16141fc8ebbe89409b947cdfd9b979da571233..f0a793afd50f4d39aa2d28fe1e3bfc313e438e43 100644 (file)
@@ -270,6 +270,9 @@ MUTATOR_HOOKFUNCTION(ca, PutClientInServer)
                        Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_JOIN_LATE);
                }
        }
+
+       if (!warmup_stage)
+               eliminatedPlayers.SendFlags |= 1;
 }
 
 MUTATOR_HOOKFUNCTION(ca, reset_map_players)
index f1e6b1ce2ec0f5b7fb3f361f9674806459d525e6..77fbfc231633cda534ad78aeca6e3484cb2cfdbf 100644 (file)
@@ -429,6 +429,11 @@ MUTATOR_HOOKFUNCTION(ft, PlayerSpawn)
        return true;
 }
 
+MUTATOR_HOOKFUNCTION(ft, PutClientInServer)
+{
+       eliminatedPlayers.SendFlags |= 1;
+}
+
 MUTATOR_HOOKFUNCTION(ft, reset_map_players)
 {
        FOREACH_CLIENT(IS_PLAYER(it), {
index 02d0907abccf0a40b28a6c388455fd962cd8f2ad..72f4b83e0c05094d69d2d1a903217349b26079c4 100644 (file)
@@ -3,14 +3,47 @@
 #include <client/draw.qh>
 #include <client/hud/panel/modicons.qh>
 
+NET_HANDLE(ENT_CLIENT_SURVIVALSTATUSES, bool isnew)
+{
+       make_pure(this);
+       int sf = 0;
+       serialize(byte, 0, sf);
+       if (sf & BIT(1))
+       {
+               for (int j = 0; j < maxclients; ++j)
+                       if (playerslots[j])
+                               playerslots[j].survival_status = SURV_STATUS_PREY;
+       }
+       if (sf & BIT(0))
+       {
+               for (int i = 1; i <= maxclients; i += 8)
+               {
+                       int f = 0;
+                       serialize(byte, 0, f);
+                       for (int b = 0; b < 8; ++b)
+                       {
+                               if (!(f & BIT(b))) continue;
+                               int j = i - 1 + b;
+                               if (playerslots[j])
+                                       playerslots[j].survival_status = SURV_STATUS_HUNTER;
+                       }
+               }
+       }
+       return true;
+}
+
 void HUD_Mod_Survival(vector pos, vector mySize)
 {
        mod_active = 1; // survival should always show the mod HUD
 
-       int mystatus = entcs_receiver(player_localnum).survival_status;
+       int mystatus = playerslots[player_localnum].survival_status;
        string player_text = "";
        vector player_color = '1 1 1';
        //string player_icon = "";
+
+       if(STAT(GAMESTARTTIME) > time || STAT(ROUNDSTARTTIME) > time || entcs_IsSpectating(player_localnum))
+               return;
+
        if(mystatus == SURV_STATUS_HUNTER)
        {
                player_text = _("Hunter");
@@ -23,11 +56,6 @@ void HUD_Mod_Survival(vector pos, vector mySize)
                player_color = '0 1 0';
                //player_icon = "player_neutral";
        }
-       else
-       {
-               // if the player has no valid status, don't draw anything
-               return;
-       }
 
        drawstring_aspect(pos, player_text, vec2(mySize.x, mySize.y), player_color, panel_fg_alpha, DRAWFLAG_NORMAL);
 }
@@ -40,9 +68,9 @@ MUTATOR_HOOKFUNCTION(cl_surv, ForcePlayercolors_Skip, CBC_ORDER_LAST)
                return false;
 
        entity player = M_ARGV(0, entity);
-       entity e = entcs_receiver(player.entnum - 1);
-       int surv_status = ((e) ? e.survival_status : 0);
-       int mystatus = entcs_receiver(player_localnum).survival_status;
+       entity e = playerslots[player.entnum - 1];
+       int surv_status = ((e) ? e.survival_status : SURV_COLOR_PREY);
+       int mystatus = playerslots[player_localnum].survival_status;
 
        int plcolor = SURV_COLOR_PREY; // default to survivor
        if((mystatus == SURV_STATUS_HUNTER || intermission || STAT(GAME_STOPPED)) && surv_status == SURV_STATUS_HUNTER)
index 1f2d1440224a593013f901868d688cd10424e5e3..a8a67ad44efe5e76395c1587fe1b13c4ea2ff201 100644 (file)
@@ -1 +1,2 @@
 #include "survival.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_SURVIVALSTATUSES)
index 6414686e0bcc67638503f6aaeda15ecb9e67754b..83817ac8ed3b7c5ff4ed10aac939ac4fb3cd85f1 100644 (file)
@@ -8,6 +8,53 @@ bool autocvar_g_survival_reward_survival = true;
 
 void nades_Clear(entity player);
 
+entity survivalStatuses;
+void SurvivalStatuses_Init();
+
+void SurvivalStatuses_Send()
+{
+       // SendFlags can be set to anything != 0, SurvivalStatuses_SendEntity won't use its value
+       survivalStatuses.SendFlags = 1;
+}
+
+bool SurvivalStatuses_SendEntity(entity this, entity dest, float sendflags)
+{
+       Stream out = MSG_ENTITY;
+       WriteHeader(out, ENT_CLIENT_SURVIVALSTATUSES);
+
+       sendflags = BIT(0) | BIT(1);
+
+       // send hunter statuses only to hunters
+       bool send_hunter_statuses = (dest.survival_status == SURV_STATUS_HUNTER || STAT(GAME_STOPPED));
+       if (!send_hunter_statuses)
+               sendflags &= !BIT(0);
+
+       serialize(byte, out, sendflags);
+       if (sendflags & BIT(0)) {
+               for (int i = 1; i <= maxclients; i += 8) {
+                       int f = 0;
+                       entity e = edict_num(i);
+                       for (int b = 0; b < 8; ++b, e = nextent(e)) {
+                               bool is_hunter = (IS_PLAYER(e) && e.survival_status == SURV_STATUS_HUNTER);
+                               if (is_hunter)
+                                       f |= BIT(b);
+                       }
+                       serialize(byte, out, f);
+               }
+       }
+       return true;
+}
+
+void SurvivalStatuses_Init()
+{
+       if(survivalStatuses)
+       {
+               backtrace("Can't spawn survivalStatuses again!");
+               return;
+       }
+       Net_LinkEntity(survivalStatuses = new_pure(survivalStatuses), false, 0, SurvivalStatuses_SendEntity);
+}
+
 void Surv_UpdateScores(bool timed_out)
 {
        // give players their hard-earned kills now that the round is over
@@ -119,6 +166,7 @@ void Surv_RoundStart()
                total_hunters++;
                it.survival_status = SURV_STATUS_HUNTER;
        });
+       SurvivalStatuses_Send();
 
        FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
        {
@@ -181,6 +229,7 @@ void surv_Initialize() // run at the start of a match, initiates game mode
        round_handler_Spawn(Surv_CheckPlayers, Surv_CheckWinner, Surv_RoundStart);
        round_handler_Init(5, autocvar_g_survival_warmup, autocvar_g_survival_round_timelimit);
        EliminatedPlayers_Init(surv_isEliminated);
+       SurvivalStatuses_Init();
 }
 
 
@@ -211,7 +260,7 @@ MUTATOR_HOOKFUNCTION(surv, PlayerPreThink)
 {
        entity player = M_ARGV(0, entity);
 
-       if(IS_PLAYER(player) || INGAME_JOINED(player))
+       if(IS_PLAYER(player) || INGAME(player))
        {
                // update the scoreboard colour display to out the real killer at the end of the round
                // running this every frame to avoid cheats
@@ -258,6 +307,9 @@ MUTATOR_HOOKFUNCTION(surv, PutClientInServer)
                        Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_JOIN_LATE);
                }
        }
+
+       if (!warmup_stage)
+               eliminatedPlayers.SendFlags |= 1;
 }
 
 MUTATOR_HOOKFUNCTION(surv, reset_map_players)
@@ -273,6 +325,7 @@ MUTATOR_HOOKFUNCTION(surv, reset_map_players)
                }
        });
        bot_relinkplayerlist();
+       SurvivalStatuses_Send();
        return true;
 }