Skip to content

Commit

Permalink
tweak(game/five): revive removed natives
Browse files Browse the repository at this point in the history
Allowing reimplemented natives to be referenced via its crossmap.

Fixes #2328
  • Loading branch information
gottfriedleibniz committed Mar 12, 2024
1 parent 78e5f7a commit fb3e658
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 14 deletions.
3 changes: 3 additions & 0 deletions code/components/rage-scripting-five/include/scrEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class
// queues the registration of a custom native function handler with an identifier
static void RegisterNativeHandler(uint64_t nativeIdentifier, NativeHandler handler);

// queues the registration of a custom native function handler that revives a removed identifier
static void ReviveNativeHandler(uint64_t nativeIdentifier, NativeHandler handler);

public:
static fwEvent<> OnScriptInit;

Expand Down
42 changes: 37 additions & 5 deletions code/components/rage-scripting-five/src/TableBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@

#include <CrossBuildRuntime.h>

struct CrossMappingEntry
{
uint64_t entries[28];
};

static std::unordered_map<uint64_t, uint64_t> g_mappingTable;
static std::shared_ptr<DeferredInitializer> g_mappingInitializer;
static std::unordered_map<uint64_t, const CrossMappingEntry*> g_unmappedTable;

namespace rage
{
Expand All @@ -32,17 +38,33 @@ namespace rage

return it->second;
}

void ReviveNative(uint64_t inNative)
{
g_mappingInitializer->Wait();

if (auto it = g_unmappedTable.find(inNative); it != g_unmappedTable.end())
{
for (uint64_t hash : it->second->entries)
{
if (hash != 0 && hash != inNative)
{
g_mappingTable.insert({ hash, inNative });
}
}
}
}
}

extern "C" DLL_EXPORT uint64_t MapNative(uint64_t inNative)
{
return rage::MapNative(inNative);
}

struct CrossMappingEntry
extern "C" DLL_EXPORT void ReviveNative(uint64_t inNative)
{
uint64_t entries[28];
};
rage::ReviveNative(inNative);
}

static void DoMapping()
{
Expand Down Expand Up @@ -208,11 +230,21 @@ static void DoMapping()
{
for (auto& nativeEntry : crossMapping_universal)
{
bool hasNative = nativeEntry.entries[maxVersion] != 0;
for (int i = 0; i < maxVersion; i++)
{
if (nativeEntry.entries[i] != 0 && nativeEntry.entries[maxVersion] != 0)
if (uint64_t hash = nativeEntry.entries[i])
{
g_mappingTable.insert({ nativeEntry.entries[i], nativeEntry.entries[maxVersion] });
if (hasNative)
{
g_mappingTable.insert({ hash, nativeEntry.entries[maxVersion] });
}
else
{
// Native was removed this version: add it to a separate table
// so it can potentially be revived by custom implementations.
g_unmappedTable.insert({ hash, &nativeEntry });
}
}
}
}
Expand Down
34 changes: 25 additions & 9 deletions code/components/rage-scripting-five/src/scrEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ void scrEngine::CreateThread(GtaThread* thread)
}

uint64_t MapNative(uint64_t inNative);
void ReviveNative(uint64_t inNative);

template<typename TReg>
bool RegisterNativeOverride(uint64_t hash, scrEngine::NativeHandler handler)
Expand Down Expand Up @@ -406,6 +407,18 @@ void scrEngine::RegisterNativeHandler(uint64_t nativeIdentifier, NativeHandler h
g_nativeHandlers.push_back(std::make_pair(nativeIdentifier, handler));
}

void scrEngine::ReviveNativeHandler(uint64_t nativeIdentifier, NativeHandler handler)
{
RegisterNativeHandler(nativeIdentifier, handler);
if (MapNative(nativeIdentifier) == nativeIdentifier)
{
// If two builds share the same maxVersion index, e.g., 2545 and 2612,
// and a script command was removed, then the native may be found in the
// mapping table instead of the unmapped table.
ReviveNative(nativeIdentifier);
}
}

static InitFunction initFunction([] ()
{
scrEngine::OnScriptInit.Connect([] ()
Expand Down Expand Up @@ -548,19 +561,22 @@ static InitFunction initFunction([]
if (xbr::IsGameBuildOrGreater<2612>())
{
// IS_BIT_SET is missing in b2612+, re-adding for compatibility
rage::scrEngine::RegisterNativeHandler(0xE2D0C323A1AE5D85 /* 2545 hash */, [](rage::scrNativeCallContext* ctx)
rage::scrEngine::OnScriptInit.Connect([]()
{
bool result = false;
rage::scrEngine::ReviveNativeHandler(0xE2D0C323A1AE5D85 /* 2545 hash */, [](rage::scrNativeCallContext* ctx)
{
bool result = false;

auto value = ctx->GetArgument<uint32_t>(0);
auto offset = ctx->GetArgument<int>(1);
auto value = ctx->GetArgument<uint32_t>(0);
auto offset = ctx->GetArgument<int>(1);

if (offset < 32)
{
result = (value & (1 << offset)) != 0;
}
if (offset < 32)
{
result = (value & (1 << offset)) != 0;
}

ctx->SetResult<int>(0, result);
ctx->SetResult<int>(0, result);
});
});
}
});
Expand Down

0 comments on commit fb3e658

Please sign in to comment.