diff --git a/BigBaseV2/src/api/remote.hpp b/BigBaseV2/src/api/remote.hpp new file mode 100644 index 00000000..a64ecc70 --- /dev/null +++ b/BigBaseV2/src/api/remote.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "api/http_request.hpp" + +namespace big::remote +{ + inline bool download_binary(const std::string_view file_url, const std::filesystem::path& location) + { + std::ofstream file(location, std::ios::binary | std::ios::trunc); + + try + { + http::Request req(file_url.data()); + http::Response res = req.send("GET", "", {}, 2500ms); + + std::ostream_iterator outputIter(file); + std::copy(res.body.begin(), res.body.end(), outputIter); + } + catch (const std::exception& e) + { + LOG(INFO) << "Failed to download binary, is the host down?: " << e.what(); + + file.close(); + + return false; + } + file.close(); + + return true; + } +} \ No newline at end of file diff --git a/BigBaseV2/src/core/globals.hpp b/BigBaseV2/src/core/globals.hpp index 271cf1ba..c8e0f156 100644 --- a/BigBaseV2/src/core/globals.hpp +++ b/BigBaseV2/src/core/globals.hpp @@ -90,6 +90,12 @@ namespace big hotkeys hotkeys{}; }; + struct spawn + { + bool preview_vehicle = false; + bool spawn_inside = false; + }; + struct spoofing { bool spoof_username = false; @@ -175,6 +181,7 @@ namespace big protections protections{}; self self{}; settings settings{}; + spawn spawn{}; spoofing spoofing{}; vehicle vehicle{}; weapons weapons{}; @@ -234,6 +241,9 @@ namespace big this->settings.hotkeys.menu_toggle = j["settings"]["hotkeys"]["menu_toggle"]; + this->spawn.preview_vehicle = j["spawn"]["preview_vehicle"]; + this->spawn.spawn_inside = j["spawn"]["spawn_inside"]; + this->spoofing.spoof_ip = j["spoofing"]["spoof_ip"]; this->spoofing.spoof_rockstar_id = j["spoofing"]["spoof_rockstar_id"]; this->spoofing.spoof_username = j["spoofing"]["spoof_username"]; @@ -355,6 +365,12 @@ namespace big } } }, + { + "spawn", { + { "preview_vehicle", this->spawn.preview_vehicle }, + { "spawn_inside", this->spawn.spawn_inside } + } + }, { "spoofing", { { "spoof_ip", this->spoofing.spoof_ip }, diff --git a/BigBaseV2/src/gui/components/components.hpp b/BigBaseV2/src/gui/components/components.hpp index 3a8fde62..ecec8665 100644 --- a/BigBaseV2/src/gui/components/components.hpp +++ b/BigBaseV2/src/gui/components/components.hpp @@ -13,5 +13,12 @@ namespace big static void sub_title(const std::string_view); static void title(const std::string_view); static void button(const std::string_view, std::function); + + static void input_text_with_hint(const std::string_view label, const std::string_view hint, char* buf, size_t buf_size, ImGuiInputTextFlags_ flag = ImGuiInputTextFlags_None, std::function cb = nullptr); + + static bool selectable(const std::string_view, bool); + static bool selectable(const std::string_view, bool, ImGuiSelectableFlags); + static void selectable(const std::string_view, bool, std::function); + static void selectable(const std::string_view, bool, ImGuiSelectableFlags, std::function); }; } \ No newline at end of file diff --git a/BigBaseV2/src/gui/components/input_text_with_hint.cpp b/BigBaseV2/src/gui/components/input_text_with_hint.cpp new file mode 100644 index 00000000..5cf4bd45 --- /dev/null +++ b/BigBaseV2/src/gui/components/input_text_with_hint.cpp @@ -0,0 +1,17 @@ +#include "gui/components/components.hpp" +#include "fiber_pool.hpp" +#include "natives.hpp" + +namespace big +{ + void components::input_text_with_hint(const std::string_view label, const std::string_view hint, char* buf, size_t buf_size, ImGuiInputTextFlags_ flag, std::function cb) { + if (ImGui::InputTextWithHint(label.data(), hint.data(), buf, buf_size, flag)) + if (cb) + g_fiber_pool->queue_job(std::move(cb)); + + if (ImGui::IsItemActive()) + g_fiber_pool->queue_job([] { + PAD::DISABLE_ALL_CONTROL_ACTIONS(0); + }); + } +} \ No newline at end of file diff --git a/BigBaseV2/src/gui/components/selectable.cpp b/BigBaseV2/src/gui/components/selectable.cpp new file mode 100644 index 00000000..e2003a1d --- /dev/null +++ b/BigBaseV2/src/gui/components/selectable.cpp @@ -0,0 +1,29 @@ +#include "gui/components/components.hpp" +#include "fiber_pool.hpp" + +namespace big +{ + bool components::selectable(const std::string_view text, bool selected) + { + return ImGui::Selectable(text.data(), selected); + } + + bool components::selectable(const std::string_view text, bool selected, ImGuiSelectableFlags flag) + { + return ImGui::Selectable(text.data(), selected, flag); + } + + void components::selectable(const std::string_view text, bool selected, std::function cb) + { + if (components::selectable(text.data(), selected)) + g_fiber_pool->queue_job(std::move(cb)); + } + + void components::selectable(const std::string_view text, bool selected, ImGuiSelectableFlags flag, std::function cb) + { + if (components::selectable(text.data(), selected, flag)) + { + g_fiber_pool->queue_job(std::move(cb)); + } + } +} \ No newline at end of file diff --git a/BigBaseV2/src/main.cpp b/BigBaseV2/src/main.cpp index a2f9f731..a0a54998 100644 --- a/BigBaseV2/src/main.cpp +++ b/BigBaseV2/src/main.cpp @@ -15,6 +15,7 @@ #include "services/player_service.hpp" #include "services/mobile_service.hpp" #include "services/notification_service.hpp" +#include "services/vehicle_preview_service.hpp" #include "services/vehicle_service.hpp" BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) @@ -67,6 +68,7 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) auto mobile_service_instance = std::make_unique(); auto notification_service_instance = std::make_unique(); auto player_service_instance = std::make_unique(); + auto vehicle_preview_service_instance = std::make_unique(); auto vehicle_service_instance = std::make_unique(); LOG(INFO) << "Registered service instances..."; @@ -96,6 +98,8 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) vehicle_service_instance.reset(); LOG(INFO) << "Vehicle Service reset."; + vehicle_preview_service_instance.reset(); + LOG(INFO) << "Vehicle Preview Service reset."; mobile_service_instance.reset(); LOG(INFO) << "Mobile Service reset."; player_service_instance.reset(); diff --git a/BigBaseV2/src/services/vehicle_preview_service.cpp b/BigBaseV2/src/services/vehicle_preview_service.cpp new file mode 100644 index 00000000..230dabfb --- /dev/null +++ b/BigBaseV2/src/services/vehicle_preview_service.cpp @@ -0,0 +1,125 @@ +#include "api/remote.hpp" +#include "fiber_pool.hpp" +#include "file_manager.hpp" +#include "gui.hpp" +#include "thread_pool.hpp" +#include "util/entity.hpp" +#include "util/vehicle.hpp" +#include "vehicle_preview_service.hpp" + +namespace big +{ + vehicle_preview_service::vehicle_preview_service() : + m_vehicle_file(g_file_manager->get_project_file("./lib/vehicles.json")) + { + if (m_vehicle_file.exists()) + this->load(); + else + { + g_thread_pool->push([this]() + { + if (remote::download_binary("http://github-proxy.damon.sh/DurtyFree/gta-v-data-dumps/master/vehicles.json", m_vehicle_file.get_path())) + this->load(); + else + LOG(WARNING) << "Failed to download vehicles.json data..."; + }); + } + + g_vehicle_preview_service = this; + } + + vehicle_preview_service::~vehicle_preview_service() + { + g_vehicle_preview_service = nullptr; + } + + nlohmann::json& vehicle_preview_service::get_vehicle_list() + { + return m_all_vehicles; + } + + void vehicle_preview_service::preview_loop() + { + if (m_running) + return; + + m_running = true; + static bool busy = false; + while (g_running && g->spawn.preview_vehicle && g_gui.m_opened) + { + if (busy) + continue; + busy = true; + + g_fiber_pool->queue_job([this] + { + auto location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(PLAYER::PLAYER_PED_ID(), 2.5f, 2.5f, .5f); + if (m_current_veh == -1) + { + location.z = -10.f; + m_current_veh = vehicle::spawn(m_model, location, 0.f, false); + ENTITY::FREEZE_ENTITY_POSITION(m_current_veh, true); + ENTITY::SET_ENTITY_ALPHA(m_current_veh, 0, 0); + ENTITY::SET_ENTITY_COLLISION(m_current_veh, false, false); + + m_new_model = false; + } + else if (m_new_model) + { + entity::delete_entity(m_current_veh); + + m_current_veh = -1; + } + else + { + if (const int alpha = ENTITY::GET_ENTITY_ALPHA(m_current_veh); alpha < 250) + ENTITY::SET_ENTITY_ALPHA(m_current_veh, std::min(255, alpha + 10), 0); + + ENTITY::SET_ENTITY_HEADING(m_current_veh, m_heading); + ENTITY::SET_ENTITY_COORDS(m_current_veh, location.x, location.y, location.z, 0, 0, 0, 0); + } + + if (m_heading += 0.5f; m_heading > 359) m_heading = 0; + + busy = false; + }); + } + + g_fiber_pool->queue_job([this] + { + entity::delete_entity(m_current_veh); + + m_current_veh = -1; + }); + + m_running = false; + } + + + void vehicle_preview_service::set_preview_vehicle(const nlohmann::json& item) + { + if (m_model != item["Name"]) + { + m_model = item["Name"]; + + m_new_model = true; + } + + if (!m_running) + g_thread_pool->push([this] { preview_loop(); }); + } + + void vehicle_preview_service::load() + { + std::ifstream file(m_vehicle_file.get_path()); + + try + { + file >> m_all_vehicles; + } + catch (const std::exception& ex) + { + LOG(WARNING) << "Failed to load vehicles.json:\n" << ex.what(); + } + } +} \ No newline at end of file diff --git a/BigBaseV2/src/services/vehicle_preview_service.hpp b/BigBaseV2/src/services/vehicle_preview_service.hpp new file mode 100644 index 00000000..48e9954b --- /dev/null +++ b/BigBaseV2/src/services/vehicle_preview_service.hpp @@ -0,0 +1,36 @@ +#pragma once +#include "file_manager/file.hpp" + +namespace big +{ + class vehicle_preview_service + { + file m_vehicle_file; + + std::condition_variable m_cond; + std::mutex m_mutex; + + nlohmann::json m_all_vehicles; + + Vehicle m_current_veh = -1; + std::string m_model; + bool m_new_model = false; + float m_heading = 0.f; + bool m_running = false; + public: + vehicle_preview_service(); + ~vehicle_preview_service(); + + nlohmann::json& get_vehicle_list(); + + void preview_loop(); + + void set_preview_vehicle(const nlohmann::json& item); + + private: + void load(); + + }; + + inline vehicle_preview_service* g_vehicle_preview_service{}; +} \ No newline at end of file diff --git a/BigBaseV2/src/util/vehicle.hpp b/BigBaseV2/src/util/vehicle.hpp index 04728545..f6746bf7 100644 --- a/BigBaseV2/src/util/vehicle.hpp +++ b/BigBaseV2/src/util/vehicle.hpp @@ -44,11 +44,9 @@ namespace big::vehicle return true; } - inline int spawn(const char* model, Vector3 location, float heading) + inline int spawn(std::string_view model, Vector3 location, float heading, bool is_networked = true) { - Hash hash = rage::joaat(model); - - if (hash) + if (const Hash hash = rage::joaat(model.data()); hash) { for (uint8_t i = 0; !STREAMING::HAS_MODEL_LOADED(hash) && i < 100; i++) { @@ -64,7 +62,7 @@ namespace big::vehicle } *(unsigned short*)g_pointers->m_model_spawn_bypass = 0x9090; - Vehicle veh = VEHICLE::CREATE_VEHICLE(hash, location.x, location.y, location.z, heading, true, false, false); + Vehicle veh = VEHICLE::CREATE_VEHICLE(hash, location.x, location.y, location.z, heading, is_networked, false, false); *(unsigned short*)g_pointers->m_model_spawn_bypass = 0x0574; script::get_current()->yield(); diff --git a/BigBaseV2/src/views/view_spawn.cpp b/BigBaseV2/src/views/view_spawn.cpp index 7ae4af82..88a68263 100644 --- a/BigBaseV2/src/views/view_spawn.cpp +++ b/BigBaseV2/src/views/view_spawn.cpp @@ -1,29 +1,72 @@ #include "views/view.hpp" #include "fiber_pool.hpp" #include "natives.hpp" -#include "script.hpp" +#include "services/vehicle_preview_service.hpp" #include "util/vehicle.hpp" namespace big { - static char model[12]; + static char model[12] = ""; + + bool does_search_match(std::string& input, const std::string& search) + { + std::transform(input.begin(), input.end(), input.begin(), ::tolower); + + return input.find(search) != std::string::npos; + } void view::spawn() { - g_fiber_pool->queue_job([] { - PAD::DISABLE_ALL_CONTROL_ACTIONS(0); - }); + ImGui::Checkbox("Preview", &g->spawn.preview_vehicle); + ImGui::SameLine(); + ImGui::Checkbox("Spawn In", &g->spawn.spawn_inside); - if ( - ImGui::InputText("Model Name", model, sizeof(model), ImGuiInputTextFlags_EnterReturnsTrue) || - ImGui::Button("Spawn") - ) + components::input_text_with_hint("Model Name", "Search", model, sizeof(model), ImGuiInputTextFlags_EnterReturnsTrue, [] { - g_fiber_pool->queue_job([] { - Ped player = PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(PLAYER::GET_PLAYER_INDEX()); - Vector3 location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(player, .0, 8.0, .5); + const auto location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(PLAYER::PLAYER_PED_ID(), 2.f, 2.f, 0.f); + const Vehicle veh = vehicle::spawn(model, location, g_local_player->m_player_info->m_ped->m_navigation->m_heading + 90.f); - vehicle::spawn((const char*)model, location, ENTITY::GET_ENTITY_HEADING(player) + 90.f); - }); + if (g->spawn.spawn_inside) + PED::SET_PED_INTO_VEHICLE(PLAYER::PLAYER_PED_ID(), veh, -1); + }); + if (ImGui::ListBoxHeader("###vehicles", { ImGui::GetWindowWidth(), ImGui::GetWindowHeight() })) + { + if (!g_vehicle_preview_service->get_vehicle_list().is_null()) + { + for (auto& item : g_vehicle_preview_service->get_vehicle_list()) + { + if (item["Name"].is_null() || item["DisplayName"].is_null()) + continue; + + std::string name = item["Name"]; + std::string display_name = item["DisplayName"]; + + std::string manufacturer; + std::string search = model; + std::transform(search.begin(), search.end(), search.begin(), ::tolower); + + if (!item["ManufacturerDisplayName"].is_null()) + manufacturer = item["ManufacturerDisplayName"]; + + if (search.empty() || + does_search_match(name, search) || + does_search_match(display_name, search) || + does_search_match(manufacturer, search)) + { + components::selectable(item["DisplayName"], item["Name"] == search, [&item] + { + const auto location = ENTITY::GET_ENTITY_COORDS(PLAYER::PLAYER_PED_ID(), true); + const Vehicle veh = vehicle::spawn(item["Name"], location, 0.f); + + if (g->spawn.spawn_inside) + PED::SET_PED_INTO_VEHICLE(PLAYER::PLAYER_PED_ID(), veh, -1); + }); + + if (g->spawn.preview_vehicle && ImGui::IsItemHovered()) + g_vehicle_preview_service->set_preview_vehicle(item); + } + } + } + else ImGui::Text("No vehicles in registry."); } } } \ No newline at end of file