Skip to content
Permalink
Browse files

Workaround CS:GO Stringtable bug (#1046)

The cause of the infamous "Index error writing string table baseline"
error appears to be a timing issue between the engine's network message
processing, the stringtable encoding, and command processing when adding
stringtable entries in OnConfigsExecuted.

When the first client connects the map is re-loaded which causes a full
refresh, the game's stringtable entries are added at tick 65, the client
connection is registered at tick 66, and stringtable entries added in
OnConfigsExecuted are registered as being added in tick 67. The engine
later calls WriteBaselines with the client's signon tick, and neglects
to encode the SM added entries as it considers them from the future.

To avoid this, always pass INT_MAX as the current tick when encoding
the baseline, so all stringtable entries are included regardless of when
they were added. Tested on both Windows and Linux.
  • Loading branch information...
asherkin committed Jul 19, 2019
1 parent 1998021 commit fcafd0784cadde36b21e0a4f36867603d49a88b4
Showing with 40 additions and 0 deletions.
  1. +27 −0 extensions/sdktools/extension.cpp
  2. +13 −0 gamedata/sdktools.games/engine.csgo.txt
@@ -101,6 +101,19 @@ extern sp_nativeinfo_t g_ClientNatives[];

static void InitSDKToolsAPI();

#if SOURCE_ENGINE == SE_CSGO
CDetour *g_WriteBaselinesDetour = NULL;

DETOUR_DECL_MEMBER3(CNetworkStringTableContainer__WriteBaselines, void, char const *, mapName, void *, buffer, int, currentTick)
{
// Replace nAtTick with INT_MAX to work around CS:GO engine bug.
// Due to a timing issue in the engine, stringtable entries added in OnConfigsExecuted can be considered
// to have been added in the future for the first client that connects, which causes them to be ignored
// when iterating for networking, which triggers a Host_Error encoding the CreateStringTable netmsg.
return DETOUR_MEMBER_CALL(CNetworkStringTableContainer__WriteBaselines)(mapName, buffer, INT_MAX);
}
#endif

bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late)
{
HandleError err;
@@ -186,6 +199,13 @@ bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late)
m_CSGOBadList.init();
m_CSGOBadList.add("m_bIsValveDS");
m_CSGOBadList.add("m_bIsQuestEligible");

g_WriteBaselinesDetour = DETOUR_CREATE_MEMBER(CNetworkStringTableContainer__WriteBaselines, "WriteBaselines");
if (g_WriteBaselinesDetour) {
g_WriteBaselinesDetour->EnableDetour();
} else {
g_pSM->LogError(myself, "Failed to find WriteBaselines signature -- stringtable error workaround disabled.");
}
#endif

return true;
@@ -217,6 +237,13 @@ void SDKTools::SDK_OnUnload()
g_RegCalls.clear();
ShutdownHelpers();

#if SOURCE_ENGINE == SE_CSGO
if (g_WriteBaselinesDetour) {
g_WriteBaselinesDetour->DisableDetour();
g_WriteBaselinesDetour = NULL;
}
#endif

if (g_pAcceptInput)
{
g_pAcceptInput->Destroy();
@@ -348,5 +348,18 @@
"mac64" "279"
}
}
"Signatures"
{
/**
* CNetworkStringTableContainer::WriteBaselines
* "Index error writing string table baseline %s\n"
*/
"WriteBaselines"
{
"library" "engine"
"windows" "\x55\x8B\xEC\x83\xEC\x60\x53\x56\x8B\xF1\x8B\x0D\x2A\x2A\x2A\x2A\x57\x89\x75\xF8\x8B\x81\x2A\x2A\x2A\x2A\x89\x45\xF4\x85\xC0"
"linux" "\x55\x89\xE5\x57\x56\x53\x81\xEC\x8C\x00\x00\x00\x8B\x0D\x2A\x2A\x2A\x2A\x8B\x75\x08\x8B\x5D\x0C\x8B\x7D\x10\x85\xC9"
}
}
}
}

0 comments on commit fcafd07

Please sign in to comment.
You can’t perform that action at this time.