v1.2.3.b8 - fix: perf percentiles and duplicate entity log lines

- #### Debug
    - **PerfLog** - `p50`, `p95` and `p99` returned the upper bound of the histogram bucket instead of a real sample, so they could report a value higher than `max`. It happened in 74% of the windows in a 6.5 hour session (e.g. `avg=0.06ms p99=8.00ms max=4.68ms`). Percentiles are now taken from the actual samples of the window, and the bucket estimate is only used as a fallback for windows that overflow the buffer - interpolated inside the bucket and clamped to `max`.
    - **EntityManager** - An entity that was already tracked logged a second `+` line, so creates and destroys stopped matching and the entity log read like a leak. Re-registering now logs `~ oldType -> newType` when the type changes and nothing when it does not.
    - **Ghost, Ninja, C4Camouflage** - The hiding prop was registered twice, first as `prop_dynamic` and then as `empty_prop`. It is now tracked under the right name from creation through the new `trackAs` parameter of `CreateTrackedDynamicProp`.
This commit is contained in:
ByDexter 2026-08-21 17:24:26 +03:00
parent b95c52028e
commit 68d311e130
8 changed files with 59 additions and 16 deletions

View file

@ -1,4 +1,4 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Utils;
@ -42,6 +42,8 @@ namespace src.utils
{
if (entityIndex == 0) return;
bool alreadyTracked = trackedEntities.TryGetValue(entityIndex, out var previous);
trackedEntities[entityIndex] = new EntityData
{
EntityIndex = entityIndex,
@ -50,8 +52,12 @@ namespace src.utils
CreatedAt = DateTime.UtcNow
};
if (Config.DebugEnabled(DebugCategory.Entity))
if (!Config.DebugEnabled(DebugCategory.Entity)) return;
if (!alreadyTracked)
Debug.WriteToDebug($"[Entity] + {entityType} #{entityIndex} owner={DescribeOwner(playerIndex)} tracked={trackedEntities.Count}", DebugCategory.Entity);
else if (previous.EntityType != entityType)
Debug.WriteToDebug($"[Entity] ~ {previous.EntityType} -> {entityType} #{entityIndex} owner={DescribeOwner(playerIndex)} tracked={trackedEntities.Count}", DebugCategory.Entity);
}
private static string DescribeOwner(uint playerIndex)
@ -130,7 +136,7 @@ namespace src.utils
}
}
public static CDynamicProp? CreateTrackedDynamicProp(uint playerIndex, string designerName = "prop_dynamic")
public static CDynamicProp? CreateTrackedDynamicProp(uint playerIndex, string designerName = "prop_dynamic", string? trackAs = null)
{
try
{
@ -138,7 +144,7 @@ namespace src.utils
var prop = Utilities.CreateEntityByName<CDynamicProp>(designerName);
if (prop == null || !prop.IsValid) return null;
RegisterEntity(prop.Index, playerIndex, designerName);
RegisterEntity(prop.Index, playerIndex, trackAs ?? designerName);
return prop;
}
catch (Exception ex)