@@ -262,6 +262,48 @@ local function getSustainedChokeAverage(deltaTicks, deltaCount)
262262 return avgHigh
263263end
264264
265+ local function getPositiveAvgChoke (posDeltas , posCount )
266+ if posCount < AVG_CHOKE_MIN_SAMPLES then
267+ return nil
268+ end
269+
270+ local sumPos = 0
271+ for i = 1 , posCount do
272+ sumPos = sumPos + posDeltas [i ]
273+ end
274+ local avgChoke = sumPos / posCount
275+ if avgChoke < AVG_CHOKE_THRESHOLD then
276+ return nil
277+ end
278+ return avgChoke
279+ end
280+
281+ local function getRhythmicChokeEvidence (posDeltas , posCount )
282+ if posCount < RHYTHM_MIN_EVENTS then
283+ return nil , nil , nil
284+ end
285+
286+ local anchorDelta = posDeltas [1 ]
287+ if not anchorDelta or anchorDelta < MIN_FAKELAG_CHOKE_TICKS then
288+ return nil , nil , nil
289+ end
290+
291+ local tolerance = getRhythmTolerance (anchorDelta )
292+ local matching , checked = countRhythmMatches (
293+ posDeltas ,
294+ anchorDelta ,
295+ RHYTHM_CHECK_COUNT ,
296+ tolerance ,
297+ posCount
298+ )
299+ if checked < RHYTHM_MIN_EVENTS or (matching / checked ) < RHYTHM_MATCH_RATIO then
300+ return nil , nil , nil
301+ end
302+
303+ return anchorDelta , " rhythmic choke" , string.format (
304+ " %d ticks (%d/%d within +/-%d)" , anchorDelta , matching , checked , tolerance )
305+ end
306+
265307-- Choke debug: simtime gap kinds (newest-first deltas).
266308-- hold=0t frozen simtime; gap=FL-sized advance; dt_rel=DT band [24,34) like unchoke/DT release.
267309local function accumulateDeltaKinds (deltaTicks , sampleCount , acc )
@@ -515,6 +557,11 @@ function FakeLag.ProcessPlayer(playerState)
515557 Evidence .HoldDecayForMethod (id , " fake_lag" )
516558 end
517559
560+ local fakeLagWeight = Evidence .GetMethodWeight (id , " fake_lag" )
561+ if fakeLagWeight >= FAKE_LAG_EVIDENCE_CAP then
562+ return
563+ end
564+
518565 local function countRecentStalls (lookbackEnd )
519566 local stalls = 0
520567 local lookback = math.min (BURST_STALL_LOOKBACK , lookbackEnd or deltaCount )
@@ -544,8 +591,6 @@ function FakeLag.ProcessPlayer(playerState)
544591 " [FakeLag] %s %s: %s (evidence +%.1f) | %s" ,
545592 id , logLabel , logDetail , addedWeight , formatDeltaKinds (kindAcc )))
546593 end
547- elseif isDebug and weight > 0 then
548- print (string.format (" [FakeLag] %s evidence blocked for %s (wanted +%.1f)" , id , logLabel , weight ))
549594 end
550595 return addedWeight
551596 end
@@ -604,35 +649,21 @@ function FakeLag.ProcessPlayer(playerState)
604649 " sustained choke" ,
605650 string.format (" avg %.1f ticks" , sustainedAvg )
606651 )
607- elseif posCount >= AVG_CHOKE_MIN_SAMPLES then
608- local sumPos = 0
609- for i = 1 , posCount do
610- sumPos = sumPos + posDeltas [i ]
611- end
612- local avgChoke = sumPos / posCount
613- if avgChoke >= AVG_CHOKE_THRESHOLD then
652+ else
653+ local avgChoke = getPositiveAvgChoke (posDeltas , posCount )
654+ if avgChoke then
614655 tryAddChokeEvidence (
615656 buildEvidenceWeight (avgChoke ),
616657 " avg choke" ,
617658 string.format (" %.1f ticks (%d releases)" , avgChoke , posCount )
618659 )
619- end
620- elseif posCount >= RHYTHM_MIN_EVENTS then
621- local anchorDelta = posDeltas [1 ]
622- if anchorDelta >= MIN_FAKELAG_CHOKE_TICKS then
623- local tolerance = getRhythmTolerance (anchorDelta )
624- local matching , checked = countRhythmMatches (
625- posDeltas ,
626- anchorDelta ,
627- RHYTHM_CHECK_COUNT ,
628- tolerance ,
629- posCount
630- )
631- if checked >= RHYTHM_MIN_EVENTS and (matching / checked ) >= RHYTHM_MATCH_RATIO then
660+ else
661+ local rhythmTicks , rhythmLabel , rhythmDetail = getRhythmicChokeEvidence (posDeltas , posCount )
662+ if rhythmTicks then
632663 tryAddChokeEvidence (
633- buildEvidenceWeight (anchorDelta ),
634- " rhythmic choke " ,
635- string.format ( " %d ticks (%d/%d within +/-%d) " , anchorDelta , matching , checked , tolerance )
664+ buildEvidenceWeight (rhythmTicks ),
665+ rhythmLabel ,
666+ rhythmDetail
636667 )
637668 end
638669 end
0 commit comments