Update Healer Man server
This commit is contained in:
1 parent
6114a2295f
commit
69809f7228
593 files changed
+903643
-40774
No files matched your search
@@ -0,0 +1,132 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdtemp, rm } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
import sharp from "sharp";
|
||||
import { Matrix4 } from "three";
|
||||
import { NodeIO } from "@gltf-transform/core";
|
||||
import { ALL_EXTENSIONS } from "@gltf-transform/extensions";
|
||||
import { convertNativeTerrainChunks } from "./terrain-geometry.mjs";
|
||||
import { writeNativeTerrainGlbs } from "./native-terrain-glb.mjs";
|
||||
|
||||
function makeChunk(id, coordinateX, xOffset) {
|
||||
return {
|
||||
id,
|
||||
coordinate: { x: coordinateX, z: 0 },
|
||||
dimension: 1,
|
||||
positions: Float32Array.from([
|
||||
xOffset, 0, 0, xOffset + 1, 0, 0,
|
||||
xOffset, 0, 1, xOffset + 1, 0, 1,
|
||||
]),
|
||||
normals: Float32Array.from(Array.from({ length: 4 }, () => [0, 1, 0]).flat()),
|
||||
uvs: Float32Array.from([0, 0, 1, 0, 0, 1, 1, 1]),
|
||||
indices: Uint16Array.from([0, 2, 3, 0, 0, 0]),
|
||||
triangleVisibilityFlags: Uint8Array.from([1, 0]),
|
||||
visibleSourceTriangles: 1,
|
||||
maskedSourceTriangles: 1,
|
||||
layers: [{ layerId: 4, tileScale: 12, sourceDDS: "textures/tile.dds" }],
|
||||
splatMaps: [{ mapIndex: 0, splatDDS: "weights/a.dds", linearPngFile: "weights/a.png", channelLayerIds: [4] }],
|
||||
material: { variantNames: [`${id}-layer-4`], weightVariantNames: [`${id}-weight-0`] },
|
||||
};
|
||||
}
|
||||
|
||||
function bounds3(array) {
|
||||
const min = [Infinity, Infinity, Infinity];
|
||||
const max = [-Infinity, -Infinity, -Infinity];
|
||||
for (let offset = 0; offset < array.length; offset += 3) {
|
||||
for (let axis = 0; axis < 3; axis += 1) {
|
||||
min[axis] = Math.min(min[axis], array[offset + axis]);
|
||||
max[axis] = Math.max(max[axis], array[offset + axis]);
|
||||
}
|
||||
}
|
||||
return { min, max };
|
||||
}
|
||||
|
||||
test("partitioned native terrain GLBs serialize local chunk bounds and indices for visuals and collision", async () => {
|
||||
const converted = convertNativeTerrainChunks(
|
||||
[makeChunk("left", 0, 0), makeChunk("right", 1, 1)],
|
||||
// Source Z reflection and meter scale match the serializer's production path.
|
||||
new Matrix4().makeScale(0.1, 0.1, -0.1),
|
||||
);
|
||||
const png = await sharp(Buffer.from([
|
||||
255, 0, 0, 255, 0, 255, 0, 255,
|
||||
0, 0, 255, 255, 255, 255, 255, 255,
|
||||
]), { raw: { width: 2, height: 2, channels: 4 } }).png().toBuffer();
|
||||
const textureBySource = new Map([
|
||||
["textures/tile.dds", { imageName: "tile.png", image: png, sourceDDS: "textures/tile.dds", colorSpace: "srgb" }],
|
||||
["weights/a.png", { imageName: "a.png", image: png, sourceDDS: "weights/a.dds", colorSpace: "linear", channelLayerIds: [4] }],
|
||||
]);
|
||||
const directory = await mkdtemp(path.join(os.tmpdir(), "native-terrain-partition-"));
|
||||
const visualFile = path.join(directory, "terrain-visual.glb");
|
||||
const collisionFile = path.join(directory, "terrain-collision.glb");
|
||||
const provenance = {
|
||||
dungeonId: "fixture",
|
||||
dungeonTitle: "Fixture",
|
||||
partitionVisualChunks: true,
|
||||
sourceManifestSha256: "a".repeat(64),
|
||||
sourceWdbSha256: "b".repeat(64),
|
||||
primaryPlacementGuid: "fixture-primary",
|
||||
metersPerSourceUnit: 0.1,
|
||||
textureSourceDDS: ["textures/tile.dds", "weights/a.dds"],
|
||||
};
|
||||
|
||||
try {
|
||||
await writeNativeTerrainGlbs({
|
||||
converted,
|
||||
textureSources: { textureBySource },
|
||||
provenance,
|
||||
visualFile,
|
||||
collisionFile,
|
||||
});
|
||||
const io = new NodeIO().registerExtensions(ALL_EXTENSIONS);
|
||||
const visual = await io.read(visualFile);
|
||||
const collision = await io.read(collisionFile);
|
||||
const visualPrimitives = visual.getRoot().listMeshes().flatMap((mesh) => mesh.listPrimitives())
|
||||
.filter((primitive) => primitive.getExtras()?.runewakerTerrainChunk);
|
||||
const collisionPrimitives = collision.getRoot().listMeshes().flatMap((mesh) => mesh.listPrimitives())
|
||||
.filter((primitive) => primitive.getExtras()?.runewakerTerrainCollisionChunk);
|
||||
|
||||
assert.equal(visualPrimitives.length, 2);
|
||||
assert.equal(collisionPrimitives.length, 2);
|
||||
for (const [primitives, extraKey, indexKey] of [
|
||||
[visualPrimitives, "runewakerTerrainChunk", "visualIndices"],
|
||||
[collisionPrimitives, "runewakerTerrainCollisionChunk", "collisionIndices"],
|
||||
]) {
|
||||
for (const primitive of primitives) {
|
||||
const metadata = primitive.getExtras()[extraKey];
|
||||
const chunk = converted.chunks.find((row) => row.id === metadata.id);
|
||||
assert.ok(chunk, `chunk metadata ${metadata.id} resolves to source geometry`);
|
||||
const positionAccessor = primitive.getAttribute("POSITION");
|
||||
const indexAccessor = primitive.getIndices();
|
||||
assert.ok(positionAccessor);
|
||||
assert.ok(indexAccessor);
|
||||
assert.deepEqual([...positionAccessor.getArray()], [...chunk.positions]);
|
||||
assert.deepEqual([...indexAccessor.getArray()], [...chunk[indexKey]].map((index) => index - chunk.vertexOffset));
|
||||
assert.deepEqual(bounds3(positionAccessor.getArray()), bounds3(chunk.positions));
|
||||
}
|
||||
}
|
||||
|
||||
const visualByChunk = new Map(visualPrimitives.map((primitive) => [
|
||||
primitive.getExtras().runewakerTerrainChunk.id,
|
||||
[...primitive.getIndices().getArray()],
|
||||
]));
|
||||
const collisionByChunk = new Map(collisionPrimitives.map((primitive) => [
|
||||
primitive.getExtras().runewakerTerrainCollisionChunk.id,
|
||||
[...primitive.getIndices().getArray()],
|
||||
]));
|
||||
assert.deepEqual(visualByChunk.get("left"), [0, 3, 2, 0, 0, 0]);
|
||||
assert.deepEqual(visualByChunk.get("right"), [0, 3, 2, 0, 0, 0]);
|
||||
assert.deepEqual(collisionByChunk.get("left"), [0, 3, 2]);
|
||||
assert.deepEqual(collisionByChunk.get("right"), [0, 3, 2]);
|
||||
const close = (actual, expected) => assert.ok(
|
||||
actual.every((value, index) => Math.abs(value - expected[index]) < 1e-6),
|
||||
`${actual} should be within 1e-6 of ${expected}`,
|
||||
);
|
||||
close(bounds3(converted.chunks[0].positions).max, [0.1, 0, 0]);
|
||||
close(bounds3(converted.chunks[1].positions).min, [0.1, 0, -0.1]);
|
||||
close(bounds3(converted.chunks[1].positions).max, [0.2, 0, 0]);
|
||||
} finally {
|
||||
await rm(directory, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user