From 245300ff84e8db42298ef38622887a25a858ab5b Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 18 Feb 2025 21:48:18 +0300 Subject: [PATCH 01/22] init --- package.json | 3 ++- renderer/viewer/lib/lightEngine.ts | 33 +++++++++++++++++++++++++ renderer/viewer/lib/worldDataEmitter.ts | 18 +++++++++++--- 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 renderer/viewer/lib/lightEngine.ts diff --git a/package.json b/package.json index 79e2a9bad..0afa4bcfd 100644 --- a/package.json +++ b/package.json @@ -162,7 +162,8 @@ "timers-browserify": "^2.0.12", "typescript": "5.5.4", "vitest": "^0.34.6", - "yaml": "^2.3.2" + "yaml": "^2.3.2", + "minecraft-lighting": "file:../minecraft-lighting" }, "optionalDependencies": { "cypress": "^10.11.0", diff --git a/renderer/viewer/lib/lightEngine.ts b/renderer/viewer/lib/lightEngine.ts new file mode 100644 index 000000000..25d0bbd01 --- /dev/null +++ b/renderer/viewer/lib/lightEngine.ts @@ -0,0 +1,33 @@ +import { createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock } from 'minecraft-lighting/src/prismarineShim' +import { LightWorld } from 'minecraft-lighting/src/engine' +import { world } from 'prismarine-world' +import { Chunk } from 'prismarine-world/types/world' +import { fillColumnWithZeroLight } from 'minecraft-lighting/src/testDebug' + +let lightEngine: LightWorld | null = null +export const getLightEngine = () => { + if (!lightEngine) throw new Error('Light engine not initialized') + return lightEngine +} + +export const createLightEngine = () => { + lightEngine = createLightEngineForSyncWorld(worldView!.world as world.WorldSync, loadedData, { + minY: viewer.world.worldConfig.minY, + height: viewer.world.worldConfig.worldHeight, + enableSkyLight: false, + }) + globalThis.lightEngine = lightEngine +} + +export const processLightChunk = async (x: number, z: number) => { + const chunkX = Math.floor(x / 16) + const chunkZ = Math.floor(z / 16) + const engine = getLightEngine() + fillColumnWithZeroLight(engine.externalWorld, chunkX, chunkZ) + return engine.receiveUpdateColumn(chunkX, chunkZ) +} + +export const updateBlockLight = (x: number, y: number, z: number, stateId: number) => { + const engine = getLightEngine() + engine.setBlock(x, y, z, convertPrismarineBlockToWorldBlock(mcData.blocks[stateId], mcData)) +} diff --git a/renderer/viewer/lib/worldDataEmitter.ts b/renderer/viewer/lib/worldDataEmitter.ts index 7c2be7154..fdeb4cb9f 100644 --- a/renderer/viewer/lib/worldDataEmitter.ts +++ b/renderer/viewer/lib/worldDataEmitter.ts @@ -5,10 +5,10 @@ import { EventEmitter } from 'events' import { generateSpiralMatrix, ViewRect } from 'flying-squid/dist/utils' import { Vec3 } from 'vec3' import { BotEvents } from 'mineflayer' -import { getItemFromBlock } from '../../../src/chatUtils' import { delayedIterator } from '../../playground/shared' import { playerState } from '../../../src/mineflayer/playerState' import { chunkPos } from './simpleUtils' +import { createLightEngine, processLightChunk, updateBlockLight } from './lightEngine' export type ChunkPosKey = string type ChunkPos = { x: number, z: number } @@ -52,6 +52,7 @@ export class WorldDataEmitter extends EventEmitter { return } + updateBlockLight(position.x, position.y, position.z, stateId) this.emit('blockUpdate', { pos: position, stateId }) } @@ -145,6 +146,7 @@ export class WorldDataEmitter extends EventEmitter { } async init (pos: Vec3) { + createLightEngine() this.updateViewDistance(this.viewDistance) this.emitter.emit('chunkPosUpdate', { pos }) const [botX, botZ] = chunkPos(pos) @@ -177,12 +179,22 @@ export class WorldDataEmitter extends EventEmitter { async loadChunk (pos: ChunkPos, isLightUpdate = false) { const [botX, botZ] = chunkPos(this.lastPos) - const dx = Math.abs(botX - Math.floor(pos.x / 16)) - const dz = Math.abs(botZ - Math.floor(pos.z / 16)) + const chunkX = Math.floor(pos.x / 16) + const chunkZ = Math.floor(pos.z / 16) + const dx = Math.abs(botX - chunkX) + const dz = Math.abs(botZ - chunkZ) if (dx <= this.viewDistance && dz <= this.viewDistance) { // eslint-disable-next-line @typescript-eslint/await-thenable -- todo allow to use async world provider but not sure if needed const column = await this.world.getColumnAt(pos['y'] ? pos as Vec3 : new Vec3(pos.x, 0, pos.z)) if (column) { + const result = await processLightChunk(pos.x, pos.z) + if (!result) return + for (const affectedChunk of result) { + if (affectedChunk.x === chunkX && affectedChunk.z === chunkZ) continue + const loadedChunk = this.loadedChunks[`${affectedChunk.x},${affectedChunk.z}`] + if (!loadedChunk) continue + void this.loadChunk(new Vec3(affectedChunk.x * 16, 0, affectedChunk.z * 16), true) + } // const latency = Math.floor(performance.now() - this.lastTime) // this.debugGotChunkLatency.push(latency) // this.lastTime = performance.now() From d5c61d83205f4c87e5009c92a098ecc22bad801c Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 20 Feb 2025 00:30:36 +0300 Subject: [PATCH 02/22] a working light --- renderer/viewer/lib/lightEngine.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/renderer/viewer/lib/lightEngine.ts b/renderer/viewer/lib/lightEngine.ts index 25d0bbd01..bf2f82b45 100644 --- a/renderer/viewer/lib/lightEngine.ts +++ b/renderer/viewer/lib/lightEngine.ts @@ -1,8 +1,7 @@ -import { createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock } from 'minecraft-lighting/src/prismarineShim' +import { createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock, fillColumnWithZeroLight } from 'minecraft-lighting/src/prismarineShim' import { LightWorld } from 'minecraft-lighting/src/engine' import { world } from 'prismarine-world' import { Chunk } from 'prismarine-world/types/world' -import { fillColumnWithZeroLight } from 'minecraft-lighting/src/testDebug' let lightEngine: LightWorld | null = null export const getLightEngine = () => { @@ -23,7 +22,7 @@ export const processLightChunk = async (x: number, z: number) => { const chunkX = Math.floor(x / 16) const chunkZ = Math.floor(z / 16) const engine = getLightEngine() - fillColumnWithZeroLight(engine.externalWorld, chunkX, chunkZ) + fillColumnWithZeroLight(worldView!.world as world.WorldSync, viewer.world.worldConfig.minY, viewer.world.worldConfig.worldHeight, chunkX, chunkZ) return engine.receiveUpdateColumn(chunkX, chunkZ) } From 48ead547e3134bd51571b78db0be822281da53f6 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 12 Mar 2025 18:23:37 +0300 Subject: [PATCH 03/22] should work. --- package.json | 2 +- pnpm-lock.yaml | 24 ++++++++++++++++++++---- renderer/viewer/lib/lightEngine.ts | 8 +++----- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 0afa4bcfd..40d16f76c 100644 --- a/package.json +++ b/package.json @@ -163,7 +163,7 @@ "typescript": "5.5.4", "vitest": "^0.34.6", "yaml": "^2.3.2", - "minecraft-lighting": "file:../minecraft-lighting" + "minecraft-lighting": "^0.0.3" }, "optionalDependencies": { "cypress": "^10.11.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7540c5bb5..4ab1d8fc0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -354,6 +354,9 @@ importers: minecraft-inventory-gui: specifier: github:zardoy/minecraft-inventory-gui#next version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/75e940a4cd50d89e0ba03db3733d5d704917a3c8(@types/react@18.2.20)(react@18.2.0) + minecraft-lighting: + specifier: ^0.0.3 + version: 0.0.3 mineflayer: specifier: github:zardoy/mineflayer version: https://codeload.github.com/zardoy/mineflayer/tar.gz/4fa1af9964cab91315d8d1ae02615f3039638828(encoding@0.1.13) @@ -6457,6 +6460,10 @@ packages: resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/75e940a4cd50d89e0ba03db3733d5d704917a3c8} version: 1.0.1 + minecraft-lighting@0.0.3: + resolution: {integrity: sha512-JDxWOy/9mogn4AjJi8sPvY1BoHSLcTSZ9QntCNTtEtQlXMNRe5Wr+4z+apgOKLXDFaisZr+jPQRY8RyjV7lJyw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/e9eb551ba30ec2e742c49e6927be6402b413bb76: resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/e9eb551ba30ec2e742c49e6927be6402b413bb76} version: 1.54.0 @@ -8883,6 +8890,9 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + vec3@0.1.10: + resolution: {integrity: sha512-Sr1U3mYtMqCOonGd3LAN9iqy0qF6C+Gjil92awyK/i2OwiUo9bm7PnLgFpafymun50mOjnDcg4ToTgRssrlTcw==} + vec3@0.1.8: resolution: {integrity: sha512-LfKrP625Bsg/Tj52YdYPsHmpsJuo+tc6fLxZxXjEo9k2xSspKlPvoYTHehykKhp1FvV9nm+XU3Ehej5/9tpDCg==} @@ -14263,7 +14273,7 @@ snapshots: prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) prismarine-registry: 1.11.0 random-seed: 0.3.0 - vec3: 0.1.8 + vec3: 0.1.10 diff-match-patch@1.0.5: {} @@ -16996,6 +17006,10 @@ snapshots: - '@types/react' - react + minecraft-lighting@0.0.3: + dependencies: + vec3: 0.1.10 + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/e9eb551ba30ec2e742c49e6927be6402b413bb76(patch_hash=dkeyukcqlupmk563gwxsmjr3yu)(encoding@0.1.13): dependencies: '@types/node-rsa': 1.1.4 @@ -17902,7 +17916,7 @@ snapshots: prismarine-chat: 1.10.1 prismarine-item: 1.16.0 prismarine-registry: 1.11.0 - vec3: 0.1.8 + vec3: 0.1.10 prismarine-item@1.16.0: dependencies: @@ -17917,7 +17931,7 @@ snapshots: dependencies: minecraft-data: 3.83.1 prismarine-nbt: 2.5.0 - vec3: 0.1.8 + vec3: 0.1.10 prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.83.1): dependencies: @@ -17964,7 +17978,7 @@ snapshots: prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c: dependencies: - vec3: 0.1.8 + vec3: 0.1.10 process-nextick-args@2.0.1: {} @@ -19968,6 +19982,8 @@ snapshots: vary@1.1.2: {} + vec3@0.1.10: {} + vec3@0.1.8: {} verror@1.10.0: diff --git a/renderer/viewer/lib/lightEngine.ts b/renderer/viewer/lib/lightEngine.ts index bf2f82b45..578ccf9b5 100644 --- a/renderer/viewer/lib/lightEngine.ts +++ b/renderer/viewer/lib/lightEngine.ts @@ -1,7 +1,5 @@ -import { createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock, fillColumnWithZeroLight } from 'minecraft-lighting/src/prismarineShim' -import { LightWorld } from 'minecraft-lighting/src/engine' +import { LightWorld, createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock, fillColumnWithZeroLight } from 'minecraft-lighting' import { world } from 'prismarine-world' -import { Chunk } from 'prismarine-world/types/world' let lightEngine: LightWorld | null = null export const getLightEngine = () => { @@ -10,7 +8,7 @@ export const getLightEngine = () => { } export const createLightEngine = () => { - lightEngine = createLightEngineForSyncWorld(worldView!.world as world.WorldSync, loadedData, { + lightEngine = createLightEngineForSyncWorld(worldView!.world as unknown as world.WorldSync, loadedData, { minY: viewer.world.worldConfig.minY, height: viewer.world.worldConfig.worldHeight, enableSkyLight: false, @@ -22,7 +20,7 @@ export const processLightChunk = async (x: number, z: number) => { const chunkX = Math.floor(x / 16) const chunkZ = Math.floor(z / 16) const engine = getLightEngine() - fillColumnWithZeroLight(worldView!.world as world.WorldSync, viewer.world.worldConfig.minY, viewer.world.worldConfig.worldHeight, chunkX, chunkZ) + fillColumnWithZeroLight(engine.externalWorld, chunkX, chunkZ) return engine.receiveUpdateColumn(chunkX, chunkZ) } From ace45a9f87a1e5497cdf3d3c14469e388e6c9327 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 14 Mar 2025 00:03:33 +0300 Subject: [PATCH 04/22] not crash pls --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- renderer/viewer/lib/mesher/world.ts | 4 ++-- src/optionsStorage.ts | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 55dbb43f7..fbc8ff693 100644 --- a/package.json +++ b/package.json @@ -169,7 +169,7 @@ "typescript": "5.5.4", "vitest": "^0.34.6", "yaml": "^2.3.2", - "minecraft-lighting": "^0.0.3" + "minecraft-lighting": "^0.0.4" }, "optionalDependencies": { "cypress": "^10.11.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0683e7a4a..71a81bc84 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -359,8 +359,8 @@ importers: specifier: github:zardoy/minecraft-inventory-gui#next version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/75e940a4cd50d89e0ba03db3733d5d704917a3c8(@types/react@18.2.20)(react@18.2.0) minecraft-lighting: - specifier: ^0.0.3 - version: 0.0.3 + specifier: ^0.0.4 + version: 0.0.4 mineflayer: specifier: github:zardoy/mineflayer version: https://codeload.github.com/zardoy/mineflayer/tar.gz/748163e536abe94f3dc8ada7a542bcd689bbbf49(encoding@0.1.13) @@ -6903,8 +6903,8 @@ packages: resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/75e940a4cd50d89e0ba03db3733d5d704917a3c8} version: 1.0.1 - minecraft-lighting@0.0.3: - resolution: {integrity: sha512-JDxWOy/9mogn4AjJi8sPvY1BoHSLcTSZ9QntCNTtEtQlXMNRe5Wr+4z+apgOKLXDFaisZr+jPQRY8RyjV7lJyw==} + minecraft-lighting@0.0.4: + resolution: {integrity: sha512-5p+Dx1SIdQhkKA8Wbm7slN0MR6s7pdnlV2MVSBSmAlR4zW8+FVpsNJfvMQ4XltRqKYyHybNDZEdJocdtdkfhpQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/5ec3dd4b367fcc039fbcb3edd214fe3cf8178a6d: @@ -17899,7 +17899,7 @@ snapshots: - '@types/react' - react - minecraft-lighting@0.0.3: + minecraft-lighting@0.0.4: dependencies: vec3: 0.1.10 diff --git a/renderer/viewer/lib/mesher/world.ts b/renderer/viewer/lib/mesher/world.ts index f2757ae62..69e0363b2 100644 --- a/renderer/viewer/lib/mesher/world.ts +++ b/renderer/viewer/lib/mesher/world.ts @@ -63,8 +63,8 @@ export class World { 15, Math.max( column.getBlockLight(posInChunk(pos)), - Math.min(skyLight, column.getSkyLight(posInChunk(pos))) - ) + 2 + // Math.min(skyLight, column.getSkyLight(posInChunk(pos))) + ) ) // lightsCache.set(key, result) if (result === 2 && [this.getBlock(pos)?.name ?? '', curBlockName].some(x => /_stairs|slab|glass_pane/.exec(x)) && !skipMoreChecks) { // todo this is obviously wrong diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index 1c5c999e3..7fe5219af 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -88,7 +88,7 @@ const defaultOptions = { showCursorBlockInSpectator: false, renderEntities: true, smoothLighting: true, - newVersionsLighting: false, + newVersionsLighting: true, chatSelect: true, autoJump: 'auto' as 'auto' | 'always' | 'never', autoParkour: false, From 9f505f81d6dd640754fa7a31f9c7418ac87eba14 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 21 Mar 2025 16:36:29 +0300 Subject: [PATCH 05/22] rm workaround --- renderer/viewer/lib/mesher/world.ts | 33 +++++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/renderer/viewer/lib/mesher/world.ts b/renderer/viewer/lib/mesher/world.ts index 69e0363b2..92fa7d860 100644 --- a/renderer/viewer/lib/mesher/world.ts +++ b/renderer/viewer/lib/mesher/world.ts @@ -51,6 +51,7 @@ export class World { } getLight (pos: Vec3, isNeighbor = false, skipMoreChecks = false, curBlockName = '') { + const IS_USING_SERVER_LIGHTING = false // for easier testing if (!(pos instanceof Vec3)) pos = new Vec3(...pos as [number, number, number]) const { enableLighting, skyLight } = this.config @@ -63,25 +64,29 @@ export class World { 15, Math.max( column.getBlockLight(posInChunk(pos)), - // Math.min(skyLight, column.getSkyLight(posInChunk(pos))) + Math.min(skyLight, column.getSkyLight(posInChunk(pos))) ) ) + const MIN_LIGHT_LEVEL = 2 + result = Math.max(result, MIN_LIGHT_LEVEL) // lightsCache.set(key, result) - if (result === 2 && [this.getBlock(pos)?.name ?? '', curBlockName].some(x => /_stairs|slab|glass_pane/.exec(x)) && !skipMoreChecks) { // todo this is obviously wrong - const lights = [ - this.getLight(pos.offset(0, 1, 0), undefined, true), - this.getLight(pos.offset(0, -1, 0), undefined, true), - this.getLight(pos.offset(0, 0, 1), undefined, true), - this.getLight(pos.offset(0, 0, -1), undefined, true), - this.getLight(pos.offset(1, 0, 0), undefined, true), - this.getLight(pos.offset(-1, 0, 0), undefined, true) - ].filter(x => x !== 2) - if (lights.length) { - const min = Math.min(...lights) - result = min + if (result === 2 && IS_USING_SERVER_LIGHTING) { + if ([this.getBlock(pos)?.name ?? '', curBlockName].some(x => /_stairs|slab|glass_pane/.exec(x)) && !skipMoreChecks) { // todo this is obviously wrong + const lights = [ + this.getLight(pos.offset(0, 1, 0), undefined, true), + this.getLight(pos.offset(0, -1, 0), undefined, true), + this.getLight(pos.offset(0, 0, 1), undefined, true), + this.getLight(pos.offset(0, 0, -1), undefined, true), + this.getLight(pos.offset(1, 0, 0), undefined, true), + this.getLight(pos.offset(-1, 0, 0), undefined, true) + ].filter(x => x !== 2) + if (lights.length) { + const min = Math.min(...lights) + result = min + } } + if (isNeighbor) result = 15 // TODO } - if (isNeighbor && result === 2) result = 15 // TODO return result } From e10f6108989014ad7524520d20d313139564ac3a Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 10 Apr 2025 05:24:53 +0300 Subject: [PATCH 06/22] humble and terrible progress --- package.json | 2 +- pnpm-lock.yaml | 31 +++++++++++----------- renderer/viewer/lib/lightEngine.ts | 17 +++++++----- renderer/viewer/lib/mesher/mesher.ts | 3 +++ renderer/viewer/lib/mesher/world.ts | 16 +++++++++-- renderer/viewer/lib/worldDataEmitter.ts | 4 +-- renderer/viewer/lib/worldrendererCommon.ts | 6 ++++- 7 files changed, 51 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index cd1c877b2..dc1b47755 100644 --- a/package.json +++ b/package.json @@ -170,7 +170,7 @@ "typescript": "5.5.4", "vitest": "^0.34.6", "yaml": "^2.3.2", - "minecraft-lighting": "^0.0.4" + "minecraft-lighting": "file:../minecraft-lighting" }, "optionalDependencies": { "cypress": "^10.11.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b906647a3..e36135e29 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -359,8 +359,8 @@ importers: specifier: github:zardoy/minecraft-inventory-gui#next version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/f57dd78ca8e3b7cdd724d4272d8cbf6743b0cf00(@types/react@18.2.20)(react@18.2.0) minecraft-lighting: - specifier: ^0.0.4 - version: 0.0.4 + specifier: file:../minecraft-lighting + version: file:../minecraft-lighting mineflayer: specifier: github:zardoy/mineflayer version: https://codeload.github.com/zardoy/mineflayer/tar.gz/06e3050ddf4d9aa655fea6e2bed182937a81705d(encoding@0.1.13) @@ -441,7 +441,7 @@ importers: version: 1.3.6 prismarine-block: specifier: github:zardoy/prismarine-block#next-era - version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9(prismarine-registry@1.11.0) prismarine-chunk: specifier: github:zardoy/prismarine-chunk#master version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) @@ -6919,9 +6919,8 @@ packages: resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/f57dd78ca8e3b7cdd724d4272d8cbf6743b0cf00} version: 1.0.1 - minecraft-lighting@0.0.4: - resolution: {integrity: sha512-5p+Dx1SIdQhkKA8Wbm7slN0MR6s7pdnlV2MVSBSmAlR4zW8+FVpsNJfvMQ4XltRqKYyHybNDZEdJocdtdkfhpQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + minecraft-lighting@file:../minecraft-lighting: + resolution: {directory: ../minecraft-lighting, type: directory} minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/3bd4dc1b2002cd7badfa5b9cf8dda35cd6cc9ac1: resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/3bd4dc1b2002cd7badfa5b9cf8dda35cd6cc9ac1} @@ -17941,7 +17940,7 @@ snapshots: - '@types/react' - react - minecraft-lighting@0.0.4: + minecraft-lighting@file:../minecraft-lighting: dependencies: vec3: 0.1.10 @@ -18084,7 +18083,7 @@ snapshots: mineflayer-pathfinder@2.4.4: dependencies: minecraft-data: 3.83.1 - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9(prismarine-registry@1.11.0) prismarine-entity: 2.3.1 prismarine-item: 1.16.0 prismarine-nbt: 2.5.0 @@ -18096,7 +18095,7 @@ snapshots: minecraft-data: 3.83.1 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/5ec3dd4b367fcc039fbcb3edd214fe3cf8178a6d(patch_hash=dkeyukcqlupmk563gwxsmjr3yu)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9(prismarine-registry@1.11.0) prismarine-chat: 1.10.1 prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) prismarine-entity: 2.3.1 @@ -18119,7 +18118,7 @@ snapshots: minecraft-data: 3.83.1 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/5ec3dd4b367fcc039fbcb3edd214fe3cf8178a6d(patch_hash=dkeyukcqlupmk563gwxsmjr3yu)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9(prismarine-registry@1.11.0) prismarine-chat: 1.10.1 prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) prismarine-entity: 2.3.1 @@ -18908,7 +18907,7 @@ snapshots: minecraft-data: 3.83.1 prismarine-registry: 1.11.0 - prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9: + prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9(prismarine-registry@1.11.0): dependencies: minecraft-data: 3.83.1 prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) @@ -18916,6 +18915,8 @@ snapshots: prismarine-item: 1.16.0 prismarine-nbt: 2.5.0 prismarine-registry: 1.11.0 + transitivePeerDependencies: + - prismarine-registry prismarine-chat@1.10.1: dependencies: @@ -18926,7 +18927,7 @@ snapshots: prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9(prismarine-registry@1.11.0) prismarine-nbt: 2.5.0 prismarine-registry: 1.11.0 smart-buffer: 4.2.0 @@ -18964,7 +18965,7 @@ snapshots: prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.83.1): dependencies: - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9(prismarine-registry@1.11.0) prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) prismarine-nbt: 2.5.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c @@ -18988,13 +18989,13 @@ snapshots: prismarine-registry@1.11.0: dependencies: minecraft-data: 3.83.1 - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9(prismarine-registry@1.11.0) prismarine-nbt: 2.7.0 prismarine-schematic@1.2.3: dependencies: minecraft-data: 3.83.1 - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9(prismarine-registry@1.11.0) prismarine-nbt: 2.5.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c vec3: 0.1.10 diff --git a/renderer/viewer/lib/lightEngine.ts b/renderer/viewer/lib/lightEngine.ts index 578ccf9b5..88e2be33c 100644 --- a/renderer/viewer/lib/lightEngine.ts +++ b/renderer/viewer/lib/lightEngine.ts @@ -1,18 +1,23 @@ import { LightWorld, createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock, fillColumnWithZeroLight } from 'minecraft-lighting' import { world } from 'prismarine-world' +import { WorldRendererCommon } from './worldrendererCommon' let lightEngine: LightWorld | null = null export const getLightEngine = () => { if (!lightEngine) throw new Error('Light engine not initialized') return lightEngine } +export const getLightEngineSafe = () => { + return lightEngine +} -export const createLightEngine = () => { - lightEngine = createLightEngineForSyncWorld(worldView!.world as unknown as world.WorldSync, loadedData, { - minY: viewer.world.worldConfig.minY, - height: viewer.world.worldConfig.worldHeight, +export const createLightEngine = (world: WorldRendererCommon) => { + lightEngine = createLightEngineForSyncWorld(world.displayOptions.worldView.world as unknown as world.WorldSync, loadedData, { + minY: world.worldSizeParams.minY, + height: world.worldSizeParams.worldHeight, enableSkyLight: false, }) + lightEngine.PARALLEL_CHUNK_PROCESSING = false globalThis.lightEngine = lightEngine } @@ -20,11 +25,11 @@ export const processLightChunk = async (x: number, z: number) => { const chunkX = Math.floor(x / 16) const chunkZ = Math.floor(z / 16) const engine = getLightEngine() - fillColumnWithZeroLight(engine.externalWorld, chunkX, chunkZ) + // fillColumnWithZeroLight(engine.externalWorld, chunkX, chunkZ) return engine.receiveUpdateColumn(chunkX, chunkZ) } export const updateBlockLight = (x: number, y: number, z: number, stateId: number) => { const engine = getLightEngine() - engine.setBlock(x, y, z, convertPrismarineBlockToWorldBlock(mcData.blocks[stateId], mcData)) + engine.setBlock(x, y, z, convertPrismarineBlockToWorldBlock(mcData.blocks[stateId], loadedData)) } diff --git a/renderer/viewer/lib/mesher/mesher.ts b/renderer/viewer/lib/mesher/mesher.ts index 21e2d8efd..3f06d60d4 100644 --- a/renderer/viewer/lib/mesher/mesher.ts +++ b/renderer/viewer/lib/mesher/mesher.ts @@ -107,6 +107,9 @@ const handleMessage = data => { } case 'chunk': { world.addColumn(data.x, data.z, data.chunk) + if (data.lightData) { + world.lightHolder.loadChunk(data.lightData) + } if (data.customBlockModels) { const chunkKey = `${data.x},${data.z}` world.customBlockModels.set(chunkKey, data.customBlockModels) diff --git a/renderer/viewer/lib/mesher/world.ts b/renderer/viewer/lib/mesher/world.ts index 92fa7d860..69eb7c1df 100644 --- a/renderer/viewer/lib/mesher/world.ts +++ b/renderer/viewer/lib/mesher/world.ts @@ -1,3 +1,4 @@ +import { WorldLightHolder } from 'minecraft-lighting/dist/worldLightHolder' import Chunks from 'prismarine-chunk' import mcData from 'minecraft-data' import { Block } from 'prismarine-block' @@ -32,6 +33,7 @@ export type WorldBlock = Omit & { } export class World { + lightHolder = new WorldLightHolder(0, 0) config = defaultMesherConfig Chunk: typeof import('prismarine-chunk/types/index').PCChunk columns = {} as { [key: string]: import('prismarine-chunk/types/index').PCChunk } @@ -63,8 +65,8 @@ export class World { let result = Math.min( 15, Math.max( - column.getBlockLight(posInChunk(pos)), - Math.min(skyLight, column.getSkyLight(posInChunk(pos))) + this.getBlockLight(pos), + Math.min(skyLight, this.getSkyLight(pos)) ) ) const MIN_LIGHT_LEVEL = 2 @@ -90,6 +92,16 @@ export class World { return result } + getBlockLight (pos: Vec3) { + return this.lightHolder.getBlockLight(pos.x, pos.y, pos.z) + // return column.getBlockLight(posInChunk(pos)) + } + + getSkyLight (pos: Vec3) { + return this.lightHolder.getSkyLight(pos.x, pos.y, pos.z) + // return column.getSkyLight(posInChunk(pos)) + } + addColumn (x, z, json) { const chunk = this.Chunk.fromJson(json) this.columns[columnKey(x, z)] = chunk as any diff --git a/renderer/viewer/lib/worldDataEmitter.ts b/renderer/viewer/lib/worldDataEmitter.ts index 42f1e51e2..a92599ee4 100644 --- a/renderer/viewer/lib/worldDataEmitter.ts +++ b/renderer/viewer/lib/worldDataEmitter.ts @@ -8,9 +8,8 @@ import { BotEvents } from 'mineflayer' import { proxy } from 'valtio' import TypedEmitter from 'typed-emitter' import { delayedIterator } from '../../playground/shared' -import { playerState } from '../../../src/mineflayer/playerState' import { chunkPos } from './simpleUtils' -import { createLightEngine, processLightChunk, updateBlockLight } from './lightEngine' +import { processLightChunk, updateBlockLight } from './lightEngine' export type ChunkPosKey = string type ChunkPos = { x: number, z: number } @@ -178,7 +177,6 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter } constructor (public readonly resourcesManager: ResourcesManager, public displayOptions: DisplayWorldOptions, public initOptions: GraphicsInitOptions) { + createLightEngine(this) + // this.initWorkers(1) // preload script on page load this.snapshotInitialValues() this.worldRendererConfig = displayOptions.inWorldRenderingConfig @@ -577,7 +580,8 @@ export abstract class WorldRendererCommon x, z, chunk, - customBlockModels: customBlockModels || undefined + customBlockModels: customBlockModels || undefined, + lightData: getLightEngineSafe()?.worldLightHolder.dumpChunk(x, z) }) } this.logWorkerWork(`-> chunk ${JSON.stringify({ x, z, chunkLength: chunk.length, customBlockModelsLength: customBlockModels ? Object.keys(customBlockModels).length : 0 })}`) From 1918c68efbc32a280d219b9095bcbda3cbf77617 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 25 Apr 2025 04:49:31 +0300 Subject: [PATCH 07/22] finish lighting --- package.json | 2 +- pnpm-lock.yaml | 11 ++++++----- renderer/viewer/lib/lightEngine.ts | 13 ++++++++++--- renderer/viewer/lib/mesher/mesher.ts | 2 ++ renderer/viewer/lib/mesher/world.ts | 13 ++++++++----- renderer/viewer/lib/worldrendererCommon.ts | 5 +++-- renderer/viewer/three/worldrendererThree.ts | 6 ++++-- src/optionsStorage.ts | 3 ++- src/watchOptions.ts | 12 ++++++++---- 9 files changed, 44 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index 58de81510..a43df849a 100644 --- a/package.json +++ b/package.json @@ -170,7 +170,7 @@ "typescript": "5.5.4", "vitest": "^0.34.6", "yaml": "^2.3.2", - "minecraft-lighting": "file:../minecraft-lighting" + "minecraft-lighting": "^0.0.8" }, "optionalDependencies": { "cypress": "^10.11.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db0810145..f04d19e92 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -343,8 +343,8 @@ importers: specifier: github:zardoy/minecraft-inventory-gui#next version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/98bc5bb8ee6da8b4b771c05b404cee796318ccd4(@types/react@18.3.18)(react@18.3.1) minecraft-lighting: - specifier: file:../minecraft-lighting - version: file:../minecraft-lighting + specifier: ^0.0.8 + version: 0.0.8 mineflayer: specifier: github:GenerelSchwerz/mineflayer version: https://codeload.github.com/GenerelSchwerz/mineflayer/tar.gz/d459d2ed76a997af1a7c94718ed7d5dee4478b8a(encoding@0.1.13) @@ -6680,8 +6680,9 @@ packages: resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/98bc5bb8ee6da8b4b771c05b404cee796318ccd4} version: 1.0.1 - minecraft-lighting@file:../minecraft-lighting: - resolution: {directory: ../minecraft-lighting, type: directory} + minecraft-lighting@0.0.8: + resolution: {integrity: sha512-HEew4qycmHv2r5+FR4vZ81YJkOR9Q8jbpj6nO9nEoiKRFvo9HamcbA6uQmSxJZKkkgt1uOp/EQ61rQXFw3nnGQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/9e116c3dd4682b17c4e2c80249a2447a093d9284: resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/9e116c3dd4682b17c4e2c80249a2447a093d9284} @@ -17322,7 +17323,7 @@ snapshots: - '@types/react' - react - minecraft-lighting@file:../minecraft-lighting: + minecraft-lighting@0.0.8: dependencies: vec3: 0.1.10 diff --git a/renderer/viewer/lib/lightEngine.ts b/renderer/viewer/lib/lightEngine.ts index 88e2be33c..c5cecfa04 100644 --- a/renderer/viewer/lib/lightEngine.ts +++ b/renderer/viewer/lib/lightEngine.ts @@ -1,4 +1,4 @@ -import { LightWorld, createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock, fillColumnWithZeroLight } from 'minecraft-lighting' +import { LightWorld, createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock } from 'minecraft-lighting' import { world } from 'prismarine-world' import { WorldRendererCommon } from './worldrendererCommon' @@ -15,7 +15,7 @@ export const createLightEngine = (world: WorldRendererCommon) => { lightEngine = createLightEngineForSyncWorld(world.displayOptions.worldView.world as unknown as world.WorldSync, loadedData, { minY: world.worldSizeParams.minY, height: world.worldSizeParams.worldHeight, - enableSkyLight: false, + // enableSkyLight: false, }) lightEngine.PARALLEL_CHUNK_PROCESSING = false globalThis.lightEngine = lightEngine @@ -26,7 +26,14 @@ export const processLightChunk = async (x: number, z: number) => { const chunkZ = Math.floor(z / 16) const engine = getLightEngine() // fillColumnWithZeroLight(engine.externalWorld, chunkX, chunkZ) - return engine.receiveUpdateColumn(chunkX, chunkZ) + + const updated = engine.receiveUpdateColumn(chunkX, chunkZ) + return updated +} + +export const dumpLightData = (x: number, z: number) => { + const engine = getLightEngineSafe() + return engine?.worldLightHolder.dumpChunk(Math.floor(x / 16), Math.floor(z / 16)) } export const updateBlockLight = (x: number, y: number, z: number, stateId: number) => { diff --git a/renderer/viewer/lib/mesher/mesher.ts b/renderer/viewer/lib/mesher/mesher.ts index 3f06d60d4..4f1885b10 100644 --- a/renderer/viewer/lib/mesher/mesher.ts +++ b/renderer/viewer/lib/mesher/mesher.ts @@ -109,6 +109,8 @@ const handleMessage = data => { world.addColumn(data.x, data.z, data.chunk) if (data.lightData) { world.lightHolder.loadChunk(data.lightData) + } else { + console.warn('no light data', data.x, data.z) } if (data.customBlockModels) { const chunkKey = `${data.x},${data.z}` diff --git a/renderer/viewer/lib/mesher/world.ts b/renderer/viewer/lib/mesher/world.ts index 69eb7c1df..cd8ad3355 100644 --- a/renderer/viewer/lib/mesher/world.ts +++ b/renderer/viewer/lib/mesher/world.ts @@ -62,11 +62,14 @@ export class World { // if (lightsCache.has(key)) return lightsCache.get(key) const column = this.getColumnByPos(pos) if (!column || !hasChunkSection(column, pos)) return 15 - let result = Math.min( - 15, - Math.max( - this.getBlockLight(pos), - Math.min(skyLight, this.getSkyLight(pos)) + let result = Math.max( + 3, + Math.min( + 15, + Math.max( + this.getBlockLight(pos), + Math.min(skyLight, this.getSkyLight(pos)) + ) ) ) const MIN_LIGHT_LEVEL = 2 diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts index aa85aa938..416ede1ff 100644 --- a/renderer/viewer/lib/worldrendererCommon.ts +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -19,7 +19,7 @@ import { chunkPos } from './simpleUtils' import { addNewStat, removeAllStats, removeStat, updatePanesVisibility, updateStatText } from './ui/newStats' import { WorldDataEmitter } from './worldDataEmitter' import { IPlayerState } from './basePlayerState' -import { createLightEngine, getLightEngine, getLightEngineSafe } from './lightEngine' +import { createLightEngine, dumpLightData, getLightEngine, getLightEngineSafe } from './lightEngine' import { MesherLogReader } from './mesherlogReader' function mod (x, n) { @@ -40,6 +40,7 @@ export const defaultWorldRendererConfig = { clipWorldBelowY: undefined as number | undefined, smoothLighting: true, enableLighting: true, + clientSideLighting: false, starfield: true, addChunksBatchWaitTime: 200, vrSupport: true, @@ -614,7 +615,7 @@ export abstract class WorldRendererCommon z, chunk, customBlockModels: customBlockModels || undefined, - lightData: getLightEngineSafe()?.worldLightHolder.dumpChunk(x, z) + lightData: dumpLightData(x, z) }) } this.logWorkerWork(() => `-> chunk ${JSON.stringify({ x, z, chunkLength: chunk.length, customBlockModelsLength: customBlockModels ? Object.keys(customBlockModels).length : 0 })}`) diff --git a/renderer/viewer/three/worldrendererThree.ts b/renderer/viewer/three/worldrendererThree.ts index 142703673..acd44e8b3 100644 --- a/renderer/viewer/three/worldrendererThree.ts +++ b/renderer/viewer/three/worldrendererThree.ts @@ -151,11 +151,13 @@ export class WorldRendererThree extends WorldRendererCommon { }) this.onReactiveValueUpdated('ambientLight', (value) => { if (!value) return - this.ambientLight.intensity = value + // this.ambientLight.intensity = value + this.ambientLight.intensity = 1 }) this.onReactiveValueUpdated('directionalLight', (value) => { if (!value) return - this.directionalLight.intensity = value + // this.directionalLight.intensity = value + this.directionalLight.intensity = 1 }) this.onReactiveValueUpdated('lookingAtBlock', (value) => { this.cursorBlock.setHighlightCursorBlock(value ? new Vec3(value.x, value.y, value.z) : null, value?.shapes) diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index ecfcac9e8..27eb520d9 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -97,7 +97,8 @@ const defaultOptions = { showCursorBlockInSpectator: false, renderEntities: true, smoothLighting: true, - newVersionsLighting: true, + // lightingStrategy: 'prefer-server' as 'only-server' | 'always-client' | 'prefer-server', + lightingStrategy: 'prefer-server' as 'always-client' | 'prefer-server', chatSelect: true, autoJump: 'auto' as 'auto' | 'always' | 'never', autoParkour: false, diff --git a/src/watchOptions.ts b/src/watchOptions.ts index 9fe55289e..d50b3fcb7 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -94,12 +94,16 @@ export const watchOptionsAfterViewerInit = () => { appViewer.inWorldRenderingConfig.smoothLighting = options.smoothLighting }) - subscribeKey(options, 'newVersionsLighting', () => { - appViewer.inWorldRenderingConfig.enableLighting = !bot.supportFeature('blockStateId') || options.newVersionsLighting - }) + const updateLightingStrategy = () => { + const clientSideLighting = options.lightingStrategy === 'always-client' || (options.lightingStrategy === 'prefer-server' && bot.supportFeature('blockStateId')) + appViewer.inWorldRenderingConfig.clientSideLighting = clientSideLighting + appViewer.inWorldRenderingConfig.enableLighting = options.dayCycleAndLighting && (!bot.supportFeature('blockStateId') || clientSideLighting) + } + + subscribeKey(options, 'lightingStrategy', updateLightingStrategy) customEvents.on('mineflayerBotCreated', () => { - appViewer.inWorldRenderingConfig.enableLighting = !bot.supportFeature('blockStateId') || options.newVersionsLighting + updateLightingStrategy() }) watchValue(options, o => { From b4c72dbb36a57bab3a005d4050feb30aa1894fb9 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 25 Apr 2025 05:24:06 +0300 Subject: [PATCH 08/22] fix crash opt --- src/watchOptions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/watchOptions.ts b/src/watchOptions.ts index d50b3fcb7..d0ff609fd 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -95,6 +95,7 @@ export const watchOptionsAfterViewerInit = () => { }) const updateLightingStrategy = () => { + if (!bot) return const clientSideLighting = options.lightingStrategy === 'always-client' || (options.lightingStrategy === 'prefer-server' && bot.supportFeature('blockStateId')) appViewer.inWorldRenderingConfig.clientSideLighting = clientSideLighting appViewer.inWorldRenderingConfig.enableLighting = options.dayCycleAndLighting && (!bot.supportFeature('blockStateId') || clientSideLighting) From 1f5b682bee3d743373a293d750996d5980c3029b Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 28 Apr 2025 09:46:59 +0300 Subject: [PATCH 09/22] FINISH OPTIONS, FINISH RECOMPUTE, ADD LIGHT TO WATER --- renderer/viewer/lib/lightEngine.ts | 21 +++++++++++- renderer/viewer/lib/mesher/models.ts | 38 +++++++++++++++++++-- renderer/viewer/lib/mesher/shared.ts | 3 ++ renderer/viewer/lib/mesher/world.ts | 18 ++++++++-- renderer/viewer/lib/worldDataEmitter.ts | 16 ++++++--- renderer/viewer/lib/worldrendererCommon.ts | 3 +- renderer/viewer/three/worldrendererThree.ts | 2 +- src/dayCycle.ts | 8 ++--- src/optionsGuiScheme.tsx | 11 +++--- src/optionsStorage.ts | 2 +- src/react/DebugOverlay.tsx | 7 ++-- src/watchOptions.ts | 9 +++-- 12 files changed, 111 insertions(+), 27 deletions(-) diff --git a/renderer/viewer/lib/lightEngine.ts b/renderer/viewer/lib/lightEngine.ts index c5cecfa04..8b83ab981 100644 --- a/renderer/viewer/lib/lightEngine.ts +++ b/renderer/viewer/lib/lightEngine.ts @@ -17,6 +17,7 @@ export const createLightEngine = (world: WorldRendererCommon) => { height: world.worldSizeParams.worldHeight, // enableSkyLight: false, }) + lightEngine.externalWorld.setBlock = () => {} lightEngine.PARALLEL_CHUNK_PROCESSING = false globalThis.lightEngine = lightEngine } @@ -36,7 +37,25 @@ export const dumpLightData = (x: number, z: number) => { return engine?.worldLightHolder.dumpChunk(Math.floor(x / 16), Math.floor(z / 16)) } +export const getDebugLightValues = (x: number, y: number, z: number) => { + const engine = getLightEngineSafe() + return { + blockLight: engine?.worldLightHolder.getBlockLight(x, y, z) ?? -1, + skyLight: engine?.worldLightHolder.getSkyLight(x, y, z) ?? -1, + } +} + export const updateBlockLight = (x: number, y: number, z: number, stateId: number) => { const engine = getLightEngine() - engine.setBlock(x, y, z, convertPrismarineBlockToWorldBlock(mcData.blocks[stateId], loadedData)) + const affected = engine['affectedChunksTimestamps'] as Map + const noAffected = affected.size === 0 + engine.setBlock(x, y, z, convertPrismarineBlockToWorldBlock(stateId, loadedData)) + + if (affected.size > 0) { + const chunks = [...affected.keys()].map(key => { + return key.split(',').map(Number) as [number, number] + }) + affected.clear() + return chunks + } } diff --git a/renderer/viewer/lib/mesher/models.ts b/renderer/viewer/lib/mesher/models.ts index fc57d2b32..32b805d1a 100644 --- a/renderer/viewer/lib/mesher/models.ts +++ b/renderer/viewer/lib/mesher/models.ts @@ -125,6 +125,13 @@ const isCube = (block: Block) => { })) } +const getVec = (v: Vec3, dir: Vec3) => { + for (const coord of ['x', 'y', 'z']) { + if (Math.abs(dir[coord]) > 0) v[coord] = 0 + } + return v.plus(dir) +} + function renderLiquid (world: World, cursor: Vec3, texture: any | undefined, type: number, biome: string, water: boolean, attr: Record, isRealWater: boolean) { const heights: number[] = [] for (let z = -1; z <= 1; z++) { @@ -142,7 +149,7 @@ function renderLiquid (world: World, cursor: Vec3, texture: any | undefined, typ // eslint-disable-next-line guard-for-in for (const face in elemFaces) { - const { dir, corners } = elemFaces[face] + const { dir, corners, mask1, mask2 } = elemFaces[face] const isUp = dir[1] === 1 const neighborPos = cursor.offset(...dir as [number, number, number]) @@ -180,6 +187,9 @@ function renderLiquid (world: World, cursor: Vec3, texture: any | undefined, typ const { su } = texture const { sv } = texture + // Get base light value for the face + const baseLight = world.getLight(neighborPos, undefined, undefined, water ? 'water' : 'lava') / 15 + for (const pos of corners) { const height = cornerHeights[pos[2] * 2 + pos[0]] attr.t_positions.push( @@ -189,7 +199,31 @@ function renderLiquid (world: World, cursor: Vec3, texture: any | undefined, typ ) attr.t_normals.push(...dir) attr.t_uvs.push(pos[3] * su + u, pos[4] * sv * (pos[1] ? 1 : height) + v) - attr.t_colors.push(tint[0], tint[1], tint[2]) + + let cornerLightResult = baseLight + if (world.config.smoothLighting) { + const dx = pos[0] * 2 - 1 + const dy = pos[1] * 2 - 1 + const dz = pos[2] * 2 - 1 + const cornerDir: [number, number, number] = [dx, dy, dz] + const side1Dir: [number, number, number] = [dx * mask1[0], dy * mask1[1], dz * mask1[2]] + const side2Dir: [number, number, number] = [dx * mask2[0], dy * mask2[1], dz * mask2[2]] + + const dirVec = new Vec3(...dir as [number, number, number]) + + const side1LightDir = getVec(new Vec3(...side1Dir), dirVec) + const side1Light = world.getLight(cursor.plus(side1LightDir)) / 15 + const side2DirLight = getVec(new Vec3(...side2Dir), dirVec) + const side2Light = world.getLight(cursor.plus(side2DirLight)) / 15 + const cornerLightDir = getVec(new Vec3(...cornerDir), dirVec) + const cornerLight = world.getLight(cursor.plus(cornerLightDir)) / 15 + // interpolate + const lights = [side1Light, side2Light, cornerLight, baseLight] + cornerLightResult = lights.reduce((acc, cur) => acc + cur, 0) / lights.length + } + + // Apply light value to tint + attr.t_colors.push(tint[0] * cornerLightResult, tint[1] * cornerLightResult, tint[2] * cornerLightResult) } } } diff --git a/renderer/viewer/lib/mesher/shared.ts b/renderer/viewer/lib/mesher/shared.ts index eb1346f41..6fe44e9c9 100644 --- a/renderer/viewer/lib/mesher/shared.ts +++ b/renderer/viewer/lib/mesher/shared.ts @@ -3,9 +3,12 @@ import { BlockType } from '../../../playground/shared' // only here for easier testing export const defaultMesherConfig = { version: '', + enableLighting: true, skyLight: 15, smoothLighting: true, + clientSideLighting: false, + outputFormat: 'threeJs' as 'threeJs' | 'webgpu', textureSize: 1024, // for testing debugModelVariant: undefined as undefined | number[], diff --git a/renderer/viewer/lib/mesher/world.ts b/renderer/viewer/lib/mesher/world.ts index cd8ad3355..ba7ea616a 100644 --- a/renderer/viewer/lib/mesher/world.ts +++ b/renderer/viewer/lib/mesher/world.ts @@ -53,7 +53,9 @@ export class World { } getLight (pos: Vec3, isNeighbor = false, skipMoreChecks = false, curBlockName = '') { - const IS_USING_SERVER_LIGHTING = false + const IS_USING_SERVER_LIGHTING = !this.config.clientSideLighting + // const IS_USING_SERVER_LIGHTING = false + // for easier testing if (!(pos instanceof Vec3)) pos = new Vec3(...pos as [number, number, number]) const { enableLighting, skyLight } = this.config @@ -96,13 +98,23 @@ export class World { } getBlockLight (pos: Vec3) { + if (!this.config.clientSideLighting) { + const column = this.getColumnByPos(pos) + if (!column) return 15 + return column.getBlockLight(posInChunk(pos)) + } + return this.lightHolder.getBlockLight(pos.x, pos.y, pos.z) - // return column.getBlockLight(posInChunk(pos)) } getSkyLight (pos: Vec3) { + if (!this.config.clientSideLighting) { + const column = this.getColumnByPos(pos) + if (!column) return 15 + return column.getSkyLight(posInChunk(pos)) + } + return this.lightHolder.getSkyLight(pos.x, pos.y, pos.z) - // return column.getSkyLight(posInChunk(pos)) } addColumn (x, z, json) { diff --git a/renderer/viewer/lib/worldDataEmitter.ts b/renderer/viewer/lib/worldDataEmitter.ts index 34755c2ad..8f569af73 100644 --- a/renderer/viewer/lib/worldDataEmitter.ts +++ b/renderer/viewer/lib/worldDataEmitter.ts @@ -80,8 +80,11 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter TypedEmitter { this.unloadChunk(pos) }, - blockUpdate: (oldBlock: any, newBlock: any) => { + blockUpdate: (oldBlock, newBlock) => { const stateId = newBlock.stateId ?? ((newBlock.type << 4) | newBlock.metadata) - this.emitter.emit('blockUpdate', { pos: oldBlock.position, stateId }) + + const updateChunks = updateBlockLight(newBlock.position.x, newBlock.position.y, newBlock.position.z, stateId) ?? [] + this.emit('blockUpdate', { pos: newBlock.position, stateId }) + for (const chunk of updateChunks) { + void this.loadChunk(new Vec3(chunk[0] * 16, 0, chunk[1] * 16), true, 'setBlockStateId light update') + } }, time: () => { this.emitter.emit('time', bot.time.timeOfDay) @@ -261,7 +269,7 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter textureSize: this.resourcesManager.currentResources!.blocksAtlasParser.atlas.latest.width, debugModelVariant: undefined, clipWorldBelowY: this.worldRendererConfig.clipWorldBelowY, - disableSignsMapsSupport: !this.worldRendererConfig.extraBlockRenderers + disableSignsMapsSupport: !this.worldRendererConfig.extraBlockRenderers, + clientSideLighting: this.worldRendererConfig.clientSideLighting } } diff --git a/renderer/viewer/three/worldrendererThree.ts b/renderer/viewer/three/worldrendererThree.ts index acd44e8b3..7aacf61d4 100644 --- a/renderer/viewer/three/worldrendererThree.ts +++ b/renderer/viewer/three/worldrendererThree.ts @@ -157,7 +157,7 @@ export class WorldRendererThree extends WorldRendererCommon { this.onReactiveValueUpdated('directionalLight', (value) => { if (!value) return // this.directionalLight.intensity = value - this.directionalLight.intensity = 1 + this.directionalLight.intensity = 0.4 }) this.onReactiveValueUpdated('lookingAtBlock', (value) => { this.cursorBlock.setHighlightCursorBlock(value ? new Vec3(value.x, value.y, value.z) : null, value?.shapes) diff --git a/src/dayCycle.ts b/src/dayCycle.ts index 50e63a21b..5b2725e24 100644 --- a/src/dayCycle.ts +++ b/src/dayCycle.ts @@ -35,10 +35,10 @@ export default () => { // todo need to think wisely how to set these values & also move directional light around! const colorInt = Math.max(int, 0.1) updateBackground({ r: dayColor.r * colorInt, g: dayColor.g * colorInt, b: dayColor.b * colorInt }) - if (!options.newVersionsLighting && bot.supportFeature('blockStateId')) { - appViewer.playerState.reactive.ambientLight = Math.max(int, 0.25) - appViewer.playerState.reactive.directionalLight = Math.min(int, 0.5) - } + // if (!options.newVersionsLighting && bot.supportFeature('blockStateId')) { + // appViewer.playerState.reactive.ambientLight = Math.max(int, 0.25) + // appViewer.playerState.reactive.directionalLight = Math.min(int, 0.45) + // } } bot.on('time', timeUpdated) diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 205144899..0184e9bf6 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -81,12 +81,12 @@ export const guiOptionsScheme: { custom () { return Experimental }, - dayCycleAndLighting: { - text: 'Day Cycle', - }, smoothLighting: {}, - newVersionsLighting: { - text: 'Lighting in Newer Versions', + lightingStrategy: { + values: [ + ['prefer-server', 'Prefer Server'], + ['always-client', 'Always Client'], + ], }, lowMemoryMode: { text: 'Low Memory Mode', @@ -94,7 +94,6 @@ export const guiOptionsScheme: { disabledDuringGame: true }, starfieldRendering: {}, - renderEntities: {}, keepChunksDistance: { max: 5, unit: '', diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index 27eb520d9..b0cc0068c 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -98,7 +98,7 @@ const defaultOptions = { renderEntities: true, smoothLighting: true, // lightingStrategy: 'prefer-server' as 'only-server' | 'always-client' | 'prefer-server', - lightingStrategy: 'prefer-server' as 'always-client' | 'prefer-server', + lightingStrategy: 'prefer-server' as 'always-client' | 'prefer-server' | 'always-server', chatSelect: true, autoJump: 'auto' as 'auto' | 'always' | 'never', autoParkour: false, diff --git a/src/react/DebugOverlay.tsx b/src/react/DebugOverlay.tsx index a7eb068f5..2175863d6 100644 --- a/src/react/DebugOverlay.tsx +++ b/src/react/DebugOverlay.tsx @@ -1,6 +1,7 @@ import { useEffect, useRef, useState } from 'react' import type { Block } from 'prismarine-block' import { getThreeJsRendererMethods } from 'renderer/viewer/three/threeJsMethods' +import { getDebugLightValues } from 'renderer/viewer/lib/lightEngine' import { getFixedFilesize } from '../downloadAndOpenFile' import { options } from '../optionsStorage' import { BlockStateModelInfo } from '../../renderer/viewer/lib/mesher/shared' @@ -128,9 +129,11 @@ export default () => { }) const freqUpdateInterval = setInterval(() => { + const lights = getDebugLightValues(Math.floor(bot.entity.position.x), Math.floor(bot.entity.position.y), Math.floor(bot.entity.position.z)) + setPos({ ...bot.entity.position }) - setSkyL(bot.world.getSkyLight(bot.entity.position)) - setBlockL(bot.world.getBlockLight(bot.entity.position)) + setSkyL(lights.skyLight) + setBlockL(lights.blockLight) setBiomeId(bot.world.getBiome(bot.entity.position)) setDimension(bot.game.dimension) setDay(bot.time.day) diff --git a/src/watchOptions.ts b/src/watchOptions.ts index d0ff609fd..effd3d874 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -96,9 +96,14 @@ export const watchOptionsAfterViewerInit = () => { const updateLightingStrategy = () => { if (!bot) return - const clientSideLighting = options.lightingStrategy === 'always-client' || (options.lightingStrategy === 'prefer-server' && bot.supportFeature('blockStateId')) + const serverAvailable = !bot.supportFeature('blockStateId') + + const serverLightingEnabled = serverAvailable && (options.lightingStrategy === 'prefer-server' || options.lightingStrategy === 'always-server') + const clientLightingEnabled = options.lightingStrategy === 'prefer-server' ? !serverAvailable : options.lightingStrategy === 'always-client' + + const clientSideLighting = !serverLightingEnabled appViewer.inWorldRenderingConfig.clientSideLighting = clientSideLighting - appViewer.inWorldRenderingConfig.enableLighting = options.dayCycleAndLighting && (!bot.supportFeature('blockStateId') || clientSideLighting) + appViewer.inWorldRenderingConfig.enableLighting = options.dayCycleAndLighting && (clientLightingEnabled || serverLightingEnabled) } subscribeKey(options, 'lightingStrategy', updateLightingStrategy) From f4eab39f7f3de463a5d47c90d6c0a55e9c68a0fe Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 30 Apr 2025 08:51:46 +0300 Subject: [PATCH 10/22] finish lighting --- pnpm-lock.yaml | 28 +++++++++++----------- renderer/viewer/lib/basePlayerState.ts | 1 + renderer/viewer/lib/mesher/shared.ts | 1 + renderer/viewer/lib/mesher/world.ts | 21 +++++++--------- renderer/viewer/lib/worldrendererCommon.ts | 6 +++-- src/mineflayer/playerState.ts | 18 ++++++++++++++ src/react/ChunksDebugScreen.tsx | 2 +- src/react/DebugOverlay.tsx | 21 +++++++++++----- src/watchOptions.ts | 8 ++++--- 9 files changed, 68 insertions(+), 38 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be002941e..a3f636c41 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -148,7 +148,7 @@ importers: version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify - version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/92707300cce08287ed7750f4447be350fc342d07 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469 node-gzip: specifier: ^1.1.2 version: 1.1.2 @@ -441,7 +441,7 @@ importers: version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 prismarine-chunk: specifier: github:zardoy/prismarine-chunk#master - version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) + version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-schematic: specifier: ^1.2.0 version: 1.2.3 @@ -6869,8 +6869,8 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/92707300cce08287ed7750f4447be350fc342d07: - resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/92707300cce08287ed7750f4447be350fc342d07} + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469} version: 0.2.4 nice-try@1.0.5: @@ -7415,8 +7415,8 @@ packages: prismarine-chat@1.11.0: resolution: {integrity: sha512-VJT/MWYB3qoiznUhrgvSQh76YFpzpCZpY85kJKxHLbd3UVoM0wsfs43Eg8dOltiZG92wc5/DTMLlT07TEeoa9w==} - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5} version: 1.38.1 engines: {node: '>=14'} @@ -13184,7 +13184,7 @@ snapshots: mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -13220,7 +13220,7 @@ snapshots: mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -14615,7 +14615,7 @@ snapshots: diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/cfaad2d1d5909fdfa63c8cc7bc05fb5e87782d71: dependencies: minecraft-data: 3.83.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-registry: 1.11.0 random-seed: 0.3.0 vec3: 0.1.10 @@ -17430,7 +17430,7 @@ snapshots: prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 prismarine-chat: 1.11.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -17454,7 +17454,7 @@ snapshots: prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 prismarine-chat: 1.11.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -17644,7 +17644,7 @@ snapshots: neo-async@2.6.2: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/92707300cce08287ed7750f4447be350fc342d07: + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469: dependencies: body-parser: 1.20.3 express: 4.21.2 @@ -18254,7 +18254,7 @@ snapshots: prismarine-nbt: 2.7.0 prismarine-registry: 1.11.0 - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1): + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 @@ -18292,7 +18292,7 @@ snapshots: prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.83.1): dependencies: prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/e68e9a423b5b1907535878fb636f12c28a1a9374(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-nbt: 2.7.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c uint4: 0.1.2 diff --git a/renderer/viewer/lib/basePlayerState.ts b/renderer/viewer/lib/basePlayerState.ts index df8cbc616..ff7617eff 100644 --- a/renderer/viewer/lib/basePlayerState.ts +++ b/renderer/viewer/lib/basePlayerState.ts @@ -31,6 +31,7 @@ export interface IPlayerState { getHeldItem?(isLeftHand: boolean): HandItemBlock | undefined username?: string onlineMode?: boolean + lightingDisabled?: boolean events: TypedEmitter diff --git a/renderer/viewer/lib/mesher/shared.ts b/renderer/viewer/lib/mesher/shared.ts index 6fe44e9c9..711400964 100644 --- a/renderer/viewer/lib/mesher/shared.ts +++ b/renderer/viewer/lib/mesher/shared.ts @@ -8,6 +8,7 @@ export const defaultMesherConfig = { skyLight: 15, smoothLighting: true, clientSideLighting: false, + flyingSquidWorkarounds: false, outputFormat: 'threeJs' as 'threeJs' | 'webgpu', textureSize: 1024, // for testing diff --git a/renderer/viewer/lib/mesher/world.ts b/renderer/viewer/lib/mesher/world.ts index ba7ea616a..22d271293 100644 --- a/renderer/viewer/lib/mesher/world.ts +++ b/renderer/viewer/lib/mesher/world.ts @@ -53,19 +53,19 @@ export class World { } getLight (pos: Vec3, isNeighbor = false, skipMoreChecks = false, curBlockName = '') { - const IS_USING_SERVER_LIGHTING = !this.config.clientSideLighting - // const IS_USING_SERVER_LIGHTING = false - // for easier testing if (!(pos instanceof Vec3)) pos = new Vec3(...pos as [number, number, number]) - const { enableLighting, skyLight } = this.config + + const IS_USING_LOCAL_SERVER_LIGHTING = this.config.flyingSquidWorkarounds + // const IS_USING_SERVER_LIGHTING = false + + const { enableLighting, skyLight, clientSideLighting } = this.config if (!enableLighting) return 15 - // const key = `${pos.x},${pos.y},${pos.z}` - // if (lightsCache.has(key)) return lightsCache.get(key) const column = this.getColumnByPos(pos) - if (!column || !hasChunkSection(column, pos)) return 15 + if (!column) return 15 + if (!clientSideLighting && !hasChunkSection(column, pos)) return 2 let result = Math.max( - 3, + 2, Math.min( 15, Math.max( @@ -74,10 +74,7 @@ export class World { ) ) ) - const MIN_LIGHT_LEVEL = 2 - result = Math.max(result, MIN_LIGHT_LEVEL) - // lightsCache.set(key, result) - if (result === 2 && IS_USING_SERVER_LIGHTING) { + if (result === 2 && IS_USING_LOCAL_SERVER_LIGHTING) { if ([this.getBlock(pos)?.name ?? '', curBlockName].some(x => /_stairs|slab|glass_pane/.exec(x)) && !skipMoreChecks) { // todo this is obviously wrong const lights = [ this.getLight(pos.offset(0, 1, 0), undefined, true), diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts index b99aa72eb..6da45d3f5 100644 --- a/renderer/viewer/lib/worldrendererCommon.ts +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -42,6 +42,7 @@ export const defaultWorldRendererConfig = { smoothLighting: true, enableLighting: true, clientSideLighting: false, + flyingSquidWorkarounds: false, starfield: true, addChunksBatchWaitTime: 200, vrSupport: true, @@ -549,7 +550,7 @@ export abstract class WorldRendererCommon skyLight = Math.floor(skyLight) return { version: this.version, - enableLighting: this.worldRendererConfig.enableLighting, + enableLighting: this.worldRendererConfig.enableLighting && !this.playerState.lightingDisabled, skyLight, smoothLighting: this.worldRendererConfig.smoothLighting, outputFormat: this.outputFormat, @@ -557,7 +558,8 @@ export abstract class WorldRendererCommon debugModelVariant: undefined, clipWorldBelowY: this.worldRendererConfig.clipWorldBelowY, disableSignsMapsSupport: !this.worldRendererConfig.extraBlockRenderers, - clientSideLighting: this.worldRendererConfig.clientSideLighting + clientSideLighting: this.worldRendererConfig.clientSideLighting, + flyingSquidWorkarounds: this.worldRendererConfig.flyingSquidWorkarounds } } diff --git a/src/mineflayer/playerState.ts b/src/mineflayer/playerState.ts index 85f0b00c9..d16bedf35 100644 --- a/src/mineflayer/playerState.ts +++ b/src/mineflayer/playerState.ts @@ -24,6 +24,7 @@ export class PlayerStateManager implements IPlayerState { private itemUsageTicks = 0 private isUsingItem = false private ready = false + public lightingDisabled = false onlineMode = false get username () { return bot.username ?? '' @@ -51,6 +52,23 @@ export class PlayerStateManager implements IPlayerState { } private botCreated () { + const handleDimensionData = (data) => { + let hasSkyLight = 1 + try { + hasSkyLight = data.dimension.value.has_skylight.value + } catch (err) { + hasSkyLight = 0 + } + this.lightingDisabled = bot.game.dimension === 'the_nether' || bot.game.dimension === 'the_end' || !hasSkyLight + } + + bot._client.on('login', (packet) => { + handleDimensionData(packet) + }) + bot._client.on('respawn', (packet) => { + handleDimensionData(packet) + }) + // Movement tracking bot.on('move', this.updateState) diff --git a/src/react/ChunksDebugScreen.tsx b/src/react/ChunksDebugScreen.tsx index 80e926d8a..9f47d023a 100644 --- a/src/react/ChunksDebugScreen.tsx +++ b/src/react/ChunksDebugScreen.tsx @@ -30,7 +30,7 @@ const Inner = () => { state, lines: [String(chunk?.loads.length ?? 0)], sidebarLines: [ - `loads: ${chunk.loads.map(l => `${l.reason} ${l.dataLength} ${l.time}`).join('\n')}`, + `loads: ${chunk.loads?.map(l => `${l.reason} ${l.dataLength} ${l.time}`).join('\n')}`, // `blockUpdates: ${chunk.blockUpdates}`, ], } diff --git a/src/react/DebugOverlay.tsx b/src/react/DebugOverlay.tsx index c187587dd..56950db24 100644 --- a/src/react/DebugOverlay.tsx +++ b/src/react/DebugOverlay.tsx @@ -31,8 +31,7 @@ export default () => { const [packetsString, setPacketsString] = useState('') const [showDebug, setShowDebug] = useState(false) const [pos, setPos] = useState<{ x: number, y: number, z: number }>({ x: 0, y: 0, z: 0 }) - const [skyL, setSkyL] = useState(0) - const [blockL, setBlockL] = useState(0) + const [lightInfo, setLightInfo] = useState<{ sky: number, block: number, info: string }>({ sky: 0, block: 0, info: '-' }) const [biomeId, setBiomeId] = useState(0) const [day, setDay] = useState(0) const [timeOfDay, setTimeOfDay] = useState(0) @@ -129,11 +128,21 @@ export default () => { }) const freqUpdateInterval = setInterval(() => { - const lights = getDebugLightValues(Math.floor(bot.entity.position.x), Math.floor(bot.entity.position.y), Math.floor(bot.entity.position.z)) + const lightingEnabled = appViewer.inWorldRenderingConfig.enableLighting + const serverLighting = !appViewer.inWorldRenderingConfig.clientSideLighting + if (!lightingEnabled || serverLighting) { + setLightInfo({ + sky: bot.world.getSkyLight(bot.entity.position), + block: bot.world.getBlockLight(bot.entity.position), + info: lightingEnabled ? 'Server Lighting' : 'Lighting Disabled' + }) + } else { + // client engine is used + const lights = getDebugLightValues(Math.floor(bot.entity.position.x), Math.floor(bot.entity.position.y), Math.floor(bot.entity.position.z)) + setLightInfo({ sky: lights.skyLight, block: lights.blockLight, info: 'Client Light Engine' }) + } setPos({ ...bot.entity.position }) - setSkyL(lights.skyLight) - setBlockL(lights.blockLight) setBiomeId(bot.world.getBiome(bot.entity.position)) setDimension(bot.game.dimension) setDay(bot.time.day) @@ -192,7 +201,7 @@ export default () => {

Client TPS: {clientTps} {serverTps ? `Server TPS: ${serverTps.value} ${serverTps.frozen ? '(frozen)' : ''}` : ''}

Facing (viewer): {bot.entity.yaw.toFixed(3)} {bot.entity.pitch.toFixed(3)}

Facing (minecraft): {quadsDescription[minecraftQuad.current]} ({minecraftYaw.current.toFixed(1)} {(bot.entity.pitch * -180 / Math.PI).toFixed(1)})

-

Light: {blockL} ({skyL} sky)

+

Light: {lightInfo.block} ({lightInfo.sky} sky) ({lightInfo.info})

Biome: minecraft:{loadedData.biomesArray[biomeId]?.name ?? 'unknown biome'}

Day: {day} Time: {timeOfDay}

diff --git a/src/watchOptions.ts b/src/watchOptions.ts index effd3d874..42bb26f69 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -96,10 +96,12 @@ export const watchOptionsAfterViewerInit = () => { const updateLightingStrategy = () => { if (!bot) return - const serverAvailable = !bot.supportFeature('blockStateId') + // for now ignore saved lighting to allow proper updates and singleplayer created worlds + // appViewer.inWorldRenderingConfig.flyingSquidWorkarounds = miscUiState.flyingSquid + const serverParsingSupported = miscUiState.flyingSquid ? /* !bot.supportFeature('blockStateId') */false : bot.supportFeature('blockStateId') - const serverLightingEnabled = serverAvailable && (options.lightingStrategy === 'prefer-server' || options.lightingStrategy === 'always-server') - const clientLightingEnabled = options.lightingStrategy === 'prefer-server' ? !serverAvailable : options.lightingStrategy === 'always-client' + const serverLightingEnabled = serverParsingSupported && (options.lightingStrategy === 'prefer-server' || options.lightingStrategy === 'always-server') + const clientLightingEnabled = options.lightingStrategy === 'prefer-server' ? !serverParsingSupported : options.lightingStrategy === 'always-client' const clientSideLighting = !serverLightingEnabled appViewer.inWorldRenderingConfig.clientSideLighting = clientSideLighting From 79f0fdd86eef7b5b460a275fa7e83050445d4079 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 30 Apr 2025 08:51:51 +0300 Subject: [PATCH 11/22] fix lava rendering --- renderer/viewer/lib/mesher/models.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/renderer/viewer/lib/mesher/models.ts b/renderer/viewer/lib/mesher/models.ts index 32b805d1a..802ecaf0a 100644 --- a/renderer/viewer/lib/mesher/models.ts +++ b/renderer/viewer/lib/mesher/models.ts @@ -103,8 +103,8 @@ function tintToGl (tint) { return [r / 255, g / 255, b / 255] } -function getLiquidRenderHeight (world: World, block: WorldBlock | null, type: number, pos: Vec3, isRealWater: boolean) { - if (!isRealWater || (block && isBlockWaterlogged(block))) return 8 / 9 +function getLiquidRenderHeight (world: World, block: WorldBlock | null, type: number, pos: Vec3, isWater: boolean, isRealWater: boolean) { + if ((isWater && !isRealWater) || (block && isBlockWaterlogged(block))) return 8 / 9 if (!block || block.type !== type) return 1 / 9 if (block.metadata === 0) { // source block const blockAbove = world.getBlock(pos.offset(0, 1, 0)) @@ -137,7 +137,7 @@ function renderLiquid (world: World, cursor: Vec3, texture: any | undefined, typ for (let z = -1; z <= 1; z++) { for (let x = -1; x <= 1; x++) { const pos = cursor.offset(x, 0, z) - heights.push(getLiquidRenderHeight(world, world.getBlock(pos), type, pos, isRealWater)) + heights.push(getLiquidRenderHeight(world, world.getBlock(pos), type, pos, water, isRealWater)) } } const cornerHeights = [ From 27c55b1afc5c21b56cc91de3e4b2e2485204ce68 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 30 Apr 2025 09:14:37 +0300 Subject: [PATCH 12/22] finish! --- renderer/viewer/lib/lightEngine.ts | 22 +++++-- renderer/viewer/lib/mesher/mesher.ts | 2 - renderer/viewer/lib/worldDataEmitter.ts | 69 +++++++++++++++------- renderer/viewer/lib/worldrendererCommon.ts | 6 +- src/appViewer.ts | 1 + src/optionsGuiScheme.tsx | 1 + 6 files changed, 68 insertions(+), 33 deletions(-) diff --git a/renderer/viewer/lib/lightEngine.ts b/renderer/viewer/lib/lightEngine.ts index 8b83ab981..84fbc820b 100644 --- a/renderer/viewer/lib/lightEngine.ts +++ b/renderer/viewer/lib/lightEngine.ts @@ -1,6 +1,7 @@ import { LightWorld, createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock } from 'minecraft-lighting' import { world } from 'prismarine-world' import { WorldRendererCommon } from './worldrendererCommon' +import { WorldDataEmitter } from './worldDataEmitter' let lightEngine: LightWorld | null = null export const getLightEngine = () => { @@ -11,10 +12,11 @@ export const getLightEngineSafe = () => { return lightEngine } -export const createLightEngine = (world: WorldRendererCommon) => { - lightEngine = createLightEngineForSyncWorld(world.displayOptions.worldView.world as unknown as world.WorldSync, loadedData, { - minY: world.worldSizeParams.minY, - height: world.worldSizeParams.worldHeight, +export const createLightEngineIfNeeded = (worldView: WorldDataEmitter) => { + if (lightEngine) return + lightEngine = createLightEngineForSyncWorld(worldView.world as unknown as world.WorldSync, loadedData, { + minY: worldView.minY, + height: worldView.worldHeight, // enableSkyLight: false, }) lightEngine.externalWorld.setBlock = () => {} @@ -23,9 +25,11 @@ export const createLightEngine = (world: WorldRendererCommon) => { } export const processLightChunk = async (x: number, z: number) => { + const engine = getLightEngineSafe() + if (!engine) return + const chunkX = Math.floor(x / 16) const chunkZ = Math.floor(z / 16) - const engine = getLightEngine() // fillColumnWithZeroLight(engine.externalWorld, chunkX, chunkZ) const updated = engine.receiveUpdateColumn(chunkX, chunkZ) @@ -46,7 +50,8 @@ export const getDebugLightValues = (x: number, y: number, z: number) => { } export const updateBlockLight = (x: number, y: number, z: number, stateId: number) => { - const engine = getLightEngine() + const engine = getLightEngineSafe() + if (!engine) return const affected = engine['affectedChunksTimestamps'] as Map const noAffected = affected.size === 0 engine.setBlock(x, y, z, convertPrismarineBlockToWorldBlock(stateId, loadedData)) @@ -59,3 +64,8 @@ export const updateBlockLight = (x: number, y: number, z: number, stateId: numbe return chunks } } + +export const destroyLightEngine = () => { + lightEngine = null + globalThis.lightEngine = null +} diff --git a/renderer/viewer/lib/mesher/mesher.ts b/renderer/viewer/lib/mesher/mesher.ts index 4f1885b10..3f06d60d4 100644 --- a/renderer/viewer/lib/mesher/mesher.ts +++ b/renderer/viewer/lib/mesher/mesher.ts @@ -109,8 +109,6 @@ const handleMessage = data => { world.addColumn(data.x, data.z, data.chunk) if (data.lightData) { world.lightHolder.loadChunk(data.lightData) - } else { - console.warn('no light data', data.x, data.z) } if (data.customBlockModels) { const chunkKey = `${data.x},${data.z}` diff --git a/renderer/viewer/lib/worldDataEmitter.ts b/renderer/viewer/lib/worldDataEmitter.ts index 9b3da8aa4..ceed72f00 100644 --- a/renderer/viewer/lib/worldDataEmitter.ts +++ b/renderer/viewer/lib/worldDataEmitter.ts @@ -9,7 +9,8 @@ import { proxy } from 'valtio' import TypedEmitter from 'typed-emitter' import { delayedIterator } from '../../playground/shared' import { chunkPos } from './simpleUtils' -import { processLightChunk, updateBlockLight } from './lightEngine' +import { createLightEngineIfNeeded, destroyLightEngine, processLightChunk, updateBlockLight } from './lightEngine' +import { WorldRendererConfig } from './worldrendererCommon' export type ChunkPosKey = string // like '16,16' type ChunkPos = { x: number, z: number } // like { x: 16, z: 16 } @@ -36,6 +37,11 @@ export type WorldDataEmitterEvents = { * It's up to the consumer to serialize the data if needed */ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter) { + minY = -64 + worldHeight = 384 + dimensionName = '' + + worldRendererConfig: WorldRendererConfig loadedChunks: Record readonly lastPos: Vec3 private eventListeners: Record = {} @@ -70,22 +76,22 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter | void - if (val) throw new Error('setBlockStateId returned promise (not supported)') - // const chunkX = Math.floor(position.x / 16) - // const chunkZ = Math.floor(position.z / 16) - // if (!this.loadedChunks[`${chunkX},${chunkZ}`] && !this.waitingSpiralChunksLoad[`${chunkX},${chunkZ}`]) { - // void this.loadChunk({ x: chunkX, z: chunkZ }) - // return - // } - - const updateChunks = updateBlockLight(position.x, position.y, position.z, stateId) ?? [] - this.emit('blockUpdate', { pos: position, stateId }) - for (const chunk of updateChunks) { - void this.loadChunk(new Vec3(chunk[0] * 16, 0, chunk[1] * 16), true, 'setBlockStateId light update') - } - } + // setBlockStateId (position: Vec3, stateId: number) { + // const val = this.world.setBlockStateId(position, stateId) as Promise | void + // if (val) throw new Error('setBlockStateId returned promise (not supported)') + // // const chunkX = Math.floor(position.x / 16) + // // const chunkZ = Math.floor(position.z / 16) + // // if (!this.loadedChunks[`${chunkX},${chunkZ}`] && !this.waitingSpiralChunksLoad[`${chunkX},${chunkZ}`]) { + // // void this.loadChunk({ x: chunkX, z: chunkZ }) + // // return + // // } + + // const updateChunks = this.worldRendererConfig.clientSideLighting ? updateBlockLight(position.x, position.y, position.z, stateId) ?? [] : [] + // this.emit('blockUpdate', { pos: position, stateId }) + // for (const chunk of updateChunks) { + // void this.loadChunk(new Vec3(chunk[0] * 16, 0, chunk[1] * 16), true, 'setBlockStateId light update') + // } + // } updateViewDistance (viewDistance: number) { this.viewDistance = viewDistance @@ -149,7 +155,7 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter { const stateId = newBlock.stateId ?? ((newBlock.type << 4) | newBlock.metadata) - const updateChunks = updateBlockLight(newBlock.position.x, newBlock.position.y, newBlock.position.z, stateId) ?? [] + const updateChunks = this.worldRendererConfig.clientSideLighting ? updateBlockLight(newBlock.position.x, newBlock.position.y, newBlock.position.z, stateId) ?? [] : [] this.emit('blockUpdate', { pos: newBlock.position, stateId }) for (const chunk of updateChunks) { void this.loadChunk(new Vec3(chunk[0] * 16, 0, chunk[1] * 16), true, 'setBlockStateId light update') @@ -162,15 +168,21 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter { - void this.updatePosition(bot.entity.position, true) + login () { + possiblyDimensionChange() }, respawn: () => { - void this.updatePosition(bot.entity.position, true) + possiblyDimensionChange() this.emitter.emit('onWorldSwitch') }, } satisfies Partial + const possiblyDimensionChange = () => { + this.minY = bot.game['minY'] ?? -64 + this.worldHeight = bot.game['height'] ?? 384 + this.dimensionName = bot.game['dimension'] ?? '' + void this.updatePosition(bot.entity.position, true) + } bot._client.on('update_light', ({ chunkX, chunkZ }) => { const chunkPos = new Vec3(chunkX * 16, 0, chunkZ * 16) @@ -218,6 +230,14 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter TypedEmitter TypedEmitter + if (!isLightUpdate && this.worldRendererConfig.clientSideLighting) { + result = await processLightChunk(pos.x, pos.z) ?? [] + } if (!result) return for (const affectedChunk of result) { if (affectedChunk.x === chunkX && affectedChunk.z === chunkZ) continue diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts index 6da45d3f5..e91f89257 100644 --- a/renderer/viewer/lib/worldrendererCommon.ts +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -19,7 +19,7 @@ import { chunkPos } from './simpleUtils' import { addNewStat, removeAllStats, removeStat, updatePanesVisibility, updateStatText } from './ui/newStats' import { WorldDataEmitter } from './worldDataEmitter' import { IPlayerState } from './basePlayerState' -import { createLightEngine, dumpLightData, getLightEngine, getLightEngineSafe } from './lightEngine' +import { createLightEngineIfNeeded, dumpLightData, getLightEngine, getLightEngineSafe } from './lightEngine' import { MesherLogReader } from './mesherlogReader' import { setSkinsConfig } from './utils/skins' @@ -173,8 +173,6 @@ export abstract class WorldRendererCommon } constructor (public readonly resourcesManager: ResourcesManager, public displayOptions: DisplayWorldOptions, public initOptions: GraphicsInitOptions) { - createLightEngine(this) - this.snapshotInitialValues() this.worldRendererConfig = displayOptions.inWorldRenderingConfig this.playerState = displayOptions.playerState @@ -1003,5 +1001,7 @@ export abstract class WorldRendererCommon this.displayOptions.worldView.removeAllListeners() // todo this.abortController.abort() removeAllStats() + + this.displayOptions.worldView.destroy() } } diff --git a/src/appViewer.ts b/src/appViewer.ts index ca62bd1be..f3969c602 100644 --- a/src/appViewer.ts +++ b/src/appViewer.ts @@ -171,6 +171,7 @@ export class AppViewer { this.currentDisplay = 'world' const startPosition = playerStateSend.getPosition() this.worldView = new WorldDataEmitter(world, renderDistance, startPosition) + this.worldView.worldRendererConfig = this.inWorldRenderingConfig window.worldView = this.worldView watchOptionsAfterWorldViewInit(this.worldView) diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 39114e3be..2afc7a242 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -86,6 +86,7 @@ export const guiOptionsScheme: { values: [ ['prefer-server', 'Prefer Server'], ['always-client', 'Always Client'], + ['always-server', 'Always Server'], ], }, lowMemoryMode: { From f4f5eddce0d66990d76658b51fdd145e1a130da9 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 30 Apr 2025 09:37:25 +0300 Subject: [PATCH 13/22] fix lighting disabling todo do sky light update re-rendering when server: engine skip calc but stores 15 sky levels, it does recalc in worker and merge updated values --- src/mineflayer/playerState.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mineflayer/playerState.ts b/src/mineflayer/playerState.ts index d16bedf35..1ab33feb9 100644 --- a/src/mineflayer/playerState.ts +++ b/src/mineflayer/playerState.ts @@ -56,9 +56,7 @@ export class PlayerStateManager implements IPlayerState { let hasSkyLight = 1 try { hasSkyLight = data.dimension.value.has_skylight.value - } catch (err) { - hasSkyLight = 0 - } + } catch {} this.lightingDisabled = bot.game.dimension === 'the_nether' || bot.game.dimension === 'the_end' || !hasSkyLight } From c97c7e0cc056b3bf48ffe00c444b3dfa085b75a0 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 1 May 2025 15:11:28 +0300 Subject: [PATCH 14/22] finish combined computation, finish settings and strategies todo: worker, horizontal sky fix, FIX SKY LEVEL from time!, fix block light blocking. OTHER done --- README.MD | 3 +- package.json | 4 +- pnpm-lock.yaml | 10 ++-- renderer/viewer/lib/basePlayerState.ts | 1 + renderer/viewer/lib/lightEngine.ts | 41 ++++++++++++----- renderer/viewer/lib/mesher/models.ts | 3 ++ renderer/viewer/lib/mesher/shared.ts | 3 +- renderer/viewer/lib/mesher/world.ts | 35 ++++++++------ renderer/viewer/lib/worldDataEmitter.ts | 13 ++++-- renderer/viewer/lib/worldrendererCommon.ts | 33 +++++++------ renderer/viewer/three/worldrendererThree.ts | 51 ++++++++++++++++++--- src/dayCycle.ts | 2 +- src/mineflayer/playerState.ts | 6 ++- src/optionsGuiScheme.tsx | 4 ++ src/optionsStorage.ts | 12 ++++- src/react/DebugOverlay.tsx | 10 ++-- src/watchOptions.ts | 26 +++++++++-- 17 files changed, 181 insertions(+), 76 deletions(-) diff --git a/README.MD b/README.MD index aa36f7e8a..8bc673192 100644 --- a/README.MD +++ b/README.MD @@ -12,9 +12,10 @@ For building the project yourself / contributing, see [Development, Debugging & ### Big Features +- Connect to Java servers running in both offline (cracked) and online mode* (it's possible because of proxy servers, see below) +- Combined Lighting System - Server Parsing + Client Side Engine for block updates - Official Mineflayer [plugin integration](https://github.com/zardoy/mcraft-fun-mineflayer-plugin)! View / Control your bot remotely. - Open any zip world file or even folder in read-write mode! -- Connect to Java servers running in both offline (cracked) and online mode* (it's possible because of proxy servers, see below) - Integrated JS server clone capable of opening Java world saves in any way (folders, zip, web chunks streaming, etc) - Singleplayer mode with simple world generations! - Works offline diff --git a/package.json b/package.json index 1522ed473..5b9f2a3fd 100644 --- a/package.json +++ b/package.json @@ -153,6 +153,7 @@ "https-browserify": "^1.0.0", "mc-assets": "^0.2.53", "minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next", + "minecraft-lighting": "^0.0.9", "mineflayer": "github:GenerelSchwerz/mineflayer", "mineflayer-mouse": "^0.1.9", "mineflayer-pathfinder": "^2.4.4", @@ -169,8 +170,7 @@ "timers-browserify": "^2.0.12", "typescript": "5.5.4", "vitest": "^0.34.6", - "yaml": "^2.3.2", - "minecraft-lighting": "^0.0.8" + "yaml": "^2.3.2" }, "optionalDependencies": { "cypress": "^10.11.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3f636c41..64ab6e275 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -343,8 +343,8 @@ importers: specifier: github:zardoy/minecraft-inventory-gui#next version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/98bc5bb8ee6da8b4b771c05b404cee796318ccd4(@types/react@18.3.18)(react@18.3.1) minecraft-lighting: - specifier: ^0.0.8 - version: 0.0.8 + specifier: ^0.0.9 + version: 0.0.9 mineflayer: specifier: github:GenerelSchwerz/mineflayer version: https://codeload.github.com/GenerelSchwerz/mineflayer/tar.gz/d459d2ed76a997af1a7c94718ed7d5dee4478b8a(encoding@0.1.13) @@ -6680,8 +6680,8 @@ packages: resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/98bc5bb8ee6da8b4b771c05b404cee796318ccd4} version: 1.0.1 - minecraft-lighting@0.0.8: - resolution: {integrity: sha512-HEew4qycmHv2r5+FR4vZ81YJkOR9Q8jbpj6nO9nEoiKRFvo9HamcbA6uQmSxJZKkkgt1uOp/EQ61rQXFw3nnGQ==} + minecraft-lighting@0.0.9: + resolution: {integrity: sha512-2ma3m3ia4YmcAFHlZ9BGo4CSVyXL2TltPoXZSeYHmgstGuZwECHzOMQOKjUEzCnQs11X9Rnqz9Dum+Y17bsbyA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/9e116c3dd4682b17c4e2c80249a2447a093d9284: @@ -17323,7 +17323,7 @@ snapshots: - '@types/react' - react - minecraft-lighting@0.0.8: + minecraft-lighting@0.0.9: dependencies: vec3: 0.1.10 diff --git a/renderer/viewer/lib/basePlayerState.ts b/renderer/viewer/lib/basePlayerState.ts index ff7617eff..856772b14 100644 --- a/renderer/viewer/lib/basePlayerState.ts +++ b/renderer/viewer/lib/basePlayerState.ts @@ -32,6 +32,7 @@ export interface IPlayerState { username?: string onlineMode?: boolean lightingDisabled?: boolean + shouldHideHand?: boolean events: TypedEmitter diff --git a/renderer/viewer/lib/lightEngine.ts b/renderer/viewer/lib/lightEngine.ts index 84fbc820b..23a0c1bb6 100644 --- a/renderer/viewer/lib/lightEngine.ts +++ b/renderer/viewer/lib/lightEngine.ts @@ -16,7 +16,8 @@ export const createLightEngineIfNeeded = (worldView: WorldDataEmitter) => { if (lightEngine) return lightEngine = createLightEngineForSyncWorld(worldView.world as unknown as world.WorldSync, loadedData, { minY: worldView.minY, - height: worldView.worldHeight, + height: worldView.minY + worldView.worldHeight, + // writeLightToOriginalWorld: true, // enableSkyLight: false, }) lightEngine.externalWorld.setBlock = () => {} @@ -49,20 +50,36 @@ export const getDebugLightValues = (x: number, y: number, z: number) => { } } -export const updateBlockLight = (x: number, y: number, z: number, stateId: number) => { +export const updateBlockLight = async (x: number, y: number, z: number, stateId: number, distance: number) => { + if (distance > 16) return [] + const chunkX = Math.floor(x / 16) * 16 + const chunkZ = Math.floor(z / 16) * 16 const engine = getLightEngineSafe() if (!engine) return - const affected = engine['affectedChunksTimestamps'] as Map - const noAffected = affected.size === 0 - engine.setBlock(x, y, z, convertPrismarineBlockToWorldBlock(stateId, loadedData)) + const result = await engine.setBlockUpdateChunkIfNeeded(x, y, z) + if (!result) return + console.log(`[light engine] updateBlockLight (${x}, ${y}, ${z}) took`, Math.round(result.time), 'ms', result.affectedChunks?.length ?? 0, 'chunks') + return result.affectedChunks - if (affected.size > 0) { - const chunks = [...affected.keys()].map(key => { - return key.split(',').map(Number) as [number, number] - }) - affected.clear() - return chunks - } + // const engine = getLightEngineSafe() + // if (!engine) return + // const affected = engine['affectedChunksTimestamps'] as Map + // const noAffected = affected.size === 0 + // engine.setBlock(x, y, z, convertPrismarineBlockToWorldBlock(stateId, loadedData)) + + // if (affected.size > 0) { + // const chunks = [...affected.keys()].map(key => { + // return key.split(',').map(Number) as [number, number] + // }) + // affected.clear() + // return chunks + // } +} + +export const lightRemoveColumn = (x: number, z: number) => { + const engine = getLightEngineSafe() + if (!engine) return + engine.columnCleanup(Math.floor(x / 16), Math.floor(z / 16)) } export const destroyLightEngine = () => { diff --git a/renderer/viewer/lib/mesher/models.ts b/renderer/viewer/lib/mesher/models.ts index 802ecaf0a..f743dfb4e 100644 --- a/renderer/viewer/lib/mesher/models.ts +++ b/renderer/viewer/lib/mesher/models.ts @@ -488,6 +488,7 @@ const isBlockWaterlogged = (block: Block) => { let unknownBlockModel: BlockModelPartsResolved export function getSectionGeometry (sx, sy, sz, world: World) { + world.hadSkyLight = false let delayedRender = [] as Array<() => void> const attr: MesherGeometryOutput = { @@ -691,6 +692,8 @@ export function getSectionGeometry (sx, sy, sz, world: World) { delete attr.uvs } + attr.hasSkylight = world.hadSkyLight + return attr } diff --git a/renderer/viewer/lib/mesher/shared.ts b/renderer/viewer/lib/mesher/shared.ts index 711400964..380be30e3 100644 --- a/renderer/viewer/lib/mesher/shared.ts +++ b/renderer/viewer/lib/mesher/shared.ts @@ -7,7 +7,7 @@ export const defaultMesherConfig = { enableLighting: true, skyLight: 15, smoothLighting: true, - clientSideLighting: false, + usingCustomLightHolder: false, flyingSquidWorkarounds: false, outputFormat: 'threeJs' as 'threeJs' | 'webgpu', @@ -48,6 +48,7 @@ export type MesherGeometryOutput = { hadErrors: boolean blocksCount: number customBlockModels?: CustomBlockModels + hasSkylight?: boolean } export type HighestBlockInfo = { y: number, stateId: number | undefined, biomeId: number | undefined } diff --git a/renderer/viewer/lib/mesher/world.ts b/renderer/viewer/lib/mesher/world.ts index 22d271293..675ceca0a 100644 --- a/renderer/viewer/lib/mesher/world.ts +++ b/renderer/viewer/lib/mesher/world.ts @@ -33,6 +33,7 @@ export type WorldBlock = Omit & { } export class World { + hadSkyLight = false lightHolder = new WorldLightHolder(0, 0) config = defaultMesherConfig Chunk: typeof import('prismarine-chunk/types/index').PCChunk @@ -59,11 +60,11 @@ export class World { const IS_USING_LOCAL_SERVER_LIGHTING = this.config.flyingSquidWorkarounds // const IS_USING_SERVER_LIGHTING = false - const { enableLighting, skyLight, clientSideLighting } = this.config + const { enableLighting, skyLight, usingCustomLightHolder } = this.config if (!enableLighting) return 15 const column = this.getColumnByPos(pos) if (!column) return 15 - if (!clientSideLighting && !hasChunkSection(column, pos)) return 2 + if (!usingCustomLightHolder && !hasChunkSection(column, pos)) return 2 let result = Math.max( 2, Math.min( @@ -95,23 +96,29 @@ export class World { } getBlockLight (pos: Vec3) { - if (!this.config.clientSideLighting) { - const column = this.getColumnByPos(pos) - if (!column) return 15 - return column.getBlockLight(posInChunk(pos)) - } + // if (this.config.clientSideLighting) { + // return this.lightHolder.getBlockLight(pos.x, pos.y, pos.z) + // } - return this.lightHolder.getBlockLight(pos.x, pos.y, pos.z) + const column = this.getColumnByPos(pos) + if (!column) return 15 + return column.getBlockLight(posInChunk(pos)) } getSkyLight (pos: Vec3) { - if (!this.config.clientSideLighting) { - const column = this.getColumnByPos(pos) - if (!column) return 15 - return column.getSkyLight(posInChunk(pos)) - } + const result = this.getSkyLightInner(pos) + if (result > 2) this.hadSkyLight = true + return result + } + + getSkyLightInner (pos: Vec3) { + // if (this.config.clientSideLighting) { + // return this.lightHolder.getSkyLight(pos.x, pos.y, pos.z) + // } - return this.lightHolder.getSkyLight(pos.x, pos.y, pos.z) + const column = this.getColumnByPos(pos) + if (!column) return 15 + return column.getSkyLight(posInChunk(pos)) } addColumn (x, z, json) { diff --git a/renderer/viewer/lib/worldDataEmitter.ts b/renderer/viewer/lib/worldDataEmitter.ts index ceed72f00..4b5039ddb 100644 --- a/renderer/viewer/lib/worldDataEmitter.ts +++ b/renderer/viewer/lib/worldDataEmitter.ts @@ -9,7 +9,7 @@ import { proxy } from 'valtio' import TypedEmitter from 'typed-emitter' import { delayedIterator } from '../../playground/shared' import { chunkPos } from './simpleUtils' -import { createLightEngineIfNeeded, destroyLightEngine, processLightChunk, updateBlockLight } from './lightEngine' +import { createLightEngineIfNeeded, destroyLightEngine, lightRemoveColumn, processLightChunk, updateBlockLight } from './lightEngine' import { WorldRendererConfig } from './worldrendererCommon' export type ChunkPosKey = string // like '16,16' @@ -152,13 +152,15 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter { this.unloadChunk(pos) }, - blockUpdate: (oldBlock, newBlock) => { + blockUpdate: async (oldBlock, newBlock) => { + if (typeof newBlock.stateId === 'number' && oldBlock?.stateId === newBlock.stateId) return const stateId = newBlock.stateId ?? ((newBlock.type << 4) | newBlock.metadata) + const distance = newBlock.position.distanceTo(this.lastPos) - const updateChunks = this.worldRendererConfig.clientSideLighting ? updateBlockLight(newBlock.position.x, newBlock.position.y, newBlock.position.z, stateId) ?? [] : [] this.emit('blockUpdate', { pos: newBlock.position, stateId }) + const updateChunks = this.worldRendererConfig.clientSideLighting === 'none' ? [] : await updateBlockLight(newBlock.position.x, newBlock.position.y, newBlock.position.z, stateId, distance) ?? [] for (const chunk of updateChunks) { - void this.loadChunk(new Vec3(chunk[0] * 16, 0, chunk[1] * 16), true, 'setBlockStateId light update') + void this.loadChunk(new Vec3(chunk.x * 16, 0, chunk.z * 16), true, 'setBlockStateId light update') } }, time: () => { @@ -308,7 +310,7 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter - if (!isLightUpdate && this.worldRendererConfig.clientSideLighting) { + if (!isLightUpdate && this.worldRendererConfig.clientSideLighting === 'full') { result = await processLightChunk(pos.x, pos.z) ?? [] } if (!result) return @@ -359,6 +361,7 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter { + skyLight = 15 worldReadyResolvers = Promise.withResolvers() worldReadyPromise = this.worldReadyResolvers.promise timeOfTheDay = 0 @@ -485,6 +487,8 @@ export abstract class WorldRendererCommon timeUpdated? (newTime: number): void + skylightUpdated? (): void + updateViewerPosition (pos: Vec3) { this.viewerPosition = pos for (const [key, value] of Object.entries(this.loadedChunks)) { @@ -532,7 +536,7 @@ export abstract class WorldRendererCommon this.sendMesherMcData() } - getMesherConfig (): MesherConfig { + changeSkyLight () { let skyLight = 15 const timeOfDay = this.timeOfTheDay if (timeOfDay < 0 || timeOfDay > 24_000) { @@ -545,18 +549,21 @@ export abstract class WorldRendererCommon skyLight = ((timeOfDay - 12_000) / 6000) * 15 } - skyLight = Math.floor(skyLight) + this.skyLight = Math.floor(skyLight) + } + + getMesherConfig (): MesherConfig { return { version: this.version, enableLighting: this.worldRendererConfig.enableLighting && !this.playerState.lightingDisabled, - skyLight, + skyLight: this.skyLight, smoothLighting: this.worldRendererConfig.smoothLighting, outputFormat: this.outputFormat, textureSize: this.resourcesManager.currentResources!.blocksAtlasParser.atlas.latest.width, debugModelVariant: undefined, clipWorldBelowY: this.worldRendererConfig.clipWorldBelowY, disableSignsMapsSupport: !this.worldRendererConfig.extraBlockRenderers, - clientSideLighting: this.worldRendererConfig.clientSideLighting, + usingCustomLightHolder: false, flyingSquidWorkarounds: this.worldRendererConfig.flyingSquidWorkarounds } } @@ -789,19 +796,17 @@ export abstract class WorldRendererCommon }) worldEmitter.on('time', (timeOfDay) => { - this.timeUpdated?.(timeOfDay) - if (timeOfDay < 0 || timeOfDay > 24_000) { throw new Error('Invalid time of day. It should be between 0 and 24000.') } + const oldSkyLight = this.skyLight this.timeOfTheDay = timeOfDay - - // if (this.worldRendererConfig.skyLight === skyLight) return - // this.worldRendererConfig.skyLight = skyLight - // if (this instanceof WorldRendererThree) { - // (this).rerenderAllChunks?.() - // } + this.changeSkyLight() + if (oldSkyLight !== this.skyLight) { + this.skylightUpdated?.() + } + this.timeUpdated?.(timeOfDay) }) worldEmitter.emit('listening') @@ -896,7 +901,7 @@ export abstract class WorldRendererCommon this.reactiveState.world.mesherWork = true const distance = this.getDistance(pos) // todo shouldnt we check loadedChunks instead? - if (!this.workers.length || distance[0] > this.viewDistance || distance[1] > this.viewDistance) return + // if (!this.workers.length || distance[0] > this.viewDistance || distance[1] > this.viewDistance) return const key = `${Math.floor(pos.x / 16) * 16},${Math.floor(pos.y / 16) * 16},${Math.floor(pos.z / 16) * 16}` // if (this.sectionsOutstanding.has(key)) return this.renderUpdateEmitter.emit('dirty', pos, value) diff --git a/renderer/viewer/three/worldrendererThree.ts b/renderer/viewer/three/worldrendererThree.ts index 4c031268d..9407d20c5 100644 --- a/renderer/viewer/three/worldrendererThree.ts +++ b/renderer/viewer/three/worldrendererThree.ts @@ -31,7 +31,7 @@ type SectionKey = string export class WorldRendererThree extends WorldRendererCommon { outputFormat = 'threeJs' as const - sectionObjects: Record = {} + sectionObjects: Record = {} chunkTextures = new Map() signsCache = new Map() starField: StarField @@ -151,13 +151,19 @@ export class WorldRendererThree extends WorldRendererCommon { }) this.onReactiveValueUpdated('ambientLight', (value) => { if (!value) return - // this.ambientLight.intensity = value - this.ambientLight.intensity = 1 + if (this.worldRendererConfig.legacyLighting) { + this.ambientLight.intensity = value + } else { + this.ambientLight.intensity = 1 + } }) this.onReactiveValueUpdated('directionalLight', (value) => { if (!value) return - // this.directionalLight.intensity = value - this.directionalLight.intensity = 0.4 + if (this.worldRendererConfig.legacyLighting) { + this.directionalLight.intensity = value + } else { + this.directionalLight.intensity = 0.4 + } }) this.onReactiveValueUpdated('lookingAtBlock', (value) => { this.cursorBlock.setHighlightCursorBlock(value ? new Vec3(value.x, value.y, value.z) : null, value?.shapes) @@ -238,10 +244,38 @@ export class WorldRendererThree extends WorldRendererCommon { } } + skylightUpdated (): void { + let updated = 0 + for (const sectionKey of Object.keys(this.sectionObjects)) { + if (this.sectionObjects[sectionKey].hasSkylight) { + // set section to be updated + const [x, y, z] = sectionKey.split(',').map(Number) + this.setSectionDirty(new Vec3(x, y, z)) + updated++ + } + } + + console.log(`Skylight changed to ${this.skyLight}. Updated`, updated, 'sections') + } + getItemRenderData (item: Record, specificProps: ItemSpecificContextProperties) { return getItemUv(item, specificProps, this.resourcesManager) } + debugOnlySunlightSections (enable: boolean, state = true) { + for (const sectionKey of Object.keys(this.sectionObjects)) { + if (!enable) { + this.sectionObjects[sectionKey].visible = true + continue + } + if (this.sectionObjects[sectionKey].hasSkylight) { + this.sectionObjects[sectionKey].visible = state + } else { + this.sectionObjects[sectionKey].visible = false + } + } + } + async demoModel () { //@ts-expect-error const pos = cursorBlockRel(0, 1, 0).position @@ -328,7 +362,7 @@ export class WorldRendererThree extends WorldRendererCommon { // debugRecomputedDeletedObjects = 0 handleWorkerMessage (data: { geometry: MesherGeometryOutput, key, type }): void { if (data.type !== 'geometry') return - let object: THREE.Object3D = this.sectionObjects[data.key] + let object = this.sectionObjects[data.key] if (object) { this.scene.remove(object) disposeObject(object) @@ -387,7 +421,10 @@ export class WorldRendererThree extends WorldRendererCommon { object.add(head) } } + + object.hasSkylight = data.geometry.hasSkylight this.sectionObjects[data.key] = object + if (this.displayOptions.inWorldRenderingConfig._renderByChunks) { object.visible = false const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}` @@ -472,7 +509,7 @@ export class WorldRendererThree extends WorldRendererCommon { const cam = this.camera instanceof THREE.Group ? this.camera.children.find(child => child instanceof THREE.PerspectiveCamera) as THREE.PerspectiveCamera : this.camera this.renderer.render(this.scene, cam) - if (this.displayOptions.inWorldRenderingConfig.showHand/* && !this.freeFlyMode */) { + if (this.displayOptions.inWorldRenderingConfig.showHand && !this.playerState.shouldHideHand /* && !this.freeFlyMode */) { this.holdingBlock.render(this.camera, this.renderer, this.ambientLight, this.directionalLight) this.holdingBlockLeft.render(this.camera, this.renderer, this.ambientLight, this.directionalLight) } diff --git a/src/dayCycle.ts b/src/dayCycle.ts index 5b2725e24..9e3c731fe 100644 --- a/src/dayCycle.ts +++ b/src/dayCycle.ts @@ -10,7 +10,7 @@ export default () => { const night = 13_500 const morningStart = 23_000 const morningEnd = 23_961 - const timeProgress = options.dayCycleAndLighting ? bot.time.timeOfDay : 0 + const timeProgress = options.dayCycle ? bot.time.timeOfDay : 0 // todo check actual colors const dayColorRainy = { r: 111 / 255, g: 156 / 255, b: 236 / 255 } diff --git a/src/mineflayer/playerState.ts b/src/mineflayer/playerState.ts index 1ab33feb9..16739c86e 100644 --- a/src/mineflayer/playerState.ts +++ b/src/mineflayer/playerState.ts @@ -91,6 +91,10 @@ export class PlayerStateManager implements IPlayerState { this.reactive.gameMode = bot.game?.gameMode } + get shouldHideHand () { + return this.reactive.gameMode === 'spectator' + } + // #region Movement and Physics State private updateState () { if (!bot?.entity || this.disableStateUpdates) return @@ -134,7 +138,7 @@ export class PlayerStateManager implements IPlayerState { } getEyeHeight (): number { - return bot.controlState.sneak ? 1.27 : 1.62 + return bot.controlState.sneak && !this.isFlying() ? 1.27 : 1.62 } isOnGround (): boolean { diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 2afc7a242..7c9bb7b3a 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -81,6 +81,10 @@ export const guiOptionsScheme: { custom () { return Experimental }, + experimentalLightingV1: { + text: 'Experimental Lighting', + tooltip: 'Once stable this setting will be removed and always enabled', + }, smoothLighting: {}, lightingStrategy: { values: [ diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index 962559b07..8aca1da82 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -8,6 +8,9 @@ import { miscUiState } from './globalState' const isDev = process.env.NODE_ENV === 'development' const initialAppConfig = process.env?.INLINED_APP_CONFIG as AppConfig ?? {} +// todo +const IS_BETA_TESTER = location.hostname.startsWith('s.') || location.hostname.startsWith('beta.') + const defaultOptions = { renderDistance: 3, keepChunksDistance: 1, @@ -45,7 +48,9 @@ const defaultOptions = { /** @unstable */ debugLogNotFrequentPackets: false, unimplementedContainers: false, - dayCycleAndLighting: true, + dayCycle: true, + // experimentalLighting: IS_BETA_TESTER, + experimentalLightingV1: location.hostname.startsWith('lighting.'), loadPlayerSkins: true, renderEars: true, lowMemoryMode: false, @@ -170,6 +175,11 @@ export const disabledSettings = proxy({ }) const migrateOptions = (options: Partial>) => { + if (options.dayCycleAndLighting) { + delete options.dayCycleAndLighting + options.dayCycle = options.dayCycleAndLighting + } + if (options.highPerformanceGpu) { options.gpuPreference = 'high-performance' delete options.highPerformanceGpu diff --git a/src/react/DebugOverlay.tsx b/src/react/DebugOverlay.tsx index 56950db24..fb4feb194 100644 --- a/src/react/DebugOverlay.tsx +++ b/src/react/DebugOverlay.tsx @@ -129,17 +129,13 @@ export default () => { const freqUpdateInterval = setInterval(() => { const lightingEnabled = appViewer.inWorldRenderingConfig.enableLighting - const serverLighting = !appViewer.inWorldRenderingConfig.clientSideLighting - if (!lightingEnabled || serverLighting) { + const { clientSideLighting } = appViewer.inWorldRenderingConfig + if (!lightingEnabled) { setLightInfo({ sky: bot.world.getSkyLight(bot.entity.position), block: bot.world.getBlockLight(bot.entity.position), - info: lightingEnabled ? 'Server Lighting' : 'Lighting Disabled' + info: lightingEnabled ? clientSideLighting === 'none' ? 'Server Lighting' : 'Server + Client Engine' : 'Lighting Disabled' }) - } else { - // client engine is used - const lights = getDebugLightValues(Math.floor(bot.entity.position.x), Math.floor(bot.entity.position.y), Math.floor(bot.entity.position.z)) - setLightInfo({ sky: lights.skyLight, block: lights.blockLight, info: 'Client Light Engine' }) } setPos({ ...bot.entity.position }) diff --git a/src/watchOptions.ts b/src/watchOptions.ts index 42bb26f69..24e51a81b 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -96,16 +96,32 @@ export const watchOptionsAfterViewerInit = () => { const updateLightingStrategy = () => { if (!bot) return + if (!options.experimentalLightingV1) { + appViewer.inWorldRenderingConfig.clientSideLighting = 'none' + appViewer.inWorldRenderingConfig.enableLighting = false + appViewer.inWorldRenderingConfig.legacyLighting = true + return + } + + const lightingEnabled = options.dayCycle + if (!lightingEnabled) { + appViewer.inWorldRenderingConfig.clientSideLighting = 'none' + appViewer.inWorldRenderingConfig.enableLighting = false + return + } + + appViewer.inWorldRenderingConfig.legacyLighting = false + // for now ignore saved lighting to allow proper updates and singleplayer created worlds // appViewer.inWorldRenderingConfig.flyingSquidWorkarounds = miscUiState.flyingSquid const serverParsingSupported = miscUiState.flyingSquid ? /* !bot.supportFeature('blockStateId') */false : bot.supportFeature('blockStateId') - const serverLightingEnabled = serverParsingSupported && (options.lightingStrategy === 'prefer-server' || options.lightingStrategy === 'always-server') - const clientLightingEnabled = options.lightingStrategy === 'prefer-server' ? !serverParsingSupported : options.lightingStrategy === 'always-client' + const serverLightingPossible = serverParsingSupported && (options.lightingStrategy === 'prefer-server' || options.lightingStrategy === 'always-server') + const clientLightingPossible = options.lightingStrategy !== 'always-server' - const clientSideLighting = !serverLightingEnabled - appViewer.inWorldRenderingConfig.clientSideLighting = clientSideLighting - appViewer.inWorldRenderingConfig.enableLighting = options.dayCycleAndLighting && (clientLightingEnabled || serverLightingEnabled) + const clientSideLighting = !serverLightingPossible + appViewer.inWorldRenderingConfig.clientSideLighting = serverLightingPossible && clientLightingPossible ? 'partial' : clientSideLighting ? 'full' : 'none' + appViewer.inWorldRenderingConfig.enableLighting = serverLightingPossible || clientLightingPossible } subscribeKey(options, 'lightingStrategy', updateLightingStrategy) From c4b9c33a3bd3f6a12a3741409c967d938ea0ad6a Mon Sep 17 00:00:00 2001 From: Vitaly Date: Thu, 1 May 2025 15:26:22 +0300 Subject: [PATCH 15/22] Update src/optionsStorage.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- src/optionsStorage.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index 8aca1da82..f027ddf31 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -103,7 +103,12 @@ const defaultOptions = { showCursorBlockInSpectator: false, renderEntities: true, smoothLighting: true, - // lightingStrategy: 'prefer-server' as 'only-server' | 'always-client' | 'prefer-server', + /** + * Controls how lighting is calculated and rendered: + * - 'always-client': Always use client-side lighting engine for all light calculations + * - 'prefer-server': Use server lighting data when available, fallback to client-side calculations + * - 'always-server': Only use lighting data from the server, disable client-side calculations + */ lightingStrategy: 'prefer-server' as 'always-client' | 'prefer-server' | 'always-server', chatSelect: true, autoJump: 'auto' as 'auto' | 'always' | 'never', From d6f394fe204f80172a14ed7e74f9773abb188400 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 2 May 2025 12:20:25 +0300 Subject: [PATCH 16/22] hide cursor block in spectator --- src/mineflayer/plugins/mouse.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mineflayer/plugins/mouse.ts b/src/mineflayer/plugins/mouse.ts index 4e82b770f..fc1ce0fda 100644 --- a/src/mineflayer/plugins/mouse.ts +++ b/src/mineflayer/plugins/mouse.ts @@ -10,7 +10,7 @@ import { sendVideoInteraction, videoCursorInteraction } from '../../customChanne function cursorBlockDisplay (bot: Bot) { const updateCursorBlock = (data?: { block: Block }) => { - if (!data?.block) { + if (!data?.block || bot.game.gameMode === 'spectator') { playerState.reactive.lookingAtBlock = undefined return } @@ -27,6 +27,10 @@ function cursorBlockDisplay (bot: Bot) { } bot.on('highlightCursorBlock', updateCursorBlock) + bot.on('game', () => { + const block = bot.mouse.getCursorState().cursorBlock + updateCursorBlock(block ? { block } : undefined) + }) bot.on('blockBreakProgressStage', (block, stage) => { const mergedShape = bot.mouse.getMergedCursorShape(block) From ddf08107f2eaf834f85e22f0d19c77dd0b904a5b Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 4 May 2025 12:24:45 +0300 Subject: [PATCH 17/22] final step: move engine to another thread --- renderer/viewer/lib/lightEngine.ts | 48 +++++++++++++++------- renderer/viewer/lib/worldDataEmitter.ts | 22 ++++++---- renderer/viewer/lib/worldrendererCommon.ts | 6 +-- src/react/DebugOverlay.tsx | 24 +++++++---- src/shims/minecraftData.ts | 11 ++++- 5 files changed, 74 insertions(+), 37 deletions(-) diff --git a/renderer/viewer/lib/lightEngine.ts b/renderer/viewer/lib/lightEngine.ts index 23a0c1bb6..6e4f03419 100644 --- a/renderer/viewer/lib/lightEngine.ts +++ b/renderer/viewer/lib/lightEngine.ts @@ -1,15 +1,18 @@ -import { LightWorld, createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock } from 'minecraft-lighting' +import { LightWorld, createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock, createPrismarineLightEngineWorker } from 'minecraft-lighting' import { world } from 'prismarine-world' -import { WorldRendererCommon } from './worldrendererCommon' +// import PrismarineWorker from 'minecraft-lighting/dist/prismarineWorker.worker.js' import { WorldDataEmitter } from './worldDataEmitter' let lightEngine: LightWorld | null = null +let lightEngineNew: ReturnType | null = null + export const getLightEngine = () => { if (!lightEngine) throw new Error('Light engine not initialized') return lightEngine } export const getLightEngineSafe = () => { - return lightEngine + // return lightEngine + return lightEngineNew } export const createLightEngineIfNeeded = (worldView: WorldDataEmitter) => { @@ -25,7 +28,21 @@ export const createLightEngineIfNeeded = (worldView: WorldDataEmitter) => { globalThis.lightEngine = lightEngine } -export const processLightChunk = async (x: number, z: number) => { +export const createLightEngineIfNeededNew = (worldView: WorldDataEmitter) => { + if (lightEngineNew) return + const worker = new Worker(new URL('minecraft-lighting/dist/prismarineWorker.worker.js', import.meta.url)) + lightEngineNew = createPrismarineLightEngineWorker(worker, worldView.world as unknown as world.WorldSync, loadedData) + lightEngineNew.initialize({ + minY: worldView.minY, + height: worldView.minY + worldView.worldHeight, + // writeLightToOriginalWorld: true, + // enableSkyLight: false, + }) + + globalThis.lightEngine = lightEngineNew +} + +export const processLightChunk = async (x: number, z: number, doLighting: boolean) => { const engine = getLightEngineSafe() if (!engine) return @@ -33,21 +50,21 @@ export const processLightChunk = async (x: number, z: number) => { const chunkZ = Math.floor(z / 16) // fillColumnWithZeroLight(engine.externalWorld, chunkX, chunkZ) - const updated = engine.receiveUpdateColumn(chunkX, chunkZ) + const updated = await engine.loadChunk(chunkX, chunkZ, doLighting) return updated } export const dumpLightData = (x: number, z: number) => { const engine = getLightEngineSafe() - return engine?.worldLightHolder.dumpChunk(Math.floor(x / 16), Math.floor(z / 16)) + // return engine?.worldLightHolder.dumpChunk(Math.floor(x / 16), Math.floor(z / 16)) } export const getDebugLightValues = (x: number, y: number, z: number) => { const engine = getLightEngineSafe() - return { - blockLight: engine?.worldLightHolder.getBlockLight(x, y, z) ?? -1, - skyLight: engine?.worldLightHolder.getSkyLight(x, y, z) ?? -1, - } + // return { + // blockLight: engine?.worldLightHolder.getBlockLight(x, y, z) ?? -1, + // skyLight: engine?.worldLightHolder.getSkyLight(x, y, z) ?? -1, + // } } export const updateBlockLight = async (x: number, y: number, z: number, stateId: number, distance: number) => { @@ -56,10 +73,11 @@ export const updateBlockLight = async (x: number, y: number, z: number, stateId: const chunkZ = Math.floor(z / 16) * 16 const engine = getLightEngineSafe() if (!engine) return - const result = await engine.setBlockUpdateChunkIfNeeded(x, y, z) - if (!result) return - console.log(`[light engine] updateBlockLight (${x}, ${y}, ${z}) took`, Math.round(result.time), 'ms', result.affectedChunks?.length ?? 0, 'chunks') - return result.affectedChunks + const start = performance.now() + const result = await engine.setBlock(x, y, z, stateId) + const end = performance.now() + console.log(`[light engine] updateBlockLight (${x}, ${y}, ${z}) took`, Math.round(end - start), 'ms', result.length, 'chunks') + return result // const engine = getLightEngineSafe() // if (!engine) return @@ -79,7 +97,7 @@ export const updateBlockLight = async (x: number, y: number, z: number, stateId: export const lightRemoveColumn = (x: number, z: number) => { const engine = getLightEngineSafe() if (!engine) return - engine.columnCleanup(Math.floor(x / 16), Math.floor(z / 16)) + engine.unloadChunk(Math.floor(x / 16), Math.floor(z / 16)) } export const destroyLightEngine = () => { diff --git a/renderer/viewer/lib/worldDataEmitter.ts b/renderer/viewer/lib/worldDataEmitter.ts index 4b5039ddb..ee373da9b 100644 --- a/renderer/viewer/lib/worldDataEmitter.ts +++ b/renderer/viewer/lib/worldDataEmitter.ts @@ -9,7 +9,7 @@ import { proxy } from 'valtio' import TypedEmitter from 'typed-emitter' import { delayedIterator } from '../../playground/shared' import { chunkPos } from './simpleUtils' -import { createLightEngineIfNeeded, destroyLightEngine, lightRemoveColumn, processLightChunk, updateBlockLight } from './lightEngine' +import { createLightEngineIfNeededNew, destroyLightEngine, lightRemoveColumn, processLightChunk, updateBlockLight } from './lightEngine' import { WorldRendererConfig } from './worldrendererCommon' export type ChunkPosKey = string // like '16,16' @@ -160,7 +160,7 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter { @@ -297,7 +297,7 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter TypedEmitter - if (!isLightUpdate && this.worldRendererConfig.clientSideLighting === 'full') { - result = await processLightChunk(pos.x, pos.z) ?? [] + let result = [] as Array<{ chunkX: number, chunkZ: number }> + if (!isLightUpdate) { + const computeLighting = this.worldRendererConfig.clientSideLighting === 'full' + const promise = processLightChunk(pos.x, pos.z, computeLighting) + if (computeLighting) { + result = (await promise) ?? [] + } } if (!result) return for (const affectedChunk of result) { - if (affectedChunk.x === chunkX && affectedChunk.z === chunkZ) continue - const loadedChunk = this.loadedChunks[`${affectedChunk.x},${affectedChunk.z}`] + if (affectedChunk.chunkX === chunkX && affectedChunk.chunkZ === chunkZ) continue + const loadedChunk = this.loadedChunks[`${affectedChunk.chunkX * 16},${affectedChunk.chunkZ * 16}`] if (!loadedChunk) continue - void this.loadChunk(new Vec3(affectedChunk.x * 16, 0, affectedChunk.z * 16), true) + void this.loadChunk(new Vec3(affectedChunk.chunkX * 16, 0, affectedChunk.chunkZ * 16), true) } // const latency = Math.floor(performance.now() - this.lastTime) // this.debugGotChunkLatency.push(latency) diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts index 1e91a2d02..0bd5d093c 100644 --- a/renderer/viewer/lib/worldrendererCommon.ts +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -1,10 +1,8 @@ /* eslint-disable guard-for-in */ import { EventEmitter } from 'events' import { Vec3 } from 'vec3' -import * as THREE from 'three' import mcDataRaw from 'minecraft-data/data.js' // note: using alias import TypedEmitter from 'typed-emitter' -import { ItemsRenderer } from 'mc-assets/dist/itemsRenderer' import { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider' import { generateSpiralMatrix } from 'flying-squid/dist/utils' import { subscribeKey } from 'valtio/utils' @@ -16,10 +14,10 @@ import { SoundSystem } from '../three/threeJsSound' import { buildCleanupDecorator } from './cleanupDecorator' import { HighestBlockInfo, MesherGeometryOutput, CustomBlockModels, BlockStateModelInfo, getBlockAssetsCacheKey, MesherConfig } from './mesher/shared' import { chunkPos } from './simpleUtils' -import { addNewStat, removeAllStats, removeStat, updatePanesVisibility, updateStatText } from './ui/newStats' +import { addNewStat, removeAllStats, updatePanesVisibility, updateStatText } from './ui/newStats' import { WorldDataEmitter } from './worldDataEmitter' import { IPlayerState } from './basePlayerState' -import { createLightEngineIfNeeded, dumpLightData, getLightEngine, getLightEngineSafe } from './lightEngine' +import { dumpLightData } from './lightEngine' import { MesherLogReader } from './mesherlogReader' import { setSkinsConfig } from './utils/skins' diff --git a/src/react/DebugOverlay.tsx b/src/react/DebugOverlay.tsx index fb4feb194..268f73a77 100644 --- a/src/react/DebugOverlay.tsx +++ b/src/react/DebugOverlay.tsx @@ -1,7 +1,6 @@ import { useEffect, useRef, useState } from 'react' import type { Block } from 'prismarine-block' import { getThreeJsRendererMethods } from 'renderer/viewer/three/threeJsMethods' -import { getDebugLightValues } from 'renderer/viewer/lib/lightEngine' import { getFixedFilesize } from '../downloadAndOpenFile' import { options } from '../optionsStorage' import { BlockStateModelInfo } from '../../renderer/viewer/lib/mesher/shared' @@ -130,13 +129,24 @@ export default () => { const freqUpdateInterval = setInterval(() => { const lightingEnabled = appViewer.inWorldRenderingConfig.enableLighting const { clientSideLighting } = appViewer.inWorldRenderingConfig - if (!lightingEnabled) { - setLightInfo({ - sky: bot.world.getSkyLight(bot.entity.position), - block: bot.world.getBlockLight(bot.entity.position), - info: lightingEnabled ? clientSideLighting === 'none' ? 'Server Lighting' : 'Server + Client Engine' : 'Lighting Disabled' - }) + let info = '' + if (lightingEnabled) { + if (clientSideLighting === 'none') { + info = 'Server Lighting' + } else if (clientSideLighting === 'full') { + info = 'Client Engine' + } else { + info = 'Server + Client Engine' + } + } else { + info = 'Lighting Disabled' } + setLightInfo({ + sky: bot.world.getSkyLight(bot.entity.position), + block: bot.world.getBlockLight(bot.entity.position), + info + }) + setPos({ ...bot.entity.position }) setBiomeId(bot.world.getBiome(bot.entity.position)) diff --git a/src/shims/minecraftData.ts b/src/shims/minecraftData.ts index 989aa698f..88f871f01 100644 --- a/src/shims/minecraftData.ts +++ b/src/shims/minecraftData.ts @@ -1,9 +1,13 @@ import { versionToNumber } from 'renderer/viewer/common/utils' import { restoreMinecraftData } from '../optimizeJson' // import minecraftInitialDataJson from '../../generated/minecraft-initial-data.json' -import { toMajorVersion } from '../utils' import { importLargeData } from '../../generated/large-data-aliases' +const toMajorVersion = version => { + const [a, b] = (String(version)).split('.') + return `${a}.${b}` +} + const customResolver = () => { const resolver = Promise.withResolvers() let resolvedData @@ -19,6 +23,9 @@ const customResolver = () => { } } +//@ts-expect-error for workers using minecraft-data +globalThis.window ??= globalThis + const optimizedDataResolver = customResolver() window._MC_DATA_RESOLVER = optimizedDataResolver window._LOAD_MC_DATA = async () => { @@ -66,7 +73,7 @@ const possiblyGetFromCache = (version: string) => { cacheTime.set(version, Date.now()) return data } -window.allLoadedMcData = new Proxy({}, { +window.allLoadedMcData ??= new Proxy({}, { get (t, version: string) { // special properties like $typeof if (version.includes('$')) return From 5720cfaf3481d63b96bb090398b92f5a67430612 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 4 May 2025 12:25:47 +0300 Subject: [PATCH 18/22] up light --- package.json | 2 +- pnpm-lock.yaml | 30 ++++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index f106449fc..e39423887 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "https-browserify": "^1.0.0", "mc-assets": "^0.2.53", "minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next", - "minecraft-lighting": "^0.0.9", + "minecraft-lighting": "^0.0.10", "mineflayer": "github:zardoy/mineflayer#gen-the-master", "mineflayer-mouse": "^0.1.9", "mineflayer-pathfinder": "^2.4.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d77103dd8..3b9ee3593 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -340,8 +340,8 @@ importers: specifier: github:zardoy/minecraft-inventory-gui#next version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/98bc5bb8ee6da8b4b771c05b404cee796318ccd4(@types/react@18.3.18)(react@18.3.1) minecraft-lighting: - specifier: ^0.0.9 - version: 0.0.9 + specifier: ^0.0.10 + version: 0.0.10 mineflayer: specifier: github:zardoy/mineflayer#gen-the-master version: https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0(encoding@0.1.13) @@ -6691,8 +6691,8 @@ packages: resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/98bc5bb8ee6da8b4b771c05b404cee796318ccd4} version: 1.0.1 - minecraft-lighting@0.0.9: - resolution: {integrity: sha512-2ma3m3ia4YmcAFHlZ9BGo4CSVyXL2TltPoXZSeYHmgstGuZwECHzOMQOKjUEzCnQs11X9Rnqz9Dum+Y17bsbyA==} + minecraft-lighting@0.0.10: + resolution: {integrity: sha512-m3RNe5opaibquxyO0ly1FpKdehapvp9hRRY37RccKY4bio2LGnN3nCZ3PrOXy0C596YpxBsG1OCYg0dqtPzehg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/9e116c3dd4682b17c4e2c80249a2447a093d9284: @@ -7437,6 +7437,11 @@ packages: version: 1.38.1 engines: {node: '>=14'} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f} + version: 1.38.1 + engines: {node: '>=14'} + prismarine-entity@2.5.0: resolution: {integrity: sha512-nRPCawUwf9r3iKqi4I7mZRlir1Ix+DffWYdWq6p/KNnmiXve+xHE5zv8XCdhZlUmOshugHv5ONl9o6ORAkCNIA==} @@ -14632,7 +14637,7 @@ snapshots: diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/cfaad2d1d5909fdfa63c8cc7bc05fb5e87782d71: dependencies: minecraft-data: 3.83.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) prismarine-registry: 1.11.0 random-seed: 0.3.0 vec3: 0.1.10 @@ -17349,7 +17354,7 @@ snapshots: - '@types/react' - react - minecraft-lighting@0.0.9: + minecraft-lighting@0.0.10: dependencies: vec3: 0.1.10 @@ -18299,6 +18304,19 @@ snapshots: transitivePeerDependencies: - minecraft-data + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1): + dependencies: + prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 + prismarine-nbt: 2.7.0 + prismarine-registry: 1.11.0 + smart-buffer: 4.2.0 + uint4: 0.1.2 + vec3: 0.1.10 + xxhash-wasm: 0.4.2 + transitivePeerDependencies: + - minecraft-data + prismarine-entity@2.5.0: dependencies: prismarine-chat: 1.11.0 From e95f84e92c74e4aa900c76e4462c4d1b1bc43e4e Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 4 May 2025 12:26:15 +0300 Subject: [PATCH 19/22] fix lock --- pnpm-lock.yaml | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a2fd25cce..7b1d012e2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -136,7 +136,7 @@ importers: version: 4.17.21 mcraft-fun-mineflayer: specifier: ^0.1.23 - version: 0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6(encoding@0.1.13)) + version: 0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0(encoding@0.1.13)) minecraft-data: specifier: 3.83.1 version: 3.83.1 @@ -151,7 +151,7 @@ importers: version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify - version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/64e351867c5711de8a183464284a8eb7d77d5f39 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469 node-gzip: specifier: ^1.1.2 version: 1.1.2 @@ -344,7 +344,7 @@ importers: version: 0.0.10 mineflayer: specifier: github:zardoy/mineflayer#gen-the-master - version: https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6(encoding@0.1.13) + version: https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0(encoding@0.1.13) mineflayer-mouse: specifier: ^0.1.10 version: 0.1.10(@types/debug@4.1.12)(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0) @@ -438,7 +438,7 @@ importers: version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 prismarine-chunk: specifier: github:zardoy/prismarine-chunk#master - version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) + version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-schematic: specifier: ^1.2.0 version: 1.2.3 @@ -6722,8 +6722,8 @@ packages: resolution: {integrity: sha512-3bxph4jfbkBh5HpeouorxzrfSLNV+i+1gugNJ2jf52HW+rt+tW7eiiFPxrJEsOVkPT/3O/dEIW7j93LRlojMkQ==} engines: {node: '>=22'} - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6: - resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6} + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0} version: 4.27.0 engines: {node: '>=22'} @@ -6886,8 +6886,8 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/64e351867c5711de8a183464284a8eb7d77d5f39: - resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/64e351867c5711de8a183464284a8eb7d77d5f39} + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469} version: 0.2.4 nice-try@1.0.5: @@ -7432,8 +7432,8 @@ packages: prismarine-chat@1.11.0: resolution: {integrity: sha512-VJT/MWYB3qoiznUhrgvSQh76YFpzpCZpY85kJKxHLbd3UVoM0wsfs43Eg8dOltiZG92wc5/DTMLlT07TEeoa9w==} - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5} version: 1.38.1 engines: {node: '>=14'} @@ -13206,7 +13206,7 @@ snapshots: mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -13242,7 +13242,7 @@ snapshots: mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -17031,12 +17031,12 @@ snapshots: maxrects-packer: '@zardoy/maxrects-packer@2.7.4' zod: 3.24.2 - mcraft-fun-mineflayer@0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6(encoding@0.1.13)): + mcraft-fun-mineflayer@0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0(encoding@0.1.13)): dependencies: '@zardoy/flying-squid': 0.0.49(encoding@0.1.13) exit-hook: 2.2.1 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/9e116c3dd4682b17c4e2c80249a2447a093d9284(patch_hash=3a55a278c417cc34ff3172cd1de8e22852935cba0586875cbd0635f1ffdaa5ab)(encoding@0.1.13) - mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6(encoding@0.1.13) + mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0(encoding@0.1.13) prismarine-item: 1.16.0 ws: 8.18.1 transitivePeerDependencies: @@ -17461,7 +17461,7 @@ snapshots: prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 prismarine-chat: 1.11.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -17477,7 +17477,7 @@ snapshots: - encoding - supports-color - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6(encoding@0.1.13): + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0(encoding@0.1.13): dependencies: '@nxg-org/mineflayer-physics-util': 1.8.7 minecraft-data: 3.83.1 @@ -17485,7 +17485,7 @@ snapshots: prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 prismarine-chat: 1.11.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -17681,7 +17681,7 @@ snapshots: neo-async@2.6.2: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/64e351867c5711de8a183464284a8eb7d77d5f39: + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469: dependencies: body-parser: 1.20.3 express: 4.21.2 @@ -18291,7 +18291,7 @@ snapshots: prismarine-nbt: 2.7.0 prismarine-registry: 1.11.0 - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1): + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 @@ -18342,7 +18342,7 @@ snapshots: prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.83.1): dependencies: prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) prismarine-nbt: 2.7.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c uint4: 0.1.2 From 90de0d0be1c1015c046b7cd14f32bcb25ac08ba0 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 4 May 2025 12:27:30 +0300 Subject: [PATCH 20/22] up chunk? --- pnpm-lock.yaml | 52 +++++++++++++++++--------------------------------- 1 file changed, 17 insertions(+), 35 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7b1d012e2..704a6819d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -136,7 +136,7 @@ importers: version: 4.17.21 mcraft-fun-mineflayer: specifier: ^0.1.23 - version: 0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0(encoding@0.1.13)) + version: 0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6(encoding@0.1.13)) minecraft-data: specifier: 3.83.1 version: 3.83.1 @@ -151,7 +151,7 @@ importers: version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify - version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/64e351867c5711de8a183464284a8eb7d77d5f39 node-gzip: specifier: ^1.1.2 version: 1.1.2 @@ -344,7 +344,7 @@ importers: version: 0.0.10 mineflayer: specifier: github:zardoy/mineflayer#gen-the-master - version: https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0(encoding@0.1.13) + version: https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6(encoding@0.1.13) mineflayer-mouse: specifier: ^0.1.10 version: 0.1.10(@types/debug@4.1.12)(@types/node@22.13.9)(jiti@2.4.2)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0) @@ -438,7 +438,7 @@ importers: version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 prismarine-chunk: specifier: github:zardoy/prismarine-chunk#master - version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) + version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) prismarine-schematic: specifier: ^1.2.0 version: 1.2.3 @@ -6722,8 +6722,8 @@ packages: resolution: {integrity: sha512-3bxph4jfbkBh5HpeouorxzrfSLNV+i+1gugNJ2jf52HW+rt+tW7eiiFPxrJEsOVkPT/3O/dEIW7j93LRlojMkQ==} engines: {node: '>=22'} - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0: - resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0} + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6} version: 4.27.0 engines: {node: '>=22'} @@ -6886,8 +6886,8 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469: - resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469} + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/64e351867c5711de8a183464284a8eb7d77d5f39: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/64e351867c5711de8a183464284a8eb7d77d5f39} version: 0.2.4 nice-try@1.0.5: @@ -7432,11 +7432,6 @@ packages: prismarine-chat@1.11.0: resolution: {integrity: sha512-VJT/MWYB3qoiznUhrgvSQh76YFpzpCZpY85kJKxHLbd3UVoM0wsfs43Eg8dOltiZG92wc5/DTMLlT07TEeoa9w==} - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5} - version: 1.38.1 - engines: {node: '>=14'} - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f: resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f} version: 1.38.1 @@ -13206,7 +13201,7 @@ snapshots: mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -13242,7 +13237,7 @@ snapshots: mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -17031,12 +17026,12 @@ snapshots: maxrects-packer: '@zardoy/maxrects-packer@2.7.4' zod: 3.24.2 - mcraft-fun-mineflayer@0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0(encoding@0.1.13)): + mcraft-fun-mineflayer@0.1.23(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6(encoding@0.1.13)): dependencies: '@zardoy/flying-squid': 0.0.49(encoding@0.1.13) exit-hook: 2.2.1 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/9e116c3dd4682b17c4e2c80249a2447a093d9284(patch_hash=3a55a278c417cc34ff3172cd1de8e22852935cba0586875cbd0635f1ffdaa5ab)(encoding@0.1.13) - mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0(encoding@0.1.13) + mineflayer: https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6(encoding@0.1.13) prismarine-item: 1.16.0 ws: 8.18.1 transitivePeerDependencies: @@ -17461,7 +17456,7 @@ snapshots: prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 prismarine-chat: 1.11.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -17477,7 +17472,7 @@ snapshots: - encoding - supports-color - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/aadfaaff1f55447a4d20e3ffb34db52791d9b1e0(encoding@0.1.13): + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/5602eca4174c0aff079e60234d7c68327eeb6fe6(encoding@0.1.13): dependencies: '@nxg-org/mineflayer-physics-util': 1.8.7 minecraft-data: 3.83.1 @@ -17485,7 +17480,7 @@ snapshots: prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 prismarine-chat: 1.11.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) prismarine-entity: 2.5.0 prismarine-item: 1.16.0 prismarine-nbt: 2.7.0 @@ -17681,7 +17676,7 @@ snapshots: neo-async@2.6.2: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/356edb3b061be0753f53fc2cf7fa995d40d05469: + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/64e351867c5711de8a183464284a8eb7d77d5f39: dependencies: body-parser: 1.20.3 express: 4.21.2 @@ -18291,19 +18286,6 @@ snapshots: prismarine-nbt: 2.7.0 prismarine-registry: 1.11.0 - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1): - dependencies: - prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 - prismarine-nbt: 2.7.0 - prismarine-registry: 1.11.0 - smart-buffer: 4.2.0 - uint4: 0.1.2 - vec3: 0.1.10 - xxhash-wasm: 0.4.2 - transitivePeerDependencies: - - minecraft-data - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.11.0) @@ -18342,7 +18324,7 @@ snapshots: prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/1d548fac63fe977c8281f0a9a522b37e4d92d0b7(minecraft-data@3.83.1): dependencies: prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/853c559bff2b402863ee9a75b125a3ca320838f9 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/47e0e5b7ff7759b8d222de7746f71023df7ce8e5(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/c5feac83b61d95feb4d4f22c063dacfb8c192a9f(minecraft-data@3.83.1) prismarine-nbt: 2.7.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/ab2146c9933eef3247c3f64446de4ccc2c484c7c uint4: 0.1.2 From f185df993f9a4f327db7747bcade1859dd586449 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 8 May 2025 20:28:00 +0300 Subject: [PATCH 21/22] fix remaining issues with worker bundle with smart approach todo: fix chunks not receive skylight, recompute fix skylight values desync time --- renderer/viewer/lib/lightEngine.ts | 31 +++------ renderer/viewer/lib/mesher/mesher.ts | 10 +++ renderer/viewer/lib/worldDataEmitter.ts | 4 +- renderer/viewer/lib/worldrendererCommon.ts | 73 +++++++++++++--------- 4 files changed, 67 insertions(+), 51 deletions(-) diff --git a/renderer/viewer/lib/lightEngine.ts b/renderer/viewer/lib/lightEngine.ts index 6e4f03419..35bb1e471 100644 --- a/renderer/viewer/lib/lightEngine.ts +++ b/renderer/viewer/lib/lightEngine.ts @@ -1,36 +1,23 @@ -import { LightWorld, createLightEngineForSyncWorld, convertPrismarineBlockToWorldBlock, createPrismarineLightEngineWorker } from 'minecraft-lighting' +import { createPrismarineLightEngineWorker } from 'minecraft-lighting' import { world } from 'prismarine-world' // import PrismarineWorker from 'minecraft-lighting/dist/prismarineWorker.worker.js' import { WorldDataEmitter } from './worldDataEmitter' +import { initMesherWorker, meshersSendMcData } from './worldrendererCommon' -let lightEngine: LightWorld | null = null let lightEngineNew: ReturnType | null = null -export const getLightEngine = () => { - if (!lightEngine) throw new Error('Light engine not initialized') - return lightEngine -} export const getLightEngineSafe = () => { // return lightEngine return lightEngineNew } -export const createLightEngineIfNeeded = (worldView: WorldDataEmitter) => { - if (lightEngine) return - lightEngine = createLightEngineForSyncWorld(worldView.world as unknown as world.WorldSync, loadedData, { - minY: worldView.minY, - height: worldView.minY + worldView.worldHeight, - // writeLightToOriginalWorld: true, - // enableSkyLight: false, - }) - lightEngine.externalWorld.setBlock = () => {} - lightEngine.PARALLEL_CHUNK_PROCESSING = false - globalThis.lightEngine = lightEngine -} - -export const createLightEngineIfNeededNew = (worldView: WorldDataEmitter) => { +export const createLightEngineIfNeededNew = (worldView: WorldDataEmitter, version: string) => { if (lightEngineNew) return - const worker = new Worker(new URL('minecraft-lighting/dist/prismarineWorker.worker.js', import.meta.url)) + const worker = initMesherWorker((data) => { + // console.log('light engine worker message', data) + }) + meshersSendMcData([worker], version) + worker.postMessage({ type: 'sideControl', value: 'lightEngine' }) lightEngineNew = createPrismarineLightEngineWorker(worker, worldView.world as unknown as world.WorldSync, loadedData) lightEngineNew.initialize({ minY: worldView.minY, @@ -101,6 +88,6 @@ export const lightRemoveColumn = (x: number, z: number) => { } export const destroyLightEngine = () => { - lightEngine = null + lightEngineNew = null globalThis.lightEngine = null } diff --git a/renderer/viewer/lib/mesher/mesher.ts b/renderer/viewer/lib/mesher/mesher.ts index 3f06d60d4..a656fc89e 100644 --- a/renderer/viewer/lib/mesher/mesher.ts +++ b/renderer/viewer/lib/mesher/mesher.ts @@ -71,7 +71,10 @@ const softCleanup = () => { globalThis.world = world } +let sideControl = false const handleMessage = data => { + if (sideControl) return + const globalVar: any = globalThis if (data.type === 'mcData') { @@ -92,6 +95,13 @@ const handleMessage = data => { } switch (data.type) { + case 'sideControl': { + if (data.value === 'lightEngine') { + sideControl = true + import('minecraft-lighting/dist/prismarineWorker.worker.js') + } + break + } case 'mesherData': { setMesherData(data.blockstatesModels, data.blocksAtlas, data.config.outputFormat === 'webgpu') allDataReady = true diff --git a/renderer/viewer/lib/worldDataEmitter.ts b/renderer/viewer/lib/worldDataEmitter.ts index ee373da9b..45227cdb4 100644 --- a/renderer/viewer/lib/worldDataEmitter.ts +++ b/renderer/viewer/lib/worldDataEmitter.ts @@ -40,6 +40,7 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter @@ -99,6 +100,7 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter() bot._client.prependListener('spawn_entity', (data) => { if (data.objectData && data.entityId !== undefined) { @@ -297,7 +299,7 @@ export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter initWorkers (numWorkers = this.worldRendererConfig.mesherWorkers) { // init workers for (let i = 0; i < numWorkers + 1; i++) { - // Node environment needs an absolute path, but browser needs the url of the file - const workerName = 'mesher.js' - // eslint-disable-next-line node/no-path-concat - const src = typeof window === 'undefined' ? `${__dirname}/${workerName}` : workerName - - let worker: any - if (process.env.SINGLE_FILE_BUILD) { - const workerCode = document.getElementById('mesher-worker-code')!.textContent! - const blob = new Blob([workerCode], { type: 'text/javascript' }) - worker = new Worker(window.URL.createObjectURL(blob)) - } else { - worker = new Worker(src) - } - - worker.onmessage = ({ data }) => { + const worker = initMesherWorker((data) => { if (Array.isArray(data)) { this.messageQueue.push(...data) } else { this.messageQueue.push(data) } void this.processMessageQueue('worker') - } - if (worker.on) worker.on('message', (data) => { worker.onmessage({ data }) }) + }) this.workers.push(worker) } } @@ -567,17 +552,13 @@ export abstract class WorldRendererCommon } sendMesherMcData () { - const allMcData = mcDataRaw.pc[this.version] ?? mcDataRaw.pc[toMajorVersion(this.version)] - const mcData = { - version: JSON.parse(JSON.stringify(allMcData.version)) - } - for (const key of dynamicMcDataFiles) { - mcData[key] = allMcData[key] - } - - for (const worker of this.workers) { - worker.postMessage({ type: 'mcData', mcData, config: this.getMesherConfig() }) - } + meshersSendMcData( + this.workers, + this.version, + { + config: this.getMesherConfig() + } + ) this.logWorkerWork('# mcData sent') } @@ -1008,3 +989,39 @@ export abstract class WorldRendererCommon this.displayOptions.worldView.destroy() } } + +export const initMesherWorker = (onGotMessage: (data: any) => void) => { + // Node environment needs an absolute path, but browser needs the url of the file + const workerName = 'mesher.js' + // eslint-disable-next-line node/no-path-concat + const src = typeof window === 'undefined' ? `${__dirname}/${workerName}` : workerName + + let worker: any + if (process.env.SINGLE_FILE_BUILD) { + const workerCode = document.getElementById('mesher-worker-code')!.textContent! + const blob = new Blob([workerCode], { type: 'text/javascript' }) + worker = new Worker(window.URL.createObjectURL(blob)) + } else { + worker = new Worker(src) + } + + worker.onmessage = ({ data }) => { + onGotMessage(data) + } + if (worker.on) worker.on('message', (data) => { worker.onmessage({ data }) }) + return worker +} + +export const meshersSendMcData = (workers: Worker[], version: string, addData = {} as Record) => { + const allMcData = mcDataRaw.pc[version] ?? mcDataRaw.pc[toMajorVersion(version)] + const mcData = { + version: JSON.parse(JSON.stringify(allMcData.version)) + } + for (const key of dynamicMcDataFiles) { + mcData[key] = allMcData[key] + } + + for (const worker of workers) { + worker.postMessage({ type: 'mcData', mcData, ...addData }) + } +} From 6a8d15b638e776b0b92c0ce14628d18c1da671d1 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 14 Jul 2025 06:40:00 +0300 Subject: [PATCH 22/22] [deploy] properly destroy world view --- renderer/viewer/lib/worldDataEmitter.ts | 4 ++++ renderer/viewer/lib/worldrendererCommon.ts | 2 +- src/appViewer.ts | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/renderer/viewer/lib/worldDataEmitter.ts b/renderer/viewer/lib/worldDataEmitter.ts index b66554a38..5edb9dc48 100644 --- a/renderer/viewer/lib/worldDataEmitter.ts +++ b/renderer/viewer/lib/worldDataEmitter.ts @@ -34,6 +34,10 @@ export type WorldDataEmitterEvents = { export class WorldDataEmitterWorker extends (EventEmitter as new () => TypedEmitter) { static readonly restorerName = 'WorldDataEmitterWorker' + + destroy () { + this.removeAllListeners() + } } export class WorldDataEmitter extends (EventEmitter as new () => TypedEmitter) { diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts index 4112b570c..046e1a1a1 100644 --- a/renderer/viewer/lib/worldrendererCommon.ts +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -569,7 +569,7 @@ export abstract class WorldRendererCommon getMesherConfig (): MesherConfig { return { version: this.version, - enableLighting: this.worldRendererConfig.enableLighting && !this.playerState.lightingDisabled, + enableLighting: this.worldRendererConfig.enableLighting && !this.playerStateReactive.lightingDisabled, skyLight: this.skyLight, smoothLighting: this.worldRendererConfig.smoothLighting, outputFormat: this.outputFormat, diff --git a/src/appViewer.ts b/src/appViewer.ts index 518791758..47201b696 100644 --- a/src/appViewer.ts +++ b/src/appViewer.ts @@ -261,6 +261,7 @@ export class AppViewer { if (cleanState) { this.currentState = undefined this.currentDisplay = null + this.worldView?.destroy() this.worldView = undefined } if (this.backend) {