Fix #5 — player_stats buffer truncation + tank/witch FK race on map resolve#6
Open
draxios wants to merge 1 commit into
Open
Fix #5 — player_stats buffer truncation + tank/witch FK race on map resolve#6draxios wants to merge 1 commit into
draxios wants to merge 1 commit into
Conversation
Bug A — query buffer truncation in player_stats upsert ------------------------------------------------------- Bizzy_Session_Flush builds a wide INSERT INTO player_stats … ON DUPLICATE KEY UPDATE statement into a stack `char sql[2048]`. After the schema grew through migration 010 the rendered statement exceeded that buffer and FormatEx silently truncated, depending on the per-int substitution widths. MySQL then rejected the malformed statement, surfacing as: Unknown column 'damage_to_ta' / 'damage_to_tan' Unknown column 'VALUE' / 'VALU' / 'V' You have an error in your SQL syntax … near '' at line 1 …and the entire flush transaction was dropped, losing the session's accumulated counters. Bump the buffer to 4096 with a clear comment + #5 reference. Long-term fix (parameterized queries — no string-build) is noted there as the follow-up; this is the safe tactical fix to stop bleeding data. Bug B — tank_records.fk_tr_map FK violation on boss spawn --------------------------------------------------------- `g_CurrentMapId` is the resolved `maps.id` for the active map and is populated through a two-step async chain (INSERT IGNORE INTO maps → SELECT id → set g_CurrentMapId) kicked off from `OnMapStart`. On a plugin hot-reload mid-map or a DB connection that completes after `OnMapStart` has already fired, `g_CurrentMapId` stays at 0 and any boss insert (tank_records / witch_records) FK-violates against maps.id. Three-part fix: - `OnServerLookup` (the DB-ready callback) now calls `Bizzy_Identity_ResolveMap()` after setting `g_ServerId`. Covers the late-DB-connect / hot-reload-mid-map case. - `Bizzy_Identity_ResolveMap` now refreshes `g_CurrentMap` from the engine via `GetCurrentMap()` on every call, so it doesn't no-op when invoked from a code path other than `OnMapStart`. - Tank- and witch-spawn inserts in tank_witch.sp now bail early when `g_CurrentMapId == 0`. Defensive — converts any remaining edge case from a noisy FK error to a silently dropped boss record. Files touched ------------- plugin/scripting/bizzymod_stats/session.sp - sql buffer 2048→4096 plugin/scripting/bizzymod_stats/identity.sp - resolve on DB-ready; refresh on every call plugin/scripting/bizzymod_stats/tank_witch.sp - g_CurrentMapId guards CHANGELOG.md - [0.6.1] entry Refs #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #5.
Two production bugs surfaced on the Campaign server from yesterday's diagnose. Both are SourcePawn-side, not schema. Tactical fixes that stop the bleeding now; longer-term refactor (parameterized queries for the wide upserts) is noted but out of scope here.
Bug A — query buffer truncation in
Bizzy_Session_Flushsession.spbuilds a wideINSERT INTO player_stats … ON DUPLICATE KEY UPDATE …statement (35+ columns each side) into a stackchar sql[2048]. After migration 010 grew the schema, the rendered statement passed 2048 bytes once you account for%dsubstitutions.FormatExsilently truncated, and the truncation point varied with the actual integer-digit widths — which is exactly the pattern in the log:The whole
txn.AddQuery(sql)for player_stats was being rejected by MySQL, dropping the entire transaction — meaning the session's accumulated counters never landed. Players were losing real stats on every map flush.Fix: bump
sql[2048]→sql[4096]in the one offending function. Comment explains the bug, links #5, and notes that the right long-term answer is parameterized queries so we don't string-build a 3KB statement on the stack at all.Bug B —
tank_records.fk_tr_mapFK violationg_CurrentMapIdis the resolvedmaps.idfor the active map. It's populated through a two-step async chain kicked off byBizzy_OnMapStart:That works the first time
OnMapStartfires. But it misses two real cases:OnMapStartalready fired before the reload; on the fresh plugin instance it won't fire again until the next map.g_CurrentMapis empty andg_CurrentMapIdis 0.OnMapStart— server boot races.OnMapStartfired withg_DB == null, soResolveMapno-op'd. By the time the DB connects, we've missed our cue.Both states leave
g_CurrentMapId = 0. The next tank or witch spawn insertsmap_id=0, which doesn't exist inmaps, and the FK constraintfk_tr_maprejects the row.Fix: three coordinated changes:
identity.spOnServerLookupg_ServerIdis set, callBizzy_Identity_ResolveMap(). Handles the DB-late case and the hot-reload case in one place — by the time DB-ready fires, we know we have a stable connection and we trigger the resolve ourselves rather than waiting for the nextOnMapStart.identity.spBizzy_Identity_ResolveMapg_CurrentMapfrom the engine viaGetCurrentMap()at the top of the function. Doesn't matter who called us or whetherOnMapStartpopulated the global yet — we read fresh each time. Idempotent, cheap.tank_witch.sptank-spawn + witch-spawng_CurrentMapId == 0to the early-return guards. Defensive — if the above two fixes ever miss an edge case, the failure mode becomes "lose one boss record" instead of "FK error in errors_*.log".What's NOT in this PR
database.sp. Considered, decided not worth the scope here — bumping the single offender's buffer is sufficient.web/orschema/. Schema is fine; the FK constraint is doing its job (catching the race).Test plan
release.ymlshould compile bizzymod_stats.smx cleanly with no new warnings.tank_records.v0.6.1onmain. Rename the## [0.6.1] — UNRELEASEDheading in CHANGELOG to today's date when tagging (or do it as part of the tag prep commit — either flow works).BIZZYMOD_STATS_TAGinbogware/bizzymod-campaign/.github/workflows/deploy.ymlfromv0.6.0→v0.6.1. (Tracked in bogware/bizzymod-campaign#4 wire-up.)🤖 Generated with Claude Code