Skip to content

Commit

Permalink
Feature Wrappers and Hotkey System (#20)
Browse files Browse the repository at this point in the history
* UI control block and some small features

* Fixed scripts unload

* FeatureCommand & HotkeySystem

* Remove useless header file

* Formatting

* Added  non-looped command

* Changed commands location

* Added description field

* test commit to test permissions

* Added descriptions to existing commands

* feat(commands): improve commands

* Reintegrated hotkey system

* Changed CommandLink to host the hotkey vector

* Added UI cue on hover for hotkeys

* Added check for hotkey changing

Commands should not execute with their respective hotkeys if the said hotkey is in process of being modified.

---------

Co-authored-by: maybegreat48 <email@hostname>
  • Loading branch information
DayibBaba and maybegreat48 authored Sep 1, 2023
1 parent 9595931 commit 614faed
Show file tree
Hide file tree
Showing 20 changed files with 1,673 additions and 10 deletions.
29 changes: 29 additions & 0 deletions src/core/commands/BoolCommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include "BoolCommand.hpp"

namespace YimMenu
{
BoolCommand::BoolCommand(std::string name, std::string label, std::string description) :
Command(name, label, description, 0)
{
}

void BoolCommand::OnCall()
{
SetState(!m_State);
}

bool BoolCommand::GetState()
{
return m_State;
}

void BoolCommand::SetState(bool state)
{
if (state && !m_State)
OnEnable();
else if (!state && m_State)
OnDisable();

m_State = state;
}
}
20 changes: 20 additions & 0 deletions src/core/commands/BoolCommand.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once
#include "Command.hpp"

namespace YimMenu
{
class BoolCommand : public Command
{
protected:
virtual void OnEnable(){};
virtual void OnDisable(){};
virtual void OnCall() override;

bool m_State = false;

public:
BoolCommand(std::string name, std::string label, std::string description);
bool GetState();
void SetState(bool state);
};
}
21 changes: 21 additions & 0 deletions src/core/commands/Command.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "util/Joaat.hpp"
#include "Command.hpp"
#include "Commands.hpp"

namespace YimMenu
{
Command::Command(std::string name, std::string label, std::string description, int num_args) :
m_Name(name),
m_Label(label),
m_Description(description),
m_NumArgs(num_args),
m_Hash(Joaat(name))
{
Commands::AddCommand(this);
}

void Command::Call()
{
OnCall();
}
}
45 changes: 45 additions & 0 deletions src/core/commands/Command.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once
#include "util/Joaat.hpp"
#include <nlohmann/json.hpp>

namespace YimMenu
{
class Command
{
private:
std::string m_Name;
std::string m_Label;
std::string m_Description;
joaat_t m_Hash;

int m_NumArgs = 0; // TODO: currently unused

protected:
virtual void OnCall() = 0;


public:
Command(std::string name, std::string label, std::string description, int num_args = 0);
void Call();

const std::string& GetName()
{
return m_Name;
}

const std::string& GetLabel()
{
return m_Label;
}

const std::string& GetDescription()
{
return m_Description;
}

joaat_t GetHash()
{
return m_Hash;
}
};
}
30 changes: 30 additions & 0 deletions src/core/commands/Commands.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "Commands.hpp"
#include "Command.hpp"
#include "LoopedCommand.hpp"

namespace YimMenu
{
void Commands::AddCommandImpl(Command* command)
{
m_Commands.insert({command->GetHash(), command});
}

void Commands::AddLoopedCommandImpl(LoopedCommand* command)
{
m_LoopedCommands.push_back(command);
}

void Commands::RunLoopedCommandsImpl()
{
for (auto& command : m_LoopedCommands)
if (command->GetState())
command->Tick();
}

Command* Commands::GetCommandImpl(joaat_t hash)
{
if (auto it = m_Commands.find(hash); it != m_Commands.end())
return it->second;
return nullptr;
}
}
61 changes: 61 additions & 0 deletions src/core/commands/Commands.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#pragma once
#include "util/Joaat.hpp"

namespace YimMenu
{
class Command;
class LoopedCommand;

class Commands
{
private:
std::unordered_map<joaat_t, Command*> m_Commands;
std::vector<LoopedCommand*> m_LoopedCommands;
Commands(){};

public:
static void AddCommand(Command* command)
{
GetInstance().AddCommandImpl(command);
}

static void AddLoopedCommand(LoopedCommand* command)
{
GetInstance().AddLoopedCommandImpl(command);

}

static void RunLoopedCommands()
{
GetInstance().RunLoopedCommandsImpl();
}

template<typename T = Command>
static T* GetCommand(joaat_t hash)
{
return reinterpret_cast<T*>(GetInstance().GetCommandImpl(hash));
}

static std::unordered_map<joaat_t, Command*> GetCommands()
{
return GetInstance().m_Commands;
};

static std::vector<LoopedCommand*> GetLoopedCommands()
{
return GetInstance().m_LoopedCommands;
}

private:
void AddCommandImpl(Command* command);
void AddLoopedCommandImpl(LoopedCommand* command);
void RunLoopedCommandsImpl();
Command* GetCommandImpl(joaat_t hash);

static Commands& GetInstance()
{
static Commands instance{};
return instance;
}
};
}
135 changes: 135 additions & 0 deletions src/core/commands/HotkeySystem.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include "HotkeySystem.hpp"

#include "game/rdr/Natives.hpp"
#include "game/backend/ScriptMgr.hpp"
#include "Commands.hpp"
#include "LoopedCommand.hpp"

// TODO: hotkeys


namespace YimMenu
{

void HotkeySystem::RegisterCommands()
{
auto commands = Commands::GetCommands();
auto looped_commands = Commands::GetLoopedCommands();

for (auto [hash, command] : commands)
{
CommandLink link(false);
m_CommandHotkeys.insert(std::make_pair(command->GetHash(), link));
}

for (auto looped_command : looped_commands)
{
CommandLink link(true);
m_CommandHotkeys.insert(std::make_pair(looped_command->GetHash(), link));
}

LOG(INFO) << "Registered " << m_CommandHotkeys.size() << " commands";
}

bool HotkeySystem::ListenAndApply(int& Hotkey, std::vector<int> blacklist)
{
static auto is_key_blacklisted = [blacklist](int key) -> bool {
for (auto key_ : blacklist)
if (key_ == key)
return true;

return false;
};

//VK_OEM_CLEAR Is about the limit in terms of virtual key codes
for (int i = 0; i < VK_OEM_CLEAR; i++)
{
if ((GetKeyState(i) & 0x8000) && i != 1 && !is_key_blacklisted(i))
{
Hotkey = i;

return true;
}
}

return false;
}
//Will return the keycode if there are no labels
std::string HotkeySystem::GetHotkeyLabel(int hotkey_modifier)
{
char key_name[32];
GetKeyNameTextA(MapVirtualKey(hotkey_modifier, MAPVK_VK_TO_VSC) << 16, key_name, 32);

if (std::string(key_name).empty())
strcpy(key_name, std::to_string(hotkey_modifier).data());

return key_name;
}

//Meant to be called in a loop
void HotkeySystem::CreateHotkey(std::vector<int>& Hotkey)
{
static auto is_key_unique = [this](int key, std::vector<int> list) -> bool {
for (auto& key_ : list)
if (GetHotkeyLabel(key_) == GetHotkeyLabel(key))
return false;

return true;
};

int pressed_key = 0;
ListenAndApply(pressed_key, Hotkey);


if (pressed_key > 1)
{
if (is_key_unique(pressed_key, Hotkey))
{
Hotkey.push_back(pressed_key);
}
}
}

void HotkeySystem::FeatureCommandsHotkeyLoop()
{
for (auto& [hash, link] : m_CommandHotkeys)
{
if (link.Hotkey.empty() || link.Listening)
continue;

bool allkeyspressed = true;

for (auto hotkey_modifier : link.Hotkey)
{
if (!(GetAsyncKeyState(hotkey_modifier) & 0x8000))
{
allkeyspressed = false;
}
}

if (allkeyspressed)
{
if (link.Looped)
{
auto looped_command = Commands::GetCommand<LoopedCommand>(hash);

if (looped_command)
looped_command->SetState(!looped_command->GetState());

LOG(INFO) << "Hotkey detected for looped command " << looped_command->GetName();
}
else
{
auto command = Commands::GetCommand(hash);
if (command)
{
command->Call();
LOG(INFO) << "Hotkey detected for command " << command->GetName();
}
}

ScriptMgr::Yield(100ms);
}
}
}
}
33 changes: 33 additions & 0 deletions src/core/commands/HotkeySystem.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#pragma once
#include "../../common.hpp"

namespace YimMenu
{
struct CommandLink
{
public:
bool Looped;
std::vector<int> Hotkey{};

CommandLink(bool looped) :
Looped(looped)
{
}

bool Listening;
};

class HotkeySystem
{
public:
std::map<uint32_t, CommandLink> m_CommandHotkeys;
void RegisterCommands();
bool ListenAndApply(int& Hotkey, std::vector<int> blacklist = {0});
std::string GetHotkeyLabel(int hotkey_modifiers);
void CreateHotkey(std::vector<int>& Hotkey);

void FeatureCommandsHotkeyLoop();
};

inline HotkeySystem g_HotkeySystem;
}
Loading

0 comments on commit 614faed

Please sign in to comment.