minecraft-renderer 0.1.54 → 0.1.56
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 +54 -54
- package/dist/mesher.js.map +3 -3
- package/dist/mesherWasm.js +46 -46
- package/dist/minecraft-renderer.js +61 -61
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +972 -972
- package/package.json +1 -1
- package/src/lib/buildWorkerMcDataIndexes.test.ts +48 -0
- package/src/lib/buildWorkerMcDataIndexes.ts +121 -0
- package/src/lib/items.ts +4 -3
- package/src/lib/utils.ts +1 -1
- package/src/lib/workerMessageSanitize.test.ts +14 -0
- package/src/lib/workerMessageSanitize.ts +48 -0
- package/src/lib/workerProxy.restore.test.ts +29 -0
- package/src/lib/workerProxy.ts +110 -36
- package/src/lib/worldrendererCommon.ts +25 -0
- package/src/resourcesManager/resourcesManager.ts +97 -11
- package/src/resourcesManager/resourcesManager.worker.test.ts +61 -0
- package/src/three/appShared.ts +1 -1
- package/src/three/chunkMeshManager.ts +4 -3
- package/src/three/entities.ts +27 -19
- package/src/three/entity/EntityMesh.ts +4 -10
- package/src/three/graphicsBackendBase.ts +25 -15
- package/src/three/graphicsBackendOffThread.ts +27 -3
- package/src/three/hand.ts +3 -3
- package/src/three/itemMesh.ts +20 -7
- package/src/three/menuBackground/assetUrl.ts +15 -0
- package/src/three/menuBackground/classic.ts +11 -5
- package/src/three/menuBackground/futuristic.ts +3 -0
- package/src/three/threeJsMedia.ts +31 -4
- package/src/three/threeJsUtils.ts +11 -0
- package/src/three/threeWorker.ts +12 -11
- package/src/three/worldRendererThree.ts +7 -0
- package/src/worldView/worldView.ts +2 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
//@ts-nocheck
|
|
2
|
-
import { join } from 'path'
|
|
3
2
|
import * as THREE from 'three'
|
|
4
3
|
import { EntityMesh } from '../entity/EntityMesh'
|
|
4
|
+
import { loadImageFromUrl } from '../../lib/utils'
|
|
5
5
|
import type { DocumentRenderer } from '../documentRenderer'
|
|
6
|
-
import {
|
|
6
|
+
import { loadThreeJsTextureFromBitmap } from '../threeJsUtils'
|
|
7
7
|
import type { MenuBackgroundView } from './activeView'
|
|
8
8
|
import { resizeMenuBackgroundCamera } from './activeView'
|
|
9
|
+
import { menuBackgroundAssetUrl } from './assetUrl'
|
|
9
10
|
|
|
10
11
|
const date = new Date()
|
|
11
12
|
const isChristmas = date.getMonth() === 11 && date.getDate() >= 24 && date.getDate() <= 26
|
|
@@ -75,7 +76,9 @@ export class ClassicMenuBackground implements MenuBackgroundView {
|
|
|
75
76
|
|
|
76
77
|
for (const file of panoramaFiles) {
|
|
77
78
|
const load = async () => {
|
|
78
|
-
const
|
|
79
|
+
const url = menuBackgroundAssetUrl('background', isChristmas ? 'christmas' : '', file)
|
|
80
|
+
const bitmap = await loadImageFromUrl(url)
|
|
81
|
+
const texture = loadThreeJsTextureFromBitmap(bitmap)
|
|
79
82
|
|
|
80
83
|
texture.matrixAutoUpdate = false
|
|
81
84
|
texture.matrix.set(-1, 0, 1, 0, 1, 0, 0, 0, 1)
|
|
@@ -96,7 +99,9 @@ export class ClassicMenuBackground implements MenuBackgroundView {
|
|
|
96
99
|
panorMaterials.push(material)
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
void load()
|
|
102
|
+
void load().catch(err => {
|
|
103
|
+
console.warn('[ClassicMenuBackground] Failed to load panorama face:', file, err)
|
|
104
|
+
})
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
const panoramaBox = new THREE.Mesh(panorGeo, panorMaterials)
|
|
@@ -137,7 +142,8 @@ export class ClassicMenuBackground implements MenuBackgroundView {
|
|
|
137
142
|
|
|
138
143
|
/** Debug helper: flat cubemap face in front of the camera. */
|
|
139
144
|
async debugImageInFrontOfCamera() {
|
|
140
|
-
const
|
|
145
|
+
const bitmap = await loadImageFromUrl(menuBackgroundAssetUrl('background', 'panorama_0.webp'))
|
|
146
|
+
const image = loadThreeJsTextureFromBitmap(bitmap)
|
|
141
147
|
const mesh = new THREE.Mesh(
|
|
142
148
|
new THREE.PlaneGeometry(1000, 1000),
|
|
143
149
|
new THREE.MeshBasicMaterial({ map: image })
|
|
@@ -632,6 +632,9 @@ export class FuturisticMenuBackground implements MenuBackgroundView {
|
|
|
632
632
|
const resourcesManager = this.resourcesManager ?? new ResourcesManager()
|
|
633
633
|
const needsAssetUpdate = !resourcesManager.currentResources?.blocksAtlasImage
|
|
634
634
|
if (needsAssetUpdate) {
|
|
635
|
+
if (typeof document === 'undefined') {
|
|
636
|
+
throw new Error('Menu atlas missing in worker; pass resourcesManager from main thread')
|
|
637
|
+
}
|
|
635
638
|
resourcesManager.currentConfig = {
|
|
636
639
|
...resourcesManager.currentConfig,
|
|
637
640
|
version: MENU_BACKGROUND_MC_VERSION,
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import * as THREE from 'three'
|
|
3
3
|
import { WorldRendererThree } from './worldRendererThree'
|
|
4
4
|
import { ThreeJsSound } from './threeJsSound'
|
|
5
|
+
import { isWebWorker } from './documentRenderer'
|
|
6
|
+
import { loadThreeJsTextureFromUrlSync } from './threeJsUtils'
|
|
5
7
|
|
|
6
8
|
type ControlModeConfig = {
|
|
7
9
|
mouseButton: 'both' | 'left' | 'right'
|
|
@@ -187,7 +189,11 @@ export class ThreeJsMedia {
|
|
|
187
189
|
|
|
188
190
|
let video: HTMLVideoElement | undefined
|
|
189
191
|
let positionalAudio: THREE.PositionalAudio | undefined
|
|
190
|
-
|
|
192
|
+
const workerVideoUnsupported = isWebWorker && !isImage
|
|
193
|
+
if (workerVideoUnsupported) {
|
|
194
|
+
console.warn(`[addMedia] Video "${id}" skipped in off-thread renderer (no HTMLVideoElement)`)
|
|
195
|
+
}
|
|
196
|
+
if (!isImage && !workerVideoUnsupported) {
|
|
191
197
|
video = document.createElement('video')
|
|
192
198
|
video.src = props.src.endsWith('.gif') ? props.src.replace('.gif', '.mp4') : props.src
|
|
193
199
|
video.loop = props.loop ?? true
|
|
@@ -268,14 +274,35 @@ export class ThreeJsMedia {
|
|
|
268
274
|
alphaTest: 0.1
|
|
269
275
|
})
|
|
270
276
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
277
|
+
let texture: THREE.Texture
|
|
278
|
+
if (video) {
|
|
279
|
+
texture = new THREE.VideoTexture(video)
|
|
280
|
+
} else if (workerVideoUnsupported) {
|
|
281
|
+
texture = this.createErrorTexture(
|
|
282
|
+
props.size.width,
|
|
283
|
+
props.size.height,
|
|
284
|
+
props.background,
|
|
285
|
+
'Video unavailable (multi-thread)',
|
|
286
|
+
)
|
|
287
|
+
} else if (isWebWorker) {
|
|
288
|
+
const loaded = loadThreeJsTextureFromUrlSync(props.src)
|
|
289
|
+
texture = loaded.texture
|
|
290
|
+
texture.minFilter = THREE.NearestFilter
|
|
291
|
+
texture.magFilter = THREE.NearestFilter
|
|
292
|
+
void loaded.promise.then(() => {
|
|
293
|
+
if (this.customMedia.get(id)?.texture === texture) {
|
|
294
|
+
material.map = texture
|
|
295
|
+
material.needsUpdate = true
|
|
296
|
+
}
|
|
297
|
+
}).catch(() => handleError())
|
|
298
|
+
} else {
|
|
299
|
+
texture = new THREE.TextureLoader().load(props.src, () => {
|
|
274
300
|
if (this.customMedia.get(id)?.texture === texture) {
|
|
275
301
|
material.map = texture
|
|
276
302
|
material.needsUpdate = true
|
|
277
303
|
}
|
|
278
304
|
}, undefined, () => handleError()) // todo cache
|
|
305
|
+
}
|
|
279
306
|
texture.minFilter = THREE.NearestFilter
|
|
280
307
|
texture.magFilter = THREE.NearestFilter
|
|
281
308
|
// texture.format = THREE.RGBAFormat
|
|
@@ -69,6 +69,17 @@ export const loadThreeJsTextureFromBitmap = (image: ImageBitmap) => {
|
|
|
69
69
|
return texture
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/** Worker-safe sync handle; image loads via fetch + OffscreenCanvas (not TextureLoader). */
|
|
73
|
+
export function loadNearestFilterTexture (imageUrl: string): THREE.Texture {
|
|
74
|
+
const { texture, promise } = loadThreeJsTextureFromUrlSync(imageUrl)
|
|
75
|
+
texture.magFilter = THREE.NearestFilter
|
|
76
|
+
texture.minFilter = THREE.NearestFilter
|
|
77
|
+
void promise.catch((err) => {
|
|
78
|
+
console.error('[texture] failed to load', imageUrl, err)
|
|
79
|
+
})
|
|
80
|
+
return texture
|
|
81
|
+
}
|
|
82
|
+
|
|
72
83
|
export async function loadTexture (texture: string, cb: (texture: THREE.Texture) => void, onLoad?: () => void): Promise<void> {
|
|
73
84
|
const cached = textureCache[texture]
|
|
74
85
|
if (!cached) {
|
package/src/three/threeWorker.ts
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
//@ts-nocheck
|
|
2
|
-
|
|
3
|
-
// This worker handles three.js rendering in an offscreen canvas
|
|
2
|
+
import { augmentWorkerMcData } from '../lib/buildWorkerMcDataIndexes'
|
|
4
3
|
|
|
5
4
|
globalThis.structuredClone ??= (value) => JSON.parse(JSON.stringify(value))
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const applyWorkerMcData = (raw: Record<string, unknown>) => {
|
|
7
|
+
augmentWorkerMcData(raw)
|
|
8
|
+
const globalVar: any = globalThis
|
|
9
|
+
globalVar.mcData = raw
|
|
10
|
+
globalVar.loadedData = raw
|
|
11
|
+
// eslint-disable-next-line no-restricted-globals
|
|
12
|
+
self.postMessage({ type: 'mcDataApplied' })
|
|
13
|
+
}
|
|
14
|
+
|
|
9
15
|
// eslint-disable-next-line no-restricted-globals
|
|
10
16
|
self.addEventListener('message', (event: MessageEvent) => {
|
|
11
17
|
const data = event.data
|
|
12
|
-
const globalVar: any = globalThis
|
|
13
|
-
|
|
14
18
|
if (data.type === 'mcData') {
|
|
15
|
-
|
|
16
|
-
globalVar.loadedData = data.mcData
|
|
19
|
+
applyWorkerMcData(data.mcData)
|
|
17
20
|
console.log('data loaded')
|
|
18
21
|
return
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
// Handle array of messages (batch mode)
|
|
22
24
|
if (Array.isArray(data)) {
|
|
23
25
|
// eslint-disable-next-line unicorn/no-array-for-each
|
|
24
26
|
data.forEach((msg) => {
|
|
25
27
|
if (msg.type === 'mcData') {
|
|
26
|
-
|
|
27
|
-
globalVar.loadedData = msg.mcData
|
|
28
|
+
applyWorkerMcData(msg.mcData)
|
|
28
29
|
}
|
|
29
30
|
})
|
|
30
31
|
}
|
|
@@ -1510,6 +1510,13 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1510
1510
|
this.chunkMeshManager.onChunkRemovedFromGate(`${x},${z}`)
|
|
1511
1511
|
}
|
|
1512
1512
|
|
|
1513
|
+
updateViewerPosition(pos: Vec3) {
|
|
1514
|
+
super.updateViewerPosition(pos)
|
|
1515
|
+
if (this.chunkMeshManager.pendingNearReveal.size > 0) {
|
|
1516
|
+
this.chunkMeshManager.tryRevealPending()
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1513
1520
|
protected onViewerChunkPositionChanged(): void {
|
|
1514
1521
|
this.chunkMeshManager.tryRevealPending()
|
|
1515
1522
|
}
|
|
@@ -11,6 +11,7 @@ import { Vec3 } from 'vec3'
|
|
|
11
11
|
import TypedEmitter from 'typed-emitter'
|
|
12
12
|
import type { WorldViewEvents, ChunkPosKey, WorldSizeParams } from './types'
|
|
13
13
|
import { generateSpiralMatrix } from '../lib/spiral'
|
|
14
|
+
import { sanitizeWorkerEventArgs } from '../lib/workerMessageSanitize'
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Helper to calculate chunk position from absolute position.
|
|
@@ -131,7 +132,7 @@ export class WorldView extends (EventEmitter as new () => TypedEmitter<WorldView
|
|
|
131
132
|
class: WorldViewWorker.restorerName,
|
|
132
133
|
type: 'event',
|
|
133
134
|
eventName,
|
|
134
|
-
args,
|
|
135
|
+
args: sanitizeWorkerEventArgs(args),
|
|
135
136
|
})
|
|
136
137
|
}) as any
|
|
137
138
|
}
|