129 lines
4.1 KiB
JavaScript
129 lines
4.1 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import {
|
|
DEAD_AIR_ARTIFACT_SPAWN,
|
|
DEAD_AIR_EXTRACTION,
|
|
DEAD_AIR_SNAPSHOT_RATE,
|
|
DEAD_AIR_TICK_RATE,
|
|
DEAD_AIR_WARDEN_ID_BASE,
|
|
deadAirGame,
|
|
} from "../dist/index.js";
|
|
|
|
function input(overrides = {}) {
|
|
return {
|
|
forward: 0,
|
|
strafe: 0,
|
|
yaw: 0,
|
|
pitch: 0,
|
|
fire: false,
|
|
sprint: false,
|
|
reload: false,
|
|
interact: false,
|
|
toggleFlashlight: false,
|
|
throwDecoy: false,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
test("DEAD AIR runs through the generic multiplayer contract", () => {
|
|
assert.equal(deadAirGame.tickRateHz, DEAD_AIR_TICK_RATE);
|
|
assert.equal(deadAirGame.snapshotRateHz, DEAD_AIR_SNAPSHOT_RATE);
|
|
const server = deadAirGame.createServer();
|
|
server.addPlayer(1);
|
|
const player = server.currentState.players.find((candidate) => candidate.id === 1);
|
|
player.x = DEAD_AIR_ARTIFACT_SPAWN.x;
|
|
player.z = DEAD_AIR_ARTIFACT_SPAWN.z;
|
|
|
|
assert.deepEqual(server.submitInput(1, {
|
|
sequence: 1,
|
|
targetTick: 1,
|
|
observedTick: 0,
|
|
input: input({ interact: true }),
|
|
}), { accepted: true });
|
|
const grabbed = server.step();
|
|
assert.equal(player.carryingArtifact, true);
|
|
assert.ok(grabbed.events.some((event) => event.type === "artifact" && event.action === "grabbed"));
|
|
|
|
player.x = DEAD_AIR_EXTRACTION.x;
|
|
player.z = DEAD_AIR_EXTRACTION.z;
|
|
const extracted = server.step();
|
|
assert.equal(player.extractions, 1);
|
|
assert.ok(extracted.events.some((event) => event.type === "artifact" && event.action === "extracted"));
|
|
});
|
|
|
|
test("an occluded warden never appears in snapshots and becomes anonymous sound", () => {
|
|
const server = deadAirGame.createServer();
|
|
server.addPlayer(1);
|
|
const viewer = server.currentState.players.find((player) => player.id === 1);
|
|
const hidden = server.currentState.players.find((player) => player.id === DEAD_AIR_WARDEN_ID_BASE);
|
|
for (const player of server.currentState.players) {
|
|
if (player.bot && player.id !== hidden.id) player.alive = false;
|
|
}
|
|
viewer.x = -25;
|
|
viewer.z = 0;
|
|
viewer.yaw = Math.PI / 2;
|
|
viewer.flashlight = true;
|
|
hidden.x = -10;
|
|
hidden.z = 0;
|
|
hidden.flashlight = false;
|
|
|
|
const snapshot = server.createSnapshot(1, 0).state;
|
|
assert.equal(snapshot.players.some((player) => player.id === hidden.id), false);
|
|
assert.equal(JSON.stringify(snapshot).includes(hidden.id.toString()), false);
|
|
|
|
const perception = server.createPerceptions(1, [{
|
|
id: 777,
|
|
type: "shot",
|
|
sourceId: hidden.id,
|
|
x: hidden.x,
|
|
z: hidden.z,
|
|
yaw: hidden.yaw,
|
|
pitch: 0,
|
|
}])[0];
|
|
assert.equal(perception.type, "sound");
|
|
assert.equal(perception.cue, "gunshot");
|
|
assert.equal("sourceId" in perception, false);
|
|
assert.equal("x" in perception, false);
|
|
assert.equal("z" in perception, false);
|
|
assert.ok(Number.isInteger(perception.direction));
|
|
});
|
|
|
|
test("private objective coordinates are redacted outside sight", () => {
|
|
const server = deadAirGame.createServer();
|
|
server.addPlayer(1);
|
|
const viewer = server.currentState.players.find((player) => player.id === 1);
|
|
viewer.x = -28;
|
|
viewer.z = 28;
|
|
viewer.yaw = Math.PI;
|
|
viewer.flashlight = false;
|
|
const snapshot = server.createSnapshot(1, 0).state;
|
|
assert.deepEqual(snapshot.artifact, {
|
|
visible: false,
|
|
x: null,
|
|
z: null,
|
|
carrierId: null,
|
|
});
|
|
assert.equal("artifactX" in snapshot, false);
|
|
assert.equal("nextEventId" in snapshot, false);
|
|
});
|
|
|
|
test("visible wardens expose pose but redact combat inventory", () => {
|
|
const server = deadAirGame.createServer();
|
|
server.addPlayer(1);
|
|
const viewer = server.currentState.players.find((player) => player.id === 1);
|
|
const visible = server.currentState.players.find((player) => player.id === DEAD_AIR_WARDEN_ID_BASE);
|
|
viewer.x = -30;
|
|
viewer.z = 30;
|
|
viewer.yaw = Math.PI / 2;
|
|
visible.x = -25;
|
|
visible.z = 30;
|
|
visible.health = 31;
|
|
visible.magazine = 2;
|
|
const replicated = server.createSnapshot(1, 0).state.players.find((player) => player.id === visible.id);
|
|
assert.ok(replicated);
|
|
assert.equal(replicated.x, visible.x);
|
|
assert.equal(replicated.health, null);
|
|
assert.equal(replicated.magazine, null);
|
|
assert.equal(replicated.reserve, null);
|
|
});
|