From 179e4bb7845e36415b5aa9d15ca822f46e5a3123 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 17 Dec 2024 23:17:55 -0600 Subject: [PATCH] Missing map files fix: Added check for official DLC maps. Prevents client missing DLC from looking for a usermap_hash in the infoJson when loading a DLC map. TODO: Handle missing map errors gracefully. Added is_dlc_map() to fastfiles header. WIP: logic for map guard. Reworked map checking. Added additional map_exists check... Added map exists checks to connect and set_new_map calls to prevent crashes when non-dlc owner joins or rotates to a dlc map. Should also prevent weird behavior for missing modmaps and joining servers with custom maps the user doesn't own. Added exit vlobby hook to set_new_map after disconenct to ensure client returns to correct state after mid-game disconnect. --- src/client/component/fastfiles.cpp | 29 ++++++++++++ src/client/component/fastfiles.hpp | 11 +++++ src/client/component/party.cpp | 74 +++++++++++++++++++++++------- src/client/tcp/hmw_tcp_utils.cpp | 2 +- 4 files changed, 98 insertions(+), 18 deletions(-) diff --git a/src/client/component/fastfiles.cpp b/src/client/component/fastfiles.cpp index e02bcaf3..d22df866 100644 --- a/src/client/component/fastfiles.cpp +++ b/src/client/component/fastfiles.cpp @@ -1187,11 +1187,40 @@ namespace fastfiles return utils::io::file_exists(utils::string::va("hmw-usermaps\\%s\\%s.ff", name.data(), name.data())); } + bool is_dlc_map(const std::string& name) + { + const std::vector dlc_zone_basenames = { + "carentan", + "broadcast", + "creek", + "killhouse" + }; + + return std::any_of(dlc_zone_basenames.begin(), dlc_zone_basenames.end(), [&](std::string base) { + return name.contains(base); + }); + } + bool is_stock_map(const std::string& name) { return fastfiles::exists(name, true); } + MAP_EXISTS_RESULT map_exists(const std::string& mapname) + { + + if (fastfiles::is_dlc_map(mapname) && fastfiles::exists(mapname)) { return MAP_EXISTS_RESULT::DLC; } + + // michelin: I'm not a fan of the existing is_stock_map or the fastfiles::exists logic. + // we should NOT be checking if a file is in root/zone to see if a map is a stock map... we should be checking a table of mapnames + // the exists check should be explicit and separate, like I've expressed here + if (fastfiles::is_stock_map(mapname) && fastfiles::exists(mapname)) { return MAP_EXISTS_RESULT::BASE_GAME; } + + if (fastfiles::usermap_exists(mapname)) { return MAP_EXISTS_RESULT::USER; } + + return MAP_EXISTS_RESULT::MISSING; + } + void enum_asset_entries(const game::XAssetType type, const std::function& callback, bool include_override) { constexpr auto max_asset_count = 0x25D78; diff --git a/src/client/component/fastfiles.hpp b/src/client/component/fastfiles.hpp index 4a0ac43b..d87e2614 100644 --- a/src/client/component/fastfiles.hpp +++ b/src/client/component/fastfiles.hpp @@ -20,6 +20,17 @@ namespace fastfiles std::optional get_current_usermap(); bool usermap_exists(const std::string& name); bool is_stock_map(const std::string& name); + bool is_dlc_map(const std::string& name); + + enum class MAP_EXISTS_RESULT { + BASE_GAME, + DLC, + USER, + MISSING + }; + + MAP_EXISTS_RESULT map_exists(const std::string& name); + void enum_asset_entries(const game::XAssetType type, const std::function& callback, bool include_override); } diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index 3ee350ea..f24d3186 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -59,8 +59,25 @@ namespace party command::execute("startentitlements", true); } + void disconnect() + { + if (!game::VirtualLobby_Loaded()) + { + if (game::CL_IsCgameInitialized()) + { + // CL_AddReliableCommand + utils::hook::invoke(0x12B810_b, 0, "disconnect"); + // CL_WritePacket + utils::hook::invoke(0x13D490_b, 0); + } + // CL_Disconnect + utils::hook::invoke(0x12F080_b, 0); + } + } + void connect_to_party(const game::netadr_s& target, const std::string& mapname, const std::string& gametype) { + if (game::Live_SyncOnlineDataFlags(0) != 0) { // initialize the game after onlinedataflags is 32 (workaround) @@ -112,22 +129,6 @@ namespace party return utils::string::va("%s", server_connection_state.motd.data()); } - void disconnect() - { - if (!game::VirtualLobby_Loaded()) - { - if (game::CL_IsCgameInitialized()) - { - // CL_AddReliableCommand - utils::hook::invoke(0x12B810_b, 0, "disconnect"); - // CL_WritePacket - utils::hook::invoke(0x13D490_b, 0); - } - // CL_Disconnect - utils::hook::invoke(0x12F080_b, 0); - } - } - utils::hook::detour cl_disconnect_hook; void cl_disconnect_stub(int show_main_menu) // possibly bool @@ -430,7 +431,32 @@ namespace party void set_new_map(const char* mapname, const char* gametype, game::msg_t* msg) { utils::hook::invoke(0x27A040_b); - + + auto map_type = fastfiles::map_exists(mapname); + if (map_type == fastfiles::MAP_EXISTS_RESULT::MISSING) + { + console::error("Failed to find one or more fastfiles for: %s", std::string(mapname).c_str()); + + command::execute("disconnect"); + scheduler::once([] + { + connect(server_connection_state.host); + }, scheduler::pipeline::main); + + // remove from virt lobby? + utils::hook::invoke(0x13C9C0_b, 1); + + menu_error( + "Missing a required map file.\n" + "If map was a...\n" + "Base Game Map: verify game files.\n" + "DLC Map: verify you have the DLC.\n" + "HMW Map: verify mod files with HMW launcher.\n" + ); + + return; + } + if (!fastfiles::is_stock_map(mapname)) { fastfiles::set_usermap(mapname); @@ -708,6 +734,20 @@ namespace party return; } + auto map_type = fastfiles::map_exists(mapname); + if (map_type == fastfiles::MAP_EXISTS_RESULT::MISSING) + { + console::error("Failed to find fastfile for zone: %s", std::string(mapname).c_str()); + menu_error("Missing a required map file.\n" + "If map was a...\n" + "Base Game Map: verify game files.\n" + "DLC Map: verify you have the DLC.\n" + "HMW Map: verify mod files with HMW launcher.\n" + ); + connecting_to_server = false; + return; + } + std::string gametype = jsonObject["gametype"]; if (gametype.empty()) { connecting_to_server = false; diff --git a/src/client/tcp/hmw_tcp_utils.cpp b/src/client/tcp/hmw_tcp_utils.cpp index c68adb62..4b01f7a5 100644 --- a/src/client/tcp/hmw_tcp_utils.cpp +++ b/src/client/tcp/hmw_tcp_utils.cpp @@ -259,7 +259,7 @@ namespace hmw_tcp_utils { void check_download_map_tcp(const nlohmann::json infoJson, std::vector& files) { const std::string mapname = infoJson["mapname"]; - if (fastfiles::is_stock_map(mapname)) + if (fastfiles::is_stock_map(mapname) || fastfiles::is_dlc_map(mapname)) { return; }