Fix css_unban / css_unmute silently failing on SQLite (long -> int via dynamic binder)#285
Open
playaopindo-dev wants to merge 1 commit into
Open
Conversation
On SQLite, INTEGER PRIMARY KEY AUTOINCREMENT values flow through
Dapper as boxed long. `int banId = ban.id;` / `int muteId = mute.id;`
against a dynamic row triggers RuntimeBinderException
("Cannot implicitly convert type 'long' to 'int'") before any
INSERT/UPDATE runs, and the surrounding bare `catch { }` in
BanManager.UnbanPlayer swallows it — leaving sa_bans.status='ACTIVE',
sa_unbans empty, and the admin staring at a cosmetic
"Unbanned with pattern X." reply. MySQL is unaffected because
MySqlConnector materialises INT as int.
Normalise the conversion path via Convert.ToInt32((object)x.id),
which handles both boxed int (MySQL) and boxed long (SQLite)
without invoking the C# dynamic binder. Same pattern fixed in
both UnbanPlayer and UnmutePlayer.
Also tighten BanManager.UnbanPlayer's bare `catch { }` to log via
the existing CS2_SimpleAdmin.Instance.Logger, matching the style
of BanPlayer/AddBanBySteamid/AddBanByIp in the same file. This is
what surfaced the bug during root-cause analysis.
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.
Fix
css_unban/css_unmutesilently failing on SQLiteFixes #284
Summary
css_unban,!unban,css_unmute,css_ungag,css_unsilenceall print their cosmetic success message but never write to the database on SQLite. Root cause: in bothBanManager.UnbanPlayerandMuteManager.UnmutePlayer, the row id is read viaint x = row.id;against a Dapperdynamic. On SQLite the value is boxed aslong, the C#dynamicbinder refuses the implicitlong→intconversion at runtime and throwsRuntimeBinderExceptionbefore either INSERT or UPDATE runs. The surrounding barecatch { }then swallows it — no log, no DB write, but the admin already saw "Unbanned with pattern X". MySQL is unaffected becauseMySqlConnectormaterialisesINTasintdirectly.Full repro, exception trace, and caller-format matrix in the linked issue.
Changes
Three minimal hunks against
eea700b:BanManager.cs::UnbanPlayer—int banId = ban.id;→int banId = Convert.ToInt32((object)ban.id);. The(object)cast bypasses thedynamicbinder soConvert.ToInt32resolves the well-definedobjectoverload, which handles both boxedint(MySQL) and boxedlong(SQLite) without runtime binding surprises.MuteManager.cs::UnmutePlayer— same one-line change at the correspondingint muteId = mute.id;.BanManager.cs::UnbanPlayer— barecatch { }replaced bycatch (Exception ex) { CS2_SimpleAdmin.Instance?.Logger?.LogError(ex, "UnbanPlayer failed for pattern {Pattern}", playerPattern); }. This matches the logging style already used by every othertry/catchin the same file (BanPlayer,AddBanBySteamid,AddBanByIp). Without this hunk the original bug would have been impossible to root-cause from logs alone; keeping it as a guard is what surfaced the issue in the first place. Drop this hunk if you prefer to land the behavioural fix in isolation.MuteManager.UnmutePlayer's existingcatch (Exception ex) { Console.WriteLine(ex); }is left untouched in this PR — its routing toConsole.WriteLine(which writes to the CS2 console scrollback but not to the rolling SA log file) is also worth tightening, but that's a separate cleanup and out of scope for this fix.Test plan
css_unban <steamid>from server console pre-fix →RuntimeBinderExceptionsurfaced via the loggingcatch,sa_bans.statusstayedACTIVE,sa_unbansempty.sa_bans.status='UNBANNED',sa_bans.unban_idpopulated,sa_unbansrow inserted with matchingban_id, no exception inlog-CS2-SimpleAdmin*.txt.dotnet build -c Releaseclean (0 warnings, 0 errors) againstnet8.0.MySqlConnectorreturnsINTasint,Convert.ToInt32((object)int)returns the sameint, so the loop body executes identically to before. A second pair of eyes on a MySQL deployment would be welcome before merge.css_unmutesmoke test on SQLite at merge time.Notes
Diff is intentionally tight. The bigger architectural smell —
Task.Run(async () => await ...)fire-and-forget inOnUnbanCommandpaired with the pre-emptive cosmetic success reply — is what made this bug invisible to admins for so long. I'd happily follow up with a separate PR that funnels these through a small result type so command replies reflect actual outcomes, if there's appetite for that direction.Tested SA version:
1.7.9a(eea700b). Repo branch:main.