Merge branch 'games-to-speak' into 'master'

Apply gamestochat restrictions to voice

See merge request kart-krew-dev/ring-racers-internal!2777
This commit is contained in:
AJ Martinez 2025-08-28 03:24:34 +00:00
commit adf4085f84
11 changed files with 130 additions and 14 deletions

View file

@ -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"
@ -233,6 +234,8 @@ static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL};
static tic_t stop_spamming[MAXPLAYERS];
static boolean IsPlayerGuest(UINT8 player);
// Generate a message for an authenticating client to sign, with some guarantees about who we are.
void GenerateChallenge(uint8_t *buf)
{
@ -3435,6 +3438,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 +3494,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 +3827,8 @@ static void Got_AddPlayer(const UINT8 **p, INT32 playernum)
}
HU_AddChatText(joinmsg, false);
SV_UpdateTempMutes();
}
if (server && multiplayer && motd[0] != '\0')
@ -3913,6 +3920,40 @@ 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]))
{
if (IsPlayerGuest(forplayer))
HU_AddChatText(va("\x82* GUESTs cannot use chat on this server. Create a profile to join in!"), false);
else
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)
{
@ -4311,7 +4352,7 @@ static size_t TotalTextCmdPerTic(tic_t tic)
}
#endif
static boolean IsPlayerGuest(int player)
static boolean IsPlayerGuest(UINT8 player)
{
return PR_IsKeyGuest(players[player].public_key);
}
@ -5327,7 +5368,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 +7584,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);

View file

@ -189,6 +189,7 @@ typedef enum
XD_TEAMCHANGE, // 41
XD_SERVERMUTEPLAYER, // 42
XD_SERVERDEAFENPLAYER, // 43
XD_SERVERTEMPMUTEPLAYER, // 44
MAXNETXCMD
} netxcmd_t;

View file

@ -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

View file

@ -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));

View file

@ -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);

View file

@ -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,50 @@ void SV_BumpMatchStats(void)
if (participated)
stat->finishedrounds++;
}
}
SV_UpdateTempMutes();
}
static void SV_UpdateTempMute(player_t *player, boolean mute)
{
UINT8 buf[2];
if (mute == !!(player->pflags2 & PF2_SERVERTEMPMUTE))
return;
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;
player_t *player = &players[i];
if (PR_IsKeyGuest(player->public_key))
{
if (cv_gamestochat.value)
SV_UpdateTempMute(player, false);
continue;
}
serverplayer_t *stat = SV_GetStatsByPlayerIndex(i);
if (i == serverplayer || IsPlayerAdmin(i))
SV_UpdateTempMute(player, false);
else if (stat->finishedrounds >= (UINT32)cv_gamestochat.value)
SV_UpdateTempMute(player, false);
else if (stat->finishedrounds < (UINT32)cv_gamestochat.value)
SV_UpdateTempMute(player, true);
}
}

View file

@ -48,6 +48,8 @@ void SV_UpdateStats(void);
void SV_BumpMatchStats(void);
void SV_UpdateTempMutes(void);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -63,8 +63,11 @@ struct Slider
arrows.x(-10 - ofs).text("\x1C");
arrows.x(kWidth + 2 + ofs).text("\x1D");
Draw::TextElement tx = Draw::TextElement().parse("<z_animated>");
h.xy(kWidth + 9, -2).text(tx.string());
if (&volume_ != &cv_voicevolume)
{
Draw::TextElement tx = Draw::TextElement().parse("<z_animated>");
h.xy(kWidth + 9, -2).text(tx.string());
}
}
h = h.y(1);
@ -85,7 +88,7 @@ struct Slider
n = std::atoi(volume_.defaultvalue);
h.x(1 + shake_ + n + (n / 10)).size(1, 7).fill(35);
if (!toggle_(false))
if (!toggle_(false) && &volume_ != &cv_voicevolume)
{
h
.x(kWidth / 2)
@ -94,6 +97,16 @@ struct Slider
.flags(V_40TRANS)
.text("S I L E N T");
}
else if (!toggle_(false))
{
h
.x(kWidth / 2)
.y(-1)
.font(Draw::Font::kThin)
.align(Draw::Align::kCenter)
.flags(V_20TRANS)
.text("DEAFENED (Voice Options)");
}
}
void input(INT32 c)

View file

@ -60,6 +60,10 @@ static void draw_routine()
V_DrawFill(x, y, range + 2, 10, 31);
V_DrawFill(x + 1, y + 1, (int) last_peak, 8, color);
if (!detected)
V_DrawThinString(x+1, y+1, V_20TRANS, "Not transmitting...");
else
V_DrawThinString(x+1, y+1, V_20TRANS|V_GREENMAP, "Transmitting");
}
static void tick_routine()

View file

@ -245,6 +245,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEUINT8(save->p, players[i].playerstate);
WRITEUINT32(save->p, players[i].pflags);
WRITEUINT32(save->p, players[i].pflags2);
WRITEUINT8(save->p, players[i].panim);
WRITEUINT8(save->p, players[i].spectator);
WRITEUINT32(save->p, players[i].spectatewait);
@ -977,6 +978,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].playerstate = (playerstate_t)READUINT8(save->p);
players[i].pflags = READUINT32(save->p);
players[i].pflags2 = READUINT32(save->p);
players[i].panim = (panim_t)READUINT8(save->p);
players[i].spectator = READUINT8(save->p);
players[i].spectatewait = READUINT32(save->p);

View file

@ -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;