diff --git a/ida/patterns.py b/ida/patterns.py index c3e82b31..38bf2169 100644 --- a/ida/patterns.py +++ b/ida/patterns.py @@ -56,8 +56,7 @@ def get_groups() -> List[Group]: Item(name='ClipToCenter', pattern='48 89 5C 24 08 55 48 8B EC 48 83 EC 30 48 8B D9 48 8B 89 68 01 00 00', expected=1) # ok ]), Group(name='gameIGameSystem', functions=[ - Item(name='Constructor', pattern='48 83 EC 28 E8 ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B C1 4C 89 09 48 83 61 48 00 48 83 61 50 00 48 83 C4 28 C3', expected=3, index=0), # ok - Item(name='Initialize', pattern='48 89 5C 24 08 57 48 83 EC 30 48 8B 42 78 4C 8B CA 48 8B D9', expected=1), # ok + Item(name='Initialize', pattern='48 89 5C 24 08 57 48 83 EC 30 48 8B 42 78 4C 8B CA 48 8B D9', expected=1), # ok Item(name='UnInitialize', pattern=' 48 89 5C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B F9 48 8D 51 42', expected=2, index=1), # ok Item(name='Spawn', pattern='48 89 5C 24 10 48 89 74 24 18 55 57 41 56 48 8D 6C 24 B0 48 81 EC 50 01 00 00 48 83 79 50 00 49 8B D9 4D 8B F0', expected=1), # ok Item(name='Despawn', pattern='48 8B C4 48 89 58 08 48 89 68 10 48 89 70 18 48 89 78 20 41 56 48 83 EC 40 48 8B E9 0F 57 C0 48 83 C1 41 48 8B F2 F3 0F 7F 40 D8 E8', expected=1), # ok diff --git a/src/reverse/Addresses.h b/src/reverse/Addresses.h index b68c13b2..fa922502 100644 --- a/src/reverse/Addresses.h +++ b/src/reverse/Addresses.h @@ -87,8 +87,6 @@ constexpr uintptr_t CWinapi_ClipToCenter = 0x140297FA8 - ImageBase; // 48 89 5C #pragma endregion #pragma region gameIGameSystem -constexpr uintptr_t gameIGameSystem_Constructor = - 0x1407BBEE0 - ImageBase; // 48 83 EC 28 E8 ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B C1 4C 89 09 48 83 61 48 00 48 83 61 50 00 48 83 C4 28 C3, expected: 3, index: 0 constexpr uintptr_t gameIGameSystem_Initialize = 0x1407147C0 - ImageBase; // 48 89 5C 24 08 57 48 83 EC 30 48 8B 42 78 4C 8B CA 48 8B D9, expected: 1, index: 0 constexpr uintptr_t gameIGameSystem_UnInitialize = 0x141F96058 - ImageBase; // 48 89 5C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B F9 48 8D 51 42, expected: 2, index: 1 constexpr uintptr_t gameIGameSystem_Spawn = diff --git a/src/reverse/RTTIExtender.cpp b/src/reverse/RTTIExtender.cpp index 2f500253..54bf892c 100644 --- a/src/reverse/RTTIExtender.cpp +++ b/src/reverse/RTTIExtender.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "RED4ext/Scripting/Utils.hpp" @@ -13,7 +14,7 @@ template struct GameCall GameCall(uintptr_t aAddress, const int32_t acOffset = 0) { const RED4ext::RelocPtr addr(aAddress); - const auto* pLocation = addr.GetAddr(); + auto* pLocation = addr.GetAddr(); m_address = pLocation ? reinterpret_cast(pLocation + acOffset) : nullptr; } @@ -105,44 +106,6 @@ template struct REDSmartPtr T* data; }; -struct IUpdatableSystem : RED4ext::IScriptable -{ - virtual void sub_110(uint64_t) = 0; // probably Update -}; - -struct gameIGameSystem : IUpdatableSystem -{ - RED4ext::GameInstance* gameInstance = nullptr; - - static void CallConstructor(void* apAddress) - { - // expected: 2, index: 0 - using TFunc = void (*)(void*); - static GameCall func(CyberEngineTweaks::Addresses::gameIGameSystem_Constructor); - func(apAddress); // gameIGameSystem::ctor() - } - - virtual void OnInitialize() = 0; // 118 - virtual void OnShutdown() = 0; // 120 - virtual void sub_128() = 0; - virtual void sub_130() = 0; - virtual void sub_138() = 0; - virtual void sub_140() = 0; - virtual void sub_148() = 0; - virtual void sub_150() = 0; - virtual void sub_158() = 0; - virtual void sub_160() = 0; - virtual void sub_168() = 0; - virtual void sub_170() = 0; - virtual void sub_178() = 0; - virtual void sub_180() = 0; - virtual void sub_188() = 0; - virtual void sub_190() = 0; - virtual void OnSystemInitializeAsync(void*) = 0; // 198 - virtual void OnSystemUnInitializeAsync(void*) = 0; // 1A0 -}; -RED4EXT_ASSERT_OFFSET(gameIGameSystem, gameInstance, 0x40); - struct TEMP_PendingEntity { struct Unk00 @@ -337,33 +300,9 @@ void CreateSingleton(const RED4ext::Handle& apClassInstanc { // Initialize system { - struct - { - uint64_t unk00 = 0; - const char* unk08 = ""; - uint64_t unk10 = 0; - uint32_t unk18 = 0; - uint32_t unk1C = 1; - union - { - uint32_t fullValue = 0xFF000200; -#pragma pack(push, 1) - struct - { - uint8_t unk00; - uint16_t unk01; - uint8_t unk03; - }; -#pragma pack(pop) - } unk20; - uint32_t unk24 = 0; - - } systemInitParams; - RED4EXT_ASSERT_SIZE(systemInitParams, 40); - - auto* pGameSystem = reinterpret_cast(apClassInstance.GetPtr()); + auto* pGameSystem = reinterpret_cast(apClassInstance.GetPtr()); pGameSystem->gameInstance = pGameInstance; - pGameSystem->OnSystemInitializeAsync(&systemInitParams); + pGameSystem->OnInitialize({}); } auto* pParentType = apClassInstance->GetType(); @@ -453,8 +392,10 @@ void WorldFunctionalTests_DespawnEntity(RED4ext::IScriptable*, RED4ext::CStackFr #pragma region EntitySpawner -struct exEntitySpawnerSystem : gameIGameSystem +struct exEntitySpawnerSystem : RED4ext::gameIGameSystem { + using AllocatorType = RED4ext::Memory::RTTIAllocator; + constexpr static char NATIVE_TYPE_STR[] = "exEntitySpawner"; constexpr static char PARENT_TYPE_STR[] = "gameIGameSystem"; constexpr static RED4ext::CName NATIVE_TYPE = NATIVE_TYPE_STR; @@ -463,40 +404,22 @@ struct exEntitySpawnerSystem : gameIGameSystem static exEntitySpawnerSystem* Singleton; static TEMP_Spawner exEntitySpawner_Spawner; -private: - static exEntitySpawnerSystem* CreateNew(void* apAddress) + RED4ext::CClass* GetNativeType() override { - constexpr int32_t VftableSize = 0x1A8; - static uintptr_t* ClonedVftable = nullptr; - - CallConstructor(apAddress); - - if (ClonedVftable == nullptr) - { - ClonedVftable = static_cast(malloc(VftableSize)); - memcpy(ClonedVftable, *static_cast(apAddress), VftableSize); - - ClonedVftable[0] = reinterpret_cast(&HOOK_GetNativeType); - ClonedVftable[0x118 / 8] = reinterpret_cast(&HOOK_OnInitialize); - ClonedVftable[0x120 / 8] = reinterpret_cast(&HOOK_OnShutdown); - } - - // overwrite vftable with our clone - *static_cast(apAddress) = ClonedVftable; - - return static_cast(apAddress); + return RED4ext::CRTTISystem::Get()->GetClass(NATIVE_TYPE_STR); } - static RED4ext::CBaseRTTIType* HOOK_GetNativeType(exEntitySpawnerSystem*) + void OnWorldAttached(RED4ext::world::RuntimeScene* aScene) override { - auto* pRTTI = RED4ext::CRTTISystem::Get(); - return pRTTI->GetClass(NATIVE_TYPE_STR); + exEntitySpawner_Spawner.Initialize(gameInstance); } - static void HOOK_OnInitialize(exEntitySpawnerSystem* apThis) { exEntitySpawner_Spawner.Initialize(apThis->gameInstance); } - - static void HOOK_OnShutdown(exEntitySpawnerSystem*) { exEntitySpawner_Spawner.UnInitialize(); } + void OnBeforeWorldDetach(RED4ext::world::RuntimeScene* aScene) override + { + exEntitySpawner_Spawner.UnInitialize(); + } +private: static void SpawnCallback(TEMP_PendingEntity::Unk00& aUnk) { using TFunc = void (*)(IScriptable*, RED4ext::ent::Entity*); @@ -565,13 +488,20 @@ struct exEntitySpawnerSystem : gameIGameSystem static void InitializeSingleton() { - // should only be called once - assert(Singleton == nullptr); auto* pRTTI = RED4ext::CRTTISystem::Get(); + auto* pSystemType = pRTTI->GetClass(NATIVE_TYPE); + auto* pGameInstance = RED4ext::CGameEngine::Get()->framework->gameInstance; + + if (pGameInstance->GetSystem(pSystemType)) + return; // already init - auto* pAllocator = pRTTI->GetClass(PARENT_TYPE)->GetAllocator(); - Singleton = CreateNew(pAllocator->AllocAligned(sizeof(exEntitySpawnerSystem), alignof(exEntitySpawnerSystem)).memory); - CreateSingleton(RED4ext::Handle(Singleton)); + auto systemInstance = RED4ext::MakeHandle(); + systemInstance->gameInstance = pGameInstance; + + pGameInstance->systemMap.Insert(pSystemType, systemInstance); + pGameInstance->systemInstances.PushBack(systemInstance); + + Singleton = systemInstance.instance; } static void Spawn(IScriptable*, RED4ext::CStackFrame* apFrame, RED4ext::ent::EntityID* apOut, int64_t) @@ -692,11 +622,40 @@ void RTTIExtender::AddFunctionalTests() } } +static void AddToInventory(RED4ext::IScriptable*, RED4ext::CStackFrame* apFrame, void*, int64_t) +{ + RED4ext::CString recordPath; + int32_t quantity{1}; + + RED4ext::GetParameter(apFrame, &recordPath); + RED4ext::GetParameter(apFrame, &quantity); + apFrame->code++; // skip ParamEnd + + RED4ext::ScriptGameInstance gameInstance; + RED4ext::Handle player; + RED4ext::ExecuteGlobalFunction("GetPlayer;GameInstance", &player, gameInstance); + + bool result; + RED4ext::TweakDBID itemID(recordPath.c_str()); + RED4ext::ExecuteFunction("gameTransactionSystem", "GiveItemByTDBID", &result, player, itemID, quantity); +} + void RTTIExtender::InitializeTypes() { exEntitySpawnerSystem::InitializeType(); AddFunctionalTests(); // This is kept for backward compatibility with mods + + { + auto pFunction = RED4ext::CGlobalFunction::Create("AddToInventory", "AddToInventory", AddToInventory); + pFunction->AddParam("String", "itemID"); + pFunction->AddParam("Int32", "quantity", false, true); + pFunction->flags.isNative = true; + pFunction->flags.isExec = true; + + auto pRTTI = RED4ext::CRTTISystem::Get(); + pRTTI->RegisterFunction(pFunction); + } } void RTTIExtender::InitializeSingletons() diff --git a/src/reverse/RTTIHelper.cpp b/src/reverse/RTTIHelper.cpp index 5705d1f0..d535fac4 100644 --- a/src/reverse/RTTIHelper.cpp +++ b/src/reverse/RTTIHelper.cpp @@ -571,7 +571,7 @@ RED4ext::IScriptable* RTTIHelper::ResolveHandle(RED4ext::CBaseFunction* apFunc, sol::variadic_results RTTIHelper::ExecuteFunction( RED4ext::CBaseFunction* apFunc, RED4ext::IScriptable* apContext, sol::variadic_args aLuaArgs, uint64_t aLuaArgOffset, std::string& aErrorMessage, bool aAllowNull) const { - static thread_local TiltedPhoques::ScratchAllocator s_scratchMemory(1 << 14); + static thread_local TiltedPhoques::ScratchAllocator s_scratchMemory(1 << 20); static thread_local uint32_t s_callDepth = 0u; if (!m_pRtti)