Example #1
0
        /// <summary>
        /// Carries out a set of inputs.
        /// </summary>
        /// <param name="inputList">A list of lists of inputs to execute.</param>
        public static void CarryOutInput(List <List <Parser.Input> > inputList)
        {
            /*Kimimaru: We're using a thread pool for efficiency
             * Though very unlikely, there's a chance the input won't execute right away if it has to wait for a thread to be available
             * However, there are often plenty of available threads, so this shouldn't be an issue since we use only one thread per input string
             * Uncomment the following lines to see how many threads are supported in the pool on your machine */
            //ThreadPool.GetMinThreads(out int workermin, out int completionmin);
            //ThreadPool.GetMaxThreads(out int workerthreads, out int completionPortThreads);
            //Console.WriteLine($"Min workers: {workermin} Max workers: {workerthreads} Min async IO threads: {completionmin} Max async IO threads: {completionPortThreads}");

            //Kimimaru: Copy the input list over to an array, which is more performant
            //and lets us bypass redundant copying and bounds checks in certain instances
            //This matters once we've begun processing inputs since we're
            //trying to reduce the delay between pressing and releasing inputs as much as we can
            Parser.Input[][] inputArray = new Parser.Input[inputList.Count][];
            for (int i = 0; i < inputArray.Length; i++)
            {
                inputArray[i] = inputList[i].ToArray();
            }

            InputWrapper inputWrapper = new InputWrapper(inputArray);

            ThreadPool.QueueUserWorkItem(new WaitCallback(ExecuteInput), inputWrapper);
        }
Example #2
0
        //Kimimaru: Think of a faster way to do this; it's rather slow
        //The idea is to look through and see the inputs that would be held at the same time and avoid the given combo
        //One list is for held inputs with another for pressed inputs - the sum of their counts is compared with the invalid combo list's count
        //Released inputs do not count

        public static bool ValidateButtonCombos(List <List <Parser.Input> > inputs, List <string> invalidCombo)
        {
            int controllerCount = InputGlobals.ControllerMngr.ControllerCount;

            //These dictionaries are for each controller port
            Dictionary <int, List <string> > currentComboDict = new Dictionary <int, List <string> >(controllerCount);
            Dictionary <int, List <string> > subComboDict     = new Dictionary <int, List <string> >(controllerCount);

            for (int i = 0; i < controllerCount; i++)
            {
                IVirtualController controller = InputGlobals.ControllerMngr.GetController(i);
                if (controller.IsAcquired == false)
                {
                    continue;
                }

                //Add already pressed inputs from all controllers
                for (int j = 0; j < invalidCombo.Count; j++)
                {
                    string button = invalidCombo[j];
                    if (controller.GetButtonState(InputGlobals.CurrentConsole.ButtonInputMap[button]) == ButtonStates.Pressed)
                    {
                        if (currentComboDict.ContainsKey(i) == false)
                        {
                            currentComboDict[i] = new List <string>(invalidCombo.Count);
                        }
                        currentComboDict[i].Add(button);
                    }
                }
            }

            //If all these inputs are somehow pressed already, whatever we do now doesn't matter
            //However, returning false here would prevent any further inputs from working, so
            //give a chance to check other inputs (such as releasing)

            for (int i = 0; i < inputs.Count; i++)
            {
                List <Parser.Input> inputList = inputs[i];

                //Clear sublists
                foreach (List <string> subList in subComboDict.Values)
                {
                    subList.Clear();
                }

                for (int j = 0; j < inputList.Count; j++)
                {
                    Parser.Input input = inputList[j];

                    //Get controller port and initialize
                    int port = input.controllerPort;

                    //Ensure a currentcombo entry is available for this port
                    if (currentComboDict.ContainsKey(port) == false)
                    {
                        currentComboDict[port] = new List <string>(invalidCombo.Count);
                    }

                    //Ensure a subcombo entry is available for this port
                    if (subComboDict.ContainsKey(port) == false)
                    {
                        subComboDict[port] = new List <string>(invalidCombo.Count);
                    }

                    //Current and sub combo lists
                    List <string> currentCombo = currentComboDict[port];

                    List <string> subCombo = subComboDict[port];

                    //Check if this input is in the invalid combo
                    if (invalidCombo.Contains(input.name) == true)
                    {
                        //If it's not a release input and isn't in the held or current inputs, add it
                        if (input.release == false && subCombo.Contains(input.name) == false && currentCombo.Contains(input.name) == false)
                        {
                            subCombo.Add(input.name);

                            //Check the count after adding
                            if ((subCombo.Count + currentCombo.Count) == invalidCombo.Count)
                            {
                                return(false);
                            }
                        }

                        //For holds, use the held combo
                        if (input.hold == true)
                        {
                            if (currentCombo.Contains(input.name) == false)
                            {
                                //Remove from the subcombo to avoid duplicates
                                currentCombo.Add(input.name);
                                subCombo.Remove(input.name);

                                if ((currentCombo.Count + subCombo.Count) == invalidCombo.Count)
                                {
                                    return(false);
                                }
                            }
                        }
                        //If released, remove from the current combo
                        else if (input.release == true)
                        {
                            currentCombo.Remove(input.name);
                        }
                    }
                }
            }

            return(true);
        }
Example #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;
                            }
                        }
                    }