115 lines
3.3 KiB
JavaScript
115 lines
3.3 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { GameDatabaseError } from "./database.mjs";
|
|
import { createOnlineSessionManager } from "./online-session.mjs";
|
|
|
|
function groupSnapshot() {
|
|
return {
|
|
invitations: [],
|
|
group: {
|
|
id: "group-one",
|
|
leaderAccountId: "leader",
|
|
members: [
|
|
{
|
|
accountId: "leader",
|
|
username: "Leader",
|
|
character: { id: "lead", name: "Bulwark", classId: "warrior", raceId: "human", gender: "male", level: 20 },
|
|
role: "tank",
|
|
},
|
|
{
|
|
accountId: "healer",
|
|
username: "Healer",
|
|
character: { id: "heal", name: "Mendara", classId: "priest", raceId: "human", gender: "female", level: 20 },
|
|
role: "healer",
|
|
},
|
|
],
|
|
activity: {
|
|
id: "activity-one",
|
|
type: "dungeon",
|
|
contentId: "wailing-caverns",
|
|
fillWithAi: false,
|
|
partySize: 2,
|
|
startingLevel: null,
|
|
startedAt: Date.now(),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
const presence = {
|
|
position: [1, 2, 3],
|
|
yaw: 0.5,
|
|
health: 900,
|
|
maxHealth: 1_000,
|
|
resource: 400,
|
|
maxResource: 500,
|
|
resourceName: "Mana",
|
|
};
|
|
|
|
test("synchronizes player presence, leader world state, and ordered combat events", () => {
|
|
const manager = createOnlineSessionManager();
|
|
const snapshot = groupSnapshot();
|
|
const leader = manager.sync({ id: "leader" }, snapshot, {
|
|
presence,
|
|
world: { mobs: { boss: { health: 500, maxHealth: 500 } }, encounter: { phase: "boss" } },
|
|
});
|
|
assert.equal(leader.authority, true);
|
|
assert.equal(leader.players[0].character.name, "Bulwark");
|
|
assert.equal(leader.world.mobs.boss.health, 500);
|
|
|
|
const healer = manager.sync({ id: "healer" }, snapshot, {
|
|
presence: { ...presence, position: [4, 5, 6] },
|
|
afterEventId: 0,
|
|
events: [{
|
|
clientEventId: "heal:1",
|
|
kind: "damage",
|
|
sourceActorId: "online-player:healer",
|
|
targetActorId: "boss",
|
|
school: "holy",
|
|
rawAmount: 75,
|
|
effectiveAmount: 60,
|
|
occurredAt: 123,
|
|
}],
|
|
});
|
|
assert.equal(healer.players.length, 2);
|
|
assert.equal(healer.events.length, 1);
|
|
assert.equal(healer.events[0].id, 1);
|
|
assert.equal(healer.events[0].sourceAccountId, "healer");
|
|
|
|
const deduplicated = manager.sync({ id: "healer" }, snapshot, {
|
|
presence,
|
|
afterEventId: 1,
|
|
events: [{
|
|
clientEventId: "heal:1",
|
|
kind: "damage",
|
|
sourceActorId: "online-player:healer",
|
|
targetActorId: "boss",
|
|
rawAmount: 75,
|
|
effectiveAmount: 60,
|
|
}],
|
|
});
|
|
assert.equal(deduplicated.events.length, 0);
|
|
assert.equal(deduplicated.latestEventId, 1);
|
|
});
|
|
|
|
test("rejects non-leader world updates and forged enemy events", () => {
|
|
const manager = createOnlineSessionManager();
|
|
const snapshot = groupSnapshot();
|
|
assert.throws(() => manager.sync({ id: "healer" }, snapshot, {
|
|
presence,
|
|
world: { mobs: {} },
|
|
}), (error) => error instanceof GameDatabaseError && error.code === "activity_authority_required");
|
|
|
|
const state = manager.sync({ id: "healer" }, snapshot, {
|
|
presence,
|
|
events: [{
|
|
clientEventId: "forged",
|
|
kind: "damage",
|
|
sourceActorId: "boss",
|
|
targetActorId: "online-player:leader",
|
|
rawAmount: 1_000_000,
|
|
}],
|
|
});
|
|
assert.equal(state.events.length, 0);
|
|
});
|