MVP checks / mvp (push) Canceled after 0s
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.
145 lines
6.0 KiB
JavaScript
145 lines
6.0 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import {
|
|
affectedSectionKeys,
|
|
createAmbientOcclusionSampler,
|
|
isAmbientOccluder,
|
|
} from "../ambient-occlusion.js";
|
|
import { unitBox } from "../math.js";
|
|
|
|
const top = [[0, 1, 1], [1, 1, 1], [1, 1, 0], [0, 1, 0]];
|
|
const stone = { state: "minecraft:stone", render: [unitBox] };
|
|
const slab = { min: [0, 0, 0], max: [1, 0.5, 1] };
|
|
const materialMap = () => new Map([
|
|
[1, stone],
|
|
[2, { state: "minecraft:stone_slab[type=bottom]", render: [slab] }],
|
|
]);
|
|
const blockMap = (...cells) => new Map(cells.map(([pos, id = 1]) => [pos.join(","), id]));
|
|
const sampleTop = (blocks, materials = materialMap(), box = unitBox, pos = [0, 0, 0]) =>
|
|
createAmbientOcclusionSampler(blocks, materials)(pos, box, [0, 1, 0], top);
|
|
|
|
test("an exposed flat floor has no dark grid or dark silhouette corners", () => {
|
|
const blocks = new Map();
|
|
for (let x = -2; x <= 2; x++)
|
|
for (let z = -2; z <= 2; z++) blocks.set(`${x},0,${z}`, 1);
|
|
assert.deepEqual(sampleTop(blocks), [1, 1, 1, 1]);
|
|
assert.deepEqual(sampleTop(blockMap([[0, 0, 0], 1])), [1, 1, 1, 1]);
|
|
});
|
|
|
|
test("one adjacent wall shades only its two touching vertices", () => {
|
|
assert.deepEqual(sampleTop(blockMap([[-1, 1, 0], 1])), [0.92, 1, 1, 0.92]);
|
|
});
|
|
|
|
test("diagonal contact shades one corner and two enclosing walls saturate it", () => {
|
|
assert.deepEqual(sampleTop(blockMap([[-1, 1, -1], 1])), [1, 1, 1, 0.92]);
|
|
const sides = [[[-1, 1, 0], 1], [[0, 1, -1], 1]];
|
|
assert.deepEqual(sampleTop(blockMap(...sides)), [0.92, 1, 0.92, 0.76]);
|
|
assert.deepEqual(sampleTop(blockMap(...sides, [[-1, 1, -1], 1])),
|
|
[0.92, 1, 0.92, 0.76]);
|
|
});
|
|
|
|
test("all six face orientations sample the outward hemisphere", () => {
|
|
for (let axis = 0; axis < 3; axis++)
|
|
for (const sign of [-1, 1]) {
|
|
const normal = [0, 0, 0];
|
|
normal[axis] = sign;
|
|
const tangent = [0, 1, 2].filter((a) => a !== axis);
|
|
const vertices = [[0, 0], [1, 0], [1, 1], [0, 1]].map(([u, v]) => {
|
|
const result = [0, 0, 0];
|
|
result[axis] = sign > 0 ? 1 : 0;
|
|
result[tangent[0]] = u;
|
|
result[tangent[1]] = v;
|
|
return result;
|
|
});
|
|
const diagonal = [0, 0, 0];
|
|
diagonal[axis] = sign;
|
|
diagonal[tangent[0]] = -1;
|
|
diagonal[tangent[1]] = -1;
|
|
const sample = createAmbientOcclusionSampler(blockMap([diagonal, 1]), materialMap());
|
|
assert.deepEqual(sample([0, 0, 0], unitBox, normal, vertices), [0.92, 1, 1, 1],
|
|
`normal ${normal}`);
|
|
}
|
|
});
|
|
|
|
test("actual slab height controls occlusion rather than whole-cell occupancy", () => {
|
|
assert.deepEqual(sampleTop(blockMap([[-1, 0, 0], 2]), materialMap(), slab),
|
|
[1, 1, 1, 1]);
|
|
assert.deepEqual(sampleTop(blockMap([[-1, 0, 0], 1]), materialMap(), slab),
|
|
[0.92, 1, 1, 0.92]);
|
|
assert.deepEqual(sampleTop(blockMap([[-1, 1, 0], 2])), [0.92, 1, 1, 0.92]);
|
|
});
|
|
|
|
test("neighboring boxes within one stair model shade its recessed tread", () => {
|
|
const tread = { min: [0, 0, 0], max: [0.5, 0.5, 1] };
|
|
const riser = { min: [0.5, 0, 0], max: [1, 1, 1] };
|
|
const materials = new Map([[1, { ...stone, render: [tread, riser] }]]);
|
|
assert.deepEqual(sampleTop(blockMap([[0, 0, 0], 1]), materials, tread),
|
|
[1, 0.92, 0.92, 1]);
|
|
});
|
|
|
|
test("render boxes extending beyond their owner can shade a neighboring face", () => {
|
|
const materials = new Map([[1, {
|
|
...stone, render: [{ min: [0, 0, 0], max: [1, 1.5, 1] }],
|
|
}]]);
|
|
assert.deepEqual(sampleTop(blockMap([[-1, 0, 0], 1]), materials),
|
|
[0.92, 1, 1, 0.92]);
|
|
});
|
|
|
|
test("transparent and cutout materials never act like opaque corner cubes", () => {
|
|
for (const overrides of [
|
|
{ transparent: true }, { opacity: 0.4 }, { cutout: true },
|
|
{ state: "minecraft:oak_leaves[persistent=true]" },
|
|
{ state: "minecraft:red_stained_glass" }, { state: "minecraft:water[level=0]" },
|
|
{ state: "minecraft:cobweb" }, { state: "minecraft:short_grass" },
|
|
]) {
|
|
const material = { ...stone, ...overrides };
|
|
assert.equal(isAmbientOccluder(material), false);
|
|
assert.deepEqual(sampleTop(blockMap([[-1, 1, 0], 1]), new Map([[1, material]])),
|
|
[1, 1, 1, 1]);
|
|
}
|
|
assert.equal(isAmbientOccluder({ ...stone, state: "minecraft:grass_block" }), true);
|
|
assert.equal(isAmbientOccluder({ ...stone, state: "minecraft:brown_mushroom_block" }), true);
|
|
});
|
|
|
|
test("a texture-pack cutout predicate is cached per material", () => {
|
|
let calls = 0;
|
|
const sample = createAmbientOcclusionSampler(blockMap([[-1, 1, 0], 1]), materialMap(),
|
|
(material, id) => { calls++; return id !== 1; });
|
|
assert.deepEqual(sample([0, 0, 0], unitBox, [0, 1, 0], top), [1, 1, 1, 1]);
|
|
sample([1, 0, 0], unitBox, [0, 1, 0], top);
|
|
assert.equal(calls, 2);
|
|
});
|
|
|
|
test("new rebuild samplers observe edits without keeping stale cached air", () => {
|
|
const blocks = blockMap();
|
|
assert.deepEqual(sampleTop(blocks), [1, 1, 1, 1]);
|
|
blocks.set("-1,1,0", 1);
|
|
assert.deepEqual(sampleTop(blocks), [0.92, 1, 1, 0.92]);
|
|
blocks.delete("-1,1,0");
|
|
assert.deepEqual(sampleTop(blocks), [1, 1, 1, 1]);
|
|
});
|
|
|
|
test("empty render geometry casts no AO and unknown blocks match placeholder cubes", () => {
|
|
assert.deepEqual(sampleTop(blockMap([[-1, 1, 0], 1]), new Map([[1, { ...stone, render: [] }]])),
|
|
[1, 1, 1, 1]);
|
|
assert.deepEqual(sampleTop(blockMap([[-1, 1, 0], 99])), [0.92, 1, 1, 0.92]);
|
|
});
|
|
|
|
test("section invalidation includes corners across positive and negative boundaries", () => {
|
|
assert.deepEqual(affectedSectionKeys([5, 5, 5]), ["0,0,0"]);
|
|
assert.deepEqual(affectedSectionKeys([16, 5, 5]), ["0,0,0", "1,0,0"]);
|
|
assert.deepEqual(affectedSectionKeys([15, 15, 15]), [
|
|
"0,0,0", "0,0,1", "0,1,0", "0,1,1",
|
|
"1,0,0", "1,0,1", "1,1,0", "1,1,1",
|
|
]);
|
|
assert.equal(affectedSectionKeys([-1, -1, -1]).length, 8);
|
|
assert.ok(affectedSectionKeys([-1, -1, -1]).includes("0,0,0"));
|
|
assert.ok(affectedSectionKeys([0, 0, 0]).includes("-1,-1,-1"));
|
|
});
|
|
|
|
test("extended render geometry widens the affected sections", () => {
|
|
assert.deepEqual(affectedSectionKeys([5, 13, 5]), ["0,0,0"]);
|
|
assert.deepEqual(affectedSectionKeys([5, 13, 5], [{ min: [0, 0, 0], max: [1, 3, 1] }]),
|
|
["0,0,0", "0,1,0"]);
|
|
});
|