diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 7c6c78f01..c0305d8bd 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2072,6 +2072,16 @@ static void CL_ConnectToServer(void) DEBFILE(va("Synchronisation Finished\n")); displayplayers[0] = consoleplayer; + + // At this point we've succesfully joined the server, if we joined by IP (ie: a valid joinedIP string), save it! + // @TODO: Save the proper server name, right now it doesn't seem like we can consistently retrieve it from the serverlist....? + // It works... sometimes but not always which is weird. + + if (*joinedIP) // false if we have "" which is \0 + M_AddToJoinedIPs(joinedIP, netbuffer->u.serverinfo.servername); + + strcpy(joinedIP, ""); // And empty this for good measure regardless of whether or not we actually used it. + } #ifndef NONET @@ -2240,6 +2250,10 @@ static void Command_ReloadBan(void) //recheck ban.txt static void Command_connect(void) { + + // By default, clear the saved address that we'd save after succesfully joining just to be sure: + strcpy(joinedIP, ""); + if (COM_Argc() < 2 || *COM_Argv(1) == 0) { CONS_Printf(M_GetText( @@ -2295,6 +2309,10 @@ static void Command_connect(void) servernode = I_NetMakeNodewPort(COM_Argv(1), COM_Argv(2)); else // address only, or address:port servernode = I_NetMakeNode(COM_Argv(1)); + + // Last IPs joined: + // Keep the address we typed in memory so that we can save it if we *succesfully* join the server + strcpy(joinedIP, COM_Argv(1)); } else { diff --git a/src/d_main.c b/src/d_main.c index 44c2673ee..3a2259337 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1158,6 +1158,9 @@ void D_SRB2Main(void) strcpy(savegamename, SAVEGAMENAME"%u.ssg"); strcpy(liveeventbackup, "live"SAVEGAMENAME".bkp"); // intentionally not ending with .ssg + // Init the joined IP table for quick rejoining of past games. + M_InitJoinedIPArray(); + { const char *userhome = D_Home(); //Alam: path to home @@ -1205,6 +1208,8 @@ void D_SRB2Main(void) configfile[sizeof configfile - 1] = '\0'; } + M_LoadJoinedIPs(); // load joined ips + // Create addons dir snprintf(addonsdir, sizeof addonsdir, "%s%s%s", srb2home, PATHSEP, "addons"); I_mkdir(addonsdir, 0755); diff --git a/src/k_menu.h b/src/k_menu.h index 96b341eb0..b9dacc5fe 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -133,6 +133,7 @@ typedef struct menu_s void (*drawroutine)(void); // draw routine void (*tickroutine)(void); // ticker routine boolean (*quitroutine)(void); // called before quit a menu return true if we can + boolean (*inputroutine)(INT32); // if set, called every frame in the input handler. Returning true overwrites normal input handling. } menu_t; typedef enum @@ -393,7 +394,8 @@ void M_MPSetupNetgameMapSelect(INT32 choice); // MP join by IP void M_MPJoinIPInit(INT32 choice); -void M_JoinIP(void); +boolean M_JoinIPInputs(INT32 ch); +void M_JoinIP(const char *ipa); // Server browser room selection void M_MPRoomSelect(INT32 choice); @@ -455,6 +457,7 @@ void M_DrawPlaybackMenu(void); 0, 0,\ M_DrawGenericMenu,\ NULL,\ + NULL,\ NULL\ } @@ -469,6 +472,7 @@ void M_DrawPlaybackMenu(void); 1, 10,\ M_DrawKartGamemodeMenu,\ NULL,\ + NULL,\ NULL\ } diff --git a/src/k_menudef.c b/src/k_menudef.c index 987bd6e26..d98c3b028 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -55,7 +55,8 @@ menu_t PLAY_CharSelectDef = { 0, 0, M_DrawCharacterSelect, M_CharacterSelectTick, - M_CharacterSelectQuit + M_CharacterSelectQuit, + NULL }; menuitem_t PLAY_MainMenu[] = @@ -116,6 +117,7 @@ menu_t PLAY_CupSelectDef = { 2, 10, M_DrawCupSelect, M_CupSelectTick, + NULL, NULL }; @@ -133,6 +135,7 @@ menu_t PLAY_LevelSelectDef = { 2, 10, M_DrawLevelSelect, M_LevelSelectTick, + NULL, NULL }; @@ -153,6 +156,7 @@ menu_t PLAY_TimeAttackDef = { 2, 10, M_DrawTimeAttack, NULL, + NULL, NULL }; @@ -178,11 +182,11 @@ menuitem_t PLAY_MP_OptSelect[] = {IT_STRING | IT_CALL, "Host Game", "Start your own online game!", NULL, M_MPHostInit, 0, 0}, - {IT_STRING | IT_CALL, "Join by IP", "Join an online game by its IP address.", - NULL, M_MPJoinIPInit, 0, 0}, - {IT_STRING | IT_CALL, "Server Browser", "Search for game servers to play in.", NULL, M_MPRoomSelectInit, 0, 0}, + + {IT_STRING | IT_CALL, "Join by IP", "Join an online game by its IP address.", + NULL, M_MPJoinIPInit, 0, 0}, }; menu_t PLAY_MP_OptSelectDef = { @@ -194,6 +198,7 @@ menu_t PLAY_MP_OptSelectDef = { -1, 1, M_DrawMPOptSelect, M_MPOptSelectTick, + NULL, NULL }; @@ -228,7 +233,8 @@ menu_t PLAY_MP_HostDef = { -1, 1, // 1 frame transition.... This is really just because I don't want the black fade when we press esc, hehe M_DrawMPHost, M_MPOptSelectTick, // This handles the unfolding options - M_MPResetOpts + M_MPResetOpts, + NULL }; // MULTIPLAYER JOIN BY IP @@ -236,11 +242,21 @@ menuitem_t PLAY_MP_JoinIP[] = { //{IT_NOTHING | IT_KEYHANDLER, NULL, NULL, NULL, M_MPOptSelect, 0, 0}, - {IT_STRING | IT_CVAR | IT_CV_STRING, "Address: ", "Type the IPv4 address of the server you wish to connect to.", + {IT_STRING | IT_CVAR | IT_CV_STRING, "IP: ", "Type the IPv4 address of the server then press enter to attempt connection.", NULL, &cv_dummyip, 0, 0}, - {IT_STRING | IT_CALL, "GO", "Select a map with the currently selected gamemode", - NULL, M_JoinIP, 0, 0}, + {IT_STRING | IT_SPACE, "LAST IPs JOINED:", "Kanade best waifu :)", + NULL, NULL, 0, 0}, + + {IT_STRING, "servip1", "The last 3 IPs you've succesfully joined are displayed here.", + NULL, NULL, 0, 0}, + + {IT_STRING, "servip2", "The last 3 IPs you've succesfully joined are displayed here.", + NULL, NULL, 0, 0}, + + {IT_STRING, "servip3", "The last 3 IPs you've succesfully joined are displayed here.", + NULL, NULL, 0, 0}, + }; menu_t PLAY_MP_JoinIPDef = { @@ -252,7 +268,8 @@ menu_t PLAY_MP_JoinIPDef = { -1, 1, // 1 frame transition.... This is really just because I don't want the black fade when we press esc, hehe M_DrawMPJoinIP, M_MPOptSelectTick, // This handles the unfolding options - M_MPResetOpts + M_MPResetOpts, + M_JoinIPInputs }; // MULTIPLAYER ROOM SELECT (CORE / MODDED) @@ -270,6 +287,7 @@ menu_t PLAY_MP_RoomSelectDef = { 0, 0, M_DrawMPRoomSelect, M_MPRoomSelectTick, + NULL, NULL }; @@ -308,5 +326,6 @@ menu_t PAUSE_PlaybackMenuDef = { 0, 0, M_DrawPlaybackMenu, NULL, + NULL, NULL }; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 3c178b654..d8945b0d5 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1317,7 +1317,7 @@ static void M_MPOptDrawer(menu_t *m, INT16 extend[3][3]) // TODO: Allow specific options to "expand" into smaller ones. patch_t *buttback = W_CachePatchName("M_PLAT2", PU_CACHE); - INT32 i, x = 142, y = 32; // Dirty magic numbers for now but they work out. + INT32 i, x = 132, y = 32; // Dirty magic numbers for now but they work out. for (i = 0; i < m->numitems; i++) { @@ -1382,7 +1382,7 @@ void M_DrawMPHost(void) { patch_t *gobutt = W_CachePatchName("M_BUTTGO", PU_CACHE); // I'm very mature - INT32 xp = 50, yp = 64, i = 0, w = 0; // Starting position for the text drawing. + INT32 xp = 40, yp = 64, i = 0, w = 0; // Starting position for the text drawing. M_DrawMPOptSelect(); // Draw the Multiplayer option select menu first // Now draw our host options... @@ -1457,62 +1457,68 @@ void M_DrawMPJoinIP(void) { patch_t *gobutt = W_CachePatchName("M_BUTTGO", PU_CACHE); // I'm very mature - INT32 xp = 70, yp = 100, i = 0; // Starting position for the text drawing. + INT32 xp = 73, yp = 133, i = 0; // Starting position for the text drawing. M_DrawMPOptSelect(); // Draw the Multiplayer option select menu first + // Now draw our host options... for (i = 0; i < currentMenu->numitems; i++) { - if (i == currentMenu->numitems-1) + switch (currentMenu->menuitems[i].status & IT_DISPLAY) { - - UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_MOSS, GTC_CACHE); - if (i == itemOn) - colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE); - - // Ideally we'd calculate this but it's not worth it for a 1-off menu probably..... - V_DrawFixedPatch(219<width/2), 114 -3, V_ALLOWLOWERCASE, colormap, currentMenu->menuitems[i].text); - } - else - { - switch (currentMenu->menuitems[i].status & IT_DISPLAY) + case IT_STRING: { - case IT_STRING: + + char str[MAXSTRINGLENGTH]; + strcpy(str, currentMenu->menuitems[i].text); + + // The last 3 options of this menu are to be the joined IP addresses... + if (currentMenu->numitems - i <= NUMLOGIP) { - V_DrawString(xp, yp, V_ALLOWLOWERCASE | (i == itemOn ? highlightflags : 0), currentMenu->menuitems[i].text); - - // Cvar specific handling - switch (currentMenu->menuitems[i].status & IT_TYPE) - { - case IT_CVAR: - { - consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction; - switch (currentMenu->menuitems[i].status & IT_CVARTYPE) - { - case IT_CV_STRING: - V_DrawThinString(xp + 65, yp-1, V_ALLOWLOWERCASE, cv->string); - if (skullAnimCounter < 4 && i == itemOn) - V_DrawCharacter(xp + 65 + V_ThinStringWidth(cv->string, 0), yp, '_' | 0x80, false); - - break; - - default: - break; - } - break; - } - } - - xp += 5; - yp += 11; - - break; + UINT8 index = NUMLOGIP - (currentMenu->numitems - i); + if (joinedIPlist[index][1] && strlen(joinedIPlist[index][1])) // Try drawing server name + strcpy(str, joinedIPlist[index][1]); + else if (joinedIPlist[index][0] && strlen(joinedIPlist[index][0])) // If that fails, get the address + strcpy(str, joinedIPlist[index][0]); + else + strcpy(str, "---"); // If that fails too then there's nothing! } - break; - } + + V_DrawString(xp, yp, V_ALLOWLOWERCASE | (i == itemOn ? highlightflags : 0), str); + // Cvar specific handling + switch (currentMenu->menuitems[i].status & IT_TYPE) + { + case IT_CVAR: + { + consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction; + switch (currentMenu->menuitems[i].status & IT_CVARTYPE) + { + case IT_CV_STRING: + V_DrawThinString(xp + 24, yp-1, V_ALLOWLOWERCASE, cv->string); + if (skullAnimCounter < 4 && i == itemOn) + V_DrawCharacter(xp + 24 + V_ThinStringWidth(cv->string, 0), yp, '_' | 0x80, false); + + // On this specific menu the only time we'll ever see this is for the connect by IP typefield. + // ...In other words it's safe to just draw a "CONNECT" string there! + V_DrawRightAlignedString(xp + 210, yp, (i == itemOn ? highlightflags : 0), "GO!"); + + break; + + default: + break; + } + break; + } + } + + xp += 5; + yp += 11; + + break; + } + break; } } diff --git a/src/k_menufunc.c b/src/k_menufunc.c index ae756c669..b5b9ea305 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -928,6 +928,19 @@ boolean M_Responder(event_t *ev) routine(ch); return true; } + + // Handle menu-specific input handling. If this returns true we skip regular input handling. + if (currentMenu->inputroutine) + { + INT32 res = 0; + if (shiftdown && ch >= 32 && ch <= 127) + ch = shiftxform[ch]; + + res = currentMenu->inputroutine(ch); + + if (res) + return true; + } if (currentMenu->menuitems[itemOn].status == IT_MSGHANDLER) { @@ -1602,7 +1615,8 @@ menu_t MessageDef = 0, 0, // transition tics M_DrawMessageMenu, // drawing routine -> NULL, // ticker routine - NULL // quit routine + NULL, // quit routine + NULL // input routine }; // @@ -2646,7 +2660,7 @@ boolean M_MPResetOpts(void) void M_MPOptSelectInit(INT32 choice) { - INT16 arrcpy[3][3] = {{0,68,0}, {0,48,0}, {0,12,0}}; + INT16 arrcpy[3][3] = {{0,68,0}, {0,12,0}, {0,64,0}}; UINT8 i = 0, j = 0; // To copy the array into the struct (void)choice; @@ -2724,20 +2738,20 @@ void M_MPJoinIPInit(INT32 choice) { (void)choice; - mpmenu.modewinextend[1][0] = 1; + mpmenu.modewinextend[2][0] = 1; M_SetupNextMenu(&PLAY_MP_JoinIPDef, true); } // Attempts to join a given IP from the menu. -void M_JoinIP(void) +void M_JoinIP(const char *ipa) { - if (*(cv_dummyip.string) == '\0') // Jack shit + if (*(ipa) == '\0') // Jack shit { M_StartMessage("Please specify an address.\n", NULL, MM_NOTHING); return; } - COM_BufAddText(va("connect \"%s\"\n", cv_dummyip.string)); + COM_BufAddText(va("connect \"%s\"\n", ipa)); M_ClearMenus(true); // A little "please wait" message. @@ -2749,6 +2763,44 @@ void M_JoinIP(void) I_FinishUpdate(); // page flip or blit buffer } +boolean M_JoinIPInputs(INT32 ch) +{ + if (itemOn == 0) // connect field + { + // enter: connect + if (ch == KEY_ENTER) + { + M_JoinIP(cv_dummyip.string); + return true; + } + // ctrl+v -> copy paste! + else if (ctrldown && (ch == 'v' || ch == 'V')) + { + const char *paste = I_ClipboardPaste(); + UINT16 i; + for (i=0; i < strlen(paste); i++) + M_ChangeStringCvar(paste[i]); // We can afford to do this since we're currently on that cvar. + + return true; // Don't input the V obviously lol. + } + + } + else if (currentMenu->numitems - itemOn <= NUMLOGIP && ch == KEY_ENTER) // On one of the last 3 options for IP rejoining + { + UINT8 index = NUMLOGIP - (currentMenu->numitems - itemOn); + + // Is there an address at this part of the table? + if (joinedIPlist[index][0] && strlen(joinedIPlist[index][0])) + M_JoinIP(joinedIPlist[index][0]); + else + S_StartSound(NULL, sfx_lose); + + return true; // eat input. + } + + return false; +} + // MULTIPLAYER ROOM SELECT MENU void M_MPRoomSelect(INT32 choice) diff --git a/src/m_misc.c b/src/m_misc.c index 512a606de..32a1efc32 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -173,6 +173,50 @@ boolean takescreenshot = false; // Take a screenshot this tic moviemode_t moviemode = MM_OFF; +char joinedIPlist[NUMLOGIP][2][255]; +char joinedIP[255]; + +// This initializes the above array to have NULL evrywhere it should. +void M_InitJoinedIPArray(void) +{ + UINT8 i; + for (i=0; i < NUMLOGIP; i++) + { + strcpy(joinedIPlist[i][0], ""); + strcpy(joinedIPlist[i][1], ""); + } +} + +// This adds an entry to the above array +void M_AddToJoinedIPs(char *address, char *servname) +{ + + UINT8 i = 0; + UINT8 dupeindex = 0; + + // Check for dupes... + for (; i < NUMLOGIP && !dupeindex; i++) + { + // I don't care about the server name (this is broken anyway...) but definitely check the addresses + if (strcmp(joinedIPlist[i][0], address) == 0) + dupeindex = i; + } + + CONS_Printf("Adding %s (%s) to list of manually joined IPs\n", servname, address); + + // Start by moving every IP up 1 slot (dropping the last IP in the table) + // If we found duplicates, start here instead and pull the rest up. + for (i = dupeindex ? : NUMLOGIP; i; i--) + { + strcpy(joinedIPlist[i][0], joinedIPlist[i-1][0]); + strcpy(joinedIPlist[i][1], joinedIPlist[i-1][1]); + } + + // and add the new IP at the start of the table! + strcpy(joinedIPlist[0][0], address); + strcpy(joinedIPlist[0][1], servname); +} + /** Returns the map number for a map identified by the last two characters in * its name. * @@ -441,6 +485,87 @@ boolean FIL_CheckExtension(const char *in) return false; } +// LAST IPs JOINED LOG FILE! +// ...It won't be as overly engineered as the config file because let's be real there's 0 need to... + +// Save the file: +void M_SaveJoinedIPs(void) +{ + FILE *f = NULL; + UINT8 i; + char *filepath; + + if (!joinedIPlist[0][0] || !strlen(joinedIPlist[0][0])) + return; // Don't bother, there's nothing to save. + + // append srb2home to beginning of filename + // but check if srb2home isn't already there, first + if (!strstr(IPLOGFILE, srb2home)) + filepath = va(pandf,srb2home, IPLOGFILE); + else + filepath = Z_StrDup(IPLOGFILE); + + f = fopen(filepath, "w"); + + if (f == NULL) + return; // Uh I guess you don't have disk space????????? + + for (i=0; i < NUMLOGIP; i++) + { + if (joinedIPlist[i][0] && strlen(joinedIPlist[i][0])) + { + char savestring[MAXSTRINGLENGTH]; + strcpy(savestring, joinedIPlist[i][0]); + strcat(savestring, IPLOGFILESEP); + strcat(savestring, joinedIPlist[i][1]); + + fputs(savestring, f); + fputs("\n", f); // Because this won't do it automatically now will it... + } + } + + fclose(f); +} + + +// Load the file: +void M_LoadJoinedIPs(void) +{ + FILE *f = NULL; + UINT8 i = 0; + char filepath[255]; + char *s; + char content[255]; // 255 is more than long enough! + + strcpy(filepath, IPLOGFILE); + f = fopen(filepath, "r"); + + if (f == NULL) + return; // File doesn't exist? sure, just do nothing then. + + while (fgets(content, 255, f) && i < NUMLOGIP && content[0] && content[0] != '\n') // Don't let us write more than we can chew! + { + + // Now we have garbage under the form of "address;string" + // Now you might ask yourself, but what do we do if the player fucked with their file and now there's a bunch of garbage? + // ...Well that's not my problem lol. + + s = strtok(content, IPLOGFILESEP); // We got the address + strcpy(joinedIPlist[i][0], s); + + s = strtok(NULL, IPLOGFILESEP); // Let's get rid of this awful \n while we're here! + + if (strlen(s)) + s[strlen(s)-1] = '\0'; // Remove the \n + + strcpy(joinedIPlist[i][1], s); + + i++; + } + fclose(f); // We're done here +} + + // ========================================================================== // CONFIGURATION FILE // ========================================================================== diff --git a/src/m_misc.h b/src/m_misc.h index d06d14397..c85aaad8e 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -42,6 +42,25 @@ void M_StopMovie(void); // the file where game vars and settings are saved #define CONFIGFILENAME "kartconfig.cfg" +// The file where we'll save the last IPs we joined +#define IPLOGFILE "kartsavedips.txt" +#define IPLOGFILESEP ";" +#define NUMLOGIP 3 + +// Array where we'll store addresses to display for last servers joined +// {address, servame} +// 255 is long enough to store the text +extern char joinedIPlist[NUMLOGIP][2][255]; + +// Keep the address we're joining in mind until we've finished joining. +// Since we don't wanna add an IP address we aren't even sure worked out. +extern char joinedIP[255]; + +void M_InitJoinedIPArray(void); +void M_AddToJoinedIPs(char *address, char *servname); +void M_SaveJoinedIPs(void); +void M_LoadJoinedIPs(void); + INT32 M_MapNumber(char first, char second); boolean FIL_WriteFile(char const *name, const void *source, size_t length); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index a21ff7d99..fbac5e7a7 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -1801,6 +1801,7 @@ void I_Quit(void) M_SaveConfig(NULL); //save game config, cvars.. #ifndef NONET D_SaveBan(); // save the ban list + M_SaveJoinedIPs(); #endif // Make sure you lose points for ALT-F4