From ba4ebc9a43e4319133b8fa865fea6c28c3b575ca Mon Sep 17 00:00:00 2001 From: Deewarz Date: Mon, 5 Feb 2024 15:48:35 +0100 Subject: [PATCH] Introduce World Debug --- code/client/CMakeLists.txt | 1 + code/client/src/core/dev_features.cpp | 388 +++++++----------- code/client/src/core/dev_features.h | 29 +- code/client/src/core/ui/audio_debug.cpp | 2 +- code/client/src/core/ui/entity_browser.cpp | 1 - code/client/src/core/ui/network_stats.cpp | 1 - code/client/src/core/ui/player_debug.cpp | 2 +- code/client/src/core/ui/world_debug.cpp | 304 ++++++++++++++ code/client/src/core/ui/world_debug.h | 32 ++ .../src/sdk/c_game_gfx_env_eff_module.h | 12 + code/client/src/sdk/patterns.cpp | 3 + code/client/src/sdk/patterns.h | 3 + 12 files changed, 521 insertions(+), 257 deletions(-) create mode 100644 code/client/src/core/ui/world_debug.cpp create mode 100644 code/client/src/core/ui/world_debug.h create mode 100644 code/client/src/sdk/c_game_gfx_env_eff_module.h diff --git a/code/client/CMakeLists.txt b/code/client/CMakeLists.txt index 8957ca58..be92d96f 100644 --- a/code/client/CMakeLists.txt +++ b/code/client/CMakeLists.txt @@ -15,6 +15,7 @@ set(MAFIAMP_CLIENT_FILES src/core/ui/web/clipboard.cpp src/core/ui/web/sdk.cpp src/core/ui/web/view.cpp + src/core/ui/world_debug.cpp src/core/states/initialize.cpp src/core/states/main_menu.cpp src/core/states/session_connected.cpp diff --git a/code/client/src/core/dev_features.cpp b/code/client/src/core/dev_features.cpp index eff1ff28..1bec5144 100644 --- a/code/client/src/core/dev_features.cpp +++ b/code/client/src/core/dev_features.cpp @@ -13,43 +13,29 @@ #include "game/helpers/controls.h" #include "game/helpers/human.h" +#include "game/overrides/character_controller.h" #include "game/streaming/entity_factory.h" -#include "sdk/c_game_traffic_module.h" -#include "sdk/entities/c_car.h" #include "sdk/entities/c_crash_obj.h" #include "sdk/entities/c_player_2.h" -#include "sdk/entities/c_vehicle.h" #include "sdk/mafia/framework/c_mafia_framework_interfaces.h" -#include "sdk/mafia/framework/director/c_game_director.h" -#include "sdk/mafia/ui/c_game_gui_2_module.h" -#include "game/helpers/ui.h" - -#include "external/imgui/widgets/corner_text.h" +#include #include #include #include "shared/rpc/chat_message.h" -#include "shared/rpc/spawn_car.h" - -#include "shared/game_rpc/human/human_changeskin.h" - -#include "modules/human.h" - -#include "sdk/mafia/framework/c_mafia_dbs.h" -#include "sdk/mafia/framework/c_vehicles_database.h" -#include "sdk/ue/sys/sodb/c_sys_odb.h" namespace MafiaMP::Core { DevFeatures::DevFeatures() { - _entityBrowser = std::make_shared(); - _cameraStudio = std::make_shared(); _audioDebug = std::make_shared(); + _cameraStudio = std::make_shared(); + _entityBrowser = std::make_shared(); + _networkStats = std::make_shared(); _playerDebug = std::make_shared(); _vehicleDebug = std::make_shared(); - _networkStats = std::make_shared(); + _worldDebug = std::make_shared(); } void DevFeatures::Init() { @@ -58,6 +44,10 @@ namespace MafiaMP::Core { } void DevFeatures::Update() { + if (_audioDebug->IsVisible()) { + _audioDebug->Update(); + } + if (_entityBrowser->IsVisible()) { _entityBrowser->Update(); } @@ -66,10 +56,6 @@ namespace MafiaMP::Core { _cameraStudio->Update(); } - if (_audioDebug->IsVisible()) { - _audioDebug->Update(); - } - if (_playerDebug->IsVisible()) { _playerDebug->Update(); } @@ -82,19 +68,35 @@ namespace MafiaMP::Core { _networkStats->Update(); } + if (_worldDebug->IsVisible()) { + _worldDebug->Update(); + } + + /** + * F8 is for console + * F9 is for main menu + * F12 is for Steam screenshot + */ + if (gApplication->_input->IsKeyPressed(FW_KEY_F1)) { - const auto human = Game::Helpers::Controls::GetLocalPlayer(); - if (human) { - const auto districtHashName = SDK::mafia::framework::director::C_GameDirector::GetInstance()->GetDistrict(human->GetPos()); - const auto result = *districtHashName; - } + ToggleWorldDebug(); } if (gApplication->_input->IsKeyPressed(FW_KEY_F2)) { - SpawnCrashObject(); + TogglePlayerDebug(); } if (gApplication->_input->IsKeyPressed(FW_KEY_F3)) { + ToggleVehicleDebug(); + } + + if (gApplication->_input->IsKeyPressed(FW_KEY_F4)) { + gApplication->GetImGUI()->ShowCursor(!_cameraStudio->IsVisible()); + MafiaMP::Game::Helpers::Controls::Lock(!_cameraStudio->IsVisible()); + ToggleCameraStudio(); + } + + if (gApplication->_input->IsKeyPressed(FW_KEY_F5)) { // If human is already created, delete it first if (_TEMP_HUMAN) { gApplication->GetEntityFactory()->ReturnEntity(_TEMP_HUMAN); @@ -153,7 +155,7 @@ namespace MafiaMP::Core { _TEMP_HUMAN->SetReturnCallback(OnHumanReturned); } - if (gApplication->_input->IsKeyPressed(FW_KEY_F4)) { + if (gApplication->_input->IsKeyPressed(FW_KEY_F6)) { if (!_TEMP_HUMAN) { return; } @@ -173,9 +175,7 @@ namespace MafiaMP::Core { } if (gApplication->_input->IsKeyPressed(FW_KEY_F7)) { - gApplication->GetImGUI()->ShowCursor(!_cameraStudio->IsVisible()); - MafiaMP::Game::Helpers::Controls::Lock(!_cameraStudio->IsVisible()); - ToggleCameraStudio(); + SpawnCrashObject(); } if (gApplication->_input->IsKeyPressed(FW_KEY_F10)) { @@ -189,186 +189,6 @@ namespace MafiaMP::Core { void DevFeatures::Shutdown() {} - void DevFeatures::Disconnect() { - gApplication->GetNetworkingEngine()->GetNetworkClient()->Disconnect(); - } - - void DevFeatures::DespawnAll() { - for (const auto &vehicle : _TEMP_vehicles) { - gApplication->GetEntityFactory()->ReturnEntity(vehicle); - } - _TEMP_vehicles.clear(); - } - - void DevFeatures::CrashMe() { - *(int *)5 = 5; - } - - void DevFeatures::BreakMe() { - __debugbreak(); - } - - void DevFeatures::CloseGame() { - // very lazy game shutdown - // don't try at home - ExitProcess(0); - } - - void DevFeatures::ToggleEntityBrowser() { - _entityBrowser->SetVisible(!_entityBrowser->IsVisible()); - } - - void DevFeatures::ToggleCameraStudio() { - _cameraStudio->SetVisible(!_playerDebug->IsVisible()); - } - - void DevFeatures::ToggleAudioDebug() { - _audioDebug->SetVisible(!_audioDebug->IsVisible()); - } - - void DevFeatures::TogglePlayerDebug() { - _playerDebug->SetVisible(!_playerDebug->IsVisible()); - } - - void DevFeatures::ToggleVehicleDebug() { - _vehicleDebug->SetVisible(!_vehicleDebug->IsVisible()); - } - - void DevFeatures::ToggleNetworkStats() { - _networkStats->SetVisible(!_networkStats->IsVisible()); - } - - void DevFeatures::SpawnCrashObject() { - auto info = Core::gApplication->GetEntityFactory()->RequestCrashObject("lh_city_stairs_module_a_v1"); - - const auto OnCrashObjRequestFinished = [&](Game::Streaming::EntityTrackingInfo *info, bool success) { - if (success) { - auto crashObj = reinterpret_cast(info->GetEntity()); - if (!crashObj) { - return; - } - crashObj->GameInit(); - crashObj->Activate(); - - auto localPlayer = SDK::GetGame()->GetActivePlayer(); - - SDK::ue::sys::math::C_Vector newPos = localPlayer->GetPos(); - SDK::ue::sys::math::C_Quat newRot = localPlayer->GetRot(); - SDK::ue::sys::math::C_Matrix transform = {}; - transform.Identity(); - transform.SetRot(newRot); - transform.SetPos(newPos); - crashObj->SetTransform(transform); - } - }; - - const auto OnCrashObjReturned = [&](Game::Streaming::EntityTrackingInfo *info, bool wasCreated) { - if (!info) { - return; - } - auto crashObj = reinterpret_cast(info->GetEntity()); - if (wasCreated && crashObj) { - crashObj->Deactivate(); - crashObj->GameDone(); - crashObj->Release(); - } - }; - - info->SetRequestFinishCallback(OnCrashObjRequestFinished); - info->SetReturnCallback(OnCrashObjReturned); - } - - void DevFeatures::SpawnCar(std::string modelName) { - const auto net = gApplication->GetNetworkingEngine()->GetNetworkClient(); - if (net->GetConnectionState() == Framework::Networking::CONNECTED) { - Shared::RPC::SpawnCar spawnCarMsg {}; - spawnCarMsg.SetModelName(modelName); - net->SendRPC(spawnCarMsg); - } - else { - auto info = Core::gApplication->GetEntityFactory()->RequestVehicle(modelName); - _TEMP_vehicles.push_back(info); - - const auto OnCarRequestFinish = [&](Game::Streaming::EntityTrackingInfo *info, bool success) { - if (success) { - auto car = reinterpret_cast(info->GetEntity()); - if (!car) { - return; - } - car->GameInit(); - car->Activate(); - car->Unlock(); - - auto localPlayer = SDK::GetGame()->GetActivePlayer(); - - SDK::ue::sys::math::C_Vector newPos = localPlayer->GetPos(); - SDK::ue::sys::math::C_Quat newRot = localPlayer->GetRot(); - SDK::ue::sys::math::C_Matrix transform = {}; - transform.Identity(); - transform.SetRot(newRot); - transform.SetPos(newPos); - car->GetVehicle()->SetVehicleMatrix(transform, SDK::ue::sys::core::E_TransformChangeType::DEFAULT); - car->GetVehicle()->SetSPZText("DEBUG", true); - } - }; - - const auto OnCarReturned = [&](Game::Streaming::EntityTrackingInfo *info, bool wasCreated) { - if (!info) { - return; - } - auto car = reinterpret_cast(info->GetEntity()); - if (wasCreated && car) { - car->Deactivate(); - car->GameDone(); - car->Release(); - } - }; - - info->SetRequestFinishCallback(OnCarRequestFinish); - info->SetReturnCallback(OnCarReturned); - } - } - - void DevFeatures::SpawnRandomCar() { - const auto mafiaDB = SDK::mafia::framework::GetMafiaDBs(); - if (!mafiaDB) { - return; - } - - const auto vehiclesDB = mafiaDB->GetVehiclesDatabase(); - if (!vehiclesDB.IsValid()) { - return; - } - - // TODO(Greavesy): May not be 'random' if our application does not use srand, but not important as only debug feature - const uint32_t randomIndex = rand() % vehiclesDB->GetVehiclesCount(); - - using namespace SDK::mafia::framework; - const C_VehiclesDatabase::TItemAccessorConst &selectedCar = vehiclesDB->GetVehicleByIndex(randomIndex); - if (const auto *vehicle = selectedCar.Get()) { - const auto vehicleID = vehicle->GetID(); - if (vehicle->GetID() == 0) { - // dud index, nothing to spawn - return; - } - - const char *modelName = vehicle->GetModelName(); - if (!modelName) { - Framework::Logging::GetLogger("Debug")->info("Skipping ID {}, encountered m_ModelName which is nullptr", vehicleID); - return; - } - - if (vehicle->HasVehicleFlags(SDK::mafia::traffic::E_TrafficVehicleFlags::E_TVF_CAR) == false) { - Framework::Logging::GetLogger("Debug")->info("Skipping {}, not E_TVF_CAR", modelName); - return; - } - - SpawnCar(modelName); - - Framework::Logging::GetLogger("Debug")->info("Spawned {}", modelName); - } - } - void DevFeatures::SetupCommands() { gApplication->_commandProcessor->RegisterCommand( "help", {}, @@ -461,7 +281,7 @@ namespace MafiaMP::Core { "spawnCar", {{"m,model", "model name of the car", cxxopts::value()->default_value("berkley_810")}}, [this](const cxxopts::ParseResult &result) { std::string modelName = result["model"].as(); - SpawnCar(modelName); + _worldDebug->SpawnCar(modelName); }, "spawn a car of a given model"); @@ -513,6 +333,13 @@ namespace MafiaMP::Core { }, "toggles entity browser dialog"); + gApplication->_commandProcessor->RegisterCommand( + "showAudioDebug", {}, + [this](const cxxopts::ParseResult &result) { + ToggleAudioDebug(); + }, + "toggles audio debug dialog"); + gApplication->_commandProcessor->RegisterCommand( "showCameraStudio", {}, [this](const cxxopts::ParseResult &result) { @@ -534,6 +361,13 @@ namespace MafiaMP::Core { }, "toggles vehicle debug dialog"); + gApplication->_commandProcessor->RegisterCommand( + "showWorldDebug", {}, + [this](const cxxopts::ParseResult &result) { + ToggleWorldDebug(); + }, + "toggles world debug dialog"); + gApplication->_commandProcessor->RegisterCommand( "showNetworkStats", {}, [this](const cxxopts::ParseResult &result) { @@ -546,24 +380,13 @@ namespace MafiaMP::Core { gApplication->_console->RegisterMenuBarDrawer([this]() { if (ImGui::BeginMenu("Debug")) { if (ImGui::MenuItem("Spawn car")) { - SpawnCar(); + _worldDebug->SpawnCar(); } if (ImGui::MenuItem("Spawn 50 cars")) { for (size_t i = 0; i < 50; i++) { - SpawnCar(); + _worldDebug->SpawnCar(); } } - if (ImGui::MenuItem("Spawn random car")) { - SpawnRandomCar(); - } - if (ImGui::MenuItem("Spawn 50 random cars")) { - for (size_t i = 0; i < 50; i++) { - SpawnRandomCar(); - } - } - if (ImGui::MenuItem("Despawn all")) { - DespawnAll(); - } if (ImGui::MenuItem("Disconnect")) { Disconnect(); } @@ -578,31 +401,118 @@ namespace MafiaMP::Core { } ImGui::EndMenu(); } + if (ImGui::BeginMenu("Editors")) { - if (ImGui::MenuItem("Entity Browser", "F11")) { - ToggleEntityBrowser(); + if (ImGui::MenuItem("World debug", "F1")) { + ToggleWorldDebug(); + } + if (ImGui::MenuItem("Player debug", "F2")) { + TogglePlayerDebug(); } - if (ImGui::MenuItem("Camera Studio")) { + if (ImGui::MenuItem("Vehicle debug", "F3")) { + ToggleVehicleDebug(); + } + if (ImGui::MenuItem("Camera Studio", "F4")) { ToggleCameraStudio(); } - if (ImGui::MenuItem("Audio debug")) { ToggleAudioDebug(); } - - if (ImGui::MenuItem("Player debug")) { - TogglePlayerDebug(); - } - if (ImGui::MenuItem("Vehicle debug")) { - ToggleVehicleDebug(); - } if (ImGui::MenuItem("Network stats", "F10")) { ToggleNetworkStats(); } + if (ImGui::MenuItem("Entity Browser", "F11")) { + ToggleEntityBrowser(); + } ImGui::EndMenu(); } }); } + void DevFeatures::ToggleAudioDebug() { + _audioDebug->SetVisible(!_audioDebug->IsVisible()); + } + + void DevFeatures::ToggleEntityBrowser() { + _entityBrowser->SetVisible(!_entityBrowser->IsVisible()); + } + + void DevFeatures::ToggleNetworkStats() { + _networkStats->SetVisible(!_networkStats->IsVisible()); + } + + void DevFeatures::ToggleCameraStudio() { + _cameraStudio->SetVisible(!_playerDebug->IsVisible()); + } + + void DevFeatures::TogglePlayerDebug() { + _playerDebug->SetVisible(!_playerDebug->IsVisible()); + } + + void DevFeatures::ToggleVehicleDebug() { + _vehicleDebug->SetVisible(!_vehicleDebug->IsVisible()); + } + + void DevFeatures::ToggleWorldDebug() { + _worldDebug->SetVisible(!_worldDebug->IsVisible()); + } + + void DevFeatures::Disconnect() { + gApplication->GetNetworkingEngine()->GetNetworkClient()->Disconnect(); + } + + void DevFeatures::CrashMe() { + *(int *)5 = 5; + } + + void DevFeatures::BreakMe() { + __debugbreak(); + } + + void DevFeatures::CloseGame() { + // very lazy game shutdown + // don't try at home + ExitProcess(0); + } + + void DevFeatures::SpawnCrashObject() { + auto info = Core::gApplication->GetEntityFactory()->RequestCrashObject("lh_city_stairs_module_a_v1"); + + const auto OnCrashObjRequestFinished = [&](Game::Streaming::EntityTrackingInfo *info, bool success) { + if (success) { + auto crashObj = reinterpret_cast(info->GetEntity()); + if (!crashObj) { + return; + } + crashObj->GameInit(); + crashObj->Activate(); + + auto localPlayer = SDK::GetGame()->GetActivePlayer(); + + SDK::ue::sys::math::C_Vector newPos = localPlayer->GetPos(); + SDK::ue::sys::math::C_Quat newRot = localPlayer->GetRot(); + SDK::ue::sys::math::C_Matrix transform = {}; + transform.Identity(); + transform.SetRot(newRot); + transform.SetPos(newPos); + crashObj->SetTransform(transform); + } + }; + + const auto OnCrashObjReturned = [&](Game::Streaming::EntityTrackingInfo *info, bool wasCreated) { + if (!info) { + return; + } + auto crashObj = reinterpret_cast(info->GetEntity()); + if (wasCreated && crashObj) { + crashObj->Deactivate(); + crashObj->GameDone(); + crashObj->Release(); + } + }; + + info->SetRequestFinishCallback(OnCrashObjRequestFinished); + info->SetReturnCallback(OnCrashObjReturned); + } } // namespace MafiaMP::Core diff --git a/code/client/src/core/dev_features.h b/code/client/src/core/dev_features.h index 5af56172..d01b9b38 100644 --- a/code/client/src/core/dev_features.h +++ b/code/client/src/core/dev_features.h @@ -20,25 +20,27 @@ #include "ui/network_stats.h" #include "ui/player_debug.h" #include "ui/vehicle_debug.h" +#include "ui/world_debug.h" #include "sdk/entities/c_human_2.h" namespace MafiaMP::Core { class DevFeatures final { private: - std::vector _TEMP_vehicles; Game::Streaming::EntityTrackingInfo *_TEMP_HUMAN = nullptr; + std::shared_ptr _audioDebug {}; + std::shared_ptr _entityBrowser {}; std::shared_ptr _cameraStudio {}; - std::shared_ptr _audioDebug {}; - std::shared_ptr _playerDebug {}; std::shared_ptr _vehicleDebug {}; + std::shared_ptr _worldDebug {}; + std::shared_ptr _networkStats {}; public: @@ -50,20 +52,19 @@ namespace MafiaMP::Core { private: void SetupCommands(); void SetupMenuBar(); - void Disconnect(); - void DespawnAll(); - void SpawnCrashObject(); - void SpawnCar(std::string modelName = "shubert_e_six_p"); - void SpawnRandomCar(); - void CrashMe(); - void BreakMe(); - void CloseGame(); - void ToggleEntityBrowser(); - void ToggleCameraStudio(); void ToggleAudioDebug(); + void ToggleCameraStudio(); + void ToggleEntityBrowser(); + void ToggleNetworkStats(); void TogglePlayerDebug(); void ToggleVehicleDebug(); - void ToggleNetworkStats(); + void ToggleWorldDebug(); + + void Disconnect(); + void CrashMe(); + void BreakMe(); + void CloseGame(); + void SpawnCrashObject(); }; } // namespace MafiaMP::Core diff --git a/code/client/src/core/ui/audio_debug.cpp b/code/client/src/core/ui/audio_debug.cpp index 6e78f31e..de175133 100644 --- a/code/client/src/core/ui/audio_debug.cpp +++ b/code/client/src/core/ui/audio_debug.cpp @@ -1,5 +1,5 @@ #include "audio_debug.h" -#include + #include #include "sdk/c_game_audio_module.h" diff --git a/code/client/src/core/ui/entity_browser.cpp b/code/client/src/core/ui/entity_browser.cpp index 70e38692..e4538743 100644 --- a/code/client/src/core/ui/entity_browser.cpp +++ b/code/client/src/core/ui/entity_browser.cpp @@ -1,7 +1,6 @@ #include "entity_browser.h" #include "../application.h" -#include #include #include diff --git a/code/client/src/core/ui/network_stats.cpp b/code/client/src/core/ui/network_stats.cpp index 238043ef..7c0e644e 100644 --- a/code/client/src/core/ui/network_stats.cpp +++ b/code/client/src/core/ui/network_stats.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include "game/helpers/controls.h" diff --git a/code/client/src/core/ui/player_debug.cpp b/code/client/src/core/ui/player_debug.cpp index fea1f54e..ef1e532e 100644 --- a/code/client/src/core/ui/player_debug.cpp +++ b/code/client/src/core/ui/player_debug.cpp @@ -1,5 +1,5 @@ #include "player_debug.h" -#include + #include #include "sdk/c_player_teleport_module.h" diff --git a/code/client/src/core/ui/world_debug.cpp b/code/client/src/core/ui/world_debug.cpp new file mode 100644 index 00000000..9a855c15 --- /dev/null +++ b/code/client/src/core/ui/world_debug.cpp @@ -0,0 +1,304 @@ +#include "world_debug.h" + +#include "../application.h" + +#include + +#include + +#include "sdk/c_game_gfx_env_eff_module.h" +#include "sdk/entities/c_player_2.h" +#include "sdk/mafia/framework/c_mafia_dbs.h" +#include "sdk/ue/game/traffic/c_streaming_traffic_module.h" +#include "sdk/ue/gfx/environmenteffects/c_gfx_environment_effects.h" + +#include "sdk/entities/c_car.h" +#include "sdk/entities/c_vehicle.h" + +#include "game/helpers/controls.h" +#include "game/helpers/human.h" + +namespace MafiaMP::Core::UI { + WorldDebug::WorldDebug() {} + + void WorldDebug::Update() { + const auto pActivePlayer = Game::Helpers::Controls::GetLocalPlayer(); + if (!pActivePlayer) { + return; + } + + const auto gfxEnvironmentEffects = SDK::ue::gfx::environmenteffects::C_GfxEnvironmentEffects::GetInstance(); + if (!gfxEnvironmentEffects) { + return; + } + const auto weatherManager = gfxEnvironmentEffects->GetWeatherManager(); + if (!weatherManager) { + return; + } + + const auto streamingTrafficModule = SDK::ue::game::traffic::C_StreamingTrafficModule::GetInstance(); + if (!streamingTrafficModule) { + return; + } + + ImGui::Begin("World debug", &_visible); + + if (ImGui::CollapsingHeader("Vehicle spawner")) { + if (ImGui::Button("Despawn all")) { + for (const auto &vehicle : _spawnedVehicles) { + gApplication->GetEntityFactory()->ReturnEntity(vehicle); + } + _spawnedVehicles.clear(); + } + + ImGui::Spacing(); + ImGui::Separator(); + ImGui::Spacing(); + + static const char *selectedVehicleModelName = "berkley_810"; + + static bool toggleShowSupportedOnly = true; + ImGui::Checkbox("Show supported by MafiaMP only", &toggleShowSupportedOnly); + + static char modelNameFilter[100] = ""; + ImGui::InputText("ModelName filter", modelNameFilter, 100); + + { + const auto mafiaDB = SDK::mafia::framework::GetMafiaDBs(); + if (!mafiaDB) { + return; + } + + const auto vehiclesDB = mafiaDB->GetVehiclesDatabase(); + if (!vehiclesDB.IsValid()) { + return; + } + + const auto vehiclesDBCount = vehiclesDB->GetVehiclesCount(); + + if (ImGui::BeginListBox("Vehicle list")) { + for (int n = 0; n < vehiclesDBCount; n++) { + using namespace SDK::mafia::framework; + const C_VehiclesDatabase::TItemAccessorConst &vehicleAccessor = vehiclesDB->GetVehicleByIndex(n); + + if (const auto *vehicle = vehicleAccessor.Get()) { + const auto vehicleID = vehicle->GetID(); + + // Unused index, nothing to spawn + if (vehicle->GetID() == 0) { + continue; + } + + const char *modelName = vehicle->GetModelName(); + if (!modelName) { + Framework::Logging::GetLogger("Debug")->info("Skipping ID {}, encountered m_ModelName which is nullptr", vehicleID); + continue; + } + + if (toggleShowSupportedOnly && vehicle->HasVehicleFlags(SDK::mafia::traffic::E_TrafficVehicleFlags::E_TVF_CAR) == false) { + continue; + } + + if (strlen(modelNameFilter) > 0 && strstr(modelName, modelNameFilter) == nullptr) { + continue; + } + + const bool isSelected = (strcmp(selectedVehicleModelName, modelName) == 0); + + auto itemName = fmt::format("{} (id: {})", modelName, vehicleID); + if (ImGui::Selectable(itemName.c_str(), isSelected)) { + selectedVehicleModelName = modelName; + } + + if (isSelected) { + ImGui::SetItemDefaultFocus(); + } + } + } + + ImGui::EndListBox(); + } + } + + static bool togglePutPlayerIn = true; + ImGui::Checkbox("Put player in", &togglePutPlayerIn); + + static bool toggleReplacePreviousVehicleSpawned = true; + ImGui::Checkbox("Replace previous vehicle spawned", &toggleReplacePreviousVehicleSpawned); + + if (ImGui::Button("Spawn")) { + SpawnCar(selectedVehicleModelName, togglePutPlayerIn, toggleReplacePreviousVehicleSpawned); + } + } + + if (ImGui::CollapsingHeader("Weather Set")) { + static float weatherSetTransitionSpeed = 1.0f; + ImGui::InputFloat("Transition speed", &weatherSetTransitionSpeed); + + static const char *weatherSetNames[] = {"__test_all_cloud", "__test_cloud", "__test_high_cloud", "_default_editor", "_default_game", "_default_game_cloudy", "_default_game_foggy", "_default_game_morning_sunny", "_default_game_overcast", "_default_game_rainy", + "_test_jakub", "_time_of_day", "cine_0495_intermission_one_morello", "cine_0997", "cine_1195_omerta_funeral_night", "cine_1195_omerta_funeral_night_emiss_off", "cine_1700_afternoon2", "cine_1700_night_rain", "cine_1700_noon", "cine_1700_sunset", "day_cycle_01", + "lh_gui_menu_default", "main_menu", "mm_000_prolgue_cp_240_norman_stairs", "mm_000_prologue_cp_000", "mm_000_prologue_cp_00_lighthouse_cliff", "mm_000_prologue_cp_00_lihgthouse", "mm_000_prologue_cp_050_church_open", "mm_000_prologue_cp_060_church_edge", + "mm_000_prologue_cp_070_church_city", "mm_000_prologue_cp_080_city_look_up", "mm_000_prologue_cp_090_city_look_down", "mm_000_prologue_cp_100_italy_metro", "mm_000_prologue_cp_110_italy_market", "mm_000_prologue_cp_120_italy_street", + "mm_000_prologue_cp_130_city_to_work", "mm_000_prologue_cp_150_work_boat", "mm_000_prologue_cp_170_work_truck", "mm_000_prologue_cp_180_crowd", "mm_000_prologue_cp_190_boat_reveal", "mm_000_prologue_cp_200_boat_boat", "mm_000_prologue_cp_210_boat_bridge", + "mm_000_prologue_cp_220_norman_bridge", "mm_000_prologue_cp_260_crowd", "mm_000_prologue_cp_300_norman_feet", "mm_00_prologue_cp_00_lighthouse_car", "mm_00_prologue_cp_00_lighthouse_house", "mm_010_chase_cp_020_escape", "mm_010_chase_cp_020_escape_gi_off", + "mm_020_taxi_cp_010_arrival", "mm_020_taxi_cp_010_arrival_gi_off", "mm_020_taxi_cp_070_cine_0200_taxi", "mm_030_molotov_cp_010_cine", "mm_030_molotov_cp_010_cinematic_intro", "mm_040_motel_cp_005_meet_salieri", "mm_050_race_cp_010", "mm_050_race_cp_110", + "mm_050_race_cp_120", "mm_050_race_cp_140", "mm_060_sarah_cp_010_cine_0600_sarah_intro", "mm_070_hoodlums_cp_010", "mm_070_hoodlums_cp_086_cover_paulie", "mm_080_brothel_cp_010_cs_start", "mm_080_brothel_cp_110_cine_0850_brothel_funera", "mm_100_farm_cp_000", + "mm_100_farm_cp_050", "mm_100_farm_cp_080", "mm_100_farm_cp_140", "mm_110_omerta_cp_010_cs_cs_park", "mm_110_omerta_cp_050_cs_safehouse", "mm_110_omerta_cp_120_cine_funeral", "mm_110_omerta_cp_120_cs_funeral", "mm_120_mansion_cp_010_cs_salvatore", + "mm_130_parking_cp_010_cine_parking", "mm_140_salieri_cp_010_cine_salieri", "mm_140_salieri_cp_100_salieri_outro", "mm_150_boat_cp_010", "mm_150_boat_cp_080_explore_the_ship", "mm_150_boat_cp_120", "mm_160_harbor_cp_000_cinematic_night", + "mm_160_harbor_cp_010_cinematic_start", "mm_160_harbor_cp_080_harbour_entrance_cutscene", "mm_170_plane_cp_010_cine_1700_plane", "mm_170_plane_cp_060_cine_1750_plane_airport", "mm_170_plane_cp_080_cine_1760_plane_shoot", "mm_180_sniper_cp_010", + "mm_180_sniper_cp_010_2", "mm_190_cigars_cp_010_cs_intro", "mm_190_cigars_cp_030_drive_to_harbor", "mm_200_bank_cp_010_bank_arrival", "mm_210_gallery_cp_010", "mm_210_gallery_cp_050", "mm_cine_0005_prologue", "mm_cine_0995_intermission_two", + "mm_cine_1395_intermission_three", "mm_cine_1795_intermission_four", "mm_prologue_cp_290_cross_road", "outro_cine_2210_salieri", "outro_cine_2210_tommy_death", "outro_cine_2210_tommy_prison", "outro_cine_2210_vincenzo_ralph", "outro_cine_2210_wedding", + "temp_teaser_trailer", "test_for_screenshots_alpha", "test_no_color_grading_day", "test_no_color_grading_night", "test_no_color_grading_overcast", "trailer_comp_02", "trailer_comp_02b", "trailer_comp_02c", "trailer_comp_03"}; + + const char *currentWeatherSet = SDK::C_GameGfxEnvEffModule::GetCurrentWeatherSetName(); + if (ImGui::BeginCombo("Name", currentWeatherSet)) { + for (int n = 0; n < IM_ARRAYSIZE(weatherSetNames); n++) { + const bool isSelected = (strcmp(currentWeatherSet, weatherSetNames[n]) == 0); + + if (ImGui::Selectable(weatherSetNames[n], isSelected)) { + std::string selectedItem(weatherSetNames[n]); + weatherManager->SetWeatherSet(selectedItem.c_str(), weatherSetTransitionSpeed); + } + + if (isSelected) { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } + } + + if (ImGui::CollapsingHeader("Time")) { + float defaultTimeFlowSpeedMult = weatherManager->GetDefaultTimeFlowSpeedMult(); + if (ImGui::SliderFloat("DefaultTimeFlowSpeedMult", &defaultTimeFlowSpeedMult, 0.0f, 100.0f)) { + weatherManager->SetDefaultTimeFlowSpeedMult(defaultTimeFlowSpeedMult); + } + + float userTimeFlowSpeedMult = weatherManager->GetUserTimeFlowSpeedMult(); + if (ImGui::SliderFloat("UserTimeFlowSpeedMult", &userTimeFlowSpeedMult, 0.0f, 100.0f)) { + weatherManager->SetUserTimeFlowSpeedMult(userTimeFlowSpeedMult); + } + + bool isTimeFlowEnabled = weatherManager->IsTimeFlowEnabled(); + if (ImGui::Checkbox("Enable TimeFlow", &isTimeFlowEnabled)) { + weatherManager->EnableTimeFlow(isTimeFlowEnabled); + } + + float dayTimeHours = weatherManager->GetDayTimeHours(); + if (ImGui::SliderFloat("DayTimeHours", &dayTimeHours, 0.0f, 24.0f)) { + weatherManager->SetDayTimeHours(dayTimeHours); + } + + float dayTimeRel = weatherManager->GetDayTimeRel(); + ImGui::Text("DayTimeRel: %f", dayTimeRel); + + float dayTimeSec = *reinterpret_cast(weatherManager + 3212); + if (ImGui::InputFloat("DayTimeSec", &dayTimeSec)) { + weatherManager->SetDayTimeSec(dayTimeSec); + } + } + + if (ImGui::CollapsingHeader("Season")) { + if (ImGui::Button("Close Season")) { + streamingTrafficModule->CloseSeason(true); + } + + bool isSeasonOpened = streamingTrafficModule->GetSeasonOpened(); + ImGui::Text("Is Season Opened: %s\n", isSeasonOpened ? "true" : "false"); + + ImGui::Text("PreviousSeasonID: %i\n", streamingTrafficModule->GetPreviousSeasonID()); + + int currentSeasonID = streamingTrafficModule->GetCurrentSeasonID(); + ImGui::Text("CurrentSeasonID: %i\n", currentSeasonID); + + static const std::map seasonMap = {{"No season", -1}, {"1930", 1}, {"1932", 2}, {"1933", 3}, {"1935", 4}, {"1938", 5}, {"Freeride", 100}}; + + auto foundSeasonID = std::find_if(seasonMap.begin(), seasonMap.end(), [currentSeasonID](const auto &pair) { + return pair.second == currentSeasonID; + }); + + const char *selectedSeasonName = (foundSeasonID != seasonMap.end()) ? foundSeasonID->first : nullptr; + + if (ImGui::BeginCombo("##seasonId", selectedSeasonName)) { + for (auto it = seasonMap.begin(); it != seasonMap.end(); ++it) { + const bool isSelected = (currentSeasonID == it->second); + + if (ImGui::Selectable(it->first, isSelected)) { + streamingTrafficModule->CloseSeason(true); + streamingTrafficModule->OpenSeason(it->second, true); + } + + if (isSelected) { + ImGui::SetItemDefaultFocus(); + } + } + + ImGui::EndCombo(); + } + } + + if (ImGui::CollapsingHeader("Traffic")) { + int m_iMaxHumanElements = streamingTrafficModule->GetMaxHumanElements(); + if (ImGui::InputInt("MaxHumanElements", &m_iMaxHumanElements)) { + streamingTrafficModule->SetMaxHumanElements(m_iMaxHumanElements); + } + } + + ImGui::End(); + } + + void WorldDebug::SpawnCar(std::string modelName, bool putPlayerIn, bool replacePrevious) { + auto info = Core::gApplication->GetEntityFactory()->RequestVehicle(modelName); + + if (replacePrevious && !_spawnedVehicles.empty()) { + auto previousVehicle = _spawnedVehicles.back(); + gApplication->GetEntityFactory()->ReturnEntity(previousVehicle); + _spawnedVehicles.pop_back(); + } + + _spawnedVehicles.push_back(info); + + const auto OnCarRequestFinish = [putPlayerIn](Game::Streaming::EntityTrackingInfo *info, bool success) { + if (success) { + auto car = reinterpret_cast(info->GetEntity()); + if (!car) { + return; + } + car->GameInit(); + car->Activate(); + car->Unlock(); + + auto localPlayer = Game::Helpers::Controls::GetLocalPlayer(); + + SDK::ue::sys::math::C_Vector newPos = localPlayer->GetPos(); + SDK::ue::sys::math::C_Quat newRot = localPlayer->GetRot(); + SDK::ue::sys::math::C_Matrix transform = {}; + transform.Identity(); + transform.SetRot(newRot); + transform.SetPos(newPos); + car->GetVehicle()->SetVehicleMatrix(transform, SDK::ue::sys::core::E_TransformChangeType::DEFAULT); + car->GetVehicle()->SetSPZText("DEBUG", true); + + if (putPlayerIn) { + auto characterController = reinterpret_cast(localPlayer->GetCharacterController()); + Game::Helpers::Human::PutIntoCar(characterController, car, 0, true); + } + } + }; + + const auto OnCarReturned = [](Game::Streaming::EntityTrackingInfo *info, bool wasCreated) { + if (!info) { + return; + } + auto car = reinterpret_cast(info->GetEntity()); + if (wasCreated && car) { + car->Deactivate(); + car->GameDone(); + car->Release(); + } + }; + + info->SetRequestFinishCallback(OnCarRequestFinish); + info->SetReturnCallback(OnCarReturned); + } +}; // namespace MafiaMP::Core::UI diff --git a/code/client/src/core/ui/world_debug.h b/code/client/src/core/ui/world_debug.h new file mode 100644 index 00000000..cb362ad7 --- /dev/null +++ b/code/client/src/core/ui/world_debug.h @@ -0,0 +1,32 @@ +#pragma once + +#include "utils/safe_win32.h" + +#include +#include + +#include "game/streaming/entity_tracking_info.h" + +namespace MafiaMP::Core::UI { + class WorldDebug final { + public: + WorldDebug(); + + void Update(); + + bool IsVisible() const { + return _visible; + } + + void SetVisible(bool visible) { + _visible = visible; + } + + void SpawnCar(std::string modelName = "berkley_810", bool putPlayerIn = false, bool replacePrevious = false); + + private: + bool _visible = false; + + std::vector _spawnedVehicles; + }; +} // namespace MafiaMP::Core::UI diff --git a/code/client/src/sdk/c_game_gfx_env_eff_module.h b/code/client/src/sdk/c_game_gfx_env_eff_module.h new file mode 100644 index 00000000..a776203c --- /dev/null +++ b/code/client/src/sdk/c_game_gfx_env_eff_module.h @@ -0,0 +1,12 @@ +#pragma once + +#include "patterns.h" + +namespace SDK { + class C_GameGfxEnvEffModule { + public: + static const char *GetCurrentWeatherSetName() { + return hook::call(gPatterns.C_GameGfxEnvEffModule__GetCurrentWeatherSetName); + } + }; +} // namespace SDK diff --git a/code/client/src/sdk/patterns.cpp b/code/client/src/sdk/patterns.cpp index cdb715de..dbad3e0e 100644 --- a/code/client/src/sdk/patterns.cpp +++ b/code/client/src/sdk/patterns.cpp @@ -141,6 +141,9 @@ namespace SDK { // C_GameFramework gPatterns.C_GameFramework__IsSuspended = reinterpret_cast(hook::get_pattern("80 39 ? 74 ? 80 79 ? ?")); + // C_GameGfxEnvEffModule + gPatterns.C_GameGfxEnvEffModule__GetCurrentWeatherSetName = reinterpret_cast(hook::get_pattern("48 8B 05 ? ? ? ? 48 8B 40 28 48 8B 40 28")); + // C_GameGUI2Module uint64_t C_GameGUI2Module = hook::get_opcode_address("E8 ? ? ? ? 41 8D 56 11"); uint8_t *C_GameGUI2Module_Bytes = reinterpret_cast(C_GameGUI2Module); diff --git a/code/client/src/sdk/patterns.h b/code/client/src/sdk/patterns.h index 39820580..8b7123c5 100644 --- a/code/client/src/sdk/patterns.h +++ b/code/client/src/sdk/patterns.h @@ -126,6 +126,9 @@ namespace SDK { // C_GameFramework uint64_t C_GameFramework__IsSuspended = 0x0; + // C_GameGfxEnvEffModule + uint64_t C_GameGfxEnvEffModule__GetCurrentWeatherSetName = 0x0; + // C_GameGUI2Module uint64_t C_GameGUI2Module__GetGameGui2Module = 0x0; uint64_t C_GameGUI2Module__Instance = 0x0;