diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 53bbaf0b6..79f081e41 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -163,6 +163,7 @@ static UINT8 localtextcmd[MAXSPLITSCREENPLAYERS][MAXTEXTCMD]; static tic_t neededtic; SINT8 servernode = 0; // the number of the server node char connectedservername[MAXSERVERNAME]; +char connectedservercontact[MAXSERVERCONTACT]; /// \brief do we accept new players? /// \todo WORK! boolean acceptnewnode = true; @@ -1283,6 +1284,9 @@ static boolean SV_SendServerConfig(INT32 node) memcpy(netbuffer->u.servercfg.server_context, server_context, 8); + strncpy(netbuffer->u.servercfg.server_name, cv_servername.string, MAXSERVERNAME); + strncpy(netbuffer->u.servercfg.server_contact, cv_server_contact.string, MAXSERVERCONTACT); + { const size_t len = sizeof (serverconfig_pak); @@ -3799,6 +3803,9 @@ void SV_ResetServer(void) // clear server_context memset(server_context, '-', 8); + memset(connectedservername, 0, MAXSERVERNAME); + memset(connectedservercontact, 0, MAXSERVERCONTACT); + CV_RevertNetVars(); // Copy our unlocks to a place where net material can grab at/overwrite them safely. @@ -3811,9 +3818,10 @@ void SV_ResetServer(void) DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n"); } -static inline void SV_GenContext(void) +static void SV_GenContext(void) { UINT8 i; + // generate server_context, as exactly 8 bytes of randomly mixed A-Z and a-z // (hopefully M_Random is initialized!! if not this will be awfully silly!) for (i = 0; i < 8; i++) @@ -3824,6 +3832,9 @@ static inline void SV_GenContext(void) else // lowercase server_context[i] = 'a'+(a-26); } + + strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); + strncpy(connectedservercontact, cv_server_contact.string, MAXSERVERCONTACT); } // @@ -4874,7 +4885,11 @@ static void HandlePacketFromAwayNode(SINT8 node) G_SetGametype(netbuffer->u.servercfg.gametype); modifiedgame = netbuffer->u.servercfg.modifiedgame; + memcpy(server_context, netbuffer->u.servercfg.server_context, 8); + + strncpy(connectedservername, netbuffer->u.servercfg.server_name, MAXSERVERNAME); + strncpy(connectedservercontact, netbuffer->u.servercfg.server_contact, MAXSERVERCONTACT); } #ifdef HAVE_DISCORDRPC diff --git a/src/d_clisrv.h b/src/d_clisrv.h index e2dd85bff..fdcf4d0fe 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -43,6 +43,9 @@ applications may follow different packet versions. #define HU_MAXMSGLEN 223 +#define MAXSERVERNAME 32 +#define MAXSERVERCONTACT 1024 + // Networking and tick handling related. #define BACKUPTICS 512 // more than enough for most timeouts.... #define CLIENTBACKUPTICS 32 @@ -226,6 +229,9 @@ struct serverconfig_pak UINT8 maxplayer; boolean allownewplayer; boolean discordinvites; + + char server_name[MAXSERVERNAME]; + char server_contact[MAXSERVERCONTACT]; } ATTRPACK; struct filetx_pak @@ -276,7 +282,6 @@ struct clientconfig_pak #define SV_DEDICATED 0x40 // server is dedicated #define SV_LOTSOFADDONS 0x20 // flag used to ask for full file list in d_netfil -#define MAXSERVERNAME 32 #define MAXFILENEEDED 915 #define MAX_MIRROR_LENGTH 256 // This packet is too large @@ -509,6 +514,7 @@ extern UINT16 software_MAXPACKETLENGTH; extern boolean acceptnewnode; extern SINT8 servernode; extern char connectedservername[MAXSERVERNAME]; +extern char connectedservercontact[MAXSERVERCONTACT]; extern UINT32 ourIP; extern uint8_t lastReceivedKey[MAXNETNODES][MAXSPLITSCREENPLAYERS][PUBKEYLENGTH]; extern uint8_t lastSentChallenge[MAXNETNODES][CHALLENGELENGTH]; diff --git a/src/d_main.c b/src/d_main.c index fd05bc3cd..c17737060 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1913,8 +1913,6 @@ void D_SRB2Main(void) COM_BufExecute(); // ensure the command buffer gets executed before the map starts (+skin) - strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); - if (M_CheckParm("-gametype") && M_IsNextParm()) { // from Command_Map_f diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7ad288f25..20425deee 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3012,8 +3012,6 @@ static void Command_Map_f(void) multiplayer = true; netgame = false; - strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); - if (cv_maxconnections.value < ssplayers+1) CV_SetValue(&cv_maxconnections, ssplayers+1); diff --git a/src/st_stuff.c b/src/st_stuff.c index c7166c414..b6581e71a 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1303,6 +1303,113 @@ void ST_AskToJoinEnvelope(void) } #endif +static INT32 ST_ServerSplash_OpacityFlag(INT32 opacity) +{ + if (opacity >= NUMTRANSMAPS) + { + return 0; + } + + opacity = max(opacity, 1); + return (NUMTRANSMAPS - opacity) << V_ALPHASHIFT; +} + +static void ST_DrawServerSplash(void) +{ + static const fixed_t SPLASH_LEN = (FRACUNIT * TICRATE) * 3; + static const fixed_t SPLASH_WAIT = (FRACUNIT * TICRATE) / 2; + + static fixed_t splashTime = -SPLASH_WAIT; + static char prevContext[8] = {0}; + + if (memcmp(prevContext, server_context, 8) != 0) + { + // Context changed, we want to draw it again + splashTime = -SPLASH_WAIT; + memcpy(prevContext, server_context, 8); + } + + if (lt_ticker < lt_endtime) + { + // Level title is running rn + return; + } + + if (splashTime >= SPLASH_LEN) + { + // We finished drawing it + return; + } + + splashTime += renderdeltatics; + if (splashTime <= 0) + { + // We're waiting a tiny bit to draw it + return; + } + + const INT32 splashTic = splashTime >> FRACBITS; + INT32 opacity = NUMTRANSMAPS; + if (splashTic < NUMTRANSMAPS) + { + opacity = splashTic; + } + else if (splashTic > (SPLASH_LEN >> FRACBITS) - NUMTRANSMAPS) + { + opacity = (SPLASH_LEN >> FRACBITS) - splashTic; + } + INT32 opacityFlag = ST_ServerSplash_OpacityFlag(opacity); + + patch_t *gridPatch = W_CachePatchName("MOTDBG", PU_CACHE); + fixed_t gridX = -splashTime / 3; + fixed_t gridY = (BASEVIDHEIGHT - gridPatch->height) * FRACUNIT; + INT32 gridOpacity = ST_ServerSplash_OpacityFlag(opacity / 2); + fixed_t maxX = (vid.width * FRACUNIT) / vid.dupx; + + while (gridX < maxX) + { + V_DrawFixedPatch( + gridX, gridY, + FRACUNIT, + (V_SNAPTOLEFT|V_SNAPTOBOTTOM) | V_SUBTRACT | gridOpacity, + gridPatch, + NULL + ); + + gridX += (gridPatch->width * FRACUNIT); + } + + patch_t *iconPatch = W_CachePatchName("MOTDICON", PU_CACHE); + fixed_t iconX = (BASEVIDWIDTH - 16 - iconPatch->width) * FRACUNIT; + fixed_t iconY = (BASEVIDHEIGHT - 8 - iconPatch->height) * FRACUNIT; + V_DrawFixedPatch( + iconX, iconY, + FRACUNIT, + (V_SNAPTORIGHT|V_SNAPTOBOTTOM) | opacityFlag, + iconPatch, + NULL + ); + + fixed_t textX = (BASEVIDWIDTH - 16 - 36) * FRACUNIT; + fixed_t textY = (BASEVIDHEIGHT - 24) * FRACUNIT; + + if (connectedservercontact[0] != 0) + { + V_DrawRightAlignedThinStringAtFixed( + textX, textY, + (V_SNAPTORIGHT|V_SNAPTOBOTTOM) | opacityFlag, + va("Contact @ %s", connectedservercontact) + ); + textY -= (10 * FRACUNIT); + } + + V_DrawRightAlignedStringAtFixed( + textX, textY, + (V_SNAPTORIGHT|V_SNAPTOBOTTOM) | opacityFlag, + connectedservername + ); +} + void ST_Drawer(void) { boolean stagetitle = false; // Decide whether to draw the stage title or not @@ -1377,6 +1484,9 @@ void ST_Drawer(void) if (stagetitle) ST_drawTitleCard(); + if (netgame) + ST_DrawServerSplash(); + // Replay manual-save stuff if (demo.recording && multiplayer && demo.savebutton && demo.savebutton + 3*TICRATE < leveltime) { diff --git a/src/v_video.cpp b/src/v_video.cpp index 17519f894..351ff4d46 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -2789,12 +2789,24 @@ void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *st V_DrawThinString(x, y, option, string); } -void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) +void V_DrawCenteredStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) { x -= (V_ThinStringWidth(string, option) / 2) * FRACUNIT; V_DrawThinStringAtFixed(x, y, option, string); } +void V_DrawRightAlignedStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) +{ + x -= V_StringWidth(string, option) * FRACUNIT; + V_DrawStringAtFixed(x, y, option, string); +} + +void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) +{ + x -= (V_StringWidth(string, option) / 2) * FRACUNIT; + V_DrawStringAtFixed(x, y, option, string); +} + void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) { x -= V_ThinStringWidth(string, option) * FRACUNIT; diff --git a/src/v_video.h b/src/v_video.h index 7a26591dc..f7c32505c 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -334,16 +334,14 @@ void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *st #define V_DrawStringAtFixed( x,y,option,string ) \ V__DrawOneScaleString (x,y,FRACUNIT,option,NULL,HU_FONT,string) +void V_DrawCenteredStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string); +void V_DrawRightAlignedStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string); #define V_DrawThinStringAtFixed( x,y,option,string ) \ V__DrawOneScaleString (x,y,FRACUNIT,option,NULL,TINY_FONT,string) void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string); void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string); - -void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string); -void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string); - // Draws a titlecard font string. // timer: when the letters start appearing (leave to 0 to disable) // threshold: when the letters start disappearing (leave to 0 to disable) (both are INT32 in case you supply negative values...)