saul / demofile-net

Blazing fast cross-platform demo parser library for Counter-Strike 2, written in C#.
MIT License
85 stars 7 forks source link

GameRule "HasMatchStarted" turns to false before match ends #84

Closed xGuysOG closed 5 days ago

xGuysOG commented 2 weeks ago

Research

Description

GameRule "HasMatchStarted" turns to false before match has really ended. As you can see in my debugs the last round end is called after, so is win match.

and while i can create my own method to check this, i feel like it should be fixed in the main Lib.

Debugs from the code: `Starting the Socket Client... ROund end called but we have an issue, it seems match was not started yet ROund end called but we have an issue, it seems match was not started yet ct:0 and t: 0 Round start called at round ct:0 and t:0 Round End called at round ct:0 and t:1 Round end called at round ct:0 and t:1 winner? Terrorist Reason TerroristsWin message #SFUI_Notice_Terrorists_Win Round start called at round ct:0 and t:1 Round End called at round ct:1 and t:1 Round end called at round ct:1 and t:1 winner? CounterTerrorist Reason CTsWin message #SFUI_Notice_CTs_Win Round start called at round ct:1 and t:1 Round End called at round ct:2 and t:1 Round end called at round ct:2 and t:1 winner? CounterTerrorist Reason CTsWin message #SFUI_Notice_CTs_Win Round start called at round ct:2 and t:1 Round End called at round ct:3 and t:1 Round end called at round ct:3 and t:1 winner? CounterTerrorist Reason CTsWin message #SFUI_Notice_CTs_Win Round start called at round ct:3 and t:1 Round End called at round ct:3 and t:2 Round end called at round ct:3 and t:2 winner? Terrorist Reason TerroristsWin message #SFUI_Notice_Terrorists_Win Round start called at round ct:3 and t:2 Round End called at round ct:3 and t:3 Bomb exploded Round end called at round ct:3 and t:3 winner? Terrorist Reason TargetBombed message #SFUI_Notice_Target_Bombed Round start called at round ct:3 and t:3 Round End called at round ct:3 and t:4 Bomb exploded Round end called at round ct:3 and t:4 winner? Terrorist Reason TargetBombed message #SFUI_Notice_Target_Bombed Round start called at round ct:3 and t:4 Round End called at round ct:4 and t:4 Round end called at round ct:4 and t:4 winner? CounterTerrorist Reason CTsWin message #SFUI_Notice_CTs_Win Round start called at round ct:4 and t:4 Round End called at round ct:5 and t:4 Round end called at round ct:5 and t:4 winner? CounterTerrorist Reason BombDefused message #SFUI_Notice_Bomb_Defused Round start called at round ct:5 and t:4 Round End called at round ct:6 and t:4 Round end called at round ct:6 and t:4 winner? CounterTerrorist Reason CTsWin message #SFUI_Notice_CTs_Win Round start called at round ct:6 and t:4 Round End called at round ct:7 and t:4 Round end called at round ct:7 and t:4 winner? CounterTerrorist Reason CTsWin message #SFUI_Notice_CTs_Win Round start called at round ct:7 and t:4 Round End called at round ct:7 and t:5 Round end called at round ct:7 and t:5 winner? Terrorist Reason TerroristsWin message #SFUI_Notice_Terrorists_Win Round start called at round ct:5 and t:7 Round End called at round ct:5 and t:8 Round end called at round ct:5 and t:8 winner? Terrorist Reason TerroristsWin message #SFUI_Notice_Terrorists_Win Round start called at round ct:5 and t:8 Round End called at round ct:6 and t:8 Round end called at round ct:6 and t:8 winner? CounterTerrorist Reason CTsWin message #SFUI_Notice_CTs_Win Round start called at round ct:6 and t:8 Round End called at round ct:7 and t:8 Round end called at round ct:7 and t:8 winner? CounterTerrorist Reason CTsWin message #SFUI_Notice_CTs_Win Round start called at round ct:7 and t:8 Round End called at round ct:8 and t:8 Round end called at round ct:8 and t:8 winner? CounterTerrorist Reason BombDefused message #SFUI_Notice_Bomb_Defused Round start called at round ct:8 and t:8 Round End called at round ct:9 and t:8 Round end called at round ct:9 and t:8 winner? CounterTerrorist Reason CTsWin message #SFUI_Notice_CTs_Win Round start called at round ct:9 and t:8 Round End called at round ct:10 and t:8 Round end called at round ct:10 and t:8 winner? CounterTerrorist Reason CTsWin message #SFUI_Notice_CTs_Win Round start called at round ct:10 and t:8 Round End called at round ct:10 and t:9 Round end called at round ct:10 and t:9 winner? Terrorist Reason TerroristsWin message #SFUI_Notice_Terrorists_Win Round start called at round ct:10 and t:9 Round End called at round ct:11 and t:9 Round end called at round ct:11 and t:9 winner? CounterTerrorist Reason CTsWin message #SFUI_Notice_CTs_Win Round start called at round ct:11 and t:9 Round End called at round ct:12 and t:9 Round end called at round ct:12 and t:9 winner? CounterTerrorist Reason BombDefused message #SFUI_Notice_Bomb_Defused Round start called at round ct:12 and t:9 ROund end called but we have an issue, it seems match was not started yet ROund end called but we have an issue, it seems match was not started yet ct:13 and t: 9 WIn match has ended Time elapsed after file data: 00:00:03.5268049 Time elapsed: 00:00:03.5955110

Finished! `

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\\demTest\\661577d74c197423489bdd75_0_1717614880949.dem";

    public static async Task Main(string[] args)
    {
        Console.WriteLine("Starting the Socket Client...");
        //SocketClient client = new SocketClient();

        //// Initialize and connect the client
        //await client.InitializeConnection();

        //Console.WriteLine("Press any key to exit...");
        //Console.ReadKey();

        //return;
        try
        {
            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.EntityEvents.CCSGameRulesProxy.AddChangeCallback(proxy => proxy.GameRules?.RoundEndCount, (proxy, _, _) =>
            {
                if (!demo.GameRules.HasMatchStarted)
                {
                    Console.WriteLine("ROund end called but we have an issue, it seems match was not started yet");
                    return;
                }
                Console.WriteLine("Round End called at round ct:" + demo.TeamCounterTerrorist.Score + " and t:" + demo.TeamTerrorist.Score);

            });

            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.RoundEnd += e =>
            {

                if (!demo.GameRules.HasMatchStarted)
                {
                    Console.WriteLine("ROund end called but we have an issue, it seems match was not started yet ct:" + demo.TeamCounterTerrorist.Score + " and t: " + demo.TeamTerrorist.Score);
                    return;
                }
                // Convert the integer to the corresponding enum value
                CSRoundEndReason reasonEnum = (CSRoundEndReason)e.Reason;

                // Convert the enum value to its string representation
                string reasonString = reasonEnum.ToString();

                CSTeamNumber winnerEnum = (CSTeamNumber)e.Winner;
                string winnerString = winnerEnum.ToString();

                Console.WriteLine("Round end called at round ct:" + demo.TeamCounterTerrorist.Score +
                                  " and t:" + demo.TeamTerrorist.Score +
                                  " winner? " + winnerString +
                                  " Reason " + reasonString +
                                  " message " + e.Message);

                Debug.WriteLine("Round end called at round ct:" + demo.TeamCounterTerrorist.Score +
                                " and t:" + demo.TeamTerrorist.Score +
                                " winner? " + winnerString +
                                " Reason " + reasonString +
                                " message " + e.Message);

            };

            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!");
        } catch (Exception e)
        { 
            Console.WriteLine("Exception: " + e.Message.ToString());
        }

        Console.ReadKey();
    }

Affected demos

https://drive.google.com/file/d/1kmBKcxTRMJMc9kcLWSC9-8Q2ZBP4EQvd/view?usp=sharing

saul commented 2 weeks ago

Does HasMatchEnded change to false and the RoundEnd event fire on the same tick? If so, this is expected.

On any given tick, entity properties (including game rules) change before events are fired.

As the library is just exposing the data in the demo file itself, I'm not too keen to add workarounds to the core.

xGuysOG commented 2 weeks ago

Does HasMatchEnded change to false and the RoundEnd event fire on the same tick? If so, this is expected.

On any given tick, entity properties (including game rules) change before events are fired.

As the library is just exposing the data in the demo file itself, I'm not too keen to add workarounds to the core.

There sadly is no "HasMatchEnded" in the gamerules, i did some tick tests and you are correct it happens on the same tick. How annoying, since i use "HasMatchStarted" to know if i should track stats or not track stats.

I guess id have to make a check on round start, and see if the next round might be the last round, and track the stats that way. Unless there is a better way then to track"HasMatchStarted"?

in0finite commented 2 weeks ago

This is not a problem of the library, this is simply the way how server updates GameRules entity properties.

There sadly is no "HasMatchEnded" in the gamerules

Yes, there is an equivalent : GameRules.GamePhase == CSGamePhase.MatchEnded.

However, you don't need that. The proper way to detect if match has started would be something like this :

bool hasMatchEverStarted = false;
demo.EntityEvents.CCSGameRulesProxy.AddChangeCallback(proxy => proxy.GameRules?.HasMatchStarted, (proxy, _, _) =>
{
    hasMatchEverStarted |= demo.GameRules.HasMatchStarted;
});