Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NetworPlayerInputs struct (Experimental) #3954

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

NiftyliuS
Copy link

@NiftyliuS NiftyliuS commented Dec 10, 2024

Note: To reduce the amount of code for the NetworkPlayerControllerBase i want to push some stand alone things.

Network Player Inputs Struct

This struct is intended to transfer the most common inputs as efficiently as possible ( see diagram ) with addition of 2 functions:

Defaults passed in constructor

var previousInputs = new NetworkPlayerInputs(){ .... }
var newInputs = new NetworkPlayerInputs(previousInputs){ movementVector= new Vector2( moveX, moveZ).normalize;

The goal of this feature is to allow the server to easily extend a previous tick inputs in case of partial inputs received
or no inputs received at all ( packet loss )

Extract only the changed inputs

var previousInputs = new NetworkPlayerInputs(){ .... }
var newInputs = new NetworkPlayerInputs(previousInputs){ movementVector= new Vector2( moveX, moveZ).normalize;

NetworkPlayerInputs? changedInputs = newInputs.GetChangedInputsComparedTo(previousInputs);
// null means no changes between the inputs and they dont need to be sent

The goal here is to allow simple extraction of changed inputs to reduce traffic significantly, especially when working with movement vectors.For example:

  • as long as the user holds W there will be no data sent to the server since nothing changed
    • there is no need to send repeating input as server can simply repeat the last received inputs
  • If the user keeps holding W but moves the mouse to look then we will only send rotation information over
    • we can afford sending partial data since we can override the look vector over the previous inputs

This will override the changed inputs of the newInputs.

[edit]

Simplified overrides of 2 NetworkPlayerInputs structs

var previousInputs = new NetworkPlayerInputs(){ .... }
var changes = new NetworkPlayerInputs(){ movementVector= new Vector2( moveX, moveZ).normalize;

var newInputs = previousInputs.OverrideWith(changes)

This is particularly usefull to reduce the code size when sending the changes over network

Usage example

    [Command(requiresAuthority)]
    private void onInputsChange(NetworkPlayerInputs clientInputChanges) {
        // Add changes on top of last known inputs stored on the server
        nextInputs = lastReceivedInputs.OverrideWith(clientInputChanges)
        lastReceivedInputs = nextInputs; // keep track of inputs
    }
    
    public void FixedUpdate() {
      // Send only the input changes from the client
      if (isClient) { 
        NetworkPlayerInputs newInputs = GetInputs();
        NetworkPlayerInputs? changes = newInputs.GetChangedInputsComparedTo(lastInputs)
        // only send if there is atleast 1 change ( excluding tick number )
        if (changes is not null) { 
            changes.TickNumber = currentClientTick;
            onInputsChange(changes.Value);
       }
        lastInputs = newInputs;
        // Do client logic
      }
      
      if (isServer) {
         if (nextInputs is null) { // duplicate last known inputs if no new inputs were sent
            nextInputs = new NetworkPlayerInputs(lastReceivedInputs) {
                TickNumber = currentTick; // update the tick to current;
            }
            // Do server logic
         }    
      }
    }

note: If ticks are not used the TickNumber can be used to pass any number in the range of 0-2047

Fields:

  • Int TickNumber - mutable int of 11bits ( 0-2047 ) that contains the tick the input happened on the client
    • It is required before sending as it is a part of the header
  • Vector2? MovementVector - reduced accuracy (254 fractions) for normalized movement vector (x: -1 to 1, y:-1 to 1)
  • Vector2? JoystickVector - reduced accuracy (254 fractions) for normalized right joystick vector (x: -1 to 1, y:-1 to 1)
  • Vector2? MouseVector - Half precision mouse position vector (float16)
  • byte[]? AdditionalInputs - Any additional inputs required for the game to run, they are compared as a byte array and if any byte is different will be sent

For binary structure see the diagram bellow.

note: In unity in both of the controller sticks produce -1 to 1 values, they are small and can allow for lower precision. If a more precise rotation is requires it is always possible to pass them as MouseVector

Byte Structure Diagram

NetworkPlayerInputsDiagramLight

Summary i guess...

This is 1 of 2 structs i want to introduce to allow for a simple and coherent exchange of inputs and states between server and client.
The second one will be related for the server to send player state for comparison and reconciliation on the client.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant