generated from YimMenu/YimMenuV2
-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Context Menu (WIP) and some other stuff (#53)
* 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
Showing
15 changed files
with
473 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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++; | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}}, | ||
|
||
}); | ||
} |
Oops, something went wrong.