@@ -27,6 +27,11 @@ local regionCache = {}
2727-- per-player scan results: id -> { regions = {region->count}, totalWearables = n }
2828local playerScanData = {}
2929
30+ -- Event-driven queue (no CreateMove scan of all players).
31+ local pendingScanIds = {}
32+ local COSMETICS_SCANS_PER_TICK = 3
33+ local MAX_WEARABLE_SCAN_ATTEMPTS = 66
34+
3035-- One entities.FindByClass("CTFWearable") pass per game tick, shared by all players.
3136local wearableCacheTick = - 1
3237local wearablesByPlayerIndex = {}
@@ -195,10 +200,79 @@ function CosmeticAbuse.Init()
195200end
196201
197202function CosmeticAbuse .InvalidatePlayer (id )
203+ id = id and tostring (id )
204+ if not id then
205+ return
206+ end
198207 playerScanData [id ] = nil
208+ pendingScanIds [id ] = nil
209+ local state = PlayerCache .GetByID (id )
210+ if state then
211+ state .wearablesScanned = nil
212+ state .wearableScanAttempts = nil
213+ end
214+ end
215+
216+ function CosmeticAbuse .RequestScan (id )
217+ if not id or not isEnabled () then
218+ return
219+ end
220+ id = tostring (id )
221+ if not id :match (" ^7656119%d+$" ) then
222+ return
223+ end
224+ pendingScanIds [id ] = true
199225 local state = PlayerCache .GetByID (id )
200226 if state then
201227 state .wearablesScanned = nil
228+ state .wearableScanAttempts = nil
229+ end
230+ playerScanData [id ] = nil
231+ end
232+
233+ function CosmeticAbuse .HasPendingWork ()
234+ return next (pendingScanIds ) ~= nil
235+ end
236+
237+ function CosmeticAbuse .ProcessPending (maxScans )
238+ if not isEnabled () then
239+ for k in pairs (pendingScanIds ) do
240+ pendingScanIds [k ] = nil
241+ end
242+ return
243+ end
244+
245+ local limit = maxScans or COSMETICS_SCANS_PER_TICK
246+ local processed = 0
247+ for id in pairs (pendingScanIds ) do
248+ if processed >= limit then
249+ break
250+ end
251+ local state = PlayerCache .GetByID (id )
252+ if not state or not state .pdata or not state .pdata .isAlive or state .pdata .isDormant then
253+ pendingScanIds [id ] = nil
254+ else
255+ CosmeticAbuse .ScanPlayer (state )
256+ processed = processed + 1
257+ if state .wearablesScanned then
258+ pendingScanIds [id ] = nil
259+ elseif (state .wearableScanAttempts or 0 ) >= MAX_WEARABLE_SCAN_ATTEMPTS then
260+ pendingScanIds [id ] = nil
261+ end
262+ end
263+ end
264+ end
265+
266+ function CosmeticAbuse .OnSessionReset ()
267+ for k in pairs (pendingScanIds ) do
268+ pendingScanIds [k ] = nil
269+ end
270+ for _ , state in pairs (PlayerCache .GetActiveTable ()) do
271+ if state and state .id then
272+ state .wearablesScanned = nil
273+ state .wearableScanAttempts = nil
274+ CosmeticAbuse .RequestScan (state .id )
275+ end
202276 end
203277end
204278
@@ -223,7 +297,7 @@ function CosmeticAbuse.ScanPlayer(playerState)
223297 if scanned == nil then
224298 local attempts = (playerState .wearableScanAttempts or 0 ) + 1
225299 playerState .wearableScanAttempts = attempts
226- if attempts < 66 then
300+ if attempts < MAX_WEARABLE_SCAN_ATTEMPTS then
227301 return
228302 end
229303 playerState .wearablesScanned = true
@@ -251,12 +325,8 @@ function CosmeticAbuse.ScanPlayer(playerState)
251325 end
252326end
253327
254- local function scanPlayerById (id )
255- if not id or not isEnabled () then return end
256- local state = PlayerCache .GetByID (tostring (id ))
257- if state then
258- CosmeticAbuse .ScanPlayer (state )
259- end
328+ local function queueScanById (id )
329+ CosmeticAbuse .RequestScan (id )
260330end
261331
262332local function onPlayerSpawn (event )
@@ -266,7 +336,7 @@ local function onPlayerSpawn(event)
266336 if not ent or not ent :IsValid () then return end
267337 local id = tostring (Common .GetSteamID64 (ent ))
268338 if id :match (" ^7656119%d+$" ) then
269- scanPlayerById (id )
339+ queueScanById (id )
270340 end
271341end
272342
@@ -277,13 +347,20 @@ local function onPlayerChangeClass(event)
277347 if not ent or not ent :IsValid () then return end
278348 local id = tostring (Common .GetSteamID64 (ent ))
279349 if id :match (" ^7656119%d+$" ) then
280- CosmeticAbuse .InvalidatePlayer (id )
281- scanPlayerById (id )
350+ CosmeticAbuse .RequestScan (id )
282351 end
283352end
284353
285- Events .Subscribe (" OnPlayerJoinTeam" , scanPlayerById )
354+ local function onSessionReset (_event )
355+ if not isEnabled () then return end
356+ CosmeticAbuse .OnSessionReset ()
357+ end
358+
359+ Events .Subscribe (" OnPlayerJoinTeam" , queueScanById )
286360Events .Register (" FireGameEvent" , " CosmeticAbuse_Spawn" , onPlayerSpawn , " player_spawn" )
287361Events .Register (" FireGameEvent" , " CosmeticAbuse_ClassChange" , onPlayerChangeClass , " player_changeclass" )
362+ Events .Register (" FireGameEvent" , " CosmeticAbuse_NewMap" , onSessionReset , " game_newmap" )
363+ Events .Register (" FireGameEvent" , " CosmeticAbuse_RoundStart" , onSessionReset , " teamplay_round_start" )
364+ Events .Register (" FireGameEvent" , " CosmeticAbuse_RoundEnd" , onSessionReset , " round_end" )
288365
289366return CosmeticAbuse
0 commit comments