Skip to content

Instantly share code, notes, and snippets.

@entropylost
Created November 17, 2020 22:20
Show Gist options
  • Save entropylost/2ca32367dc648830c848b46ca1e51ef4 to your computer and use it in GitHub Desktop.
Save entropylost/2ca32367dc648830c848b46ca1e51ef4 to your computer and use it in GitHub Desktop.
Short thing for deterministic lockstep.
const playerId = 123; // Unique ID.
let tick = 0;
let minTick = 0;
const state = [/* INITIAL STATE*/];
const inputs = [[]];
(function run() {
tick++;
// currentInputs is an array of all inputs. Each input is of an "input" type.
// Inputs is an array of inputs, ordered by tick, with each input containing a .playerId which is the
// ID of the player, and a .input which is the "input" type that currentInputs has.
const currentInputs = getAllInputs();
inputs[tick] = currentInputs.map((input) => { playerId, input });
// Send all inputs to all other players.
send({ playerId, inputs: currentInputs, tick });
// Reset the minTick to the current tick, to keep track of where the simulation should restart from.
minTick = tick;
// Poll all messages sent. This will call receive for each sender.
poll();
// Resimulate. For best performance this would be split between multiple different render ticks
// To prevent the game from freezing whenever a packet arrives 10 seconds late.
for (let i = minTick; i < tick; i++) {
state[i] = simulate(state[i - 1], inputs[i]);
}
// Simulate the next state.
state[tick] = simulate(state[tick - 1], inputs[tick]);
requestAnimationFrame(run);
})();
// Second argument is just an arbitrary object sent from the other client.
// Inputs is the type of an array of a "input".
function receive({ playerId, inputs: senderInputs, tick: senderTick }) {
if (tick < senderTick) {
throw new Error('Sender is sending message in future.');
}
inputs[tick].push(...inputs.map((input) => { playerId, input }));
minTick = Math.min(minTick, senderTick);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment