Skip to content

Commit fcafd07

Browse files
authored
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.
1 parent 1998021 commit fcafd07

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

extensions/sdktools/extension.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,19 @@ extern sp_nativeinfo_t g_ClientNatives[];
101101

102102
static void InitSDKToolsAPI();
103103

104+
#if SOURCE_ENGINE == SE_CSGO
105+
CDetour *g_WriteBaselinesDetour = NULL;
106+
107+
DETOUR_DECL_MEMBER3(CNetworkStringTableContainer__WriteBaselines, void, char const *, mapName, void *, buffer, int, currentTick)
108+
{
109+
// Replace nAtTick with INT_MAX to work around CS:GO engine bug.
110+
// Due to a timing issue in the engine, stringtable entries added in OnConfigsExecuted can be considered
111+
// to have been added in the future for the first client that connects, which causes them to be ignored
112+
// when iterating for networking, which triggers a Host_Error encoding the CreateStringTable netmsg.
113+
return DETOUR_MEMBER_CALL(CNetworkStringTableContainer__WriteBaselines)(mapName, buffer, INT_MAX);
114+
}
115+
#endif
116+
104117
bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late)
105118
{
106119
HandleError err;
@@ -186,6 +199,13 @@ bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late)
186199
m_CSGOBadList.init();
187200
m_CSGOBadList.add("m_bIsValveDS");
188201
m_CSGOBadList.add("m_bIsQuestEligible");
202+
203+
g_WriteBaselinesDetour = DETOUR_CREATE_MEMBER(CNetworkStringTableContainer__WriteBaselines, "WriteBaselines");
204+
if (g_WriteBaselinesDetour) {
205+
g_WriteBaselinesDetour->EnableDetour();
206+
} else {
207+
g_pSM->LogError(myself, "Failed to find WriteBaselines signature -- stringtable error workaround disabled.");
208+
}
189209
#endif
190210

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

240+
#if SOURCE_ENGINE == SE_CSGO
241+
if (g_WriteBaselinesDetour) {
242+
g_WriteBaselinesDetour->DisableDetour();
243+
g_WriteBaselinesDetour = NULL;
244+
}
245+
#endif
246+
220247
if (g_pAcceptInput)
221248
{
222249
g_pAcceptInput->Destroy();

gamedata/sdktools.games/engine.csgo.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,5 +348,18 @@
348348
"mac64" "279"
349349
}
350350
}
351+
"Signatures"
352+
{
353+
/**
354+
* CNetworkStringTableContainer::WriteBaselines
355+
* "Index error writing string table baseline %s\n"
356+
*/
357+
"WriteBaselines"
358+
{
359+
"library" "engine"
360+
"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"
361+
"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"
362+
}
363+
}
351364
}
352365
}

0 commit comments

Comments
 (0)