Add some options, maxplayer/allownewplayer dont need to be netvars anymore

This commit is contained in:
Sally Coolatta 2020-08-22 01:53:27 -04:00
parent 8ff62cdc7f
commit 571c670670
6 changed files with 234 additions and 34 deletions

View file

@ -3257,14 +3257,16 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}};
consvar_t cv_netticbuffer = {"netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_netticbuffer = {"netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_allownewplayer = {"allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; static void Joinable_OnChange(void);
consvar_t cv_allownewplayer = {"allowjoin", "On", CV_SAVE|CV_CALL, CV_OnOff, Joinable_OnChange, 0, NULL, NULL, 0, 0, NULL};
#ifdef VANILLAJOINNEXTROUND #ifdef VANILLAJOINNEXTROUND
consvar_t cv_joinnextround = {"joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done consvar_t cv_joinnextround = {"joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done
#endif #endif
static void MaxPlayers_OnChange(void);
static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {MAXPLAYERS, "MAX"}, {0, NULL}}; static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {MAXPLAYERS, "MAX"}, {0, NULL}};
consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE|CV_NETVAR|CV_CALL, maxplayers_cons_t, MaxPlayers_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE|CV_CALL, maxplayers_cons_t, Joinable_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t resynchattempts_cons_t[] = {{0, "MIN"}, {20, "MAX"}, {0, NULL}}; static CV_PossibleValue_t resynchattempts_cons_t[] = {{0, "MIN"}, {20, "MAX"}, {0, NULL}};
consvar_t cv_resynchattempts = {"resynchattempts", "5", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL }; consvar_t cv_resynchattempts = {"resynchattempts", "5", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL };
@ -3282,10 +3284,10 @@ consvar_t cv_downloadspeed = {"downloadspeed", "16", CV_SAVE, downloadspeed_cons
static void Got_AddPlayer(UINT8 **p, INT32 playernum); static void Got_AddPlayer(UINT8 **p, INT32 playernum);
static void Got_RemovePlayer(UINT8 **p, INT32 playernum); static void Got_RemovePlayer(UINT8 **p, INT32 playernum);
static void MaxPlayers_OnChange(void) static void Joinable_OnChange(void)
{ {
#ifdef HAVE_DISCORDRPC #ifdef HAVE_DISCORDRPC
DRPC_UpdatePresence(); DRPC_SendDiscordInfo();
#else #else
return; return;
#endif #endif

View file

@ -712,6 +712,10 @@ void D_RegisterServerCommands(void)
#endif #endif
CV_RegisterVar(&cv_dummyconsvar); CV_RegisterVar(&cv_dummyconsvar);
#ifdef HAVE_DISCORDRPC
RegisterNetXCmd(XD_DISCORD, DRPC_RecieveDiscordInfo);
#endif
} }
// ========================================================================= // =========================================================================
@ -1007,6 +1011,9 @@ void D_RegisterClientCommands(void)
#ifdef HAVE_DISCORDRPC #ifdef HAVE_DISCORDRPC
CV_RegisterVar(&cv_discordrp); CV_RegisterVar(&cv_discordrp);
CV_RegisterVar(&cv_discordstreamer);
CV_RegisterVar(&cv_discordasks);
CV_RegisterVar(&cv_discordinvites);
#endif #endif
} }

View file

@ -181,6 +181,9 @@ typedef enum
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
XD_LUACMD, // 26 XD_LUACMD, // 26
XD_LUAVAR, // 27 XD_LUAVAR, // 27
#endif
#ifdef HAVE_DISCORDRPC
XD_DISCORD, // 28
#endif #endif
MAXNETXCMD MAXNETXCMD
} netxcmd_t; } netxcmd_t;

View file

@ -27,6 +27,7 @@
#include "mserv.h" // ms_RoomId #include "mserv.h" // ms_RoomId
#include "z_zone.h" #include "z_zone.h"
#include "m_random.h" // P_GetInitSeed #include "m_random.h" // P_GetInitSeed
#include "byteptr.h"
#include "discord.h" #include "discord.h"
#include "doomdef.h" #include "doomdef.h"
@ -38,6 +39,13 @@
#define IP_SIZE 16 #define IP_SIZE 16
consvar_t cv_discordrp = {"discordrp", "On", CV_SAVE|CV_CALL, CV_OnOff, DRPC_UpdatePresence, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_discordrp = {"discordrp", "On", CV_SAVE|CV_CALL, CV_OnOff, DRPC_UpdatePresence, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_discordstreamer = {"discordstreamer", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_discordasks = {"discordasks", "Yes", CV_SAVE|CV_CALL, CV_YesNo, DRPC_UpdatePresence, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t discordinvites_cons_t[] = {{0, "Admins Only"}, {1, "Everyone"}, {0, NULL}};
consvar_t cv_discordinvites = {"discordinvites", "Everyone", CV_SAVE|CV_CALL, discordinvites_cons_t, DRPC_SendDiscordInfo, 0, NULL, NULL, 0, 0, NULL};
struct discordInfo_s discordInfo;
discordRequest_t *discordRequestList = NULL; discordRequest_t *discordRequestList = NULL;
@ -86,9 +94,16 @@ static char *DRPC_XORIPString(const char *input)
None None
--------------------------------------------------*/ --------------------------------------------------*/
static void DRPC_HandleReady(const DiscordUser *user) static void DRPC_HandleReady(const DiscordUser *user)
{
if (cv_discordstreamer.value)
{
CONS_Printf("Discord: connected to %s\n", user->username);
}
else
{ {
CONS_Printf("Discord: connected to %s#%s (%s)\n", user->username, user->discriminator, user->userId); CONS_Printf("Discord: connected to %s#%s (%s)\n", user->username, user->discriminator, user->userId);
} }
}
/*-------------------------------------------------- /*--------------------------------------------------
static void DRPC_HandleDisconnect(int err, const char *msg) static void DRPC_HandleDisconnect(int err, const char *msg)
@ -145,6 +160,50 @@ static void DRPC_HandleJoin(const char *secret)
free(ip); free(ip);
} }
/*--------------------------------------------------
static boolean DRPC_InvitesAreAllowed(void)
Determines whenever or not invites or
ask to join requests are allowed.
Input Arguments:-
None
Return:-
true if invites are allowed, false otherwise.
--------------------------------------------------*/
static boolean DRPC_InvitesAreAllowed(void)
{
if (!Playing())
{
// We're not playing, so we should not be getting invites.
return false;
}
if (cv_discordasks.value == 0)
{
// Client has the CVar set to off, so never allow invites from this client.
return false;
}
if (discordInfo.joinsAllowed == true)
{
if (discordInfo.everyoneCanInvite == true)
{
// Everyone's allowed!
return true;
}
else if (consoleplayer == serverplayer || IsPlayerAdmin(consoleplayer))
{
// Only admins are allowed!
return true;
}
}
// Did not pass any of the checks
return false;
}
/*-------------------------------------------------- /*--------------------------------------------------
static void DRPC_HandleJoinRequest(const DiscordUser *requestUser) static void DRPC_HandleJoinRequest(const DiscordUser *requestUser)
@ -161,16 +220,25 @@ static void DRPC_HandleJoin(const char *secret)
static void DRPC_HandleJoinRequest(const DiscordUser *requestUser) static void DRPC_HandleJoinRequest(const DiscordUser *requestUser)
{ {
discordRequest_t *append = discordRequestList; discordRequest_t *append = discordRequestList;
discordRequest_t *newRequest = Z_Calloc(sizeof(discordRequest_t), PU_STATIC, NULL); discordRequest_t *newRequest;
// Discord requests exprie after 30 seconds if (DRPC_InvitesAreAllowed() == false)
{
// Something weird happened if this occurred...
Discord_Respond(requestUser->userId, DISCORD_REPLY_IGNORE);
return;
}
newRequest = Z_Calloc(sizeof(discordRequest_t), PU_STATIC, NULL);
// Discord requests expire after 30 seconds
newRequest->timer = (30*TICRATE)-1; newRequest->timer = (30*TICRATE)-1;
newRequest->username = Z_Calloc(344+1+8, PU_STATIC, NULL); newRequest->username = Z_Calloc(344, PU_STATIC, NULL);
snprintf(newRequest->username, 344+1+8, "%s#%s", snprintf(newRequest->username, 344, "%s", requestUser->username);
requestUser->username,
requestUser->discriminator newRequest->discriminator = Z_Calloc(8, PU_STATIC, NULL);
); snprintf(newRequest->discriminator, 8, "%s", requestUser->discriminator);
newRequest->userID = Z_Calloc(32, PU_STATIC, NULL); newRequest->userID = Z_Calloc(32, PU_STATIC, NULL);
snprintf(newRequest->userID, 32, "%s", requestUser->userId); snprintf(newRequest->userID, 32, "%s", requestUser->userId);
@ -257,6 +325,68 @@ void DRPC_Init(void)
DRPC_UpdatePresence(); DRPC_UpdatePresence();
} }
/*--------------------------------------------------
void DRPC_SendDiscordInfo(void)
See header file for description.
--------------------------------------------------*/
void DRPC_SendDiscordInfo(void)
{
UINT8 buf[3];
UINT8 *p = buf;
UINT8 maxplayer;
if (!server)
return;
maxplayer = (UINT8)(min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxplayers.value));
WRITEUINT8(p, maxplayer);
WRITEUINT8(p, cv_allownewplayer.value);
WRITEUINT8(p, cv_discordinvites.value);
SendNetXCmd(XD_DISCORD, &buf, 3);
}
/*--------------------------------------------------
void DRPC_RecieveDiscordInfo(UINT8 **p, INT32 playernum)
See header file for description.
--------------------------------------------------*/
void DRPC_RecieveDiscordInfo(UINT8 **p, INT32 playernum)
{
if (playernum != serverplayer /*&& !IsPlayerAdmin(playernum)*/)
{
// protect against hacked/buggy client
CONS_Alert(CONS_WARNING, M_GetText("Illegal Discord info command received from %s\n"), player_names[playernum]);
if (server)
{
XBOXSTATIC UINT8 buf[2];
buf[0] = (UINT8)playernum;
buf[1] = KICK_MSG_CON_FAIL;
SendNetXCmd(XD_KICK, &buf, 2);
}
return;
}
discordInfo.maxPlayers = READUINT8(*p);
discordInfo.joinsAllowed = (boolean)READUINT8(*p);
discordInfo.everyoneCanInvite = (boolean)READUINT8(*p);
DRPC_UpdatePresence();
if (DRPC_InvitesAreAllowed() == false)
{
// Flush the request list, if it still exists
while (discordRequestList != NULL)
{
Discord_Respond(discordRequestList->userID, DISCORD_REPLY_IGNORE);
DRPC_RemoveRequest(discordRequestList);
}
}
}
#ifdef HAVE_CURL #ifdef HAVE_CURL
/*-------------------------------------------------- /*--------------------------------------------------
static size_t DRPC_WriteServerIP(char *s, size_t size, size_t n, void *userdata) static size_t DRPC_WriteServerIP(char *s, size_t size, size_t n, void *userdata)
@ -410,8 +540,6 @@ void DRPC_UpdatePresence(void)
// Server info // Server info
if (netgame) if (netgame)
{ {
const char *join;
switch (ms_RoomId) switch (ms_RoomId)
{ {
case -1: discordPresence.state = "Private"; break; // Private server case -1: discordPresence.state = "Private"; break; // Private server
@ -426,14 +554,19 @@ void DRPC_UpdatePresence(void)
discordPresence.partySize = D_NumPlayers(); // Players in server discordPresence.partySize = D_NumPlayers(); // Players in server
discordPresence.partyMax = cv_maxplayers.value; // Max players (TODO: another variable should hold this, so that maxplayers doesn't have to be a netvar) discordPresence.partyMax = cv_maxplayers.value; // Max players (TODO: another variable should hold this, so that maxplayers doesn't have to be a netvar)
if (DRPC_InvitesAreAllowed() == true)
{
const char *join;
// Grab the host's IP for joining. // Grab the host's IP for joining.
if (cv_allownewplayer.value && ((join = DRPC_GetServerIP()) != NULL)) if ((join = DRPC_GetServerIP()) != NULL)
{ {
char *xorjoin = DRPC_XORIPString(join); char *xorjoin = DRPC_XORIPString(join);
discordPresence.joinSecret = xorjoin; discordPresence.joinSecret = xorjoin;
free(xorjoin); free(xorjoin);
} }
} }
}
else else
{ {
// Offline info // Offline info

View file

@ -18,15 +18,26 @@
#include "discord_rpc.h" #include "discord_rpc.h"
extern consvar_t cv_discordrp; extern consvar_t cv_discordrp;
extern consvar_t cv_discordstreamer;
extern consvar_t cv_discordasks;
extern consvar_t cv_discordinvites;
extern struct discordInfo_s {
UINT8 maxPlayers;
boolean joinsAllowed;
boolean everyoneCanInvite;
} discordInfo;
typedef struct discordRequest_s { typedef struct discordRequest_s {
tic_t timer; // Tics left on the request before it expires. tic_t timer; // Tics left on the request before it expires.
char *username; // Discord user name + their discriminator. char *username; // Discord user name.
char *discriminator; // Discord discriminator (The little hashtag thing after the username). Separated for a "hide discriminators" cvar.
char *userID; // The ID of the Discord user, gets used with Discord_Respond() char *userID; // The ID of the Discord user, gets used with Discord_Respond()
// HAHAHA, no. // HAHAHA, no.
// *Maybe* if it was only PNG I would boot up curl just to get AND convert this to Doom GFX, // *Maybe* if it was only PNG I would boot up curl just to get AND convert this to Doom GFX,
// but it can be a JEPG, WebP, or GIF too :) // but it can *also* be a JEPG, WebP, or GIF :)
// Hey, wanna add ImageMagick as a dependency? :dying:
//patch_t *avatar; //patch_t *avatar;
struct discordRequest_s *next; // Next request in the list. struct discordRequest_s *next; // Next request in the list.
@ -55,6 +66,26 @@ void DRPC_RemoveRequest(discordRequest_t *removeRequest);
void DRPC_Init(void); void DRPC_Init(void);
/*--------------------------------------------------
void DRPC_SendDiscordInfo(void);
Sends the server's information needed for
the rich presence state.
--------------------------------------------------*/
void DRPC_SendDiscordInfo(void);
/*--------------------------------------------------
void DRPC_RecieveDiscordInfo(UINT8 **p, INT32 playernum);
Recieves the server's information needed for
the rich presence state.
--------------------------------------------------*/
void DRPC_RecieveDiscordInfo(UINT8 **p, INT32 playernum);
/*-------------------------------------------------- /*--------------------------------------------------
void DRPC_UpdatePresence(void); void DRPC_UpdatePresence(void);

View file

@ -304,6 +304,9 @@ menu_t OP_SoundOptionsDef;
//Misc //Misc
menu_t OP_DataOptionsDef, OP_ScreenshotOptionsDef, OP_EraseDataDef; menu_t OP_DataOptionsDef, OP_ScreenshotOptionsDef, OP_EraseDataDef;
#ifdef HAVE_DISCORDRPC
menu_t OP_DiscordOptionsDef;
#endif
menu_t OP_HUDOptionsDef, OP_ChatOptionsDef; menu_t OP_HUDOptionsDef, OP_ChatOptionsDef;
menu_t OP_GameOptionsDef, OP_ServerOptionsDef; menu_t OP_GameOptionsDef, OP_ServerOptionsDef;
#ifndef NONET #ifndef NONET
@ -1361,19 +1364,15 @@ static menuitem_t OP_SoundOptionsMenu[] =
static menuitem_t OP_DataOptionsMenu[] = static menuitem_t OP_DataOptionsMenu[] =
{ {
#ifdef HAVE_DISCORDRPC
{IT_STRING | IT_CVAR, NULL, "Discord Rich Presence", &cv_discordrp, 10},
{IT_STRING | IT_CALL, NULL, "Screenshot Options...", M_ScreenshotOptions, 30},
{IT_STRING | IT_CALL, NULL, "Addon Options...", M_AddonsOptions, 40},
{IT_STRING | IT_SUBMENU, NULL, "Replay Options...", &MISC_ReplayOptionsDef, 50},
{IT_STRING | IT_SUBMENU, NULL, "Erase Data...", &OP_EraseDataDef, 70},
#else
{IT_STRING | IT_CALL, NULL, "Screenshot Options...", M_ScreenshotOptions, 10}, {IT_STRING | IT_CALL, NULL, "Screenshot Options...", M_ScreenshotOptions, 10},
{IT_STRING | IT_CALL, NULL, "Addon Options...", M_AddonsOptions, 20}, {IT_STRING | IT_CALL, NULL, "Addon Options...", M_AddonsOptions, 20},
{IT_STRING | IT_SUBMENU, NULL, "Replay Options...", &MISC_ReplayOptionsDef, 30}, {IT_STRING | IT_SUBMENU, NULL, "Replay Options...", &MISC_ReplayOptionsDef, 30},
#ifdef HAVE_DISCORDRPC
{IT_STRING | IT_SUBMENU, NULL, "Discord Options...", &OP_DiscordOptionsDef, 40},
{IT_STRING | IT_SUBMENU, NULL, "Erase Data...", &OP_EraseDataDef, 60},
#else
{IT_STRING | IT_SUBMENU, NULL, "Erase Data...", &OP_EraseDataDef, 50}, {IT_STRING | IT_SUBMENU, NULL, "Erase Data...", &OP_EraseDataDef, 50},
#endif #endif
}; };
@ -1437,6 +1436,19 @@ enum
op_addons_folder = 2, op_addons_folder = 2,
}; };
#ifdef HAVE_DISCORDRPC
static menuitem_t OP_DiscordOptionsMenu[] =
{
{IT_STRING | IT_CVAR, NULL, "Rich Presence", &cv_discordrp, 10},
{IT_HEADER, NULL, "Rich Presence Settings", NULL, 30},
{IT_STRING | IT_CVAR, NULL, "Streamer Mode", &cv_discordstreamer, 40},
{IT_STRING | IT_CVAR, NULL, "Allow Ask To Join", &cv_discordasks, 60},
{IT_STRING | IT_CVAR, NULL, "Allow Invites", &cv_discordinvites, 70},
};
#endif
static menuitem_t OP_HUDOptionsMenu[] = static menuitem_t OP_HUDOptionsMenu[] =
{ {
{IT_STRING | IT_CVAR, NULL, "Show HUD (F3)", &cv_showhud, 10}, {IT_STRING | IT_CVAR, NULL, "Show HUD (F3)", &cv_showhud, 10},
@ -2118,6 +2130,7 @@ menu_t OP_OpenGLColorDef =
menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30); menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30);
menu_t OP_ScreenshotOptionsDef = DEFAULTMENUSTYLE("M_SCSHOT", OP_ScreenshotOptionsMenu, &OP_DataOptionsDef, 30, 30); menu_t OP_ScreenshotOptionsDef = DEFAULTMENUSTYLE("M_SCSHOT", OP_ScreenshotOptionsMenu, &OP_DataOptionsDef, 30, 30);
menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE("M_ADDONS", OP_AddonsOptionsMenu, &OP_DataOptionsDef, 30, 30); menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE("M_ADDONS", OP_AddonsOptionsMenu, &OP_DataOptionsDef, 30, 30);
menu_t OP_DiscordOptionsDef = DEFAULTMENUSTYLE(NULL, OP_DiscordOptionsMenu, &OP_DataOptionsDef, 30, 30);
menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_DataOptionsDef, 30, 30); menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_DataOptionsDef, 30, 30);
// ========================================================================== // ==========================================================================
@ -6275,7 +6288,12 @@ static void M_Options(INT32 choice)
OP_MainMenu[4].status = OP_MainMenu[5].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); OP_MainMenu[4].status = OP_MainMenu[5].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU);
OP_MainMenu[8].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); // Play credits OP_MainMenu[8].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); // Play credits
#ifdef HAVE_DISCORDRPC
OP_DataOptionsMenu[4].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); // Erase data
#else
OP_DataOptionsMenu[3].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); // Erase data OP_DataOptionsMenu[3].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); // Erase data
#endif
OP_GameOptionsMenu[3].status = OP_GameOptionsMenu[3].status =
(M_SecretUnlocked(SECRET_ENCORE)) ? (IT_CVAR|IT_STRING) : IT_SECRET; // cv_kartencore (M_SecretUnlocked(SECRET_ENCORE)) ? (IT_CVAR|IT_STRING) : IT_SECRET; // cv_kartencore
@ -11360,14 +11378,20 @@ static void M_DrawDiscordRequests(void)
return; return;
} }
V_DrawThinString(x, y, V_ALLOWLOWERCASE|V_6WIDTHSPACE, curRequest->username); V_DrawThinString(x, y, V_ALLOWLOWERCASE|V_6WIDTHSPACE,
cv_discordstreamer.value ? curRequest->username :
va("%s#%s", curRequest->username, curRequest->discriminator)
);
V_DrawThinString(x, y + 24, V_ALLOWLOWERCASE|V_6WIDTHSPACE, "A - Accept B - Decline"); V_DrawThinString(x, y + 24, V_ALLOWLOWERCASE|V_6WIDTHSPACE, "A - Accept B - Decline");
y -= 16; y -= 16;
while (curRequest->next != NULL) while (curRequest->next != NULL)
{ {
curRequest = curRequest->next; curRequest = curRequest->next;
V_DrawThinString(x, y, V_ALLOWLOWERCASE|V_6WIDTHSPACE, curRequest->username); V_DrawThinString(x, y, V_ALLOWLOWERCASE|V_6WIDTHSPACE,
cv_discordstreamer.value ? curRequest->username :
va("%s#%s", curRequest->username, curRequest->discriminator)
);
y -= 8; y -= 8;
} }
} }