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; } } }
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; } }