minecraft-renderer 0.1.73 → 0.1.74
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/minecraft-renderer.js +20 -18
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +94 -92
- package/package.json +1 -1
- package/src/graphicsBackend/config.ts +4 -0
- package/src/graphicsBackend/types.ts +1 -0
- package/src/lib/bindAbortableListener.ts +1 -1
- package/src/lib/createPlayerObject.ts +1 -1
- package/src/lib/worldrendererCommon.reconfigure.test.ts +4 -1
- package/src/lib/worldrendererCommon.removeColumn.test.ts +8 -4
- package/src/lib/worldrendererCommon.ts +1 -1
- package/src/three/bannerRenderer.ts +4 -1
- package/src/three/entities.ts +2 -1
- package/src/three/graphicsBackendBase.ts +9 -5
- package/src/three/itemMesh.ts +1 -1
- package/src/three/modules/rain.ts +22 -21
- package/src/three/modules/starfield.ts +17 -5
- package/src/three/worldRendererThree.ts +7 -6
- package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +14 -8
package/package.json
CHANGED
|
@@ -81,6 +81,10 @@ export const defaultWorldRendererConfig = {
|
|
|
81
81
|
isPlayground: false,
|
|
82
82
|
instantCameraUpdate: false,
|
|
83
83
|
isRaining: false,
|
|
84
|
+
// rainColor: 'rgb(64, 87, 148)', // original minecraft blue
|
|
85
|
+
rainColor: 'rgb(118, 148, 226)',
|
|
86
|
+
/** Rain particle opacity 0–1. */
|
|
87
|
+
rainOpacity: 0.5,
|
|
84
88
|
|
|
85
89
|
// Module states: 'enabled' = force on, 'disabled' = force off, 'auto' = use autoEnableCheck
|
|
86
90
|
moduleStates: {} as Record<string, 'enabled' | 'disabled' | 'auto'>
|
|
@@ -101,6 +101,7 @@ export interface GraphicsInitOptions<S = any> {
|
|
|
101
101
|
/** Live app options (e.g. valtio proxy); used for WebGL `gpuPreference` at context creation. */
|
|
102
102
|
getRendererOptions?: () => RendererStorageOptions
|
|
103
103
|
rendererSpecificSettings: S
|
|
104
|
+
hello?: boolean
|
|
104
105
|
callbacks: {
|
|
105
106
|
displayCriticalError: (error: Error) => void
|
|
106
107
|
setRendererSpecificSettings: (key: string, value: any) => void
|
|
@@ -10,7 +10,7 @@ import type { WorldViewWorker } from '../worldView'
|
|
|
10
10
|
export function bindAbortableListener<E extends keyof WorldViewEvents>(
|
|
11
11
|
emitter: Pick<WorldViewWorker, 'on' | 'off'>,
|
|
12
12
|
event: E,
|
|
13
|
-
handler: (...args: WorldViewEvents[E]) => void,
|
|
13
|
+
handler: (...args: Parameters<WorldViewEvents[E]>) => void,
|
|
14
14
|
signal: AbortSignal
|
|
15
15
|
): void {
|
|
16
16
|
emitter.on(event, handler as (...args: any[]) => void)
|
|
@@ -12,7 +12,7 @@ export type PlayerObjectType = PlayerObject & {
|
|
|
12
12
|
|
|
13
13
|
/** Starfield + log-depth world: cutout skin mats need alphaTest and depthWrite (not mesh traverse). */
|
|
14
14
|
export function configurePlayerSkinMaterials (playerObject: PlayerObject): void {
|
|
15
|
-
const skin = playerObject.skin
|
|
15
|
+
const skin = playerObject.skin as any
|
|
16
16
|
const materials = [
|
|
17
17
|
skin.layer1Material,
|
|
18
18
|
skin.layer1MaterialBiased,
|
|
@@ -6,6 +6,7 @@ import { proxy } from 'valtio'
|
|
|
6
6
|
import * as worldRendererModule from './worldrendererCommon'
|
|
7
7
|
import { WorldRendererCommon } from './worldrendererCommon'
|
|
8
8
|
import { defaultWorldRendererConfig } from '../graphicsBackend/config'
|
|
9
|
+
import { defaultPerformanceInstabilityFactors } from '../performanceMonitor'
|
|
9
10
|
import { getInitialPlayerState } from '../playerState/playerState'
|
|
10
11
|
import type { DisplayWorldOptions, GraphicsInitOptions } from '../graphicsBackend/types'
|
|
11
12
|
|
|
@@ -46,6 +47,8 @@ class TestWorldRenderer extends WorldRendererCommon {
|
|
|
46
47
|
updateCamera() {}
|
|
47
48
|
render() {}
|
|
48
49
|
updateShowChunksBorder() {}
|
|
50
|
+
updatePlayerEntity() {}
|
|
51
|
+
worldStop() {}
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
function createRenderer(workerCount = 2, worldView?: DisplayWorldOptions['worldView']) {
|
|
@@ -56,7 +59,7 @@ function createRenderer(workerCount = 2, worldView?: DisplayWorldOptions['worldV
|
|
|
56
59
|
heightmaps: {} as Record<string, Int16Array>,
|
|
57
60
|
allChunksLoaded: false,
|
|
58
61
|
mesherWork: false,
|
|
59
|
-
instabilityFactors:
|
|
62
|
+
instabilityFactors: defaultPerformanceInstabilityFactors(),
|
|
60
63
|
intersectMedia: null,
|
|
61
64
|
},
|
|
62
65
|
renderer: '',
|
|
@@ -5,6 +5,7 @@ import { Vec3 } from 'vec3'
|
|
|
5
5
|
import { proxy } from 'valtio'
|
|
6
6
|
import { WorldRendererCommon } from './worldrendererCommon'
|
|
7
7
|
import { defaultWorldRendererConfig } from '../graphicsBackend/config'
|
|
8
|
+
import { defaultPerformanceInstabilityFactors } from '../performanceMonitor'
|
|
8
9
|
import { getInitialPlayerState } from '../playerState/playerState'
|
|
9
10
|
import type { DisplayWorldOptions, GraphicsInitOptions } from '../graphicsBackend/types'
|
|
10
11
|
|
|
@@ -45,16 +46,18 @@ class TestWorldRenderer extends WorldRendererCommon {
|
|
|
45
46
|
updateCamera() {}
|
|
46
47
|
render() {}
|
|
47
48
|
updateShowChunksBorder() {}
|
|
49
|
+
updatePlayerEntity() {}
|
|
50
|
+
worldStop() {}
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
function createRenderer() {
|
|
51
54
|
const rendererState = proxy({
|
|
52
55
|
world: {
|
|
53
|
-
chunksLoaded:
|
|
54
|
-
heightmaps:
|
|
56
|
+
chunksLoaded: {} as Record<string, true>,
|
|
57
|
+
heightmaps: {} as Record<string, Int16Array>,
|
|
55
58
|
allChunksLoaded: false,
|
|
56
59
|
mesherWork: false,
|
|
57
|
-
instabilityFactors:
|
|
60
|
+
instabilityFactors: defaultPerformanceInstabilityFactors(),
|
|
58
61
|
intersectMedia: null,
|
|
59
62
|
},
|
|
60
63
|
renderer: '',
|
|
@@ -73,6 +76,7 @@ function createRenderer() {
|
|
|
73
76
|
avgRenderTime: 0,
|
|
74
77
|
world: {
|
|
75
78
|
chunksLoaded: new Set<string>(),
|
|
79
|
+
chunksLoadedCount: 0,
|
|
76
80
|
chunksTotalNumber: 0,
|
|
77
81
|
chunksFullInfo: '',
|
|
78
82
|
},
|
|
@@ -93,7 +97,7 @@ function createRenderer() {
|
|
|
93
97
|
},
|
|
94
98
|
}
|
|
95
99
|
|
|
96
|
-
const renderer = new TestWorldRenderer(displayOptions.resourcesManager, displayOptions, initOptions)
|
|
100
|
+
const renderer = new TestWorldRenderer(displayOptions.resourcesManager, displayOptions as DisplayWorldOptions, initOptions)
|
|
97
101
|
renderer.active = true
|
|
98
102
|
renderer.workers = [{ postMessage: vi.fn() }, { postMessage: vi.fn() }]
|
|
99
103
|
renderer.viewDistance = 16
|
|
@@ -1443,7 +1443,7 @@ export const initMesherWorker = (onGotMessage: (data: any) => void, workerName =
|
|
|
1443
1443
|
let mesherMcDataTintsMissingWarned = false
|
|
1444
1444
|
|
|
1445
1445
|
export const meshersSendMcData = (workers: Worker[], version: string, mcDataKeys = dynamicMcDataFiles, mcDataFull: IndexedData) => {
|
|
1446
|
-
const mcData = {
|
|
1446
|
+
const mcData: { version: IndexedData['version']; tints?: unknown; [key: string]: unknown } = {
|
|
1447
1447
|
version: JSON.parse(JSON.stringify(mcDataFull.version))
|
|
1448
1448
|
}
|
|
1449
1449
|
for (const [finalKey, sourceKey] of Object.entries(mcDataKeys)) {
|
|
@@ -270,7 +270,10 @@ export function createBannerMesh(
|
|
|
270
270
|
mesh.position.set(clothXOffset, clothYOffset, clothZPosition + thickness / 2 + 0.004)
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
-
const group = new THREE.Group() as THREE.Group & {
|
|
273
|
+
const group = new THREE.Group() as THREE.Group & {
|
|
274
|
+
bannerTexture?: THREE.Texture
|
|
275
|
+
bannerMaterial?: THREE.MeshBasicMaterial
|
|
276
|
+
}
|
|
274
277
|
group.rotation.set(
|
|
275
278
|
0,
|
|
276
279
|
-THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)),
|
package/src/three/entities.ts
CHANGED
|
@@ -552,7 +552,8 @@ export class Entities {
|
|
|
552
552
|
currentSkinUrls = {} as Record<string, string>
|
|
553
553
|
|
|
554
554
|
private isCanvasBlank(canvas: HTMLCanvasElement | OffscreenCanvas): boolean {
|
|
555
|
-
|
|
555
|
+
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null
|
|
556
|
+
return !ctx
|
|
556
557
|
?.getImageData(0, 0, canvas.width, canvas.height).data
|
|
557
558
|
.some(channel => channel !== 0)
|
|
558
559
|
}
|
|
@@ -69,7 +69,7 @@ export const getBackendMethods = (worldRenderer: WorldRendererThree): any => {
|
|
|
69
69
|
// New method for updating skybox
|
|
70
70
|
setSkyboxImage: worldRenderer.skyboxRenderer.setSkyboxImage.bind(worldRenderer.skyboxRenderer),
|
|
71
71
|
// Rain methods
|
|
72
|
-
setRain:
|
|
72
|
+
setRain: worldRenderer.setRain.bind(worldRenderer),
|
|
73
73
|
spawnBlockBreakParticles(x: number, y: number, z: number, blockName: string, floorMap: number[], biomeName?: string) {
|
|
74
74
|
const module = worldRenderer.getModule<import('./modules/blockBreakParticles').BlockBreakParticlesModule>('blockBreakParticles')
|
|
75
75
|
module?.spawnBlockBreakParticles(x, y, z, blockName, floorMap, biomeName)
|
|
@@ -145,6 +145,10 @@ export const createGraphicsBackendBase = () => {
|
|
|
145
145
|
let frameTimingCollector: FrameTimingCollector | null = null
|
|
146
146
|
|
|
147
147
|
const init = (initOptionsArg: GraphicsInitOptions, mainData?: ThreeRendererMainData) => {
|
|
148
|
+
if (initOptionsArg.hello) {
|
|
149
|
+
console.log('Thanks for using minecraft-renderer project: one of the most performant Minecraft world renderers for the web!')
|
|
150
|
+
}
|
|
151
|
+
|
|
148
152
|
if (isWebWorker) {
|
|
149
153
|
initOptions = restoreTransferred(initOptionsArg, initOptionsRestorers, globalThis as unknown as Worker)
|
|
150
154
|
} else {
|
|
@@ -166,8 +170,8 @@ export const createGraphicsBackendBase = () => {
|
|
|
166
170
|
worldRenderer.destroy()
|
|
167
171
|
worldRenderer = null
|
|
168
172
|
frameTimingCollector = null
|
|
169
|
-
|
|
170
|
-
|
|
173
|
+
; (globalThis as any).world = undefined
|
|
174
|
+
; (globalThis as any).frameTimingCollector = undefined
|
|
171
175
|
}
|
|
172
176
|
|
|
173
177
|
if (menuBackgroundRenderer) {
|
|
@@ -202,8 +206,8 @@ export const createGraphicsBackendBase = () => {
|
|
|
202
206
|
worldRenderer.destroy()
|
|
203
207
|
worldRenderer = null
|
|
204
208
|
frameTimingCollector = null
|
|
205
|
-
|
|
206
|
-
|
|
209
|
+
; (globalThis as any).world = undefined
|
|
210
|
+
; (globalThis as any).frameTimingCollector = undefined
|
|
207
211
|
}
|
|
208
212
|
|
|
209
213
|
const displayOptionsRestorers = [ResourcesManager, WorldViewWorker]
|
package/src/three/itemMesh.ts
CHANGED
|
@@ -40,7 +40,7 @@ export function create3DItemMesh (
|
|
|
40
40
|
throw new Error(`Invalid canvas dimensions: ${canvas.width}x${canvas.height}`)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const ctx = canvas.getContext('2d')
|
|
43
|
+
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D
|
|
44
44
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
|
|
45
45
|
const { data } = imageData
|
|
46
46
|
|
|
@@ -17,11 +17,6 @@ const FALL_SPEED_MAX = 24
|
|
|
17
17
|
const HORIZONTAL_DRIFT = 1.2
|
|
18
18
|
const RESPAWN_BELOW = -5
|
|
19
19
|
|
|
20
|
-
const moduleOptions = {
|
|
21
|
-
particleCount: 2000,
|
|
22
|
-
speedFactor: 1,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
20
|
export class RainModule implements RendererModuleController {
|
|
26
21
|
private instancedMesh?: THREE.InstancedMesh
|
|
27
22
|
private geometry?: THREE.BoxGeometry
|
|
@@ -32,8 +27,14 @@ export class RainModule implements RendererModuleController {
|
|
|
32
27
|
private readonly tempPosition = new THREE.Vector3()
|
|
33
28
|
private readonly tempQuaternion = new THREE.Quaternion()
|
|
34
29
|
private readonly tempScale = new THREE.Vector3()
|
|
30
|
+
private readonly configUnsubs: Array<() => void> = []
|
|
35
31
|
|
|
36
|
-
constructor(private readonly worldRenderer: WorldRendererThree) {
|
|
32
|
+
constructor(private readonly worldRenderer: WorldRendererThree) {
|
|
33
|
+
this.configUnsubs.push(
|
|
34
|
+
this.worldRenderer.onReactiveConfigUpdated('rainColor', () => this.syncRainAppearance()),
|
|
35
|
+
this.worldRenderer.onReactiveConfigUpdated('rainOpacity', () => this.syncRainAppearance()),
|
|
36
|
+
)
|
|
37
|
+
}
|
|
37
38
|
|
|
38
39
|
enable(): void {
|
|
39
40
|
if (this.enabled) return
|
|
@@ -42,6 +43,7 @@ export class RainModule implements RendererModuleController {
|
|
|
42
43
|
this.createRain()
|
|
43
44
|
} else {
|
|
44
45
|
this.instancedMesh.visible = true
|
|
46
|
+
this.syncRainAppearance()
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
|
|
@@ -60,8 +62,6 @@ export class RainModule implements RendererModuleController {
|
|
|
60
62
|
render?: (deltaTime: number) => void = (deltaTime) => {
|
|
61
63
|
if (!this.enabled || !this.instancedMesh || !this.material) return
|
|
62
64
|
|
|
63
|
-
this.syncMaterialToSceneFog()
|
|
64
|
-
|
|
65
65
|
const cameraPos = this.worldRenderer.getCameraPosition()
|
|
66
66
|
this.instancedMesh.position.set(0, 0, 0)
|
|
67
67
|
|
|
@@ -126,6 +126,9 @@ export class RainModule implements RendererModuleController {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
dispose(): void {
|
|
129
|
+
for (const unsub of this.configUnsubs) unsub()
|
|
130
|
+
this.configUnsubs.length = 0
|
|
131
|
+
|
|
129
132
|
if (this.instancedMesh) {
|
|
130
133
|
this.worldRenderer.scene.remove(this.instancedMesh)
|
|
131
134
|
}
|
|
@@ -137,33 +140,31 @@ export class RainModule implements RendererModuleController {
|
|
|
137
140
|
this.particles = []
|
|
138
141
|
}
|
|
139
142
|
|
|
140
|
-
|
|
141
|
-
private syncMaterialToSceneFog(): void {
|
|
143
|
+
private syncRainAppearance(): void {
|
|
142
144
|
if (!this.material) return
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
this.material.fog = true
|
|
145
|
+
|
|
146
|
+
const { rainColor, rainOpacity } = this.worldRenderer.worldRendererConfig
|
|
147
|
+
this.material.color.set(rainColor)
|
|
148
|
+
this.material.opacity = Math.max(0, Math.min(1, rainOpacity))
|
|
149
|
+
this.material.needsUpdate = true
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
private createRain(): void {
|
|
153
|
+
const { rainColor, rainOpacity } = this.worldRenderer.worldRendererConfig
|
|
154
|
+
|
|
153
155
|
this.geometry = new THREE.BoxGeometry(0.03, 0.3, 0.03)
|
|
154
156
|
this.material = new THREE.MeshBasicMaterial({
|
|
155
|
-
color:
|
|
157
|
+
color: rainColor,
|
|
156
158
|
transparent: true,
|
|
157
|
-
opacity: 0.
|
|
159
|
+
opacity: Math.max(0, Math.min(1, rainOpacity)),
|
|
158
160
|
// Must write depth so log-depth blocks occlude rain correctly (see cubeBlockShader).
|
|
159
161
|
depthWrite: true,
|
|
160
|
-
fog:
|
|
162
|
+
fog: false,
|
|
161
163
|
})
|
|
162
164
|
|
|
163
165
|
this.instancedMesh = new THREE.InstancedMesh(this.geometry, this.material, PARTICLE_COUNT)
|
|
164
166
|
this.instancedMesh.name = 'rain-particles'
|
|
165
167
|
this.instancedMesh.frustumCulled = false
|
|
166
|
-
this.syncMaterialToSceneFog()
|
|
167
168
|
|
|
168
169
|
const dummy = new THREE.Matrix4()
|
|
169
170
|
const position = new THREE.Vector3()
|
|
@@ -26,8 +26,10 @@ class StarfieldMaterial extends THREE.ShaderMaterial {
|
|
|
26
26
|
uniform float fade;
|
|
27
27
|
varying vec3 vColor;
|
|
28
28
|
void main() {
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
// fade scales star brightness (0 = invisible). With additive blending this is
|
|
30
|
+
// the only way to dim stars — scene fog never reaches this shader. Driven by the
|
|
31
|
+
// rain state so stars disappear in rain like in vanilla.
|
|
32
|
+
gl_FragColor = vec4(vColor * fade, 1.0);
|
|
31
33
|
|
|
32
34
|
#include <tonemapping_fragment>
|
|
33
35
|
#include <${threeVersion >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>
|
|
@@ -41,6 +43,8 @@ export class StarfieldModule implements RendererModuleController {
|
|
|
41
43
|
private timer = new THREE.Timer()
|
|
42
44
|
private enabled = false
|
|
43
45
|
private currentTime?: number
|
|
46
|
+
/** Current star brightness multiplier; lerps toward 0 while raining, 1 otherwise. */
|
|
47
|
+
private fade = 1
|
|
44
48
|
|
|
45
49
|
constructor(private readonly worldRenderer: WorldRendererThree) { }
|
|
46
50
|
|
|
@@ -72,12 +76,20 @@ export class StarfieldModule implements RendererModuleController {
|
|
|
72
76
|
return this.currentTime > nightTime && this.currentTime < morningStart
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
render?: (deltaTime: number) => void = (
|
|
79
|
+
render?: (deltaTime: number) => void = (deltaTime) => {
|
|
76
80
|
if (!this.points) return
|
|
77
81
|
this.points.position.set(0, 0, 0)
|
|
82
|
+
|
|
83
|
+
const material = this.points.material as StarfieldMaterial
|
|
78
84
|
this.timer.update(performance.now())
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
material.uniforms.time.value = this.timer.getElapsed() * 0.2
|
|
86
|
+
|
|
87
|
+
// Fade stars out while raining (vanilla scales star brightness by 1 - rainLevel).
|
|
88
|
+
// isRaining is a boolean here, so ease toward the target instead of snapping.
|
|
89
|
+
const target = this.worldRenderer.worldRendererConfig.isRaining ? 0 : 1
|
|
90
|
+
const t = Math.min(1, deltaTime * 2)
|
|
91
|
+
this.fade += (target - this.fade) * t
|
|
92
|
+
material.uniforms.fade.value = this.fade
|
|
81
93
|
}
|
|
82
94
|
|
|
83
95
|
/**
|
|
@@ -355,6 +355,11 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
355
355
|
return targetState
|
|
356
356
|
}
|
|
357
357
|
|
|
358
|
+
setRain(enabled: boolean): void {
|
|
359
|
+
this.worldRendererConfig.isRaining = enabled
|
|
360
|
+
this.toggleModule('rain', enabled)
|
|
361
|
+
}
|
|
362
|
+
|
|
358
363
|
/**
|
|
359
364
|
* Dispose all modules
|
|
360
365
|
*/
|
|
@@ -696,7 +701,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
696
701
|
this.syncSkyLevelFromTime(newTime)
|
|
697
702
|
}
|
|
698
703
|
|
|
699
|
-
private syncSkyLevelFromTime
|
|
704
|
+
private syncSkyLevelFromTime(timeOfDay: number): void {
|
|
700
705
|
const skyLevel = calculateSkyLightSimple(timeOfDay) / 15
|
|
701
706
|
this.chunkMeshManager.setSkyLevel(skyLevel)
|
|
702
707
|
}
|
|
@@ -792,10 +797,6 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
792
797
|
}
|
|
793
798
|
}
|
|
794
799
|
|
|
795
|
-
override updateViewerPosition(pos: Vec3): void {
|
|
796
|
-
this.viewerChunkPosition = pos
|
|
797
|
-
}
|
|
798
|
-
|
|
799
800
|
cameraSectionPositionUpdate() {
|
|
800
801
|
// eslint-disable-next-line guard-for-in
|
|
801
802
|
for (const key in this.sectionObjects) {
|
|
@@ -1583,7 +1584,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1583
1584
|
this.chunkMeshManager.onChunkRemovedFromGate(`${x},${z}`)
|
|
1584
1585
|
}
|
|
1585
1586
|
|
|
1586
|
-
updateViewerPosition(pos: Vec3) {
|
|
1587
|
+
override updateViewerPosition(pos: Vec3) {
|
|
1587
1588
|
super.updateViewerPosition(pos)
|
|
1588
1589
|
if (this.chunkMeshManager.pendingNearReveal.size > 0) {
|
|
1589
1590
|
this.chunkMeshManager.tryRevealPending()
|
|
@@ -23,6 +23,12 @@ import { renderWasmOutputToGeometry } from '../bridge/render-from-wasm'
|
|
|
23
23
|
|
|
24
24
|
const VERSION = '1.16.5'
|
|
25
25
|
const STONE = 1
|
|
26
|
+
|
|
27
|
+
function requireShaderCubeResources() {
|
|
28
|
+
const resources = getShaderCubeResources()
|
|
29
|
+
if (!resources) throw new Error('shader cube resources unavailable in test')
|
|
30
|
+
return resources
|
|
31
|
+
}
|
|
26
32
|
/** mc-assets blocksAtlases.json → stone */
|
|
27
33
|
const STONE_ATLAS_TILE_INDEX = 552
|
|
28
34
|
|
|
@@ -39,7 +45,7 @@ test('packWord2: AO diagonal flip sets bit 12', () => {
|
|
|
39
45
|
light_data: [[1, 1, 1, 1]],
|
|
40
46
|
light_combined: [[255, 255, 255, 255]],
|
|
41
47
|
}
|
|
42
|
-
const { textureIndexMapping, tintPalette } =
|
|
48
|
+
const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
|
|
43
49
|
const model = {
|
|
44
50
|
elements: [{
|
|
45
51
|
faces: {
|
|
@@ -78,7 +84,7 @@ test('packWord0: section-local lx/ly/lz and face id', () => {
|
|
|
78
84
|
light_data: [[0.5, 0.5, 0.5, 0.5]],
|
|
79
85
|
light_combined: [[128, 128, 128, 128]],
|
|
80
86
|
}
|
|
81
|
-
const { textureIndexMapping, tintPalette } =
|
|
87
|
+
const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
|
|
82
88
|
const model = {
|
|
83
89
|
elements: [{
|
|
84
90
|
faces: {
|
|
@@ -111,7 +117,7 @@ test('packWord0: section-local lx/ly/lz and face id', () => {
|
|
|
111
117
|
})
|
|
112
118
|
|
|
113
119
|
test('isShaderCubeBlock: rejects model rotation and sectionHeight !== 16', () => {
|
|
114
|
-
const { textureIndexMapping } =
|
|
120
|
+
const { textureIndexMapping } = requireShaderCubeResources()
|
|
115
121
|
const baseModel = {
|
|
116
122
|
elements: [{
|
|
117
123
|
faces: {
|
|
@@ -222,7 +228,7 @@ test('south face: AO corners remapped to shader order (elemFaces [0,3,1,2] → s
|
|
|
222
228
|
light_data: [[1, 1, 1, 1]],
|
|
223
229
|
light_combined: [[10, 20, 30, 40]],
|
|
224
230
|
}
|
|
225
|
-
const { textureIndexMapping, tintPalette } =
|
|
231
|
+
const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
|
|
226
232
|
const model = { elements: [{ faces: SIX_FACE_TEXTURES }] }
|
|
227
233
|
tryBuildShaderCubeInstances(
|
|
228
234
|
block,
|
|
@@ -248,7 +254,7 @@ test('south face: diagonal flip uses remapped AO (differs from raw elemFaces for
|
|
|
248
254
|
light_data: [[1, 1, 1, 1]],
|
|
249
255
|
light_combined: [[255, 255, 255, 255]],
|
|
250
256
|
}
|
|
251
|
-
const { textureIndexMapping, tintPalette } =
|
|
257
|
+
const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
|
|
252
258
|
const model = { elements: [{ faces: SIX_FACE_TEXTURES }] }
|
|
253
259
|
const opts = {
|
|
254
260
|
sectionOrigin: { x: 0, y: 0, z: 0 },
|
|
@@ -285,7 +291,7 @@ test('doAO false: full bright AO/light and no diagonal flip', () => {
|
|
|
285
291
|
light_data: [[0, 0, 0, 0]],
|
|
286
292
|
light_combined: [[0, 0, 0, 0]],
|
|
287
293
|
}
|
|
288
|
-
const { textureIndexMapping, tintPalette } =
|
|
294
|
+
const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
|
|
289
295
|
const model = { elements: [{ faces: SIX_FACE_TEXTURES }] }
|
|
290
296
|
tryBuildShaderCubeInstances(
|
|
291
297
|
block,
|
|
@@ -329,7 +335,7 @@ test.each(SECTION_ORIGIN_ROUND_TRIP_CASES)(
|
|
|
329
335
|
light_data: [[1, 1, 1, 1]],
|
|
330
336
|
light_combined: [[255, 255, 255, 255]],
|
|
331
337
|
}
|
|
332
|
-
const { textureIndexMapping, tintPalette } =
|
|
338
|
+
const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
|
|
333
339
|
const model = { elements: [{ faces: SIX_FACE_TEXTURES }] }
|
|
334
340
|
tryBuildShaderCubeInstances(
|
|
335
341
|
block,
|
|
@@ -361,7 +367,7 @@ test('section index relative decode past 2^20: exact integer subtract', () => {
|
|
|
361
367
|
light_data: [[1, 1, 1, 1]],
|
|
362
368
|
light_combined: [[255, 255, 255, 255]],
|
|
363
369
|
}
|
|
364
|
-
const { textureIndexMapping, tintPalette } =
|
|
370
|
+
const { textureIndexMapping, tintPalette } = requireShaderCubeResources()
|
|
365
371
|
const model = { elements: [{ faces: SIX_FACE_TEXTURES }] }
|
|
366
372
|
tryBuildShaderCubeInstances(
|
|
367
373
|
block,
|