From 8a87f0ed7d2525c261630cea46edfeee48defc25 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 27 Aug 2025 20:38:45 -0400 Subject: [PATCH] Apply gamestochat restrictions to voice --- src/d_clisrv.c | 36 ++++++++++++++++++++++++++++-- src/d_netcmd.h | 1 + src/d_player.h | 2 ++ src/g_game.c | 2 +- src/k_hud.cpp | 4 ++-- src/k_serverstats.c | 53 +++++++++++++++++++++++++++++++++++++++++---- src/k_serverstats.h | 2 ++ src/y_inter.cpp | 2 +- 8 files changed, 92 insertions(+), 10 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 46466b399..c2dc256cf 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -73,6 +73,7 @@ #include "r_fps.h" #include "filesrch.h" // refreshdirmenu #include "k_objects.h" +#include "k_serverstats.h" // updatemutes // cl loading screen #include "v_video.h" @@ -3435,6 +3436,7 @@ static void Got_RemovePlayer(const UINT8 **p, INT32 playernum); static void Got_AddBot(const UINT8 **p, INT32 playernum); static void Got_ServerMutePlayer(const UINT8 **p, INT32 playernum); static void Got_ServerDeafenPlayer(const UINT8 **p, INT32 playernum); +static void Got_ServerTempMutePlayer(const UINT8 **p, INT32 playernum); void Joinable_OnChange(void); void Joinable_OnChange(void) @@ -3490,6 +3492,7 @@ void D_ClientServerInit(void) COM_AddCommand("serverdeafen", Command_ServerDeafen); COM_AddCommand("serverundeafen", Command_ServerUndeafen); RegisterNetXCmd(XD_SERVERMUTEPLAYER, Got_ServerMutePlayer); + RegisterNetXCmd(XD_SERVERTEMPMUTEPLAYER, Got_ServerTempMutePlayer); RegisterNetXCmd(XD_SERVERDEAFENPLAYER, Got_ServerDeafenPlayer); gametic = 0; @@ -3822,6 +3825,7 @@ static void Got_AddPlayer(const UINT8 **p, INT32 playernum) } HU_AddChatText(joinmsg, false); + SV_UpdateTempMutes(); } if (server && multiplayer && motd[0] != '\0') @@ -3913,6 +3917,34 @@ static void Got_ServerMutePlayer(const UINT8 **p, INT32 playernum) } } +// Xcmd XD_SERVERTEMPMUTEPLAYER +static void Got_ServerTempMutePlayer(const UINT8 **p, INT32 playernum) +{ + UINT8 forplayer = READUINT8(*p); + UINT8 muted = READUINT8(*p); + if (playernum != serverplayer) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal server mute player cmd from %s\n"), player_names[playernum]); + if (server) + { + SendKick(playernum, KICK_MSG_CON_FAIL); + } + } + if (muted && !(players[forplayer].pflags2 & PF2_SERVERTEMPMUTE)) + { + players[forplayer].pflags2 |= PF2_SERVERTEMPMUTE; + if (P_IsMachineLocalPlayer(&players[forplayer])) + HU_AddChatText(va("\x82* You are temporarily muted until you finish more rounds."), false); + } + else if (!muted && players[forplayer].pflags2 & PF2_SERVERTEMPMUTE) + { + players[forplayer].pflags2 &= ~PF2_SERVERTEMPMUTE; + if (P_IsMachineLocalPlayer(&players[forplayer])) + HU_AddChatText(va("\x82* You've now finished enough rounds to use chat."), false); + } +} + + // Xcmd XD_SERVERDEAFENPLAYER static void Got_ServerDeafenPlayer(const UINT8 **p, INT32 playernum) { @@ -5327,7 +5359,7 @@ static void PT_HandleVoiceServer(SINT8 node) } player = &players[playernum]; - if (player->pflags2 & (PF2_SELFMUTE | PF2_SELFDEAFEN | PF2_SERVERMUTE | PF2_SERVERDEAFEN)) + if (player->pflags2 & (PF2_SELFMUTE | PF2_SELFDEAFEN | PF2_SERVERMUTE | PF2_SERVERDEAFEN | PF2_SERVERTEMPMUTE)) { // ignore, they should not be able to broadcast voice return; @@ -7543,7 +7575,7 @@ void NetVoiceUpdate(void) // 1. In a netgame, // 2. Not self-muted by cvar // 3. The consoleplayer is not server or self muted or deafened - if (netgame && !cv_voice_selfmute.value && !(players[consoleplayer].pflags2 & (PF2_SERVERMUTE | PF2_SELFMUTE | PF2_SELFDEAFEN | PF2_SERVERDEAFEN))) + if (netgame && !cv_voice_selfmute.value && !(players[consoleplayer].pflags2 & (PF2_SERVERMUTE | PF2_SELFMUTE | PF2_SERVERTEMPMUTE | PF2_SELFDEAFEN | PF2_SERVERDEAFEN))) { DoVoicePacket(servernode, g_local_opus_frame, encoded, result); S_SetPlayerVoiceActive(consoleplayer); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index c983bdeeb..36a0ed134 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -189,6 +189,7 @@ typedef enum XD_TEAMCHANGE, // 41 XD_SERVERMUTEPLAYER, // 42 XD_SERVERDEAFENPLAYER, // 43 + XD_SERVERTEMPMUTEPLAYER, // 44 MAXNETXCMD } netxcmd_t; diff --git a/src/d_player.h b/src/d_player.h index cdcaa6562..c8323be13 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -148,6 +148,8 @@ typedef enum PF2_BUBBLECONTACT = 1<<7, // ACHTUNG VERY BAD HACK - Don't allow Bubble Shield to contact certain objects unless this is a fresh blowup. PF2_SUPERTRANSFERVFX = 1<<8, // Don't respawn the "super transfer available" VFX. PF2_FASTTUMBLEBOUNCE = 1<<9, // Don't lose speed when tumblebouncing. + + PF2_SERVERTEMPMUTE = 1<<10, // Haven't met gamestochat requirement } pflags2_t; typedef enum diff --git a/src/g_game.c b/src/g_game.c index 487a26116..31cd80b9a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2407,7 +2407,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) xtralife = players[player].xtralife; pflags = (players[player].pflags & (PF_WANTSTOJOIN|PF_KICKSTARTACCEL|PF_SHRINKME|PF_SHRINKACTIVE|PF_AUTOROULETTE|PF_ANALOGSTICK|PF_AUTORING)); - pflags2 = (players[player].pflags2 & (PF2_SELFMUTE | PF2_SELFDEAFEN | PF2_SERVERMUTE | PF2_SERVERDEAFEN | PF2_STRICTFASTFALL)); + pflags2 = (players[player].pflags2 & (PF2_SELFMUTE | PF2_SELFDEAFEN | PF2_SERVERTEMPMUTE | PF2_SERVERMUTE | PF2_SERVERDEAFEN | PF2_STRICTFASTFALL)); // SRB2kart memcpy(&itemRoulette, &players[player].itemRoulette, sizeof (itemRoulette)); diff --git a/src/k_hud.cpp b/src/k_hud.cpp index dbaf90bfa..9734d8cdc 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -3003,7 +3003,7 @@ void PositionFacesInfo::draw_1p() { voxmic = kp_voice_remotedeafened; } - else if (players[rankplayer[i]].pflags2 & (PF2_SELFMUTE | PF2_SERVERMUTE)) + else if (players[rankplayer[i]].pflags2 & (PF2_SELFMUTE | PF2_SERVERMUTE | PF2_SERVERTEMPMUTE)) { voxmic = kp_voice_remotemuted; } @@ -8283,7 +8283,7 @@ void K_drawKartHUD(void) if (netgame && cv_voice_allowservervoice.value == 1) { - if (players[consoleplayer].pflags2 & (PF2_SELFMUTE | PF2_SERVERMUTE | PF2_SELFDEAFEN | PF2_SERVERDEAFEN)) + if (players[consoleplayer].pflags2 & (PF2_SELFMUTE | PF2_SERVERMUTE | PF2_SERVERTEMPMUTE | PF2_SELFDEAFEN | PF2_SERVERDEAFEN)) { patch_t* micmuted = kp_voice_localmuted; V_DrawFixedPatch(-1 * FRACUNIT, (BASEVIDHEIGHT - 21) << FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, micmuted, NULL); diff --git a/src/k_serverstats.c b/src/k_serverstats.c index 4556b84a9..32564da9d 100644 --- a/src/k_serverstats.c +++ b/src/k_serverstats.c @@ -20,6 +20,7 @@ #include "k_serverstats.h" #include "z_zone.h" #include "time.h" +#include "d_netcmd.h" // isplayeradmin static serverplayer_t *trackedList; static size_t numtracked = 0; @@ -231,7 +232,7 @@ serverplayer_t *SV_GetStats(player_t *player) // Write clientpowerlevels and timestamps back to matching trackedList entries, then save trackedList to disk // (NB: Stats changes can be made directly to trackedList through other paths, but will only write to disk here) void SV_UpdateStats(void) -{ +{ UINT32 i, j, hash; if (!server) @@ -250,7 +251,7 @@ void SV_UpdateStats(void) hash = quickncasehash((char*)players[i].public_key, PUBKEYLENGTH); for(j = 0; j < numtracked; j++) - { + { if (hash != trackedList[j].hash) // Not crypto magic, just an early out with a faster comparison continue; if (memcmp(&trackedList[j].public_key, players[i].public_key, PUBKEYLENGTH) == 0) @@ -265,6 +266,7 @@ void SV_UpdateStats(void) // so this shouldn't be reachable. } + SV_UpdateTempMutes(); SV_SaveStats(); } @@ -272,6 +274,9 @@ void SV_BumpMatchStats(void) { int i; + if (!server) + return; + for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) @@ -284,7 +289,7 @@ void SV_BumpMatchStats(void) serverplayer_t *stat = SV_GetStatsByPlayerIndex(i); // It should never be advantageous to idle, only count rounds where the player accomplishes something. - // If you NO CONTESTed, assume no participation... + // If you NO CONTESTed, assume no participation... boolean participated = !(players[i].pflags & PF_NOCONTEST); if (gametyperules & GTR_CIRCUIT) @@ -303,4 +308,44 @@ void SV_BumpMatchStats(void) if (participated) stat->finishedrounds++; } -} \ No newline at end of file + + SV_UpdateTempMutes(); +} + +static void SV_UpdateTempMute(player_t *player, boolean mute) +{ + UINT8 buf[2]; + + buf[0] = player - players; + buf[1] = (UINT8)(mute); + SendNetXCmd(XD_SERVERTEMPMUTEPLAYER, &buf, 2); +} + +void SV_UpdateTempMutes(void) +{ + int i; + + if (!server) + return; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + if (players[i].spectator) + continue; + if (PR_IsKeyGuest(players[i].public_key)) + continue; + + player_t *player = &players[i]; + + serverplayer_t *stat = SV_GetStatsByPlayerIndex(i); + + if (i == serverplayer || IsPlayerAdmin(i)) + SV_UpdateTempMute(player, false); + else if (stat->finishedrounds >= (UINT32)cv_gamestochat.value && player->pflags2 & PF2_SERVERTEMPMUTE) + SV_UpdateTempMute(player, false); + else if (stat->finishedrounds < (UINT32)cv_gamestochat.value && !(player->pflags2 & PF2_SERVERTEMPMUTE)) + SV_UpdateTempMute(player, true); + } +} diff --git a/src/k_serverstats.h b/src/k_serverstats.h index 3273351dc..ab3d5be0e 100644 --- a/src/k_serverstats.h +++ b/src/k_serverstats.h @@ -48,6 +48,8 @@ void SV_UpdateStats(void); void SV_BumpMatchStats(void); +void SV_UpdateTempMutes(void); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/y_inter.cpp b/src/y_inter.cpp index 1f3dffee9..3ed2b82fc 100644 --- a/src/y_inter.cpp +++ b/src/y_inter.cpp @@ -814,7 +814,7 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) voxxoffs = 1; voxyoffs = -5; } - else if (players[pnum].pflags2 & (PF2_SELFMUTE | PF2_SERVERMUTE)) + else if (players[pnum].pflags2 & (PF2_SELFMUTE | PF2_SERVERMUTE | PF2_SERVERTEMPMUTE)) { voxpat = (patch_t*) W_CachePatchName("VOXCRM", PU_HUDGFX); voxxoffs = 1;