From b3d932f512291c9c7020d254aca144842ba99a28 Mon Sep 17 00:00:00 2001 From: Phoenix616 Date: Fri, 10 Jan 2025 15:04:03 +0100 Subject: [PATCH 01/11] Item Frame support --- prismarine-viewer/viewer/lib/entities.ts | 154 ++++++++++++++---- .../viewer/lib/entity/EntityMesh.js | 67 ++++++-- .../viewer/lib/entity/entities.json | 50 +++++- prismarine-viewer/viewer/lib/viewer.ts | 2 +- .../viewer/lib/worldDataEmitter.ts | 4 + src/worldInteractions.ts | 6 + 6 files changed, 227 insertions(+), 56 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.ts b/prismarine-viewer/viewer/lib/entities.ts index efc80b5de..934f158c4 100644 --- a/prismarine-viewer/viewer/lib/entities.ts +++ b/prismarine-viewer/viewer/lib/entities.ts @@ -20,6 +20,8 @@ import { getMesh } from './entity/EntityMesh' import { WalkingGeneralSwing } from './entity/animations' import { disposeObject } from './threeJsUtils' import { armorModels } from './entity/objModels' +import { Viewer } from "./viewer"; +import { mapDownloader } from 'mineflayer-item-map-downloader/' const { loadTexture } = globalThis.isElectron ? require('./utils.electron.js') : require('./utils') export const TWEEN_DURATION = 120 @@ -160,15 +162,16 @@ const addNametag = (entity, options, mesh) => { // todo cleanup const nametags = {} +const itemFrameMaps = {} const isFirstUpperCase = (str) => str.charAt(0) === str.charAt(0).toUpperCase() -function getEntityMesh (entity, scene, options, overrides) { +function getEntityMesh (entity, world, options, overrides) { if (entity.name) { try { // https://github.com/PrismarineJS/prismarine-viewer/pull/410 const entityName = (isFirstUpperCase(entity.name) ? snakeCase(entity.name) : entity.name).toLowerCase() - const e = new Entity.EntityMesh('1.16.4', entityName, scene, overrides) + const e = new Entity.EntityMesh('1.16.4', entityName, world, overrides) if (e.mesh) { addNametag(entity, options, e.mesh) @@ -220,7 +223,7 @@ export class Entities extends EventEmitter { size?: number; }) - constructor (public scene: THREE.Scene) { + constructor (public viewer: Viewer) { super() this.entitiesOptions = {} this.debugMode = 'none' @@ -229,7 +232,7 @@ export class Entities extends EventEmitter { clear () { for (const mesh of Object.values(this.entities)) { - this.scene.remove(mesh) + this.viewer.scene.remove(mesh) disposeObject(mesh) } this.entities = {} @@ -251,9 +254,9 @@ export class Entities extends EventEmitter { this.rendering = rendering for (const ent of entity ? [entity] : Object.values(this.entities)) { if (rendering) { - if (!this.scene.children.includes(ent)) this.scene.add(ent) + if (!this.viewer.scene.children.includes(ent)) this.viewer.scene.add(ent) } else { - this.scene.remove(ent) + this.viewer.scene.remove(ent) } } } @@ -405,6 +408,7 @@ export class Entities extends EventEmitter { } getItemMesh (item) { + // TODO: Render proper model (especially for blocks) instead of flat texture const textureUv = this.getItemUv?.(item.itemId ?? item.blockId) if (textureUv) { // todo use geometry buffer uv instead! @@ -458,9 +462,13 @@ export class Entities extends EventEmitter { update (entity: import('prismarine-entity').Entity & { delete?; pos, name }, overrides) { const isPlayerModel = entity.name === 'player' - if (entity.name === 'zombie' || entity.name === 'zombie_villager' || entity.name === 'husk') { + if (entity.name === 'zombie_villager' || entity.name === 'husk') { overrides.texture = `textures/1.16.4/entity/${entity.name === 'zombie_villager' ? 'zombie_villager/zombie_villager.png' : `zombie/${entity.name}.png`}` } + if (entity.name === 'glow_item_frame') { + if (!overrides.textures) overrides.textures = [] + overrides.textures['background'] = 'block:glow_item_frame' + } // this can be undefined in case where packet entity_destroy was sent twice (so it was already deleted) let e = this.entities[entity.id] @@ -468,7 +476,7 @@ export class Entities extends EventEmitter { if (!e) return if (e.additionalCleanup) e.additionalCleanup() this.emit('remove', entity) - this.scene.remove(e) + this.viewer.scene.remove(e) disposeObject(e) // todo dispose textures as well ? delete this.entities[entity.id] @@ -539,7 +547,7 @@ export class Entities extends EventEmitter { //@ts-expect-error playerObject.animation.isMoving = false } else { - mesh = getEntityMesh(entity, this.scene, this.entitiesOptions, overrides) + mesh = getEntityMesh(entity, this.viewer.world, this.entitiesOptions, overrides) } if (!mesh) return mesh.name = 'mesh' @@ -558,7 +566,7 @@ export class Entities extends EventEmitter { group.add(mesh) group.add(boxHelper) boxHelper.visible = false - this.scene.add(group) + this.viewer.scene.add(group) e = group this.entities[entity.id] = e @@ -682,31 +690,38 @@ export class Entities extends EventEmitter { } // todo handle map, map_chunks events - // if (entity.name === 'item_frame' || entity.name === 'glow_item_frame') { - // const example = { - // "present": true, - // "itemId": 847, - // "itemCount": 1, - // "nbtData": { - // "type": "compound", - // "name": "", - // "value": { - // "map": { - // "type": "int", - // "value": 2146483444 - // }, - // "interactiveboard": { - // "type": "byte", - // "value": 1 - // } - // } - // } - // } - // const item = entity.metadata?.[8] - // if (item.nbtData) { - // const nbt = nbt.simplify(item.nbtData) - // } - // } + let itemFrameMeta = getSpecificEntityMetadata('item_frame', entity) + if (!itemFrameMeta) { + itemFrameMeta = getSpecificEntityMetadata('glow_item_frame', entity) + } + if (itemFrameMeta) { + // TODO: Figure out why this doesn't match the Item mineflayer type + const item = itemFrameMeta?.item as any as { nbtData: { value: { map: { value: number } } } } + mesh.scale.set(1, 1, 1) + if (item) { + const rotation = (itemFrameMeta.rotation as any as number) + const mapNumber = item.nbtData?.value?.map?.value + if (mapNumber) { + // TODO: Use proper larger item frame model when a map exists + mesh.scale.set(16/12, 16/12, 1) + e.children.find(c => c.name === 'item')?.removeFromParent() + this.addMapModel(e, mapNumber, rotation) + } else { + e.children.find(c => c.name === 'item' || c.name.startsWith('map_'))?.removeFromParent() + const itemMesh = this.getItemMesh(item) + if (itemMesh) { + itemMesh.mesh.position.set(0, 0, 0.45) + itemMesh.mesh.scale.set(0.5, 0.5, 0.5) + itemMesh.mesh.rotateY(Math.PI) + itemMesh.mesh.rotateZ(rotation * Math.PI / 4) + itemMesh.mesh.name = 'item' + e.add(itemMesh.mesh) + } + } + } else { + e.children.find(c => c.name === 'item' || c.name.startsWith('map_'))?.removeFromParent() + } + } if (entity.username) { e.username = entity.username @@ -729,6 +744,73 @@ export class Entities extends EventEmitter { } } + updateMap(mapNumber, data) { + let itemFrameMeshs = itemFrameMaps[mapNumber] + if (!itemFrameMeshs) return + itemFrameMeshs = itemFrameMeshs.filter(mesh => mesh.parent) + itemFrameMaps[mapNumber] = itemFrameMeshs + itemFrameMeshs?.forEach(mesh => { + mesh.material.map = this.loadMap(data) + mesh.material.needsUpdate = true + mesh.visible = true + }) + } + + addMapModel(entityMesh: THREE.Object3D, mapNumber: number, rotation: number) { + const material = new THREE.MeshLambertMaterial({ + transparent: true, + alphaTest: 0.1, + }) + + let mapMesh + const exitingMapMesh = entityMesh.children.find(c => c.name.startsWith('map_')) as THREE.Mesh + if (exitingMapMesh) { + exitingMapMesh.material = material + mapMesh = exitingMapMesh + const existingMapNumber = parseInt(exitingMapMesh.name.split('_')[1]) + itemFrameMaps[existingMapNumber] = itemFrameMaps[existingMapNumber]?.filter(mesh => mesh !== exitingMapMesh) + } else { + mapMesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), material) + + mapMesh.rotation.set(0, Math.PI, 0) + entityMesh.add(mapMesh) + } + let isInvisible = true; + entityMesh.traverseVisible(c => { + if (c.name == 'geometry_frame') { + isInvisible = false + } + }); + if (isInvisible) { + mapMesh.position.set(0, 0, 0.499) + } else { + mapMesh.position.set(0, 0, 0.437) + } + mapMesh.rotateZ(rotation * Math.PI / 2) + mapMesh.name = `map_${mapNumber}` + + bot.loadPlugin(mapDownloader) + const imageData = bot.mapDownloader.maps?.[mapNumber] as any as string + if (imageData) { + material.map = this.loadMap(imageData) + } else { + mapMesh.visible = false + } + + if (!itemFrameMaps[mapNumber]) { + itemFrameMaps[mapNumber] = [] + } + itemFrameMaps[mapNumber].push(mapMesh) + } + + loadMap(data: any) { + const texture = new THREE.TextureLoader().load(data) + texture.magFilter = THREE.NearestFilter + texture.minFilter = THREE.NearestFilter + texture.needsUpdate = true + return texture + } + handleDamageEvent (entityId, damageAmount) { const entityMesh = this.entities[entityId]?.children.find(c => c.name === 'mesh') if (entityMesh) { @@ -796,7 +878,7 @@ function addArmorModel (entityMesh: THREE.Object3D, slotType: string, item: Item material.map = texture }) } else { - mesh = getMesh(texturePath, armorModels.armorModel[slotType]) + mesh = getMesh(viewer.world, texturePath, armorModels.armorModel[slotType]) mesh.name = meshName material = mesh.material material.side = THREE.DoubleSide diff --git a/prismarine-viewer/viewer/lib/entity/EntityMesh.js b/prismarine-viewer/viewer/lib/entity/EntityMesh.js index 69dd95d65..d0abff813 100644 --- a/prismarine-viewer/viewer/lib/entity/EntityMesh.js +++ b/prismarine-viewer/viewer/lib/entity/EntityMesh.js @@ -94,7 +94,7 @@ function dot(a, b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] } -function addCube(attr, boneId, bone, cube, texWidth = 64, texHeight = 64, mirror = false) { +function addCube(attr, boneId, bone, cube, sameTextureForAllFaces = false, texWidth = 64, texHeight = 64, mirror = false) { const cubeRotation = new THREE.Euler(0, 0, 0) if (cube.rotation) { cubeRotation.x = -cube.rotation[0] * Math.PI / 180 @@ -107,8 +107,15 @@ function addCube(attr, boneId, bone, cube, texWidth = 64, texHeight = 64, mirror const eastOrWest = dir[0] !== 0 const faceUvs = [] for (const pos of corners) { - const u = (cube.uv[0] + dot(pos[3] ? u1 : u0, cube.size)) / texWidth - const v = (cube.uv[1] + dot(pos[4] ? v1 : v0, cube.size)) / texHeight + let u; + let v; + if (sameTextureForAllFaces) { + u = (cube.uv[0] + pos[3] * cube.size[0]) / texWidth + v = (cube.uv[1] + pos[4] * cube.size[1]) / texHeight + } else { + u = (cube.uv[0] + dot(pos[3] ? u1 : u0, cube.size)) / texWidth + v = (cube.uv[1] + dot(pos[4] ? v1 : v0, cube.size)) / texHeight + } const posX = eastOrWest && mirror ? pos[0] ^ 1 : pos[0] const posY = pos[1] @@ -148,7 +155,23 @@ function addCube(attr, boneId, bone, cube, texWidth = 64, texHeight = 64, mirror } } -export function getMesh(texture, jsonModel, overrides = {}) { +export function getMesh(world, texture, jsonModel, overrides = {}) { + let textureWidth = jsonModel.texturewidth ?? 64 + let textureHeight = jsonModel.textureheight ?? 64 + let textureOffset = undefined + let useBlockTexture = texture.startsWith('block:'); + if (useBlockTexture) { + const blockName = texture.substring(6) + const textureInfo = world.blocksAtlasParser.getTextureInfo(blockName) + if (textureInfo) { + textureWidth = world.material.map.image.width + textureHeight = world.material.map.image.height + textureOffset = [textureInfo.u, textureInfo.v] + } else { + console.error(`Unknown block ${blockName}`) + } + } + const bones = {} const geoData = { @@ -186,7 +209,7 @@ export function getMesh(texture, jsonModel, overrides = {}) { if (jsonBone.cubes) { for (const cube of jsonBone.cubes) { - addCube(geoData, i, bone, cube, jsonModel.texturewidth, jsonModel.textureheight, jsonBone.mirror) + addCube(geoData, i, bone, cube, useBlockTexture, textureWidth, textureHeight, jsonBone.mirror) } } i++ @@ -215,18 +238,25 @@ export function getMesh(texture, jsonModel, overrides = {}) { mesh.bind(skeleton) mesh.scale.set(1 / 16, 1 / 16, 1 / 16) - loadTexture(texture, texture => { - if (material.map) { - // texture is already loaded - return - } - texture.magFilter = THREE.NearestFilter - texture.minFilter = THREE.NearestFilter - texture.flipY = false - texture.wrapS = THREE.RepeatWrapping - texture.wrapT = THREE.RepeatWrapping + if (textureOffset) { + texture = world.material.map.clone() + texture.offset.set(textureOffset[0], textureOffset[1]) + texture.needsUpdate = true material.map = texture - }) + } else { + loadTexture(texture.endsWith('.png') || texture.startsWith('data:image/') ? texture : texture + '.png', texture => { + if (material.map) { + // texture is already loaded + return + } + texture.magFilter = THREE.NearestFilter + texture.minFilter = THREE.NearestFilter + texture.flipY = false + texture.wrapS = THREE.RepeatWrapping + texture.wrapT = THREE.RepeatWrapping + material.map = texture + }) + } return mesh } @@ -252,6 +282,7 @@ export const temporaryMap = { 'hopper_minecart': 'minecart', 'command_block_minecart': 'minecart', 'tnt_minecart': 'minecart', + 'glow_item_frame': 'item_frame', 'glow_squid': 'squid', 'trader_llama': 'llama', 'chest_boat': 'boat', @@ -321,7 +352,7 @@ const offsetEntity = { // eslint-disable-next-line @typescript-eslint/no-extraneous-class export class EntityMesh { - constructor(version, type, scene, /** @type {{textures?, rotation?: Record}} */overrides = {}) { + constructor(version, type, world, /** @type {{textures?, rotation?: Record}} */overrides = {}) { const originalType = type const mappedValue = temporaryMap[type] if (mappedValue) type = mappedValue @@ -388,7 +419,7 @@ export class EntityMesh { const texture = overrides.textures?.[name] ?? e.textures[name] if (!texture) continue // console.log(JSON.stringify(jsonModel, null, 2)) - const mesh = getMesh(texture + '.png', jsonModel, overrides) + const mesh = getMesh(world, texture, jsonModel, overrides) mesh.name = `geometry_${name}` this.mesh.add(mesh) diff --git a/prismarine-viewer/viewer/lib/entity/entities.json b/prismarine-viewer/viewer/lib/entity/entities.json index 9824d4182..4436a44bf 100644 --- a/prismarine-viewer/viewer/lib/entity/entities.json +++ b/prismarine-viewer/viewer/lib/entity/entities.json @@ -7838,6 +7838,53 @@ } } }, + "item_frame": { + "identifier": "minecraft:item_frame", + "materials": {"default": "item_frame"}, + "textures": { + "background": "block:item_frame", + "frame": "block:oak_planks" + }, + "geometry": { + "background": { + "bones": [ + { + "name": "base" + }, + { + "name": "background", + "parent": "base", + "rotation": [0, 180, 0], + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-5, -5, -8], "size": [10, 10, 0.5], "uv": [3, 3]} + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + }, + "frame": { + "bones": [ + { + "name": "frame", + "parent": "base", + "rotation": [0, 180, 0], + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-6, -6, -8], "size": [12, 1, 1], "uv": [2, 2]}, + {"origin": [-6, 5, -8], "size": [12, 1, 1], "uv": [2, 13]}, + {"origin": [-6, -5, -8], "size": [1, 10, 1], "uv": [2, 3]}, + {"origin": [5, -5, -8], "size": [1, 10, 1], "uv": [13, 3]} + ] + } + ], + "texturewidth": 16, + "textureheight": 16 + } + }, + "render_controllers": ["controller.render.item_frame"] + }, "leash_knot": { "identifier": "minecraft:leash_knot", "materials": {"default": "leash_knot"}, @@ -7847,7 +7894,8 @@ "bones": [ { "name": "knot", - "cubes": [{"origin": [-3, 2, -3], "size": [6, 8, 6]}] + "rotation": [0, 180, 0], + "cubes": [{"origin": [5, 6, 5], "size": [6, 8, 6], "uv": [0, 0]}] } ], "texturewidth": 32, diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts index c90bc811f..929b38000 100644 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ b/prismarine-viewer/viewer/lib/viewer.ts @@ -48,7 +48,7 @@ export class Viewer { this.threeJsWorld = new WorldRendererThree(this.scene, this.renderer, worldConfig) this.setWorld() this.resetScene() - this.entities = new Entities(this.scene) + this.entities = new Entities(this) // this.primitives = new Primitives(this.scene, this.camera) this.domElement = renderer.domElement diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index 61d5a503a..6cf4e5809 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -75,6 +75,10 @@ export class WorldDataEmitter extends EventEmitter { this.eventListeners = { // 'move': botPosition, entitySpawn (e: any) { + if (e.name === "item_frame" || e.name === "glow_item_frame") { + // Item frames use block positions in the protocol, not their center. Fix that. + e.position.translate(0.5, 0.5, 0.5) + } emitEntity(e) }, entityUpdate (e: any) { diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 1134d7f89..a5bfb61f3 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -5,6 +5,7 @@ import * as THREE from 'three' // wouldn't better to create atlas instead? import { Vec3 } from 'vec3' import { LineMaterial } from 'three-stdlib' +import { mapDownloader } from 'mineflayer-item-map-downloader/' import { Entity } from 'prismarine-entity' import destroyStage0 from '../assets/destroy_stage_0.png' import destroyStage1 from '../assets/destroy_stage_1.png' @@ -158,6 +159,11 @@ class WorldInteraction { upLineMaterial() // todo use gamemode update only bot.on('game', upLineMaterial) + + bot.loadPlugin(mapDownloader) + bot.mapDownloader.on('new_map', ({ png, id }) => { + viewer.entities.updateMap(id, png) + }) } activateEntity (entity: Entity) { From 3955a50b7386261927e36db77ea2d66e7bf6a08b Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 15 Jan 2025 16:03:03 +0700 Subject: [PATCH 02/11] remove mineflayer-item-map-downloader from viewer --- prismarine-viewer/viewer/lib/entities.ts | 35 ++++++++++++------------ src/react/HeldMapUi.tsx | 3 +- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.ts b/prismarine-viewer/viewer/lib/entities.ts index 934f158c4..f454b7de0 100644 --- a/prismarine-viewer/viewer/lib/entities.ts +++ b/prismarine-viewer/viewer/lib/entities.ts @@ -20,8 +20,7 @@ import { getMesh } from './entity/EntityMesh' import { WalkingGeneralSwing } from './entity/animations' import { disposeObject } from './threeJsUtils' import { armorModels } from './entity/objModels' -import { Viewer } from "./viewer"; -import { mapDownloader } from 'mineflayer-item-map-downloader/' +import { Viewer } from './viewer' const { loadTexture } = globalThis.isElectron ? require('./utils.electron.js') : require('./utils') export const TWEEN_DURATION = 120 @@ -214,6 +213,7 @@ export class Entities extends EventEmitter { clock = new THREE.Clock() rendering = true itemsTexture: THREE.Texture | null = null + cachedMapsImages = {} as Record getItemUv: undefined | ((idOrName: number | string) => { texture: THREE.Texture; u: number; @@ -703,7 +703,7 @@ export class Entities extends EventEmitter { const mapNumber = item.nbtData?.value?.map?.value if (mapNumber) { // TODO: Use proper larger item frame model when a map exists - mesh.scale.set(16/12, 16/12, 1) + mesh.scale.set(16 / 12, 16 / 12, 1) e.children.find(c => c.name === 'item')?.removeFromParent() this.addMapModel(e, mapNumber, rotation) } else { @@ -744,19 +744,21 @@ export class Entities extends EventEmitter { } } - updateMap(mapNumber, data) { + updateMap (mapNumber, data) { let itemFrameMeshs = itemFrameMaps[mapNumber] if (!itemFrameMeshs) return itemFrameMeshs = itemFrameMeshs.filter(mesh => mesh.parent) itemFrameMaps[mapNumber] = itemFrameMeshs - itemFrameMeshs?.forEach(mesh => { - mesh.material.map = this.loadMap(data) - mesh.material.needsUpdate = true - mesh.visible = true - }) + if (itemFrameMeshs) { + for (const mesh of itemFrameMeshs) { + mesh.material.map = this.loadMap(data) + mesh.material.needsUpdate = true + mesh.visible = true + } + } } - addMapModel(entityMesh: THREE.Object3D, mapNumber: number, rotation: number) { + addMapModel (entityMesh: THREE.Object3D, mapNumber: number, rotation: number) { const material = new THREE.MeshLambertMaterial({ transparent: true, alphaTest: 0.1, @@ -767,7 +769,7 @@ export class Entities extends EventEmitter { if (exitingMapMesh) { exitingMapMesh.material = material mapMesh = exitingMapMesh - const existingMapNumber = parseInt(exitingMapMesh.name.split('_')[1]) + const existingMapNumber = Number(exitingMapMesh.name.split('_')[1]) itemFrameMaps[existingMapNumber] = itemFrameMaps[existingMapNumber]?.filter(mesh => mesh !== exitingMapMesh) } else { mapMesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), material) @@ -775,12 +777,12 @@ export class Entities extends EventEmitter { mapMesh.rotation.set(0, Math.PI, 0) entityMesh.add(mapMesh) } - let isInvisible = true; + let isInvisible = true entityMesh.traverseVisible(c => { - if (c.name == 'geometry_frame') { + if (c.name === 'geometry_frame') { isInvisible = false } - }); + }) if (isInvisible) { mapMesh.position.set(0, 0, 0.499) } else { @@ -789,8 +791,7 @@ export class Entities extends EventEmitter { mapMesh.rotateZ(rotation * Math.PI / 2) mapMesh.name = `map_${mapNumber}` - bot.loadPlugin(mapDownloader) - const imageData = bot.mapDownloader.maps?.[mapNumber] as any as string + const imageData = this.cachedMapsImages?.[mapNumber] if (imageData) { material.map = this.loadMap(imageData) } else { @@ -803,7 +804,7 @@ export class Entities extends EventEmitter { itemFrameMaps[mapNumber].push(mapMesh) } - loadMap(data: any) { + loadMap (data: any) { const texture = new THREE.TextureLoader().load(data) texture.magFilter = THREE.NearestFilter texture.minFilter = THREE.NearestFilter diff --git a/src/react/HeldMapUi.tsx b/src/react/HeldMapUi.tsx index 12f032982..c57abb413 100644 --- a/src/react/HeldMapUi.tsx +++ b/src/react/HeldMapUi.tsx @@ -34,9 +34,10 @@ export default () => { updateHeldMap() }) - bot.on('new_map', () => { + bot.on('new_map', ({ id }) => { // total maps: Object.keys(bot.mapDownloader.maps).length updateHeldMap() + viewer.entities.cachedMapsImages[id] = bot.mapDownloader.maps?.[id] as unknown as string }) }, []) From 559e531b783e022a7c6dc5fd1380887d3a9d2bb1 Mon Sep 17 00:00:00 2001 From: Phoenix616 Date: Wed, 15 Jan 2025 22:06:55 +0100 Subject: [PATCH 03/11] Move map caching out of HeldMapUi and improve handling of map and item models This includes disposing of remove item/map meshes of item frames --- pnpm-lock.yaml | 127 ++++++++++++++++------- prismarine-viewer/viewer/lib/entities.ts | 87 +++++++++------- src/react/HeldMapUi.tsx | 1 - 3 files changed, 139 insertions(+), 76 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c5ad3115f..07ece12b4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -426,6 +426,9 @@ importers: minecrafthawkeye: specifier: ^1.3.6 version: 1.3.6 + mineflayer-item-map-downloader: + specifier: github:zardoy/mineflayer-item-map-downloader + version: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7(patch_hash=bck55yjvd4wrgz46x7o4vfur5q)(encoding@0.1.13) prismarine-block: specifier: github:zardoy/prismarine-block#next-era version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/23849d4d24af91f45a5bd38781a6f82d40316c05 @@ -441,6 +444,9 @@ importers: process: specifier: ^0.11.10 version: 0.11.10 + sharp: + specifier: ^0.29.1 + version: 0.29.3 socket.io: specifier: ^4.0.0 version: 4.7.2 @@ -4582,6 +4588,11 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + detect-libc@2.0.2: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} engines: {node: '>=8'} @@ -6988,6 +6999,9 @@ packages: node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + node-addon-api@4.3.0: + resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} + node-addon-api@5.1.0: resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} @@ -7533,11 +7547,16 @@ packages: version: 1.36.0 engines: {node: '>=14'} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/aba0d8e1efa49f4c75646cdb9635cfab41ad4ad9: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/aba0d8e1efa49f4c75646cdb9635cfab41ad4ad9} + version: 1.38.0 + engines: {node: '>=14'} + prismarine-entity@2.3.1: resolution: {integrity: sha512-HOv8l7IetHNf4hwZ7V/W4vM3GNl+e6VCtKDkH9h02TRq7jWngsggKtJV+VanCce/sNwtJUhJDjORGs728ep4MA==} - prismarine-item@1.15.0: - resolution: {integrity: sha512-DysyiCzaI8S7PpRLFylAZnQo2CppXiBbaUp+8rhK+EzvzmMdS+D1/oETQm9ysB5Jw9eCer6iWGMgzZXxJE5+/w==} + prismarine-item@1.16.0: + resolution: {integrity: sha512-88Tz+/6HquYIsDuseae5G3IbqLeMews2L+ba2gX+p6K6soU9nuFhCfbwN56QuB7d/jZFcWrCYAPE5+UhwWh67w==} prismarine-nbt@2.2.1: resolution: {integrity: sha512-Mb50c58CPnuZ+qvM31DBa08tf9UumlTq1LkvpMoUpKfCuN05GZHTqCUwER3lxTSHLL0GZKghIPbYR/JQkINijQ==} @@ -8328,6 +8347,10 @@ packages: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} + sharp@0.29.3: + resolution: {integrity: sha512-fKWUuOw77E4nhpyzCCJR1ayrttHoFHBT2U/kR/qEMRhvPEcluG4BKj324+SCO1e84+knXHwhJ1HHJGnUt4ElGA==} + engines: {node: '>=12.13.0'} + sharp@0.30.7: resolution: {integrity: sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig==} engines: {node: '>=12.13.0'} @@ -9794,7 +9817,7 @@ snapshots: '@babel/traverse': 7.22.11 '@babel/types': 7.23.0 convert-source-map: 1.9.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -9862,7 +9885,7 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-compilation-targets': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.4 transitivePeerDependencies: @@ -10589,7 +10612,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.22.13 '@babel/types': 7.23.0 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -11482,7 +11505,7 @@ snapshots: nopt: 5.0.0 npmlog: 5.0.1 rimraf: 3.0.2 - semver: 7.5.4 + semver: 7.6.0 tar: 6.2.0 transitivePeerDependencies: - encoding @@ -12421,7 +12444,7 @@ snapshots: prompts: 2.4.2 puppeteer-core: 2.1.1 read-pkg-up: 7.0.1 - semver: 7.5.4 + semver: 7.6.0 simple-update-notifier: 2.0.0 strip-json-comments: 3.1.1 tempy: 1.0.1 @@ -12547,7 +12570,7 @@ snapshots: pretty-hrtime: 1.0.3 prompts: 2.4.2 read-pkg-up: 7.0.1 - semver: 7.5.4 + semver: 7.6.0 telejson: 7.2.0 tiny-invariant: 1.3.1 ts-dedent: 2.2.0 @@ -13112,7 +13135,7 @@ snapshots: ignore: 5.2.4 natural-compare: 1.4.0 natural-compare-lite: 1.4.0 - semver: 7.5.4 + semver: 7.6.0 ts-api-utils: 1.0.3(typescript@5.5.4) optionalDependencies: typescript: 5.5.4 @@ -13151,7 +13174,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.5.4) '@typescript-eslint/utils': 6.1.0(eslint@8.50.0)(typescript@5.5.4) - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) eslint: 8.50.0 ts-api-utils: 1.0.3(typescript@5.5.4) optionalDependencies: @@ -13169,7 +13192,7 @@ snapshots: dependencies: '@typescript-eslint/types': 6.1.0 '@typescript-eslint/visitor-keys': 6.1.0 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.0 @@ -13183,7 +13206,7 @@ snapshots: dependencies: '@typescript-eslint/types': 6.7.3 '@typescript-eslint/visitor-keys': 6.7.3 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.0 @@ -13197,7 +13220,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.0.0 '@typescript-eslint/visitor-keys': 8.0.0 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 @@ -13448,7 +13471,7 @@ snapshots: node-rsa: 1.1.1 prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/416dd49bec42f4cc9f50ccf79527e6e4c01cebcb(minecraft-data@3.80.0) prismarine-entity: 2.3.1 - prismarine-item: 1.15.0 + prismarine-item: 1.16.0 prismarine-nbt: 2.5.0 prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/d807fc339a3d95a7aef91468d4d64d367e7c682a(minecraft-data@3.80.0) prismarine-windows: 2.9.0 @@ -13534,14 +13557,14 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color optional: true agent-base@7.1.0: dependencies: - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -14790,9 +14813,11 @@ snapshots: optionalDependencies: supports-color: 8.1.1 - debug@4.3.7: + debug@4.3.7(supports-color@8.1.1): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 decamelize-keys@1.1.1: dependencies: @@ -14913,6 +14938,8 @@ snapshots: detect-indent@6.1.0: {} + detect-libc@1.0.3: {} + detect-libc@2.0.2: {} detect-node-es@1.1.0: {} @@ -14924,7 +14951,7 @@ snapshots: detect-port@1.5.1: dependencies: address: 1.2.2 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -14935,7 +14962,7 @@ snapshots: diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/cfaad2d1d5909fdfa63c8cc7bc05fb5e87782d71: dependencies: minecraft-data: 3.80.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/416dd49bec42f4cc9f50ccf79527e6e4c01cebcb(minecraft-data@3.80.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/aba0d8e1efa49f4c75646cdb9635cfab41ad4ad9(minecraft-data@3.80.0) prismarine-registry: 1.10.0 random-seed: 0.3.0 vec3: 0.1.8 @@ -15349,7 +15376,7 @@ snapshots: esbuild-register@3.5.0(esbuild@0.18.20): dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) esbuild: 0.18.20 transitivePeerDependencies: - supports-color @@ -15602,7 +15629,7 @@ snapshots: read-pkg-up: 7.0.1 regexp-tree: 0.1.27 regjsparser: 0.10.0 - semver: 7.5.4 + semver: 7.6.0 strip-indent: 3.0.0 eslint-scope@5.1.1: @@ -15864,7 +15891,7 @@ snapshots: extract-zip@2.0.1(supports-color@8.1.1): dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -16533,7 +16560,7 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color optional: true @@ -16577,14 +16604,14 @@ snapshots: https-proxy-agent@4.0.0: dependencies: agent-base: 5.1.1 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color optional: true @@ -16592,7 +16619,7 @@ snapshots: https-proxy-agent@7.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -17666,7 +17693,7 @@ snapshots: micromark@4.0.0: dependencies: '@types/debug': 4.1.12 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.0 @@ -17810,7 +17837,7 @@ snapshots: minecraft-data: 3.80.0 prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/23849d4d24af91f45a5bd38781a6f82d40316c05 prismarine-entity: 2.3.1 - prismarine-item: 1.15.0 + prismarine-item: 1.16.0 prismarine-nbt: 2.2.1 prismarine-physics: https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b vec3: 0.1.8 @@ -17824,7 +17851,7 @@ snapshots: prismarine-chat: 1.10.1 prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/416dd49bec42f4cc9f50ccf79527e6e4c01cebcb(minecraft-data@3.80.0) prismarine-entity: 2.3.1 - prismarine-item: 1.15.0 + prismarine-item: 1.16.0 prismarine-nbt: 2.5.0 prismarine-physics: https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b prismarine-recipe: 1.3.1(prismarine-registry@1.10.0) @@ -17847,7 +17874,7 @@ snapshots: prismarine-chat: 1.10.1 prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/416dd49bec42f4cc9f50ccf79527e6e4c01cebcb(minecraft-data@3.80.0) prismarine-entity: 2.3.1 - prismarine-item: 1.15.0 + prismarine-item: 1.16.0 prismarine-nbt: 2.5.0 prismarine-physics: https://codeload.github.com/zardoy/prismarine-physics/tar.gz/353e25b800149393f40539ec381218be44cbb03b prismarine-recipe: 1.3.1(prismarine-registry@1.10.0) @@ -18062,6 +18089,8 @@ snapshots: node-abort-controller@3.1.1: {} + node-addon-api@4.3.0: {} + node-addon-api@5.1.0: {} node-canvas-webgl@0.3.0(encoding@0.1.13): @@ -18656,7 +18685,7 @@ snapshots: minecraft-data: 3.80.0 prismarine-biome: 1.3.0(minecraft-data@3.80.0)(prismarine-registry@1.7.0) prismarine-chat: 1.10.1 - prismarine-item: 1.15.0 + prismarine-item: 1.16.0 prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 @@ -18679,14 +18708,27 @@ snapshots: transitivePeerDependencies: - minecraft-data + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/aba0d8e1efa49f4c75646cdb9635cfab41ad4ad9(minecraft-data@3.80.0): + dependencies: + prismarine-biome: 1.3.0(minecraft-data@3.80.0)(prismarine-registry@1.10.0) + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/23849d4d24af91f45a5bd38781a6f82d40316c05 + prismarine-nbt: 2.5.0 + prismarine-registry: 1.10.0 + smart-buffer: 4.2.0 + uint4: 0.1.2 + vec3: 0.1.8 + xxhash-wasm: 0.4.2 + transitivePeerDependencies: + - minecraft-data + prismarine-entity@2.3.1: dependencies: prismarine-chat: 1.10.1 - prismarine-item: 1.15.0 + prismarine-item: 1.16.0 prismarine-registry: 1.10.0 vec3: 0.1.8 - prismarine-item@1.15.0: + prismarine-item@1.16.0: dependencies: prismarine-nbt: 2.5.0 prismarine-registry: 1.10.0 @@ -18748,7 +18790,7 @@ snapshots: prismarine-windows@2.9.0: dependencies: - prismarine-item: 1.15.0 + prismarine-item: 1.16.0 prismarine-registry: 1.10.0 typed-emitter: 2.1.0 @@ -18942,7 +18984,7 @@ snapshots: puppeteer-core@2.1.1: dependencies: '@types/mime-types': 2.1.2 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) extract-zip: 1.7.0 https-proxy-agent: 4.0.0 mime: 2.6.0 @@ -19603,7 +19645,7 @@ snapshots: send@1.1.0: dependencies: - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) destroy: 1.2.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -19702,6 +19744,17 @@ snapshots: dependencies: kind-of: 6.0.3 + sharp@0.29.3: + dependencies: + color: 4.2.3 + detect-libc: 1.0.3 + node-addon-api: 4.3.0 + prebuild-install: 7.1.1 + semver: 7.6.0 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + sharp@0.30.7: dependencies: color: 4.2.3 @@ -19929,7 +19982,7 @@ snapshots: socks-proxy-agent@7.0.0: dependencies: agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.3.7(supports-color@8.1.1) socks: 2.7.1 transitivePeerDependencies: - supports-color diff --git a/prismarine-viewer/viewer/lib/entities.ts b/prismarine-viewer/viewer/lib/entities.ts index f454b7de0..ea69df561 100644 --- a/prismarine-viewer/viewer/lib/entities.ts +++ b/prismarine-viewer/viewer/lib/entities.ts @@ -161,7 +161,6 @@ const addNametag = (entity, options, mesh) => { // todo cleanup const nametags = {} -const itemFrameMaps = {} const isFirstUpperCase = (str) => str.charAt(0) === str.charAt(0).toUpperCase() @@ -213,7 +212,8 @@ export class Entities extends EventEmitter { clock = new THREE.Clock() rendering = true itemsTexture: THREE.Texture | null = null - cachedMapsImages = {} as Record + cachedMapsImages = {} as Record + itemFrameMaps = {} as Record[]> getItemUv: undefined | ((idOrName: number | string) => { texture: THREE.Texture; u: number; @@ -696,18 +696,31 @@ export class Entities extends EventEmitter { } if (itemFrameMeta) { // TODO: Figure out why this doesn't match the Item mineflayer type - const item = itemFrameMeta?.item as any as { nbtData: { value: { map: { value: number } } } } + const item = itemFrameMeta?.item as any as { itemId, blockId, nbtData: { value: { map: { value: number } } } } mesh.scale.set(1, 1, 1) - if (item) { + e.children.find(c => { + if (c.name.startsWith('map_')) { + disposeObject(c) + const existingMapNumber = parseInt(c.name.split('_')[1]) + this.itemFrameMaps[existingMapNumber] = this.itemFrameMaps[existingMapNumber]?.filter(mesh => mesh !== c) + if (c instanceof THREE.Mesh) { + c.material?.map?.dispose() + } + return true + } else if (c.name === 'item') { + disposeObject(c) + return true + } + return false + })?.removeFromParent() + if (item && (item.itemId ?? item.blockId ?? 0) !== 0) { const rotation = (itemFrameMeta.rotation as any as number) const mapNumber = item.nbtData?.value?.map?.value if (mapNumber) { // TODO: Use proper larger item frame model when a map exists mesh.scale.set(16 / 12, 16 / 12, 1) - e.children.find(c => c.name === 'item')?.removeFromParent() this.addMapModel(e, mapNumber, rotation) } else { - e.children.find(c => c.name === 'item' || c.name.startsWith('map_'))?.removeFromParent() const itemMesh = this.getItemMesh(item) if (itemMesh) { itemMesh.mesh.position.set(0, 0, 0.45) @@ -718,8 +731,6 @@ export class Entities extends EventEmitter { e.add(itemMesh.mesh) } } - } else { - e.children.find(c => c.name === 'item' || c.name.startsWith('map_'))?.removeFromParent() } } @@ -745,10 +756,11 @@ export class Entities extends EventEmitter { } updateMap (mapNumber, data) { - let itemFrameMeshs = itemFrameMaps[mapNumber] + this.cachedMapsImages[mapNumber] = data; //bot.mapDownloader.maps?.[id] as unknown as string + let itemFrameMeshs = this.itemFrameMaps[mapNumber] if (!itemFrameMeshs) return itemFrameMeshs = itemFrameMeshs.filter(mesh => mesh.parent) - itemFrameMaps[mapNumber] = itemFrameMeshs + this.itemFrameMaps[mapNumber] = itemFrameMeshs if (itemFrameMeshs) { for (const mesh of itemFrameMeshs) { mesh.material.map = this.loadMap(data) @@ -759,25 +771,25 @@ export class Entities extends EventEmitter { } addMapModel (entityMesh: THREE.Object3D, mapNumber: number, rotation: number) { - const material = new THREE.MeshLambertMaterial({ - transparent: true, - alphaTest: 0.1, - }) + const imageData = this.cachedMapsImages?.[mapNumber] + let texture : THREE.Texture | null = null + if (imageData) { + texture = this.loadMap(imageData) + } + const parameters = { + transparent: true, + alphaTest: 0.1, + } + if (texture?.image) { + parameters['map'] = texture + } + const material = new THREE.MeshLambertMaterial(parameters) - let mapMesh - const exitingMapMesh = entityMesh.children.find(c => c.name.startsWith('map_')) as THREE.Mesh - if (exitingMapMesh) { - exitingMapMesh.material = material - mapMesh = exitingMapMesh - const existingMapNumber = Number(exitingMapMesh.name.split('_')[1]) - itemFrameMaps[existingMapNumber] = itemFrameMaps[existingMapNumber]?.filter(mesh => mesh !== exitingMapMesh) - } else { - mapMesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), material) + let mapMesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), material) - mapMesh.rotation.set(0, Math.PI, 0) - entityMesh.add(mapMesh) - } - let isInvisible = true + mapMesh.rotation.set(0, Math.PI, 0) + entityMesh.add(mapMesh) + let isInvisible = false; entityMesh.traverseVisible(c => { if (c.name === 'geometry_frame') { isInvisible = false @@ -788,27 +800,26 @@ export class Entities extends EventEmitter { } else { mapMesh.position.set(0, 0, 0.437) } - mapMesh.rotateZ(rotation * Math.PI / 2) + mapMesh.rotateZ(Math.PI * 2 - rotation * Math.PI / 2) mapMesh.name = `map_${mapNumber}` - const imageData = this.cachedMapsImages?.[mapNumber] - if (imageData) { - material.map = this.loadMap(imageData) - } else { + if (!texture || !texture.image) { mapMesh.visible = false } - if (!itemFrameMaps[mapNumber]) { - itemFrameMaps[mapNumber] = [] + if (!this.itemFrameMaps[mapNumber]) { + this.itemFrameMaps[mapNumber] = [] } - itemFrameMaps[mapNumber].push(mapMesh) + this.itemFrameMaps[mapNumber].push(mapMesh) } loadMap (data: any) { const texture = new THREE.TextureLoader().load(data) - texture.magFilter = THREE.NearestFilter - texture.minFilter = THREE.NearestFilter - texture.needsUpdate = true + if (texture) { + texture.magFilter = THREE.NearestFilter + texture.minFilter = THREE.NearestFilter + texture.needsUpdate = true + } return texture } diff --git a/src/react/HeldMapUi.tsx b/src/react/HeldMapUi.tsx index c57abb413..8ea77bb3d 100644 --- a/src/react/HeldMapUi.tsx +++ b/src/react/HeldMapUi.tsx @@ -37,7 +37,6 @@ export default () => { bot.on('new_map', ({ id }) => { // total maps: Object.keys(bot.mapDownloader.maps).length updateHeldMap() - viewer.entities.cachedMapsImages[id] = bot.mapDownloader.maps?.[id] as unknown as string }) }, []) From 8c0c1aee226142290606ac1fb4205311226d4770 Mon Sep 17 00:00:00 2001 From: Phoenix616 Date: Wed, 15 Jan 2025 22:25:58 +0100 Subject: [PATCH 04/11] Fix linting issues --- prismarine-viewer/viewer/lib/entities.ts | 20 +++++++++---------- .../viewer/lib/entity/EntityMesh.js | 10 +++++----- .../viewer/lib/worldDataEmitter.ts | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.ts b/prismarine-viewer/viewer/lib/entities.ts index ea69df561..9487bdb9c 100644 --- a/prismarine-viewer/viewer/lib/entities.ts +++ b/prismarine-viewer/viewer/lib/entities.ts @@ -213,7 +213,7 @@ export class Entities extends EventEmitter { rendering = true itemsTexture: THREE.Texture | null = null cachedMapsImages = {} as Record - itemFrameMaps = {} as Record[]> + itemFrameMaps = {} as Record>> getItemUv: undefined | ((idOrName: number | string) => { texture: THREE.Texture; u: number; @@ -701,7 +701,7 @@ export class Entities extends EventEmitter { e.children.find(c => { if (c.name.startsWith('map_')) { disposeObject(c) - const existingMapNumber = parseInt(c.name.split('_')[1]) + const existingMapNumber = parseInt(c.name.split('_')[1], 10) this.itemFrameMaps[existingMapNumber] = this.itemFrameMaps[existingMapNumber]?.filter(mesh => mesh !== c) if (c instanceof THREE.Mesh) { c.material?.map?.dispose() @@ -756,7 +756,7 @@ export class Entities extends EventEmitter { } updateMap (mapNumber, data) { - this.cachedMapsImages[mapNumber] = data; //bot.mapDownloader.maps?.[id] as unknown as string + this.cachedMapsImages[mapNumber] = data let itemFrameMeshs = this.itemFrameMaps[mapNumber] if (!itemFrameMeshs) return itemFrameMeshs = itemFrameMeshs.filter(mesh => mesh.parent) @@ -772,24 +772,24 @@ export class Entities extends EventEmitter { addMapModel (entityMesh: THREE.Object3D, mapNumber: number, rotation: number) { const imageData = this.cachedMapsImages?.[mapNumber] - let texture : THREE.Texture | null = null + let texture: THREE.Texture | null = null if (imageData) { - texture = this.loadMap(imageData) + texture = this.loadMap(imageData) } const parameters = { - transparent: true, - alphaTest: 0.1, + transparent: true, + alphaTest: 0.1, } if (texture?.image) { parameters['map'] = texture } const material = new THREE.MeshLambertMaterial(parameters) - let mapMesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), material) + const mapMesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), material) mapMesh.rotation.set(0, Math.PI, 0) entityMesh.add(mapMesh) - let isInvisible = false; + let isInvisible = false entityMesh.traverseVisible(c => { if (c.name === 'geometry_frame') { isInvisible = false @@ -803,7 +803,7 @@ export class Entities extends EventEmitter { mapMesh.rotateZ(Math.PI * 2 - rotation * Math.PI / 2) mapMesh.name = `map_${mapNumber}` - if (!texture || !texture.image) { + if (!texture?.image) { mapMesh.visible = false } diff --git a/prismarine-viewer/viewer/lib/entity/EntityMesh.js b/prismarine-viewer/viewer/lib/entity/EntityMesh.js index d0abff813..a2b40befa 100644 --- a/prismarine-viewer/viewer/lib/entity/EntityMesh.js +++ b/prismarine-viewer/viewer/lib/entity/EntityMesh.js @@ -107,8 +107,8 @@ function addCube(attr, boneId, bone, cube, sameTextureForAllFaces = false, texWi const eastOrWest = dir[0] !== 0 const faceUvs = [] for (const pos of corners) { - let u; - let v; + let u + let v if (sameTextureForAllFaces) { u = (cube.uv[0] + pos[3] * cube.size[0]) / texWidth v = (cube.uv[1] + pos[4] * cube.size[1]) / texHeight @@ -158,10 +158,10 @@ function addCube(attr, boneId, bone, cube, sameTextureForAllFaces = false, texWi export function getMesh(world, texture, jsonModel, overrides = {}) { let textureWidth = jsonModel.texturewidth ?? 64 let textureHeight = jsonModel.textureheight ?? 64 - let textureOffset = undefined - let useBlockTexture = texture.startsWith('block:'); + let textureOffset + const useBlockTexture = texture.startsWith('block:') if (useBlockTexture) { - const blockName = texture.substring(6) + const blockName = texture.slice(6) const textureInfo = world.blocksAtlasParser.getTextureInfo(blockName) if (textureInfo) { textureWidth = world.material.map.image.width diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index 6cf4e5809..e556f7a32 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -75,7 +75,7 @@ export class WorldDataEmitter extends EventEmitter { this.eventListeners = { // 'move': botPosition, entitySpawn (e: any) { - if (e.name === "item_frame" || e.name === "glow_item_frame") { + if (e.name === 'item_frame' || e.name === 'glow_item_frame') { // Item frames use block positions in the protocol, not their center. Fix that. e.position.translate(0.5, 0.5, 0.5) } From 1ee70a876c67b67c8b86da30ca5634adf0ebd7c2 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 16 Jan 2025 09:25:41 +0700 Subject: [PATCH 05/11] fix lockfile --- pnpm-lock.yaml | 41 ++++------------------------------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 816c036e6..f1417af7e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -426,9 +426,6 @@ importers: minecrafthawkeye: specifier: ^1.3.6 version: 1.3.6 - mineflayer-item-map-downloader: - specifier: github:zardoy/mineflayer-item-map-downloader - version: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7(patch_hash=bck55yjvd4wrgz46x7o4vfur5q)(encoding@0.1.13) prismarine-block: specifier: github:zardoy/prismarine-block#next-era version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/23849d4d24af91f45a5bd38781a6f82d40316c05 @@ -444,9 +441,6 @@ importers: process: specifier: ^0.11.10 version: 0.11.10 - sharp: - specifier: ^0.29.1 - version: 0.29.3 socket.io: specifier: ^4.0.0 version: 4.7.2 @@ -4588,11 +4582,6 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} - detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - detect-libc@2.0.2: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} engines: {node: '>=8'} @@ -6999,9 +6988,6 @@ packages: node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - node-addon-api@4.3.0: - resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} - node-addon-api@5.1.0: resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} @@ -7547,8 +7533,8 @@ packages: version: 1.36.0 engines: {node: '>=14'} - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/aba0d8e1efa49f4c75646cdb9635cfab41ad4ad9: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/aba0d8e1efa49f4c75646cdb9635cfab41ad4ad9} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/cc4d8a232e33e946fa0929dceabe92df4d405734: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/cc4d8a232e33e946fa0929dceabe92df4d405734} version: 1.38.0 engines: {node: '>=14'} @@ -8347,10 +8333,6 @@ packages: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} - sharp@0.29.3: - resolution: {integrity: sha512-fKWUuOw77E4nhpyzCCJR1ayrttHoFHBT2U/kR/qEMRhvPEcluG4BKj324+SCO1e84+knXHwhJ1HHJGnUt4ElGA==} - engines: {node: '>=12.13.0'} - sharp@0.30.7: resolution: {integrity: sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig==} engines: {node: '>=12.13.0'} @@ -14938,8 +14920,6 @@ snapshots: detect-indent@6.1.0: {} - detect-libc@1.0.3: {} - detect-libc@2.0.2: {} detect-node-es@1.1.0: {} @@ -14962,7 +14942,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/aba0d8e1efa49f4c75646cdb9635cfab41ad4ad9(minecraft-data@3.83.1) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/cc4d8a232e33e946fa0929dceabe92df4d405734(minecraft-data@3.83.1) prismarine-registry: 1.10.0 random-seed: 0.3.0 vec3: 0.1.8 @@ -18089,8 +18069,6 @@ snapshots: node-abort-controller@3.1.1: {} - node-addon-api@4.3.0: {} - node-addon-api@5.1.0: {} node-canvas-webgl@0.3.0(encoding@0.1.13): @@ -18708,7 +18686,7 @@ snapshots: transitivePeerDependencies: - minecraft-data - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/aba0d8e1efa49f4c75646cdb9635cfab41ad4ad9(minecraft-data@3.83.1): + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/cc4d8a232e33e946fa0929dceabe92df4d405734(minecraft-data@3.83.1): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.83.1)(prismarine-registry@1.10.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/23849d4d24af91f45a5bd38781a6f82d40316c05 @@ -19744,17 +19722,6 @@ snapshots: dependencies: kind-of: 6.0.3 - sharp@0.29.3: - dependencies: - color: 4.2.3 - detect-libc: 1.0.3 - node-addon-api: 4.3.0 - prebuild-install: 7.1.1 - semver: 7.6.0 - simple-get: 4.0.1 - tar-fs: 2.1.1 - tunnel-agent: 0.6.0 - sharp@0.30.7: dependencies: color: 4.2.3 From 0fc37a5ee08854ec03703f42c402cfa57369d40f Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 16 Jan 2025 09:26:57 +0700 Subject: [PATCH 06/11] remove duplicated plugin load --- prismarine-viewer/viewer/lib/entities.ts | 14 +++++++------- src/react/HeldMapUi.tsx | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.ts b/prismarine-viewer/viewer/lib/entities.ts index 9487bdb9c..f9eb34005 100644 --- a/prismarine-viewer/viewer/lib/entities.ts +++ b/prismarine-viewer/viewer/lib/entities.ts @@ -755,14 +755,14 @@ export class Entities extends EventEmitter { } } - updateMap (mapNumber, data) { + updateMap (mapNumber: string | number, data: string) { this.cachedMapsImages[mapNumber] = data - let itemFrameMeshs = this.itemFrameMaps[mapNumber] - if (!itemFrameMeshs) return - itemFrameMeshs = itemFrameMeshs.filter(mesh => mesh.parent) - this.itemFrameMaps[mapNumber] = itemFrameMeshs - if (itemFrameMeshs) { - for (const mesh of itemFrameMeshs) { + let itemFrameMeshes = this.itemFrameMaps[mapNumber] + if (!itemFrameMeshes) return + itemFrameMeshes = itemFrameMeshes.filter(mesh => mesh.parent) + this.itemFrameMaps[mapNumber] = itemFrameMeshes + if (itemFrameMeshes) { + for (const mesh of itemFrameMeshes) { mesh.material.map = this.loadMap(data) mesh.material.needsUpdate = true mesh.visible = true diff --git a/src/react/HeldMapUi.tsx b/src/react/HeldMapUi.tsx index 8ea77bb3d..fcf3d4484 100644 --- a/src/react/HeldMapUi.tsx +++ b/src/react/HeldMapUi.tsx @@ -6,8 +6,6 @@ export default () => { const [dataUrl, setDataUrl] = useState(null) // true means loading useEffect(() => { - bot.loadPlugin(mapDownloader) - setImageConverter((buf: Uint8Array) => { const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d')! From f6aa84f1bf9493a11605711b3a711002afd6085c Mon Sep 17 00:00:00 2001 From: Phoenix616 Date: Thu, 16 Jan 2025 22:13:19 +0100 Subject: [PATCH 07/11] Fix issues with certain maps and non-rotated items not showing up --- prismarine-viewer/viewer/lib/entities.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.ts b/prismarine-viewer/viewer/lib/entities.ts index f9eb34005..9d58fd142 100644 --- a/prismarine-viewer/viewer/lib/entities.ts +++ b/prismarine-viewer/viewer/lib/entities.ts @@ -714,7 +714,7 @@ export class Entities extends EventEmitter { return false })?.removeFromParent() if (item && (item.itemId ?? item.blockId ?? 0) !== 0) { - const rotation = (itemFrameMeta.rotation as any as number) + const rotation = (itemFrameMeta.rotation as any as number) ?? 0 const mapNumber = item.nbtData?.value?.map?.value if (mapNumber) { // TODO: Use proper larger item frame model when a map exists @@ -780,7 +780,7 @@ export class Entities extends EventEmitter { transparent: true, alphaTest: 0.1, } - if (texture?.image) { + if (texture) { parameters['map'] = texture } const material = new THREE.MeshLambertMaterial(parameters) @@ -803,7 +803,7 @@ export class Entities extends EventEmitter { mapMesh.rotateZ(Math.PI * 2 - rotation * Math.PI / 2) mapMesh.name = `map_${mapNumber}` - if (!texture?.image) { + if (!texture) { mapMesh.visible = false } From 9b98e502c0169669fd6b7cca37c0fe66a94eb9ff Mon Sep 17 00:00:00 2001 From: Phoenix616 Date: Thu, 16 Jan 2025 23:20:06 +0100 Subject: [PATCH 08/11] Fix ceiling/floor frames rotation and item alignment --- prismarine-viewer/viewer/lib/entities.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/prismarine-viewer/viewer/lib/entities.ts b/prismarine-viewer/viewer/lib/entities.ts index 9d58fd142..e0a286aba 100644 --- a/prismarine-viewer/viewer/lib/entities.ts +++ b/prismarine-viewer/viewer/lib/entities.ts @@ -698,6 +698,7 @@ export class Entities extends EventEmitter { // TODO: Figure out why this doesn't match the Item mineflayer type const item = itemFrameMeta?.item as any as { itemId, blockId, nbtData: { value: { map: { value: number } } } } mesh.scale.set(1, 1, 1) + e.rotation.x = -entity.pitch e.children.find(c => { if (c.name.startsWith('map_')) { disposeObject(c) @@ -723,7 +724,7 @@ export class Entities extends EventEmitter { } else { const itemMesh = this.getItemMesh(item) if (itemMesh) { - itemMesh.mesh.position.set(0, 0, 0.45) + itemMesh.mesh.position.set(0, 0, 0.43) itemMesh.mesh.scale.set(0.5, 0.5, 0.5) itemMesh.mesh.rotateY(Math.PI) itemMesh.mesh.rotateZ(rotation * Math.PI / 4) From 47116e0ffbc59c766f6a8082d55f6627938c4553 Mon Sep 17 00:00:00 2001 From: Phoenix616 Date: Thu, 16 Jan 2025 23:25:58 +0100 Subject: [PATCH 09/11] Rename `world` to `worldRenderer` to be clearer what it is --- prismarine-viewer/viewer/lib/entity/EntityMesh.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entity/EntityMesh.js b/prismarine-viewer/viewer/lib/entity/EntityMesh.js index a2b40befa..9033489af 100644 --- a/prismarine-viewer/viewer/lib/entity/EntityMesh.js +++ b/prismarine-viewer/viewer/lib/entity/EntityMesh.js @@ -155,17 +155,17 @@ function addCube(attr, boneId, bone, cube, sameTextureForAllFaces = false, texWi } } -export function getMesh(world, texture, jsonModel, overrides = {}) { +export function getMesh(worldRenderer, texture, jsonModel, overrides = {}) { let textureWidth = jsonModel.texturewidth ?? 64 let textureHeight = jsonModel.textureheight ?? 64 let textureOffset const useBlockTexture = texture.startsWith('block:') if (useBlockTexture) { const blockName = texture.slice(6) - const textureInfo = world.blocksAtlasParser.getTextureInfo(blockName) + const textureInfo = worldRenderer.blocksAtlasParser.getTextureInfo(blockName) if (textureInfo) { - textureWidth = world.material.map.image.width - textureHeight = world.material.map.image.height + textureWidth = worldRenderer.material.map.image.width + textureHeight = worldRenderer.material.map.image.height textureOffset = [textureInfo.u, textureInfo.v] } else { console.error(`Unknown block ${blockName}`) @@ -239,7 +239,7 @@ export function getMesh(world, texture, jsonModel, overrides = {}) { mesh.scale.set(1 / 16, 1 / 16, 1 / 16) if (textureOffset) { - texture = world.material.map.clone() + texture = worldRenderer.material.map.clone() texture.offset.set(textureOffset[0], textureOffset[1]) texture.needsUpdate = true material.map = texture @@ -352,7 +352,7 @@ const offsetEntity = { // eslint-disable-next-line @typescript-eslint/no-extraneous-class export class EntityMesh { - constructor(version, type, world, /** @type {{textures?, rotation?: Record}} */overrides = {}) { + constructor(version, type, worldRenderer, /** @type {{textures?, rotation?: Record}} */overrides = {}) { const originalType = type const mappedValue = temporaryMap[type] if (mappedValue) type = mappedValue @@ -419,7 +419,7 @@ export class EntityMesh { const texture = overrides.textures?.[name] ?? e.textures[name] if (!texture) continue // console.log(JSON.stringify(jsonModel, null, 2)) - const mesh = getMesh(world, texture, jsonModel, overrides) + const mesh = getMesh(worldRenderer, texture, jsonModel, overrides) mesh.name = `geometry_${name}` this.mesh.add(mesh) From a289a3100585f6c99a5e2c5c990f67e8d0121696 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 25 Jan 2025 20:24:26 +0300 Subject: [PATCH 10/11] rm up --- src/worldInteractions.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index a5bfb61f3..1134d7f89 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -5,7 +5,6 @@ import * as THREE from 'three' // wouldn't better to create atlas instead? import { Vec3 } from 'vec3' import { LineMaterial } from 'three-stdlib' -import { mapDownloader } from 'mineflayer-item-map-downloader/' import { Entity } from 'prismarine-entity' import destroyStage0 from '../assets/destroy_stage_0.png' import destroyStage1 from '../assets/destroy_stage_1.png' @@ -159,11 +158,6 @@ class WorldInteraction { upLineMaterial() // todo use gamemode update only bot.on('game', upLineMaterial) - - bot.loadPlugin(mapDownloader) - bot.mapDownloader.on('new_map', ({ png, id }) => { - viewer.entities.updateMap(id, png) - }) } activateEntity (entity: Entity) { From 91b4778b387567de249de87320c2f9edeea686e7 Mon Sep 17 00:00:00 2001 From: Phoenix616 Date: Mon, 27 Jan 2025 12:12:42 +0100 Subject: [PATCH 11/11] Support map numbers from components in ItemFrames too --- prismarine-viewer/viewer/lib/entities.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.ts b/prismarine-viewer/viewer/lib/entities.ts index e0a286aba..26a528a57 100644 --- a/prismarine-viewer/viewer/lib/entities.ts +++ b/prismarine-viewer/viewer/lib/entities.ts @@ -696,7 +696,7 @@ export class Entities extends EventEmitter { } if (itemFrameMeta) { // TODO: Figure out why this doesn't match the Item mineflayer type - const item = itemFrameMeta?.item as any as { itemId, blockId, nbtData: { value: { map: { value: number } } } } + const item = itemFrameMeta?.item as any as { itemId, blockId, components, nbtData: { value: { map: { value: number } } } } mesh.scale.set(1, 1, 1) e.rotation.x = -entity.pitch e.children.find(c => { @@ -716,7 +716,7 @@ export class Entities extends EventEmitter { })?.removeFromParent() if (item && (item.itemId ?? item.blockId ?? 0) !== 0) { const rotation = (itemFrameMeta.rotation as any as number) ?? 0 - const mapNumber = item.nbtData?.value?.map?.value + const mapNumber = item.nbtData?.value?.map?.value ?? item.components?.find(x => x.type === 'map_id')?.data if (mapNumber) { // TODO: Use proper larger item frame model when a map exists mesh.scale.set(16 / 12, 16 / 12, 1)