Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Racing UI API #100

Merged
merged 18 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions code/client/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,15 @@ set(MAFIAMP_SDK_FILES
src/sdk/entities/c_player_2.cpp
src/sdk/entities/c_vehicle.cpp
src/sdk/inventory/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
src/sdk/mafia/framework/c_vehicles_database.cpp
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
Expand Down
66 changes: 66 additions & 0 deletions code/client/src/core/ui/world_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@
#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/mafia/database/c_ui_database.h"
#include "sdk/mafia/ui/hud/race_xbin.h"
#include "sdk/mafia/ui/hud/c_hud_controller.h"

#include "sdk/entities/c_car.h"
#include "sdk/entities/c_vehicle.h"

#include "game/helpers/controls.h"
#include "game/helpers/human.h"
#include "../../sdk/mafia/ui/c_game_gui_2_module.h"

namespace MafiaMP::Core::UI {
WorldDebug::WorldDebug() {}
Expand Down Expand Up @@ -244,6 +248,68 @@ namespace MafiaMP::Core::UI {
}
}

if (ImGui::CollapsingHeader("Racing")) {
using namespace SDK::mafia::ui;
using namespace SDK::mafia::database;

auto GameGuiModule = GetGameGui2Module();
SDK::ue::C_WeakPtr<SDK::ue::sys::sodb::C_DatabaseInterface> result = GameGuiModule->GetDatabase();
if (C_UIDatabase *database = reinterpret_cast<C_UIDatabase *>(result.Get())) {
C_UIDatabase::C_HUDTable *hudTable = database->GetHUDTable();

ImGui::PushItemWidth(75.0f);

// VISIBLE
ImGui::Text("Racing HUDElement Visiblity");
ImGui::PushID("Racing_Visible");
ImGui::Checkbox("##racing_visible_hudtable", &hudTable->m_RacingVisible);
ImGui::PopID();

ImGui::Spacing();

// LAPS
ImGui::Text("Current Laps / Num Laps");
ImGui::PushID("Laps");
ImGui::InputScalar("##total_laps_hudtable", ImGuiDataType_U16, &hudTable->m_CurLap);
ImGui::SameLine();
ImGui::InputScalar("##curent_lap_hudtable", ImGuiDataType_U16, &hudTable->m_TotalLaps);
ImGui::PopID();

ImGui::Spacing();

// POSITIONS
ImGui::Text("Current Position / Max Position");
ImGui::PushID("Positions");
ImGui::InputScalar("##total_position_hudtable", ImGuiDataType_U16, &hudTable->m_CurPosition);
ImGui::SameLine();
ImGui::InputScalar("##curent_position_hudtable", ImGuiDataType_U16, &hudTable->m_TotalPositions);
ImGui::PopID();

ImGui::Spacing();

// CHECKPOINTS
ImGui::Text("Current Checkpoint / Max Checkpoints");
ImGui::PushID("Checkpoints");
ImGui::InputScalar("##total_checkpoint_hudtable", ImGuiDataType_U16, &hudTable->m_CurCheckpoint);
ImGui::SameLine();
ImGui::InputScalar("##curent_checkpoint_hudtable", ImGuiDataType_U16, &hudTable->m_TotalCheckpoints);
ImGui::PopID();

ImGui::Spacing();

// COUNTDOWN
ImGui::Text("Countdown");
ImGui::SameLine();
ImGui::TextDisabled("(3, 2, 1 for lights, 0 for GO). Sound is played automatically");
ImGui::PushID("Countdown");
ImGui::InputScalar("##countdown_hudtable", ImGuiDataType_U8, &hudTable->m_Countdown);
ImGui::PopID();


ImGui::PopItemWidth();
}
}

ImGui::End();
}

Expand Down
11 changes: 11 additions & 0 deletions code/client/src/sdk/mafia/database/c_ui_database.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "sdk/mafia/database/c_ui_database.h"

#include "../../patterns.h"

namespace SDK {
namespace mafia::database {
C_UIDatabase::C_HUDTable* C_UIDatabase::GetHUDTable() {
return m_HUDTable;
}
}
}
33 changes: 33 additions & 0 deletions code/client/src/sdk/mafia/database/c_ui_database.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#pragma once

#include "sdk/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 padding_0[0x1E];
bool m_RacingVisible = false;
uint8_t padding_1[0x3]; // most likely other 'is visible' flags
uint8_t padding_2[0x34A];
float m_TargetTime = 0.0f;
uint16_t m_CurCheckpoint = 0; // maybe
uint16_t m_TotalCheckpoints = 0; // maybe
uint16_t m_CurPosition = 0;
uint16_t m_TotalPositions = 0;
uint32_t m_Unknown = 0;
uint16_t m_CurLap = 0;
uint16_t m_TotalLaps = 0;
uint8_t m_Countdown = 0;
};

C_HUDTable *GetHUDTable();

private:
uint8_t padding[0x20];
C_HUDTable *m_HUDTable = nullptr;
};
}; // namespace mafia::framework
}; // namespace SDK
5 changes: 5 additions & 0 deletions code/client/src/sdk/mafia/ui/c_game_gui_2_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ namespace SDK {
hook::this_call(gPatterns.C_GameGUI2Module__SendMessageMovie, this, title, msg, varArgs, unk2);
}

ue::C_WeakPtr<ue::sys::sodb::C_DatabaseInterface> C_GameGUI2Module::GetDatabase() {
ue::C_WeakPtr<ue::sys::sodb::C_DatabaseInterface> database;
return hook::this_call<ue::C_WeakPtr<ue::sys::sodb::C_DatabaseInterface> &>(gPatterns.C_GameGUI2Module__GetDatabase, this, database);
}

C_GameGUI2Module *C_GameGUI2Module::GetInstance() {
return *reinterpret_cast<C_GameGUI2Module **>(gPatterns.C_GameGUI2Module__Instance);
}
Expand Down
4 changes: 4 additions & 0 deletions code/client/src/sdk/mafia/ui/c_game_gui_2_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "support/c_fader.h"

#include "../../ue/c_variant.h"
#include "sdk/ue/sys/sodb/c_database_interface.h"
#include "sdk/ue/c_weak_ptr.h"

#include <cstdint>

Expand Down Expand Up @@ -40,6 +42,8 @@ namespace SDK {
return *reinterpret_cast<mafia::ui::menu::C_MainMenu **>((uint64_t)this + 0x0C0);
}

ue::C_WeakPtr<ue::sys::sodb::C_DatabaseInterface> GetDatabase();

static C_GameGUI2Module *GetInstance();
};

Expand Down
35 changes: 35 additions & 0 deletions code/client/src/sdk/mafia/ui/hud/c_hud_controller.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
#pragma once

#include <utils/hooking/hooking.h>

namespace SDK {
namespace mafia::ui::hud {

class C_RaceTimer {
public:

// NB: Do not use in MP!
// This starts C_RaceManager!
// Use mafia::ui::hud::RaceXBin instead!
void SetVisible(const bool visible) {
hook::this_call(0x14304F520, this, visible);
}

// NB: Do not use in MP!
// This starts C_RaceManager!
// Use mafia::ui::hud::RaceXBin instead!
void StartRace(const uint32_t NumCheckpoints, const float TargetTime, const uint32_t NumLaps) {
hook::this_call(0x14305BF80, this, NumCheckpoints, TargetTime, NumLaps);
}

private:
void *m_Vtable = nullptr;
void *m_Unk0 = nullptr;
float m_Timer = 0.0f;
uint32_t m_CurrentCheckpoint = 0;
uint32_t m_CurrentLap = 0;
};

class C_HudController {
public:
C_RaceTimer *GetRacingTimer() {
return m_RaceTimer;
}

private:
char pad0[0x5A8]; // 0000 - 0x5A8
C_RaceTimer *m_RaceTimer = nullptr;
};
} // namespace mafia::ui::hud
} // namespace SDK
88 changes: 88 additions & 0 deletions code/client/src/sdk/mafia/ui/hud/race_xbin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include "race_xbin.h"

#include "sdk/mafia/database/c_ui_database.h"
#include "sdk/mafia/ui/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() {
using namespace SDK::mafia::ui;
using namespace SDK::mafia::database;
using namespace SDK::ue::sys::sodb;

// Fetch database
C_GameGUI2Module *GameGuiModule = GetGameGui2Module();
SDK::ue::C_WeakPtr<C_DatabaseInterface> result = GameGuiModule->GetDatabase();

// need to cast to C_UIDatabase
// TODO: Feels like this should be dynamic_cast, rather than reinterpret_cast
Comment on lines +15 to +16
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we handle that comment now? not a big deal

Copy link
Collaborator Author

@Greavesy1899 Greavesy1899 Mar 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Causes a crash using dynamic_cast, unsure why. I'll debug though.

if (C_UIDatabase *database = reinterpret_cast<C_UIDatabase *>(result.Get())) {
return database->GetHUDTable();
}

return nullptr;
}
}

namespace SDK {
namespace mafia::ui::hud {

// only has an effect in cpp
using namespace SDK::mafia::database;

void RaceXBin::SetVisible(const bool bVisiblity) {
if (C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) {
hudTable->m_RacingVisible = bVisiblity;
}
}

void RaceXBin::SetTargetTime(const float InTargetTime) {
if (C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) {
hudTable->m_TargetTime = InTargetTime;
}
}

void RaceXBin::SetPosition(const uint16_t InPosition) {
if (C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) {
hudTable->m_CurPosition = InPosition;
}
}

void RaceXBin::SetPositionTotal(const uint16_t InTotalPosition) {
if (C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) {
hudTable->m_TotalPositions = InTotalPosition;
}
}

void RaceXBin::SetLaps(const uint16_t InLaps) {
if (C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) {
hudTable->m_CurLap = InLaps;
}
}

void RaceXBin::SetLapsTotal(const uint16_t InTotalLaps) {
if (C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) {
hudTable->m_TotalLaps = InTotalLaps;
}
}

void RaceXBin::SetCheckpoints(const uint16_t InCheckpoint) {
if (C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) {
hudTable->m_CurCheckpoint = InCheckpoint;
}
}

void RaceXBin::SetCheckpointsTotal(const uint16_t InTotalCheckpoints) {
if (C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) {
hudTable->m_TotalCheckpoints = InTotalCheckpoints;
}
}

void RaceXBin::SetCountdown(const uint8_t InCountdown) {
if (C_UIDatabase::C_HUDTable *hudTable = RaceXBinUtils::GetHUDTable()) {
hudTable->m_Countdown = InCountdown;
}
}
} // namespace mafia::ui::hud
} // namespace SDK
77 changes: 77 additions & 0 deletions code/client/src/sdk/mafia/ui/hud/race_xbin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#pragma once

#include <stdint.h>

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 bVisiblity);

/**
* 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 InTargetTime);

/**
* 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 InPosition);

/**
* Set the max amount of Positions on the Racing HUD Element
* @param InTotalPosition - Max number of positions
*/
static void SetPositionTotal(const uint16_t InTotalPosition);

/**
* 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 InLaps);

/**
* Set the number of Laps on the Racing HUD Element
* @param InTotalPosition - Number of Laps
*/
static void SetLapsTotal(const uint16_t InTotalLaps);

/**
* 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 InCheckpoint);

/**
* Set the max amount of Checkpoints on the Racing HUD Element
* @param InTotalPosition - Max number of checkpoints
*/
static void SetCheckpointsTotal(const uint16_t InTotalCheckpoints);

/**
* 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 InCountdown);
};
} // namespace mafia::ui::hud
} // namespace SDK
1 change: 1 addition & 0 deletions code/client/src/sdk/patterns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t *>(C_GameGUI2Module);

gPatterns.C_GameGUI2Module__GetDatabase = reinterpret_cast<uint64_t>(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<uint64_t>("E8 ? ? ? ? 40 80 F6 01");
gPatterns.C_GameGUI2Module__Instance = reinterpret_cast<uint64_t>(C_GameGUI2Module_Bytes + *(int32_t *)(C_GameGUI2Module_Bytes + 3) + 7);
gPatterns.C_GameGUI2Module__SendHUDSimpleBooleanMessage = hook::get_opcode_address<uint64_t>("E8 ? ? ? ? 49 8B 97 ? ? ? ? 4C 8D 05 ? ? ? ?");
Expand Down
Loading
Loading