minecraft-renderer 0.1.63 → 0.1.65

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minecraft-renderer",
3
- "version": "0.1.63",
3
+ "version": "0.1.65",
4
4
  "description": "The most Modular Minecraft world renderer with Three.js WebGL backend",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,12 +1,12 @@
1
1
  //@ts-nocheck
2
2
  import {
3
- FUTURISTIC_CAMERA_IDS,
4
- FUTURISTIC_CAMERA_LABELS,
5
- FUTURISTIC_SCENE_IDS,
6
- FUTURISTIC_SCENE_LABELS,
3
+ V2_CAMERA_IDS,
4
+ V2_CAMERA_LABELS,
5
+ V2_SCENE_IDS,
6
+ V2_SCENE_LABELS,
7
7
  MINECRAFT_BLOCK_GROUP_IDS,
8
8
  MINECRAFT_BLOCK_GROUP_LABELS
9
- } from '../three/menuBackground/futuristicMeta'
9
+ } from '../three/menuBackground/v2Meta'
10
10
  import { MENU_BACKGROUND_OPTION_DEFAULTS } from '../three/menuBackground/config'
11
11
  import type { RendererGpuPreference } from '../three/menuBackground/gpuPreference'
12
12
 
@@ -54,11 +54,11 @@ export const RENDERER_DEFAULT_OPTIONS = {
54
54
  defaultSkybox: true as boolean,
55
55
  menuBackgroundMode: MB.mode,
56
56
  menuBackgroundMinecraftTextures: MB.minecraftTextures as boolean,
57
- menuBackgroundFuturisticScene: MB.futuristicScene,
58
- menuBackgroundFuturisticCamera: MB.futuristicCamera,
59
- menuBackgroundFuturisticBlockGroup: MB.futuristicBlockGroup,
60
- menuBackgroundFuturisticCameraSpeed: MB.futuristicCameraSpeedPercent,
61
- menuBackgroundFuturisticBlockSpeed: MB.futuristicBlockSpeedPercent,
57
+ menuBackgroundV2Scene: MB.v2Scene,
58
+ menuBackgroundV2Camera: MB.v2Camera,
59
+ menuBackgroundV2BlockGroup: MB.v2BlockGroup,
60
+ menuBackgroundV2CameraSpeed: MB.v2CameraSpeedPercent,
61
+ menuBackgroundV2BlockSpeed: MB.v2BlockSpeedPercent,
62
62
  rendererFuturisticReveal: false as boolean,
63
63
  rendererPerfDebugOverlay: false as boolean,
64
64
  disableBlockEntityTextures: false as boolean,
@@ -110,37 +110,54 @@ export function migrateRendererOptions(saved: Record<string, unknown>): void {
110
110
  }
111
111
  delete saved.wasmExperimentalMesher
112
112
  delete saved.rendererWasmMesher
113
+
114
+ if (saved.menuBackgroundMode === 'futuristic') {
115
+ saved.menuBackgroundMode = 'v2'
116
+ }
117
+ const futuristicToV2: Array<[string, string]> = [
118
+ ['menuBackgroundFuturisticScene', 'menuBackgroundV2Scene'],
119
+ ['menuBackgroundFuturisticCamera', 'menuBackgroundV2Camera'],
120
+ ['menuBackgroundFuturisticBlockGroup', 'menuBackgroundV2BlockGroup'],
121
+ ['menuBackgroundFuturisticCameraSpeed', 'menuBackgroundV2CameraSpeed'],
122
+ ['menuBackgroundFuturisticBlockSpeed', 'menuBackgroundV2BlockSpeed'],
123
+ ]
124
+ for (const [oldKey, newKey] of futuristicToV2) {
125
+ if (saved[oldKey] !== undefined && saved[newKey] === undefined) {
126
+ saved[newKey] = saved[oldKey]
127
+ }
128
+ delete saved[oldKey]
129
+ }
113
130
  }
114
131
 
115
132
  /** Settings UI metadata for {@link RENDERER_DEFAULT_OPTIONS} keys. */
116
133
  export const RENDERER_OPTIONS_META: Partial<Record<RendererDefaultOptionKey, RendererOptionMeta>> = {
117
134
  menuBackgroundMode: {
118
- possibleValues: [['classic', 'Classic'], ['futuristic', 'Futuristic']],
135
+ possibleValues: [['classic', 'Classic'], ['v2', 'V2']],
119
136
  requiresRestart: true
120
137
  },
121
138
  menuBackgroundMinecraftTextures: {
122
139
  text: 'Minecraft block textures',
123
- tooltip: 'Use block atlas on futuristic menu cubes (loads assets on menu)'
140
+ tooltip: 'Use block atlas on V2 menu cubes (loads assets on menu)'
124
141
  },
125
- menuBackgroundFuturisticScene: {
126
- possibleValues: FUTURISTIC_SCENE_IDS.map(id => [id, FUTURISTIC_SCENE_LABELS[id]] as [string, string])
142
+ menuBackgroundV2Scene: {
143
+ possibleValues: V2_SCENE_IDS.map(id => [id, V2_SCENE_LABELS[id]] as [string, string])
127
144
  },
128
- menuBackgroundFuturisticCamera: {
129
- possibleValues: FUTURISTIC_CAMERA_IDS.map(id => [id, FUTURISTIC_CAMERA_LABELS[id]] as [string, string])
145
+ menuBackgroundV2Camera: {
146
+ possibleValues: V2_CAMERA_IDS.map(id => [id, V2_CAMERA_LABELS[id]] as [string, string])
130
147
  },
131
- menuBackgroundFuturisticBlockGroup: {
148
+ menuBackgroundV2BlockGroup: {
132
149
  possibleValues: MINECRAFT_BLOCK_GROUP_IDS.map(id => [id, MINECRAFT_BLOCK_GROUP_LABELS[id]] as [string, string]),
133
150
  text: 'Block pool',
134
151
  tooltip: 'Block set for textured menu cubes (requires Minecraft textures)'
135
152
  },
136
- menuBackgroundFuturisticCameraSpeed: {
153
+ menuBackgroundV2CameraSpeed: {
137
154
  text: 'Camera speed',
138
155
  tooltip: 'Orbit / fly-through camera path speed. 0 freezes the path; mouse parallax still works.',
139
156
  min: 0,
140
157
  max: 200,
141
158
  unit: '%'
142
159
  },
143
- menuBackgroundFuturisticBlockSpeed: {
160
+ menuBackgroundV2BlockSpeed: {
144
161
  text: 'Block speed',
145
162
  tooltip: 'Floating blocks and sky rotation. Independent of camera path speed.',
146
163
  min: 0,
@@ -315,11 +332,11 @@ export const RENDERER_RENDER_GUI_SECTIONS: ReadonlyArray<{
315
332
  keys: [
316
333
  'menuBackgroundMode',
317
334
  'menuBackgroundMinecraftTextures',
318
- 'menuBackgroundFuturisticScene',
319
- 'menuBackgroundFuturisticCamera',
320
- 'menuBackgroundFuturisticBlockGroup',
321
- 'menuBackgroundFuturisticCameraSpeed',
322
- 'menuBackgroundFuturisticBlockSpeed'
335
+ 'menuBackgroundV2Scene',
336
+ 'menuBackgroundV2Camera',
337
+ 'menuBackgroundV2BlockGroup',
338
+ 'menuBackgroundV2CameraSpeed',
339
+ 'menuBackgroundV2BlockSpeed'
323
340
  ]
324
341
  },
325
342
  {
@@ -11,7 +11,7 @@ import { rendererShaderCubeDebugModeToValue } from './rendererDefaultOptions'
11
11
  import type { MenuBackgroundOptions } from '../three/menuBackground/types'
12
12
  import type { MenuBackgroundRenderer } from '../three/menuBackground/renderer'
13
13
  import { menuBackgroundSpeedToMultiplier } from '../three/menuBackground/config'
14
- import type { FuturisticCameraId, FuturisticSceneId, MinecraftBlockGroupId } from '../three/menuBackground/futuristic'
14
+ import type { V2CameraId, V2SceneId, MinecraftBlockGroupId } from '../three/menuBackground/v2'
15
15
  import { setSkinsConfig } from '../lib/utils/skins'
16
16
 
17
17
  export type { RendererStorageOptions } from './rendererDefaultOptions'
@@ -37,20 +37,20 @@ export function menuBackgroundOptionsFromStorage(o: Pick<
37
37
  RendererStorageOptions,
38
38
  | 'menuBackgroundMode'
39
39
  | 'menuBackgroundMinecraftTextures'
40
- | 'menuBackgroundFuturisticScene'
41
- | 'menuBackgroundFuturisticCamera'
42
- | 'menuBackgroundFuturisticBlockGroup'
43
- | 'menuBackgroundFuturisticCameraSpeed'
44
- | 'menuBackgroundFuturisticBlockSpeed'
40
+ | 'menuBackgroundV2Scene'
41
+ | 'menuBackgroundV2Camera'
42
+ | 'menuBackgroundV2BlockGroup'
43
+ | 'menuBackgroundV2CameraSpeed'
44
+ | 'menuBackgroundV2BlockSpeed'
45
45
  >): MenuBackgroundOptions {
46
46
  return {
47
47
  mode: o.menuBackgroundMode as MenuBackgroundOptions['mode'],
48
48
  useMinecraftTextures: o.menuBackgroundMinecraftTextures,
49
- futuristicScene: o.menuBackgroundFuturisticScene as FuturisticSceneId,
50
- futuristicCamera: o.menuBackgroundFuturisticCamera as FuturisticCameraId,
51
- futuristicBlockGroup: o.menuBackgroundFuturisticBlockGroup as MinecraftBlockGroupId,
52
- futuristicCameraSpeed: menuBackgroundSpeedToMultiplier(o.menuBackgroundFuturisticCameraSpeed),
53
- futuristicBlockSpeed: menuBackgroundSpeedToMultiplier(o.menuBackgroundFuturisticBlockSpeed),
49
+ v2Scene: o.menuBackgroundV2Scene as V2SceneId,
50
+ v2Camera: o.menuBackgroundV2Camera as V2CameraId,
51
+ v2BlockGroup: o.menuBackgroundV2BlockGroup as MinecraftBlockGroupId,
52
+ v2CameraSpeed: menuBackgroundSpeedToMultiplier(o.menuBackgroundV2CameraSpeed),
53
+ v2BlockSpeed: menuBackgroundSpeedToMultiplier(o.menuBackgroundV2BlockSpeed),
54
54
  }
55
55
  }
56
56
 
@@ -58,20 +58,20 @@ export function applyMenuBackgroundLiveOptions(
58
58
  menu: MenuBackgroundRenderer,
59
59
  o: Pick<
60
60
  RendererStorageOptions,
61
- | 'menuBackgroundFuturisticScene'
62
- | 'menuBackgroundFuturisticCamera'
63
- | 'menuBackgroundFuturisticBlockGroup'
64
- | 'menuBackgroundFuturisticCameraSpeed'
65
- | 'menuBackgroundFuturisticBlockSpeed'
61
+ | 'menuBackgroundV2Scene'
62
+ | 'menuBackgroundV2Camera'
63
+ | 'menuBackgroundV2BlockGroup'
64
+ | 'menuBackgroundV2CameraSpeed'
65
+ | 'menuBackgroundV2BlockSpeed'
66
66
  >
67
67
  ): void {
68
- const futuristic = menu.futuristic
69
- if (!futuristic) return
70
- futuristic.setScene?.(o.menuBackgroundFuturisticScene)
71
- futuristic.setCamera?.(o.menuBackgroundFuturisticCamera)
72
- void futuristic.setBlockGroup?.(o.menuBackgroundFuturisticBlockGroup)
73
- futuristic.setCameraSpeed?.(menuBackgroundSpeedToMultiplier(o.menuBackgroundFuturisticCameraSpeed))
74
- futuristic.setBlockSpeed?.(menuBackgroundSpeedToMultiplier(o.menuBackgroundFuturisticBlockSpeed))
68
+ const v2 = menu.v2
69
+ if (!v2) return
70
+ v2.setScene?.(o.menuBackgroundV2Scene)
71
+ v2.setCamera?.(o.menuBackgroundV2Camera)
72
+ void v2.setBlockGroup?.(o.menuBackgroundV2BlockGroup)
73
+ v2.setCameraSpeed?.(menuBackgroundSpeedToMultiplier(o.menuBackgroundV2CameraSpeed))
74
+ v2.setBlockSpeed?.(menuBackgroundSpeedToMultiplier(o.menuBackgroundV2BlockSpeed))
75
75
  }
76
76
 
77
77
  function resolveWasmMesherActive(o: RendererStorageOptions): boolean {
package/src/index.ts CHANGED
@@ -85,21 +85,21 @@ export type {
85
85
  MenuBackgroundMode,
86
86
  MenuBackgroundOptions,
87
87
  MenuBackgroundView,
88
- FuturisticSceneId,
89
- FuturisticCameraId,
90
- FuturisticMenuBackgroundOptions,
88
+ V2SceneId,
89
+ V2CameraId,
90
+ V2MenuBackgroundOptions,
91
91
  MinecraftBlockGroupId
92
92
  } from './three/menuBackground'
93
93
  export {
94
94
  MenuBackgroundRenderer,
95
95
  ClassicMenuBackground,
96
- FuturisticMenuBackground,
96
+ V2MenuBackground,
97
97
  WorldBlocksMenuBackground,
98
98
  MENU_BACKGROUND_MC_VERSION,
99
- FUTURISTIC_SCENE_IDS,
100
- FUTURISTIC_CAMERA_IDS,
101
- FUTURISTIC_SCENE_LABELS,
102
- FUTURISTIC_CAMERA_LABELS,
99
+ V2_SCENE_IDS,
100
+ V2_CAMERA_IDS,
101
+ V2_SCENE_LABELS,
102
+ V2_CAMERA_LABELS,
103
103
  MINECRAFT_BLOCK_GROUPS,
104
104
  MINECRAFT_BLOCK_GROUP_IDS,
105
105
  MINECRAFT_BLOCK_GROUP_LABELS,
@@ -0,0 +1,182 @@
1
+ //@ts-nocheck
2
+ import { EventEmitter } from 'events'
3
+ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
4
+ import { Vec3 } from 'vec3'
5
+ import { proxy } from 'valtio'
6
+ import { WorldRendererCommon } from './worldrendererCommon'
7
+ import { defaultWorldRendererConfig } from '../graphicsBackend/config'
8
+ import { getInitialPlayerState } from '../playerState/playerState'
9
+ import type { DisplayWorldOptions, GraphicsInitOptions } from '../graphicsBackend/types'
10
+
11
+ vi.mock('./ui/newStats', () => ({
12
+ addNewStat: vi.fn(() => ({ updateText: vi.fn(), setVisibility: vi.fn() })),
13
+ updateStatText: vi.fn(),
14
+ removeAllStats: vi.fn(),
15
+ updatePanesVisibility: vi.fn(),
16
+ MC_RENDERER_DEBUG_OVERLAY_CLASS: 'mc-renderer-debug-overlay',
17
+ }))
18
+
19
+ vi.mock('./utils/skins', () => ({
20
+ setSkinsConfig: vi.fn(),
21
+ steveTexture: {},
22
+ stevePngUrl: '',
23
+ }))
24
+
25
+ function ensurePromiseWithResolvers() {
26
+ if (!Promise.withResolvers) {
27
+ Promise.withResolvers = function <T>() {
28
+ let resolve!: (value: T | PromiseLike<T>) => void
29
+ let reject!: (reason?: unknown) => void
30
+ const promise = new Promise<T>((res, rej) => {
31
+ resolve = res
32
+ reject = rej
33
+ })
34
+ return { promise, resolve, reject }
35
+ }
36
+ }
37
+ }
38
+
39
+ class TestWorldRenderer extends WorldRendererCommon {
40
+ outputFormat = 'threeJs' as const
41
+
42
+ changeBackgroundColor() {}
43
+ changeCardinalLight() {}
44
+ handleWorkerMessage() {}
45
+ updateCamera() {}
46
+ render() {}
47
+ updateShowChunksBorder() {}
48
+ }
49
+
50
+ function createRenderer() {
51
+ const rendererState = proxy({
52
+ world: {
53
+ chunksLoaded: new Set<string>(),
54
+ heightmaps: new Map<string, Int16Array>(),
55
+ allChunksLoaded: false,
56
+ mesherWork: false,
57
+ instabilityFactors: {},
58
+ intersectMedia: null,
59
+ },
60
+ renderer: '',
61
+ preventEscapeMenu: false,
62
+ })
63
+
64
+ const displayOptions = {
65
+ version: '1.21.1',
66
+ worldView: new EventEmitter() as DisplayWorldOptions['worldView'],
67
+ inWorldRenderingConfig: { ...defaultWorldRendererConfig },
68
+ playerStateReactive: getInitialPlayerState(),
69
+ rendererState,
70
+ nonReactiveState: {
71
+ fps: 0,
72
+ worstRenderTime: 0,
73
+ avgRenderTime: 0,
74
+ world: {
75
+ chunksLoaded: new Set<string>(),
76
+ chunksTotalNumber: 0,
77
+ chunksFullInfo: '',
78
+ },
79
+ renderer: {
80
+ timeline: { live: [], frozen: [], lastSecond: [] },
81
+ },
82
+ },
83
+ resourcesManager: {} as DisplayWorldOptions['resourcesManager'],
84
+ }
85
+
86
+ const initOptions: GraphicsInitOptions = {
87
+ config: { sceneBackground: '#000' },
88
+ rendererSpecificSettings: {},
89
+ callbacks: {
90
+ displayCriticalError: vi.fn(),
91
+ setRendererSpecificSettings: vi.fn(),
92
+ fireCustomEvent: vi.fn(),
93
+ },
94
+ }
95
+
96
+ const renderer = new TestWorldRenderer(displayOptions.resourcesManager, displayOptions, initOptions)
97
+ renderer.active = true
98
+ renderer.workers = [{ postMessage: vi.fn() }, { postMessage: vi.fn() }]
99
+ renderer.viewDistance = 16
100
+ renderer.viewerChunkPosition = new Vec3(0, 64, 0)
101
+ renderer.worldSizeParams = { minY: 0, worldHeight: 256 }
102
+ renderer.loadedChunks['160,0'] = true
103
+ return renderer
104
+ }
105
+
106
+ function sectionKeysForColumn(renderer: TestWorldRenderer, x: number, z: number): string[] {
107
+ const keys: string[] = []
108
+ const sectionHeight = renderer.getSectionHeight()
109
+ for (let y = renderer.worldMinYRender; y < renderer.worldSizeParams.worldHeight; y += sectionHeight) {
110
+ keys.push(`${x},${y},${z}`)
111
+ }
112
+ return keys
113
+ }
114
+
115
+ describe('WorldRendererCommon.removeColumn sectionsWaiting reconciliation', () => {
116
+ beforeEach(() => {
117
+ ensurePromiseWithResolvers()
118
+ vi.useFakeTimers()
119
+ vi.stubGlobal('location', { href: 'http://localhost/' })
120
+ })
121
+
122
+ afterEach(() => {
123
+ vi.useRealTimers()
124
+ vi.unstubAllGlobals()
125
+ })
126
+
127
+ test('clears sectionsWaiting when viewDistance gate blocks setSectionDirty(false)', () => {
128
+ const renderer = createRenderer()
129
+ const columnX = 160
130
+ const columnZ = 0
131
+ const sectionPos = new Vec3(columnX, 64, columnZ)
132
+
133
+ renderer.setSectionDirty(sectionPos, true)
134
+ expect(renderer.sectionsWaiting.get(`${columnX},64,${columnZ}`)).toBe(1)
135
+
136
+ renderer.viewDistance = 4
137
+ renderer.removeColumn(columnX, columnZ)
138
+
139
+ for (const key of sectionKeysForColumn(renderer, columnX, columnZ)) {
140
+ expect(renderer.sectionsWaiting.has(key)).toBe(false)
141
+ }
142
+ })
143
+
144
+ test('treats late sectionFinished as a no-op after removeColumn', () => {
145
+ const renderer = createRenderer()
146
+ const sectionKey = '160,64,0'
147
+ const debugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {})
148
+
149
+ renderer.sectionsWaiting.set(sectionKey, 1)
150
+ renderer.viewDistance = 4
151
+ renderer.removeColumn(160, 0)
152
+
153
+ expect(() => {
154
+ renderer.handleMessage({ type: 'sectionFinished', key: sectionKey, workerIndex: 0 })
155
+ }).not.toThrow()
156
+
157
+ expect(renderer.sectionsWaiting.has(sectionKey)).toBe(false)
158
+ expect(debugSpy).toHaveBeenCalledWith(
159
+ expect.stringContaining('sectionFinished for non-outstanding section'),
160
+ )
161
+
162
+ debugSpy.mockRestore()
163
+ })
164
+
165
+ test('clears sectionsWaiting when unload happens before batched dirty flush', () => {
166
+ const renderer = createRenderer()
167
+ renderer.forceCallFromMesherReplayer = false
168
+ const columnX = 160
169
+ const columnZ = 0
170
+
171
+ renderer.setSectionDirty(new Vec3(columnX, 64, columnZ), true)
172
+ expect(renderer.sectionsWaiting.get(`${columnX},64,${columnZ}`)).toBe(1)
173
+
174
+ renderer.viewDistance = 4
175
+ renderer.removeColumn(columnX, columnZ)
176
+ vi.advanceTimersByTime(0)
177
+
178
+ for (const key of sectionKeysForColumn(renderer, columnX, columnZ)) {
179
+ expect(renderer.sectionsWaiting.has(key)).toBe(false)
180
+ }
181
+ })
182
+ })
@@ -424,7 +424,10 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
424
424
  }
425
425
  if (data.type === 'sectionFinished') { // on after load & unload section
426
426
  this.logWorkerWork(`<- ${data.workerIndex} sectionFinished ${data.key} ${JSON.stringify({ processTime: data.processTime })}`)
427
- if (!this.sectionsWaiting.has(data.key)) throw new Error(`sectionFinished event for non-outstanding section ${data.key}`)
427
+ if (!this.sectionsWaiting.has(data.key)) {
428
+ console.debug(`sectionFinished for non-outstanding section ${data.key} (viewDistance=${this.viewDistance})`)
429
+ return
430
+ }
428
431
  this.sectionsWaiting.set(data.key, this.sectionsWaiting.get(data.key)! - 1)
429
432
  if (this.sectionsWaiting.get(data.key) === 0) {
430
433
  this.sectionsWaiting.delete(data.key)
@@ -787,9 +790,11 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
787
790
  this.sectionDirtyPendingArgs.delete(key)
788
791
  }
789
792
  }
790
- for (const worker of this.workers) {
791
- worker.postMessage({ type: 'unloadChunk', x, z })
793
+ for (let i = 0; i < this.workers.length; i++) {
794
+ this.toWorkerMessagesQueue[i] ??= []
795
+ this.toWorkerMessagesQueue[i].push({ type: 'unloadChunk', x, z })
792
796
  }
797
+ this.dispatchMessages()
793
798
  this.logWorkerWork(`-> unloadChunk ${JSON.stringify({ x, z })}`)
794
799
  delete this.finishedChunks[`${x},${z}`]
795
800
  this.allChunksFinished = Object.keys(this.finishedChunks).length === this.chunksLength
@@ -798,9 +803,14 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
798
803
  this.initialChunkLoadWasStartedIn = undefined
799
804
  }
800
805
  const sectionHeight = this.getSectionHeight()
801
- for (let y = this.worldSizeParams.minY; y < this.worldSizeParams.worldHeight; y += sectionHeight) {
802
- this.setSectionDirty(new Vec3(x, y, z), false)
803
- delete this.finishedSections[`${x},${y},${z}`]
806
+ for (let y = this.worldMinYRender; y < this.worldSizeParams.worldHeight; y += sectionHeight) {
807
+ const sectionKey = `${x},${y},${z}`
808
+ const waitingCount = this.sectionsWaiting.get(sectionKey)
809
+ if (waitingCount !== undefined && waitingCount > 0) {
810
+ console.debug(`[removeColumn] clearing non-zero sectionsWaiting for ${sectionKey}: ${waitingCount} (chunk ${x},${z}, viewDistance=${this.viewDistance})`)
811
+ }
812
+ this.sectionsWaiting.delete(sectionKey)
813
+ delete this.finishedSections[sectionKey]
804
814
  }
805
815
  this.highestBlocksByChunks.delete(`${x},${z}`)
806
816
  const heightmapKey = `${Math.floor(x / 16)},${Math.floor(z / 16)}`