Redesigned Vehicle Spawn menus to have consistent features. (#2063)
Closes #2053
This commit is contained in:
@ -2,6 +2,7 @@
|
||||
#include "fiber_pool.hpp"
|
||||
#include "script.hpp"
|
||||
#include "services/vehicle/persist_car_service.hpp"
|
||||
#include "services/model_preview/model_preview_service.hpp"
|
||||
#include "util/mobile.hpp"
|
||||
#include "util/teleport.hpp"
|
||||
#include "views/view.hpp"
|
||||
@ -22,13 +23,15 @@ namespace big
|
||||
{
|
||||
if (!selected_vehicle_file.empty())
|
||||
{
|
||||
const auto vehicle = persist_car_service::load_vehicle(selected_vehicle_file, g.vehicle.persist_vehicle_sub_folder);
|
||||
const auto vehicle = persist_car_service::load_vehicle(selected_vehicle_file, g.persist_car.persist_vehicle_sub_folder);
|
||||
if (!vehicle)
|
||||
{
|
||||
g_notification_service->push_warning("PERSIST_CAR"_T.data(), "PERSIST_CAR_TO_MANY_SPAWNED"_T.data());
|
||||
}
|
||||
else if (g.spawn_vehicle.spawn_inside)
|
||||
else if (g.persist_car.spawn_inside)
|
||||
{
|
||||
teleport::into_vehicle(vehicle);
|
||||
}
|
||||
|
||||
selected_vehicle_file.clear();
|
||||
}
|
||||
@ -43,25 +46,47 @@ namespace big
|
||||
static std::string selected_vehicle_file;
|
||||
|
||||
const auto vehicle_folders = persist_car_service::list_sub_folders();
|
||||
const auto vehicle_files = persist_car_service::list_files(g.vehicle.persist_vehicle_sub_folder);
|
||||
const auto vehicle_files = persist_car_service::list_files(g.persist_car.persist_vehicle_sub_folder);
|
||||
|
||||
if (ImGui::Checkbox("PREVIEW"_T.data(), &g.persist_car.preview_vehicle))
|
||||
{
|
||||
if (!g.persist_car.preview_vehicle)
|
||||
{
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("PREVIEW_DESC"_T.data());
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("SPAWN_IN"_T.data(), &g.persist_car.spawn_inside);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("SPAWN_IN_DESC"_T.data());
|
||||
|
||||
auto folder_display = g.vehicle.persist_vehicle_sub_folder.empty() ? "ROOT"_T.data() : g.vehicle.persist_vehicle_sub_folder.c_str();
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
auto folder_display = g.persist_car.persist_vehicle_sub_folder.empty() ?
|
||||
"ROOT"_T.data() :
|
||||
g.persist_car.persist_vehicle_sub_folder.c_str();
|
||||
if (ImGui::BeginCombo("FOLDER"_T.data(), folder_display))
|
||||
{
|
||||
if (ImGui::Selectable("ROOT"_T.data(), g.vehicle.persist_vehicle_sub_folder == ""))
|
||||
g.vehicle.persist_vehicle_sub_folder = "";
|
||||
if (ImGui::Selectable("ROOT"_T.data(), g.persist_car.persist_vehicle_sub_folder == ""))
|
||||
g.persist_car.persist_vehicle_sub_folder.clear();
|
||||
|
||||
for (std::string folder_name : vehicle_folders)
|
||||
{
|
||||
if (ImGui::Selectable(folder_name.c_str(), g.vehicle.persist_vehicle_sub_folder == folder_name))
|
||||
g.vehicle.persist_vehicle_sub_folder = folder_name;
|
||||
if (ImGui::Selectable(folder_name.c_str(), g.persist_car.persist_vehicle_sub_folder == folder_name))
|
||||
g.persist_car.persist_vehicle_sub_folder = folder_name;
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
ImGui::PushItemWidth(250);
|
||||
static char search[64];
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
components::input_text_with_hint("FILE_NAME"_T, "SEARCH"_T, search, sizeof(search), ImGuiInputTextFlags_None);
|
||||
std::string lower_search = search;
|
||||
std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower);
|
||||
|
||||
ImGui::SetNextItemWidth(250);
|
||||
ImGui::Text("SAVED_VEHICLES"_T.data());
|
||||
|
||||
static const auto over_30 = (30 * ImGui::GetTextLineHeightWithSpacing() + 2);
|
||||
@ -70,12 +95,29 @@ namespace big
|
||||
{
|
||||
for (const auto& pair : vehicle_files)
|
||||
{
|
||||
if (ImGui::Selectable(pair.c_str(), selected_vehicle_file == pair))
|
||||
std::string pair_lower = pair;
|
||||
std::transform(pair_lower.begin(), pair_lower.end(), pair_lower.begin(), tolower);
|
||||
if (pair_lower.contains(lower_search))
|
||||
{
|
||||
selected_vehicle_file = pair;
|
||||
g_fiber_pool->queue_job([] {
|
||||
load_vehicle(selected_vehicle_file);
|
||||
});
|
||||
if (ImGui::Selectable(pair.c_str(), selected_vehicle_file == pair))
|
||||
{
|
||||
selected_vehicle_file = pair;
|
||||
g_fiber_pool->queue_job([] {
|
||||
load_vehicle(selected_vehicle_file);
|
||||
g_model_preview_service->stop_preview();
|
||||
});
|
||||
}
|
||||
|
||||
if (!g.persist_car.preview_vehicle || (g.persist_car.preview_vehicle && !ImGui::IsAnyItemHovered()))
|
||||
{
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
else if (ImGui::IsItemHovered())
|
||||
{
|
||||
g_fiber_pool->queue_job([pair] {
|
||||
g_model_preview_service->show_vehicle_persisted(pair);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,19 +130,17 @@ namespace big
|
||||
static char vehicle_file_name_input[50]{};
|
||||
|
||||
components::small_text("VEHICLE_FILE_NAME"_T);
|
||||
ImGui::PushItemWidth(250);
|
||||
ImGui::SetNextItemWidth(250);
|
||||
ImGui::InputText("##vehiclefilename", vehicle_file_name_input, IM_ARRAYSIZE(vehicle_file_name_input));
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("VEHICLE_FILE_NAME_EXAMPLE"_T.data());
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
static char save_folder[50]{};
|
||||
components::small_text("VEHICLE_FOLDER_NAME"_T);
|
||||
ImGui::PushItemWidth(250);
|
||||
ImGui::SetNextItemWidth(250);
|
||||
ImGui::InputText("##foldername", save_folder, IM_ARRAYSIZE(save_folder));
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("VEHICLE_FOLDER_NAME_EXAMPLE"_T.data());
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
components::button("SAVE_VEHICLE"_T, [] {
|
||||
if (!self::veh)
|
||||
|
@ -19,27 +19,28 @@ namespace big
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("PREVIEW_DESC"_T.data());
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("SPAWN_IN"_T.data(), &g.clone_pv.spawn_inside);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("SPAWN_IN_DESC"_T.data());
|
||||
ImGui::SameLine();
|
||||
|
||||
static char plate_buf[9] = {0};
|
||||
int num_of_rows = 3;
|
||||
|
||||
ImGui::Checkbox("SPAWN_CLONE"_T.data(), &g.clone_pv.spawn_clone);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("SPAWN_CLONE_DESC"_T.data());
|
||||
if (g.clone_pv.spawn_clone)
|
||||
{
|
||||
num_of_rows = 5;
|
||||
|
||||
ImGui::Checkbox("SPAWN_MAXED"_T.data(), &g.clone_pv.spawn_maxed);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("SPAWN_MAXED_DESC"_T.data());
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("CLONE_PV_PLATE"_T.data(), &g.clone_pv.clone_plate);
|
||||
if (g.clone_pv.clone_plate)
|
||||
{
|
||||
num_of_rows = 4;
|
||||
}
|
||||
else
|
||||
if (!g.clone_pv.clone_plate)
|
||||
{
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
|
||||
@ -86,7 +87,44 @@ namespace big
|
||||
components::input_text_with_hint("MODEL_NAME"_T, "SEARCH"_T, search, sizeof(search), ImGuiInputTextFlags_None);
|
||||
|
||||
g_mobile_service->refresh_personal_vehicles();
|
||||
if (ImGui::BeginListBox("###personal_veh_list", {300, static_cast<float>(*g_pointers->m_gta.m_resolution_y - 188 - 38 * num_of_rows)}))
|
||||
|
||||
auto num_of_rows = 0;
|
||||
|
||||
std::set<int> indexes_to_use;
|
||||
|
||||
if (!g_mobile_service->personal_vehicles().empty())
|
||||
{
|
||||
std::string lower_search = search;
|
||||
std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower);
|
||||
|
||||
for (const auto& it : g_mobile_service->personal_vehicles())
|
||||
{
|
||||
const auto& label = it.first;
|
||||
const auto& personal_veh = it.second;
|
||||
const auto& item = g_gta_data_service->vehicle_by_hash(personal_veh->get_hash());
|
||||
|
||||
std::string vehicle_class = item.m_vehicle_class;
|
||||
std::string display_name = label;
|
||||
std::string display_manufacturer = item.m_display_manufacturer;
|
||||
std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower);
|
||||
std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower);
|
||||
|
||||
if ((selected_class == -1 || class_arr[selected_class] == vehicle_class)
|
||||
&& (display_name.find(lower_search) != std::string::npos || display_manufacturer.find(lower_search) != std::string::npos))
|
||||
{
|
||||
indexes_to_use.insert(personal_veh->get_id());
|
||||
}
|
||||
}
|
||||
num_of_rows = indexes_to_use.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
num_of_rows = 2;
|
||||
}
|
||||
|
||||
static const auto over_30 = (30 * ImGui::GetTextLineHeightWithSpacing() + 2);
|
||||
const auto box_height = num_of_rows <= 30 ? (num_of_rows * ImGui::GetTextLineHeightWithSpacing() + 2) : over_30;
|
||||
if (ImGui::BeginListBox("###personal_veh_list", {300, box_height}))
|
||||
{
|
||||
if (g_mobile_service->personal_vehicles().empty())
|
||||
{
|
||||
@ -99,19 +137,12 @@ namespace big
|
||||
|
||||
for (const auto& it : g_mobile_service->personal_vehicles())
|
||||
{
|
||||
const auto& label = it.first;
|
||||
const auto& personal_veh = it.second;
|
||||
const auto& item = g_gta_data_service->vehicle_by_hash(personal_veh->get_hash());
|
||||
|
||||
std::string vehicle_class = item.m_vehicle_class;
|
||||
std::string display_name = label;
|
||||
std::string display_manufacturer = item.m_display_manufacturer;
|
||||
std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower);
|
||||
std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower);
|
||||
|
||||
if ((selected_class == -1 || class_arr[selected_class] == vehicle_class)
|
||||
&& (display_name.find(lower_search) != std::string::npos || display_manufacturer.find(lower_search) != std::string::npos))
|
||||
if (indexes_to_use.contains(personal_veh->get_id()))
|
||||
{
|
||||
const auto& label = it.first;
|
||||
|
||||
ImGui::PushID('v' << 24 & personal_veh->get_id());
|
||||
components::selectable(label, false, [&personal_veh] {
|
||||
if (g.clone_pv.spawn_clone)
|
||||
|
@ -257,7 +257,7 @@ namespace big
|
||||
});
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox("TIRESMOKE"_T.data(), (bool*)&owned_mods[MOD_TYRE_SMOKE]))
|
||||
if (ImGui::Checkbox("TIRE_SMOKE"_T.data(), (bool*)&owned_mods[MOD_TYRE_SMOKE]))
|
||||
{
|
||||
g_fiber_pool->queue_job([] {
|
||||
VEHICLE::TOGGLE_VEHICLE_MOD(player_vehicle, MOD_TYRE_SMOKE, owned_mods[MOD_TYRE_SMOKE]);
|
||||
|
@ -9,8 +9,6 @@ namespace big
|
||||
{
|
||||
void render_spawn_new_vehicle()
|
||||
{
|
||||
ImGui::SetWindowSize({0.f, (float)*g_pointers->m_gta.m_resolution_y}, ImGuiCond_Always);
|
||||
|
||||
if (ImGui::Checkbox("PREVIEW"_T.data(), &g.spawn_vehicle.preview_vehicle))
|
||||
{
|
||||
if (!g.spawn_vehicle.preview_vehicle)
|
||||
@ -18,6 +16,8 @@ namespace big
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("PREVIEW_DESC"_T.data());
|
||||
ImGui::SameLine();
|
||||
components::command_checkbox<"spawnin">();
|
||||
ImGui::SameLine();
|
||||
@ -64,7 +64,43 @@ namespace big
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
components::input_text_with_hint("MODEL_NAME"_T, "SEARCH"_T, search, sizeof(search), ImGuiInputTextFlags_None);
|
||||
|
||||
if (ImGui::BeginListBox("###vehicles", {300, static_cast<float>(*g_pointers->m_gta.m_resolution_y - 188 - 38 * 4)}))
|
||||
vehicle_map calculated_map{};
|
||||
|
||||
if (g_gta_data_service->vehicles().size() > 0)
|
||||
{
|
||||
for (auto& item : g_gta_data_service->vehicles())
|
||||
{
|
||||
const auto& vehicle = item.second;
|
||||
|
||||
std::string display_name = vehicle.m_display_name;
|
||||
std::string display_manufacturer = vehicle.m_display_manufacturer;
|
||||
std::string clazz = vehicle.m_vehicle_class;
|
||||
|
||||
std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower);
|
||||
std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower);
|
||||
|
||||
std::string lower_search = search;
|
||||
std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower);
|
||||
|
||||
if ((selected_class == -1 || class_arr[selected_class] == clazz) && (display_name.find(lower_search) != std::string::npos || display_manufacturer.find(lower_search) != std::string::npos))
|
||||
{
|
||||
calculated_map.emplace(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const auto over_30 = (30 * ImGui::GetTextLineHeightWithSpacing() + 2);
|
||||
auto calculated_size = calculated_map.size();
|
||||
if (calculated_map.size() == 0)
|
||||
{
|
||||
calculated_size++;
|
||||
}
|
||||
if (self::veh)
|
||||
{
|
||||
calculated_size++;
|
||||
}
|
||||
const auto box_height = calculated_size <= 30 ? (calculated_size * ImGui::GetTextLineHeightWithSpacing() + 2) : over_30;
|
||||
if (ImGui::BeginListBox("###vehicles", {300, box_height}))
|
||||
{
|
||||
if (self::veh)
|
||||
{
|
||||
@ -125,66 +161,50 @@ namespace big
|
||||
}
|
||||
}
|
||||
|
||||
const auto& item_arr = g_gta_data_service->vehicles();
|
||||
if (item_arr.size() > 0)
|
||||
if (calculated_map.size() > 0)
|
||||
{
|
||||
std::string lower_search = search;
|
||||
std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower);
|
||||
|
||||
for (auto& item : item_arr)
|
||||
for (auto& item : calculated_map)
|
||||
{
|
||||
const auto& vehicle = item.second;
|
||||
ImGui::PushID(vehicle.m_hash);
|
||||
components::selectable(vehicle.m_display_name, false, [&vehicle] {
|
||||
const auto spawn_location =
|
||||
vehicle::get_spawn_location(g.spawn_vehicle.spawn_inside, vehicle.m_hash);
|
||||
const auto spawn_heading = ENTITY::GET_ENTITY_HEADING(self::ped);
|
||||
|
||||
std::string display_name = vehicle.m_display_name;
|
||||
std::string display_manufacturer = vehicle.m_display_manufacturer;
|
||||
std::string clazz = vehicle.m_vehicle_class;
|
||||
auto veh = vehicle::spawn(vehicle.m_hash, spawn_location, spawn_heading);
|
||||
|
||||
std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower);
|
||||
std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower);
|
||||
if (veh == 0)
|
||||
{
|
||||
g_notification_service->push_error("VEHICLE"_T.data(), "UNABLE_TO_SPAWN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g.spawn_vehicle.spawn_maxed)
|
||||
{
|
||||
vehicle::max_vehicle(veh);
|
||||
}
|
||||
|
||||
if ((selected_class == -1 || class_arr[selected_class] == clazz)
|
||||
&& (display_name.find(lower_search) != std::string::npos || display_manufacturer.find(lower_search) != std::string::npos))
|
||||
vehicle::set_plate(veh, plate_buf);
|
||||
|
||||
if (g.spawn_vehicle.spawn_inside)
|
||||
{
|
||||
vehicle::teleport_into_vehicle(veh);
|
||||
}
|
||||
}
|
||||
|
||||
g_model_preview_service->stop_preview();
|
||||
ENTITY::SET_ENTITY_AS_NO_LONGER_NEEDED(&veh);
|
||||
});
|
||||
ImGui::PopID();
|
||||
|
||||
if (!g.spawn_vehicle.preview_vehicle || (g.spawn_vehicle.preview_vehicle && !ImGui::IsAnyItemHovered()))
|
||||
{
|
||||
ImGui::PushID(vehicle.m_hash);
|
||||
components::selectable(vehicle.m_display_name, false, [&vehicle] {
|
||||
const auto spawn_location =
|
||||
vehicle::get_spawn_location(g.spawn_vehicle.spawn_inside, vehicle.m_hash);
|
||||
const auto spawn_heading = ENTITY::GET_ENTITY_HEADING(self::ped);
|
||||
|
||||
auto veh = vehicle::spawn(vehicle.m_hash, spawn_location, spawn_heading);
|
||||
|
||||
if (veh == 0)
|
||||
{
|
||||
g_notification_service->push_error("VEHICLE"_T.data(), "UNABLE_TO_SPAWN_VEHICLE"_T.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g.spawn_vehicle.spawn_maxed)
|
||||
{
|
||||
vehicle::max_vehicle(veh);
|
||||
}
|
||||
|
||||
vehicle::set_plate(veh, plate_buf);
|
||||
|
||||
if (g.spawn_vehicle.spawn_inside)
|
||||
{
|
||||
vehicle::teleport_into_vehicle(veh);
|
||||
}
|
||||
}
|
||||
|
||||
g_model_preview_service->stop_preview();
|
||||
ENTITY::SET_ENTITY_AS_NO_LONGER_NEEDED(&veh);
|
||||
});
|
||||
ImGui::PopID();
|
||||
|
||||
if (!g.spawn_vehicle.preview_vehicle || (g.spawn_vehicle.preview_vehicle && !ImGui::IsAnyItemHovered()))
|
||||
{
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
else if (ImGui::IsItemHovered())
|
||||
{
|
||||
g_model_preview_service->show_vehicle(vehicle.m_hash, g.spawn_vehicle.spawn_maxed);
|
||||
}
|
||||
g_model_preview_service->stop_preview();
|
||||
}
|
||||
else if (ImGui::IsItemHovered())
|
||||
{
|
||||
g_model_preview_service->show_vehicle(vehicle.m_hash, g.spawn_vehicle.spawn_maxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,16 +218,15 @@ namespace big
|
||||
|
||||
void view::spawn_vehicle()
|
||||
{
|
||||
static int spawn_type = 0;
|
||||
ImGui::RadioButton("New", &spawn_type, 0);
|
||||
ImGui::RadioButton("New", &g.spawn_vehicle.spawn_type, 0);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Personal", &spawn_type, 1);
|
||||
ImGui::RadioButton("Personal", &g.spawn_vehicle.spawn_type, 1);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Persistent", &spawn_type, 2);
|
||||
ImGui::RadioButton("Persistent", &g.spawn_vehicle.spawn_type, 2);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Xml", &spawn_type, 3);
|
||||
ImGui::RadioButton("Xml", &g.spawn_vehicle.spawn_type, 3);
|
||||
|
||||
switch (spawn_type)
|
||||
switch (g.spawn_vehicle.spawn_type)
|
||||
{
|
||||
case 0: render_spawn_new_vehicle(); break;
|
||||
case 1: view::pv(); break;
|
||||
|
Reference in New Issue
Block a user