From d1e4b0830c2e7c58b9988100cfb42fff5fe66f39 Mon Sep 17 00:00:00 2001 From: gir489 <100792176+gir489returns@users.noreply.github.com> Date: Wed, 14 Aug 2024 02:41:47 -0400 Subject: [PATCH] Refactor Weapons JSON parser to associate path with recentness (#3565) * Added a RPF parse hierarchy to ensure the latest weapon file is loaded into the Weapons JSON. * Fixed erroneous attachment descriptions being displayed and persisted to the Weapons JSON. * Fix for components that had empty descriptions. --- src/services/gta_data/gta_data_service.cpp | 49 +++++++++++++++++++--- src/services/gta_data/weapon_item.hpp | 17 +++++++- src/views/self/view_weapons.cpp | 7 ++-- 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/services/gta_data/gta_data_service.cpp b/src/services/gta_data/gta_data_service.cpp index 6d31c432..d0c68164 100644 --- a/src/services/gta_data/gta_data_service.cpp +++ b/src/services/gta_data/gta_data_service.cpp @@ -218,6 +218,27 @@ namespace big std::sort(m_weapon_types.begin(), m_weapon_types.end()); } + static RPFDatafileSource determine_file_type(std::string file_path, std::string_view rpf_filename) + { + if (file_path.contains("/dlc_patch/")) + { + return RPFDatafileSource::DLCUPDATE; + } + else if (rpf_filename == "dlc.rpf") + { + return RPFDatafileSource::DLC; + } + else if (rpf_filename == "update.rpf") + { + return RPFDatafileSource::UPDATE; + } + else if (rpf_filename == "common.rpf") + { + return RPFDatafileSource::BASE; + } + return RPFDatafileSource::UNKNOWN; + } + inline void parse_ped(std::vector& peds, std::vector& mapped_peds, pugi::xml_document& doc) { const auto& items = doc.select_nodes("/CPedModelInfo__InitDataList/InitDatas/Item"); @@ -261,7 +282,7 @@ namespace big std::vector peds; std::vector vehicles; //std::vector weapons; - std::unordered_map weapons; + std::unordered_map weapons; std::vector weapon_components; constexpr auto exists = [](const hash_array& arr, uint32_t val) -> bool { @@ -377,6 +398,9 @@ namespace big LocDesc = display_string; } + if (LocDesc.ends_with("INVALID")) + LocDesc.clear(); + weapon_component component; component.m_name = name; @@ -388,9 +412,9 @@ namespace big } }); } - else if (const auto file_str = path.string(); file_str.find("weapon") != std::string::npos && path.extension() == ".meta") + else if (const auto file_str = path.string(); file_str.contains("weapon") && !file_str.contains("vehicle") && path.extension() == ".meta") { - rpf_wrapper.read_xml_file(path, [&exists, &weapons, &mapped_weapons](pugi::xml_document& doc) { + rpf_wrapper.read_xml_file(path, [&exists, &weapons, &mapped_weapons, file_str, &rpf_wrapper](pugi::xml_document& doc) { const auto& items = doc.select_nodes("/CWeaponInfoBlob/Infos/Item/Infos/Item[@type='CWeaponInfo']"); for (const auto& item_node : items) { @@ -408,11 +432,11 @@ namespace big if (std::strcmp(human_name_hash, "WT_INVALID") == 0 || std::strcmp(human_name_hash, "WT_VEHMINE") == 0) continue; - auto weapon = weapon_item{}; + auto weapon = weapon_item_parsed{}; weapon.m_name = name; - weapon.m_display_name = human_name_hash; + weapon.rpf_file_type = determine_file_type(file_str, rpf_wrapper.get_name()); auto weapon_flags = std::string(item.child("WeaponFlags").text().as_string()); @@ -477,6 +501,14 @@ namespace big weapon.m_hash = hash; + if (weapons.contains(hash)) + { + if (weapons[hash].rpf_file_type > weapon.rpf_file_type) + { + continue; + } + } + weapons[hash] = weapon; skip: continue; @@ -540,7 +572,12 @@ namespace big for (auto& item : weapon_components) { item.m_display_name = HUD::GET_FILENAME_FOR_AUDIO_CONVERSATION(item.m_display_name.c_str()); - item.m_display_desc = HUD::GET_FILENAME_FOR_AUDIO_CONVERSATION(item.m_display_desc.c_str()); + if (!item.m_display_desc.empty()) + { + item.m_display_desc = HUD::GET_FILENAME_FOR_AUDIO_CONVERSATION(item.m_display_desc.c_str()); + if (item.m_display_desc == "NULL") + item.m_display_desc.clear(); + } } for (auto it = peds.begin(); it != peds.end();) { diff --git a/src/services/gta_data/weapon_item.hpp b/src/services/gta_data/weapon_item.hpp index c1c16920..4adb76c2 100644 --- a/src/services/gta_data/weapon_item.hpp +++ b/src/services/gta_data/weapon_item.hpp @@ -2,7 +2,16 @@ namespace big { - class weapon_item final + enum RPFDatafileSource : std::uint8_t + { + UNKNOWN, + BASE, + UPDATE, + DLC, + DLCUPDATE + }; + + class weapon_item { public: std::string m_name; @@ -16,4 +25,10 @@ namespace big NLOHMANN_DEFINE_TYPE_INTRUSIVE(weapon_item, m_name, m_display_name, m_weapon_type, m_hash, m_reward_hash, m_reward_ammo_hash, m_attachments, m_throwable) }; + + class weapon_item_parsed : public weapon_item + { + public: + RPFDatafileSource rpf_file_type = RPFDatafileSource::UNKNOWN; + }; } \ No newline at end of file diff --git a/src/views/self/view_weapons.cpp b/src/views/self/view_weapons.cpp index b95f2103..6853c390 100644 --- a/src/views/self/view_weapons.cpp +++ b/src/views/self/view_weapons.cpp @@ -292,19 +292,20 @@ namespace big { continue; } + ImGui::PushID(attachment_hash); bool is_selected = attachment_hash == selected_weapon_attachment_hash; - std::string display_name = attachment_name.append("##").append(std::to_string(attachment_hash)); - if (ImGui::Selectable(display_name.c_str(), is_selected, ImGuiSelectableFlags_None)) + if (ImGui::Selectable(attachment_name.c_str(), is_selected, ImGuiSelectableFlags_None)) { selected_weapon_attachment = attachment_name; selected_weapon_attachment_hash = attachment_hash; } - if (ImGui::IsItemHovered()) + if (ImGui::IsItemHovered() && !attachment_component.m_display_desc.empty()) ImGui::SetTooltip(attachment_component.m_display_desc.c_str()); if (is_selected) { ImGui::SetItemDefaultFocus(); } + ImGui::PopID(); } }