diff --git a/package.json b/package.json index ed9cbec1..66e074cb 100644 --- a/package.json +++ b/package.json @@ -150,7 +150,7 @@ "http-browserify": "^1.7.0", "http-server": "^14.1.1", "https-browserify": "^1.0.0", - "mc-assets": "^0.2.48", + "mc-assets": "^0.2.49", "mineflayer-mouse": "^0.1.7", "minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next", "mineflayer": "github:zardoy/mineflayer", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f673776..a419da1d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -353,11 +353,11 @@ importers: specifier: ^1.0.0 version: 1.0.0 mc-assets: - specifier: ^0.2.48 - version: 0.2.48 + specifier: ^0.2.49 + version: 0.2.49 minecraft-inventory-gui: specifier: github:zardoy/minecraft-inventory-gui#next - version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/69dee6aa15f7c8a6df2a2ab01972e6a7b2f9ee30(@types/react@18.2.20)(react@18.2.0) + version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/f57dd78ca8e3b7cdd724d4272d8cbf6743b0cf00(@types/react@18.2.20)(react@18.2.0) mineflayer: specifier: github:zardoy/mineflayer version: https://codeload.github.com/zardoy/mineflayer/tar.gz/06e3050ddf4d9aa655fea6e2bed182937a81705d(encoding@0.1.13) @@ -6694,8 +6694,8 @@ packages: maxrects-packer@2.7.3: resolution: {integrity: sha512-bG6qXujJ1QgttZVIH4WDanhoJtvbud/xP/XPyf6A69C9RdA61BM4TomFALCq2nrTa+tARRIBB4LuIFsnUQU2wA==} - mc-assets@0.2.48: - resolution: {integrity: sha512-ixFBAkdWuluBZ3RhWXvD+KyLX5jKAK8ksXJamAuJxc7nXHP6xK5rEAR3qQ7JVYh27USl3mE+GWTFy/aF0CGRYg==} + mc-assets@0.2.49: + resolution: {integrity: sha512-pFR43FqG1bxiQVLXX8c4LNA/7wcFRGDFFclsBM6tY8tKFNolKhwiSaLmV0xtFHEF6SZGv9g2hkMqxsbAzMD/6A==} engines: {node: '>=18.0.0'} mcraft-fun-mineflayer@0.1.14: @@ -6912,8 +6912,8 @@ packages: minecraft-folder-path@1.2.0: resolution: {integrity: sha512-qaUSbKWoOsH9brn0JQuBhxNAzTDMwrOXorwuRxdJKKKDYvZhtml+6GVCUrY5HRiEsieBEjCUnhVpDuQiKsiFaw==} - minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/69dee6aa15f7c8a6df2a2ab01972e6a7b2f9ee30: - resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/69dee6aa15f7c8a6df2a2ab01972e6a7b2f9ee30} + minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/f57dd78ca8e3b7cdd724d4272d8cbf6743b0cf00: + resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/f57dd78ca8e3b7cdd724d4272d8cbf6743b0cf00} version: 1.0.1 minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/3bd4dc1b2002cd7badfa5b9cf8dda35cd6cc9ac1: @@ -17605,7 +17605,7 @@ snapshots: maxrects-packer@2.7.3: {} - mc-assets@0.2.48: + mc-assets@0.2.49: dependencies: maxrects-packer: 2.7.3 zod: 3.24.1 @@ -17922,7 +17922,7 @@ snapshots: minecraft-folder-path@1.2.0: {} - minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/69dee6aa15f7c8a6df2a2ab01972e6a7b2f9ee30(@types/react@18.2.20)(react@18.2.0): + minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/f57dd78ca8e3b7cdd724d4272d8cbf6743b0cf00(@types/react@18.2.20)(react@18.2.0): dependencies: valtio: 1.11.2(@types/react@18.2.20)(react@18.2.0) transitivePeerDependencies: diff --git a/renderer/viewer/lib/guiRenderer.ts b/renderer/viewer/lib/guiRenderer.ts index bdfd805c..2689126e 100644 --- a/renderer/viewer/lib/guiRenderer.ts +++ b/renderer/viewer/lib/guiRenderer.ts @@ -11,6 +11,7 @@ import { getItemDefinition } from 'mc-assets/dist/itemDefinitions' export const activeGuiAtlas = proxy({ atlas: null as null | { json, image }, + version: 0 }) export const getNonFullBlocksModels = () => { @@ -278,5 +279,6 @@ export const generateGuiAtlas = async () => { const itemImages = await generateItemsGui(itemsModelsResolved, true) console.timeEnd('generate items gui atlas') await generateAtlas({ ...blockImages, ...itemImages }) + activeGuiAtlas.version++ // await generateAtlas(blockImages) } diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts index 8d89c6b7..c0a0ff8d 100644 --- a/renderer/viewer/lib/worldrendererCommon.ts +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -183,7 +183,7 @@ export abstract class WorldRendererCommon }) if (this.wasChunkSentToWorker(chunkKey)) { const [x, y, z] = blockPos.split(',').map(Number) - this.setBlockStateId(new Vec3(x, y, z), undefined, false) + this.setBlockStateId(new Vec3(x, y, z), undefined) } } @@ -722,7 +722,7 @@ export abstract class WorldRendererCommon abstract worldStop? () queueAwaited = false - messagesQueue = {} as { [workerIndex: string]: any[] } + toWorkerMessagesQueue = {} as { [workerIndex: string]: any[] } getWorkerNumber (pos: Vec3, updateAction = false) { if (updateAction) { @@ -749,8 +749,8 @@ export abstract class WorldRendererCommon // is always dispatched to the same worker const hash = this.getWorkerNumber(pos, useChangeWorker) this.sectionsWaiting.set(key, (this.sectionsWaiting.get(key) ?? 0) + 1) - this.messagesQueue[hash] ??= [] - this.messagesQueue[hash].push({ + this.toWorkerMessagesQueue[hash] ??= [] + this.toWorkerMessagesQueue[hash].push({ // this.workers[hash].postMessage({ type: 'dirty', x: pos.x, @@ -767,11 +767,11 @@ export abstract class WorldRendererCommon this.queueAwaited = true setTimeout(() => { // group messages and send as one - for (const workerIndex in this.messagesQueue) { + for (const workerIndex in this.toWorkerMessagesQueue) { const worker = this.workers[Number(workerIndex)] - worker.postMessage(this.messagesQueue[workerIndex]) + worker.postMessage(this.toWorkerMessagesQueue[workerIndex]) } - this.messagesQueue = {} + this.toWorkerMessagesQueue = {} this.queueAwaited = false }) } diff --git a/renderer/viewer/three/panorama.ts b/renderer/viewer/three/panorama.ts index 8f79ff54..682d25d2 100644 --- a/renderer/viewer/three/panorama.ts +++ b/renderer/viewer/three/panorama.ts @@ -124,7 +124,7 @@ export class PanoramaRenderer { async worldBlocksPanorama () { const version = '1.21.4' - this.options.resourcesManager.currentConfig = { version } + this.options.resourcesManager.currentConfig = { version, noInventoryGui: true, } await this.options.resourcesManager.updateAssetsData({ }) if (this.abortController.signal.aborted) return console.time('load panorama scene') diff --git a/renderer/viewer/three/worldrendererThree.ts b/renderer/viewer/three/worldrendererThree.ts index 25a5afb4..e705b2d1 100644 --- a/renderer/viewer/three/worldrendererThree.ts +++ b/renderer/viewer/three/worldrendererThree.ts @@ -299,20 +299,6 @@ export class WorldRendererThree extends WorldRendererCommon { // this.debugRecomputedDeletedObjects++ // } - // if (!this.initialChunksLoad && this.enableChunksLoadDelay) { - // const newPromise = new Promise(resolve => { - // if (this.droppedFpsPercentage > 0.5) { - // setTimeout(resolve, 1000 / 50 * this.droppedFpsPercentage) - // } else { - // setTimeout(resolve) - // } - // }) - // this.promisesQueue.push(newPromise) - // for (const promise of this.promisesQueue) { - // await promise - // } - // } - const geometry = new THREE.BufferGeometry() geometry.setAttribute('position', new THREE.BufferAttribute(data.geometry.positions, 3)) geometry.setAttribute('normal', new THREE.BufferAttribute(data.geometry.normals, 3)) diff --git a/src/index.ts b/src/index.ts index d48429a2..623a88ac 100644 --- a/src/index.ts +++ b/src/index.ts @@ -702,6 +702,7 @@ export async function connect (connectOptions: ConnectOptions) { } }) }) + await appViewer.resourcesManager.promiseAssetsReady } console.log('try to focus window') window.focus?.() diff --git a/src/inventoryWindows.ts b/src/inventoryWindows.ts index e3808152..30299cf6 100644 --- a/src/inventoryWindows.ts +++ b/src/inventoryWindows.ts @@ -119,12 +119,13 @@ export const onGameLoad = () => { if (!appViewer.resourcesManager['_inventoryChangeTracked']) { appViewer.resourcesManager['_inventoryChangeTracked'] = true - const upWindowItems = () => { + const texturesChanged = () => { if (!lastWindow) return upWindowItemsLocal() + upJei(lastJeiSearch) } - appViewer.resourcesManager.on('assetsInventoryReady', () => upWindowItems()) - appViewer.resourcesManager.on('assetsTexturesUpdated', () => upWindowItems()) + appViewer.resourcesManager.on('assetsInventoryReady', () => texturesChanged()) + appViewer.resourcesManager.on('assetsTexturesUpdated', () => texturesChanged()) } } @@ -176,6 +177,7 @@ const getImage = ({ path = undefined as string | undefined, texture = undefined export type ResolvedItemModelRender = { modelName: string, + originalItemName?: string } export const renderSlot = (model: ResolvedItemModelRender, debugIsQuickbar = false, fullBlockModelSupport = false): { @@ -200,7 +202,8 @@ export const renderSlot = (model: ResolvedItemModelRender, debugIsQuickbar = fal if (!fullBlockModelSupport) { const atlas = activeGuiAtlas.atlas?.json // todo atlas holds all rendered blocks, not all possibly rendered item/block models, need to request this on demand instead (this is how vanilla works) - const item = atlas?.textures[itemModelName.replace('minecraft:', '').replace('block/', '').replace('blocks/', '').replace('item/', '').replace('items/', '').replace('_inventory', '').replace('_bottom', '').replace('_height2', '').replace('_stable', '').replace('_unstable', '')] + const tryGetAtlasTexture = (name?: string) => name && atlas?.textures[name.replace('minecraft:', '').replace('block/', '').replace('blocks/', '').replace('item/', '').replace('items/', '').replace('_inventory', '')] + const item = tryGetAtlasTexture(itemModelName) ?? tryGetAtlasTexture(model.originalItemName) if (item) { const x = item.u * atlas.width const y = item.v * atlas.height @@ -217,6 +220,7 @@ export const renderSlot = (model: ResolvedItemModelRender, debugIsQuickbar = fal assertDefined(appViewer.resourcesManager.currentResources?.itemsRenderer) itemTexture = appViewer.resourcesManager.currentResources.itemsRenderer.getItemTexture(itemModelName, {}, false, fullBlockModelSupport) + ?? (model.originalItemName ? appViewer.resourcesManager.currentResources.itemsRenderer.getItemTexture(model.originalItemName, {}, false, fullBlockModelSupport) : undefined) ?? appViewer.resourcesManager.currentResources.itemsRenderer.getItemTexture('item/missing_texture')! } catch (err) { inGameError(`Failed to render item ${itemModelName} (original: ${originalItemName}) on ${bot.version} (resourcepack: ${options.enabledResourcepack}): ${err.stack}`) @@ -249,20 +253,29 @@ const getItemName = (slot: Item | RenderItem | null) => { return text.join('') } -let lastMappedSots = [] as any[] +let lastMappedSlots = [] as any[] const itemToVisualKey = (slot: RenderItem | Item | null) => { - if (!slot) return null - return slot.name + slot['count'] + (slot['metadata'] ?? '-') + (slot.nbt ? JSON.stringify(slot.nbt) : '') + (slot['components'] ? JSON.stringify(slot['components']) : '') + if (!slot) return '' + const keys = [ + slot.name, + slot['count'], + slot['metadata'], + slot.nbt ? JSON.stringify(slot.nbt) : '', + slot['components'] ? JSON.stringify(slot['components']) : '', + activeGuiAtlas.version, + ].join('|') + return keys } const mapSlots = (slots: Array, isJei = false) => { const newSlots = slots.map((slot, i) => { - // todo stateid - if (!slot) return + if (!slot) return null if (!isJei) { - const oldKey = itemToVisualKey(lastMappedSots[i]) - if (oldKey && oldKey === itemToVisualKey(slot)) { - return lastMappedSots[i] + const oldKey = lastMappedSlots[i]?.cacheKey + const newKey = itemToVisualKey(slot) + slot['cacheKey'] = newKey + if (oldKey && oldKey === newKey) { + return lastMappedSlots[i] } } @@ -270,7 +283,7 @@ const mapSlots = (slots: Array, isJei = false) => { if (slot.durabilityUsed && slot.maxDurability) slot.durabilityUsed = Math.min(slot.durabilityUsed, slot.maxDurability) const debugIsQuickbar = !isJei && i === bot.inventory.hotbarStart + bot.quickBarSlot const modelName = getItemModelName(slot, { 'minecraft:display_context': 'gui', }, appViewer.resourcesManager) - const slotCustomProps = renderSlot({ modelName }, debugIsQuickbar) + const slotCustomProps = renderSlot({ modelName, originalItemName: slot.name }, debugIsQuickbar) const itemCustomName = getItemName(slot) Object.assign(slot, { ...slotCustomProps, displayName: itemCustomName ?? slot.displayName }) //@ts-expect-error @@ -285,7 +298,7 @@ const mapSlots = (slots: Array, isJei = false) => { } return slot }) - lastMappedSots = newSlots + lastMappedSlots = newSlots return newSlots } @@ -331,7 +344,9 @@ const implementedContainersGuiMap = { 'minecraft:villager': 'VillagerWin', } +let lastJeiSearch = '' const upJei = (search: string) => { + lastJeiSearch = search search = search.toLowerCase() // todo fix pre flat const itemsArray = [ diff --git a/src/resourcesManager.ts b/src/resourcesManager.ts index 5b3f403b..d4c1fe81 100644 --- a/src/resourcesManager.ts +++ b/src/resourcesManager.ts @@ -51,6 +51,7 @@ export interface ResourcesCurrentConfig { version: string texturesVersion?: string noBlockstatesModels?: boolean + noInventoryGui?: boolean includeOnlyBlocks?: string[] } @@ -58,6 +59,7 @@ export interface UpdateAssetsRequest { _?: false } +const STABLE_MODELS_VERSION = '1.21.4' export class ResourcesManager extends (EventEmitter as new () => TypedEmitter) { // Source data (imported, not changing) sourceBlockStatesModels: any = null @@ -69,6 +71,10 @@ export class ResourcesManager extends (EventEmitter as new () => TypedEmitter() + get promiseAssetsReady () { + return this._promiseAssetsReadyResolvers.promise + } async loadMcData (version: string) { await loadMinecraftData(version) @@ -85,6 +91,7 @@ export class ResourcesManager extends (EventEmitter as new () => TypedEmitter TypedEmitter TypedEmitter { - this.emit('assetsInventoryReady') + if (abortController.signal.aborted) return + if (!unstableSkipEvent) { + this.emit('assetsInventoryReady') + } + this._promiseAssetsReadyResolvers.resolve() }) } }