Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feature: onesync: experimental 16-bit ID mode (onesync_enableBeyond)
  • Loading branch information
blattersturm committed Feb 4, 2020
1 parent b9ff85b commit e1b1d58
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 45 deletions.
2 changes: 2 additions & 0 deletions code/client/shared/ICoreGameInit.h
Expand Up @@ -33,6 +33,8 @@ class ICoreGameInit

bool OneSyncEnabled = false;

bool OneSyncBigIdEnabled = false;

uint64_t NetProtoVersion = 0;

private:
Expand Down
Expand Up @@ -17,6 +17,14 @@ void* operator new[](size_t size, size_t alignment, size_t alignmentOffset, cons
return ::operator new[](size);
}

namespace rl
{
bool MessageBuffer::GetLengthHackState()
{
return false;
}
}

constexpr const uint32_t kPacketSizeBits = 17;
constexpr const uint32_t kFragmentSize = 1024 - 1;
constexpr const uint32_t kFragmentSizeBits = 10;
Expand Down
Expand Up @@ -315,7 +315,7 @@ struct AckPacketWrapper
}
};

static constexpr const int MaxObjectId = 1 << 13;
static constexpr const int MaxObjectId = (1 << 16) - 1;

struct GameStateClientData : public sync::ClientSyncDataBase
{
Expand Down Expand Up @@ -414,9 +414,9 @@ class ServerGameState : public fwRefCountable, public fx::IAttached<fx::ServerIn
// as bitset is not thread-safe
std::mutex m_objectIdsMutex;

eastl::bitset<8192> m_objectIdsSent;
eastl::bitset<8192> m_objectIdsUsed;
eastl::bitset<8192> m_objectIdsStolen;
eastl::bitset<MaxObjectId> m_objectIdsSent;
eastl::bitset<MaxObjectId> m_objectIdsUsed;
eastl::bitset<MaxObjectId> m_objectIdsStolen;

uint64_t m_frameIndex;

Expand Down
2 changes: 2 additions & 0 deletions code/components/citizen-server-impl/src/GameServer.cpp
Expand Up @@ -1154,6 +1154,8 @@ namespace fx
{
if (targetNetId == 0xFFFF)
{
client->SetHasRouted();

instance->GetComponent<fx::ServerGameState>()->ParseGameStatePacket(client, packetData);

return;
Expand Down
3 changes: 3 additions & 0 deletions code/components/citizen-server-impl/src/InitConnectMethod.cpp
Expand Up @@ -42,6 +42,8 @@ void RegisterServerIdentityProvider(ServerIdentityProviderBase* provider)
g_serverProviders.push_front(provider);
g_providersByType.insert({ provider->GetIdentifierPrefix(), provider });
}

extern bool IsLengthHack();
}

static bool VerifyTicket(const std::string& guid, const std::string& ticket)
Expand Down Expand Up @@ -371,6 +373,7 @@ static InitFunction initFunction([]()
data["enhancedHostSupport"] = ehVar->GetValue() && !g_oneSyncVar->GetValue();
data["onesync"] = g_oneSyncVar->GetValue();
data["onesync_big"] = fx::IsBigMode();
data["onesync_lh"] = fx::IsLengthHack();
data["token"] = token;
data["gamename"] = gameName;

Expand Down
41 changes: 30 additions & 11 deletions code/components/citizen-server-impl/src/state/ServerGameState.cpp
Expand Up @@ -24,13 +24,27 @@
#include <DebugAlias.h>

static bool g_bigMode;
static bool g_lengthHack;

namespace fx
{
bool IsBigMode()
{
return g_bigMode;
}

bool IsLengthHack()
{
return g_lengthHack;
}
}

namespace rl
{
bool MessageBuffer::GetLengthHackState()
{
return g_lengthHack;
}
}

CPool<fx::ScriptGuid>* g_scriptHandlePool;
Expand All @@ -44,6 +58,7 @@ std::shared_ptr<ConVar<bool>> g_oneSyncRadiusFrequency;
std::shared_ptr<ConVar<std::string>> g_oneSyncLogVar;
std::shared_ptr<ConVar<bool>> g_oneSyncWorkaround763185;
std::shared_ptr<ConVar<bool>> g_oneSyncBigMode;
std::shared_ptr<ConVar<bool>> g_oneSyncLengthHack;

static tbb::concurrent_queue<std::string> g_logQueue;

Expand Down Expand Up @@ -335,7 +350,7 @@ glm::vec3 GetPlayerFocusPos(const std::shared_ptr<sync::SyncEntityState>& entity
}

ServerGameState::ServerGameState()
: m_frameIndex(0), m_entitiesById(1 << 13)
: m_frameIndex(0), m_entitiesById(MaxObjectId)
{
m_tg = std::make_unique<ThreadPool>();
}
Expand Down Expand Up @@ -537,7 +552,7 @@ void ServerGameState::Tick(fx::ServerInstanceBase* instance)
sync::CVehicleGameStateNodeData*,
std::shared_ptr<fx::Client>
>
> relevantEntities(8192);
> relevantEntities(MaxObjectId);

{
std::shared_lock<std::shared_mutex> lock(m_entityListMutex);
Expand Down Expand Up @@ -575,7 +590,7 @@ void ServerGameState::Tick(fx::ServerInstanceBase* instance)
entityClient = entity->client.lock();
}

relevantEntities[entity->handle & 0x1FFF] = { entity, entityPosition, vehicleData, entityClient };
relevantEntities[entity->handle & 0xFFFF] = { entity, entityPosition, vehicleData, entityClient };
}
}

Expand Down Expand Up @@ -1146,15 +1161,13 @@ void ServerGameState::Tick(fx::ServerInstanceBase* instance)
// NOTE: this is a thread hazard, but generally it doesn't matter if the bitset is inconsistent here
// all that'll happen is we'll send a removal _later_, or send _duplicates_, both of which are typically fine.
auto clientData = GetClientDataUnlocked(this, cmdState.client);
auto& ref = clientData->pendingRemovals;

for (uint16_t i = 0; i < MaxObjectId; i++)
for (auto i = ref.find_first(); i != ref.size(); i = ref.find_next(i))
{
if (clientData->pendingRemovals.test(i))
{
cmdState.cloneBuffer.Write(3, 3);
cmdState.cloneBuffer.Write(13, i);
cmdState.maybeFlushBuffer();
}
cmdState.cloneBuffer.Write(3, 3);
cmdState.cloneBuffer.Write(13, int32_t(i));
cmdState.maybeFlushBuffer();
}
});
}
Expand Down Expand Up @@ -2394,7 +2407,7 @@ void ServerGameState::SendObjectIds(const std::shared_ptr<fx::Client>& client, i
auto [data, lock] = GetClientData(this, client);
std::unique_lock<std::mutex> objectIdsLock(m_objectIdsMutex);

int id = 1;
int id = (g_lengthHack) ? 8193 : 1;

for (int i = 0; i < numIds; i++)
{
Expand Down Expand Up @@ -2634,9 +2647,15 @@ static InitFunction initFunction([]()

fx::ServerInstanceBase::OnServerCreate.Connect([](fx::ServerInstanceBase* instance)
{
// .. to infinity?
g_oneSyncBigMode = instance->AddVariable<bool>("onesync_enableInfinity", ConVar_None, false);

g_bigMode = g_oneSyncBigMode->GetValue();

// or maybe, beyond?
g_oneSyncLengthHack = instance->AddVariable<bool>("onesync_enableBeyond", ConVar_None, false);

g_lengthHack = g_oneSyncLengthHack->GetValue();
}, INT32_MIN);

fx::ServerInstanceBase::OnServerCreate.Connect([](fx::ServerInstanceBase* instance)
Expand Down
13 changes: 12 additions & 1 deletion code/components/gta-net-five/src/CloneDebug.cpp
Expand Up @@ -430,7 +430,18 @@ bool netSyncTree::WriteTreeCfx(int flags, int objFlags, rage::netObject* object,
}

// #NETVER: 2018-12-27 17:41 -> increased maximum packet size to 768 from 256 to account for large CPlayerAppearanceDataNode
int sizeLength = (Instance<ICoreGameInit>::Get()->NetProtoVersion >= 0x201812271741) ? 13 : 11;
static auto icgi = Instance<ICoreGameInit>::Get();

int sizeLength = 13;

if (icgi->OneSyncBigIdEnabled)
{
sizeLength = 16;
}
else if (icgi->NetProtoVersion < 0x201812271741)
{
sizeLength = 11;
}

TraverseTree<WriteTreeState>(this, state, [sizeLength](WriteTreeState& state, rage::netSyncNodeBase* node, const std::function<bool()>& cb)
{
Expand Down
2 changes: 1 addition & 1 deletion code/components/gta-net-five/src/CloneExperiments.cpp
Expand Up @@ -27,7 +27,7 @@ extern NetLibrary* g_netLibrary;

class CNetGamePlayer;

static ICoreGameInit* icgi;
ICoreGameInit* icgi;

namespace rage
{
Expand Down
112 changes: 85 additions & 27 deletions code/components/gta-net-five/src/rlNetBuffer.cpp
@@ -1,17 +1,37 @@
#include <StdInc.h>
#include <Hooking.h>
#include <MinHook.h>

#include <rlNetBuffer.h>
#include <state/RlMessageBuffer.h>

#include <ICoreGameInit.h>

extern ICoreGameInit* icgi;

namespace rl
{
bool MessageBuffer::GetLengthHackState()
{
return icgi->OneSyncBigIdEnabled;
}
}

static hook::cdecl_stub<bool(void*, uint32_t, int)> _netBuffer_WriteInteger([]()
{
return hook::get_pattern("48 8B D9 40 84 79 1C 75 6F 8B 49 10", -0x29);
});

static hook::cdecl_stub<void(void*, uint32_t, int, int)> _netBuffer_WriteUnsigned([]()
static bool(*g_orig_netBuffer_WriteUnsigned)(void* a1, uint32_t a2, int length, int a4);
static bool _netBuffer_WriteUnsigned(void* a1, uint32_t a2, int length, int a4)
{
return hook::get_pattern("49 C1 FA 03 41 83 E1 07 4C 03 D1 B9 20 00 00 00", -0xE);
});
if (length == 13 && icgi->OneSyncBigIdEnabled)
{
length = 16;
}

return g_orig_netBuffer_WriteUnsigned(a1, a2, length, a4);
}

static hook::cdecl_stub<bool(void*, bool)> _netBuffer_WriteBit([]()
{
Expand All @@ -23,48 +43,86 @@ static hook::cdecl_stub<bool(void*, uint32_t*, int)> _netBuffer_ReadInteger([]()
return hook::get_pattern("8B 44 24 30 8B D6 48 8B CB 89 07 E8", -0x50);
});

static hook::cdecl_stub<void(rage::datBitBuffer*, int)> _netBuffer_BumpReadWriteCursor([]()
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)
{
return hook::get_pattern("01 51 10 8B 41 10 3B 41 14 7E 03");
});
if (length == 13 && icgi->OneSyncBigIdEnabled)
{
length = 16;
}

namespace rage
{
bool datBitBuffer::ReadInteger(uint32_t* integer, int bits)
{
return _netBuffer_ReadInteger(this, integer, bits);
return g_orig_netBuffer_ReadUnsigned(a1, a2, length, a4);
}

bool datBitBuffer::WriteInteger(uint32_t integer, int bits)
static void(*g_orig_netBuffer_BumpReadWriteCursor)(rage::datBitBuffer* a1, int length);
static void _netBuffer_BumpReadWriteCursor(rage::datBitBuffer* a1, int length)
{
return _netBuffer_WriteInteger(this, integer, bits);
if (length == 13 && icgi->OneSyncBigIdEnabled)
{
length = 16;
}

return g_orig_netBuffer_BumpReadWriteCursor(a1, length);
}

bool datBitBuffer::WriteUns(uint32_t integer, int bits)
static void(*g_orig_netBuffer_BumpWriteCursor)(rage::datBitBuffer* a1, int length);
static void _netBuffer_BumpWriteCursor(rage::datBitBuffer* a1, int length)
{
// this method only exists inlined in GTA V so we have to manually implement it
if (m_f1C & 1)
if (length == 13 && icgi->OneSyncBigIdEnabled)
{
return false;
length = 16;
}

if (m_unkBit + bits > m_maxBit)
return g_orig_netBuffer_BumpWriteCursor(a1, length);
}

namespace rage
{
bool datBitBuffer::ReadInteger(uint32_t* integer, int bits)
{
return false;
return _netBuffer_ReadInteger(this, integer, bits);
}

if (!(m_f1C & 2))
bool datBitBuffer::WriteInteger(uint32_t integer, int bits)
{
_netBuffer_WriteUnsigned(m_data, integer, bits, m_f8 + m_unkBit);
return _netBuffer_WriteInteger(this, integer, bits);
}

_netBuffer_BumpReadWriteCursor(this, bits);
bool datBitBuffer::WriteUns(uint32_t integer, int bits)
{
// this method only exists inlined in GTA V so we have to manually implement it
if (m_f1C & 1)
{
return false;
}

if (m_unkBit + bits > m_maxBit)
{
return false;
}

return true;
if (!(m_f1C & 2))
{
_netBuffer_WriteUnsigned(m_data, integer, bits, m_f8 + m_unkBit);
}

_netBuffer_BumpReadWriteCursor(this, bits);

return true;
}

bool datBitBuffer::WriteBit(bool bit)
{
return _netBuffer_WriteBit(this, bit);
}
}

bool datBitBuffer::WriteBit(bool bit)
static HookFunction hookFunction([]()
{
return _netBuffer_WriteBit(this, bit);
}
}
MH_Initialize();
MH_CreateHook(hook::get_pattern("01 51 10 8B 41 10 3B 41 14 7E 03"), _netBuffer_BumpReadWriteCursor, (void**)&g_orig_netBuffer_BumpReadWriteCursor);
MH_CreateHook(hook::get_pattern("01 51 10 8B 41 10 3B 41 18 7E 03"), _netBuffer_BumpWriteCursor, (void**)&g_orig_netBuffer_BumpWriteCursor);
MH_CreateHook(hook::get_pattern("41 83 E1 07 45 8B D8 49 C1 FA 03 BB 08 00 00 00", -0x12), _netBuffer_ReadUnsigned, (void**)&g_orig_netBuffer_ReadUnsigned);
MH_CreateHook(hook::get_pattern("49 C1 FA 03 41 83 E1 07 4C 03 D1 B9 20 00 00 00", -0xE), _netBuffer_WriteUnsigned, (void**)&g_orig_netBuffer_WriteUnsigned);
MH_EnableHook(MH_ALL_HOOKS);
});
2 changes: 1 addition & 1 deletion code/components/lovely-script/src/Lovely.cpp
Expand Up @@ -79,7 +79,7 @@ class LovelyThread : public GtaThread
virtual void DoRun() override
{
// TEMP: force-disable population for 1s big using script
if (Instance<ICoreGameInit>::Get()->HasVariable("onesync_big"))
if (Instance<ICoreGameInit>::Get()->HasVariable("onesync_big") && !Instance<ICoreGameInit>::Get()->OneSyncBigIdEnabled)
{
for (int i = 1; i <= 15; i++)
{
Expand Down
1 change: 1 addition & 0 deletions code/components/net/src/NetLibrary.cpp
Expand Up @@ -1198,6 +1198,7 @@ concurrency::task<void> NetLibrary::ConnectToServer(const std::string& rootUrl)

Instance<ICoreGameInit>::Get()->EnhancedHostSupport = (!node["enhancedHostSupport"].is_null() && node.value("enhancedHostSupport", false));
Instance<ICoreGameInit>::Get()->OneSyncEnabled = (!node["onesync"].is_null() && node["onesync"].get<bool>());
Instance<ICoreGameInit>::Get()->OneSyncBigIdEnabled = (!node["onesync_lh"].is_null() && node["onesync_lh"].get<bool>());
Instance<ICoreGameInit>::Get()->NetProtoVersion = (!node["bitVersion"].is_null() ? node["bitVersion"].get<uint64_t>() : 0);

bool big1s = (!node["onesync_big"].is_null() && node["onesync_big"].get<bool>());
Expand Down

0 comments on commit e1b1d58

Please sign in to comment.