#pragma once #include "core/memory/Pattern.hpp" #include "core/util/Joaat.hpp" namespace rage { class scrProgram; } namespace YimMenu { class ScriptPatches { public: class Data { std::uint8_t** m_Data; std::uint32_t m_Pages; std::uint32_t m_Size; public: inline std::uint8_t** GetData() const { return m_Data; } inline std::uint32_t GetSize() const { return m_Size; } Data(rage::scrProgram* program); ~Data(); }; class Patch { std::vector m_OriginalBytes; std::vector m_PatchedBytes; std::optional m_Pc; SimplePattern m_Pattern; int32_t m_Offset; bool m_Enabled; std::uint32_t m_Hash; std::optional GetPC(); void Apply(); void Restore(); public: Patch(joaat_t script, SimplePattern pattern, int32_t offset, std::vector patch); void Enable(); void Disable(); void Update(); bool InScope(std::uint32_t hash); }; static std::shared_ptr AddPatch(joaat_t script, const std::string& pattern, int32_t offset, std::vector patch) { return GetInstance().AddPatchImpl(script, pattern, offset, patch); } static void RegisterProgram(rage::scrProgram* program) { GetInstance().RegisterProgramImpl(program); } static void UnregisterProgram(rage::scrProgram* program) { GetInstance().UnregisterProgramImpl(program); } static void OnScriptVMEnter(rage::scrProgram* program) { GetInstance().OnScriptVMEnterImpl(program); } static void OnScriptVMLeave(rage::scrProgram* program) { GetInstance().OnScriptVMLeaveImpl(program); } private: ScriptPatches(); ~ScriptPatches(); static ScriptPatches& GetInstance() { static ScriptPatches Instance; return Instance; } std::shared_ptr AddPatchImpl(joaat_t script, const std::string& pattern, int32_t offset, std::vector patch); void RegisterProgramImpl(rage::scrProgram* program); void UnregisterProgramImpl(rage::scrProgram* program); void OnScriptVMEnterImpl(rage::scrProgram* program); void OnScriptVMLeaveImpl(rage::scrProgram* program); Data* GetDataImpl(joaat_t script); std::vector> m_Patches; std::unordered_map> m_Datas; std::uint8_t** m_CurrentlyReplacedBytecode; }; using ScriptPatch = std::shared_ptr; }