diff --git a/src/eos.cpp b/src/eos.cpp index 543166f48..6abd42a09 100644 --- a/src/eos.cpp +++ b/src/eos.cpp @@ -27,6 +27,7 @@ #include "interface/ui.hpp" #include "lobbies.hpp" #include "prng.hpp" +#include "ui/MainMenu.hpp" EOSFuncs EOS; @@ -400,14 +401,16 @@ void EOS_CALL EOSFuncs::OnCreateLobbyFinished(const EOS_Lobby_CreateLobbyCallbac EOSFuncs::logError("OnCreateLobbyFinished: null data"); return; } - else if ( data->ResultCode == EOS_EResult::EOS_Success ) + + EOS.CurrentLobbyData.LobbyCreationResult = data->ResultCode; + if ( data->ResultCode == EOS_EResult::EOS_Success ) { EOS.CurrentLobbyData.LobbyId = data->LobbyId; EOS.CurrentLobbyData.LobbyAttributes.lobbyName = EOS.CurrentUserInfo.Name + "'s lobby"; strncpy(EOS.currentLobbyName, EOS.CurrentLobbyData.LobbyAttributes.lobbyName.c_str(), 31); - Uint32 keygen = local_rng.rand() % (1679615 + 1); // limit of 'zzzz' as base-36 string + Uint32 keygen = local_rng.uniform(0, (36 * 36 * 36 * 36) - 1); // limit of 'zzzz' as base-36 string EOS.CurrentLobbyData.LobbyAttributes.gameJoinKey = EOS.getLobbyCodeFromGameKey(keygen); std::chrono::system_clock::duration epochDuration = std::chrono::system_clock::now().time_since_epoch(); EOS.CurrentLobbyData.LobbyAttributes.lobbyCreationTime = std::chrono::duration_cast(epochDuration).count(); @@ -895,11 +898,21 @@ void EOS_CALL EOSFuncs::OnMemberStatusReceived(const EOS_Lobby_LobbyMemberStatus { if ( data->CurrentStatus == EOS_ELobbyMemberStatus::EOS_LMS_CLOSED || (data->CurrentStatus == EOS_ELobbyMemberStatus::EOS_LMS_KICKED - && (data->TargetUserId == EOS.CurrentUserInfo.getProductUserIdHandle())) + && data->TargetUserId == EOS.CurrentUserInfo.getProductUserIdHandle()) ) { // if lobby closed or we got kicked, then clear data. LobbyLeaveCleanup(EOS.CurrentLobbyData); + switch (data->CurrentStatus) { + case EOS_ELobbyMemberStatus::EOS_LMS_CLOSED: + //MainMenu::disconnectedFromServer("The host has shutdown the lobby."); + break; + case EOS_ELobbyMemberStatus::EOS_LMS_KICKED: + //MainMenu::disconnectedFromServer("You have been kicked\nfrom the online lobby."); + break; + default: + break; + } } else { @@ -907,7 +920,6 @@ void EOS_CALL EOSFuncs::OnMemberStatusReceived(const EOS_Lobby_LobbyMemberStatus EOSFuncs::logInfo("OnMemberStatusReceived: received user: %s, event: %d, updating lobby", EOSFuncs::Helpers_t::shortProductIdToString(data->TargetUserId).c_str(), static_cast(data->CurrentStatus)); - return; } } break; @@ -1817,6 +1829,17 @@ void EOSFuncs::searchLobbies(LobbyParameters_t::LobbySearchOptions searchType, { LobbySearchResults.lastResultWasFiltered = false; + if ( LobbySearchResults.useLobbyCode ) + { + for ( int c = 0; c < 4 && EOS.lobbySearchByCode[c] != 0; ++c ) + { + if ( EOS.lobbySearchByCode[c] >= 'A' && EOS.lobbySearchByCode[c] <= 'Z' ) + { + EOS.lobbySearchByCode[c] = 'a' + (EOS.lobbySearchByCode[c] - 'A'); // to lowercase. + } + } + } + LobbyHandle = EOS_Platform_GetLobbyInterface(PlatformHandle); logInfo("searchLobbies: starting search"); EOS_Lobby_CreateLobbySearchOptions CreateSearchOptions = {}; diff --git a/src/eos.hpp b/src/eos.hpp index 06c322254..35fb72487 100644 --- a/src/eos.hpp +++ b/src/eos.hpp @@ -276,6 +276,7 @@ class EOSFuncs bool bLobbyHasBasicDetailsRead = false; bool bAwaitingLeaveCallback = false; bool bAwaitingCreationCallback = false; + EOS_EResult LobbyCreationResult = EOS_EResult::EOS_Success; bool bDenyLobbyJoinEvent = false; class PlayerLobbyData_t { diff --git a/src/lobbies.cpp b/src/lobbies.cpp index b9f43884b..40034564f 100644 --- a/src/lobbies.cpp +++ b/src/lobbies.cpp @@ -61,6 +61,15 @@ std::string LobbyHandler_t::getLobbyJoinFailedConnectString(int result) snprintf(buf, 1023, "Failed to join lobby:\n\nLobby is full."); break; #ifdef USE_EOS +#ifdef STEAMWORKS + case static_cast(EOS_EResult::EOS_InvalidUser): + snprintf(buf, 1023, "Failed to join lobby:\n\nCrossplay not enabled."); + break; +#else + case static_cast(EOS_EResult::EOS_InvalidUser): + snprintf(buf, 1023, "Failed to join lobby:\n\nNot connected to Epic Online."); + break; +#endif case static_cast(EOS_EResult::EOS_NotFound): snprintf(buf, 1023, "Failed to join lobby:\n\nLobby no longer exists."); break; @@ -713,13 +722,6 @@ void LobbyHandler_t::searchLobbyWithFilter(button_t* my) { #ifdef USE_EOS EOS.LobbySearchResults.showLobbiesInProgress = LobbyHandler.filterShowInProgressLobbies; - for ( int c = 0; c < 4 && EOS.lobbySearchByCode[c] != 0; ++c ) - { - if ( EOS.lobbySearchByCode[c] >= 'A' && EOS.lobbySearchByCode[c] <= 'Z' ) - { - EOS.lobbySearchByCode[c] = 'a' + (EOS.lobbySearchByCode[c] - 'A'); // to lowercase. - } - } if ( strcmp(EOS.lobbySearchByCode, "") != 0 ) { diff --git a/src/menu.cpp b/src/menu.cpp index aa21b9e53..e620cde9c 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -11278,7 +11278,7 @@ void openSteamLobbyWaitWindow(button_t* my) #ifdef STEAMWORKS //c_SteamMatchmaking_RequestLobbyList(); //SteamMatchmaking()->RequestLobbyList(); //TODO: Is this sufficient for it to work? - cpp_SteamMatchmaking_RequestLobbyList(); + //cpp_SteamMatchmaking_RequestLobbyList(); #endif LobbyHandler.selectedLobbyInList = 0; diff --git a/src/player.cpp b/src/player.cpp index 340c43f39..a7a0820c5 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -23,6 +23,7 @@ #include "ui/GameUI.hpp" #include "ui/Frame.hpp" #include "ui/Slider.hpp" +#include "lobbies.hpp" #ifdef NINTENDO #include "nintendo/baronynx.hpp" @@ -5537,3 +5538,56 @@ void Player::clearGUIPointers() } skillSheetEntryFrames[playernum].legendFrame = nullptr; } + +const char* Player::getAccountName() const { + if (directConnect) { + switch (playernum) { + case 0: return "Player 1"; + case 1: return "Player 2"; + case 2: return "Player 3"; + case 3: return "Player 4"; + default: return "Player X"; + } + } else { + if (LobbyHandler.getP2PType() == LobbyHandler_t::LobbyServiceType::LOBBY_STEAM) { +#ifdef STEAMWORKS + if (isLocalPlayer()) { + return SteamFriends()->GetPersonaName(); + } else { + for (int remoteIDIndex = 0; remoteIDIndex < MAXPLAYERS; ++remoteIDIndex) { + if (steamIDRemote[remoteIDIndex]) { + const char* memberNumChar = SteamMatchmaking()->GetLobbyMemberData( + *static_cast(currentLobby), + *static_cast(steamIDRemote[remoteIDIndex]), + "clientnum"); + if (memberNumChar) { + std::string str = memberNumChar; + if (!str.empty()) { + int memberNum = std::stoi(str); + if (memberNum >= 0 && memberNum < MAXPLAYERS && memberNum == playernum) { + return SteamFriends()->GetFriendPersonaName( + *static_cast(steamIDRemote[remoteIDIndex])); + } + } + } + } + } + } +#endif + } + else if (LobbyHandler.getP2PType() == LobbyHandler_t::LobbyServiceType::LOBBY_CROSSPLAY) { +#if defined USE_EOS + if (isLocalPlayer()) { + return EOS.CurrentUserInfo.Name.c_str(); + } else { + for (auto& player : EOS.CurrentLobbyData.playersInLobby) { + if (player.clientNumber == playernum) { + return player.name.c_str(); + } + } + } +#endif + } + } + return "Unknown"; +} \ No newline at end of file diff --git a/src/player.hpp b/src/player.hpp index 79275e8e4..569e2c9fa 100644 --- a/src/player.hpp +++ b/src/player.hpp @@ -616,6 +616,8 @@ class Player void init(); void cleanUpOnEntityRemoval(); + const char* getAccountName() const; + view_t& camera() const { return *cam; } const int camera_x1() const { return cam->winx; } const int camera_x2() const { return cam->winx + cam->winw; } diff --git a/src/steam.cpp b/src/steam.cpp index a6d531127..4ee668952 100644 --- a/src/steam.cpp +++ b/src/steam.cpp @@ -35,6 +35,7 @@ #ifdef STEAMWORKS +static std::string roomkey_cached; Uint32 numSteamLobbies = 0; int selectedSteamLobby = 0; char lobbyText[MAX_STEAM_LOBBIES][64]; @@ -679,12 +680,19 @@ SteamAPICall_t cpp_SteamMatchmaking_RequestAppTicket() return m_SteamCallResultEncryptedAppTicket; } -SteamAPICall_t cpp_SteamMatchmaking_RequestLobbyList() +SteamAPICall_t cpp_SteamMatchmaking_RequestLobbyList(const char* roomkey) { + if (roomkey) { + SteamMatchmaking()->AddRequestLobbyListStringFilter("roomkey", roomkey, ELobbyComparison::k_ELobbyComparisonEqual); + roomkey_cached = roomkey; + } else { + roomkey_cached = ""; + } SteamMatchmaking()->AddRequestLobbyListDistanceFilter(ELobbyDistanceFilter::k_ELobbyDistanceFilterWorldwide); SteamMatchmaking()->AddRequestLobbyListNearValueFilter("lobbyCreationTime", SteamUtils()->GetServerRealTime()); - SteamMatchmaking()->AddRequestLobbyListNumericalFilter("lobbyModifiedTime", - SteamUtils()->GetServerRealTime() - 8, k_ELobbyComparisonEqualToOrGreaterThan); + auto realtime = SteamUtils()->GetServerRealTime(); + SteamMatchmaking()->AddRequestLobbyListNumericalFilter("lobbyModifiedTime", + realtime - 8, k_ELobbyComparisonEqualToOrGreaterThan); SteamAPICall_t m_SteamCallResultLobbyMatchList = SteamMatchmaking()->RequestLobbyList(); steam_server_client_wrapper->m_SteamCallResultLobbyMatchList_Set(m_SteamCallResultLobbyMatchList); return m_SteamCallResultLobbyMatchList; @@ -1397,6 +1405,7 @@ void steam_OnLobbyMatchListCallback( void* pCallback, bool bIOFailure ) { // we had a Steam I/O failure - we probably timed out talking to the Steam back-end servers // doesn't matter in this case, we can just act if no lobbies were received + printlog("steam_OnLobbyMatchListCallback() failed - are we disconnected from steam?"); } // lobbies are returned in order of closeness to the user, so add them to the list in that order @@ -1409,10 +1418,12 @@ void steam_OnLobbyMatchListCallback( void* pCallback, bool bIOFailure ) lobbyIDs[iLobby] = steamIDLobby; // pull some info from the lobby metadata (name, players, etc) - const char* lobbyName = SteamMatchmaking()->GetLobbyData(*static_cast(steamIDLobby), "name"); //TODO: Again with the void pointers. - const char* lobbyVersion = SteamMatchmaking()->GetLobbyData(*static_cast(steamIDLobby), "ver"); //TODO: VOID. - int numPlayers = SteamMatchmaking()->GetNumLobbyMembers(*static_cast(steamIDLobby)); //TODO MORE VOID POINTERS. - const char* lobbyNumMods = SteamMatchmaking()->GetLobbyData(*static_cast(steamIDLobby), "svNumMods"); //TODO: VOID. + auto lobby = *static_cast(steamIDLobby); + const char* lobbyTime = SteamMatchmaking()->GetLobbyData(lobby, "lobbyModifiedTime"); + const char* lobbyName = SteamMatchmaking()->GetLobbyData(lobby, "name"); + const char* lobbyVersion = SteamMatchmaking()->GetLobbyData(lobby, "ver"); + const int numPlayers = SteamMatchmaking()->GetNumLobbyMembers(lobby); + const char* lobbyNumMods = SteamMatchmaking()->GetLobbyData(lobby, "svNumMods"); int numMods = atoi(lobbyNumMods); string versionText = lobbyVersion; if ( versionText == "" ) @@ -1455,6 +1466,13 @@ void steam_OnLobbyMatchListCallback( void* pCallback, bool bIOFailure ) lobbyPlayers[iLobby] = 0; } } + if (!roomkey_cached.empty()) { + roomkey_cached = ""; + if (numSteamLobbies) { + multiplayer = SINGLE; + MainMenu::receivedInvite(lobbyIDs[0]); + } + } } //Helper func. //TODO: Bugger it! @@ -1532,6 +1550,22 @@ void* cpp_LobbyCreated_Lobby(void* pCallback) return id; } +static std::string generateRoomKey(Uint32 key) +{ + const char allChars[37] = "0123456789abcdefghijklmnopqrstuvwxyz"; + std::string code = ""; + while ( key != 0 ) + { + code += (allChars[key % 36]); + key /= 36; + } + while ( code.size() < 4 ) + { + code += '0'; + } + return code; +} + void steam_OnLobbyCreated( void* pCallback, bool bIOFailure ) { #ifdef STEAMDEBUG @@ -1555,6 +1589,12 @@ void steam_OnLobbyCreated( void* pCallback, bool bIOFailure ) // set the game version of the lobby SteamMatchmaking()->SetLobbyData(*lobby, "ver", VERSION); + // set room key + Uint32 keygen = local_rng.uniform(0, (36 * 36 * 36 * 36) - 1); // limit of 'zzzz' as base-36 string + auto key = generateRoomKey(keygen); + SteamMatchmaking()->SetLobbyData(*lobby, "roomkey", key.c_str()); + printlog("Steam room key is: %s", key.c_str()); + // set lobby server flags char svFlagsChar[16]; snprintf(svFlagsChar, 15, "%d", svFlags); diff --git a/src/steam.hpp b/src/steam.hpp index 509b4e7c5..b92f2a97a 100644 --- a/src/steam.hpp +++ b/src/steam.hpp @@ -60,7 +60,7 @@ extern int connectingToLobbyStatus; //These are all an utter bodge. //They should not exist, but potato. //TODO: Remove all of these wrappers and access the steam stuff directly. -SteamAPICall_t cpp_SteamMatchmaking_RequestLobbyList(); +SteamAPICall_t cpp_SteamMatchmaking_RequestLobbyList(const char* roomkey); SteamAPICall_t cpp_SteamMatchmaking_JoinLobby(CSteamID steamIDLobby); SteamAPICall_t cpp_SteamMatchmaking_CreateLobby(ELobbyType eLobbyType, int cMaxMembers); SteamAPICall_t cpp_SteamMatchmaking_RequestAppTicket(); diff --git a/src/ui/MainMenu.cpp b/src/ui/MainMenu.cpp index e1a0547cb..e5ec712ce 100644 --- a/src/ui/MainMenu.cpp +++ b/src/ui/MainMenu.cpp @@ -5754,6 +5754,7 @@ namespace MainMenu { const Uint32 seconds = time(NULL) / seconds_in_day; if (add_to_list) { + playSound(238, 64); lobby_chat_messages.emplace_back(LobbyChatMessage{seconds, color, msg}); if (lobby_chat_messages.size() > lobby_chat_max_messages) { lobby_chat_messages.pop_front(); @@ -5771,11 +5772,7 @@ namespace MainMenu { auto frame = lobby->findFrame("chat window"); if (!frame) { frame = toggleLobbyChatWindow(); - assert(frame); - } - - if (add_to_list) { - playSound(238, 64); + return; } const int w = frame->getSize().w; @@ -5785,7 +5782,7 @@ namespace MainMenu { auto subframe_size = subframe->getActualSize(); int y = subframe_size.h; - static ConsoleVariable timestamp_messages("/chat_timestamp", true); + static ConsoleVariable timestamp_messages("/chat_timestamp", false); char buf[1024]; const Uint32 hour = seconds / 3600; @@ -5807,8 +5804,9 @@ namespace MainMenu { field->setColor(color); field->setText(buf); - (void)snprintf(buf, sizeof(buf), "[%.2u:%.2u:%.2u]", hour, min, sec); - field->setTooltip(buf); + //char tooltip_buf[32]; + //(void)snprintf(tooltip_buf, sizeof(tooltip_buf), "[%.2u:%.2u:%.2u]", hour, min, sec); + //field->setTooltip(tooltip_buf); const int new_w = std::max(subframe_size.w, text_w + 8); @@ -5980,9 +5978,12 @@ namespace MainMenu { chat_buffer->setColor(makeColor(201, 162, 100, 255)); chat_buffer->setEditable(true); chat_buffer->setCallback([](Field& field){ - sendChatMessageOverNet(field.getText()); - field.setText(""); - field.activate(); + auto text = field.getText(); + if (text && *text) { + sendChatMessageOverNet(text); + field.setText(""); + field.activate(); + } }); chat_buffer->setTickCallback([](Widget& widget){ auto field = static_cast(&widget); @@ -6045,10 +6046,6 @@ namespace MainMenu { } static void disconnectFromLobby() { - if (multiplayer == SINGLE) { - return; - } - if (multiplayer == SERVER) { // send disconnect message to clients for (int c = 1; c < MAXPLAYERS; c++) { @@ -6140,12 +6137,16 @@ namespace MainMenu { net_packet->address.port = net_clients[c - 1].port; sendPacketSafe(net_sock, -1, net_packet, c - 1); } - char shortname[32] = { 0 }; - strncpy(shortname, stats[i]->name, 22); char buf[1024]; - snprintf(buf, sizeof(buf), language[1376], shortname); + snprintf(buf, sizeof(buf), "*** %s has timed out ***", players[i]->getAccountName()); addLobbyChatMessage(0xffffffff, buf); + + if (directConnect) { + createWaitingStone(i); + } else { + createInviteButton(i); + } continue; } } @@ -6172,14 +6173,18 @@ namespace MainMenu { } if (hostHasLostP2P) { -#if defined(STEAMWORKS) - auto error_code = connectingToLobbyStatus; -#elif defined(USE_EOS) - auto error_code = EOS.ConnectingToLobbyStatus; -#else - auto error_code = -1; // just so this compiles always -#endif - auto error_str = LobbyHandler_t::getLobbyJoinFailedConnectString(error_code); + int error_code = -1; + if (LobbyHandler.getP2PType() == LobbyHandler_t::LobbyServiceType::LOBBY_CROSSPLAY) { +#ifdef USE_EOS + error_code = EOS.ConnectingToLobbyStatus; +#endif // USE_EOS + } + else if (LobbyHandler.getP2PType() == LobbyHandler_t::LobbyServiceType::LOBBY_STEAM) { +#ifdef STEAMWORKS + error_code = connectingToLobbyStatus; +#endif //STEAMWORKS + } + auto error_str = LobbyHandler_t::getLobbyJoinFailedConnectString(error_code); disconnectFromLobby(); destroyMainMenu(); createMainMenu(false); @@ -6319,9 +6324,13 @@ namespace MainMenu { return; } + char fmt[1024]; + int len = snprintf(fmt, sizeof(fmt), "%s: %s", players[clientnum]->getAccountName(), msg); + len = std::min((int)sizeof(fmt), len); + strcpy((char*)net_packet->data, "CMSG"); - strcat((char*)(net_packet->data), msg); - net_packet->len = 4 + strlen(msg) + 1; + strcat((char*)(net_packet->data), fmt); + net_packet->len = 4 + len + 1; net_packet->data[net_packet->len - 1] = 0; // send packet @@ -6334,7 +6343,7 @@ namespace MainMenu { net_packet->address.port = net_clients[i - 1].port; sendPacketSafe(net_sock, -1, net_packet, i - 1); } - addLobbyChatMessage(0xffffffff, msg); + addLobbyChatMessage(0xffffffff, fmt); } else if (multiplayer == CLIENT) { net_packet->address.host = net_server.host; net_packet->address.port = net_server.port; @@ -6592,6 +6601,10 @@ namespace MainMenu { // finally, open a player card! if (playerNum >= 1 && playerNum < MAXPLAYERS) { createReadyStone(playerNum, false, false); + + char buf[1024]; + snprintf(buf, sizeof(buf), "*** %s has joined the game ***", players[playerNum]->getAccountName()); + addLobbyChatMessage(0xffffffff, buf); } continue; @@ -6681,12 +6694,16 @@ namespace MainMenu { sendPacketSafe(net_sock, -1, net_packet, c - 1); } - char shortname[32] = { 0 }; - strncpy(shortname, stats[player]->name, 22); - char buf[1024]; - snprintf(buf, sizeof(buf), language[1376], shortname); + snprintf(buf, sizeof(buf), "*** %s has left the game ***", players[player]->getAccountName()); addLobbyChatMessage(0xffffffff, buf); + + if (directConnect) { + createWaitingStone(player); + } else { + createInviteButton(player); + } + continue; } @@ -7022,11 +7039,8 @@ namespace MainMenu { stats[player]->playerRace = net_packet->data[8]; strcpy(stats[player]->name, (char*)(&net_packet->data[9])); - char shortname[32] = { 0 }; - strncpy(shortname, stats[player]->name, 22); - char buf[1024]; - snprintf(buf, sizeof(buf), language[1388], shortname); + snprintf(buf, sizeof(buf), "*** %s has joined the game ***", players[player]->getAccountName()); addLobbyChatMessage(0xffffffff, buf); if (player != clientnum) { @@ -7079,7 +7093,7 @@ namespace MainMenu { connectionErrorPrompt("You have been kicked\nfrom the remote server."); } else { char buf[1024]; - snprintf(buf, sizeof(buf), language[1120], stats[playerDisconnected]->name); + snprintf(buf, sizeof(buf), "*** %s has left the game ***", players[playerDisconnected]->getAccountName()); addLobbyChatMessage(0xffffffff, buf); if (directConnect) { createWaitingStone(playerDisconnected); @@ -7127,6 +7141,38 @@ namespace MainMenu { handlePacketsAsClient(); } doKeepAlive(); + + // push username to lobby + if (multiplayer != SINGLE && !directConnect) { + if (LobbyHandler.getP2PType() == LobbyHandler_t::LobbyServiceType::LOBBY_CROSSPLAY) { +#ifdef USE_EOS + if (EOS.CurrentLobbyData.currentLobbyIsValid()) { + if (EOS.CurrentLobbyData.getClientnumMemberAttribute(EOS.CurrentUserInfo.getProductUserIdHandle()) < 0) { + if (EOS.CurrentLobbyData.assignClientnumMemberAttribute(EOS.CurrentUserInfo.getProductUserIdHandle(), clientnum)) { + EOS.CurrentLobbyData.modifyLobbyMemberAttributeForCurrentUser(); + } + } + } +#endif + } + + if (LobbyHandler.getP2PType() == LobbyHandler_t::LobbyServiceType::LOBBY_STEAM) { +#ifdef STEAMWORKS + if (currentLobby) { + const char* memberNumChar = SteamMatchmaking()->GetLobbyMemberData( + *static_cast(currentLobby), SteamUser()->GetSteamID(), "clientnum"); + if (memberNumChar) { + std::string str = memberNumChar; + if (str.empty() || std::to_string(clientnum) != str) { + SteamMatchmaking()->SetLobbyMemberData(*static_cast(currentLobby), + "clientnum", std::to_string(clientnum).c_str()); + printlog("[STEAM Lobbies]: Updating clientnum %d to lobby member data", clientnum); + } + } + } +#endif + } + } } static void setupNetGameAsServer() { @@ -7150,10 +7196,10 @@ namespace MainMenu { } static void finalizeOnlineLobby() { - closeNetworkInterfaces(); - directConnect = false; if (LobbyHandler.getHostingType() == LobbyHandler_t::LobbyServiceType::LOBBY_STEAM) { #ifdef STEAMWORKS + closeNetworkInterfaces(); + directConnect = false; for ( int c = 0; c < MAXPLAYERS; c++ ) { if ( steamIDRemote[c] ) { cpp_Free_CSteamID(steamIDRemote[c]); @@ -7162,10 +7208,6 @@ namespace MainMenu { } ::currentLobbyType = k_ELobbyTypePublic; cpp_SteamMatchmaking_CreateLobby(::currentLobbyType, MAXPLAYERS); -#endif - } else if (LobbyHandler.getHostingType() == LobbyHandler_t::LobbyServiceType::LOBBY_CROSSPLAY) { -#ifdef USE_EOS - EOS.createLobby(); #endif } setupNetGameAsServer(); @@ -7414,6 +7456,17 @@ namespace MainMenu { if (strncmp(address, steam_str, sizeof(steam_str) - 1) == 0) { lobby = getLobbySteamID(address); } + else if ((char)tolower((int)address[0]) == 's' && strlen(address) == 5) { + connectingToLobby = true; + connectingToLobbyWindow = true; + joinLobbyWaitingForHostResponse = true; + LobbyHandler.setLobbyJoinType(LobbyHandler_t::LobbyServiceType::LOBBY_STEAM); + LobbyHandler.setP2PType(LobbyHandler_t::LobbyServiceType::LOBBY_STEAM); + flushP2PPackets(100, 200); + requestingLobbies = true; + cpp_SteamMatchmaking_RequestLobbyList(address + 1); + return true; + } } else if (pLobby) { lobby = static_cast(pLobby); @@ -7440,6 +7493,23 @@ namespace MainMenu { if (strncmp(address, epic_str, sizeof(epic_str) - 1) == 0) { lobby = getLobbyEpic(address); } + else if ((char)tolower((int)address[0]) == 'e' && strlen(address) == 5) { + memcpy(EOS.lobbySearchByCode, address + 1, 4); + EOS.lobbySearchByCode[4] = '\0'; + EOS.LobbySearchResults.useLobbyCode = true; + EOS.bConnectingToLobby = true; + EOS.bConnectingToLobbyWindow = true; + EOS.bJoinLobbyWaitingForHostResponse = true; + LobbyHandler.setLobbyJoinType(LobbyHandler_t::LobbyServiceType::LOBBY_CROSSPLAY); + LobbyHandler.setP2PType(LobbyHandler_t::LobbyServiceType::LOBBY_CROSSPLAY); + flushP2PPackets(100, 200); + EOS.searchLobbies( + EOSFuncs::LobbyParameters_t::LobbySearchOptions::LOBBY_SEARCH_ALL, + EOSFuncs::LobbyParameters_t::LobbyJoinOptions::LOBBY_JOIN_FIRST_SEARCH_RESULT, + ""); + EOS.LobbySearchResults.useLobbyCode = false; + return true; + } } else if (pLobby) { lobby = static_cast(pLobby); @@ -11214,7 +11284,11 @@ namespace MainMenu { } else { strcpy(shortname, stats[player]->name); } - field->setText(shortname); + + char buf[128]; + snprintf(buf, sizeof(buf), "%s\n(%s)", shortname, players[player]->getAccountName()); + + field->setText(buf); }); if (local) { @@ -11512,7 +11586,6 @@ namespace MainMenu { soundCancel(); disconnectFromLobby(); destroyMainMenu(); - currentLobbyType = LobbyType::None; createMainMenu(false); } else { binaryPrompt( @@ -11522,7 +11595,6 @@ namespace MainMenu { soundActivate(); disconnectFromLobby(); destroyMainMenu(); - currentLobbyType = LobbyType::None; createMainMenu(false); }, [](Button& button){ // no @@ -12100,15 +12172,6 @@ namespace MainMenu { } #endif - // set state -#ifdef STEAMWORKS - requestingLobbies = true; -#endif -#if defined USE_EOS - EOS.bRequestingLobbies = true; -#endif - LobbyHandler.selectedLobbyInList = 0; - // create new window textPrompt("lobby_list_request", "Requesting lobby list...", [](Widget& widget){ @@ -12131,7 +12194,7 @@ namespace MainMenu { LobbyInfo info; info.name = lobbyText[c]; info.players = lobbyPlayers[c]; - info.ping = 100; // TODO + info.ping = 50; // TODO info.locked = false; // TODO info.flags = 0; // TODO info.address = "steam:" + std::to_string(c); @@ -12144,7 +12207,7 @@ namespace MainMenu { LobbyInfo info; info.name = lobby.LobbyAttributes.lobbyName; info.players = MAXPLAYERS - lobby.FreeSlots; - info.ping = 100; // TODO + info.ping = 50; // TODO info.locked = lobby.LobbyAttributes.gameCurrentLevel != -1; info.flags = lobby.LobbyAttributes.serverFlags; info.address = "epic:" + std::to_string(c); @@ -12155,10 +12218,13 @@ namespace MainMenu { }); // request new lobbies + LobbyHandler.selectedLobbyInList = 0; #ifdef STEAMWORKS - cpp_SteamMatchmaking_RequestLobbyList(); + requestingLobbies = true; + cpp_SteamMatchmaking_RequestLobbyList(nullptr); #endif #ifdef USE_EOS + EOS.bRequestingLobbies = true; #ifdef STEAMWORKS if ( EOS.CurrentUserInfo.bUserLoggedIn ) { @@ -13607,6 +13673,33 @@ namespace MainMenu { "host_lan_image" ); + auto host_online_fn = [](Button&){ + soundActivate(); +#ifdef USE_EOS + if (LobbyHandler.getHostingType() == LobbyHandler_t::LobbyServiceType::LOBBY_CROSSPLAY) { + closeNetworkInterfaces(); + directConnect = false; + EOS.createLobby(); + textPrompt("host_eos_prompt", "Creating online lobby...", + [](Widget&){ + if (EOS.CurrentLobbyData.bAwaitingCreationCallback) { + return; + } else { + if (EOS.CurrentLobbyData.LobbyCreationResult == EOS_EResult::EOS_Success) { + createLobby(LobbyType::LobbyOnline); + } else { + closePrompt("host_eos_prompt"); + monoPrompt("Failed to create lobby", "Okay", + [](Button&){soundCancel(); closeMono();}); + } + } + }); + } +#else + createLobby(LobbyType::LobbyOnline); +#endif + }; + auto host_online_button = window->addButton("host_online"); host_online_button->setSize(SDL_Rect{96, 232, 164, 62}); host_online_button->setBackground("*images/ui/Main Menus/Play/NewGameConnectivity/ButtonStandard/Button_Standard_Default_00.png"); @@ -13628,7 +13721,7 @@ namespace MainMenu { host_online_button->setWidgetUp("host_lan"); host_online_button->setWidgetDown("join"); #if defined(STEAMWORKS) || defined(USE_EOS) - host_online_button->setCallback([](Button&){soundActivate(); createLobby(LobbyType::LobbyOnline);}); + host_online_button->setCallback(host_online_fn); #else host_online_button->setCallback([](Button&){soundError();}); #endif @@ -15843,13 +15936,17 @@ namespace MainMenu { } void disconnectedFromServer(const char* text) { - // when a player is disconnected from the server in-game - multiplayer = SINGLE; - disconnectFromLobby(); - destroyMainMenu(); - createDummyMainMenu(); - disconnectPrompt(text); - pauseGame(2, 0); + // when a player is disconnected from the server + if (multiplayer != SINGLE) { + multiplayer = SINGLE; + disconnectFromLobby(); + destroyMainMenu(); + createDummyMainMenu(); + disconnectPrompt(text); + if (!intro) { + pauseGame(2, 0); + } + } } void openGameoverWindow(int player, bool tutorial) {