Refactored weapons.bin into weapons.json for extensibility and readability. (#1632)
* Refactored weapons.bin into weapons.json for extensibility and human readability. Added weapon attachments scraping from the meta files (currently is missing a lot of attachments, more than half, requires RPF reading refactoring to fix.) Added Ammunation to Self -> Weapons, because it's vital you protect yourself, the patriotic way. * Fixed weapons.xml not properly populating all the components. Refactored buttons to use components::button. * Refactored the Attachments code to implicitly trust that the attachments will be there now. Added proper versioning to the weapons.json file. Removed debug logging from gta_data_service.cpp. * Fixed Ammunation buttons. Added loading message for the new weapons.json system. Fixed a bug where two components shared the same name, the user could not select the 2nd component. Fixed Attachments displaying an attachment from a previous weapon if the user changed weapons. * Fixed Tint Apply button not using the components::button template.
This commit is contained in:
parent
f10c698396
commit
6f40a38045
@ -32,7 +32,6 @@ namespace big
|
||||
gta_data_service::gta_data_service() :
|
||||
m_peds_cache(g_file_manager->get_project_file("./cache/peds.bin"), 5),
|
||||
m_vehicles_cache(g_file_manager->get_project_file("./cache/vehicles.bin"), 4),
|
||||
m_weapons_cache(g_file_manager->get_project_file("./cache/weapons.bin"), 5),
|
||||
m_update_state(eGtaDataUpdateState::IDLE)
|
||||
{
|
||||
if (!is_cache_up_to_date())
|
||||
@ -120,12 +119,28 @@ namespace big
|
||||
|
||||
const weapon_item& gta_data_service::weapon_by_hash(std::uint32_t hash)
|
||||
{
|
||||
for (const auto& [name, weapon] : m_weapons)
|
||||
for (const auto& [name, weapon] : m_weapons_cache.weapon_map)
|
||||
if (rage::joaat(name) == hash)
|
||||
return weapon;
|
||||
return gta_data_service::empty_weapon;
|
||||
}
|
||||
|
||||
const weapon_component& gta_data_service::weapon_component_by_hash(std::uint32_t hash)
|
||||
{
|
||||
for (const auto& component : m_weapons_cache.weapon_components)
|
||||
if (component.second.m_hash == hash)
|
||||
return component.second;
|
||||
return gta_data_service::empty_component;
|
||||
}
|
||||
|
||||
const weapon_component& gta_data_service::weapon_component_by_name(std::string name)
|
||||
{
|
||||
for (const auto& component : m_weapons_cache.weapon_components)
|
||||
if (component.first == name)
|
||||
return component.second;
|
||||
return gta_data_service::empty_component;
|
||||
}
|
||||
|
||||
string_vec& gta_data_service::ped_types()
|
||||
{
|
||||
return m_ped_types;
|
||||
@ -145,7 +160,26 @@ namespace big
|
||||
{
|
||||
m_peds_cache.load();
|
||||
m_vehicles_cache.load();
|
||||
m_weapons_cache.load();
|
||||
|
||||
auto weapons_file = g_file_manager->get_project_file("./cache/weapons.json");
|
||||
if (weapons_file.exists())
|
||||
{
|
||||
std::ifstream file(weapons_file.get_path());
|
||||
file.open(weapons_file.get_path());
|
||||
|
||||
try
|
||||
{
|
||||
nlohmann::json weapons_file_json;
|
||||
file >> weapons_file_json;
|
||||
m_weapons_cache = weapons_file_json["weapons_cache"];
|
||||
file.close();
|
||||
}
|
||||
catch (const std::exception& exception)
|
||||
{
|
||||
file.close();
|
||||
LOG(WARNING) << "Detected corrupt weapons: " << exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
const auto file_version = memory::module("GTA5.exe").size();
|
||||
|
||||
@ -158,7 +192,8 @@ namespace big
|
||||
|
||||
load_peds();
|
||||
load_vehicles();
|
||||
load_weapons();
|
||||
LOG(INFO) << "Loading " << m_weapons_cache.weapon_map.size() << " weapons from cache.";
|
||||
LOG(INFO) << "Loading " << m_weapons_cache.weapon_components.size() << " weapon components from cache.";
|
||||
|
||||
LOG(VERBOSE) << "Loaded all data from cache.";
|
||||
}
|
||||
@ -199,24 +234,6 @@ namespace big
|
||||
m_vehicles_cache.free();
|
||||
}
|
||||
|
||||
void gta_data_service::load_weapons()
|
||||
{
|
||||
const auto weapon_count = m_weapons_cache.data_size() / sizeof(weapon_item);
|
||||
LOG(INFO) << "Loading " << weapon_count << " weapons from cache.";
|
||||
|
||||
auto cached_weapons = reinterpret_cast<const weapon_item*>(m_weapons_cache.data());
|
||||
for (size_t i = 0; i < weapon_count; i++)
|
||||
{
|
||||
const auto weapon = cached_weapons[i];
|
||||
|
||||
add_if_not_exists(m_weapon_types, weapon.m_weapon_type);
|
||||
m_weapons.insert({weapon.m_name, weapon});
|
||||
}
|
||||
|
||||
std::sort(m_weapon_types.begin(), m_weapon_types.end());
|
||||
m_weapons_cache.free();
|
||||
}
|
||||
|
||||
inline void parse_ped(std::vector<ped_item>& peds, std::vector<std::uint32_t>& mapped_peds, pugi::xml_document& doc)
|
||||
{
|
||||
const auto& items = doc.select_nodes("/CPedModelInfo__InitDataList/InitDatas/Item");
|
||||
@ -253,10 +270,12 @@ namespace big
|
||||
hash_array mapped_peds;
|
||||
hash_array mapped_vehicles;
|
||||
hash_array mapped_weapons;
|
||||
hash_array mapped_components;
|
||||
|
||||
std::vector<ped_item> peds;
|
||||
std::vector<vehicle_item> vehicles;
|
||||
std::vector<weapon_item> weapons;
|
||||
std::vector<weapon_component> weapon_components;
|
||||
|
||||
constexpr auto exists = [](const hash_array& arr, std::uint32_t val) -> bool {
|
||||
return std::find(arr.begin(), arr.end(), val) != arr.end();
|
||||
@ -313,6 +332,46 @@ namespace big
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (const auto file_str = path.string(); file_str.find("weaponcomponents") != std::string::npos && path.extension() == ".meta")
|
||||
{
|
||||
rpf_wrapper.read_xml_file(path, [&exists, &weapon_components, &mapped_components](pugi::xml_document& doc) {
|
||||
const auto& items = doc.select_nodes("/CWeaponComponentInfoBlob/Infos/*[self::Item[@type='CWeaponComponentInfo'] or self::Item[@type='CWeaponComponentFlashLightInfo'] or self::Item[@type='CWeaponComponentScopeInfo'] or self::Item[@type='CWeaponComponentSuppressorInfo'] or self::Item[@type='CWeaponComponentVariantModelInfo'] or self::Item[@type='CWeaponComponentClipInfo']]");
|
||||
for (const auto& item_node : items)
|
||||
{
|
||||
const auto item = item_node.node();
|
||||
const std::string name = item.child("Name").text().as_string();
|
||||
const auto hash = rage::joaat(name);
|
||||
|
||||
if (!name.starts_with("COMPONENT"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (exists(mapped_components, hash))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
mapped_components.emplace_back(hash);
|
||||
|
||||
std::string LocName = item.child("LocName").text().as_string();
|
||||
std::string LocDesc = item.child("LocDesc").text().as_string();
|
||||
|
||||
if (LocName.ends_with("INVALID") || LocName.ends_with("RAIL"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
weapon_component component;
|
||||
|
||||
component.m_name = name;
|
||||
component.m_hash = hash;
|
||||
component.m_display_name = LocName;
|
||||
component.m_display_desc = LocDesc;
|
||||
|
||||
weapon_components.push_back(component);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (const auto file_str = path.string(); file_str.find("weapon") != std::string::npos && path.extension() == ".meta")
|
||||
{
|
||||
rpf_wrapper.read_xml_file(path, [&exists, &weapons, &mapped_weapons](pugi::xml_document& doc) {
|
||||
@ -336,9 +395,9 @@ namespace big
|
||||
|
||||
auto weapon = weapon_item{};
|
||||
|
||||
std::strncpy(weapon.m_name, name, sizeof(weapon.m_name));
|
||||
weapon.m_name = name;
|
||||
|
||||
std::strncpy(weapon.m_display_name, human_name_hash, sizeof(weapon.m_display_name));
|
||||
weapon.m_display_name = human_name_hash;
|
||||
|
||||
auto weapon_flags = std::string(item.child("WeaponFlags").text().as_string());
|
||||
|
||||
@ -378,10 +437,10 @@ namespace big
|
||||
|
||||
if (std::strlen(category) > 6)
|
||||
{
|
||||
std::strncpy(weapon.m_weapon_type, category + 6, sizeof(weapon.m_weapon_type));
|
||||
weapon.m_weapon_type = category + 6;
|
||||
}
|
||||
|
||||
if (is_gun || !std::strcmp(weapon.m_weapon_type, "MELEE") || !std::strcmp(weapon.m_weapon_type, "UNARMED"))
|
||||
if (is_gun || weapon.m_weapon_type == "MELEE" || weapon.m_weapon_type == "UNARMED")
|
||||
{
|
||||
const std::string reward_prefix = "REWARD_";
|
||||
weapon.m_reward_hash = rage::joaat(reward_prefix + name);
|
||||
@ -393,6 +452,14 @@ namespace big
|
||||
}
|
||||
}
|
||||
|
||||
for (pugi::xml_node attach_point : item.child("AttachPoints").children("Item"))
|
||||
{
|
||||
for (pugi::xml_node component : attach_point.child("Components").children("Item"))
|
||||
{
|
||||
weapon.m_attachments.push_back(component.child_value("Name"));
|
||||
}
|
||||
}
|
||||
|
||||
weapon.m_hash = hash;
|
||||
|
||||
weapons.emplace_back(std::move(weapon));
|
||||
@ -453,7 +520,12 @@ namespace big
|
||||
}
|
||||
for (auto& item : weapons)
|
||||
{
|
||||
std::strncpy(item.m_display_name, HUD::GET_FILENAME_FOR_AUDIO_CONVERSATION(item.m_display_name), sizeof(item.m_display_name));
|
||||
item.m_display_name = HUD::GET_FILENAME_FOR_AUDIO_CONVERSATION(item.m_display_name.c_str());
|
||||
}
|
||||
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());
|
||||
}
|
||||
for (auto it = peds.begin(); it != peds.end();)
|
||||
{
|
||||
@ -481,10 +553,10 @@ namespace big
|
||||
|
||||
m_update_state = eGtaDataUpdateState::IDLE;
|
||||
LOG(INFO) << "Cache has been rebuilt.\n\tPeds: " << peds.size() << "\n\tVehicles: " << vehicles.size()
|
||||
<< "\n\tWeapons: " << weapons.size();
|
||||
<< "\n\tWeapons: " << weapons.size() << "\n\tWeaponComponents: " << weapon_components.size();
|
||||
|
||||
LOG(VERBOSE) << "Starting cache saving procedure...";
|
||||
g_thread_pool->push([this, peds = std::move(peds), vehicles = std::move(vehicles), weapons = std::move(weapons)] {
|
||||
g_thread_pool->push([this, peds = std::move(peds), vehicles = std::move(vehicles), weapons = std::move(weapons), weapon_components = std::move(weapon_components)] {
|
||||
const auto file_version = memory::module("GTA5.exe").size();
|
||||
|
||||
{
|
||||
@ -506,12 +578,34 @@ namespace big
|
||||
}
|
||||
|
||||
{
|
||||
const auto data_size = sizeof(weapon_item) * weapons.size();
|
||||
m_weapons_cache.set_data(std::make_unique<std::uint8_t[]>(data_size), data_size);
|
||||
std::memcpy(m_weapons_cache.data(), weapons.data(), data_size);
|
||||
m_weapons_cache.version_info.m_game_build = g_pointers->m_gta.m_game_version;
|
||||
m_weapons_cache.version_info.m_online_version = g_pointers->m_gta.m_online_version;
|
||||
m_weapons_cache.version_info.m_file_version = file_version;
|
||||
|
||||
m_weapons_cache.set_header_version(file_version);
|
||||
m_weapons_cache.write();
|
||||
for (auto weapon : weapons)
|
||||
{
|
||||
add_if_not_exists(m_weapon_types, weapon.m_weapon_type);
|
||||
m_weapons_cache.weapon_map.insert({weapon.m_name, weapon});
|
||||
}
|
||||
|
||||
for (auto weapon_component : weapon_components)
|
||||
{
|
||||
m_weapons_cache.weapon_components.insert({weapon_component.m_name, weapon_component});
|
||||
}
|
||||
|
||||
auto weapons_file = big::g_file_manager->get_project_file("./cache/weapons.json");
|
||||
std::ofstream file(weapons_file.get_path());
|
||||
try
|
||||
{
|
||||
nlohmann::json weapons_file_json;
|
||||
weapons_file_json["weapons_cache"] = m_weapons_cache;
|
||||
file << weapons_file_json;
|
||||
file.flush();
|
||||
}
|
||||
catch (const std::exception& exception)
|
||||
{
|
||||
LOG(WARNING) << "Failed to write weapons JSON: " << exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
LOG(INFO) << "Finished writing cache to disk.";
|
||||
@ -519,4 +613,4 @@ namespace big
|
||||
load_data();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
#include "cache_file.hpp"
|
||||
#include "ped_item.hpp"
|
||||
#include "vehicle_item.hpp"
|
||||
#include "weapon_item.hpp"
|
||||
#include "weapon_file.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -20,7 +20,6 @@ namespace big
|
||||
|
||||
using ped_map = std::map<std::string, ped_item>;
|
||||
using vehicle_map = std::map<std::string, vehicle_item>;
|
||||
using weapon_map = std::map<std::string, weapon_item>;
|
||||
using string_vec = std::vector<std::string>;
|
||||
|
||||
class gta_data_service final
|
||||
@ -39,6 +38,8 @@ namespace big
|
||||
const ped_item& ped_by_hash(std::uint32_t hash);
|
||||
const vehicle_item& vehicle_by_hash(std::uint32_t hash);
|
||||
const weapon_item& weapon_by_hash(std::uint32_t hash);
|
||||
const weapon_component& weapon_component_by_hash(std::uint32_t hash);
|
||||
const weapon_component& weapon_component_by_name(std::string name);
|
||||
|
||||
string_vec& ped_types();
|
||||
string_vec& vehicle_classes();
|
||||
@ -52,9 +53,13 @@ namespace big
|
||||
{
|
||||
return m_vehicles;
|
||||
}
|
||||
weapon_map& weapons()
|
||||
std::map<std::string, weapon_item>& weapons()
|
||||
{
|
||||
return m_weapons;
|
||||
return m_weapons_cache.weapon_map;
|
||||
}
|
||||
std::map<std::string, weapon_component>& weapon_components()
|
||||
{
|
||||
return m_weapons_cache.weapon_components;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -63,19 +68,17 @@ namespace big
|
||||
void load_data();
|
||||
void load_peds();
|
||||
void load_vehicles();
|
||||
void load_weapons();
|
||||
|
||||
void rebuild_cache();
|
||||
|
||||
private:
|
||||
cache_file m_peds_cache;
|
||||
cache_file m_vehicles_cache;
|
||||
cache_file m_weapons_cache;
|
||||
weapon_file m_weapons_cache;
|
||||
|
||||
// std::map is free sorting algo
|
||||
ped_map m_peds;
|
||||
vehicle_map m_vehicles;
|
||||
weapon_map m_weapons;
|
||||
|
||||
string_vec m_ped_types;
|
||||
string_vec m_vehicle_classes;
|
||||
@ -87,6 +90,7 @@ namespace big
|
||||
static constexpr ped_item empty_ped{};
|
||||
static constexpr vehicle_item empty_vehicle{};
|
||||
static constexpr weapon_item empty_weapon{};
|
||||
static constexpr weapon_component empty_component{};
|
||||
};
|
||||
|
||||
inline gta_data_service* g_gta_data_service{};
|
||||
|
15
src/services/gta_data/weapon_component.hpp
Normal file
15
src/services/gta_data/weapon_component.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace big
|
||||
{
|
||||
class weapon_component final
|
||||
{
|
||||
public:
|
||||
std::string m_name;
|
||||
Hash m_hash;
|
||||
std::string m_display_name;
|
||||
std::string m_display_desc;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(weapon_component, m_name, m_hash, m_display_name, m_display_desc)
|
||||
};
|
||||
}
|
30
src/services/gta_data/weapon_file.hpp
Normal file
30
src/services/gta_data/weapon_file.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include "weapon_item.hpp"
|
||||
#include "weapon_component.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
|
||||
class weapon_file
|
||||
{
|
||||
public:
|
||||
struct version_info
|
||||
{
|
||||
std::string m_game_build;
|
||||
std::string m_online_version;
|
||||
std::uint32_t m_file_version;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(version_info, m_game_build, m_online_version, m_file_version)
|
||||
} version_info{};
|
||||
|
||||
std::map<std::string, weapon_item> weapon_map;
|
||||
std::map<std::string, weapon_component> weapon_components;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE(weapon_file, version_info, weapon_map, weapon_components)
|
||||
|
||||
bool up_to_date(std::uint32_t file_version) const
|
||||
{
|
||||
return file_version == version_info.m_file_version;
|
||||
}
|
||||
};
|
||||
}
|
@ -2,17 +2,18 @@
|
||||
|
||||
namespace big
|
||||
{
|
||||
#pragma pack(push, 4)
|
||||
class weapon_item final
|
||||
{
|
||||
public:
|
||||
char m_name[32];
|
||||
char m_display_name[32];
|
||||
char m_weapon_type[16];
|
||||
std::string m_name;
|
||||
std::string m_display_name;
|
||||
std::string m_weapon_type;
|
||||
std::uint32_t m_hash;
|
||||
std::uint32_t m_reward_hash;
|
||||
std::uint32_t m_reward_ammo_hash;
|
||||
std::vector<std::string> m_attachments;
|
||||
bool m_throwable;
|
||||
|
||||
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)
|
||||
};
|
||||
#pragma pack(pop)
|
||||
}
|
@ -181,4 +181,4 @@ namespace big
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -176,5 +176,93 @@ namespace big
|
||||
ImGui::SliderFloat("Distance", &g.weapons.aimbot.distance, 1.f, 1000.f, "%.0f");
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Ammunation");
|
||||
static Hash selected_weapon_hash, selected_weapon_attachment_hash{};
|
||||
static std::string selected_weapon, selected_weapon_attachment;
|
||||
ImGui::PushItemWidth(300);
|
||||
if (ImGui::BeginCombo("Weapons", selected_weapon.c_str()))
|
||||
{
|
||||
for (auto& weapon : g_gta_data_service->weapons())
|
||||
{
|
||||
bool is_selected = weapon.second.m_hash == selected_weapon_hash;
|
||||
if (weapon.second.m_display_name != "NULL" && ImGui::Selectable(weapon.second.m_display_name.c_str(), is_selected, ImGuiSelectableFlags_None))
|
||||
{
|
||||
selected_weapon = weapon.second.m_display_name;
|
||||
selected_weapon_hash = weapon.second.m_hash;
|
||||
selected_weapon_attachment_hash = {};
|
||||
selected_weapon_attachment.clear();
|
||||
}
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine();
|
||||
components::button("Give Weapon", [] {
|
||||
WEAPON::GIVE_WEAPON_TO_PED(self::ped, selected_weapon_hash, 9999, false, true);
|
||||
});
|
||||
ImGui::SameLine();
|
||||
components::button("Remove Weapon", [] {
|
||||
WEAPON::REMOVE_WEAPON_FROM_PED(self::ped, selected_weapon_hash);
|
||||
});
|
||||
|
||||
ImGui::PushItemWidth(250);
|
||||
if (ImGui::BeginCombo("Attachments", selected_weapon_attachment.c_str()))
|
||||
{
|
||||
auto weapon = g_gta_data_service->weapon_by_hash(selected_weapon_hash);
|
||||
if (!weapon.m_attachments.empty())
|
||||
{
|
||||
for (std::string attachment : weapon.m_attachments)
|
||||
{
|
||||
auto attachment_component = g_gta_data_service->weapon_component_by_name(attachment);
|
||||
std::string attachment_name = attachment_component.m_display_name;
|
||||
Hash attachment_hash = attachment_component.m_hash;
|
||||
if (attachment_hash == NULL)
|
||||
{
|
||||
attachment_name = attachment;
|
||||
attachment_hash = rage::joaat(attachment);
|
||||
}
|
||||
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))
|
||||
{
|
||||
selected_weapon_attachment = attachment_name;
|
||||
selected_weapon_attachment_hash = attachment_hash;
|
||||
}
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
components::button("Add to Weapon", [] {
|
||||
WEAPON::GIVE_WEAPON_COMPONENT_TO_PED(self::ped, selected_weapon_hash, selected_weapon_attachment_hash);
|
||||
});
|
||||
ImGui::SameLine();
|
||||
components::button("Remove from Weapon", [] {
|
||||
WEAPON::REMOVE_WEAPON_COMPONENT_FROM_PED(self::ped, selected_weapon_hash, selected_weapon_attachment_hash);
|
||||
});
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
static const char* default_tints[]{"Black tint", "Green tint", "Gold tint", "Pink tint", "Army tint", "LSPD tint", "Orange tint", "Platinum tint"};
|
||||
static const char* mk2_tints[]{"Classic Black", "Classic Grey", "Classic Two - Tone", "Classic White", "Classic Beige", "Classic Green", "Classic Blue", "Classic Earth", "Classic Brown & Black", "Red Contrast", "Blue Contrast", "Yellow Contrast", "Orange Contrast", "Bold Pink", "Bold Purple & Yellow", "Bold Orange", "Bold Green & Purple", "Bold Red Features", "Bold Green Features", "Bold Cyan Features", "Bold Yellow Features", "Bold Red & White", "Bold Blue & White", "Metallic Gold", "Metallic Platinum", "Metallic Grey & Lilac", "Metallic Purple & Lime", "Metallic Red", "Metallic Green", "Metallic Blue", "Metallic White & Aqua", "Metallic Red & Yellow"};
|
||||
static int tint;
|
||||
|
||||
if (selected_weapon.ends_with("Mk II"))
|
||||
{
|
||||
ImGui::Combo("Tints", &tint, mk2_tints, IM_ARRAYSIZE(mk2_tints));
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::Combo("Tints", &tint, default_tints, IM_ARRAYSIZE(default_tints));
|
||||
}
|
||||
ImGui::SameLine();
|
||||
components::button("Apply", [] {
|
||||
WEAPON::SET_PED_WEAPON_TINT_INDEX(self::ped, selected_weapon_hash, tint);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -491,7 +491,7 @@ namespace big
|
||||
if (ImGui::BeginCombo("##ped_weapon",
|
||||
selected_ped_weapon_type == SPAWN_PED_NO_WEAPONS ? "NO_WEAPONS"_T.data() :
|
||||
selected_ped_weapon_hash == 0 ? "ALL"_T.data() :
|
||||
g_gta_data_service->weapon_by_hash(selected_ped_weapon_hash).m_display_name))
|
||||
g_gta_data_service->weapon_by_hash(selected_ped_weapon_hash).m_display_name.c_str()))
|
||||
{
|
||||
if (selected_ped_weapon_type != SPAWN_PED_NO_WEAPONS)
|
||||
{
|
||||
@ -509,7 +509,7 @@ namespace big
|
||||
{
|
||||
if (selected_ped_weapon_type == SPAWN_PED_ALL_WEAPONS || weapon.m_weapon_type == weapon_type_arr[selected_ped_weapon_type])
|
||||
{
|
||||
if (ImGui::Selectable(weapon.m_display_name, weapon.m_hash == selected_ped_weapon_hash))
|
||||
if (ImGui::Selectable(weapon.m_display_name.c_str(), weapon.m_hash == selected_ped_weapon_hash))
|
||||
{
|
||||
selected_ped_weapon_hash = weapon.m_hash;
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ namespace big
|
||||
std::string filter = new_template.m_weapon_model;
|
||||
std::transform(p_model.begin(), p_model.end(), p_model.begin(), ::tolower);
|
||||
std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower);
|
||||
if (p_model.find(filter) != std::string::npos && ImGui::Selectable(p.m_name))
|
||||
if (p_model.find(filter) != std::string::npos && ImGui::Selectable(p.m_name.c_str()))
|
||||
{
|
||||
new_template.m_weapon_model = p.m_name;
|
||||
}
|
||||
|
Reference in New Issue
Block a user