> For the complete documentation index, see [llms.txt](https://kinematicsoup.gitbook.io/reactor/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kinematicsoup.gitbook.io/reactor/examples/input_processors.md).

# Input Processors

## Summary

Shows how to use an input processor to control when and how inputs are used to update player controllers. This example adds the inputs to a buffer and processes them in an update handler. It tries to keep a minimum number of inputs bufferred so it doesn't run out of inputs to process, and will process inputs faster if the buffer grows too large. If it runs out of inputs to process, it will not update the player's player controllers until it receives new input, which is different from the default behaviour that updates player controllers with the last input again, which could result in a player walking off a ledge if their packets are delayed and the server replays their last input to continue walking when they are near a ledge.

## Description

Server player scripts that implement the *ksIInputProcessor* interface are input processors. The interface has one function `public bool ProcessInput(ksInput input, int numUpdates)` that is called once for every input received from the player it is attached to. The second parameter is the number of inputs being processed in a single frame. If no inputs were available for the frame, the value will be 0 and the input will be a copy of the input from the previous frame. The maximum number of inputs processed in one frame is 8. If there are more inputs waiting to be processed, the remaining inputs will be processed on the following frame.

Call `Player.UpdateControllers(deltaTime, input)` to update all of the player's player controllers. `Time.UnscaledDelta` will be set to the delta time value while updating the controllers if it is non-negative, otherwise it will be unchanged. This function will mark the input as used. You can also mark an input as used by calling `input.Use()`. Returning true will prevent futher input processors from being called. If all input processors return false and none of them mark the input as used, Reactor will update the player controllers with the input and will divide `Time.UnscaledDelta` by the number of inputs being processed on that frame.

When you are done with an input, it is recommended you call `input.CleanUp()` to return the input to its object pool.

The following script provides an example implementation of an input processor. It queues inputs in a buffer and tries to keep a minimum number of inputs bufferred so it doesn't run out of inputs to process, and will process inputs faster if the buffer grows too large. In order for It to work properly `Room.InputInterval` on the client and the server update interval must be the same. Both default to 60 updates per second. You must also set `Room.SendUnchangedInputs` to true on the client. When it is false, clients will only send inputs when inputs changed since the last frame, which results in `ProcessInputs` being called with `numUpdate` being 0 when inputs are not changing. This input processor does not buffer inputs when no inputs were received and expects inputs to be sent even when they are unchanged.

It has a `m_maxInputs` field which is the maximum number of input updates it is allowed to process in one frame using `Time.UnscaledDelta` as the timestep for each player controller update. It increments every frame and decrements when updates are processed, but will not decrement below zero. If it needs to process more inputs than allowed in one frame, the time step for each player controller update is reduced. This prevents it from using time steps that are too large when the client sends more inputs than it should, but otherwise tries to use the same time steps that the client used to generate the inputs.

```c#
using System.Collections.Generic;
using KS.Reactor.Server;
using KS.Reactor;

// Input processor that buffers inputs and tries to keep a minimum number of inputs buffered. To use this, Room.InputInterval
// on the client (defaults to 1/60) and the update interval on the server must be the same. You must also set
// Room.SendUnchangedInput to true on the client.
public class spInputProcessor : ksServerPlayerScript, ksIInputProcessor
{
    // If the input buffer is empty, wait until there are this many frames before processing inputs again.
    [ksEditable]
    public int MinBufferSize = 3;
    // If the input buffer has more frames than this, process 2 at a time.
    [ksEditable]
    public int MaxBufferSize = 6;

    private Queue<ksInput> m_inputBuffer = new Queue<ksInput>();
    private bool m_growingBuffer = true;

    // Maximum number of inputs updates allowed to run in one frame using the full time step. If more updates than
    // this are run, the time step for each update will be reduced. This increments every frame and decrements and
    // updates are run.
    private int m_maxUpdates;

    // Called after all other scripts on all entities are attached.
    public override void Initialize()
    {
        // Add the update handler to update group -1 so it runs before the physics simulation step.
        Room.OnUpdate[-1] += Update;
    }
    
    // Called when the script is detached.
    public override void Detached()
    {
        Room.OnUpdate[-1] -= Update;
    }

    private ulong m_lastFrame;
    
    // Process input and update player controllers. Return true to stop further processing of the input.
    public bool ProcessInput(ksInput input, int numUpdates)
    {
        // Add new inputs to the buffer. NumUpdates is zero if no inputs were received for this frame, in which input
        // is the same as the last input we received and we don't want to add it to the buffer.
        if (numUpdates > 0)
        {
            m_inputBuffer.Enqueue(input);
        }
        return true;
    }
    
    // Called during the update cycle
    private void Update()
    {
        // Increment the maximum number of inputs we can process this frame using the full time step.
        m_maxUpdates++;

        // Check if we need to grow the buffer before we process more inputs.
        m_growingBuffer = m_inputBuffer.Count < (m_growingBuffer ? MinBufferSize : 1);
        if (m_growingBuffer)
        {
            return;
        }

        // Determine how many inputs to process this frame.
        int numUpdates = m_inputBuffer.Count > MaxBufferSize ? 2 : 1;

        // If we're processing more inputs than the max, reduce the delta time step for each input update.
        float deltaTime;
        if (numUpdates > m_maxUpdates)
        {
            deltaTime = Time.UnscaledDelta * m_maxUpdates / numUpdates;
            m_maxUpdates = 0;
        }
        else
        {
            deltaTime = Time.UnscaledDelta;
            m_maxUpdates -= numUpdates;
        }

        // Update player controllers with the inputs and delta time step.
        for (int i = 0; i < numUpdates; i++)
        {
            ksInput input = m_inputBuffer.Dequeue();
            Player.UpdateControllers(deltaTime, input);

            // Calling CleanUp returns the input to its object pool. It is recommended you call this when you are done
            // with an input, though it is not necessary.
            input.CleanUp();
        }
    }
}
```
