Release alpha 14 menu and developer test tools

This commit is contained in:
Emporex committed 2026-10-11 20:21:59 +02:00
1 parent 026d0bad58
commit a536b698f7
5 files changed
+464 -76

No files matched your search

+46 -11
View File
@@ -37,7 +37,8 @@ const balanceNk = {
}
}
};
assert.throws(() => context.rpcGetGameBalance({}, {}, balanceNk, "{}"), /authentication required/);
const serverBalance = JSON.parse(context.rpcGetGameBalance({}, {}, balanceNk, "{}"));
assert.strictEqual(serverBalance.config.towers[0].damage, 22, "The internal PHP page calls balance read through Nakama's HTTP-key server-to-server RPC context, which has no userId.");
const adminBalance = JSON.parse(context.rpcGetGameBalance({ userId: "pilot-b" }, {}, balanceNk, "{}"));
assert.strictEqual(adminBalance.config.towers[0].damage, 22);
const editedBalance = JSON.parse(JSON.stringify(adminBalance.config));
@@ -372,16 +373,50 @@ assert.strictEqual(state.towers.length, 2);
assert.strictEqual(state.credits[0], 310);
assert.strictEqual(state.credits[1], 250);
state = context.matchLoop({}, logger, nk, dispatcher, 6, state, [message(presenceA, 13, {})]).state;
state = context.matchLoop({}, logger, nk, dispatcher, 51, state,
[message(presenceA, 10, { tower_type: 7, x: 2200, y: 600 }),
message(presenceB, 15, { password: "incorrect" }),
message(presenceB, 16, { amount: 500 })]).state;
assert.strictEqual(state.towers.length, 2, "Admin tower builds must be rejected before developer authorization.");
assert.strictEqual(state.credits[1], 250, "Unauthorized player must not be able to adjust test energy.");
assert.strictEqual(state.devAuthorized["pilot-b"], undefined, "Wrong developer password must not authorize the player.");
state = context.matchLoop({}, logger, nk, dispatcher, 52, state,
[message(presenceB, 15, { password: "Spring.3" })]).state;
assert.strictEqual(state.devAuthorized["pilot-b"], undefined, "A non-admin account must not gain developer access even with the password.");
assert.strictEqual(context.DEV_ADMIN_USER_IDS["pilot-a"], undefined);
assert.strictEqual(context.DEV_ADMIN_USER_IDS["6605c44c-17a2-4cc4-bf3e-e772fd6229b0"], true);
context.DEV_ADMIN_USER_IDS["pilot-a"] = true;
state = context.matchLoop({}, logger, nk, dispatcher, 53, state,
[message(presenceA, 15, { password: "Spring.3" })]).state;
assert.strictEqual(state.devAuthorized["pilot-a"], true, "Correct developer password should authorize this player for the match.");
state = context.matchLoop({}, logger, nk, dispatcher, 54, state,
[message(presenceA, 16, { amount: 500 })]).state;
assert.strictEqual(state.credits[0], 810, "Authorized test energy addition should change server credits by 500.");
state = context.matchLoop({}, logger, nk, dispatcher, 55, state,
[message(presenceA, 16, { amount: -500 })]).state;
assert.strictEqual(state.credits[0], 310, "Authorized test energy removal should change server credits by 500.");
state = context.matchLoop({}, logger, nk, dispatcher, 56, state,
[message(presenceA, 10, { tower_type: 7, x: 2200, y: 600 })]).state;
assert.ok(state.towers.some(tower => tower.type === 7 && tower.owner === 0), "Authorized player may build the admin turret anywhere on the co-op map.");
const adminCombatState = {
balance: state.balance,
towers: [{ id: 99, type: 7, x: 2200, y: 600, owner: 0, level: 1, cooldown: 0, angle: 0 }],
enemies: [{ id: 99, type: 8, x: 2250, y: 600, hp: 100000, max_hp: 100000, shield: true, shield_hp: 1000, shield_resistance: 0.28 }],
shots: [], credits: [0, 0]
};
context.updateTowers(adminCombatState, 0.1);
assert.strictEqual(adminCombatState.enemies.length, 0, "One admin turret shot should destroy even a shielded enemy.");
state = context.matchLoop({}, logger, nk, dispatcher, 57, state, [message(presenceA, 13, {})]).state;
assert.strictEqual(state.wave, 1);
assert.strictEqual(state.waveActive, true);
assert.strictEqual(context.snapshot(state, 6).wave_types_remaining.length, state.spawnRemaining);
assert.strictEqual(context.snapshot(state, 56).wave_types_remaining.length, state.spawnRemaining);
const groundSchedule = context.buildWaveSchedule(state, 3, context.wavePopulation(state, 3));
assert.ok(groundSchedule.some(entry => context.ENEMIES[entry.type].category === "ground"), "Ground units should enter the wave schedule from wave 3.");
for (let tick = 7; tick < 30; tick++) state = context.matchLoop({}, logger, nk, dispatcher, tick, state, []).state;
for (let tick = 57; tick < 80; tick++) state = context.matchLoop({}, logger, nk, dispatcher, tick, state, []).state;
assert.ok(state.enemies.length > 0 || state.spawnRemaining > 0);
assert.ok(sent.some(entry => entry.opCode === 1 && entry.data.started === true));
const compactSnapshot = context.snapshot(state, 29);
const compactSnapshot = context.snapshot(state, 79);
const untrimmedSnapshot = { ...compactSnapshot, towers: state.towers, enemies: state.enemies };
assert.ok(JSON.stringify(compactSnapshot).length < JSON.stringify(untrimmedSnapshot).length, "Frequent snapshots should omit simulation-only properties.");
assert.ok(compactSnapshot.towers.every(tower => !Object.hasOwn(tower, "cooldown")));
@@ -389,17 +424,17 @@ assert.ok(compactSnapshot.enemies.every(enemy => !Object.hasOwn(enemy, "shield_r
assert.ok(state.towers.every(tower => Object.hasOwn(tower, "cooldown")), "Network serialization must not alter simulation state.");
const towerA = state.towers.find(tower => tower.owner === 0);
state = context.matchLoop({}, logger, nk, dispatcher, 30, state, [message(presenceA, 11, { tower_id: towerA.id })]).state;
state = context.matchLoop({}, logger, nk, dispatcher, 80, state, [message(presenceA, 11, { tower_id: towerA.id })]).state;
assert.strictEqual(state.towers.find(tower => tower.id === towerA.id).level, 2);
state = context.matchLoop({}, logger, nk, dispatcher, 31, state, [message(presenceA, 12, { tower_id: towerA.id })]).state;
state = context.matchLoop({}, logger, nk, dispatcher, 81, state, [message(presenceA, 12, { tower_id: towerA.id })]).state;
assert.ok(!state.towers.some(tower => tower.id === towerA.id));
state = context.matchLeave({}, logger, nk, dispatcher, 32, state, [presenceB]).state;
state = context.matchLeave({}, logger, nk, dispatcher, 82, state, [presenceB]).state;
assert.strictEqual(state.started, true);
assert.strictEqual(state.pausedForReconnect, true);
assert.strictEqual(context.snapshot(state, 32).players[1].connected, false);
assert.strictEqual(context.matchJoinAttempt({}, logger, nk, dispatcher, 33, state, presenceB, {}).accept, true);
state = context.matchJoin({}, logger, nk, dispatcher, 33, state, [presenceB]).state;
assert.strictEqual(context.snapshot(state, 82).players[1].connected, false);
assert.strictEqual(context.matchJoinAttempt({}, logger, nk, dispatcher, 83, state, presenceB, {}).accept, true);
state = context.matchJoin({}, logger, nk, dispatcher, 83, state, [presenceB]).state;
assert.strictEqual(state.pausedForReconnect, false);
assert.strictEqual(state.slots["pilot-b"], 1);