diablo2-web/tests/net-scene-integration.test.ts

49 lines
2.4 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { createNetSimulation } from '../src/scene/net-scene.ts'
import { createWorld, addPlayer } from '../src/game/combat.ts'
import { LockstepSession } from '../src/net/lockstep.ts'
describe('net-scene lockstep integration', () => {
it('detects inventory desyncs when one peer picks up an item', () => {
// Setup identical honest and tampered simulations
const worldA = createWorld(0, 0)
addPlayer(worldA, 10, 0)
// Create worldB identical to worldA
const worldB = createWorld(0, 0)
addPlayer(worldB, 10, 0)
const options = {
playerSpeed: 100, playerReach: 20, playerCooldownTicks: 10,
playerDamage: 10, playerManaPerAttack: 0, respawnTicks: 10,
}
const terrain = { overlap: () => 0 }
const simA = createNetSimulation(worldA, options, terrain, [0, 100], 2)
const simB = createNetSimulation(worldB, options, terrain, [0, 100], 2)
// BOTH have an item at the same coordinate.
// However, A has Gold, B has a Potion.
simA.ground.push({ x: 0, y: 0, item: { name: 'Gold', stack: 100, value: 100, base: {} as unknown as import('../src/game/items.ts').ItemBase, prefix: null, suffix: null, level: 1, invWidth: 1, invHeight: 1, stats: {} } })
simB.ground.push({ x: 0, y: 0, item: { name: 'Potion', stack: 1, value: 5, base: {} as unknown as import('../src/game/items.ts').ItemBase, prefix: null, suffix: null, level: 1, invWidth: 1, invHeight: 1, stats: {} } })
const sessionA = new LockstepSession({ peers: 2, inputDelayTicks: 0 }, simA.simulation)
const sessionB = new LockstepSession({ peers: 2, inputDelayTicks: 0 }, simB.simulation)
// Tick 0: BOTH pick up!
// At the end of the tick, both grounds are empty. But inventories differ.
sessionA.submit(0, { tick: 0, movement: {x:0, y:0}, attack: false, pickup: true, talk: false, skill: 0 })
sessionA.submit(1, { tick: 0, movement: {x:0, y:0}, attack: false, pickup: false, talk: false, skill: 0 })
sessionB.submit(0, { tick: 0, movement: {x:0, y:0}, attack: false, pickup: true, talk: false, skill: 0 })
sessionB.submit(1, { tick: 0, movement: {x:0, y:0}, attack: false, pickup: false, talk: false, skill: 0 })
const outA = sessionA.step()
const outB = sessionB.step()
expect(outA.kind).toBe('stepped')
expect(outB.kind).toBe('stepped')
if (outA.kind === 'stepped' && outB.kind === 'stepped') { expect(outA.hash).not.toBe(outB.hash) }
})
})