<commit_before>﻿using rlbot.flat;
using RLBotDotNet.Utils;
using RLBotDotNet.Server;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;

namespace RLBotDotNet
{
    /// <summary>
    /// Manages the C# bots and runs them.
    /// </summary>
    /// <typeparam name="T">The custom bot class that should be run.</typeparam>
    public class BotManager<T> where T : Bot
    {
        private ManualResetEvent botRunEvent = new ManualResetEvent(false);
        private List<BotProcess> botProcesses;
        private GameTickPacket currentGameTickPacket;
        private FieldInfo fieldInfo;
        private Thread serverThread;

        /// <summary>
        /// Creates a new BotManager instance to run the bots.
        /// </summary>
        /// <param name="port">The port that the manager listens to for the Python clients.</param>
        public BotManager(int port)
        {
        }

        /// <summary>
        /// Adds a bot to the <see cref="botProcesses"/> list if the index is not there already.
        /// </summary>
        /// <param name="bot"></param>
        private void RegisterBot(string name, int team, int index)
        {
            // Only add a bot if botProcesses doesn't contain the index given in the parameters.
            if (!botProcesses.Any(b => b.bot.index == index))
            {
                // Create a bot instance, run it in a separate thread, and add it to botProcesses.
                T bot = (T)Activator.CreateInstance(typeof(T), name, team, index);
                Thread thread = new Thread(() => RunBot(bot));

                BotProcess botProcess = new BotProcess()
                {
                    bot = bot,
                    thread = thread
                };

                botProcesses.Add(botProcess);
            }
        }

        /// <summary>
        /// Calls the given bot's <see cref="Bot.GetOutput(GameTickPacket)"/> method and
        /// updates its input through the interface DLL.
        /// </summary>
        /// <param name="bot"></param>
        private void RunBot(Bot bot)
        {
            while (true)
            {
                Controller botInput = bot.GetOutput(currentGameTickPacket);
                RLBotInterface.SetBotInput(botInput, bot.index);
                botRunEvent.WaitOne();
            }
        }

        /// <summary>
        /// The main bot manager loop. This will continuously run the bots by setting <see cref="botRunEvent"/>.
        /// </summary>
        private void MainBotLoop()
        {
            //GetGameTickPacket();
            //botRunEvent.Set();
            //botRunEvent.Reset();
            throw new NotImplementedException();
        }

        /// <summary>
        /// Stops the given bot's thread.
        /// </summary>
        /// <param name="botProcess">The bot process to stop.</param>
        private void StopBotProcess(BotProcess botProcess)
        {
            botProcess.thread.Abort();
        }

        /// <summary>
        /// Start the server and be ready to manage the bots.
        /// </summary>
        /// <param name="port">The port that the manager listens to for the Python clients.</param>
        public void Start(int port)
        {
            BotManagerServer server = new BotManagerServer();
            server.BotReceivedEvent += OnBotReceived;
            serverThread = new Thread(() => server.Start(port));

        }

        /// <summary>
        /// Method that is subscribed to <see cref="BotManagerServer.BotReceivedEvent"/>.
        /// This method parses the event's message and calls the appropriate methods.
        /// </summary>
        /// <param name="message">The message from the event.</param>
        private void OnBotReceived(string message)
        {
            try
            {
                string[] split = message.Split(' ');

                if (split.Length < 2)
                    throw new Exception("Server received too few command arguments from client");


                if (split[0] == "add")
                    RegisterBot(split[1], int.Parse(split[2]), int.Parse(split[3]));
                else if (split[0] == "remove")
                {
                    int index = int.Parse(split[1]);
                    BotProcess proc = botProcesses.Find(b => b.bot.index == index);
                    StopBotProcess(proc);
                }
                else
                    throw new Exception("Server received bad command from client: " + split[0]);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        /// <summary>
        /// Calls <see cref="RLBotInterface.GetGameTickPacket"/>, and also sets <see cref="currentGameTickPacket"/>.
        /// </summary>
        /// <returns>The current frame's GameTickPacket.</returns>
        private GameTickPacket GetGameTickPacket()
        {
            currentGameTickPacket = RLBotInterface.GetGameTickPacket();
            return currentGameTickPacket;
        }

        /// <summary>
        /// Calls <see cref="RLBotInterface.GetFieldInfo"/>, and also sets <see cref="fieldInfo"/>.
        /// </summary>
        /// <returns>The game's FieldInfo.</returns>
        private FieldInfo GetFieldInfo()
        {
            // Since FieldInfo will never change during a match, we only call RLBotInterface.GetFieldInfo once.
            if (fieldInfo.Equals(null) && RLBotInterface.IsInitialized())
                fieldInfo = RLBotInterface.GetFieldInfo();

            return fieldInfo;
        }
    }
}<commit_msg>Implementing MainBotLoop, starting server thread<commit_after>﻿using rlbot.flat;
using RLBotDotNet.Utils;
using RLBotDotNet.Server;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;

namespace RLBotDotNet
{
    /// <summary>
    /// Manages the C# bots and runs them.
    /// </summary>
    /// <typeparam name="T">The custom bot class that should be run.</typeparam>
    public class BotManager<T> where T : Bot
    {
        private ManualResetEvent botRunEvent = new ManualResetEvent(false);
        private List<BotProcess> botProcesses = new List<BotProcess>();
        private GameTickPacket currentGameTickPacket;
        private FieldInfo fieldInfo;
        private Thread serverThread;

        /// <summary>
        /// Creates a new BotManager instance to run the bots.
        /// </summary>
        /// <param name="port">The port that the manager listens to for the Python clients.</param>
        public BotManager(int port)
        {
        }

        /// <summary>
        /// Adds a bot to the <see cref="botProcesses"/> list if the index is not there already.
        /// </summary>
        /// <param name="bot"></param>
        private void RegisterBot(string name, int team, int index)
        {
            // Only add a bot if botProcesses doesn't contain the index given in the parameters.
            if (!botProcesses.Any(b => b.bot.index == index))
            {
                // Create a bot instance, run it in a separate thread, and add it to botProcesses.
                T bot = (T)Activator.CreateInstance(typeof(T), name, team, index);
                Thread thread = new Thread(() => RunBot(bot));

                BotProcess botProcess = new BotProcess()
                {
                    bot = bot,
                    thread = thread
                };

                botProcesses.Add(botProcess);
            }
        }

        /// <summary>
        /// Calls the given bot's <see cref="Bot.GetOutput(GameTickPacket)"/> method and
        /// updates its input through the interface DLL.
        /// </summary>
        /// <param name="bot"></param>
        private void RunBot(Bot bot)
        {
            while (true)
            {
                Controller botInput = bot.GetOutput(currentGameTickPacket);
                RLBotInterface.SetBotInput(botInput, bot.index);
                botRunEvent.WaitOne();
            }
        }

        /// <summary>
        /// The main bot manager loop. This will continuously run the bots by setting <see cref="botRunEvent"/>.
        /// </summary>
        private void MainBotLoop()
        {
            while (true)
            {
                GetGameTickPacket();
                botRunEvent.Set();
                botRunEvent.Reset();
                Thread.Sleep(16);
            }
        }

        /// <summary>
        /// Stops the given bot's thread.
        /// </summary>
        /// <param name="botProcess">The bot process to stop.</param>
        private void StopBotProcess(BotProcess botProcess)
        {
            botProcess.thread.Abort();
        }

        /// <summary>
        /// Start the server and be ready to manage the bots.
        /// </summary>
        /// <param name="port">The port that the manager listens to for the Python clients.</param>
        public void Start(int port)
        {
            BotManagerServer server = new BotManagerServer();
            server.BotReceivedEvent += OnBotReceived;
            serverThread = new Thread(() => server.Start(port));
            serverThread.Start();

        }

        /// <summary>
        /// Method that is subscribed to <see cref="BotManagerServer.BotReceivedEvent"/>.
        /// This method parses the event's message and calls the appropriate methods.
        /// </summary>
        /// <param name="message">The message from the event.</param>
        private void OnBotReceived(string message)
        {
            try
            {
                string[] split = message.Split(' ');

                if (split.Length < 2)
                    throw new Exception("Server received too few command arguments from client");


                if (split[0] == "add")
                    RegisterBot(split[1], int.Parse(split[2]), int.Parse(split[3]));
                else if (split[0] == "remove")
                {
                    int index = int.Parse(split[1]);
                    BotProcess proc = botProcesses.Find(b => b.bot.index == index);
                    StopBotProcess(proc);
                    botProcesses.Remove(proc);
                }
                else
                    throw new Exception("Server received bad command from client: " + split[0]);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine(e.StackTrace);
            }
        }

        /// <summary>
        /// Calls <see cref="RLBotInterface.GetGameTickPacket"/>, and also sets <see cref="currentGameTickPacket"/>.
        /// </summary>
        /// <returns>The current frame's GameTickPacket.</returns>
        private GameTickPacket GetGameTickPacket()
        {
            currentGameTickPacket = RLBotInterface.GetGameTickPacket();
            return currentGameTickPacket;
        }

        /// <summary>
        /// Calls <see cref="RLBotInterface.GetFieldInfo"/>, and also sets <see cref="fieldInfo"/>.
        /// </summary>
        /// <returns>The game's FieldInfo.</returns>
        private FieldInfo GetFieldInfo()
        {
            // Since FieldInfo will never change during a match, we only call RLBotInterface.GetFieldInfo once.
            if (fieldInfo.Equals(null) && RLBotInterface.IsInitialized())
                fieldInfo = RLBotInterface.GetFieldInfo();

            return fieldInfo;
        }
    }
}
{'fraction_non_alphanumeric': 0.11211699164345404, 'fraction_numerical': 0.0015668523676880223, 'mean_word_length': 1.6435803037275656, 'pattern_counts': {'":': 0, '<': 102, '<?xml version=': 0, '>': 108, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3016593', 'n_tokens_mistral': 2932, 'n_tokens_neox': 2807, 'n_words': 835}