示例#1
0
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count < 1)
            {
                BotProgram.MsgHandler.QueueMessage("Usage: state #");
                return;
            }

            string stateNumStr = args[0];

            if (int.TryParse(stateNumStr, out int stateNum) == false)
            {
                BotProgram.MsgHandler.QueueMessage("Invalid state number.");
                return;
            }

            string saveStateStr = $"ss{stateNum}";

            if (InputGlobals.CurrentConsole.ButtonInputMap.ContainsKey(saveStateStr) == false)
            {
                BotProgram.MsgHandler.QueueMessage("Invalid state number.");
                return;
            }

            User user = BotProgram.GetOrAddUser(e.Command.ChatMessage.Username, false);

            //Check if the user can perform this input
            ParserPostProcess.InputValidation inputValidation = ParserPostProcess.CheckInputPermissions(user.Level, saveStateStr, BotProgram.BotData.InputAccess.InputAccessDict);

            //If the input isn't valid, exit
            if (inputValidation.IsValid == false)
            {
                if (string.IsNullOrEmpty(inputValidation.Message) == false)
                {
                    BotProgram.MsgHandler.QueueMessage(inputValidation.Message);
                }

                return;
            }

            //Savestates are always performed on the first controller
            IVirtualController joystick = InputGlobals.ControllerMngr.GetController(0);

            joystick.PressButton(InputGlobals.CurrentConsole.ButtonInputMap[saveStateStr]);
            joystick.UpdateController();

            //Track the time of the savestate
            DateTime curTime = DateTime.UtcNow;

            //Add a new savestate log
            GameLog newStateLog = new GameLog();

            newStateLog.User = e.Command.ChatMessage.Username;

            string date = curTime.ToShortDateString();
            string time = curTime.ToLongTimeString();

            newStateLog.DateTimeString = $"{date} at {time}";

            newStateLog.User       = e.Command.ChatMessage.Username;
            newStateLog.LogMessage = string.Empty;

            //Add the message if one was specified
            if (args.Count > 1)
            {
                string message = e.Command.ArgumentsAsString.Remove(0, stateNumStr.Length + 1);
                newStateLog.LogMessage = message;
            }

            //Add or replace the log and save the bot data
            BotProgram.BotData.SavestateLogs[stateNum] = newStateLog;
            BotProgram.SaveBotData();

            BotProgram.MsgHandler.QueueMessage($"Saved state {stateNum}!");

            //Wait a bit before releasing the input
            const float wait = 50f;
            Stopwatch   sw   = Stopwatch.StartNew();

            while (sw.ElapsedMilliseconds < wait)
            {
            }

            joystick.ReleaseButton(InputGlobals.CurrentConsole.ButtonInputMap[saveStateStr]);
            joystick.UpdateController();
        }
        private static void ExecuteInput(object obj)
        {
            /*************************************************************
            * PERFORMANCE CRITICAL CODE                                  *
            * Even the smallest change must be thoroughly tested         *
            *************************************************************/

            //Increment running threads
            Interlocked.Increment(ref RunningInputThreads);

            //Get the input list - this should have been validated beforehand
            InputWrapper inputWrapper = (InputWrapper)obj;

            ParsedInput[][] inputArray = inputWrapper.InputArray;

            Stopwatch sw = new Stopwatch();

            List <int> indices = new List <int>(16);
            IVirtualControllerManager vcMngr = inputWrapper.VCManager;

            int controllerCount = vcMngr.ControllerCount;

            //Use Span with stack memory to avoid allocations and improve speed
            Span <int> nonWaits = stackalloc int[controllerCount];

            nonWaits.Clear();

            //This is used to track which controller ports were used across all inputs
            //This helps prevent updating controllers that weren't used at the end
            Span <int> usedControllerPorts = stackalloc int[controllerCount];

            usedControllerPorts.Clear();

            GameConsole curConsole = inputWrapper.Console;

            //Don't check for overflow to improve performance
            unchecked
            {
                for (int i = 0; i < inputArray.Length; i++)
                {
                    ref ParsedInput[] inputs = ref inputArray[i];

                    indices.Clear();

                    //Press all buttons unless it's a release input
                    for (int j = 0; j < inputs.Length; j++)
                    {
                        indices.Add(j);

                        //Get a reference to avoid copying the struct
                        ref ParsedInput input = ref inputs[j];

                        //Don't do anything for a blank input
                        if (curConsole.IsBlankInput(input) == true)
                        {
                            continue;
                        }

                        int port = input.controllerPort;

                        //Get the controller we're using
                        IVirtualController controller = vcMngr.GetController(port);

                        //These are set to 1 instead of incremented to prevent any chance of overflow
                        nonWaits[port]            = 1;
                        usedControllerPorts[port] = 1;

                        if (input.release == true)
                        {
                            InputHelper.ReleaseInput(input, curConsole, controller);
                        }
                        else
                        {
                            InputHelper.PressInput(input, curConsole, controller);
                        }
                    }

                    //Update the controllers if there are non-wait inputs
                    for (int waitIdx = 0; waitIdx < nonWaits.Length; waitIdx++)
                    {
                        //Store by ref and change directly to avoid calling the indexer twice
                        ref int nonWaitVal = ref nonWaits[waitIdx];

                        if (nonWaitVal > 0)
                        {
                            IVirtualController controller = vcMngr.GetController(waitIdx);
                            controller.UpdateController();
                            nonWaitVal = 0;
                        }
                    }
示例#3
0
        private static void ExecuteInput(object obj)
        {
            /*************************************************************
            * PERFORMANCE CRITICAL CODE                                  *
            * Even the smallest change must be thoroughly tested         *
            *************************************************************/

            //Increment running threads
            Interlocked.Increment(ref RunningInputThreads);

            //Get the input list - this should have been validated beforehand
            InputWrapper inputWrapper = (InputWrapper)obj;

            Parser.Input[][] inputArray = inputWrapper.InputArray;

            Stopwatch sw = new Stopwatch();

            List <int> indices = new List <int>(16);
            IVirtualControllerManager vcMngr = InputGlobals.ControllerMngr;

            int controllerCount = vcMngr.ControllerCount;

            int[] nonWaits = new int[controllerCount];

            //This is used to track which controller ports were used across all inputs
            //This helps prevent updating controllers that weren't used at the end
            int[] usedControllerPorts = new int[controllerCount];

            ConsoleBase curConsole = InputGlobals.CurrentConsole;

            //Don't check for overflow to improve performance
            unchecked
            {
                for (int i = 0; i < inputArray.Length; i++)
                {
                    ref Parser.Input[] inputs = ref inputArray[i];

                    indices.Clear();

                    //Press all buttons unless it's a release input
                    for (int j = 0; j < inputs.Length; j++)
                    {
                        indices.Add(j);

                        //Get a reference to avoid copying the struct
                        ref Parser.Input input = ref inputs[j];

                        //Don't do anything for a wait input
                        if (curConsole.IsWait(input) == true)
                        {
                            continue;
                        }

                        int port = input.controllerPort;

                        //Get the controller we're using
                        IVirtualController controller = vcMngr.GetController(port);

                        //These are set to 1 instead of incremented to prevent any chance of overflow
                        nonWaits[port]            = 1;
                        usedControllerPorts[port] = 1;

                        if (input.release == true)
                        {
                            controller.ReleaseInput(input);
                        }
                        else
                        {
                            controller.PressInput(input);
                        }
                    }

                    //Update the controllers if there are non-wait inputs
                    for (int waitIdx = 0; waitIdx < nonWaits.Length; waitIdx++)
                    {
                        if (nonWaits[waitIdx] > 0)
                        {
                            IVirtualController controller = vcMngr.GetController(waitIdx);
                            controller.UpdateController();
                            nonWaits[waitIdx] = 0;
                        }
                    }

                    sw.Start();

                    while (indices.Count > 0)
                    {
                        //End the input prematurely
                        if (StopRunningInputs == true)
                        {
                            goto End;
                        }

                        //Release buttons when we should
                        for (int j = indices.Count - 1; j >= 0; j--)
                        {
                            ref Parser.Input input = ref inputs[indices[j]];

                            if (sw.ElapsedMilliseconds < input.duration)
                            {
                                continue;
                            }

                            //Release if the input isn't a hold and isn't a wait input
                            if (input.hold == false && curConsole.IsWait(input) == false)
                            {
                                int port = input.controllerPort;

                                //Get the controller we're using
                                IVirtualController controller = vcMngr.GetController(port);

                                controller.ReleaseInput(input);

                                //Track that we have a non-wait or hold input so we can update the controller with all input releases at once
                                nonWaits[port] = 1;

                                usedControllerPorts[port] = 1;
                            }

                            indices.RemoveAt(j);
                        }

                        //Update the controllers if there are non-wait inputs
                        for (int waitIdx = 0; waitIdx < nonWaits.Length; waitIdx++)
                        {
                            if (nonWaits[waitIdx] > 0)
                            {
                                IVirtualController controller = vcMngr.GetController(waitIdx);
                                controller.UpdateController();

                                nonWaits[waitIdx] = 0;
                            }
                        }
                    }
        public override void ExecuteCommand(EvtChatCommandArgs e)
        {
            List <string> args = e.Command.ArgumentsAsList;

            if (args.Count != 1)
            {
                BotProgram.MsgHandler.QueueMessage("Usage: state #");
                return;
            }

            string stateNumStr = args[0];

            if (int.TryParse(stateNumStr, out int stateNum) == false)
            {
                BotProgram.MsgHandler.QueueMessage($"Invalid state number.");
                return;
            }

            string loadStateStr = $"ls{stateNum}";

            if (InputGlobals.CurrentConsole.ButtonInputMap.ContainsKey(loadStateStr) == false)
            {
                BotProgram.MsgHandler.QueueMessage($"Invalid state number.");
                return;
            }

            User user = BotProgram.GetOrAddUser(e.Command.ChatMessage.Username, false);

            //Check if the user can perform this input
            ParserPostProcess.InputValidation inputValidation = ParserPostProcess.CheckInputPermissions(user.Level, loadStateStr, BotProgram.BotData.InputAccess.InputAccessDict);

            //If the input isn't valid, exit
            if (inputValidation.IsValid == false)
            {
                if (string.IsNullOrEmpty(inputValidation.Message) == false)
                {
                    BotProgram.MsgHandler.QueueMessage(inputValidation.Message);
                }

                return;
            }

            //Load states are always performed on the first controller
            IVirtualController joystick = InputGlobals.ControllerMngr.GetController(0);

            joystick.PressButton(InputGlobals.CurrentConsole.ButtonInputMap[loadStateStr]);
            joystick.UpdateController();

            BotProgram.MsgHandler.QueueMessage($"Loaded state {stateNum}!");

            //Wait a bit before releasing the input
            const float wait = 50f;
            Stopwatch   sw   = Stopwatch.StartNew();

            while (sw.ElapsedMilliseconds < wait)
            {
            }

            joystick.ReleaseButton(InputGlobals.CurrentConsole.ButtonInputMap[loadStateStr]);
            joystick.UpdateController();
        }