Exemplo n.º 1
0
    public void EnqueueInput(NetCommand.PlayerInputCommand command, Player player, uint serverWorldTick)
    {
        // Monitoring.
        DebugUI.ShowValue("sv stale inputs", staleInputs);

        // Calculate the last tick in the incoming command.
        uint maxTick = command.StartWorldTick + (uint)command.Inputs.Length - 1;

        // Scan for inputs which haven't been handled yet.
        if (maxTick >= serverWorldTick)
        {
            uint start = serverWorldTick > command.StartWorldTick
          ? serverWorldTick - command.StartWorldTick : 0;
            for (int i = (int)start; i < command.Inputs.Length; ++i)
            {
                // Apply inputs to the associated player controller and simulate the world.
                var worldTick = command.StartWorldTick + i;
                var tickInput = new TickInput {
                    WorldTick      = (uint)worldTick,
                    RemoteViewTick = (uint)(worldTick - command.ClientWorldTickDeltas[i]),
                    Player         = player,
                    Inputs         = command.Inputs[i],
                };
                queue.Enqueue(tickInput, worldTick);

                // Store the latest input in case the simulation needs to repeat missed frames.
                latestPlayerInput[player.Id] = tickInput;
            }
        }
        else
        {
            staleInputs++;
        }
    }
    // Process a single world tick update.
    protected override void Tick(float dt)
    {
        // Grab inputs.
        var          sampled = handler.SampleInputs();
        PlayerInputs inputs  = sampled.HasValue ? sampled.Value : new PlayerInputs();

        // If the oldest server state is too stale, freeze the player.
        if (Settings.FreezeClientOnStaleServer &&
            WorldTick - lastServerWorldTick >= Settings.MaxStaleServerStateTicks)
        {
            Debug.Log("Server state is too old (is the network connection dead?)");
            inputs = new PlayerInputs();
        }

        // Update our snapshot buffers.
        uint bufidx = WorldTick % 1024;

        localPlayerInputsSnapshots[bufidx]    = inputs;
        localPlayerStateSnapshots[bufidx]     = localPlayer.Controller.ToNetworkState();
        localPlayerWorldTickSnapshots[bufidx] = lastServerWorldTick;

        // Send a command for all inputs not yet acknowledged from the server.
        var unackedInputs         = new List <PlayerInputs>();
        var clientWorldTickDeltas = new List <short>();

        // TODO: lastServerWorldTick is technically not the same as lastAckedInputTick, fix this.
        for (uint tick = lastServerWorldTick; tick <= WorldTick; ++tick)
        {
            unackedInputs.Add(localPlayerInputsSnapshots[tick % 1024]);
            clientWorldTickDeltas.Add((short)(tick - localPlayerWorldTickSnapshots[tick % 1024]));
        }
        var command = new NetCommand.PlayerInputCommand {
            StartWorldTick        = lastServerWorldTick,
            Inputs                = unackedInputs.ToArray(),
            ClientWorldTickDeltas = clientWorldTickDeltas.ToArray(),
        };

        handler.SendInputs(command);

        // Prediction - Apply inputs to the associated player controller and simulate the world.
        localPlayer.Controller.SetPlayerInputs(inputs);
        SimulateWorld(dt);
        ++WorldTick;

        // Notify camera.
        // TODO: Fix this - This is needed because the camera is not hooked into the same
        // world simulation "Simulate()" fixed loop, it can only used its own FixedUpdate, and so
        // it needs to be synced up a bit better.
        // Need some interface for entities that participate.
        GameObject.FindObjectOfType <CPMCameraController>().PlayerPositionUpdated();

        // Process a world state frame from the server if we have it.
        ProcessServerWorldState();
    }
Exemplo n.º 3
0
 private void HandlePlayerInput(NetCommand.PlayerInputCommand cmd, NetPeer peer)
 {
     if (cmd.Inputs == null)
     {
         Debug.LogError("Shouldnt be null here");
     }
     simulation.EnqueuePlayerInput(
         new WithPeer <NetCommand.PlayerInputCommand> {
         Peer = peer, Value = cmd
     });
 }
Exemplo n.º 4
0
 public void SendInputs(NetCommand.PlayerInputCommand command)
 {
     netChannel.SendNSCommand(serverPeer, command);
 }