Skip to content

fix(core): harden config init, dedupe weapon tracking, style cleanup - #27

Merged
Rushaway merged 4 commits into
masterfrom
fix/late-load-timer-and-init
Sep 15, 2026
Merged

Rushaway merged 4 commits into
masterfrom
fix/late-load-timer-and-init

Conversation

@Rushaway

@Rushaway Rushaway commented Sep 10, 2026

Copy link
Copy Markdown
Member

Summary

While reviewing the plugin I found a few bugs and rough edges. This PR fixes them with minimal, surgical changes.

1. Config values read before the config is executed (bug / fragility)

g_MaxWeapons and g_MaxWeaponLifetime were read from ConVar.IntValue immediately after CreateConVar, i.e. before AutoExecConfig runs. It only happened to work because the change hook fires when the generated cfg is executed. Added OnConfigsExecuted() to read the effective values at the correct time (also runs on late load). The OnPluginStart reads are kept as a safe default for the tiny window in between.

2. FindConVar("mp_freezetime") every round + no null guard

Event_RoundStart looked up mp_freezetime every round and passed the result straight to GetConVarInt, which throws a native error if the ConVar does not exist. Now cached once in OnPluginStart, self-healed (re-looked-up) if it was still null (e.g. queried before the engine registered it), and null-checked before use. The cached handle stays valid for the plugin's lifetime — mp_freezetime is a permanent engine convar, so its current value is always read live from .IntValue at each round_start, including when a map (e.g. a ze-style multi-stage map) changes the cvar's value between rounds.

3. InsertWeapon could track the same entity twice (bug)

Nothing stopped the same weapon entref being inserted twice (e.g. OnClientDisconnect simulates a drop that the engine may also report via SDKHook_WeaponDropPost). RemoveWeapon only clears the first match, so the duplicate leaks a tracking slot and can cause other weapons to be evicted early when the list looks "full". Added a dedupe check in the existing scan loop (no extra iteration cost).

4. Max-weapons shrink logic deduplicated

Extracted the max-weapons shrink-and-kill logic into ApplyMaxWeapons() and used it from both OnConVarChanged and OnConfigsExecuted, so the two call sites can't drift out of sync.

5. Housekeeping

  • Version 2.2.42.2.5.
  • Consistent if ( / for ( spacing throughout.
  • Removed a couple of stale/redundant comments.
  • .github/copilot-instructions.md: fixed stale version numbers, the project tree, and the "Modernization Opportunities" section (the CloseHandledelete migration it described is already done).

Testing

  • Not compiled locally (no spcomp available); relying on CI.
  • Behaviour review only.

Notes / not changed

  • OnMapStart/OnMapEnd timer setup is unchanged: SourceMod calls OnMapStart (and replays OnClientPutInServer) for plugins loaded mid-map, so the repeating cleanup timer already starts correctly on a late load — no fix was needed there.
  • OnWeaponSpawnedOnWeaponSpawnedPost is a redundant pass-through and the naming hints it may have been meant as SDKHook_SpawnPost. Left as-is to avoid a behavioural change without a test server.
  • OnClientDisconnect iterates weapon slots 0..4 (magic number); left untouched.

🤖 Generated with Claude Code

- Move cleanup timer creation from OnMapStart to OnPluginStart so
  lifetime-based cleanup keeps working when the plugin is loaded or
  reloaded mid-map. OnMapStart/OnMapEnd are not fired for late-loaded
  plugins, so previously the timer never started until the next map
  change. It is now a single repeating timer for the plugin lifetime,
  freed in OnPluginEnd.
- Read sm_weaponcleaner_max / sm_weaponcleaner_lifetime in
  OnConfigsExecuted instead of relying on the ConVar change hook
  happening to fire during AutoExecConfig.
- Cache mp_freezetime once instead of calling FindConVar() every
  round_start, and guard against it being missing (avoids a native
  error on games without the ConVar).
- Guard InsertWeapon against tracking the same weapon entity twice,
  which could leak a tracking slot and evict other weapons early
  (e.g. OnClientDisconnect simulating a drop that the engine also
  reports).
- Bump version to 2.2.5 and refresh copilot-instructions.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 10, 2026 20:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The cleanup timer is still created without a no-mapchange flag, so it will be destroyed on map change and won’t be recreated after OnMapStart was removed.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR makes small, targeted fixes to WeaponCleaner’s initialization and weapon cleanup behavior, aiming to make lifetime-based cleanup and round-start logic more robust—especially when the plugin is loaded mid-map.

Changes:

  • Move the repeating cleanup timer creation into OnPluginStart and add OnPluginEnd cleanup.
  • Read effective ConVar values after config execution via OnConfigsExecuted(), and cache/guard mp_freezetime.
  • Prevent InsertWeapon from tracking the same weapon entity reference twice; update Copilot instructions/version notes.
File summaries
File Description
addons/sourcemod/scripting/WeaponCleaner.sp Adjusts timer lifecycle, config initialization timing, freeze-time lookup safety, and weapon tracking dedupe.
.github/copilot-instructions.md Updates repository documentation (versions, tree, and modernization notes).
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread addons/sourcemod/scripting/WeaponCleaner.sp Outdated
…nk logic

- Retry FindConVar("mp_freezetime") in Event_RoundStart if the cached
  handle is still null, so a late-registered convar isn't stuck at 0
  freeze time for the plugin's whole lifetime.
- Extract the max-weapons shrink-and-kill logic into ApplyMaxWeapons()
  and use it from both OnConVarChanged and OnConfigsExecuted, so the
  two call sites can't drift out of sync.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No unresolved review issues remain.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Rushaway and others added 2 commits September 15, 2026 09:03
SourceMod calls OnMapStart (and replays OnClientPutInServer) for
plugins loaded mid-map, so the cleanup timer was never actually
missing on late load. Move it back to OnMapStart/OnMapEnd instead of
OnPluginStart/OnPluginEnd.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Rushaway Rushaway changed the title fix(core): start cleanup timer on late load and harden init fix(core): harden config init, dedupe weapon tracking, style cleanup Sep 15, 2026
@Rushaway
Rushaway merged commit 0429085 into master Sep 15, 2026
6 checks passed
@Rushaway
Rushaway deleted the fix/late-load-timer-and-init branch September 15, 2026 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants