This commit is contained in:
111
packages/shared/test/flux.test.mjs
Normal file
111
packages/shared/test/flux.test.mjs
Normal file
@@ -0,0 +1,111 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import {
|
||||
FLUX_BOT_IDS,
|
||||
FLUX_SNAPSHOT_RATE,
|
||||
FLUX_TICK_RATE,
|
||||
fluxGame,
|
||||
} from "../dist/index.js";
|
||||
|
||||
function createThrustPacket(sequence, targetTick, thrust = true) {
|
||||
return {
|
||||
sequence,
|
||||
targetTick,
|
||||
observedTick: Math.max(0, targetTick - 1),
|
||||
input: { thrust },
|
||||
};
|
||||
}
|
||||
|
||||
test("Flux Relay is a complete game defined through the public authoring API", () => {
|
||||
assert.equal(fluxGame.tickRateHz, FLUX_TICK_RATE);
|
||||
assert.equal(fluxGame.snapshotRateHz, FLUX_SNAPSHOT_RATE);
|
||||
|
||||
const server = fluxGame.createServer();
|
||||
server.addPlayer(1);
|
||||
assert.deepEqual(server.submitInput(1, createThrustPacket(1, 1)), {
|
||||
accepted: true,
|
||||
});
|
||||
|
||||
const events = [];
|
||||
for (let tick = 0; tick < 180; tick += 1) {
|
||||
events.push(...server.step().events);
|
||||
}
|
||||
|
||||
assert.ok(server.currentState.cyanScore >= 2);
|
||||
assert.equal(server.currentState.orangeScore, 0);
|
||||
assert.ok(
|
||||
events.some((event) => event.type === "round-won" && event.team === "cyan"),
|
||||
);
|
||||
assert.ok(server.currentState.players.some((player) => player.id === FLUX_BOT_IDS[0]));
|
||||
});
|
||||
|
||||
test("Flux snapshots disclose exact energy only to its owner", () => {
|
||||
const server = fluxGame.createServer();
|
||||
server.addPlayer(1);
|
||||
server.addPlayer(2);
|
||||
|
||||
const playerOneView = server.createSnapshot(1, 0).state;
|
||||
const playerTwoView = server.createSnapshot(2, 0).state;
|
||||
|
||||
assert.equal(playerOneView.players.find((player) => player.id === 1)?.energy, 100);
|
||||
assert.equal(playerOneView.players.find((player) => player.id === 2)?.energy, null);
|
||||
assert.equal(playerTwoView.players.find((player) => player.id === 1)?.energy, null);
|
||||
assert.equal(playerTwoView.players.find((player) => player.id === 2)?.energy, 100);
|
||||
assert.ok(
|
||||
playerOneView.players
|
||||
.filter((player) => player.bot)
|
||||
.every((player) => player.energy === null),
|
||||
);
|
||||
assert.equal("nextEventId" in playerOneView, false);
|
||||
});
|
||||
|
||||
test("the same private Flux event becomes a self cue or anonymous field cue", () => {
|
||||
const server = fluxGame.createServer();
|
||||
server.addPlayer(1);
|
||||
server.addPlayer(2);
|
||||
const player = server.currentState.players.find((candidate) => candidate.id === 1);
|
||||
player.energy = 0.2;
|
||||
|
||||
server.submitInput(1, createThrustPacket(1, 1));
|
||||
const result = server.step();
|
||||
const overheat = result.events.find((event) => event.type === "overheated");
|
||||
assert.ok(overheat);
|
||||
|
||||
const ownCue = server.createPerceptions(1, [overheat])[0];
|
||||
const fieldCue = server.createPerceptions(2, [overheat])[0];
|
||||
assert.equal(ownCue.scope, "self");
|
||||
assert.equal(fieldCue.scope, "field");
|
||||
assert.equal("playerId" in ownCue, false);
|
||||
assert.equal("playerId" in fieldCue, false);
|
||||
});
|
||||
|
||||
test("Flux uses the generic protocol, prediction, acknowledgement, and reconciliation", () => {
|
||||
const server = fluxGame.createServer();
|
||||
server.addPlayer(7);
|
||||
const client = fluxGame.createClient();
|
||||
client.initialize(7, server.createSnapshot(7, 10));
|
||||
|
||||
const packet = client.createInput({ thrust: true }, 1);
|
||||
const wirePacket = fluxGame.protocol.decodeClient(
|
||||
fluxGame.protocol.encodeClient({ kind: "input", packet }),
|
||||
);
|
||||
assert.equal(wirePacket.kind, "input");
|
||||
assert.deepEqual(wirePacket.packet, packet);
|
||||
assert.equal(server.submitInput(7, packet).accepted, true);
|
||||
|
||||
client.step();
|
||||
const result = server.step();
|
||||
client.acknowledge(result.acknowledgements[0].sequence);
|
||||
const wireSnapshot = fluxGame.protocol.decodeServer(
|
||||
fluxGame.protocol.encodeServer({
|
||||
kind: "snapshot",
|
||||
snapshot: server.createSnapshot(7, 20),
|
||||
}),
|
||||
);
|
||||
assert.equal(wireSnapshot.kind, "snapshot");
|
||||
client.reconcile(wireSnapshot.snapshot);
|
||||
|
||||
const local = client.currentState.players.find((player) => player.id === 7);
|
||||
assert.equal(local.thrust, true);
|
||||
assert.ok(local.energy < 100);
|
||||
});
|
||||
Reference in New Issue
Block a user