MVP checks / mvp (push) Waiting to run
Add shared Rust/WASM physics, worker meshing and diagnostics, 64-chunk full-height streaming, atlas texture support, and baseline world import. Document the current implementation and include the supplied in-game lobby screenshot.
71 lines
4.8 KiB
JavaScript
71 lines
4.8 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {SectionVoxelMap} from '../section-voxel-map.js';
|
|
import {decodeSection,applySectionView,applySectionBatch} from '../section-stream.js';
|
|
import {samplePhysicsWorld} from '../player-physics.js';
|
|
const record=(section,id=1)=>({section,palette:[id],runs:[4096,0]});
|
|
const view=()=>({world:'world',revision:0,blocks:new SectionVoxelMap(),loadedSections:new Set(),viewGeneration:0});
|
|
const message=(generation=1)=>({world:'world',revision:0,generation,view_center:[0,0,0],view_min:[-48,-32,-48],view_max:[63,47,63],unload:[]});
|
|
test('compact sections decode known air and preserve negative coordinates without per-voxel keys',()=>{
|
|
const world=new SectionVoxelMap(),cells=decodeSection(record([-1,-4,1],3)).cells;
|
|
world.setSection('-1,-4,1',cells);assert.equal(world.getAt(-1,-64,16),3);assert.equal(world.size,4096);assert.equal(world.byteLength,4);
|
|
world.delete('-1,-64,16');assert.equal(world.size,4095);assert.equal(world.getAt(-1,-64,16),0);
|
|
world.setSection('0,0,0',new Uint32Array(4096));assert.equal(world.hasSection('0,0,0'),true);assert.equal(world.size,4095);
|
|
assert.deepEqual([...world.materialIds()],[3]);world.deleteSection('-1,-4,1');assert.equal(world.size,0);assert.equal(world.sectionCount,1);
|
|
});
|
|
test('malformed compact sections are rejected before any valid section is applied',()=>{
|
|
const v=view();applySectionView(v,message());
|
|
const bad={...record([1,0,0]),runs:[4097,0]};
|
|
assert.equal(applySectionBatch(v,{...message(),sections:[record([0,0,0]),bad]}).status,'resync');assert.equal(v.blocks.size,0);
|
|
for(const runs of [[4095,0],[4096,1],[0,0],[4096.1,0],[4096,-1]])assert.throws(()=>decodeSection({...record([0,0,0]),runs}));
|
|
});
|
|
test('new views retain overlap and reject delayed batches from previous generations',()=>{
|
|
const v=view();applySectionView(v,message());
|
|
applySectionBatch(v,{...message(),sections:[record([-3,0,0]),record([0,0,0])]});const cells=[...v.blocks.sectionEntries()][1][1];
|
|
const moved={...message(2),view_center:[16,0,0],view_min:[-32,-32,-48],view_max:[79,47,63],unload:[[-3,0,0]]};
|
|
assert.deepEqual(applySectionView(v,moved).unload,[[-3,0,0]]);assert.equal(v.blocks.hasSection('-3,0,0'),false);
|
|
assert.equal([...v.blocks.sectionEntries()][0][1],cells);
|
|
assert.equal(applySectionBatch(v,{...message(),sections:[record([-3,0,0])]}).status,'ignored');
|
|
assert.equal(v.blocks.hasSection('-3,0,0'),false);
|
|
});
|
|
test('collision sampling distinguishes missing terrain from a received air section',()=>{
|
|
const world=new SectionVoxelMap(),body={position:[8,3,8],velocity:[0,0,0],pose:'standing'},bounds={min:[0,0,0],max:[15,15,15]};
|
|
assert.equal(samplePhysicsWorld(body,world,new Map(),bounds),null);
|
|
world.setSection('0,0,0',new Uint32Array(4096));assert.deepEqual(samplePhysicsWorld(body,world,new Map(),bounds),{blocks:[]});
|
|
});
|
|
|
|
test('uniform sections remain compact across worker copies and expand only when edited',()=>{
|
|
const world=new SectionVoxelMap();
|
|
world.setSection('0,0,0',new Uint32Array([7]));
|
|
world.setSection('1,0,0',new Uint32Array([0]));
|
|
assert.equal(world.byteLength,8);assert.equal(world.size,4096);
|
|
const samples=[];world.forEachBlock((x,y,z,id)=>samples.push([x,y,z,id]),{min:[14,0,0],max:[17,0,0]});
|
|
assert.deepEqual(samples,[[14,0,0,7],[15,0,0,7]]);
|
|
assert.equal([...world.keysInSection('1,0,0')].length,0);
|
|
world.set('15,0,0',9);assert.equal(world.byteLength,16388);
|
|
assert.equal(world.getAt(14,0,0),7);assert.equal(world.getAt(15,0,0),9);
|
|
assert.deepEqual([...world.materialIds()],[7,9]);
|
|
world.deleteSection('0,0,0');assert.equal(world.byteLength,4);assert.equal(world.size,0);
|
|
world.clear();assert.equal(world.byteLength,0);
|
|
});
|
|
|
|
test('full-height worlds allow flight above the ceiling but still require interior collision data',()=>{
|
|
const blocks=new SectionVoxelMap(),bounds={min:[-32,-64,-32],max:[47,319,47],fullHeight:true};
|
|
const body={position:[8,400,8],velocity:[0,0,0],pose:'standing'};
|
|
assert.deepEqual(samplePhysicsWorld(body,blocks,new Map(),bounds),{blocks:[]});
|
|
body.position[1]=310;assert.equal(samplePhysicsWorld(body,blocks,new Map(),bounds),null);
|
|
blocks.setSection('0,19,0',new Uint32Array([0]));
|
|
assert.deepEqual(samplePhysicsWorld(body,blocks,new Map(),bounds),{blocks:[]});
|
|
});
|
|
|
|
test('large uniform batches load compactly and reject oversized batches atomically',()=>{
|
|
const v=view(),m={...message(),view_min:[-48,-64,-48],view_max:[63,319,63],full_height:true};
|
|
applySectionView(v,m);
|
|
const sections=Array.from({length:128},(_,i)=>record([i%7-3,Math.floor(i/7)-4,0],0));
|
|
assert.equal(applySectionBatch(v,{...m,sections}).status,'applied');
|
|
assert.equal(v.blocks.sectionCount,128);assert.equal(v.blocks.byteLength,512);
|
|
const oversized=[...sections,record([0,0,1])];
|
|
assert.equal(applySectionBatch(v,{...m,sections:oversized}).status,'resync');
|
|
assert.equal(v.blocks.hasSection('0,0,1'),false);
|
|
});
|