minecraft-renderer 0.1.104 → 0.1.106
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mesher.js +79 -73
- package/dist/mesher.js.map +4 -4
- package/dist/mesherWasm.js +217 -211
- package/dist/minecraft-renderer.js +60 -60
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +450 -444
- package/package.json +2 -2
- package/src/mesher-legacy/test/tests.test.ts +38 -35
- package/src/mesher-shared/mcDataWorkerShim.test.ts +1 -1
- package/src/mesher-shared/modelsGeometryCommon.test.ts +50 -0
- package/src/mesher-shared/modelsGeometryCommon.ts +18 -2
- package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "minecraft-renderer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.106",
|
|
4
4
|
"description": "The most Modular Minecraft world renderer with Three.js WebGL backend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"lil-gui": "^0.18.2",
|
|
81
81
|
"lodash": "^4.17.21",
|
|
82
82
|
"mc-assets": "^0.2.72",
|
|
83
|
-
"minecraft-data": "3.
|
|
83
|
+
"minecraft-data": "3.117.0",
|
|
84
84
|
"mineflayer": "^4.33.0",
|
|
85
85
|
"npm-run-all": "^4.1.5",
|
|
86
86
|
"prettier": "^3.8.4",
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
//@ts-nocheck
|
|
2
2
|
import { test, expect } from 'vitest'
|
|
3
|
-
import { versions } from 'minecraft-data'
|
|
3
|
+
import minecraftData, { versions } from 'minecraft-data'
|
|
4
4
|
import { INVISIBLE_BLOCKS } from '../../mesher-shared/worldConstants'
|
|
5
5
|
import { setup } from './mesherTester'
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
// newest release that minecraft-data has data for (its protocol versions list can run ahead of the data, e.g. 26.2 / 26.3)
|
|
8
|
+
const lastVersion = versions.pc
|
|
9
|
+
.map(x => x.minecraftVersion)
|
|
10
|
+
.filter(version => !/w|-pre|-rc|-snapshot/.test(version))
|
|
11
|
+
.find(version => minecraftData(version))!
|
|
8
12
|
|
|
9
13
|
const addPositions = [
|
|
10
14
|
// [[0, 0, 0], 'diamond_block'],
|
|
@@ -16,42 +20,41 @@ const addPositions = [
|
|
|
16
20
|
// [[0, 0, -1], 'stone'],
|
|
17
21
|
] as const
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
/** Meshes the default state of every block of the version and returns the blocks that gave no geometry / errored */
|
|
24
|
+
function meshAllBlocks(version: string) {
|
|
25
|
+
const { mesherWorld, getGeometry, pos, mcData } = setup(version, addPositions as any)
|
|
21
26
|
const ignoreAsExpected = new Set([...INVISIBLE_BLOCKS, 'water', 'lava'])
|
|
22
27
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const missingBlocks = {} /* as {[number, number]} */
|
|
26
|
-
const erroredBlocks = {} /* as {[number, number]} */
|
|
28
|
+
const missingBlocks: string[] = []
|
|
29
|
+
const erroredBlocks: string[] = []
|
|
27
30
|
for (const block of mcData.blocksArray) {
|
|
28
31
|
if (ignoreAsExpected.has(block.name)) continue
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// if (block.transparent) continue
|
|
33
|
-
mesherWorld.setBlockStateId(pos, i)
|
|
34
|
-
const start = performance.now()
|
|
35
|
-
const { centerFaces, totalTiles, centerTileNeighbors, attr } = getGeometry()
|
|
36
|
-
time += performance.now() - start
|
|
37
|
-
times++
|
|
38
|
-
if (centerFaces === 0) {
|
|
39
|
-
const objAdd = attr.hadErrors ? erroredBlocks : missingBlocks
|
|
40
|
-
if (objAdd[block.name]) continue
|
|
41
|
-
objAdd[block.name] = true
|
|
42
|
-
// invalidBlocks[block.name] = [i - block.defaultState!, centerTileNeighbors]
|
|
43
|
-
// console.log('INVALID', block.name, centerTileNeighbors, i - block.minStateId)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
32
|
+
mesherWorld.setBlockStateId(pos, block.defaultState)
|
|
33
|
+
const { centerFaces, attr } = getGeometry()
|
|
34
|
+
if (centerFaces === 0) (attr.hadErrors ? erroredBlocks : missingBlocks).push(block.name)
|
|
46
35
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
return { missingBlocks, erroredBlocks }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// These tests only guard against making the renderer worse. Blocks that a new minecraft-data / mc-assets version adds
|
|
40
|
+
// without a model must not fail them (versions are updated automatically), so the newest version is only checked for errors.
|
|
41
|
+
|
|
42
|
+
// TODO resolve creaking_heart issue (1.21.3)
|
|
43
|
+
const KNOWN_MISSING_BLOCKS = ['structure_void']
|
|
44
|
+
// pinned: the data of a released version doesn't grow new blocks, so what renders here must keep rendering
|
|
45
|
+
const pinnedVersion = '1.21.8'
|
|
46
|
+
|
|
47
|
+
test(`Blocks of ${pinnedVersion} that rendered keep rendering`, () => {
|
|
48
|
+
const { missingBlocks, erroredBlocks } = meshAllBlocks(pinnedVersion)
|
|
49
|
+
// fixing a block (it renders now) is fine, only blocks that stopped rendering fail
|
|
50
|
+
expect(missingBlocks.filter(name => !KNOWN_MISSING_BLOCKS.includes(name))).toEqual([])
|
|
51
|
+
expect(erroredBlocks).toEqual([])
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('Newest version: no block fails to mesh', () => {
|
|
55
|
+
const { missingBlocks, erroredBlocks } = meshAllBlocks(lastVersion)
|
|
56
|
+
console.log('Checked blocks of version', lastVersion)
|
|
57
|
+
// visibility only, e.g. new block entities that need a custom model in mc-assets
|
|
58
|
+
if (missingBlocks.length > 0) console.warn(`Blocks of ${lastVersion} that render nothing:`, missingBlocks.join(', '))
|
|
59
|
+
expect(erroredBlocks).toEqual([])
|
|
57
60
|
})
|
|
@@ -58,7 +58,7 @@ describe('mesher worker minecraft-data shim', () => {
|
|
|
58
58
|
const { mcData } = supplyFor('1.21.8')
|
|
59
59
|
const newest = mcData.protocolVersions[0]
|
|
60
60
|
// a version from the future: only the main thread knows it
|
|
61
|
-
const future = { ...mcData.version, minecraftVersion: '99.9', majorVersion: '99', dataVersion: newest.dataVersion + 1000, version: 9999 }
|
|
61
|
+
const future = { ...mcData.version, minecraftVersion: '99.9', majorVersion: '99', dataVersion: (newest.dataVersion ?? 0) + 1000, version: 9999 }
|
|
62
62
|
;(globalThis as any).mcData = {
|
|
63
63
|
...mcData,
|
|
64
64
|
version: future,
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
import { buildElementRotation, buildRotationMatrix, buildXyzRotationMatrix, matmul3 } from './modelsGeometryCommon'
|
|
4
|
+
|
|
5
|
+
const origin: [number, number, number] = [8, 8, 8]
|
|
6
|
+
const close = (a: number[], b: number[]) => a.forEach((v, i) => expect(v).toBeCloseTo(b[i], 9))
|
|
7
|
+
|
|
8
|
+
describe('buildElementRotation', () => {
|
|
9
|
+
it('keeps the axis/angle form working', () => {
|
|
10
|
+
const { localMatrix } = buildElementRotation({ origin, axis: 'y', angle: 90 })
|
|
11
|
+
close(matmul3(localMatrix, [1, 0, 0]), [0, 0, -1])
|
|
12
|
+
close(matmul3(localMatrix, [0, 0, 1]), [1, 0, 0])
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it.each(['x', 'y', 'z'] as const)('x/y/z form about a single axis (%s) equals the axis/angle form', axis => {
|
|
16
|
+
const viaAxis = buildElementRotation({ origin: [2, 5, 11], axis, angle: 37 })
|
|
17
|
+
const viaXyz = buildElementRotation({ origin: [2, 5, 11], [axis]: 37 })
|
|
18
|
+
viaAxis.localMatrix.forEach((row, i) => close(viaXyz.localMatrix[i], row))
|
|
19
|
+
close(viaXyz.localShift, viaAxis.localShift)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('applies a combined x/y/z rotation as rotationZYX: z first, then y, then x', () => {
|
|
23
|
+
const rotation = { x: -40.06672, y: 3.06532, z: -2.57258 }
|
|
24
|
+
const vector = [0.3, -1.2, 0.8]
|
|
25
|
+
const stepwise = matmul3(
|
|
26
|
+
buildRotationMatrix('x', rotation.x),
|
|
27
|
+
matmul3(buildRotationMatrix('y', rotation.y), matmul3(buildRotationMatrix('z', rotation.z), vector))
|
|
28
|
+
)
|
|
29
|
+
close(matmul3(buildXyzRotationMatrix(rotation), vector), stepwise)
|
|
30
|
+
// order matters (guards against x, y, z being swapped)
|
|
31
|
+
const reversed = matmul3(
|
|
32
|
+
buildRotationMatrix('z', rotation.z),
|
|
33
|
+
matmul3(buildRotationMatrix('y', rotation.y), matmul3(buildRotationMatrix('x', rotation.x), vector))
|
|
34
|
+
)
|
|
35
|
+
expect(Math.abs(reversed[0] - stepwise[0]) + Math.abs(reversed[1] - stepwise[1])).toBeGreaterThan(1e-3)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('rotates around the element origin (the origin stays in place)', () => {
|
|
39
|
+
const rotationOrigin: [number, number, number] = [2.53162, 8.56801, 5.10154]
|
|
40
|
+
const { localMatrix, localShift } = buildElementRotation({ origin: rotationOrigin, x: -40, y: 3, z: -2.5 })
|
|
41
|
+
const moved = matmul3(localMatrix, rotationOrigin).map((v, i) => v + localShift[i])
|
|
42
|
+
close(moved, rotationOrigin)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('treats a rotation without any angle as no rotation', () => {
|
|
46
|
+
const { localMatrix, localShift } = buildElementRotation({ origin })
|
|
47
|
+
localMatrix.forEach((row, i) => close(row, [0, 1, 2].map(j => (i === j ? 1 : 0))))
|
|
48
|
+
close(localShift, [0, 0, 0])
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -88,11 +88,27 @@ export function matmulmat3(a, b) {
|
|
|
88
88
|
return te
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/** Plain row-major product a * b (not the transposed convention of matmulmat3) */
|
|
92
|
+
function mulMat3(a: number[][], b: number[][]) {
|
|
93
|
+
return a.map((row, i) => row.map((_, j) => row[0] * b[0][j] + row[1] * b[1][j] + row[2] * b[2][j]))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 26.x element rotation: degrees about each axis, `{ origin, x, y, z }` instead of `{ origin, axis, angle }`.
|
|
98
|
+
* Applied like vanilla's `rotationZYX(z, y, x)`: a vector is rotated about z first, then y, then x.
|
|
99
|
+
*/
|
|
100
|
+
export function buildXyzRotationMatrix({ x = 0, y = 0, z = 0 }: { x?: number; y?: number; z?: number }) {
|
|
101
|
+
return mulMat3(buildRotationMatrix('x', x), mulMat3(buildRotationMatrix('y', y), buildRotationMatrix('z', z)))
|
|
102
|
+
}
|
|
103
|
+
|
|
91
104
|
export function buildElementRotation(rotation) {
|
|
92
|
-
|
|
105
|
+
// elements without an axis use the 26.x x/y/z form (a missing x/y/z is 0, so no rotation at all is the identity)
|
|
106
|
+
const isAxisAngle = rotation.axis !== undefined
|
|
107
|
+
let localMatrix = isAxisAngle ? buildRotationMatrix(rotation.axis, rotation.angle) : buildXyzRotationMatrix(rotation)
|
|
93
108
|
let localShift = vecsub3(rotation.origin, matmul3(localMatrix, rotation.origin))
|
|
94
109
|
|
|
95
|
-
|
|
110
|
+
// rescale is only defined for a single axis rotation
|
|
111
|
+
if (rotation.rescale && isAxisAngle) {
|
|
96
112
|
const FIT_TO_BLOCK_SCALE_MULTIPLIER = 2 - Math.sqrt(2)
|
|
97
113
|
const angleRad = (rotation.angle * Math.PI) / 180
|
|
98
114
|
const scale = Math.abs(Math.sin(angleRad)) * FIT_TO_BLOCK_SCALE_MULTIPLIER
|
|
@@ -19,6 +19,7 @@ import { GlobalBlockBuffer } from '../../three/globalBlockBuffer'
|
|
|
19
19
|
import { buildVisibleCubeSpans } from '../../three/cubeDrawSpans'
|
|
20
20
|
import { createCubeBlockMaterial, computeSectionOriginRel, setCubeShadingTheme } from '../../three/shaders/cubeBlockShader'
|
|
21
21
|
import * as THREE from 'three'
|
|
22
|
+
import blocksAtlasesJson from 'mc-assets/dist/blocksAtlases.json'
|
|
22
23
|
import { renderWasmOutputToGeometry } from '../bridge/render-from-wasm'
|
|
23
24
|
|
|
24
25
|
const VERSION = '1.16.5'
|
|
@@ -29,8 +30,8 @@ function requireShaderCubeResources() {
|
|
|
29
30
|
if (!resources) throw new Error('shader cube resources unavailable in test')
|
|
30
31
|
return resources
|
|
31
32
|
}
|
|
32
|
-
/** mc-assets blocksAtlases.json → stone */
|
|
33
|
-
const STONE_ATLAS_TILE_INDEX =
|
|
33
|
+
/** mc-assets blocksAtlases.json → stone (looked up, tile positions change whenever the atlas gets new textures) */
|
|
34
|
+
const STONE_ATLAS_TILE_INDEX = blocksAtlasesJson.latest.textures.stone.tileIndex
|
|
34
35
|
|
|
35
36
|
beforeEach(() => {
|
|
36
37
|
resetShaderCubeResources()
|