diff --git a/Source/DiabloUI/selconn.cpp b/Source/DiabloUI/selconn.cpp index c709b5a87..1e629ea2f 100644 --- a/Source/DiabloUI/selconn.cpp +++ b/Source/DiabloUI/selconn.cpp @@ -8,6 +8,12 @@ namespace devilution { int provider; +const char *ConnectionNames[] { + "ZeroTier", + N_("Client-Server (TCP)"), + N_("Loopback"), +}; + namespace { char selconn_MaxPlayers[21]; @@ -32,13 +38,13 @@ void SelconnLoad() #ifndef NONET #ifndef DISABLE_ZERO_TIER - vecConnItems.push_back(std::make_unique("Zerotier", SELCONN_ZT)); + vecConnItems.push_back(std::make_unique(ConnectionNames[SELCONN_ZT], SELCONN_ZT)); #endif #ifndef DISABLE_TCP - vecConnItems.push_back(std::make_unique(_("Client-Server (TCP)"), SELCONN_TCP)); + vecConnItems.push_back(std::make_unique(_(ConnectionNames[SELCONN_TCP]), SELCONN_TCP)); #endif #endif - vecConnItems.push_back(std::make_unique(_("Loopback"), SELCONN_LOOPBACK)); + vecConnItems.push_back(std::make_unique(_(ConnectionNames[SELCONN_LOOPBACK]), SELCONN_LOOPBACK)); UiAddBackground(&vecSelConnDlg); UiAddLogo(&vecSelConnDlg); diff --git a/Source/DiabloUI/selgame.cpp b/Source/DiabloUI/selgame.cpp index ad1379dc5..11d791029 100644 --- a/Source/DiabloUI/selgame.cpp +++ b/Source/DiabloUI/selgame.cpp @@ -38,6 +38,10 @@ const char *title = ""; std::vector> vecSelGameDlgItems; std::vector> vecSelGameDialog; +std::vector Gamelist; +int HighlightedItem; + +constexpr const char *DefaultPassword = "asd"; } // namespace @@ -74,7 +78,7 @@ void selgame_GameSelection_Init() UiAddLogo(&vecSelGameDialog); SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 }; - vecSelGameDialog.push_back(std::make_unique(_("Client-Server (TCP)"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelGameDialog.push_back(std::make_unique(_(ConnectionNames[provider]), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 211), 205, 192 }; vecSelGameDialog.push_back(std::make_unique(_("Description:"), rect2, UiFlags::FontSize24 | UiFlags::ColorUiSilver)); @@ -88,6 +92,10 @@ void selgame_GameSelection_Init() vecSelGameDlgItems.push_back(std::make_unique(_("Create Game"), 0)); vecSelGameDlgItems.push_back(std::make_unique(_("Join Game"), 1)); + for (unsigned i = 0; i < Gamelist.size(); i++) { + vecSelGameDlgItems.push_back(std::make_unique(Gamelist[i].c_str(), i + 2)); + } + vecSelGameDialog.push_back(std::make_unique(vecSelGameDlgItems, PANEL_LEFT + 305, (UI_OFFSET_Y + 255), 285, 26, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorUiGold)); SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 299), (Sint16)(UI_OFFSET_Y + 427), 140, 35 }; @@ -96,11 +104,12 @@ void selgame_GameSelection_Init() SDL_Rect rect6 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 }; vecSelGameDialog.push_back(std::make_unique(_("CANCEL"), &UiFocusNavigationEsc, rect6, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorUiGold)); - UiInitList(vecSelGameDlgItems.size(), selgame_GameSelection_Focus, selgame_GameSelection_Select, selgame_GameSelection_Esc, vecSelGameDialog, true); + UiInitList(vecSelGameDlgItems.size(), selgame_GameSelection_Focus, selgame_GameSelection_Select, selgame_GameSelection_Esc, vecSelGameDialog, true, nullptr, HighlightedItem); } void selgame_GameSelection_Focus(int value) { + HighlightedItem = value; switch (vecSelGameDlgItems[value]->m_value) { case 0: strncpy(selgame_Description, _("Create a new game with a difficulty setting of your choice."), sizeof(selgame_Description) - 1); @@ -108,6 +117,9 @@ void selgame_GameSelection_Focus(int value) case 1: strncpy(selgame_Description, _("Enter an IP or a hostname and join a game already in progress at that address."), sizeof(selgame_Description) - 1); break; + default: + strncpy(selgame_Description, _("Join the public game already in progress at this address."), sizeof(selgame_Description) - 1); + break; } const std::string wrapped = WordWrapString(selgame_Description, DESCRIPTION_WIDTH); strncpy(selgame_Description, wrapped.data(), sizeof(selgame_Description) - 1); @@ -131,6 +143,13 @@ void selgame_GameSelection_Select(int value) selgame_enteringGame = true; selgame_selectedGame = value; + if (value > 1 && selgame_selectedGame != 0) { + strcpy(selgame_Ip, Gamelist[value - 2].c_str()); + strcpy(selgame_Password, DefaultPassword); + selgame_Password_Select(value); + return; + } + gfnHeroInfo(UpdateHeroLevel); selgame_FreeVectors(); @@ -184,6 +203,7 @@ void selgame_GameSelection_Select(int value) SDL_Rect rect7 = { (Sint16)(PANEL_LEFT + 449), (Sint16)(UI_OFFSET_Y + 427), 140, 35 }; vecSelGameDialog.push_back(std::make_unique(_("CANCEL"), &UiFocusNavigationEsc, rect7, UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::FontSize30 | UiFlags::ColorUiGold)); + HighlightedItem = 0; UiInitList(0, nullptr, selgame_Password_Init, selgame_GameSelection_Init, vecSelGameDialog); break; } @@ -281,6 +301,7 @@ void selgame_Diff_Esc() return; } + HighlightedItem = 0; selgame_GameSelection_Init(); } @@ -372,7 +393,7 @@ void selgame_Password_Init(int /*value*/) UiAddLogo(&vecSelGameDialog); SDL_Rect rect1 = { (Sint16)(PANEL_LEFT + 24), (Sint16)(UI_OFFSET_Y + 161), 590, 35 }; - vecSelGameDialog.push_back(std::make_unique(_("Client-Server (TCP)"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); + vecSelGameDialog.push_back(std::make_unique(_(ConnectionNames[provider]), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 35), (Sint16)(UI_OFFSET_Y + 211), 205, 192 }; vecSelGameDialog.push_back(std::make_unique(_("Description:"), rect2, UiFlags::FontSize24 | UiFlags::ColorUiSilver)); @@ -466,17 +487,50 @@ void selgame_Password_Esc() selgame_GameSpeedSelection(); } +void RefreshGameList() +{ + static uint32_t lastRequest = 0; + static uint32_t lastUpdate = 0; + + if (selgame_enteringGame) + return; + + uint32_t currentTime = SDL_GetTicks(); + + if (lastRequest == 0 || currentTime - lastRequest > 30000) { + DvlNet_SendInfoRequest(); + lastRequest = currentTime; + lastUpdate = currentTime - 3000; // Give 2 sec for responses, but don't wait 5 + } + + if (lastUpdate == 0 || currentTime - lastUpdate > 5000) { + std::vector gamelist = DvlNet_GetGamelist(); + Gamelist.clear(); + for (unsigned i = 0; i < gamelist.size(); i++) { + Gamelist.push_back(gamelist[i]); + } + selgame_GameSelection_Init(); + lastUpdate = currentTime; + } +} + bool UiSelectGame(GameData *gameData, int *playerId) { gdwPlayerId = playerId; m_game_data = gameData; LoadBackgroundArt("ui_art\\selgame.pcx"); + HighlightedItem = 0; selgame_GameSelection_Init(); selgame_endMenu = false; + + DvlNet_SetPassword(DefaultPassword); + DvlNet_ClearGamelist(); + while (!selgame_endMenu) { UiClearScreen(); UiPollAndRender(); + RefreshGameList(); } selgame_Free(); diff --git a/Source/dvlnet/abstract_net.h b/Source/dvlnet/abstract_net.h index df8e233e3..0bca69406 100644 --- a/Source/dvlnet/abstract_net.h +++ b/Source/dvlnet/abstract_net.h @@ -48,6 +48,10 @@ public: { } + virtual void clear_gamelist() + { + } + virtual std::vector get_gamelist() { return std::vector(); diff --git a/Source/dvlnet/base_protocol.h b/Source/dvlnet/base_protocol.h index 1cbc6b6e7..741e65c41 100644 --- a/Source/dvlnet/base_protocol.h +++ b/Source/dvlnet/base_protocol.h @@ -26,6 +26,7 @@ public: virtual std::string make_default_gamename(); virtual void send_info_request(); + virtual void clear_gamelist(); virtual std::vector get_gamelist(); virtual ~base_protocol() = default; @@ -98,9 +99,10 @@ bool base_protocol

::wait_firstpeer() template void base_protocol

::send_info_request() { - auto pkt = pktfty->make_packet(PLR_BROADCAST, - PLR_MASTER); - proto.send_oob_mc(pkt->Data()); + if (wait_network()) { + auto pkt = pktfty->make_packet(PLR_BROADCAST, PLR_MASTER); + proto.send_oob_mc(pkt->Data()); + } } template @@ -273,6 +275,12 @@ void base_protocol

::recv_ingame(packet &pkt, endpoint sender) RecvLocal(pkt); } +template +void base_protocol

::clear_gamelist() +{ + game_list.clear(); +} + template std::vector base_protocol

::get_gamelist() { diff --git a/Source/dvlnet/cdwrap.h b/Source/dvlnet/cdwrap.h index 338f9ae34..413c91134 100644 --- a/Source/dvlnet/cdwrap.h +++ b/Source/dvlnet/cdwrap.h @@ -37,6 +37,10 @@ public: virtual bool SNetGetTurnsInTransit(uint32_t *turns); virtual void setup_gameinfo(buffer_t info); virtual std::string make_default_gamename(); + virtual void send_info_request(); + virtual void clear_gamelist(); + virtual std::vector get_gamelist(); + virtual void setup_password(std::string pw); cdwrap(); virtual ~cdwrap() = default; @@ -161,5 +165,29 @@ std::string cdwrap::make_default_gamename() return dvlnet_wrap->make_default_gamename(); } +template +void cdwrap::send_info_request() +{ + dvlnet_wrap->send_info_request(); +} + +template +void cdwrap::clear_gamelist() +{ + dvlnet_wrap->clear_gamelist(); +} + +template +std::vector cdwrap::get_gamelist() +{ + return dvlnet_wrap->get_gamelist(); +} + +template +void cdwrap::setup_password(std::string pw) +{ + return dvlnet_wrap->setup_password(pw); +} + } // namespace net } // namespace devilution diff --git a/Source/storm/storm.h b/Source/storm/storm.h index acb60d32f..af62b1635 100644 --- a/Source/storm/storm.h +++ b/Source/storm/storm.h @@ -8,6 +8,7 @@ #include "appfat.h" #include "multi.h" +#include "utils/language.h" #include "utils/stdcompat/string_view.hpp" namespace devilution { @@ -23,6 +24,8 @@ enum conn_type : uint8_t { SELCONN_LOOPBACK, }; +extern const char *ConnectionNames[]; + struct PCXHeader { uint8_t Manufacturer; uint8_t Version; @@ -289,4 +292,9 @@ inline std::uint64_t SFileGetFilePointer(HANDLE hFile) #endif +void DvlNet_SendInfoRequest(); +void DvlNet_ClearGamelist(); +std::vector DvlNet_GetGamelist(); +void DvlNet_SetPassword(std::string pw); + } // namespace devilution diff --git a/Source/storm/storm_dvlnet.h b/Source/storm/storm_dvlnet.h deleted file mode 100644 index 286399101..000000000 --- a/Source/storm/storm_dvlnet.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -void DvlNet_SendInfoRequest(); -std::vector DvlNet_GetGamelist(); -void DvlNet_SetPassword(std::string pw); diff --git a/Source/storm/storm_net.cpp b/Source/storm/storm_net.cpp index ebd3907b1..6a906cfcc 100644 --- a/Source/storm/storm_net.cpp +++ b/Source/storm/storm_net.cpp @@ -9,7 +9,6 @@ #include "dvlnet/abstract_net.h" #include "menu.h" #include "options.h" -#include "storm/storm_dvlnet.h" #include "utils/stubs.h" namespace devilution { @@ -219,6 +218,11 @@ void DvlNet_SendInfoRequest() dvlnet_inst->send_info_request(); } +void DvlNet_ClearGamelist() +{ + return dvlnet_inst->clear_gamelist(); +} + std::vector DvlNet_GetGamelist() { return dvlnet_inst->get_gamelist();