
Changes: - Switch from pointer singleton to pre-instanced singleton - Added default constructor to cache_file object - Fixed an issue where maps and vectors would not be cleared before (re)generating a cache.
198 lines
6.9 KiB
C++
198 lines
6.9 KiB
C++
#include "persist_weapons.hpp"
|
|
|
|
#include "gta/weapons.hpp"
|
|
#include "natives.hpp"
|
|
#include "services/gta_data/gta_data_service.hpp"
|
|
|
|
namespace big
|
|
{
|
|
static weaponloadout_json persist_weapon_loadout;
|
|
|
|
void persist_weapons::save_weapons(std::string loadout_name)
|
|
{
|
|
Player player = self::id;
|
|
Ped player_ped = self::ped;
|
|
weaponloadout_json weapon_json{};
|
|
for (const auto& [name, weapon] : g_gta_data_service.weapons())
|
|
{
|
|
Hash weapon_hash = weapon.m_hash;
|
|
if (weapon_hash != WEAPON_UNARMED && WEAPON::HAS_PED_GOT_WEAPON(player_ped, weapon_hash, FALSE))
|
|
{
|
|
weaponloadout_weapon_json weapon_loadout;
|
|
weapon_loadout.weapon = weapon_hash;
|
|
weapon_loadout.group = rage::joaat("GROUP_" + weapon.m_weapon_type);
|
|
weapon_loadout.tint = WEAPON::GET_PED_WEAPON_TINT_INDEX(player_ped, weapon_hash);
|
|
for (auto component : weapon.m_attachments)
|
|
{
|
|
Hash component_hash = rage::joaat(component);
|
|
if (WEAPON::HAS_PED_GOT_WEAPON_COMPONENT(player_ped, weapon_hash, component_hash))
|
|
weapon_loadout.component_array.push_back(component_hash);
|
|
}
|
|
weapon_json.weapons.push_back(weapon_loadout);
|
|
}
|
|
}
|
|
if (WEAPON::HAS_PED_GOT_WEAPON(player_ped, GADGET_PARACHUTE, FALSE))
|
|
{
|
|
weapon_json.parachutes = 1;
|
|
int parachute_tint, parachute_pack_tint, reserve_pack_tint, smoke_trail[3]{};
|
|
bool hasReserve = PLAYER::GET_PLAYER_HAS_RESERVE_PARACHUTE(player);
|
|
PLAYER::GET_PLAYER_PARACHUTE_TINT_INDEX(player, ¶chute_tint);
|
|
PLAYER::GET_PLAYER_PARACHUTE_PACK_TINT_INDEX(player, ¶chute_pack_tint);
|
|
weapon_json.parachute_tint = parachute_tint;
|
|
weapon_json.parachute_pack_tint = parachute_pack_tint;
|
|
if (hasReserve == true)
|
|
{
|
|
weapon_json.parachutes = 2;
|
|
PLAYER::GET_PLAYER_RESERVE_PARACHUTE_TINT_INDEX(player, &reserve_pack_tint);
|
|
weapon_json.reserve_pack_tint = reserve_pack_tint;
|
|
}
|
|
PLAYER::GET_PLAYER_PARACHUTE_SMOKE_TRAIL_COLOR(player,
|
|
&weapon_json.smoke_trail[0],
|
|
&weapon_json.smoke_trail[1],
|
|
&weapon_json.smoke_trail[2]);
|
|
}
|
|
|
|
nlohmann::json json_output_file = weapon_json;
|
|
const auto file = get_weapon_config_folder().get_file(loadout_name + ".json");
|
|
std::ofstream file_stream(file.get_path(), std::ios::out | std::ios::trunc);
|
|
file_stream << json_output_file.dump(4);
|
|
file_stream.close();
|
|
}
|
|
|
|
void persist_weapons::set_weapon_loadout(std::string loadout_name)
|
|
{
|
|
if (loadout_name.empty())
|
|
return;
|
|
|
|
g.persist_weapons.weapon_loadout_file = loadout_name;
|
|
persist_weapon_loadout = get_loadout(loadout_name);
|
|
}
|
|
|
|
void persist_weapons::check_player_has_weapons()
|
|
{
|
|
if (!g.persist_weapons.enabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (persist_weapon_loadout.weapons.empty())
|
|
{
|
|
if (g.persist_weapons.weapon_loadout_file.empty())
|
|
{
|
|
return;
|
|
}
|
|
persist_weapon_loadout = get_loadout(g.persist_weapons.weapon_loadout_file);
|
|
}
|
|
|
|
if (g_local_player == nullptr || g_local_player->m_player_info == nullptr || g_local_player->m_player_info->m_game_state == eGameState::InMPCutscene || STREAMING::IS_PLAYER_SWITCH_IN_PROGRESS() || DLC::GET_IS_LOADING_SCREEN_ACTIVE()) [[unlikely]]
|
|
{
|
|
return;
|
|
}
|
|
|
|
give_Loadout(persist_weapon_loadout);
|
|
}
|
|
|
|
void persist_weapons::give_player_loadout(std::string loadout_name)
|
|
{
|
|
give_Loadout(get_loadout(loadout_name));
|
|
}
|
|
|
|
weaponloadout_json persist_weapons::get_loadout(std::string loadout_name)
|
|
{
|
|
auto file = get_weapon_config_folder().get_file(loadout_name);
|
|
|
|
if (file.exists())
|
|
{
|
|
std::ifstream file_stream(file.get_path());
|
|
try
|
|
{
|
|
nlohmann::json json_input_file;
|
|
|
|
file_stream >> json_input_file;
|
|
file_stream.close();
|
|
|
|
weaponloadout_json loadout = json_input_file;
|
|
return loadout;
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
g_notification_service.push_warning("Persist Weapons", "Failed to load JSON file from disk.");
|
|
LOG(WARNING) << "Persist Weapons failed to load JSON file: " << g.persist_weapons.weapon_loadout_file << " because " << e.what();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g.persist_weapons.weapon_loadout_file.clear();
|
|
LOG(WARNING) << "persist_weapons cannot open file" << g.persist_weapons.weapon_loadout_file;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
big::folder persist_weapons::get_weapon_config_folder()
|
|
{
|
|
const auto folder = g_file_manager.get_project_folder("./weapon_loadouts");
|
|
|
|
return folder;
|
|
}
|
|
|
|
std::vector<std::string> persist_weapons::list_weapon_loadouts()
|
|
{
|
|
std::vector<std::string> file_paths;
|
|
|
|
const auto file_path = get_weapon_config_folder();
|
|
for (const auto& directory_entry : std::filesystem::directory_iterator(file_path.get_path()))
|
|
if (directory_entry.path().extension() == ".json")
|
|
file_paths.push_back(directory_entry.path().filename().generic_string());
|
|
|
|
return file_paths;
|
|
}
|
|
|
|
void persist_weapons::give_Loadout(const weaponloadout_json& loadout)
|
|
{
|
|
Player player = self::id;
|
|
Ped player_ped = self::ped;
|
|
if (PED::IS_PED_DEAD_OR_DYING(player_ped, true)) [[unlikely]]
|
|
return;
|
|
|
|
for (auto weapon : loadout.weapons)
|
|
{
|
|
Hash weapon_hash = weapon.weapon;
|
|
bool is_gun = (weapon.group != GROUP_MELEE);
|
|
if (WEAPON::HAS_PED_GOT_WEAPON(player_ped, weapon_hash, FALSE) == false
|
|
|| (is_gun && (WEAPON::GET_PED_WEAPON_TINT_INDEX(player_ped, weapon_hash) != weapon.tint || (WEAPON::GET_AMMO_IN_PED_WEAPON(player_ped, weapon_hash) == 0))))
|
|
{
|
|
int maxAmmo;
|
|
if (WEAPON::GET_MAX_AMMO(player_ped, weapon_hash, &maxAmmo) == FALSE)
|
|
maxAmmo = 9999;
|
|
WEAPON::GIVE_WEAPON_TO_PED(player_ped, weapon_hash, maxAmmo, FALSE, FALSE);
|
|
if (weapon.group != GROUP_MELEE)
|
|
{
|
|
WEAPON::SET_PED_WEAPON_TINT_INDEX(player_ped, weapon_hash, weapon.tint);
|
|
for (auto component : g_gta_data_service.weapon_by_hash(weapon_hash).m_attachments)
|
|
WEAPON::REMOVE_WEAPON_COMPONENT_FROM_PED(player_ped, weapon_hash, rage::joaat(component));
|
|
for (auto component : weapon.component_array)
|
|
WEAPON::GIVE_WEAPON_COMPONENT_TO_PED(player_ped, weapon_hash, component);
|
|
WEAPON::GIVE_WEAPON_TO_PED(player_ped, weapon_hash, (WEAPON::GET_MAX_AMMO(player_ped, weapon_hash, &maxAmmo) == TRUE) ? maxAmmo : 9999, FALSE, FALSE); //Mk II weapons require giving the weapon to the player twice for them to work, because reasons.
|
|
}
|
|
}
|
|
}
|
|
if (loadout.parachutes != 0)
|
|
{
|
|
WEAPON::GIVE_WEAPON_TO_PED(player_ped, GADGET_PARACHUTE, 1, FALSE, FALSE);
|
|
PLAYER::SET_PLAYER_PARACHUTE_TINT_INDEX(player, loadout.parachute_tint);
|
|
PLAYER::SET_PLAYER_PARACHUTE_PACK_TINT_INDEX(player, loadout.parachute_pack_tint);
|
|
if (loadout.parachutes == 2)
|
|
{
|
|
PLAYER::SET_PLAYER_HAS_RESERVE_PARACHUTE(player);
|
|
PLAYER::SET_PLAYER_RESERVE_PARACHUTE_TINT_INDEX(player, loadout.reserve_pack_tint);
|
|
}
|
|
auto smoke_trail = loadout.smoke_trail;
|
|
if ((smoke_trail[0] + smoke_trail[1] + smoke_trail[2]) != 765) //255 + 255 + 255
|
|
{
|
|
PLAYER::SET_PLAYER_CAN_LEAVE_PARACHUTE_SMOKE_TRAIL(player, TRUE);
|
|
PLAYER::SET_PLAYER_PARACHUTE_SMOKE_TRAIL_COLOR(player, smoke_trail[0], smoke_trail[1], smoke_trail[2]);
|
|
}
|
|
}
|
|
}
|
|
}
|