minecraft-renderer 0.1.55 → 0.1.57

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.
@@ -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
- if (!isImage) {
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
- const texture = video
272
- ? new THREE.VideoTexture(video)
273
- : new THREE.TextureLoader().load(props.src, () => {
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) {
@@ -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
  }