From 3e48d6965a9b27529f79aa3bb5a519b5592aef95 Mon Sep 17 00:00:00 2001 From: Nikhil Narayana Date: Sat, 18 Dec 2021 17:20:42 -0800 Subject: [PATCH] pull in project-slippi/Ishiiruka/commit/5a77120289f7542302a2eb53b9ee2bce43d490f6 enforce stage for fixed rules modes --- Source/Core/Core/HW/EXI/EXI_DeviceSlippi.cpp | 104 ++++++++++++------ Source/Core/Core/HW/EXI/EXI_DeviceSlippi.h | 2 + Source/Core/Core/Slippi/SlippiMatchmaking.cpp | 6 + Source/Core/Core/Slippi/SlippiMatchmaking.h | 1 + 4 files changed, 80 insertions(+), 33 deletions(-) diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.cpp index 43357ef598..a4104d3bee 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.cpp @@ -27,6 +27,7 @@ #include "Core/Host.h" #include "Core/NetPlayClient.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/Slippi/SlippiMatchmaking.h" #include "Core/Slippi/SlippiPlayback.h" #include "Core/Slippi/SlippiReplayComm.h" #include "Core/State.h" @@ -1508,7 +1509,6 @@ bool CEXISlippi::isDisconnected() return status != SlippiNetplayClient::SlippiConnectStatus::NET_CONNECT_STATUS_CONNECTED; } -static int tempTestCount = 0; void CEXISlippi::handleOnlineInputs(u8* payload) { m_read_queue.clear(); @@ -1829,10 +1829,23 @@ void CEXISlippi::startFindMatch(u8* payload) // give someone an early error before they even queue so that they wont enter the queue and make // someone else get force removed from queue and have to requeue auto directMode = SlippiMatchmaking::OnlinePlayMode::DIRECT; - if (search.mode < directMode && localSelections.characterId >= 26) + if (SlippiMatchmaking::IsFixedRulesMode(search.mode)) { - forcedError = "The character you selected is not allowed in this mode"; - return; + // Character check + if (localSelections.characterId >= 26) + { + forcedError = "The character you selected is not allowed in this mode"; + return; + } + + // Stage check + if (localSelections.isStageSelected && + std::find(singlesStages.begin(), singlesStages.end(), localSelections.stageId) == + singlesStages.end()) + { + forcedError = "The stage being requested is not allowed in this mode"; + return; + } } #ifndef LOCAL_TESTING @@ -2070,14 +2083,53 @@ void CEXISlippi::prepareOnlineMatchState() if (rps[i].characterId >= 26) remoteCharOk = false; } - if (lastSearch.mode < directMode && (!localCharOk || !remoteCharOk)) + + // TODO: This is annoying, ideally remotePlayerSelections would just include everyone including + // the local player + // TODO: Would also simplify some logic in the Netplay class + std::vector orderedSelections(4); + orderedSelections[lps.playerIdx] = lps; + for (int i = 0; i < remotePlayerCount; i++) { - // If we get here, someone is doing something bad, clear the lobby - handleConnectionCleanup(); + orderedSelections[rps[i].playerIdx] = rps[i]; + } + + // Overwrite stage information. Make sure everyone loads the same stage + u16 stageId = 0x1F; // Default to battlefield if there was no selection + for (auto selections : orderedSelections) + { + if (!selections.isStageSelected) + continue; + + // Stage selected by this player, use that selection + stageId = selections.stageId; + break; + } + + if (SlippiMatchmaking::IsFixedRulesMode(lastSearch.mode)) + { + // If we enter one of these conditions, someone is doing something bad, clear the lobby if (!localCharOk) + { + handleConnectionCleanup(); forcedError = "The character you selected is not allowed in this mode"; - prepareOnlineMatchState(); - return; + prepareOnlineMatchState(); + return; + } + + if (!remoteCharOk) + { + handleConnectionCleanup(); + prepareOnlineMatchState(); + return; + } + + if (std::find(singlesStages.begin(), singlesStages.end(), stageId) == singlesStages.end()) + { + handleConnectionCleanup(); + prepareOnlineMatchState(); + return; + } } // Overwrite local player character @@ -2121,20 +2173,6 @@ void CEXISlippi::prepareOnlineMatchState() onlineMatchBlock[0x61 + 3 * 0x24] = 0; } - // Overwrite stage - u16 stageId; - if (isDecider) - { - stageId = lps.isStageSelected ? lps.stageId : rps[0].stageId; - } - else - { - stageId = rps[0].isStageSelected ? rps[0].stageId : lps.stageId; - } - - u16* stage = (u16*)&onlineMatchBlock[0xE]; - *stage = Common::swap16(stageId); - // Set rng offset rngOffset = isDecider ? lps.rngOffset : rps[0].rngOffset; WARN_LOG(SLIPPI_ONLINE, "Rng Offset: 0x%x", rngOffset); @@ -2244,22 +2282,22 @@ void CEXISlippi::prepareOnlineMatchState() m_read_queue.insert(m_read_queue.end(), onlineMatchBlock.begin(), onlineMatchBlock.end()); } +std::vector CEXISlippi::singlesStages = { + // 0x2, // FoD + 0x3, // Pokemon + 0x8, // Yoshi's Story + 0x1C, // Dream Land + 0x1F, // Battlefield + 0x20, // Final Destination +}; + u16 CEXISlippi::getRandomStage() { static u16 selectedStage; - static std::vector stages = { - 0x2, // FoD - 0x3, // Pokemon - 0x8, // Yoshi's Story - 0x1C, // Dream Land - 0x1F, // Battlefield - 0x20, // Final Destination - }; - // Reset stage pool if it's empty if (stagePool.empty()) - stagePool.insert(stagePool.end(), stages.begin(), stages.end()); + stagePool.insert(stagePool.end(), singlesStages.begin(), singlesStages.end()); // Get random stage int randIndex = generator() % stagePool.size(); diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.h b/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.h index 278cce5a35..4d39b9d542 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.h +++ b/Source/Core/Core/HW/EXI/EXI_DeviceSlippi.h @@ -251,5 +251,7 @@ private: std::map> activeSavestates; std::deque> availableSavestates; + + static std::vector singlesStages; }; } // namespace ExpansionInterface diff --git a/Source/Core/Core/Slippi/SlippiMatchmaking.cpp b/Source/Core/Core/Slippi/SlippiMatchmaking.cpp index 04810384a0..ccb0966c7d 100644 --- a/Source/Core/Core/Slippi/SlippiMatchmaking.cpp +++ b/Source/Core/Core/Slippi/SlippiMatchmaking.cpp @@ -85,6 +85,12 @@ std::unique_ptr SlippiMatchmaking::GetNetplayClient() return std::move(m_netplayClient); } +bool IsFixedRulesMode(SlippiMatchmaking::OnlinePlayMode mode) +{ + return mode == SlippiMatchmaking::OnlinePlayMode::UNRANKED || + mode == SlippiMatchmaking::OnlinePlayMode::RANKED; +} + void SlippiMatchmaking::sendMessage(json msg) { enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE; diff --git a/Source/Core/Core/Slippi/SlippiMatchmaking.h b/Source/Core/Core/Slippi/SlippiMatchmaking.h index 96df53181e..d8ab24bf27 100644 --- a/Source/Core/Core/Slippi/SlippiMatchmaking.h +++ b/Source/Core/Core/Slippi/SlippiMatchmaking.h @@ -57,6 +57,7 @@ public: std::vector GetPlayerInfo(); std::string GetPlayerName(u8 port); u8 RemotePlayerCount(); + static bool IsFixedRulesMode(OnlinePlayMode mode); protected: const std::string MM_HOST_DEV = "35.197.121.196"; // Dev host