diff --git a/CMakeLists.txt b/CMakeLists.txt index e5b30a0..bdcfaa0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,6 @@ file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS lib/Patterns/*.cpp) add_library(${PROJECT_NAME} SHARED ${SOURCES} ) -add_library(Mirrored SHARED lib/Patterns/Patterns.cpp lib/ParserUtils.cc src/misc/mirrored.cc) if (ENABLE_DEBUG_MENU) include(cmake/DebugImgui.cmake) @@ -42,7 +41,4 @@ endif() set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".asi") target_link_libraries(${PROJECT_NAME} PUBLIC dbghelp minhook) -target_link_libraries(Mirrored PUBLIC minhook) -target_compile_definitions(Mirrored PUBLIC NOMINMAX) - target_compile_definitions(${PROJECT_NAME} PUBLIC NOMINMAX) diff --git a/lib/CCredits.cc b/lib/CCredits.cc index 8e17fd9..5546557 100644 --- a/lib/CCredits.cc +++ b/lib/CCredits.cc @@ -5,5 +5,5 @@ void CCreditArray::InitialisePatterns () { sm_Instance = GetRelativeReference ( - "? 8b 05 ? ? ? ? 83 3c 03 0e e9 ? ? ? ? 66", 3, 7); + "? 89 ? ? ? ? ? 89 ? ? ? ? ? 74 ? ? 8d ? ? ? ? ? e8 ? ? ? ? 8b ? ? ? ? ? 83", 3, 7); } diff --git a/lib/CCredits.hh b/lib/CCredits.hh index 9573ddf..f77d121 100644 --- a/lib/CCredits.hh +++ b/lib/CCredits.hh @@ -1,6 +1,7 @@ #pragma once #include "rage.hh" +#include "ParserUtils.hh" #include enum class eCreditLineType : uint32_t @@ -22,26 +23,18 @@ enum class eCreditLineType : uint32_t JOB_AND_NAME_MED }; -struct CCreditItem +struct CCreditItem : public ParserWrapper { - eCreditLineType LineType; - uint8_t _pad0x8[4]; - atString cTextId1; - uint8_t _pad0x14[4]; - atString cTextId2; - uint8_t _pad0x24[4]; - - CCreditItem () = default; - - CCreditItem (eCreditLineType lineType, atString textId1 = "", - atString textId2 = "") - : LineType (lineType), cTextId1 (textId1), cTextId2 (textId2){}; }; -class CCreditArray +class CCreditArray : public ParserWrapper { public: - atArray CreditItems; + auto& + GetCreditItems () + { + return Get> ("CreditItems"_joaat); + } inline static CCreditArray *sm_Instance = nullptr; diff --git a/lib/CItemInfo.hh b/lib/CItemInfo.hh index b91da22..7934d31 100644 --- a/lib/CItemInfo.hh +++ b/lib/CItemInfo.hh @@ -3,6 +3,8 @@ #include #include "ParserUtils.hh" +#include + class CItemInfo { public: @@ -12,14 +14,12 @@ public: uint32_t Audio; uint32_t Slot; +private: virtual void Destructor (); virtual bool GetIsClassId (uint32_t hash); // virtual uint32_t* GetClassId (); (older versions) - virtual uint32_t &GetClassId (uint32_t &out); - - // Do not use the following virtual functions for compatibility reasons. - //******************************************************* + virtual uint32_t *_GetClassId (uint32_t *out); // Not present in older versions of GTA V virtual uint32_t *_GetBaseClassId (uint32_t &out); @@ -29,7 +29,19 @@ public: virtual parStructure *_parser_GetStructure (); +public: //******************************************************* + uint32_t + GetClassId () + { + uint32_t tmp; + + // Later versions return hash directly + if (Rainbomizer::Logger::GetGameBuild () >= 2802) + return static_cast (uintptr_t (_GetClassId (nullptr))); + else + return *_GetClassId(&tmp); + } }; class CAmmoInfo : public ParserWrapper, public CItemInfo diff --git a/lib/ParserUtils.hh b/lib/ParserUtils.hh index b3687a3..c4c3089 100644 --- a/lib/ParserUtils.hh +++ b/lib/ParserUtils.hh @@ -214,6 +214,18 @@ protected: public: using Type = Class; + ParserWrapper () = default; + ParserWrapper (const ParserWrapper &other) + { + memcpy (this, &other, GetSize ()); + } + + void + operator= (const ParserWrapper &other) + { + memcpy (this, &other, GetSize ()); + } + inline static constexpr uint32_t GetHash () { @@ -286,4 +298,10 @@ public: { return GetStaticData ()->Structure->nSize; } + + void + CopyTo (uint8_t *out) + { + memcpy (out, this, GetSize ()); + } }; diff --git a/lib/Patterns/Patterns.cpp b/lib/Patterns/Patterns.cpp index bb14874..948a6cf 100644 --- a/lib/Patterns/Patterns.cpp +++ b/lib/Patterns/Patterns.cpp @@ -143,32 +143,37 @@ void pattern::Initialize(std::string_view pattern) m_hash = fnv_1()(pattern); #endif - // transform the base pattern from IDA format to canonical format - TransformPattern(pattern, m_bytes, m_mask); + static FILE* file = fopen("patterns.txt", "w"); + fprintf (file, "%s\n", pattern.data ()); + fflush (file); + + // transform the base pattern from IDA format to canonical format + TransformPattern (pattern, m_bytes, m_mask); #if PATTERNS_USE_HINTS - // if there's hints, try those first + // if there's hints, try those first #if PATTERNS_CAN_SERIALIZE_HINTS - if (m_rangeStart == reinterpret_cast(GetModuleHandle(nullptr))) + if (m_rangeStart + == reinterpret_cast (GetModuleHandle (nullptr))) #endif - { - auto range = getHints().equal_range(m_hash); + { + auto range = getHints ().equal_range (m_hash); - if (range.first != range.second) - { - std::for_each(range.first, range.second, [&] (const auto& hint) - { - ConsiderHint(hint.second); - }); + if (range.first != range.second) + { + std::for_each (range.first, range.second, + [&] (const auto &hint) { + ConsiderHint (hint.second); + }); - // if the hints succeeded, we don't need to do anything more + // if the hints succeeded, we don't need to do anything more if (!m_matches.empty()) { m_matched = true; return; } - } - } + } + } #endif } diff --git a/lib/Patterns/Patterns.hh b/lib/Patterns/Patterns.hh index 531936e..af0dd75 100644 --- a/lib/Patterns/Patterns.hh +++ b/lib/Patterns/Patterns.hh @@ -101,6 +101,17 @@ namespace hook } public: + + auto& getMask () + { + return m_mask; + } + + auto& getBytes () + { + return m_bytes; + } + pattern(std::string_view pattern) : hook::pattern(getRVA(0)) { diff --git a/lib/Utils.hh b/lib/Utils.hh index 292f638..8ae3bf3 100644 --- a/lib/Utils.hh +++ b/lib/Utils.hh @@ -173,6 +173,22 @@ RegisterHook (const std::string &pattern, int offset, F hookedFunc) RegisterHook (addr, hookedFunc); } +/*******************************************************/ +template +void +RegisterHookOperand (const std::string &pattern, int offset, F hookedFunc, O& originalFunc) +{ + hook::pattern p (pattern); + auto result = p.get_one (); + + injector::WriteMemory (originalFunc, result.get (offset + 4) + + *result.get (offset)); + + *result.get (offset) + = Trampoline::MakeTrampoline (GetModuleHandle (nullptr)) + ->Jump (hookedFunc) - result.get(offset + 4); +} + /*******************************************************/ void RegisterJmpHook (void *addr, void *dst, void **outOrignal, int size); @@ -254,6 +270,12 @@ GetRelativeReference (const std::string &pattern, int dataOffset) RegisterHook (pattern, offset, F, function); \ } +#define REGISTER_HOOK_OPERAND(pattern, offset, function, ret, ...) \ + { \ + static ret (*F) (__VA_ARGS__); \ + RegisterHookOperand (pattern, offset, F, function); \ + } + /*******************************************************/ #define REGISTER_HOOK_JMP(pattern, offset, function, ret, ...) \ { \ diff --git a/lib/atArray.hh b/lib/atArray.hh index a49e2ca..a39295c 100644 --- a/lib/atArray.hh +++ b/lib/atArray.hh @@ -97,6 +97,15 @@ struct atArrayGetSizeWrapper uint16_t Size; uint16_t Capacity; + atArrayGetSizeWrapper () = default; + + atArrayGetSizeWrapper (uint8_t *data, uint16_t size) + { + this->Data = *reinterpret_castData) *> (&data); + this->Size = size; + this->Capacity = size; + } + constexpr Iterator end () { diff --git a/lib/audEngine.cc b/lib/audEngine.cc index ca3f724..9c28756 100644 --- a/lib/audEngine.cc +++ b/lib/audEngine.cc @@ -32,7 +32,7 @@ audEngine::InitialisePatterns () "? 8d 2d ? ? ? ? ? 8b f0 85 d2 74 ? ", 3, 7); ConvertCall (hook::get_pattern ( - "8d 42 01 ? 8b c9 a9 fe ff ff ff 75 ? 33 c0"), + "8d ? ? ? 8b ? a9 fe ff ff ff 75 ? 33 ? c3 "), audMetadataManager_GetObjectByRef); ConvertCall (hook::get_pattern ( diff --git a/lib/scrThread.cc b/lib/scrThread.cc index 662f4c3..02024d1 100644 --- a/lib/scrThread.cc +++ b/lib/scrThread.cc @@ -1,6 +1,7 @@ #include "scrThread.hh" #include "Patterns/Patterns.hh" #include "Utils.hh" +#include #include #include #include @@ -198,23 +199,22 @@ scrThread::FindCurrentFunctionBounds (scrProgram *program) /*******************************************************/ uint16_t -scrThread::FindInstSize (scrProgram *program, uint32_t offset) +scrThread::FindInstSize(uint8_t* bytes, int64_t bytesLen) { - auto getByteAt = [program] (uint32_t offset) -> uint8_t & { - return program->GetCodeByte (offset); - }; - - uint8_t opcode = getByteAt (offset); + uint8_t opcode = bytes[0]; uint16_t size = 1; auto params = mOpcodes[opcode].second; for (size_t i = 0; i < strlen (params); ++i) { + if (bytesLen != -1 && size >= bytesLen) + return 0xFFFF; + switch (params[i]) { - case '$': size += getByteAt (offset + size) + 1; break; + case '$': size += bytes[size] + 1; break; case 'R': size += 2; break; - case 'S': size += getByteAt (offset + size) * 6 + 1; break; + case 'S': size += bytes[size] * 6 + 1; break; case 'a': size += 3; break; case 'b': size += 1; break; case 'd': @@ -227,6 +227,13 @@ scrThread::FindInstSize (scrProgram *program, uint32_t offset) return size; } +/*******************************************************/ +uint16_t +scrThread::FindInstSize (scrProgram *program, uint32_t offset) +{ + return FindInstSize(&program->GetCodeByte(offset)); +} + #ifdef ENABLE_DEBUG_SERVER /*******************************************************/ std::string diff --git a/lib/scrThread.hh b/lib/scrThread.hh index a66b926..e5a2ec1 100644 --- a/lib/scrThread.hh +++ b/lib/scrThread.hh @@ -394,6 +394,7 @@ public: scrProgram *GetProgram (); + static uint16_t FindInstSize (uint8_t* code, int64_t size = -1); static uint16_t FindInstSize (scrProgram *program, uint32_t offset); static std::string DisassemblInsn (scrProgram *program, uint32_t offset); diff --git a/src/common/PatchFilterDLC2612.cc b/src/common/PatchFilterDLC2612.cc index 1a574b7..2ee1d42 100644 --- a/src/common/PatchFilterDLC2612.cc +++ b/src/common/PatchFilterDLC2612.cc @@ -61,6 +61,9 @@ static std::unordered_set g_badFiles{ "dlc_mpSum2_g9ec:/common/data/effects/peds/first_person_alternates.meta", "dlc_mpSum2_g9ec:/common/data/effects/peds/first_person.meta", "dlc_mpSum2_g9ecCRC:/common/data/pedalternatevariations.meta", + + "dlc_mpChristmas3_G9EC:/x64/levels/mpChristmas3_G9EC/vehiclemods/entity3hsw_mods.rpf", + "dlc_mpChristmas3_G9EC:/x64/levels/mpChristmas3_G9EC/vehiclemods/issi8hsw_mods.rpf" }; static void (*_applyChangeSetEntry)(ChangeSetEntry* entry); diff --git a/src/common/logger.cc b/src/common/logger.cc index ac18b05..9d58b83 100644 --- a/src/common/logger.cc +++ b/src/common/logger.cc @@ -8,8 +8,8 @@ #ifndef NDEBUG #define RAINBOMIZER_BUILD "Debug Build: " __DATE__ " " __TIME__ #else -#define RAINBOMIZER_BUILD "Release v3.3.1: " __DATE__ " " __TIME__ -#define RAINBOMIZER_BUILD_SHORT "Release v3.3.1" +#define RAINBOMIZER_BUILD "Release v3.3.3: " __DATE__ " " __TIME__ +#define RAINBOMIZER_BUILD_SHORT "Release v3.3.3" #endif constexpr int RAINBOMIZER_BUILD_NUMBER = @@ -26,6 +26,8 @@ char *(*rage__formatf6eb9) (char *, char const *, ...); namespace Rainbomizer { +static uint32_t sg_GameBuild = 0; + /*******************************************************/ std::string GetTimeNow () @@ -91,6 +93,12 @@ Logger::LogMessage (const char *format, ...) fflush (file); } +uint32_t +Logger::GetGameBuild () +{ + return sg_GameBuild; +} + /*******************************************************/ class DisplayBuildVersion { @@ -99,6 +107,9 @@ class DisplayBuildVersion char *version) { #ifndef NDEBUG + sg_GameBuild = std::stoi (version); + Logger::LogMessage("Set Game Build to %d", sg_GameBuild); + return rage__formatf6eb9 (out, "Rainbomizer Build %d Build %s", RAINBOMIZER_BUILD_NUMBER + 1, version); #else diff --git a/src/common/logger.hh b/src/common/logger.hh index 9aa82d2..e4df906 100644 --- a/src/common/logger.hh +++ b/src/common/logger.hh @@ -12,6 +12,8 @@ class Logger public: static void LogMessage (const char *format, ...); + + static uint32_t GetGameBuild (); }; } // namespace Rainbomizer diff --git a/src/common/minhook.hh b/src/common/minhook.hh index 812ed00..43906a6 100644 --- a/src/common/minhook.hh +++ b/src/common/minhook.hh @@ -42,6 +42,15 @@ public: MH_EnableHook (MH_ALL_HOOKS); } + template + static void + RegisterHookOperand (const std::string &pattern, int32_t off, O &origFunc, + F hookedFunc, bool enable = true) + { + RegisterHook (GetRelativeReference (pattern, off, off + 4), origFunc, + hookedFunc, enable); + } + template static void RegisterHookApi (const wchar_t *moduleName, const char *moduleProc, @@ -72,6 +81,13 @@ public: MinHookWrapper::HookBranchDestination (pattern, off, F, function); \ } +/*******************************************************/ +#define REGISTER_MH_HOOK_OPERAND(pattern, off, function, ret, ...) \ + { \ + static ret (*F) (__VA_ARGS__); \ + MinHookWrapper::RegisterHookOperand (pattern, off, F, function); \ + } + /*******************************************************/ #define REGISTER_MH_HOOK(pattern, off, function, ret, ...) \ { \ diff --git a/src/debug/scripts.cc b/src/debug/scripts.cc index e99fa31..5a8d43e 100644 --- a/src/debug/scripts.cc +++ b/src/debug/scripts.cc @@ -617,7 +617,7 @@ class TimeTravelDebugInterface : public DebugInterface TimeTravelDebugInterface () { InitialiseAllComponents (); - InitialisePerOpcodeHook (); + //InitialisePerOpcodeHook (); } }; diff --git a/src/misc/credits.cc b/src/misc/credits.cc index 865cfb8..351b369 100644 --- a/src/misc/credits.cc +++ b/src/misc/credits.cc @@ -1,9 +1,13 @@ +#include "Patterns/Patterns.hh" +#include "atArray.hh" #include #include +#include #include #include +#include #include #include #include @@ -12,32 +16,45 @@ class CText; +struct CreditItem +{ + eCreditLineType type; + std::string title; +}; + static std::array g_RainbomizerCreditsList - = {CCreditItem{eCreditLineType::JOB_BIG, "Rainbomizer"}, - CCreditItem{eCreditLineType::SPACE_BIG}, - CCreditItem{eCreditLineType::JOB_MED, "Lead Developer"}, - CCreditItem{eCreditLineType::NAME_BIG, "Parik"}, - CCreditItem{eCreditLineType::SPACE_MED}, - CCreditItem{eCreditLineType::JOB_MED, "Major Contributors"}, - CCreditItem{eCreditLineType::NAME_BIG, "Fryterp23"}, - CCreditItem{eCreditLineType::NAME_BIG, "123robot"}, - CCreditItem{eCreditLineType::SPACE_MED}, - CCreditItem{eCreditLineType::JOB_MED, "Beta Testers"}, - CCreditItem{eCreditLineType::NAME_BIG, "Gibstack"}, - CCreditItem{eCreditLineType::NAME_BIG, "Hugo_One"}, - CCreditItem{eCreditLineType::NAME_BIG, "mo_xi"}, - CCreditItem{eCreditLineType::NAME_BIG, "SpeedyFolf"}, - CCreditItem{eCreditLineType::SPACE_MED}, - CCreditItem{eCreditLineType::SPACE_BIG}}; + = {CreditItem{eCreditLineType::JOB_BIG, "Rainbomizer"}, + CreditItem{eCreditLineType::SPACE_BIG}, + CreditItem{eCreditLineType::JOB_MED, "Lead Developer"}, + CreditItem{eCreditLineType::NAME_BIG, "Parik"}, + CreditItem{eCreditLineType::SPACE_MED}, + CreditItem{eCreditLineType::JOB_MED, "Major Contributors"}, + CreditItem{eCreditLineType::NAME_BIG, "Fryterp23"}, + CreditItem{eCreditLineType::NAME_BIG, "123robot"}, + CreditItem{eCreditLineType::SPACE_MED}, + CreditItem{eCreditLineType::JOB_MED, "Beta Testers"}, + CreditItem{eCreditLineType::NAME_BIG, "Gibstack"}, + CreditItem{eCreditLineType::NAME_BIG, "Hugo_One"}, + CreditItem{eCreditLineType::NAME_BIG, "mo_xi"}, + CreditItem{eCreditLineType::NAME_BIG, "SpeedyFolf"}, + CreditItem{eCreditLineType::SPACE_MED}, + CreditItem{eCreditLineType::SPACE_BIG}}; class RainbomizerCredits { class NewCredits { - CCreditItem * pOrigArrData = 0; - uint32_t nOrigArrSize = 0; - uint32_t nOrigArrCapa = 0; - std::vector aNewArray; + uint8_t *pOrigArrData = 0; + uint32_t nOrigArrSize = 0; + uint32_t nOrigArrCapa = 0; + + std::unique_ptr pCreditItemData; + atArrayGetSizeWrapper aEditedCredits; + + auto GetCreditItems () + { + return CCreditArray::sm_Instance->GetCreditItems(); + } public: NewCredits (){}; @@ -45,7 +62,23 @@ class RainbomizerCredits bool ShouldRegenerate () { - return nOrigArrSize != CCreditArray::sm_Instance->CreditItems.Size; + return nOrigArrSize != GetCreditItems ().Size; + } + + size_t + GetTotalCreditLinesAfterEditing () + { + return g_RainbomizerCreditsList.size () + GetCreditItems ().Size; + } + + void + ResetEditedCreditsData (size_t size) + { + pCreditItemData + = std::make_unique (size * CCreditItem::GetSize ()); + + aEditedCredits + = decltype (aEditedCredits) (pCreditItemData.get (), size); } void @@ -54,56 +87,71 @@ class RainbomizerCredits if (!ShouldRegenerate ()) return; - aNewArray.clear (); - - if (CCreditArray::sm_Instance->CreditItems.Size == 0) + if (GetCreditItems().Size == 0) return; + ResetEditedCreditsData (GetTotalCreditLinesAfterEditing ()); + auto &arr = aEditedCredits; + + size_t idx = 0; for (const auto &i : g_RainbomizerCreditsList) - aNewArray.push_back (i); + { + arr[idx] = CCreditArray::sm_Instance->GetCreditItems ()[3]; + + arr[idx].Get ("LineType"_joaat) = i.type; + + if (Rainbomizer::Logger::GetGameBuild () >= 2802) + arr[idx].Get ("bLiteral"_joaat) = true; - for (const auto &i : CCreditArray::sm_Instance->CreditItems) - aNewArray.push_back (i); + arr[idx].Get ("cTextId1"_joaat) + = i.title.c_str (); + + idx++; + } + + for (const auto &i : CCreditArray::sm_Instance->GetCreditItems ()) + { + arr[idx] = i; + idx++; + } } void Replace () { - auto &arr = CCreditArray::sm_Instance->CreditItems; + auto &arr = CCreditArray::sm_Instance->GetCreditItems(); + + pOrigArrData + = std::exchange (*reinterpret_cast (&arr.Data), + pCreditItemData.get ()); - pOrigArrData = std::exchange (arr.Data, aNewArray.data ()); - nOrigArrSize = std::exchange (arr.Size, aNewArray.size ()); + nOrigArrSize = std::exchange (arr.Size, aEditedCredits.Size); nOrigArrCapa = std::exchange (arr.Capacity, arr.Size); } void Restore () { - auto &arr = CCreditArray::sm_Instance->CreditItems; - arr.Data = pOrigArrData; - arr.Size = nOrigArrSize; - arr.Capacity = nOrigArrCapa; + auto &arr = CCreditArray::sm_Instance->GetCreditItems(); + + *reinterpret_cast (&arr.Data) = pOrigArrData; + arr.Size = nOrigArrSize; + arr.Capacity = nOrigArrCapa; } }; inline static NewCredits sm_NewCredits; - template + template static void - ReplaceCreditsArray (void *section) + ReplaceCreditsArray (bool a1) { - EnterCriticalSection_92 (section); - sm_NewCredits.Regenerate (); sm_NewCredits.Replace (); - } - template - static void - RestoreCreditsArray (void *section) - { + CCredits__Draw (a1); + sm_NewCredits.Restore (); - LeaveCriticalSection_93 (section); } template @@ -119,10 +167,9 @@ class RainbomizerCredits } void - InitialiseFixJobTitleHooks () + InitialiseFixJobTitleHooks (std::string_view pattern) { - hook::pattern p ("74 ? ? 8b 54 03 08 eb ? ? 8d 15 ? ? ? ? ? 8d 0d ? ? " - "? ? e8 ? ? ? ?"); + hook::pattern p (pattern); using CText_GetText_Prototype = char *(*) (CText *, char *); static CText_GetText_Prototype orig; @@ -133,6 +180,7 @@ class RainbomizerCredits } public: + RainbomizerCredits () { if (!ConfigManager::ReadConfig ("RainbomizerCredits")) @@ -140,14 +188,17 @@ class RainbomizerCredits InitialiseAllComponents (); - REGISTER_HOOK ("8a d9 0f 29 ? ? ? 8d 0d ? ? ? ? 0f 29 ? ? e8 ? ? ? ?", - 17, ReplaceCreditsArray, void, void *); + REGISTER_MH_HOOK_OPERAND ( + "? 8d ? ? ? ? ? 33 ? ? 88 ? ? e8 ? ? ? ? ? 8d ? ? ? ? " + "? 33 ? e8 ? ? ? ? ? 8d ? ? ? 8d ? ? ? ? ?", + 3, ReplaceCreditsArray, void, bool); - InitialiseFixJobTitleHooks (); + InitialiseFixJobTitleHooks ( + "74 ? ? 8b 54 18 28 eb ? ? 8d 15 ? ? ? ? ? 8d 0d ? ? ? ? e8 ? ? ? " + "? eb ? 66 39 ? ? ? "); - REGISTER_HOOK_JMP ( - "8d 0d ? ? ? ? ? 8d ? ? ? 01 00 00 ? 8b ? ? 41 0f 28 ? ? 41 0f 28 " - "? ? ? 8b e3 41 5f 41 5e 41 5d 41 5c 5f 5e 5d e9", - 42, RestoreCreditsArray, void, void *); + InitialiseFixJobTitleHooks ( + "74 ? ? 8b 54 03 08 eb ? ? 8d 15 ? ? ? ? ? 8d 0d ? ? " + "? ? e8 ? ? ? ?"); } } _rbcredits; diff --git a/src/misc/respawns.cc b/src/misc/respawns.cc index df2f95c..af36f0b 100644 --- a/src/misc/respawns.cc +++ b/src/misc/respawns.cc @@ -105,8 +105,8 @@ class RespawnRandomizer if (Config ().MiddleOfNowhere) { - ops.Write (16, YscOpCode::PUSH_CONST_0); - ops.Write (17, YscOpCode::NOP); + ops.Write (16, ops.OpCode (PUSH_CONST_0)); + ops.Write (17, ops.OpCode (NOP)); } sm_Initialised = true; @@ -135,7 +135,7 @@ class RespawnRandomizer else { ops.Init (m_Offsets[0].Switch); - ops.Write (16, YscOpCode::PUSH_CONST_U8); + ops.Write (16, ops.OpCode(PUSH_CONST_U8)); ops.Write (17, RandomInt (6)); } } diff --git a/src/misc/scenes.cc b/src/misc/scenes.cc index 65e92b7..70f0ecd 100644 --- a/src/misc/scenes.cc +++ b/src/misc/scenes.cc @@ -13,43 +13,40 @@ class SwitchSceneRandomizer if (!utils.IsAnyOf ("player_controller_b"_joaat)) return false; - static constexpr uint8_t SHELL_CODE[] + static uint8_t SHELL_CODE[] = {// PUSH_CONST_0 - uint8_t (YscOpCode::PUSH_CONST_0), + utils.OpCode (PUSH_CONST_0), // PUSH_CONST_S16 314 (total number of thingies) - uint8_t (YscOpCode::PUSH_CONST_S16), 0x3a, 0x1, + utils.OpCode (PUSH_CONST_S16), 0x3a, 0x1, // NATIVE (GET_RANDOM_INT_IN_RANGE) - uint8_t (YscOpCode::NATIVE), 0x2, 0x0, 0x0, + utils.OpCode (NATIVE), 0x2, 0x0, 0x0, // LOCAL_U8_LOAD 0x4 - uint8_t (YscOpCode::LOCAL_U8_LOAD), 0x1, + utils.OpCode (LOCAL_U8_LOAD), 0x1, // STORE - uint8_t (YscOpCode::STORE), + utils.OpCode (STORE), // PUSH_CONST_FM1 - uint8_t (YscOpCode::PUSH_CONST_FM1), + utils.OpCode (PUSH_CONST_FM1), // LOCAL_U8_LOAD 0x8 - uint8_t (YscOpCode::LOCAL_U8_LOAD), 0x2, + utils.OpCode (LOCAL_U8_LOAD), 0x2, // STORE - uint8_t (YscOpCode::STORE), + utils.OpCode (STORE), // PUSH_CONST_1 - uint8_t (YscOpCode::PUSH_CONST_1), + utils.OpCode (PUSH_CONST_1), // LEAVE 0x6, 0x1 - uint8_t (YscOpCode::LEAVE), 0x6, 0x1}; + utils.OpCode (LEAVE), 0x6, 0x1}; constexpr uint32_t NATIVE_OPCODE_OFFSET = 4; constexpr uint32_t NATIVE_OPCODE_SIZE = 4; - static_assert (SHELL_CODE[NATIVE_OPCODE_OFFSET] == YscOpCode::NATIVE, - "Native Opcode Offset Incorrect"); - // // Generate dynamic shellcode uint8_t shellCode[sizeof (SHELL_CODE)]; memcpy (shellCode, SHELL_CODE, sizeof (SHELL_CODE)); diff --git a/src/mission/missions_Code.cc b/src/mission/missions_Code.cc index 84b1cc8..f8c1537 100644 --- a/src/mission/missions_Code.cc +++ b/src/mission/missions_Code.cc @@ -47,16 +47,16 @@ MissionRandomizer_CodeFixes::ApplyCreditsFix_FinaleAB (YscUtilsOps &utils) utils.Init ("50 ? ? 6e 57 ? ? 2c ? ? ? 61 ? ? ? 59 ? ?"); utils.NOP (/*Offset=*/0, /*Size=*/4); - utils.Write (/*Offset=*/4, YscOpCode::J); + utils.Write (/*Offset=*/4, utils.OpCode(J)); utils.Init ("59 ? ? 2c ? ? ? 06 56 ? ? 43 88 13 2c 04 ? ? 2c ? ? ? 56"); utils.NOP (/*Offset=*/0, /*Size=*/25); utils.Init ("2d 00 02 00 ? 2c ? ? ? 06 56 ? ? 6e 2c 04"); - utils.Write (/*Offset=*/10, YscOpCode::J); + utils.Write (/*Offset=*/10, utils.OpCode (J)); utils.Init ("5f ? ? ? 6e 57 ? ? 2c ? ? ? 61 ? ? ? 59 ? ?"); - utils.Write (/*Offset=*/5, YscOpCode::J); + utils.Write (/*Offset=*/5, utils.OpCode (J)); return true; } @@ -65,7 +65,7 @@ MissionRandomizer_CodeFixes::ApplyCreditsFix_FinaleAB (YscUtilsOps &utils) bool MissionRandomizer_CodeFixes::ApplyCreditsFix_FinaleC2 (YscUtilsOps &utils) { - static constexpr uint8_t j_0x24[] = {0x55, 0x16, 0x00}; + static uint8_t j_0x24[] = {utils.OpCode (J), 0x16, 0x00}; if (!utils.IsAnyOf ("finalec2"_joaat)) return false; @@ -74,7 +74,7 @@ MissionRandomizer_CodeFixes::ApplyCreditsFix_FinaleC2 (YscUtilsOps &utils) utils.WriteBytes (/*Offset=*/5, j_0x24); utils.Init ("5f ? ? ? 06 56 ? ? 2c ? ? ? 61"); - utils.Write (/*Offset=*/5, YscOpCode::J); + utils.Write (/*Offset=*/5, utils.OpCode(J)); utils.Init ("5a ? ? 43 88 13 2c 04 ? ? 2c ? ? ? 06 56 ? ? 6e 2c 04 ? ? 55"); utils.NOP (/*Offset=*/0, /*Size=*/26); @@ -94,9 +94,9 @@ MissionRandomizer_CodeFixes::ApplyTriggererWaitFix (YscUtilsOps &utils) // missions that wait for the triggerer, but you would need to go through // all the missions and find out which ones are broken. - static constexpr uint8_t return_1[] = { - 0x6f, // PUSH_CONST_1 - 0x2e, 0x1, 0x1 // LEAVE 0x1, 0x1 + static uint8_t return_1[] = { + utils.OpCode (PUSH_CONST_1), // PUSH_CONST_1 + utils.OpCode (LEAVE), 0x1, 0x1 // LEAVE 0x1, 0x1 }; if (!MR::sm_Data.IsValidMission (utils.GetProgram ()->m_nScriptHash)) @@ -130,7 +130,7 @@ MissionRandomizer_CodeFixes::ApplyPrepNoRepeatFix (YscUtilsOps &utils) return false; utils.Init ("2d 00 03 00 ? 6e 5d ? ? ? 06 56 ? ? 5d ? ? ? 6f"); - utils.Write (/*Offset=*/11, YscOpCode::J); + utils.Write (/*Offset=*/11, utils.OpCode(J)); return true; } @@ -208,7 +208,7 @@ MissionRandomizer_CodeFixes::ApplyReplayControllerFix (YscUtilsOps &utils) return false; uint8_t shellCode[] - = {uint8_t (YscOpCode::GLOBAL_U24_LOAD), 0x00, 0x00, 0x00}; + = {utils.OpCode(GLOBAL_U24_LOAD), 0x00, 0x00, 0x00}; utils.Init ( "2d 00 ? ? ? 5d ? ? ? 56 ? ? 5e ? ? ? 40 ? 6e 5d ? ? ? 39 ? 38"); diff --git a/src/mission/missions_YscUtils.cc b/src/mission/missions_YscUtils.cc index 7ff486b..514dcef 100644 --- a/src/mission/missions_YscUtils.cc +++ b/src/mission/missions_YscUtils.cc @@ -1,16 +1,31 @@ #include "missions_YscUtils.hh" #include +#include "common/logger.hh" + /*******************************************************/ void YscUtils::FindCodePattern (std::string_view pattern_str, - std::function CB) + std::function CB, + bool translate) { m_pProgram->ForEachCodePage ([&] (int, uint8_t *block, size_t size) { auto pattern = hook::make_range_pattern (uintptr_t (block), uintptr_t (block) + size, pattern_str); + // Translate patterns to new version + auto& bytes = pattern.getBytes (); + for (size_t offset = 0; translate && offset < bytes.size (); offset++) + { + auto instSize = scrThread::FindInstSize (bytes.data () + offset, + bytes.size ()); + + bytes[offset] = OpCode (YscOpCode (bytes[offset])); + + offset += instSize - 1; + } + pattern.for_each_result ( [CB] (hook::pattern_match match) { CB (match); }); }); diff --git a/src/mission/missions_YscUtils.hh b/src/mission/missions_YscUtils.hh index 394b759..bc8c202 100644 --- a/src/mission/missions_YscUtils.hh +++ b/src/mission/missions_YscUtils.hh @@ -25,8 +25,13 @@ class YscUtils public: YscUtils (scrProgram *program) : m_pProgram (program){}; + // Given a pattern, finds occurrances of it in the program and calls + // function CB with the pattern matches. If translate is true, it will + // convert the pattern from an old version pattern to support the latest + // version. void FindCodePattern (std::string_view pattern, - std::function CB); + std::function CB, + bool translate = true); void FindString (const char *str, void (*CB) (char *)); @@ -48,6 +53,21 @@ public: return m_pProgram; } + bool GetShouldTranslateOpcodes () + { + return Rainbomizer::Logger::GetGameBuild() >= 2802; + } + + // Translates version 1 opcodes to version 2 and above + uint8_t + OpCode (YscOpCode op) + { + if (op > YscOpCode::CALL && GetShouldTranslateOpcodes ()) + return uint8_t (op) + 3; + + return op; + } + /* Make sure the script doesn't call WAIT or a native that changes the * script's state. The script will stop execution there and not continue! */ template @@ -358,7 +378,7 @@ public: /* Initialise the UtilsOps to a certain pattern for further operations */ void - Init (std::string_view pattern) + Init (std::string_view pattern, bool translate = true) { uint8_t *ptr = nullptr; FindCodePattern (pattern, [&ptr] (hook::pattern_match m) { diff --git a/src/peds/peds_PlayerFixes.hh b/src/peds/peds_PlayerFixes.hh index e2ce103..c826353 100644 --- a/src/peds/peds_PlayerFixes.hh +++ b/src/peds/peds_PlayerFixes.hh @@ -148,10 +148,13 @@ class PedRandomizer_PlayerFixes if (!ops.IsAnyOf ("mission_triggerer_a"_joaat)) return false; - uint8_t return_0x1[] = {0x6f, 0x2e, 0x00, 0x01}; + static uint8_t return_1[] = { + ops.OpCode (PUSH_CONST_1), // PUSH_CONST_1 + ops.OpCode (LEAVE), 0x0, 0x1 // LEAVE 0x0, 0x1 + }; ops.Init ("2d 00 03 00 ? 2c ? ? ? ? 5d ? ? ? 39 02 38 02 6e"); - ops.WriteBytes (/*Offset=*/5, return_0x1); + ops.WriteBytes (/*Offset=*/5, return_1); return true; } @@ -163,11 +166,14 @@ class PedRandomizer_PlayerFixes if (!ops.IsAnyOf ("michael4"_joaat)) return false; - uint8_t return_0x1[] = {0x6f, 0x2e, 0x03, 0x01}; + static uint8_t return_1[] = { + ops.OpCode (PUSH_CONST_1), // PUSH_CONST_1 + ops.OpCode (LEAVE), 0x3, 0x1 // LEAVE 0x0, 0x1 + }; ops.Init ("26 0c 10 5d ? ? ? 06 56 ? ? 28 c9 14 71 0d"); ops.FollowBranchDestination (/*Offset=*/3); - ops.WriteBytes (/*Offset=*/5, return_0x1); + ops.WriteBytes (/*Offset=*/5, return_1); return true; } diff --git a/src/vehicles/vehicles.cc b/src/vehicles/vehicles.cc index ed739c8..1d25246 100644 --- a/src/vehicles/vehicles.cc +++ b/src/vehicles/vehicles.cc @@ -363,9 +363,9 @@ class ScriptVehicleRandomizer if (!ops.IsAnyOf ("fanatic3"_joaat)) return false; - static constexpr uint8_t return_1[] = { - 0x6f, // PUSH_CONST_1 - 0x2e, 0x1, 0x1 // LEAVE 0x1, 0x1 + static uint8_t return_1[] = { + ops.OpCode (PUSH_CONST_1), // PUSH_CONST_1 + 0x2e, 0x1, 0x1 // LEAVE 0x1, 0x1 }; ops.Init ("2d 01 03 00 ? 38 ? 28 54 9c 77 43 08 "); diff --git a/src/weapons/stats.cc b/src/weapons/stats.cc index b9ae95e..f48a758 100644 --- a/src/weapons/stats.cc +++ b/src/weapons/stats.cc @@ -104,10 +104,9 @@ class WeaponStatsRandomizer std::uint32_t hash; if (sample) - sm_ItemInfoRandomizer.AddSample (i, i->GetClassId (hash)); + sm_ItemInfoRandomizer.AddSample (i, i->GetClassId ()); else - sm_ItemInfoRandomizer.RandomizeObject (i, i->GetClassId ( - hash)); + sm_ItemInfoRandomizer.RandomizeObject (i, i->GetClassId ()); } return true; diff --git a/src/weapons/weapons.cc b/src/weapons/weapons.cc index aa5c45c..5107795 100644 --- a/src/weapons/weapons.cc +++ b/src/weapons/weapons.cc @@ -119,10 +119,9 @@ class WeaponRandomizer for (auto &info : CWeaponInfoManager::sm_Instance->aItemInfos) { static_assert ("cweaponinfo"_joaat == 0x861905b4); - uint32_t outHash = 0; if (info->Model && !DoesElementExist (mExceptions, info->Name) - && info->GetClassId (outHash) == "cweaponinfo"_joaat + && info->GetClassId () == "cweaponinfo"_joaat && IsValidWeapon (*static_cast (info))) { mValidWeapons.push_back (info->Name);