Skip to content

Commit

Permalink
Merge pull request #856 from psiberx/master
Browse files Browse the repository at this point in the history
Patch 2.0
  • Loading branch information
maximegmd committed Sep 26, 2023
2 parents 6b1da70 + 3cee4bc commit a7502c6
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 103 deletions.
3 changes: 1 addition & 2 deletions ida/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions src/reverse/Addresses.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
155 changes: 57 additions & 98 deletions src/reverse/RTTIExtender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <RED4ext/Scripting/Natives/Generated/WorldTransform.hpp>
#include <RED4ext/Scripting/Natives/Generated/ent/Entity.hpp>
#include <RED4ext/Scripting/Natives/Generated/ent/EntityID.hpp>
#include <RED4ext/Scripting/Natives/Generated/game/IGameSystem.hpp>

#include "RED4ext/Scripting/Utils.hpp"

Expand All @@ -13,7 +14,7 @@ template <typename T> struct GameCall
GameCall(uintptr_t aAddress, const int32_t acOffset = 0)
{
const RED4ext::RelocPtr<uint8_t> addr(aAddress);
const auto* pLocation = addr.GetAddr();
auto* pLocation = addr.GetAddr();
m_address = pLocation ? reinterpret_cast<T>(pLocation + acOffset) : nullptr;
}

Expand Down Expand Up @@ -105,44 +106,6 @@ template <typename T> 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<TFunc> 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
Expand Down Expand Up @@ -337,33 +300,9 @@ void CreateSingleton(const RED4ext::Handle<RED4ext::IScriptable>& 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<gameIGameSystem*>(apClassInstance.GetPtr());
auto* pGameSystem = reinterpret_cast<RED4ext::gameIGameSystem*>(apClassInstance.GetPtr());
pGameSystem->gameInstance = pGameInstance;
pGameSystem->OnSystemInitializeAsync(&systemInitParams);
pGameSystem->OnInitialize({});
}

auto* pParentType = apClassInstance->GetType();
Expand Down Expand Up @@ -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;
Expand All @@ -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<uintptr_t*>(malloc(VftableSize));
memcpy(ClonedVftable, *static_cast<uintptr_t**>(apAddress), VftableSize);

ClonedVftable[0] = reinterpret_cast<uintptr_t>(&HOOK_GetNativeType);
ClonedVftable[0x118 / 8] = reinterpret_cast<uintptr_t>(&HOOK_OnInitialize);
ClonedVftable[0x120 / 8] = reinterpret_cast<uintptr_t>(&HOOK_OnShutdown);
}

// overwrite vftable with our clone
*static_cast<uintptr_t**>(apAddress) = ClonedVftable;

return static_cast<exEntitySpawnerSystem*>(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*);
Expand Down Expand Up @@ -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<IScriptable>(Singleton));
auto systemInstance = RED4ext::MakeHandle<exEntitySpawnerSystem>();
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)
Expand Down Expand Up @@ -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<RED4ext::IScriptable> 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()
Expand Down
2 changes: 1 addition & 1 deletion src/reverse/RTTIHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit a7502c6

Please sign in to comment.