Skip to content

Commit

Permalink
Context Menu (WIP) and some other stuff (#53)
Browse files Browse the repository at this point in the history
* Working but incomplete

* adhoc: Added missing commands

* Separated contextmenu tick

* Removed duplicate loop

* Small changes

* Removed unused enum

* Fixed exception handler not working
  • Loading branch information
DayibBaba authored Oct 24, 2023
1 parent 20503dd commit f1a8992
Show file tree
Hide file tree
Showing 15 changed files with 473 additions and 28 deletions.
3 changes: 2 additions & 1 deletion src/core/logger/ExceptionHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ namespace YimMenu

ExceptionHandler::ExceptionHandler()
{
LOG(INFO) << "ExceptionHandler initialized";
m_OldErrorMode = SetErrorMode(0);
m_Handler = SetUnhandledExceptionFilter(&VectoredExceptionHandler);
m_Handler = AddVectoredExceptionHandler(0, &VectoredExceptionHandler);
}

ExceptionHandler::~ExceptionHandler()
Expand Down
168 changes: 168 additions & 0 deletions src/game/bigfeatures/ContextMenu.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#include "ContextMenu.hpp"

#include "ContextMenus.hpp"
#include "core/frontend/Notifications.hpp"
#include "game/backend/Players.hpp"
#include "game/backend/ScriptMgr.hpp"
#include "game/pointers/Pointers.hpp"
#include "game/rdr/Enums.hpp"
#include "game/backend/FiberPool.hpp"

namespace YimMenu
{
void ContextMenu::SetEntityImpl(int handle, void* pointer)
{
m_EntityHandle = handle;
m_EntityPointer = pointer;
}

double ContextMenu::CumulativeDistanceToMiddleOfScreenImpl(rage::fvector2 screenPos)
{
double cumDist{};

if (screenPos.x > 0.5)
cumDist += screenPos.x - 0.5;
else
cumDist += 0.5 - screenPos.x;

if (screenPos.y > 0.5)
cumDist += screenPos.y - 0.5;
else
cumDist += 0.5 - screenPos.y;

return cumDist;
}

int ContextMenu::GetEntityHandleClosestToMiddleOfScreenImpl(bool includePlayers, bool includePeds = false, bool includeVehicles = false, bool includeObjects = false)
{
int closestHandle{};
float distance = 1;

auto updateClosestEntity = [&](int handle) -> void {
auto worldCoords = ENTITY::GET_ENTITY_COORDS(handle, false, true);
rage::fvector2 screenPos{};
float worldCoords_[3] = {worldCoords.x, worldCoords.y, worldCoords.z};
Pointers.WorldToScreen(worldCoords_, &screenPos.x, &screenPos.y);
if (CumulativeDistanceToMiddleOfScreen(screenPos) < distance && handle != Self::PlayerPed)
{
closestHandle = handle;
distance = CumulativeDistanceToMiddleOfScreen(screenPos);
}
};

if (includePlayers)
{
for (auto [id, plyr] : YimMenu::Players::GetPlayers())
{
if (plyr.IsValid() || plyr.GetPed().GetPointer<void*>())
updateClosestEntity(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(id));
}
}

return closestHandle;
}

void ContextMenu::HandleEntityAndMenuImpl()
{
if (m_Enabled && g_ContextMenu)
{
auto handle = GetEntityHandleClosestToMiddleOfScreenImpl(true);

static auto switchToMenu = [&](ContextOperationsMenu menu) -> void {
if (m_CurrentOperationsMenu != menu)
{
m_CurrentOperationsMenu = menu;
}
};

if (handle && ENTITY::DOES_ENTITY_EXIST(handle))
{
m_EntityHandle = handle;

if (ENTITY::IS_ENTITY_A_PED(m_EntityHandle))
{
if (PED::IS_PED_A_PLAYER(m_EntityHandle))
switchToMenu(ContextMenuPlayers);
else
switchToMenu(ContextMenuDefault); //TODO Create Ped menu
}
else if (ENTITY::IS_ENTITY_A_VEHICLE(m_EntityHandle))
{
switchToMenu(ContextMenuDefault); //TODO Create Vehicle menu
}
else if (ENTITY::IS_ENTITY_AN_OBJECT(m_EntityHandle))
{
switchToMenu(ContextMenuDefault); //TODO Create Object menu
}

if (m_CurrentOperationsMenu.m_SelectedOperation.m_Name.empty())
m_CurrentOperationsMenu.m_SelectedOperation = m_CurrentOperationsMenu.m_Operations.front();

auto entPos = ENTITY::GET_ENTITY_COORDS(handle, false, true);
float worldCoords_[3] = {entPos.x, entPos.y, entPos.z};
Pointers.WorldToScreen(worldCoords_, &m_ScreenPos.x, &m_ScreenPos.y);
m_ScreenPos.x *= Pointers.ScreenResX;
m_ScreenPos.y *= Pointers.ScreenResY;

PAD::DISABLE_CONTROL_ACTION(0, (int)eNativeInputs::INPUT_NEXT_WEAPON, true);
PAD::DISABLE_CONTROL_ACTION(0, (int)eNativeInputs::INPUT_PREV_WEAPON, true);
PAD::DISABLE_CONTROL_ACTION(0, (int)eNativeInputs::INPUT_ATTACK, true);

if (PAD::IS_DISABLED_CONTROL_JUST_PRESSED(0, (int)eNativeInputs::INPUT_PREV_WEAPON))
m_CurrentOperationsMenu.SelectPrevious();

if (PAD::IS_DISABLED_CONTROL_JUST_PRESSED(0, (int)eNativeInputs::INPUT_NEXT_WEAPON))
m_CurrentOperationsMenu.SelectNext();

if (PAD::IS_DISABLED_CONTROL_JUST_PRESSED(0, (int)eNativeInputs::INPUT_ATTACK))
FiberPool::Push([=] {
m_CurrentOperationsMenu.m_SelectedOperation.m_Operation();
});

m_MenuIsInitialized = true;
}
else
{
m_EntityHandle = 0;
m_MenuIsInitialized = false;
}
}
}

void DrawOperation(ContextMenuOperation operation, bool selected, int position, ImDrawList* drawList)
{
auto screenPos = ContextMenu::GetScreenPos();

//Make compatible with ESP
if (g_Esp)
screenPos.y += 20;

if (position > 0)
screenPos.y += (m_OperationCardY * position) + 2 /*Margin between operation cards*/;

auto cardColor = selected ? ImGui::ColorConvertFloat4ToU32(ImVec4(1, 0, 0, 0.5)) : ImGui::ColorConvertFloat4ToU32(ImVec4(1, 0, 0, 0.2));

ImVec2 endPos = ImVec2(screenPos.x + m_OperationCardX, screenPos.y + m_OperationCardY);
drawList->AddRectFilled(ImVec2(screenPos.x, screenPos.y), endPos, cardColor, 3.f);

drawList->AddText(ImVec2(screenPos.x, screenPos.y),
ImGui::ColorConvertFloat4ToU32(ImVec4(1, 1, 1, 1)),
operation.m_Name.data());
}

void ContextMenu::DrawContextMenuImpl()
{
if (m_MenuIsInitialized && m_Enabled && g_ContextMenu)
{
if (const auto drawList = ImGui::GetBackgroundDrawList())
{
int position = 0;
for (auto& operation : m_CurrentOperationsMenu.m_Operations)
{
DrawOperation(operation, operation == m_CurrentOperationsMenu.m_SelectedOperation, position, drawList);
position++;
}
}
}
}
}
151 changes: 151 additions & 0 deletions src/game/bigfeatures/ContextMenu.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#pragma once
#include "game/rdr/Natives.hpp"

namespace YimMenu
{
static inline float m_OperationCardX = 125.0f;
static inline float m_OperationCardY = 15.0f;

struct ContextMenuOperation
{
std::string m_Name;
std::function<void()> m_Operation;

bool operator==(const ContextMenuOperation& other) const
{
return m_Name == other.m_Name;
};
};

struct ContextOperationsMenu
{
std::vector<ContextMenuOperation> m_Operations;
std::string m_Name;
ContextMenuOperation m_SelectedOperation;

ContextOperationsMenu() = default;
ContextOperationsMenu(std::string name, std::vector<ContextMenuOperation> operations) :
m_Name(name),
m_Operations(operations)
{
m_SelectedOperation = m_Operations.front();
}

bool operator==(const ContextOperationsMenu& other) const
{
return m_Name == other.m_Name;
};

void SelectNext()
{
auto it = std::find(m_Operations.begin(), m_Operations.end(), m_SelectedOperation);
if (it != m_Operations.end())
{
it++;
if (it == m_Operations.end())
{
it = m_Operations.begin();
}
m_SelectedOperation = *it;
}
}

void SelectPrevious()
{
auto it = std::find(m_Operations.begin(), m_Operations.end(), m_SelectedOperation);
if (it != m_Operations.end())
{
if (it == m_Operations.begin())
{
it = m_Operations.end();
}
it--;
m_SelectedOperation = *it;
}
}
};

class ContextMenu
{
private:
static ContextMenu& GetInstance()
{
static ContextMenu instance{};
return instance;
}

bool m_Enabled = false;
int m_EntityHandle{};
void* m_EntityPointer{};
ContextOperationsMenu m_CurrentOperationsMenu{};
bool m_MenuIsInitialized = false;
rage::fvector2 m_ScreenPos{};

double CumulativeDistanceToMiddleOfScreenImpl(rage::fvector2 screenPos);
int GetEntityHandleClosestToMiddleOfScreenImpl(bool includePlayers, bool includePeds, bool includeVehicles, bool includeObjects);
void SetEntityImpl(int handle, void* pointer);
void HandleEntityAndMenuImpl();
void DrawContextMenuImpl();

public:
static void Enable()
{
GetInstance().m_Enabled = true;
}

static void Disable()
{
GetInstance().m_Enabled = false;
}

static bool* GetEnabled()
{
return &GetInstance().m_Enabled;
}

static double CumulativeDistanceToMiddleOfScreen(rage::fvector2 screenPos)
{
return GetInstance().CumulativeDistanceToMiddleOfScreenImpl(screenPos);
}

static int GetEntityHandleClosestToMiddleOfScreen(bool includePlayers, bool includePeds = false, bool includeVehicles = false, bool includeObjects = false)
{
return GetInstance().GetEntityHandleClosestToMiddleOfScreenImpl(includePlayers, includePeds, includeVehicles, includeObjects);
}

static void HandleEntityAndMenu()
{
GetInstance().HandleEntityAndMenuImpl();
}

static void DrawContextMenu()
{
GetInstance().DrawContextMenuImpl();
}

static void SetEntity(int handle, void* pointer)
{
GetInstance().SetEntityImpl(handle, pointer);
}

static int GetEntityHandle()
{
return GetInstance().m_EntityHandle;
}

static void* GetEntityPointer()
{
return GetInstance().m_EntityPointer;
}

static bool IsMenuIinitialized()
{
return GetInstance().m_MenuIsInitialized;
}

static rage::fvector2 GetScreenPos()
{
return GetInstance().m_ScreenPos;
}
};
}
30 changes: 30 additions & 0 deletions src/game/bigfeatures/ContextMenus.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once
#include "ContextMenu.hpp"
#include "game/features/Features.hpp"
#include "game/rdr/Natives.hpp"
#include "util/teleport.hpp"

namespace YimMenu
{
inline ContextOperationsMenu ContextMenuDefault = ContextOperationsMenu("Default",
{
ContextMenuOperation{"Error",
[&] {

}}
});

inline ContextOperationsMenu ContextMenuPlayers = ContextOperationsMenu("Players",
{
ContextMenuOperation
{"Teleport to player", [&] {
auto playerPos = ENTITY::GET_ENTITY_COORDS(ContextMenu::GetEntityHandle(), false, true);
Teleport::TeleportEntity(Self::PlayerPed, playerPos);
}},
{"Explode", [&] {
auto playerPos = ENTITY::GET_ENTITY_COORDS(ContextMenu::GetEntityHandle(), false, true);
FIRE::ADD_EXPLOSION(playerPos.x, playerPos.y, playerPos.z, 22, 1.0f, true, false, 1.0f);
}},

});
}
Loading

0 comments on commit f1a8992

Please sign in to comment.