finish plugin

using System.Numerics;
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Utils;
using Utils;
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;

namespace AIStatsCollector;

public class StatsCollector : BasePlugin
{
    public override string ModuleName => "AI Stats Collector";
    public override string ModuleVersion => "1.0";

    private readonly PlayerDataContainer<PlayerData> _players;

    public StatsCollector()
    {
        _players = new PlayerDataContainer<PlayerData>(this, i => new()
        {
            Controller = Utilities.GetPlayerFromSlot(i)!
        });
    }

    public override void Load(bool hotReload)
    {
        RegisterEventHandler<EventPlayerDeath>(OnPlayerDeath);
        RegisterEventHandler<EventRoundFreezeEnd>(OnRoundStart);

        RegisterListener<Listeners.OnTick>(OnTick);
    }

    private HookResult OnRoundStart(EventRoundFreezeEnd @event, GameEventInfo info)
    {
        foreach (var player in _players.ActivePlayers)
        {
            player.FramesData = new PlayerFrames
            {
                AccountId = new SteamID(player.Controller.SteamID).AccountId
            };
        }

        return HookResult.Continue;
    }

    private HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info)
    {
        
    }

    private void OnTick()
    {
        var tickedTime = Server.TickedTime;
        foreach (var player in _players.ActivePlayers)
        {
            if (player.FramesData != null)
            {
                var pawn = player.Controller.PlayerPawn.Value!;

                var activeWeapon = pawn.WeaponServices!.ActiveWeapon.Value;
                if (activeWeapon == null)
                    continue;

                var id = activeWeapon.AttributeManager.Item.ItemDefinitionIndex;

                player.FramesData.Frames.Add(new FrameData
                {
                    TickedTime = (float)tickedTime,
                    Position = Vector3FromVector(pawn.AbsOrigin!),
                    Angles = Vector3FromAngle(pawn.AbsRotation!),
                    Velocity = Vector3FromVector(pawn.AbsVelocity!),
                    Health = pawn.Health,
                    Weapon = id,
                    PunchAngle = Vector3FromAngle(pawn.AimPunchAngle),
                    Buttons = (int)player.Controller.Buttons
                });
            }
        }
    }

    private Vector3 Vector3FromVector(Vector vector)
    {
        return new Vector3(vector.X, vector.Y, vector.Z);
    }

    private Vector2 Vector2FromVector(Vector vector)
    {
        return new Vector2(vector.X, vector.Y);
    }

    private Vector3 Vector3FromAngle(QAngle angle)
    {
        return new Vector3(angle.X, angle.Y, angle.Z);
    }
}

public class PlayerData
{
    public required CCSPlayerController Controller { get; set; }
    public PlayerFrames? FramesData { get; set; }
}

public class GameData
{
    public PlayerFrames Player1Data { get; set; }
    public PlayerFrames Player2Data { get; set; }
}

public class PlayerFrames
{
    public int AccountId { get; set; }
    public List<FrameData> Frames { get; set; } = new();
}

public class FrameData
{
    public float TickedTime { get; set; }
    public Vector3 Position { get; set; }
    public Vector3 Angles { get; set; }
    public Vector3 Velocity { get; set; }
    public int Health { get; set; }
    public ushort Weapon { get; set; }
    public Vector3 PunchAngle { get; set; }
    public int Buttons { get; set; }
}