minecraft-renderer 0.1.40 → 0.1.42
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 +8 -8
- package/dist/mesher.js.map +4 -4
- package/dist/mesherWasm.js +93 -93
- package/dist/minecraft-renderer.js +57 -57
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +19 -19
- package/package.json +3 -4
- package/src/bundler/bundlePrepare.ts +56 -0
- package/src/graphicsBackend/appViewer.ts +10 -0
- package/src/graphicsBackend/config.ts +1 -1
- package/src/graphicsBackend/preloadWorkers.ts +187 -0
- package/src/lib/worldrendererCommon.ts +1 -1
- package/src/{mesher → mesher-legacy}/mesher.ts +14 -4
- package/src/{mesher → mesher-legacy}/test/mesherTester.ts +2 -2
- package/src/{mesher → mesher-legacy}/test/run/test-js.ts +1 -1
- package/src/{mesher → mesher-legacy}/test/test-perf.ts +1 -1
- package/src/{mesher → mesher-legacy}/test/tests.test.ts +1 -1
- package/src/{mesher → mesher-shared}/shared.ts +2 -0
- package/src/playground/allEntitiesDebug.ts +1 -1
- package/src/three/chunkMeshManager.ts +1 -1
- package/src/three/entities.ts +19 -6
- package/src/three/entity/EntityMesh.ts +123 -140
- package/src/three/graphicsBackendBase.ts +13 -0
- package/src/three/holdingBlock.ts +1 -1
- package/src/three/holdingBlockLegacy.ts +1 -1
- package/src/three/modules/sciFiWorldReveal.ts +1 -1
- package/src/three/worldRendererThree.ts +2 -2
- package/src/wasm-mesher/README.md +90 -0
- package/src/{wasm-lib → wasm-mesher/bridge}/convertChunk.ts +2 -2
- package/src/{wasm-lib → wasm-mesher/bridge}/render-from-wasm.ts +4 -4
- package/src/wasm-mesher/runtime-build/wasm_mesher.d.ts +251 -0
- package/src/wasm-mesher/runtime-build/wasm_mesher.js +1061 -0
- package/src/wasm-mesher/runtime-build/wasm_mesher_bg.wasm +0 -0
- package/src/wasm-mesher/runtime-build/wasm_mesher_bg.wasm.d.ts +26 -0
- package/src/{mesher/test → wasm-mesher/tests}/heightmapParity.test.ts +4 -4
- package/src/{mesher/test → wasm-mesher/tests}/mesherWasmConversionCache.test.ts +2 -2
- package/src/{mesher/test → wasm-mesher/tests}/splitColumnWasmOutput.test.ts +1 -1
- package/src/wasm-mesher/worker/mesherWasm.ts +1425 -0
- package/src/{mesher → wasm-mesher/worker}/mesherWasmConversionCache.ts +1 -1
- package/src/worldView/types.ts +90 -0
- package/src/mesher/mesherWasm.ts +0 -696
- package/wasm/wasm_mesher.d.ts +0 -46
- package/wasm/wasm_mesher.js +0 -443
- package/wasm/wasm_mesher_bg.wasm +0 -0
- package/wasm/wasm_mesher_bg.wasm.d.ts +0 -9
- /package/src/{mesher → mesher-legacy}/test/a.ts +0 -0
- /package/src/{mesher → mesher-legacy}/test/playground.ts +0 -0
- /package/src/{mesher → mesher-legacy}/test/run/chunk.ts +0 -0
- /package/src/{mesher → mesher-legacy}/test/snapshotUtils.ts +0 -0
- /package/src/{mesher → mesher-shared}/blockEntityMetadata.ts +0 -0
- /package/src/{mesher → mesher-shared}/computeHeightmap.ts +0 -0
- /package/src/{mesher → mesher-shared}/models.ts +0 -0
- /package/src/{mesher → mesher-shared}/modelsGeometryCommon.ts +0 -0
- /package/src/{mesher → mesher-shared}/standaloneRenderer.ts +0 -0
- /package/src/{mesher → mesher-shared}/world.ts +0 -0
- /package/src/{mesher → mesher-shared}/worldConstants.ts +0 -0
- /package/src/{mesher → wasm-mesher/worker}/mesherWasmRequestTracker.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "minecraft-renderer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.42",
|
|
4
4
|
"description": "The most Modular Minecraft world renderer with Three.js WebGL backend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
11
|
"src",
|
|
12
|
-
"wasm",
|
|
13
12
|
"logo.webp"
|
|
14
13
|
],
|
|
15
14
|
"browserslist": {
|
|
@@ -121,8 +120,8 @@
|
|
|
121
120
|
"watch:lib": "node scripts/buildLib.mjs -w",
|
|
122
121
|
"build:mesher": "node scripts/buildMesherWorker.mjs",
|
|
123
122
|
"build:wasm": "cd wasm-mesher && ./build.sh web",
|
|
124
|
-
"test:wasm": "cd wasm-mesher && wasm-pack build --target nodejs --out-dir pkg --dev && node build.mjs && node test-chunk.cjs && node test-section-boundary.cjs",
|
|
125
|
-
"test:wasm:boundary": "cd wasm-mesher && wasm-pack build --target nodejs --out-dir pkg --dev && node build.mjs && node test-section-boundary.cjs",
|
|
123
|
+
"test:wasm": "cd wasm-mesher && wasm-pack build --target nodejs --out-dir pkg --dev && node build.mjs && node tests/test-chunk.cjs && node tests/test-section-boundary.cjs",
|
|
124
|
+
"test:wasm:boundary": "cd wasm-mesher && wasm-pack build --target nodejs --out-dir pkg --dev && node build.mjs && node tests/test-section-boundary.cjs",
|
|
126
125
|
"watch:mesher": "pnpm build:mesher -w",
|
|
127
126
|
"build:threeworker": "node scripts/buildThreeWorker.mjs",
|
|
128
127
|
"watch:threeworker": "pnpm build:threeworker -w",
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import { cp, mkdir, stat } from 'node:fs/promises'
|
|
3
|
+
import { createRequire } from 'node:module'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
|
|
6
|
+
/** Worker-related basenames inside `minecraft-renderer`/`dist`; skipped if missing. */
|
|
7
|
+
export const MESHER_DIST_FILES = [
|
|
8
|
+
'mesher.js',
|
|
9
|
+
'mesher.js.map',
|
|
10
|
+
'mesherWasm.js',
|
|
11
|
+
'mesherWasm.js.map',
|
|
12
|
+
] as const
|
|
13
|
+
|
|
14
|
+
export type BundlePrepareMesherOptions = {
|
|
15
|
+
cwd?: string
|
|
16
|
+
packageName?: string
|
|
17
|
+
outDir?: string
|
|
18
|
+
mesherDistDir?: string
|
|
19
|
+
files?: readonly string[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function resolveSrcDist (opts: BundlePrepareMesherOptions | undefined, cwd: string): string {
|
|
23
|
+
if (opts?.mesherDistDir) return path.resolve(cwd, opts.mesherDistDir)
|
|
24
|
+
const pkg = opts?.packageName ?? 'minecraft-renderer'
|
|
25
|
+
const req = createRequire(path.join(cwd, 'package.json'))
|
|
26
|
+
return path.join(path.dirname(req.resolve(`${pkg}/package.json`)), 'dist')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function bundlePrepareMesherWorkers (opts?: BundlePrepareMesherOptions): Promise<string[]> {
|
|
30
|
+
const cwd = opts?.cwd ?? process.cwd()
|
|
31
|
+
const outDir = path.resolve(cwd, opts?.outDir ?? 'dist')
|
|
32
|
+
const srcDist = resolveSrcDist(opts, cwd)
|
|
33
|
+
const names = opts?.files ?? MESHER_DIST_FILES
|
|
34
|
+
|
|
35
|
+
await stat(srcDist).catch(() => {
|
|
36
|
+
throw new Error(`[bundlePrepareMesherWorkers] missing dist: ${srcDist}`)
|
|
37
|
+
})
|
|
38
|
+
await mkdir(outDir, { recursive: true })
|
|
39
|
+
|
|
40
|
+
const copied: string[] = []
|
|
41
|
+
for (const name of names) {
|
|
42
|
+
const from = path.join(srcDist, name)
|
|
43
|
+
let st
|
|
44
|
+
try {
|
|
45
|
+
st = await stat(from)
|
|
46
|
+
} catch {
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
if (!st.isFile()) continue
|
|
50
|
+
const to = path.join(outDir, name)
|
|
51
|
+
await mkdir(path.dirname(to), { recursive: true })
|
|
52
|
+
await cp(from, to)
|
|
53
|
+
copied.push(path.relative(process.cwd(), to) || to)
|
|
54
|
+
}
|
|
55
|
+
return copied
|
|
56
|
+
}
|
|
@@ -26,6 +26,7 @@ import { getInitialPlayerState } from './playerState'
|
|
|
26
26
|
import { defaultWorldRendererConfig, defaultGraphicsBackendConfig, getDefaultRendererState, WorldRendererConfig } from './config'
|
|
27
27
|
import { PlayerStateReactive } from '../playerState/playerState'
|
|
28
28
|
import { ResourcesManager, ResourcesManagerTransferred } from '../resourcesManager'
|
|
29
|
+
import { preloadMesherWorkerScript } from './preloadWorkers'
|
|
29
30
|
|
|
30
31
|
export interface AppViewerOptions {
|
|
31
32
|
config?: Partial<GraphicsBackendConfig>
|
|
@@ -101,6 +102,15 @@ export class AppViewer {
|
|
|
101
102
|
this.resolveWorldReady = resolve
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Preload mesher worker script (HTTP validate + ephemeral Worker + `mc-web-ping` / `mc-web-pong`).
|
|
107
|
+
* Chooses `/mesherWasm.js` vs `/mesher.js` from `inWorldRenderingConfig.wasmMesher`.
|
|
108
|
+
*/
|
|
109
|
+
preloadWorkers (): Promise<void> {
|
|
110
|
+
const script = this.inWorldRenderingConfig.wasmMesher ? 'mesherWasm.js' : 'mesher.js'
|
|
111
|
+
return preloadMesherWorkerScript({ script })
|
|
112
|
+
}
|
|
113
|
+
|
|
104
114
|
/**
|
|
105
115
|
* Load a graphics backend.
|
|
106
116
|
*/
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
/** Structured reason so logs / support can tell fetch vs worker vs ping failures apart. */
|
|
3
|
+
export type MesherWorkerPreloadFailure =
|
|
4
|
+
| { phase: 'fetch'; code: 'timeout' | 'network' | 'bad-status'; status?: number; detail?: string }
|
|
5
|
+
| { phase: 'fetch'; code: 'invalid-body'; hint: 'empty' | 'html' }
|
|
6
|
+
| { phase: 'worker'; code: 'construct-failed'; message: string }
|
|
7
|
+
| { phase: 'worker'; code: 'script-error'; message: string }
|
|
8
|
+
| { phase: 'ping'; code: 'timeout' | 'messageerror' | 'post-failed'; detail?: string }
|
|
9
|
+
|
|
10
|
+
export class MesherWorkerPreloadError extends Error {
|
|
11
|
+
readonly failure: MesherWorkerPreloadFailure
|
|
12
|
+
|
|
13
|
+
constructor(message: string, failure: MesherWorkerPreloadFailure) {
|
|
14
|
+
super(message)
|
|
15
|
+
this.name = 'MesherWorkerPreloadError'
|
|
16
|
+
this.failure = failure
|
|
17
|
+
console.error('[mesher preload]', failure, message)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function isMcWebPong(data: unknown): boolean {
|
|
22
|
+
if (!data || typeof data !== 'object') return false
|
|
23
|
+
if ((data as { type?: string }).type === 'mc-web-pong') return true
|
|
24
|
+
if (Array.isArray(data)) {
|
|
25
|
+
return data.some(d => d && typeof d === 'object' && (d as { type?: string }).type === 'mc-web-pong')
|
|
26
|
+
}
|
|
27
|
+
return false
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const DEFAULT_FETCH_MS = 45_000
|
|
31
|
+
const DEFAULT_PING_MS = 10_000
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Validates a mesher worker script over HTTP (not HTML/error page), instantiates a Worker, and waits for `mc-web-pong`.
|
|
35
|
+
* Use `mesher.js` for the legacy mesher bundle and `mesherWasm.js` for the WASM mesher bundle.
|
|
36
|
+
* Single-file builds skip (blob worker).
|
|
37
|
+
*/
|
|
38
|
+
export async function preloadMesherWorkerScript(opts?: {
|
|
39
|
+
fetchTimeoutMs?: number
|
|
40
|
+
pingTimeoutMs?: number
|
|
41
|
+
/** Worker script basename relative to `document.baseURI`. Defaults to `mesher.js`. */
|
|
42
|
+
script?: string
|
|
43
|
+
}): Promise<void> {
|
|
44
|
+
if (process.env.SINGLE_FILE_BUILD) return
|
|
45
|
+
|
|
46
|
+
const fetchTimeoutMs = opts?.fetchTimeoutMs ?? DEFAULT_FETCH_MS
|
|
47
|
+
const pingTimeoutMs = opts?.pingTimeoutMs ?? DEFAULT_PING_MS
|
|
48
|
+
const scriptBasename = opts?.script ?? 'mesher.js'
|
|
49
|
+
const scriptUrl = new URL(scriptBasename, document.baseURI).href
|
|
50
|
+
|
|
51
|
+
let res: Response
|
|
52
|
+
try {
|
|
53
|
+
const ctrl = new AbortController()
|
|
54
|
+
const t = window.setTimeout(() => ctrl.abort(), fetchTimeoutMs)
|
|
55
|
+
try {
|
|
56
|
+
res = await fetch(scriptUrl, {
|
|
57
|
+
credentials: 'same-origin',
|
|
58
|
+
cache: 'force-cache',
|
|
59
|
+
signal: ctrl.signal,
|
|
60
|
+
})
|
|
61
|
+
} finally {
|
|
62
|
+
clearTimeout(t)
|
|
63
|
+
}
|
|
64
|
+
} catch (e: unknown) {
|
|
65
|
+
const err = e as { name?: string; message?: string }
|
|
66
|
+
if (err?.name === 'AbortError') {
|
|
67
|
+
throw new MesherWorkerPreloadError(
|
|
68
|
+
`Mesher script fetch timed out after ${fetchTimeoutMs}ms (${scriptUrl}).`,
|
|
69
|
+
{ phase: 'fetch', code: 'timeout' }
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
throw new MesherWorkerPreloadError(
|
|
73
|
+
`Mesher script fetch failed (network): ${err?.message ?? e}. URL: ${scriptUrl}`,
|
|
74
|
+
{ phase: 'fetch', code: 'network', detail: String(err?.message ?? e) }
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!res.ok) {
|
|
79
|
+
throw new MesherWorkerPreloadError(
|
|
80
|
+
`Mesher script HTTP ${res.status} ${res.statusText}: ${scriptUrl}`,
|
|
81
|
+
{ phase: 'fetch', code: 'bad-status', status: res.status }
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const contentType = res.headers.get('content-type') ?? ''
|
|
86
|
+
const buf = await res.arrayBuffer()
|
|
87
|
+
if (buf.byteLength === 0) {
|
|
88
|
+
throw new MesherWorkerPreloadError(
|
|
89
|
+
`Mesher script response was empty: ${scriptUrl}`,
|
|
90
|
+
{ phase: 'fetch', code: 'invalid-body', hint: 'empty' }
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const headSize = Math.min(1024, buf.byteLength)
|
|
95
|
+
const head = new TextDecoder().decode(buf.slice(0, headSize)).trimStart()
|
|
96
|
+
if (head.startsWith('<!DOCTYPE') || head.startsWith('<html') || head.startsWith('<HTML')) {
|
|
97
|
+
throw new MesherWorkerPreloadError(
|
|
98
|
+
`Mesher URL returned HTML (wrong path, redirect, or SPA fallback), not JavaScript: ${scriptUrl}`,
|
|
99
|
+
{ phase: 'fetch', code: 'invalid-body', hint: 'html' }
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (contentType.length > 0 && !/javascript|ecmascript/i.test(contentType)) {
|
|
104
|
+
console.warn('[mesher preload] Unexpected Content-Type for mesher worker script:', contentType, scriptUrl)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let worker: Worker | undefined
|
|
108
|
+
try {
|
|
109
|
+
worker = new Worker(scriptUrl)
|
|
110
|
+
} catch (e: unknown) {
|
|
111
|
+
const msg = e instanceof Error ? e.message : String(e)
|
|
112
|
+
throw new MesherWorkerPreloadError(
|
|
113
|
+
`Could not construct Worker for mesher (${scriptUrl}): ${msg}`,
|
|
114
|
+
{ phase: 'worker', code: 'construct-failed', message: msg }
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
await new Promise<void>((resolve, reject) => {
|
|
119
|
+
let settled = false
|
|
120
|
+
const pingTimer = window.setTimeout(() => {
|
|
121
|
+
if (settled) return
|
|
122
|
+
settled = true
|
|
123
|
+
cleanup()
|
|
124
|
+
reject(new MesherWorkerPreloadError(
|
|
125
|
+
`Mesher worker did not reply with mc-web-pong within ${pingTimeoutMs}ms (wrong script, SW stale cache, worker blocked, or COEP/CORP). URL: ${scriptUrl}`,
|
|
126
|
+
{ phase: 'ping', code: 'timeout' }
|
|
127
|
+
))
|
|
128
|
+
}, pingTimeoutMs)
|
|
129
|
+
|
|
130
|
+
const cleanup = () => {
|
|
131
|
+
clearTimeout(pingTimer)
|
|
132
|
+
const w = worker
|
|
133
|
+
worker = undefined
|
|
134
|
+
if (!w) return
|
|
135
|
+
w.removeEventListener('message', onMessage)
|
|
136
|
+
w.removeEventListener('error', onError)
|
|
137
|
+
w.removeEventListener('messageerror', onMessageError)
|
|
138
|
+
w.terminate()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const done = () => {
|
|
142
|
+
if (settled) return
|
|
143
|
+
settled = true
|
|
144
|
+
cleanup()
|
|
145
|
+
resolve()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const fail = (err: Error) => {
|
|
149
|
+
if (settled) return
|
|
150
|
+
settled = true
|
|
151
|
+
cleanup()
|
|
152
|
+
reject(err)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function onMessage(ev: MessageEvent) {
|
|
156
|
+
if (isMcWebPong(ev.data)) done()
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function onError(ev: ErrorEvent) {
|
|
160
|
+
fail(new MesherWorkerPreloadError(
|
|
161
|
+
`Mesher worker script failed to load or threw during startup: ${ev.message || 'unknown'} @ ${scriptUrl}`,
|
|
162
|
+
{ phase: 'worker', code: 'script-error', message: ev.message }
|
|
163
|
+
))
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function onMessageError() {
|
|
167
|
+
fail(new MesherWorkerPreloadError(
|
|
168
|
+
`Mesher worker message channel error (structured clone / deserialization). URL: ${scriptUrl}`,
|
|
169
|
+
{ phase: 'ping', code: 'messageerror' }
|
|
170
|
+
))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
worker!.addEventListener('message', onMessage)
|
|
174
|
+
worker!.addEventListener('error', onError)
|
|
175
|
+
worker!.addEventListener('messageerror', onMessageError)
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
worker!.postMessage({ type: 'mc-web-ping', t: performance.now(), workerIndex: 0 })
|
|
179
|
+
} catch (e: unknown) {
|
|
180
|
+
const detail = e instanceof Error ? e.message : String(e)
|
|
181
|
+
fail(new MesherWorkerPreloadError(
|
|
182
|
+
`Failed to post mc-web-ping to mesher worker: ${detail}`,
|
|
183
|
+
{ phase: 'ping', code: 'post-failed', detail }
|
|
184
|
+
))
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
}
|
|
@@ -9,7 +9,7 @@ import { proxy, subscribe } from 'valtio'
|
|
|
9
9
|
import type { ResourcesManagerTransferred } from '../resourcesManager/resourcesManager'
|
|
10
10
|
import { dynamicMcDataFiles } from './buildSharedConfig.mjs'
|
|
11
11
|
import { DisplayWorldOptions, GraphicsInitOptions, RendererReactiveState, SoundSystem } from '../graphicsBackend/types'
|
|
12
|
-
import { HighestBlockInfo, CustomBlockModels, BlockStateModelInfo, getBlockAssetsCacheKey, MesherConfig, MesherMainEvent, SECTION_HEIGHT } from '../mesher/shared'
|
|
12
|
+
import { HighestBlockInfo, CustomBlockModels, BlockStateModelInfo, getBlockAssetsCacheKey, MesherConfig, MesherMainEvent, SECTION_HEIGHT } from '../mesher-shared/shared'
|
|
13
13
|
import { chunkPos } from './simpleUtils'
|
|
14
14
|
import { addNewStat, removeAllStats, updatePanesVisibility, updateStatText } from './ui/newStats'
|
|
15
15
|
import { getPlayerStateUtils } from '../graphicsBackend/playerState'
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
//@ts-nocheck
|
|
2
2
|
import { Vec3 } from 'vec3'
|
|
3
|
-
import { World } from '
|
|
4
|
-
import { getSectionGeometry, setBlockStatesData as setMesherData } from '
|
|
5
|
-
import { BlockStateModelInfo } from '
|
|
6
|
-
import { handleGetHeightmap, EMPTY_COLUMN_HEIGHTMAP_SENTINEL } from '
|
|
3
|
+
import { World } from '../mesher-shared/world'
|
|
4
|
+
import { getSectionGeometry, setBlockStatesData as setMesherData } from '../mesher-shared/models'
|
|
5
|
+
import { BlockStateModelInfo } from '../mesher-shared/shared'
|
|
6
|
+
import { handleGetHeightmap, EMPTY_COLUMN_HEIGHTMAP_SENTINEL } from '../mesher-shared/computeHeightmap'
|
|
7
7
|
|
|
8
8
|
globalThis.structuredClone ??= (value) => JSON.parse(JSON.stringify(value))
|
|
9
9
|
|
|
@@ -169,6 +169,16 @@ const handleMessage = data => {
|
|
|
169
169
|
|
|
170
170
|
break
|
|
171
171
|
}
|
|
172
|
+
case 'mc-web-ping': {
|
|
173
|
+
const replyWorkerIndex = typeof data.workerIndex === 'number' ? data.workerIndex : workerIndex
|
|
174
|
+
global.postMessage({
|
|
175
|
+
type: 'mc-web-pong',
|
|
176
|
+
workerIndex: replyWorkerIndex,
|
|
177
|
+
t: data.t,
|
|
178
|
+
recvAt: typeof performance !== 'undefined' ? performance.now() : undefined,
|
|
179
|
+
})
|
|
180
|
+
break
|
|
181
|
+
}
|
|
172
182
|
// No default
|
|
173
183
|
}
|
|
174
184
|
}
|
|
@@ -3,8 +3,8 @@ import ChunkLoader, { PCChunk } from 'prismarine-chunk'
|
|
|
3
3
|
import { Vec3 } from 'vec3'
|
|
4
4
|
import MinecraftData from 'minecraft-data'
|
|
5
5
|
import blocksAtlasesJson from 'mc-assets/dist/blocksAtlases.json'
|
|
6
|
-
import { World as MesherWorld } from '
|
|
7
|
-
import { setBlockStatesData, getSectionGeometry } from '
|
|
6
|
+
import { World as MesherWorld } from '../../mesher-shared/world'
|
|
7
|
+
import { setBlockStatesData, getSectionGeometry } from '../../mesher-shared/models'
|
|
8
8
|
|
|
9
9
|
interface Options {
|
|
10
10
|
chunkOverride?: PCChunk
|
|
@@ -3,7 +3,7 @@ import ChunkLoader from 'prismarine-chunk'
|
|
|
3
3
|
import { setup } from '../mesherTester'
|
|
4
4
|
import { compareOrWriteSnapshot } from '../snapshotUtils'
|
|
5
5
|
import { getChunk, VERSION } from './chunk'
|
|
6
|
-
import { mesherGeometryToExportFormat } from '../../../wasm-
|
|
6
|
+
import { mesherGeometryToExportFormat } from '../../../wasm-mesher/bridge/render-from-wasm'
|
|
7
7
|
import fs from 'fs'
|
|
8
8
|
import { join } from 'path'
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ import PrismarineWorld from 'prismarine-world'
|
|
|
3
3
|
import PrismarineChunk from 'prismarine-chunk'
|
|
4
4
|
import { Vec3 } from 'vec3'
|
|
5
5
|
import MinecraftData from 'minecraft-data'
|
|
6
|
-
import { defaultMesherConfig } from '
|
|
6
|
+
import { defaultMesherConfig } from '../../mesher-shared/shared'
|
|
7
7
|
import { setup } from './mesherTester.js'
|
|
8
8
|
import { generateSpiralMatrix } from '../../lib/spiral'
|
|
9
9
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//@ts-nocheck
|
|
2
2
|
import { test, expect } from 'vitest'
|
|
3
3
|
import { versions } from 'minecraft-data'
|
|
4
|
-
import { INVISIBLE_BLOCKS } from '
|
|
4
|
+
import { INVISIBLE_BLOCKS } from '../../mesher-shared/worldConstants'
|
|
5
5
|
import { setup } from './mesherTester'
|
|
6
6
|
|
|
7
7
|
const lastVersion = versions.pc.map(x => x.minecraftVersion).filter(version => !version.includes('w'))[0]
|
|
@@ -87,6 +87,8 @@ export interface MesherMainEvents {
|
|
|
87
87
|
};
|
|
88
88
|
blockStateModelInfo: { type: 'blockStateModelInfo'; info: Record<string, BlockStateModelInfo> };
|
|
89
89
|
heightmap: { type: 'heightmap'; key: string; heightmap: Int16Array };
|
|
90
|
+
/** Reply to `{ type: 'mc-web-ping', t?, workerIndex? }` from the main thread (not batched in worker). */
|
|
91
|
+
mcWebPong: { type: 'mc-web-pong'; workerIndex: number; t?: number; recvAt?: number };
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
export type MesherMainEvent = MesherMainEvents[keyof MesherMainEvents]
|
|
@@ -34,7 +34,7 @@ export const displayEntitiesDebugList = (mcData: IndexedData) => {
|
|
|
34
34
|
const results: Array<{
|
|
35
35
|
entity: string;
|
|
36
36
|
supported: boolean;
|
|
37
|
-
type?: 'obj' | 'bedrock' | 'special';
|
|
37
|
+
type?: 'obj' | 'bedrock' | 'gltf' | 'special';
|
|
38
38
|
mappedFrom?: string;
|
|
39
39
|
textureMap?: boolean;
|
|
40
40
|
errors?: string[];
|
|
@@ -3,7 +3,7 @@ import PrismarineChatLoader from 'prismarine-chat'
|
|
|
3
3
|
import * as THREE from 'three'
|
|
4
4
|
import * as nbt from 'prismarine-nbt'
|
|
5
5
|
import { Vec3 } from 'vec3'
|
|
6
|
-
import { MesherGeometryOutput } from '../mesher/shared'
|
|
6
|
+
import { MesherGeometryOutput } from '../mesher-shared/shared'
|
|
7
7
|
import { chunkPos } from '../lib/simpleUtils'
|
|
8
8
|
import { renderSign } from '../sign-renderer'
|
|
9
9
|
import { getMesh } from './entity/EntityMesh'
|
package/src/three/entities.ts
CHANGED
|
@@ -28,6 +28,12 @@ import { WorldRendererThree } from './worldRendererThree'
|
|
|
28
28
|
import { IndexedData } from 'minecraft-data'
|
|
29
29
|
import { ItemSpecificContextProperties } from '../playerState/types'
|
|
30
30
|
|
|
31
|
+
export type EntityModelOverridePart = {
|
|
32
|
+
modelPath: string | ArrayBuffer
|
|
33
|
+
modelType: Entity.EntityModelType
|
|
34
|
+
metadata?: any
|
|
35
|
+
}
|
|
36
|
+
|
|
31
37
|
// Type for entity metadata - simplified version
|
|
32
38
|
type EntityMetadataVersions = {
|
|
33
39
|
[key: string]: any
|
|
@@ -250,7 +256,7 @@ export class Entities {
|
|
|
250
256
|
currentlyRendering = true
|
|
251
257
|
cachedMapsImages = {} as Record<number, string>
|
|
252
258
|
itemFrameMaps = {} as Record<number, Array<THREE.Mesh<THREE.PlaneGeometry, THREE.MeshLambertMaterial>>>
|
|
253
|
-
pendingModelOverrides = new Map<string, {
|
|
259
|
+
pendingModelOverrides = new Map<string, { parts: EntityModelOverridePart[] }>()
|
|
254
260
|
|
|
255
261
|
private motionCache = new Map<string, { pos: THREE.Vector3, speed: number }>()
|
|
256
262
|
private _wasThirdPerson = false
|
|
@@ -1380,8 +1386,8 @@ export class Entities {
|
|
|
1380
1386
|
beforeEntityAdded(entity: import('prismarine-entity').Entity) {
|
|
1381
1387
|
const override = this.pendingModelOverrides.get(entity.id.toString())
|
|
1382
1388
|
if (override) {
|
|
1383
|
-
const {
|
|
1384
|
-
entity['customModel'] =
|
|
1389
|
+
const { parts } = override
|
|
1390
|
+
entity['customModel'] = parts.length === 1 ? parts[0]! : { parts }
|
|
1385
1391
|
this.pendingModelOverrides.delete(entity.id.toString())
|
|
1386
1392
|
}
|
|
1387
1393
|
}
|
|
@@ -1580,9 +1586,16 @@ export class Entities {
|
|
|
1580
1586
|
return intersects[0]?.object
|
|
1581
1587
|
}
|
|
1582
1588
|
|
|
1583
|
-
updateEntityModel(
|
|
1584
|
-
|
|
1585
|
-
|
|
1589
|
+
updateEntityModel(
|
|
1590
|
+
entityId: string,
|
|
1591
|
+
modelPathOrParts: string | EntityModelOverridePart[],
|
|
1592
|
+
modelType?: Entity.EntityModelType,
|
|
1593
|
+
metadata?: any
|
|
1594
|
+
) {
|
|
1595
|
+
const parts: EntityModelOverridePart[] = Array.isArray(modelPathOrParts)
|
|
1596
|
+
? modelPathOrParts
|
|
1597
|
+
: [{ modelPath: modelPathOrParts, modelType: modelType!, metadata }]
|
|
1598
|
+
this.pendingModelOverrides.set(entityId, { parts })
|
|
1586
1599
|
|
|
1587
1600
|
// Force entity recreation if it exists
|
|
1588
1601
|
const entity = this.entities[entityId]
|