saul / demofile-net

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

PlayerBlind inconsistent and not working #59

Closed xGuysOG closed 4 months ago

xGuysOG commented 5 months ago

Research

Description

It seems that there must be some issue with the "PlayerBlind" event not always being parsed correctly from a demo, as it gets called in some demos and on some it dosnt, it seems that the "FlashbangDetonate" event gets called every time so just seems like a parsing issue on your side, but i could be wrong. below ive attached 1 that works and 1 that dosnt that i used in my test.

Code to reproduce

public static class Program
{
    public static string flashNoWork = "C:\\Users\\xguys\\Desktop\\Flash issues\\crystal_vulture.dem";
    public static string flashWork = "C:\\Users\\xguys\\Desktop\\Flash issues\\hedensted_ingearme.dem";

    public static async Task Main(string[] args)
    {
        Stopwatch stopwatch3 = new Stopwatch();
        stopwatch3.Start();
        MemoryStream _fileStream;
        byte[] _demoBytes;
        //_demoBytes = File.ReadAllBytes(demoFilePath);
        _demoBytes = await File.ReadAllBytesAsync(flashWork);
        _fileStream = new MemoryStream(_demoBytes);

        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        var demo = new DemoParser();

        demo.Source1GameEvents.BombExploded += e =>
        {
            Console.WriteLine("Bomb exploded");
        };

        demo.Source1GameEvents.PlayerBlind += e =>
        {
            Console.WriteLine("Player blind");

        };

        demo.Source1GameEvents.FlashbangDetonate += e =>
        {
            Console.WriteLine("Flashbang detonate");
        };

        demo.Source1GameEvents.RoundStart += e =>
        {

            if (!demo.GameRules.HasMatchStarted)
            {
                //PowerLigaManager.Log("ROund end called but we have an issue, it seems match was not started yet");
                return;
            }
            Console.WriteLine("Round start called at round ct:" + demo.TeamCounterTerrorist.Score + " and t:" + demo.TeamTerrorist.Score);
            Debug.WriteLine("Round start called at round ct:" + demo.TeamCounterTerrorist.Score + " and t:" + demo.TeamTerrorist.Score);
        };

        demo.Source1GameEvents.CsWinPanelMatch += e =>
    {
        Console.WriteLine("WIn match has ended");
    };
        await demo.ReadAllAsync(_fileStream);
        stopwatch3.Stop();

        stopwatch.Stop();
        Console.WriteLine("Time elapsed after file data: {0}", stopwatch.Elapsed);
        Console.WriteLine("Time elapsed: {0}", stopwatch3.Elapsed);
        Console.WriteLine("\nFinished!");
        Console.ReadKey();
    }
}

Affected demos

https://drive.google.com/drive/folders/1VdU7tr2s_4SV_EHUOViCJm4AUWxNzvDy?usp=sharing

in0finite commented 5 months ago

I found similar issue with Source1PlayerFootstepEvent, it fires on 2 seconds interval, whereas in new demos Source1PlayerSoundEvent is used instead, and it fires constantly.

Not sure if it's related to this one, or is it a bug in library at all. It could be a bug on server-side. Client technically doesn't need this event, he can check the blind state in CCSPlayerPawn.FlashDuration.

Anyways, this should be tried with other parsing libraries, to see if they give the same behavior.

xGuysOG commented 5 months ago

I found similar issue with Source1PlayerFootstepEvent, it fires on 2 seconds interval, whereas in new demos Source1PlayerSoundEvent is used instead, and it fires constantly.

Not sure if it's related to this one, or is it a bug in library at all. It could be a bug on server-side. Client technically doesn't need this event, he can check the blind state in CCSPlayerPawn.FlashDuration.

Anyways, this should be tried with other parsing libraries, to see if they give the same behavior.

I guess, i know that the javascript parses on cs2lense and noesis use this event to track it.

I use it to get stats on how often players blind people and for how long, its the only real way to get it that I've found other then getting the "FlashbangDetonate" and then getting all players in that moment and getting if they are blind which seems very very bad.

in0finite commented 5 months ago

I guess, i know that the javascript parses on cs2lense and noesis use this event to track it.

Then it's probably a bug in this library.

xGuysOG commented 4 months ago

@saul Any chance you will get to look at this anytime soon?

saul commented 4 months ago

This still isn't ideal, but should be robust enough. If you're concerned about multiple flashbangs going off on the same tick, you can add a radius check. But this should suffice:

var flashQueue = new List<CCSPlayerPawn>();

demo.EntityEvents.CCSPlayerPawn.AddChangeCallback(
    p => p.FlashDuration,
    (p, _, newFlashDuration) =>
    {
        if (newFlashDuration > 0)
        {
            flashQueue.Add(p);
        }
    });

demo.Source1GameEvents.FlashbangDetonate += e =>
{
    Console.WriteLine($"Flashbang detonated at {e.X},{e.Y},{e.Z} by {e.PlayerPawn}:");
    foreach (var pawn in flashQueue)
    {
        Console.WriteLine($"  - {pawn} - {pawn.FlashDuration} secs");
    }
    flashQueue.Clear();
};

I don't believe this is a bug in the library - in the demo you linked, player_blind is simply never recorded.

Hope that helps