Skip to content

feat(net/rdr3): extended object id manager #3280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7806,7 +7806,7 @@ static InitFunction initFunction([]()

constexpr bool canLengthHack =
#ifdef STATE_RDR3
false
true
#else
true
#endif
Expand Down
2 changes: 2 additions & 0 deletions code/components/gta-net-five/include/rlNetBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class datBitBuffer
return (m_curBit / 8) + leftoverBit;
}

bool ReadBit(bool* bit);

bool ReadInteger(uint32_t* integer, int bits);

// NOTE: SIGNED
Expand Down
172 changes: 116 additions & 56 deletions code/components/gta-net-five/src/CloneExperiments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1398,41 +1398,17 @@ static CScenarioInfo* GetTaskScenarioInfo(void* task)

static constexpr int kPlayerNetIdLength = 16;

namespace rage
{
struct CSyncDataBase
{
char m_pad[24];
};

struct CSyncDataReader : CSyncDataBase
{
datBitBuffer* m_buffer;
};

struct CSyncDataWriter : CSyncDataBase
{
datBitBuffer* m_buffer;
};

struct CSyncDataSizeCalculator : CSyncDataBase
{
uint32_t m_size;
};
}

static hook::cdecl_stub<void(rage::CSyncDataBase*, uint8_t*, char*)> _syncDataBaseSerializePlayerIndex([]()
static hook::cdecl_stub<void(rage::CSyncDataBase*, uint8_t*, char*)> _syncDataBase_SerializePlayerIndex([]()
{
return hook::get_call(hook::get_pattern("0F B6 12 48 8B 05 ? ? ? ? 44", 0x1D));
});

static void (*g_origSyncDataReaderSerializePlayerIndex)(rage::CSyncDataReader*, uint8_t*, char*);

static void SyncDataReaderSerializePlayerIndex(rage::CSyncDataReader* syncData, uint8_t* index, char* prefix)
static void (*g_origSyncDataReader_SerializePlayerIndex)(rage::CSyncDataReader*, uint8_t*, char*);
static void SyncDataReader_SerializePlayerIndex(rage::CSyncDataReader* syncData, uint8_t* index, char* prefix)
{
if (!icgi->OneSyncEnabled)
{
return g_origSyncDataReaderSerializePlayerIndex(syncData, index, prefix);
return g_origSyncDataReader_SerializePlayerIndex(syncData, index, prefix);
}

uint32_t playerNetId = -1;
Expand All @@ -1448,16 +1424,15 @@ static void SyncDataReaderSerializePlayerIndex(rage::CSyncDataReader* syncData,

*index = playerIndex;

_syncDataBaseSerializePlayerIndex(syncData, index, prefix);
_syncDataBase_SerializePlayerIndex(syncData, index, prefix);
}

static void (*g_origSyncDataWriterSerializePlayerIndex)(rage::CSyncDataWriter*, uint8_t*, char*);

static void SyncDataWriterSerializePlayerIndex(rage::CSyncDataWriter* syncData, uint8_t* index, char* prefix)
static void (*g_origSyncDataWriter_SerializePlayerIndex)(rage::CSyncDataWriter*, uint8_t*, char*);
static void SyncDataWriter_SerializePlayerIndex(rage::CSyncDataWriter * syncData, uint8_t * index, char* prefix)
{
if (!icgi->OneSyncEnabled)
{
return g_origSyncDataWriterSerializePlayerIndex(syncData, index, prefix);
return g_origSyncDataWriter_SerializePlayerIndex(syncData, index, prefix);
}

uint16_t playerNetId = -1;
Expand All @@ -1467,25 +1442,98 @@ static void SyncDataWriterSerializePlayerIndex(rage::CSyncDataWriter* syncData,
playerNetId = g_netIdsByPlayer[player];
}

_syncDataBaseSerializePlayerIndex(syncData, index, prefix);
_syncDataBase_SerializePlayerIndex(syncData, index, prefix);

syncData->m_buffer->WriteUns(playerNetId, kPlayerNetIdLength);
}

static void (*g_origSyncDataSizeCalculatorSerializePlayerIndex)(rage::CSyncDataSizeCalculator*);

static void SyncDataSizeCalculatorSerializePlayerIndex(rage::CSyncDataSizeCalculator* syncData)
static void (*g_origSyncDataSizeCalculator_SerializePlayerIndex)(rage::CSyncDataSizeCalculator*);
static void SyncDataSizeCalculator_SerializePlayerIndex(rage::CSyncDataSizeCalculator* syncData)
{
static_assert(offsetof(rage::CSyncDataSizeCalculator, m_size) == 0x18);

if (!icgi->OneSyncEnabled)
{
return g_origSyncDataSizeCalculatorSerializePlayerIndex(syncData);
return g_origSyncDataSizeCalculator_SerializePlayerIndex(syncData);
}

syncData->m_size += kPlayerNetIdLength;
}

static void (*g_origSyncDataSizeCalculator_SerializeObjectId)(rage::CSyncDataSizeCalculator*);
static void SyncDataSizeCalculator_SerializeObjectId(rage::CSyncDataSizeCalculator* syncData)
{
if (!icgi->OneSyncEnabled)
{
return g_origSyncDataSizeCalculator_SerializeObjectId(syncData);
}

syncData->m_size += (icgi->OneSyncBigIdEnabled ? 16 : 13);
}

static hook::cdecl_stub<void(rage::CSyncDataBase*, uint16_t*, char*)> _syncDataBaseSerializeObjectId([]()
{
return hook::get_call(hook::get_pattern("0F B7 03 B9 3F 1F 00 00 66 FF C8 66 3B C1 76 04", -5));
});

static void (*g_origSyncDataWriter_SerializeObjectIdPrefix)(rage::CSyncDataWriter*, uint16_t*, char*);
static void SyncDataWriter_SerializeObjectIdPrefix(rage::CSyncDataWriter* syncData, uint16_t* objectId, char* prefix)
{
if (!icgi->OneSyncEnabled)
{
return g_origSyncDataWriter_SerializeObjectIdPrefix(syncData, objectId, prefix);
}

_syncDataBaseSerializeObjectId(syncData, objectId, prefix);

syncData->m_buffer->WriteUns(*objectId, icgi->OneSyncBigIdEnabled ? 16 : 13);
}

static void (*g_origSyncDataReader_SerializeObjectIdPrefix)(rage::CSyncDataReader*, uint16_t*, char*);
static void SyncDataReader_SerializeObjectIdPrefix(rage::CSyncDataReader* syncData, uint16_t* objectId, char* prefix)
{
if (!icgi->OneSyncEnabled)
{
return g_origSyncDataReader_SerializeObjectIdPrefix(syncData, objectId, prefix);
}

uint32_t netObjectId = 0;

if (syncData->m_buffer->ReadInteger(&netObjectId, icgi->OneSyncBigIdEnabled ? 16 : 13))
{
*objectId = netObjectId;
}

_syncDataBaseSerializeObjectId(syncData, objectId, prefix);
}

static void (*g_origSyncDataWriter_SerializeObjectIdStatic)(rage::CSyncDataWriter*, uint16_t*);
static void SyncDataWriter_SerializeObjectIdStatic(rage::CSyncDataWriter* syncData, uint16_t* objectId)
{
if (!icgi->OneSyncEnabled)
{
return g_origSyncDataWriter_SerializeObjectIdStatic(syncData, objectId);
}

syncData->m_buffer->WriteUns(*objectId, icgi->OneSyncBigIdEnabled ? 16 : 13);
}

static void (*g_origSyncDataReader_SerializeObjectIdStatic)(rage::CSyncDataReader*, uint16_t*);
static void SyncDataReader_SerializeObjectIdStatic(rage::CSyncDataReader* syncData, uint16_t* objectId)
{
if (!icgi->OneSyncEnabled)
{
return g_origSyncDataReader_SerializeObjectIdStatic(syncData, objectId);
}

uint32_t netObjectId = 0;

if (syncData->m_buffer->ReadInteger(&netObjectId, icgi->OneSyncBigIdEnabled ? 16 : 13))
{
*objectId = netObjectId;
}
}

static rlGamerInfo* (*g_origNetGamePlayerGetGamerInfo)(CNetGamePlayer*);

static rlGamerInfo* NetGamePlayerGetGamerInfo(CNetGamePlayer* self)
Expand Down Expand Up @@ -2024,22 +2072,43 @@ static HookFunction hookFunction([]()
hook::call(location, playerPedGetterStub.GetCode());
}

// patch SerializePlayerIndex methods of sync data reader/writer
MH_CreateHook(hook::get_pattern("80 3B 20 73 ? 65 4C 8B 0C", -0x2F), SyncDataReaderSerializePlayerIndex, (void**)&g_origSyncDataReaderSerializePlayerIndex);
MH_CreateHook(xbr::IsGameBuildOrGreater<1436>() ? hook::get_pattern("41 B2 3F 48 8D 54 24 30 44 88", -30) : hook::get_pattern("80 3A 20 48 8B D9 C6 44", -6), SyncDataWriterSerializePlayerIndex, (void**)&g_origSyncDataWriterSerializePlayerIndex);
// CSyncedDataWriter/CSyncedDataReader::SerializeObjectID (static).
MH_CreateHook(hook::get_pattern("66 3B C1 76 ? 33 C0 EB ? 0F B7 0A", -0xE), SyncDataWriter_SerializeObjectIdStatic, (void**)&g_origSyncDataWriter_SerializeObjectIdStatic);
MH_CreateHook(hook::get_call(hook::get_pattern("E8 ? ? ? ? 48 8D 53 0A")), SyncDataReader_SerializeObjectIdStatic, (void**)&g_origSyncDataReader_SerializeObjectIdStatic);

// CSyncedDataWriter/CSyncedDataReader::SerializeObjectID (prefixed).
MH_CreateHook(hook::get_pattern("E8 ? ? ? ? 0F B7 03 B9", -0x10), SyncDataWriter_SerializeObjectIdPrefix, (void**)&g_origSyncDataWriter_SerializeObjectIdPrefix);
MH_CreateHook(hook::get_pattern("B9 ? ? ? ? 49 8B 04 ? 8A 14 01", xbr::IsGameBuildOrGreater<1491>() ? -0x36 : -0x3E), SyncDataReader_SerializeObjectIdPrefix, (void**)&g_origSyncDataReader_SerializeObjectIdPrefix);

// also patch sync data size calculator allowing more bits
// patch sync data size calculator allowing more bits
{
auto sizeCalculatorVtable = hook::get_address<uintptr_t*>(hook::get_pattern("B8 BF FF 00 00 48 8B CF 66 21 87", 27));
g_origSyncDataSizeCalculatorSerializePlayerIndex = (decltype(g_origSyncDataSizeCalculatorSerializePlayerIndex))sizeCalculatorVtable[25];
hook::put(&sizeCalculatorVtable[25], (uintptr_t)SyncDataSizeCalculatorSerializePlayerIndex);
static constexpr int kSizeCalculatorSerializePlayerIndex = 25;
static constexpr int kSizeCalculatorSerializeObjectId1 = 26;
static constexpr int kSizeCalculatorSerializeObjectId2 = 27;
static constexpr int kSizeCalculatorSerializeObjectId3 = 28;

const auto sizeCalculatorVtable = hook::get_address<uintptr_t*>(hook::get_pattern("B8 BF FF 00 00 48 8B CF 66 21 87", 27));

g_origSyncDataSizeCalculator_SerializePlayerIndex = (decltype(g_origSyncDataSizeCalculator_SerializePlayerIndex))sizeCalculatorVtable[kSizeCalculatorSerializePlayerIndex];
hook::put(&sizeCalculatorVtable[kSizeCalculatorSerializePlayerIndex], (uintptr_t)SyncDataSizeCalculator_SerializePlayerIndex);

g_origSyncDataSizeCalculator_SerializeObjectId = (decltype(g_origSyncDataSizeCalculator_SerializeObjectId))sizeCalculatorVtable[kSizeCalculatorSerializeObjectId1];
hook::put(&sizeCalculatorVtable[kSizeCalculatorSerializeObjectId1], (uintptr_t)SyncDataSizeCalculator_SerializeObjectId);
hook::put(&sizeCalculatorVtable[kSizeCalculatorSerializeObjectId2], (uintptr_t)SyncDataSizeCalculator_SerializeObjectId);
hook::put(&sizeCalculatorVtable[kSizeCalculatorSerializeObjectId3], (uintptr_t)SyncDataSizeCalculator_SerializeObjectId);
}

// patch SerializePlayerIndex methods of sync data reader/writer
MH_CreateHook(hook::get_pattern("80 3B 20 73 ? 65 4C 8B 0C", -0x2F), SyncDataReader_SerializePlayerIndex, (void**)&g_origSyncDataReader_SerializePlayerIndex);
MH_CreateHook(xbr::IsGameBuildOrGreater<1436>() ? hook::get_pattern("41 B2 3F 48 8D 54 24 30 44 88", -30) : hook::get_pattern("80 3A 20 48 8B D9 C6 44", -6), SyncDataWriter_SerializePlayerIndex, (void**)&g_origSyncDataWriter_SerializePlayerIndex);

// attempt to get some information about CNetGamePlayer::GetGamerInfo related crashes
{
static constexpr int kNetGamePlayerGetGamerInfoIndex = 12;

auto netGamePlayerVtable = hook::get_address<uintptr_t*>(hook::get_pattern("E8 ? ? ? ? 33 F6 48 8D 05 ? ? ? ? 48 8D 8B", 10));
g_origNetGamePlayerGetGamerInfo = (decltype(g_origNetGamePlayerGetGamerInfo))netGamePlayerVtable[12];
hook::put(&netGamePlayerVtable[12], (uintptr_t)NetGamePlayerGetGamerInfo);
g_origNetGamePlayerGetGamerInfo = (decltype(g_origNetGamePlayerGetGamerInfo))netGamePlayerVtable[kNetGamePlayerGetGamerInfoIndex];
hook::put(&netGamePlayerVtable[kNetGamePlayerGetGamerInfoIndex], (uintptr_t)NetGamePlayerGetGamerInfo);
}

// patch CAIConditionIsLocalPlayerVisibleToAnyPlayer behavior to properly handle scoping players
Expand Down Expand Up @@ -2422,14 +2491,6 @@ static void SkipCopyIf1s(void* a1, void* a2, void* a3, void* a4, void* a5)
}
}

#ifdef IS_RDR3
static uint64_t CSyncedVarBase__GetMaxBits(void* self)
{
// object id length + 1 extra bit
return ((icgi->OneSyncBigIdEnabled) ? 16 : 13) + 1;
}
#endif

static HookFunction hookFunction2([]()
{
// 2 matches, 1st is data, 2nd is parent
Expand Down Expand Up @@ -2457,7 +2518,6 @@ static HookFunction hookFunction2([]()
auto location = hook::get_pattern<char>("49 89 43 C8 E8 ? ? ? ? 84 C0 0F 95 C0 48 83 C4 58", -0x3E);
hook::set_call(&g_origWriteDataNode, location + 0x42);
#endif

hook::jump(location, WriteDataNodeStub);
#endif
}
Expand Down
36 changes: 36 additions & 0 deletions code/components/gta-net-five/src/rlNetBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ static hook::cdecl_stub<bool(void*, uint32_t*, int)> _netBuffer_ReadInteger([]()
#endif
});

#ifdef IS_RDR3
static hook::cdecl_stub<bool(void*, uint64_t, int)> _netBuffer_writeWord([]()
{
return hook::get_pattern("48 8B 74 24 ? 48 83 C4 ? 5F C3 90 B4 ? 8B C4", -0x63);
});

static hook::cdecl_stub<bool(void*, uint8_t, int)> _netBuffer_writeByte([]()
{
return hook::get_pattern("48 8B 5C 24 ? 40 8A C7 48 8B 74 24 ? 48 83 C4 ? 5F C3 90 49 48 89 5C 24", -0x5B);
});
#endif

static void(*g_orig_netBuffer_ReadUnsigned)(void* a1, uint32_t* a2, int length, int a4);
static void _netBuffer_ReadUnsigned(void* a1, uint32_t* a2, int length, int a4)
{
Expand Down Expand Up @@ -105,10 +117,34 @@ namespace rage
return _netBuffer_ReadInteger(this, integer, bits);
}

bool datBitBuffer::ReadBit(bool* bit)
{
uint32_t result = 0;
if (ReadInteger(&result, 1))
{
*bit = (result == 1);
return true;
}

return false;
}

bool datBitBuffer::WriteInteger(uint32_t integer, int bits)
{
return _netBuffer_WriteInteger(this, integer, bits);
}

#ifdef IS_RDR3
bool datBitBuffer::WriteWord(uint64_t integer, int bits)
{
return _netBuffer_writeWord(this, integer, bits);
}

bool datBitBuffer::WriteByte(uint8_t byte, int bits)
{
return _netBuffer_writeByte(this, byte, bits);
}
#endif

bool datBitBuffer::WriteUns(uint32_t integer, int bits)
{
Expand Down
1 change: 1 addition & 0 deletions code/components/gta-net-rdr3/component.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ return function()
files {
'components/gta-net-five/include/CloneManager.h',
'components/gta-net-five/include/FramePacketHandler.h',
'components/gta-net/five/include/ObjectIdPacketHandler.h',
'components/gta-net-five/src/ClientRPC.cpp',
'components/gta-net-five/src/CloneDebug.cpp',
'components/gta-net-five/src/CloneExperiments.cpp',
Expand Down
32 changes: 32 additions & 0 deletions code/components/gta-net-rdr3/include/netObjectMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <netObject.h>
#include <CrossBuildRuntime.h>
#include <rlNetBuffer.h>

class CNetGamePlayer;

Expand Down Expand Up @@ -90,4 +91,35 @@ class netObjectMgr

static netObjectMgr* GetInstance();
};

enum eSyncDataSerializer : uint8_t
{
SYNC_DATA_UNKNOWN = 0x0,
SYNC_DATA_READER = 0x1,
SYNC_DATA_WRITER = 0x2,
SYNC_DATA_CLEANER = 0x3,
SYNC_DATA_UNK = 0x4,
};

struct CSyncDataBase
{
char m_pad1[8];
eSyncDataSerializer m_type;
char m_pad[15];
};

struct CSyncDataReader : CSyncDataBase
{
datBitBuffer* m_buffer;
};

struct CSyncDataWriter : CSyncDataBase
{
datBitBuffer* m_buffer;
};

struct CSyncDataSizeCalculator : CSyncDataBase
{
uint32_t m_size;
};
}
6 changes: 6 additions & 0 deletions code/components/gta-net-rdr3/include/rlNetBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,17 @@ class datBitBuffer
return (m_curBit / 8) + leftoverBit;
}

bool ReadBit(bool* bit);

bool ReadInteger(uint32_t* integer, int bits);

// NOTE: SIGNED
bool WriteInteger(uint32_t integer, int bits);

bool WriteWord(uint64_t integer, int bits);

bool WriteByte(uint8_t byte, int bits);

bool WriteUns(uint32_t integer, int bits);

bool WriteBit(bool bit);
Expand Down
Loading