diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 16ed731e56ad606486da9943ab962260ab328d57..352321e19c934b68a20e2fe8bf6456533c694c06 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -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}}; 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 consvar_t cv_joinnextround = {"joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done #endif -static void MaxPlayers_OnChange(void); 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}}; 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_RemovePlayer(UINT8 **p, INT32 playernum); -static void MaxPlayers_OnChange(void) +static void Joinable_OnChange(void) { #ifdef HAVE_DISCORDRPC - DRPC_UpdatePresence(); + DRPC_SendDiscordInfo(); #else return; #endif diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 213ba5d48ebdd1113dd8d229eb218432b2134550..8778a242011552c8a8d5187e89a832cd403eb461 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -708,10 +708,14 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_showping); #ifdef SEENAMES - CV_RegisterVar(&cv_allowseenames); + CV_RegisterVar(&cv_allowseenames); #endif CV_RegisterVar(&cv_dummyconsvar); + +#ifdef HAVE_DISCORDRPC + RegisterNetXCmd(XD_DISCORD, DRPC_RecieveDiscordInfo); +#endif } // ========================================================================= @@ -1007,6 +1011,9 @@ void D_RegisterClientCommands(void) #ifdef HAVE_DISCORDRPC CV_RegisterVar(&cv_discordrp); + CV_RegisterVar(&cv_discordstreamer); + CV_RegisterVar(&cv_discordasks); + CV_RegisterVar(&cv_discordinvites); #endif } diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 2d8e5705a5717cc7196c689e0051cf895af04ada..d6e7e08dbfd611605bee336cab5f0c78c9c6d34e 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -181,6 +181,9 @@ typedef enum #ifdef HAVE_BLUA XD_LUACMD, // 26 XD_LUAVAR, // 27 +#endif +#ifdef HAVE_DISCORDRPC + XD_DISCORD, // 28 #endif MAXNETXCMD } netxcmd_t; diff --git a/src/discord.c b/src/discord.c index 2c2bed5b85276ac5b9a14a8d9d0ac4d87b786485..7e20cde658301528fbd92a7032fb119e75310fad 100644 --- a/src/discord.c +++ b/src/discord.c @@ -27,6 +27,7 @@ #include "mserv.h" // ms_RoomId #include "z_zone.h" #include "m_random.h" // P_GetInitSeed +#include "byteptr.h" #include "discord.h" #include "doomdef.h" @@ -38,6 +39,13 @@ #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_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; @@ -87,7 +95,14 @@ static char *DRPC_XORIPString(const char *input) --------------------------------------------------*/ static void DRPC_HandleReady(const DiscordUser *user) { - CONS_Printf("Discord: connected to %s#%s (%s)\n", user->username, user->discriminator, user->userId); + 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); + } } /*-------------------------------------------------- @@ -145,6 +160,50 @@ static void DRPC_HandleJoin(const char *secret) 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) @@ -161,16 +220,25 @@ static void DRPC_HandleJoin(const char *secret) static void DRPC_HandleJoinRequest(const DiscordUser *requestUser) { 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->username = Z_Calloc(344+1+8, PU_STATIC, NULL); - snprintf(newRequest->username, 344+1+8, "%s#%s", - requestUser->username, - requestUser->discriminator - ); + newRequest->username = Z_Calloc(344, PU_STATIC, NULL); + snprintf(newRequest->username, 344, "%s", requestUser->username); + + newRequest->discriminator = Z_Calloc(8, PU_STATIC, NULL); + snprintf(newRequest->discriminator, 8, "%s", requestUser->discriminator); newRequest->userID = Z_Calloc(32, PU_STATIC, NULL); snprintf(newRequest->userID, 32, "%s", requestUser->userId); @@ -257,6 +325,68 @@ void DRPC_Init(void) 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 /*-------------------------------------------------- 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 if (netgame) { - const char *join; - switch (ms_RoomId) { case -1: discordPresence.state = "Private"; break; // Private server @@ -426,12 +554,17 @@ void DRPC_UpdatePresence(void) 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) - // Grab the host's IP for joining. - if (cv_allownewplayer.value && ((join = DRPC_GetServerIP()) != NULL)) + if (DRPC_InvitesAreAllowed() == true) { - char *xorjoin = DRPC_XORIPString(join); - discordPresence.joinSecret = xorjoin; - free(xorjoin); + const char *join; + + // Grab the host's IP for joining. + if ((join = DRPC_GetServerIP()) != NULL) + { + char *xorjoin = DRPC_XORIPString(join); + discordPresence.joinSecret = xorjoin; + free(xorjoin); + } } } else diff --git a/src/discord.h b/src/discord.h index fd306fa8cd3a6d59c989a1e25d5a393a8978e066..6bd081a981f473b0fd87fb7148ad537b1fb8c291 100644 --- a/src/discord.h +++ b/src/discord.h @@ -18,15 +18,26 @@ #include "discord_rpc.h" 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 { 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() // HAHAHA, no. // *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; 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_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); diff --git a/src/m_menu.c b/src/m_menu.c index db0dd9a368a64da927cfdacc1cbe3fd897df6b4a..da88ea831b7548434ea8bfc1bf6e9853c9f08f69 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -304,6 +304,9 @@ menu_t OP_SoundOptionsDef; //Misc 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_GameOptionsDef, OP_ServerOptionsDef; #ifndef NONET @@ -1361,19 +1364,15 @@ static menuitem_t OP_SoundOptionsMenu[] = 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, "Addon Options...", M_AddonsOptions, 20}, {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}, #endif }; @@ -1424,7 +1423,7 @@ static menuitem_t OP_AddonsOptionsMenu[] = {IT_HEADER, NULL, "Menu", NULL, 0}, {IT_STRING|IT_CVAR, NULL, "Location", &cv_addons_option, 10}, {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_addons_folder, 20}, - {IT_STRING|IT_CVAR, NULL, "Identify addons via", &cv_addons_md5, 48}, + {IT_STRING|IT_CVAR, NULL, "Identify addons via", &cv_addons_md5, 48}, {IT_STRING|IT_CVAR, NULL, "Show unsupported file types", &cv_addons_showall, 58}, {IT_HEADER, NULL, "Search", NULL, 76}, @@ -1437,6 +1436,19 @@ enum 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[] = { {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_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_DiscordOptionsDef = DEFAULTMENUSTYLE(NULL, OP_DiscordOptionsMenu, &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[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 +#endif OP_GameOptionsMenu[3].status = (M_SecretUnlocked(SECRET_ENCORE)) ? (IT_CVAR|IT_STRING) : IT_SECRET; // cv_kartencore @@ -11360,14 +11378,20 @@ static void M_DrawDiscordRequests(void) 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"); y -= 16; while (curRequest->next != NULL) { 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; } }