saul / demofile-net

Blazing fast cross-platform demo parser library for Counter-Strike 2 and Valve's Deadlock, written in C#.
MIT License
111 stars 10 forks source link

Duplicated `Create` events for entities in POV demos #91

Closed in0finite closed 2 months ago

in0finite commented 2 months ago

Research

Description

Some entities are created multiple times.

Code to reproduce

static readonly DemoParser s_demoParser = new();
static readonly Dictionary<ulong, CBaseEntity> s_entitiesPerHandle = new();

public static async Task Main(string[] args)
{

string path = ; // add your path here

s_demoParser.EntityEvents.CBaseEntity.Create += StoreEntity;
s_demoParser.EntityEvents.CBaseEntity.Delete += RemoveEntity;

var stream = new MemoryStream(File.ReadAllBytes(path));
await s_demoParser.ReadAllAsync(stream, default);

}

static string GetTimeSpan()
{
    float seconds = s_demoParser.CurrentDemoTick.Value / 64f;
    TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
    return timeSpan.ToString("g").PadRight(15);
}

static void StoreEntity<T>(T entity)
    where T : CBaseEntity
{
    if (s_entitiesPerHandle.TryGetValue(entity.EntityHandle.Value, out var existingEntity))
    {
        string msg = $"[{GetTimeSpan()}] Trying to add entity {entity.GetType().Name} which already exists: {existingEntity.GetType().Name}, {existingEntity.EntityHandle.Value}";
        //throw new InvalidOperationException(msg);
        Console.WriteLine(msg);
        s_entitiesPerHandle[entity.EntityHandle.Value] = entity;
        return;
    }

    s_entitiesPerHandle.Add(entity.EntityHandle.Value, entity);
}

static void RemoveEntity<T>(T entity)
    where T : CBaseEntity
{
    if (!s_entitiesPerHandle.Remove(entity.EntityHandle.Value))
    {
        throw new InvalidOperationException(
            $"[{GetTimeSpan()}] Trying to remove entity {entity.GetType().Name} which does not exist: {entity.EntityHandle.Value}");
    }
}

Affected demos

test_casual_pov2.zip

in0finite commented 2 months ago

This also happens in CSTV demos, but only for CCSGOViewModel entities, while in POV demos, it happens for all kind of entities.