diff --git a/code/client/CMakeLists.txt b/code/client/CMakeLists.txt index 9ebf7974..54c62bd8 100644 --- a/code/client/CMakeLists.txt +++ b/code/client/CMakeLists.txt @@ -68,6 +68,8 @@ set(MAFIAMP_SDK_FILES srC/sdk/entities/c_human2.cpp src/sdk/entities/c_player_2.cpp src/sdk/entities/c_vehicle.cpp + src/sdk/c_inventory_wrapper.cpp + src/sdk/mafia/database/c_ui_database.cpp src/sdk/mafia/framework/director/c_game_director.cpp src/sdk/mafia/framework/c_mafia_dbs.cpp src/sdk/mafia/framework/c_mafia_framework.cpp @@ -75,6 +77,7 @@ set(MAFIAMP_SDK_FILES src/sdk/mafia/streaming/c_actors_slot_wrapper.cpp src/sdk/mafia/streaming/c_slot_wrapper.cpp src/sdk/mafia/streaming/c_streaming_module.cpp + src/sdk/mafia/ui/hud/race_xbin.cpp src/sdk/mafia/ui/menu/c_save_menu.cpp src/sdk/mafia/ui/navigation/c_navigation.cpp src/sdk/mafia/ui/support/c_fader.cpp diff --git a/code/client/src/core/ui/devs/debug_world.cpp b/code/client/src/core/ui/devs/debug_world.cpp index ace0b6cc..6f866e6f 100644 --- a/code/client/src/core/ui/devs/debug_world.cpp +++ b/code/client/src/core/ui/devs/debug_world.cpp @@ -8,7 +8,11 @@ #include "sdk/entities/c_car.h" #include "sdk/entities/c_player_2.h" #include "sdk/entities/c_vehicle.h" +#include "sdk/mafia/database/c_ui_database.h" #include "sdk/mafia/framework/c_mafia_dbs.h" +#include "sdk/mafia/ui/c_game_gui_2_module.h" +#include "sdk/mafia/ui/hud/race_xbin.h" +#include "sdk/mafia/ui/hud/c_hud_controller.h" #include "sdk/ue/game/traffic/c_streaming_traffic_module.h" #include "sdk/ue/gfx/environmenteffects/c_gfx_environment_effects.h" @@ -242,6 +246,62 @@ namespace MafiaMP::Core::UI::Devs { streamingTrafficModule->SetMaxHumanElements(m_iMaxHumanElements); } } + + if (ImGui::CollapsingHeader("Racing")) { + SDK::mafia::ui::C_GameGUI2Module *GameGuiModule = SDK::mafia::ui::GetGameGui2Module(); + SDK::ue::C_WeakPtr result = GameGuiModule->GetDatabase(); + if (SDK::mafia::database::C_UIDatabase *database = reinterpret_cast(result.Get())) { + SDK::mafia::database::C_UIDatabase::C_HUDTable *hudTable = database->GetHUDTable(); + + ImGui::PushItemWidth(75.0f); + + // VISIBLE + ImGui::Text("Racing HUDElement Visibility"); + ImGui::Checkbox("##racing_visible_hudtable", &hudTable->m_bRacingVisible); + + ImGui::Spacing(); + + // LAPS + ImGui::Text("Current Laps / Num Laps"); + ImGui::InputScalar("##total_laps_hudtable", ImGuiDataType_U16, &hudTable->m_uCurLap); + ImGui::SameLine(); + ImGui::InputScalar("##curent_lap_hudtable", ImGuiDataType_U16, &hudTable->m_uTotalLaps); + + ImGui::Spacing(); + + // POSITIONS + ImGui::Text("Current Position / Max Position"); + ImGui::InputScalar("##total_position_hudtable", ImGuiDataType_U16, &hudTable->m_uCurPosition); + ImGui::SameLine(); + ImGui::InputScalar("##curent_position_hudtable", ImGuiDataType_U16, &hudTable->m_uTotalPositions); + + ImGui::Spacing(); + + // CHECKPOINTS + ImGui::Text("Current Checkpoint / Max Checkpoints"); + ImGui::InputScalar("##total_checkpoint_hudtable", ImGuiDataType_U16, &hudTable->m_uCurCheckpoint); + ImGui::SameLine(); + ImGui::InputScalar("##curent_checkpoint_hudtable", ImGuiDataType_U16, &hudTable->m_uTotalCheckpoints); + + ImGui::Spacing(); + + // UNKNOWN + ImGui::Text("Current UNKNOWN / Max UNKNOWN"); + ImGui::InputScalar("##total_UNKNOWN_hudtable", ImGuiDataType_U16, &hudTable->m_uUnknown1); + ImGui::SameLine(); + ImGui::InputScalar("##curent_UNKNOWN_hudtable", ImGuiDataType_U16, &hudTable->m_uUnknown2); + + ImGui::Spacing(); + + // COUNTDOWN + ImGui::Text("Countdown"); + ImGui::SameLine(); + ImGui::TextDisabled("(3, 2, 1 for lights, 0 for GO). Sound is played automatically"); + ImGui::InputScalar("##countdown_hudtable", ImGuiDataType_U8, &hudTable->m_uCountdown); + + ImGui::PopItemWidth(); + } + } }; CreateUIWindow("World debug", windowContent, &_open); diff --git a/code/client/src/sdk/mafia/database/c_ui_database.cpp b/code/client/src/sdk/mafia/database/c_ui_database.cpp new file mode 100644 index 00000000..114998c4 --- /dev/null +++ b/code/client/src/sdk/mafia/database/c_ui_database.cpp @@ -0,0 +1 @@ +#include "c_ui_database.h" diff --git a/code/client/src/sdk/mafia/database/c_ui_database.h b/code/client/src/sdk/mafia/database/c_ui_database.h new file mode 100644 index 00000000..c361f59c --- /dev/null +++ b/code/client/src/sdk/mafia/database/c_ui_database.h @@ -0,0 +1,39 @@ +#pragma once + +#include "../../ue/sys/sodb/c_database_interface.h" + +namespace SDK { + namespace mafia::database { + class C_UIDatabase: public ue::sys::sodb::C_DatabaseInterface { + public: + class C_HUDTable { + public: + uint8_t pad0[0x1E]; // 0000 - 001E + bool m_bRacingVisible = false; // 001E - 001F + uint8_t pad1[0x3]; // 001F - 0022 + uint8_t pad2[0x346]; // 0022 - 0368 + float m_fElapsedTime = 0.0f; // 0368 - 036C + float m_fTargetTime = 0.0f; // 036C - 0370 + uint16_t m_uCurCheckpoint = 0; // 0370 - 0372 + uint16_t m_uTotalCheckpoints = 0; // 0372 - 0374 + uint16_t m_uCurPosition = 0; // 0374 - 0376 + uint16_t m_uTotalPositions = 0; // 0376 - 0378 + uint16_t m_uUnknown1 = 0; // 0378 - 037C + uint16_t m_uUnknown2 = 0; // 0378 - 037C + uint16_t m_uCurLap = 0; // 037C - 037E + uint16_t m_uTotalLaps = 0; // 037E - 0380 + uint8_t m_uCountdown = 0; // 0380 - 0381 + }; + + C_HUDTable *GetHUDTable() const { + return m_pHUDTable; + } + + private: + // NB: Atleast 0x38 is part of C_DatabaseInterface + // Since m_pHUDTable is at 0x20, that could actually be part of base class + uint8_t pad0[0x20]; // 0000 - 0020 + C_HUDTable *m_pHUDTable = nullptr; // 0020 - 0028 + }; + }; // namespace mafia::database +}; // namespace SDK diff --git a/code/client/src/sdk/mafia/ui/c_game_gui_2_module.cpp b/code/client/src/sdk/mafia/ui/c_game_gui_2_module.cpp index e469564c..b5b75b52 100644 --- a/code/client/src/sdk/mafia/ui/c_game_gui_2_module.cpp +++ b/code/client/src/sdk/mafia/ui/c_game_gui_2_module.cpp @@ -12,6 +12,11 @@ namespace SDK { hook::this_call(gPatterns.C_GameGUI2Module__SendMessageMovie, this, title, msg, varArgs, unk2); } + ue::C_WeakPtr C_GameGUI2Module::GetDatabase() { + ue::C_WeakPtr database; + return hook::this_call &>(gPatterns.C_GameGUI2Module__GetDatabase, this, database); + } + C_GameGUI2Module *C_GameGUI2Module::GetInstance() { return *reinterpret_cast(gPatterns.C_GameGUI2Module__Instance); } diff --git a/code/client/src/sdk/mafia/ui/c_game_gui_2_module.h b/code/client/src/sdk/mafia/ui/c_game_gui_2_module.h index ada9a231..a11178c6 100644 --- a/code/client/src/sdk/mafia/ui/c_game_gui_2_module.h +++ b/code/client/src/sdk/mafia/ui/c_game_gui_2_module.h @@ -8,6 +8,8 @@ #include "support/c_fader.h" #include "../../ue/c_variant.h" +#include "../../ue/c_weak_ptr.h" +#include "../../ue/sys/sodb/c_database_interface.h" #include @@ -40,6 +42,8 @@ namespace SDK { return *reinterpret_cast((uint64_t)this + 0x0C0); } + ue::C_WeakPtr GetDatabase(); + static C_GameGUI2Module *GetInstance(); }; diff --git a/code/client/src/sdk/mafia/ui/hud/c_hud_controller.h b/code/client/src/sdk/mafia/ui/hud/c_hud_controller.h index ebbe214c..a7d7e230 100644 --- a/code/client/src/sdk/mafia/ui/hud/c_hud_controller.h +++ b/code/client/src/sdk/mafia/ui/hud/c_hud_controller.h @@ -1,9 +1,42 @@ #pragma once +#include "../../../patterns.h" + namespace SDK { namespace mafia::ui::hud { + + class C_RaceTimer { + public: + + // This starts C_RaceManager! + // If you do not wish to use C_RaceManager, use mafia::ui::hud::RaceXBin instead! + void SetVisible(const bool visible) { + hook::this_call(gPatterns.C_RaceTimer_SetVisible, this, visible); + } + + // This starts C_RaceManager! + // If you do not wish to use C_RaceManager, Use mafia::ui::hud::RaceXBin instead! + void StartRace(const uint32_t numCheckpoints, const float targetTime, const uint32_t numLaps) { + hook::this_call(gPatterns.C_RaceTimer_StartRace, this, numCheckpoints, targetTime, numLaps); + } + + private: + void *m_pVtable = nullptr; // 0000 - 0008 + void *m_pUnk0 = nullptr; // 0008 - 0010 + float m_fTimer = 0.0f; // 0010 - 0014 + uint32_t m_uCurrentCheckpoint = 0; // 0014 - 0018 + uint32_t m_uCurrentLap = 0; // 0018 - 001C + }; + class C_HudController { public: + C_RaceTimer *GetRacingTimer() { + return m_pRaceTimer; + } + + private: + char pad0[0x5A8]; // 0000 - 05A8 + C_RaceTimer *m_pRaceTimer = nullptr; // 05A8 - 05B0 }; } // namespace mafia::ui::hud } // namespace SDK diff --git a/code/client/src/sdk/mafia/ui/hud/race_xbin.cpp b/code/client/src/sdk/mafia/ui/hud/race_xbin.cpp new file mode 100644 index 00000000..f8477bb0 --- /dev/null +++ b/code/client/src/sdk/mafia/ui/hud/race_xbin.cpp @@ -0,0 +1,82 @@ +#include "race_xbin.h" + +#include "../../database/c_ui_database.h" +#include "../c_game_gui_2_module.h" + +namespace RaceXBinUtils +{ + // Handy little utility function to fetch the HUDTable, for the Racing XBin. + SDK::mafia::database::C_UIDatabase::C_HUDTable *GetHUDTable() { + + // Fetch database + SDK::mafia::ui::C_GameGUI2Module *GameGuiModule = SDK::mafia::ui::GetGameGui2Module(); + SDK::ue::C_WeakPtr result = GameGuiModule->GetDatabase(); + + // need to cast to C_UIDatabase + // TODO: Feels like this should be dynamic_cast, rather than reinterpret_cast + if (SDK::mafia::database::C_UIDatabase *database = reinterpret_cast(result.Get())) { + return database->GetHUDTable(); + } + + return nullptr; + } +} + +namespace SDK { + namespace mafia::ui::hud { + + void RaceXBin::SetVisible(const bool visibility) { + if (SDK::mafia::database::C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) { + hudTable->m_bRacingVisible = visibility; + } + } + + void RaceXBin::SetTargetTime(const float targetTime) { + if (SDK::mafia::database::C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) { + hudTable->m_fTargetTime = targetTime; + } + } + + void RaceXBin::SetPosition(const uint16_t currentPosition) { + if (SDK::mafia::database::C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) { + hudTable->m_uCurPosition = currentPosition; + } + } + + void RaceXBin::SetPositionTotal(const uint16_t totalPositions) { + if (SDK::mafia::database::C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) { + hudTable->m_uTotalPositions = totalPositions; + } + } + + void RaceXBin::SetLaps(const uint16_t currentLap) { + if (SDK::mafia::database::C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) { + hudTable->m_uCurLap = currentLap; + } + } + + void RaceXBin::SetLapsTotal(const uint16_t totalLaps) { + if (SDK::mafia::database::C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) { + hudTable->m_uTotalLaps = totalLaps; + } + } + + void RaceXBin::SetCheckpoints(const uint16_t currentCheckpoint) { + if (SDK::mafia::database::C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) { + hudTable->m_uCurCheckpoint = currentCheckpoint; + } + } + + void RaceXBin::SetCheckpointsTotal(const uint16_t totalCheckpoint) { + if (SDK::mafia::database::C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) { + hudTable->m_uTotalCheckpoints = totalCheckpoint; + } + } + + void RaceXBin::SetCountdown(const uint8_t countdown) { + if (SDK::mafia::database::C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) { + hudTable->m_uCountdown = countdown; + } + } + } // namespace mafia::ui::hud +} // namespace SDK diff --git a/code/client/src/sdk/mafia/ui/hud/race_xbin.h b/code/client/src/sdk/mafia/ui/hud/race_xbin.h new file mode 100644 index 00000000..dfdb96eb --- /dev/null +++ b/code/client/src/sdk/mafia/ui/hud/race_xbin.h @@ -0,0 +1,77 @@ +#pragma once + +#include + +namespace SDK { + namespace mafia::ui::hud { + + /** + * Handy structure which provides an API to update the Racing HUD Element. + * Note that there are some discrepancies with the executable code however + * all functionality should be the same. + */ + class RaceXBin { + public: + + /** + * Set the visibility of the Racing HUD Element. + * @param bVisibility - Should the HUD Element be visible + */ + static void SetVisible(const bool visiblity); + + /** + * Set the Target Time on the Racing HUD Element. + * Note that this may not have an effect (eg. appear on the HUD) + * @param InTargetTime - Target Time to show on the HUD + */ + static void SetTargetTime(const float targetTime); + + /** + * Set the current Position on the Racing HUD Element. + * Note that 'Total Positions' may need to be set before this to have an effect. + * @param InPosition - The current position out of Total Positions + */ + static void SetPosition(const uint16_t currentPosition); + + /** + * Set the max amount of Positions on the Racing HUD Element + * @param InTotalPosition - Max number of positions + */ + static void SetPositionTotal(const uint16_t totalPositions); + + /** + * Set the current Lap on the Racing HUD Element. + * Note that 'Total Laps' may need to be set before this to have an effect. + * @param InLaps - The current Lap out of Total Laps + */ + static void SetLaps(const uint16_t currentLap); + + /** + * Set the number of Laps on the Racing HUD Element + * @param InTotalPosition - Number of Laps + */ + static void SetLapsTotal(const uint16_t totalLaps); + + /** + * Set the current Checkpoint on the Racing HUD Element. + * Note that 'Total Checkpoints' may need to be set before this to have an effect. + * @param InPosition - The current Checkpoint out of Total Checkpoints + */ + static void SetCheckpoints(const uint16_t currentCheckpoint); + + /** + * Set the max amount of Checkpoints on the Racing HUD Element + * @param InTotalPosition - Max number of checkpoints + */ + static void SetCheckpointsTotal(const uint16_t totalCheckpoints); + + /** + * Set the countdown. Max is 3, Minimum is 0. + * The HUD automatically plays the noise when the countdown is updated. + * The caller will have to manage a timer for the countdown. + * @param InCountdown - Current step in the Countdown + */ + static void SetCountdown(const uint8_t countdown); + }; + } // namespace mafia::ui::hud +} // namespace SDK diff --git a/code/client/src/sdk/patterns.cpp b/code/client/src/sdk/patterns.cpp index 79e70e2e..e2abaa64 100644 --- a/code/client/src/sdk/patterns.cpp +++ b/code/client/src/sdk/patterns.cpp @@ -148,6 +148,7 @@ namespace SDK { uint64_t C_GameGUI2Module = hook::get_opcode_address("E8 ? ? ? ? 41 8D 56 11"); uint8_t *C_GameGUI2Module_Bytes = reinterpret_cast(C_GameGUI2Module); + gPatterns.C_GameGUI2Module__GetDatabase = reinterpret_cast(hook::get_pattern("48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 48 8D B9 ? ? ? ? 48 8B F2")); gPatterns.C_GameGUI2Module__GetGameGui2Module = hook::get_opcode_address("E8 ? ? ? ? 40 80 F6 01"); gPatterns.C_GameGUI2Module__Instance = reinterpret_cast(C_GameGUI2Module_Bytes + *(int32_t *)(C_GameGUI2Module_Bytes + 3) + 7); gPatterns.C_GameGUI2Module__SendHUDSimpleBooleanMessage = hook::get_opcode_address("E8 ? ? ? ? 49 8B 97 ? ? ? ? 4C 8D 05 ? ? ? ?"); @@ -312,6 +313,10 @@ namespace SDK { // C_Quat gPatterns.C_Quat__SetDir = hook::get_opcode_address("E8 ? ? ? ? F3 44 0F 59 5D ?"); + + // C_RaceTimer + gPatterns.C_RaceTimer_SetVisible = reinterpret_cast(hook::get_pattern("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 56 41 57 48 83 EC ? 0F B6 F2")); + gPatterns.C_RaceTimer_StartRace = reinterpret_cast(hook::get_pattern("48 89 5C 24 ? 57 48 83 EC ? 48 8B F9 C7 41 ? ? ? ? ? 41 0F B7 C9")); // C_SceneObject gPatterns.C_SceneObject__SetTransform = reinterpret_cast(hook::get_pattern("40 53 48 83 EC ? 48 8D 41 ? 48 8B D9 0F 10 02")); diff --git a/code/client/src/sdk/patterns.h b/code/client/src/sdk/patterns.h index 5fac7d3e..ca5cad8a 100644 --- a/code/client/src/sdk/patterns.h +++ b/code/client/src/sdk/patterns.h @@ -130,6 +130,7 @@ namespace SDK { uint64_t C_GameGfxEnvEffModule__GetCurrentWeatherSetName = 0x0; // C_GameGUI2Module + uint64_t C_GameGUI2Module__GetDatabase = 0x0; uint64_t C_GameGUI2Module__GetGameGui2Module = 0x0; uint64_t C_GameGUI2Module__Instance = 0x0; uint64_t C_GameGUI2Module__SendHUDSimpleBooleanMessage = 0x0; @@ -281,6 +282,10 @@ namespace SDK { // C_Quat uint64_t C_Quat__SetDir = 0x0; + // C_RaceTimer + uint64_t C_RaceTimer_SetVisible = 0x0; + uint64_t C_RaceTimer_StartRace = 0x0; + // C_SceneObject uint64_t C_SceneObject__SetTransform = 0x0; diff --git a/code/client/src/sdk/ue/game/traffic/c_race_manager.h b/code/client/src/sdk/ue/game/traffic/c_race_manager.h index bd24b325..f1ca9a76 100644 --- a/code/client/src/sdk/ue/game/traffic/c_race_manager.h +++ b/code/client/src/sdk/ue/game/traffic/c_race_manager.h @@ -2,8 +2,12 @@ namespace SDK { namespace ue::game::traffic { + + /** + * Stubbed ingame Race Manager. + * For MP we avoid this, so just a stub + */ class C_RaceManager { - public: }; - } -} + } // namespace ue::game::traffic +} // namespace SDK