From e2ee1ff13331af19390894128c744d4b33673db3 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Wed, 12 Feb 2025 16:06:43 +0300 Subject: [PATCH 01/32] Fix setting of lastError to avoid false spam into console --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 8e85c039..f168b6e4 100644 --- a/index.html +++ b/index.html @@ -54,8 +54,8 @@ }) }) } + window.lastError = errorOrMessage instanceof Error ? errorOrMessage : new Error(errorOrMessage) } - window.lastError = errorOrMessage instanceof Error ? errorOrMessage : new Error(errorOrMessage) } window.addEventListener('unhandledrejection', (e) => onError(e.reason, true)) window.addEventListener('error', (e) => onError(e.error ?? e.message)) From cab9eed5e77cd1c4c3ac337b3ca47988f05a0997 Mon Sep 17 00:00:00 2001 From: Max Lee Date: Wed, 12 Feb 2025 19:26:23 +0100 Subject: [PATCH 02/32] fix: resource pack armor textures and leather armor color bleed (#274) --- renderer/viewer/lib/entities.ts | 12 ++-- renderer/viewer/lib/entity/armorModels.ts | 67 +++++++++++----------- renderer/viewer/lib/entity/objModels.js | 1 - renderer/viewer/lib/worldrendererCommon.ts | 1 + src/resourcePack.ts | 29 +++++++++- 5 files changed, 67 insertions(+), 43 deletions(-) diff --git a/renderer/viewer/lib/entities.ts b/renderer/viewer/lib/entities.ts index 0dcd8ec1..72969840 100644 --- a/renderer/viewer/lib/entities.ts +++ b/renderer/viewer/lib/entities.ts @@ -20,7 +20,7 @@ import * as Entity from './entity/EntityMesh' import { getMesh } from './entity/EntityMesh' import { WalkingGeneralSwing } from './entity/animations' import { disposeObject } from './threeJsUtils' -import { armorModels } from './entity/objModels' +import { armorModel, armorTextures } from './entity/armorModels' import { Viewer } from './viewer' import { getBlockMeshFromModel } from './holdingBlock' const { loadTexture } = globalThis.isElectron ? require('./utils.electron.js') : require('./utils') @@ -950,11 +950,11 @@ function addArmorModel (entityMesh: THREE.Object3D, slotType: string, item: Item } const armorMaterial = itemParts[0] if (!texturePath) { - // TODO: Support resource pack // TODO: Support mirroring on certain parts of the model - texturePath = armorModels[`${armorMaterial}Layer${layer}${overlay ? 'Overlay' : ''}`] + const armorTextureName = `${armorMaterial}_layer_${layer}${overlay ? '_overlay' : ''}` + texturePath = viewer.world.customTextures.armor?.textures[armorTextureName]?.src ?? armorTextures[armorTextureName] } - if (!texturePath || !armorModels.armorModel[slotType]) { + if (!texturePath || !armorModel[slotType]) { removeArmorModel(entityMesh, slotType) return } @@ -973,7 +973,7 @@ function addArmorModel (entityMesh: THREE.Object3D, slotType: string, item: Item material.map = texture }) } else { - mesh = getMesh(viewer.world, texturePath, armorModels.armorModel[slotType]) + mesh = getMesh(viewer.world, texturePath, armorModel[slotType]) mesh.name = meshName material = mesh.material if (!isPlayerHead) { @@ -991,6 +991,8 @@ function addArmorModel (entityMesh: THREE.Object3D, slotType: string, item: Item material.color.setHex(0xB5_6D_51) // default brown color } addArmorModel(entityMesh, slotType, item, layer, true) + } else { + material.color.setHex(0xFF_FF_FF) } const group = new THREE.Object3D() group.name = `armor_${slotType}${overlay ? '_overlay' : ''}` diff --git a/renderer/viewer/lib/entity/armorModels.ts b/renderer/viewer/lib/entity/armorModels.ts index e1d3f87b..3a87f8db 100644 --- a/renderer/viewer/lib/entity/armorModels.ts +++ b/renderer/viewer/lib/entity/armorModels.ts @@ -1,36 +1,35 @@ -/* - * prismarine-web-client - prismarine-web-client - * Copyright (C) 2024 Max Lee aka Phoenix616 (mail@moep.tv) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -// TODO: replace with load from resource pack -export { default as chainmailLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/chainmail_layer_1.png' -export { default as chainmailLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/chainmail_layer_2.png' -export { default as diamondLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/diamond_layer_1.png' -export { default as diamondLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/diamond_layer_2.png' -export { default as goldenLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/gold_layer_1.png' -export { default as goldenLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/gold_layer_2.png' -export { default as ironLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/iron_layer_1.png' -export { default as ironLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/iron_layer_2.png' -export { default as leatherLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_1.png' -export { default as leatherLayer1Overlay } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_1_overlay.png' -export { default as leatherLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_2.png' -export { default as leatherLayer2Overlay } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_2_overlay.png' -export { default as netheriteLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/netherite_layer_1.png' -export { default as netheriteLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/netherite_layer_2.png' -export { default as turtleLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/turtle_layer_1.png' +import { default as chainmailLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/chainmail_layer_1.png' +import { default as chainmailLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/chainmail_layer_2.png' +import { default as diamondLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/diamond_layer_1.png' +import { default as diamondLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/diamond_layer_2.png' +import { default as goldenLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/gold_layer_1.png' +import { default as goldenLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/gold_layer_2.png' +import { default as ironLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/iron_layer_1.png' +import { default as ironLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/iron_layer_2.png' +import { default as leatherLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_1.png' +import { default as leatherLayer1Overlay } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_1_overlay.png' +import { default as leatherLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_2.png' +import { default as leatherLayer2Overlay } from 'mc-assets/dist/other-textures/latest/models/armor/leather_layer_2_overlay.png' +import { default as netheriteLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/netherite_layer_1.png' +import { default as netheriteLayer2 } from 'mc-assets/dist/other-textures/latest/models/armor/netherite_layer_2.png' +import { default as turtleLayer1 } from 'mc-assets/dist/other-textures/latest/models/armor/turtle_layer_1.png' export { default as armorModel } from './armorModels.json' + +export const armorTextures = { + 'leather_layer_1': leatherLayer1, + 'leather_layer_1_overlay': leatherLayer1Overlay, + 'leather_layer_2': leatherLayer2, + 'leather_layer_2_overlay': leatherLayer2Overlay, + 'chainmail_layer_1': chainmailLayer1, + 'chainmail_layer_2': chainmailLayer2, + 'iron_layer_1': ironLayer1, + 'iron_layer_2': ironLayer2, + 'diamond_layer_1': diamondLayer1, + 'diamond_layer_2': diamondLayer2, + 'golden_layer_1': goldenLayer1, + 'golden_layer_2': goldenLayer2, + 'netherite_layer_1': netheriteLayer1, + 'netherite_layer_2': netheriteLayer2, + 'turtle_layer_1': turtleLayer1 +} diff --git a/renderer/viewer/lib/entity/objModels.js b/renderer/viewer/lib/entity/objModels.js index 5af29606..edff440b 100644 --- a/renderer/viewer/lib/entity/objModels.js +++ b/renderer/viewer/lib/entity/objModels.js @@ -1,2 +1 @@ export * as externalModels from './exportedModels' -export * as armorModels from './armorModels' diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts index 327298af..bdc2e128 100644 --- a/renderer/viewer/lib/worldrendererCommon.ts +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -124,6 +124,7 @@ export abstract class WorldRendererCommon customTextures: { items?: CustomTexturesData blocks?: CustomTexturesData + armor?: CustomTexturesData } = {} workersProcessAverageTime = 0 workersProcessAverageTimeCount = 0 diff --git a/src/resourcePack.ts b/src/resourcePack.ts index 60e92b40..3ad1b2e9 100644 --- a/src/resourcePack.ts +++ b/src/resourcePack.ts @@ -4,6 +4,7 @@ import fs from 'fs' import JSZip from 'jszip' import { proxy, subscribe } from 'valtio' import { WorldRendererThree } from 'renderer/viewer/lib/worldrendererThree' +import { armorTextures } from 'renderer/viewer/lib/entity/armorModels' import { collectFilesToCopy, copyFilesAsyncWithProgress, mkdirRecursive, removeFileRecursiveAsync } from './browserfs' import { setLoadingScreenStatus } from './appStatus' import { showNotification } from './react/NotificationProvider' @@ -203,7 +204,7 @@ const getFilesMapFromDir = async (dir: string) => { return files } -export const getResourcepackTiles = async (type: 'blocks' | 'items', existingTextures: string[]) => { +export const getResourcepackTiles = async (type: 'blocks' | 'items' | 'armor', existingTextures: string[]) => { const basePath = await getActiveResourcepackBasePath() if (!basePath) return let firstTextureSize: number | undefined @@ -212,11 +213,25 @@ export const getResourcepackTiles = async (type: 'blocks' | 'items', existingTex setLoadingScreenStatus(`Generating atlas texture for ${type}`) } const textures = {} as Record + let path + switch (type) { + case 'blocks': + path = 'block' + break + case 'items': + path = 'item' + break + case 'armor': + path = 'models/armor' + break + default: + throw new Error('Invalid type') + } for (const namespace of namespaces) { const texturesCommonBasePath = `${basePath}/assets/${namespace}/textures` const isMinecraftNamespace = namespace === 'minecraft' - let texturesBasePath = `${texturesCommonBasePath}/${type === 'blocks' ? 'block' : 'item'}` - const texturesBasePathAlt = `${texturesCommonBasePath}/${type === 'blocks' ? 'blocks' : 'items'}` + let texturesBasePath = `${texturesCommonBasePath}/${path}` + const texturesBasePathAlt = `${texturesCommonBasePath}/${path}s` if (!(await existsAsync(texturesBasePath))) { if (await existsAsync(texturesBasePathAlt)) { texturesBasePath = texturesBasePathAlt @@ -465,9 +480,11 @@ const repeatArr = (arr, i) => Array.from({ length: i }, () => arr) const updateTextures = async () => { const origBlocksFiles = Object.keys(viewer.world.sourceData.blocksAtlases.latest.textures) const origItemsFiles = Object.keys(viewer.world.sourceData.itemsAtlases.latest.textures) + const origArmorFiles = Object.keys(armorTextures) const { usedTextures: extraBlockTextures = new Set() } = await prepareBlockstatesAndModels() ?? {} const blocksData = await getResourcepackTiles('blocks', [...origBlocksFiles, ...extraBlockTextures]) const itemsData = await getResourcepackTiles('items', origItemsFiles) + const armorData = await getResourcepackTiles('armor', origArmorFiles) await updateAllReplacableTextures() viewer.world.customTextures = {} if (blocksData) { @@ -482,6 +499,12 @@ const updateTextures = async () => { textures: itemsData.textures } } + if (armorData) { + viewer.world.customTextures.armor = { + tileSize: armorData.firstTextureSize, + textures: armorData.textures + } + } if (viewer.world.active) { await viewer.world.updateTexturesData() if (viewer.world instanceof WorldRendererThree) { From 25c07b14a91ee98e621a3c0069566cebf24495eb Mon Sep 17 00:00:00 2001 From: gguio <109200692+gguio@users.noreply.github.com> Date: Thu, 13 Feb 2025 06:07:19 +0400 Subject: [PATCH 03/32] feat: some minimap fixes (#249) --- renderer/playground/scenes/main.ts | 2 +- renderer/viewer/lib/worldrendererCommon.ts | 15 +- src/controls.ts | 17 +- src/globalState.ts | 1 + src/react/Fullmap.tsx | 98 +++------ src/react/Minimap.stories.tsx | 74 ------- src/react/Minimap.tsx | 103 ++------- src/react/MinimapDrawer.ts | 46 ++-- src/react/MinimapProvider.tsx | 245 +++++++++------------ src/reactUi.tsx | 13 +- 10 files changed, 210 insertions(+), 404 deletions(-) delete mode 100644 src/react/Minimap.stories.tsx diff --git a/renderer/playground/scenes/main.ts b/renderer/playground/scenes/main.ts index 33fe2528..73a36762 100644 --- a/renderer/playground/scenes/main.ts +++ b/renderer/playground/scenes/main.ts @@ -295,7 +295,7 @@ class MainScene extends BasePlaygroundScene { } } - worldView!.setBlockStateId(this.targetPos, block.stateId) + worldView!.setBlockStateId(this.targetPos, block.stateId ?? 0) console.log('up stateId', block.stateId) this.params.metadata = block.metadata this.metadataGui.updateDisplay() diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts index bdc2e128..b276241a 100644 --- a/renderer/viewer/lib/worldrendererCommon.ts +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -180,12 +180,18 @@ export abstract class WorldRendererCommon this.geometryReceiveCount[data.workerIndex] ??= 0 this.geometryReceiveCount[data.workerIndex]++ const geometry = data.geometry as MesherGeometryOutput - for (const key in geometry.highestBlocks) { - const highest = geometry.highestBlocks[key] - if (!this.highestBlocks[key] || this.highestBlocks[key].y < highest.y) { - this.highestBlocks[key] = highest + for (const [key, highest] of geometry.highestBlocks.entries()) { + const currHighest = this.highestBlocks.get(key) + if (!currHighest || currHighest.y < highest.y) { + this.highestBlocks.set(key, highest) } } + // for (const key in geometry.highestBlocks) { + // const highest = geometry.highestBlocks[key] + // if (!this.highestBlocks[key] || this.highestBlocks[key].y < highest.y) { + // this.highestBlocks[key] = highest + // } + // } const chunkCoords = data.key.split(',').map(Number) this.lastChunkDistance = Math.max(...this.getDistance(new Vec3(chunkCoords[0], 0, chunkCoords[2]))) } @@ -205,6 +211,7 @@ export abstract class WorldRendererCommon return x === chunkCoords[0] && z === chunkCoords[2] })) { this.finishedChunks[`${chunkCoords[0]},${chunkCoords[2]}`] = true + this.renderUpdateEmitter.emit(`chunkFinished`, `${chunkCoords[0] / 16},${chunkCoords[2] / 16}`) } } this.checkAllFinished() diff --git a/src/controls.ts b/src/controls.ts index deee9c68..b0add043 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -524,13 +524,18 @@ contro.on('trigger', ({ command }) => { if (command === 'ui.toggleFullscreen') { void goFullscreen(true) } +}) - if (command === 'ui.toggleMap') { - if (activeModalStack.at(-1)?.reactType === 'full-map') { - hideModal({ reactType: 'full-map' }) - } else { - showModal({ reactType: 'full-map' }) - } +// show-hide Fullmap +contro.on('trigger', ({ command }) => { + if (command !== 'ui.toggleMap') return + const isActive = isGameActive(true) + if (activeModalStack.at(-1)?.reactType === 'full-map') { + miscUiState.displayFullmap = false + hideModal({ reactType: 'full-map' }) + } else if (isActive && !activeModalStack.length) { + miscUiState.displayFullmap = true + showModal({ reactType: 'full-map' }) } }) diff --git a/src/globalState.ts b/src/globalState.ts index 0fb1dc69..992503ef 100644 --- a/src/globalState.ts +++ b/src/globalState.ts @@ -137,6 +137,7 @@ export const miscUiState = proxy({ usingGamepadInput: false, appConfig: null as AppConfig | null, displaySearchInput: false, + displayFullmap: false }) export const isGameActive = (foregroundCheck: boolean) => { diff --git a/src/react/Fullmap.tsx b/src/react/Fullmap.tsx index 69a2c514..39c5e954 100644 --- a/src/react/Fullmap.tsx +++ b/src/react/Fullmap.tsx @@ -2,23 +2,21 @@ import { Vec3 } from 'vec3' import { useRef, useEffect, useState, CSSProperties, Dispatch, SetStateAction } from 'react' import { WorldWarp } from 'flying-squid/dist/lib/modules/warps' import { TransformWrapper, TransformComponent, ReactZoomPanPinchRef } from 'react-zoom-pan-pinch' -import { MinimapDrawer, DrawerAdapter, ChunkInfo } from './MinimapDrawer' +import { DrawerAdapter } from './MinimapDrawer' import Button from './Button' import Input from './Input' import './Fullmap.css' type FullmapProps = { - toggleFullMap: () => void, adapter: DrawerAdapter, - drawer: MinimapDrawer | null, - canvasRef: any + toggleFullMap?: () => void, } -export default ({ toggleFullMap, adapter }: FullmapProps) => { +export default ({ adapter, toggleFullMap }: FullmapProps) => { const [grid, setGrid] = useState(() => new Set()) const zoomRef = useRef(null) - const redrawCell = useRef(false) + const [redraw, setRedraw] = useState | null>(null) const [lastWarpPos, setLastWarpPos] = useState({ x: 0, y: 0, z: 0 }) const stateRef = useRef({ scale: 1, positionX: 0, positionY: 0 }) const cells = useRef({ columns: 0, rows: 0 }) @@ -73,7 +71,7 @@ export default ({ toggleFullMap, adapter }: FullmapProps) => { zIndex: '-1' }} onClick={toggleFullMap} - /> + > : + )} {!lockConnect && <>
diff --git a/src/react/PixelartIcon.tsx b/src/react/PixelartIcon.tsx index 5e6302e8..8694d9f5 100644 --- a/src/react/PixelartIcon.tsx +++ b/src/react/PixelartIcon.tsx @@ -8,7 +8,7 @@ export default ({ className = undefined as undefined | string, onClick = () => { } }) => { - if (width !== undefined) styles = { width, height: width, ...styles } + if (width !== undefined) styles = { width, height: width, fontSize: width, ...styles } iconName = iconName.replace('pixelarticons:', '') return
Date: Tue, 18 Feb 2025 20:37:15 +0300 Subject: [PATCH 20/32] minor visual updates to status component --- src/react/NetworkStatus.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/react/NetworkStatus.tsx b/src/react/NetworkStatus.tsx index 57e3990e..386e08cf 100644 --- a/src/react/NetworkStatus.tsx +++ b/src/react/NetworkStatus.tsx @@ -37,16 +37,16 @@ export default () => { return () => clearInterval(interval) }, []) - // if (!lastConnectOptions.value?.proxy) return null + if (!lastConnectOptions.value?.proxy) return null const { username } = bot.player - const { proxy: proxyUrl, server: serverIp } = lastConnectOptions.value! + const { proxy: proxyUrl, server: serverIp } = lastConnectOptions.value const pingTotal = serverPing const ICON_SIZE = 18 return (
- + From 0cd11ebe293576ea2d3c185110f534348a1bd392 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 18 Feb 2025 20:58:19 +0300 Subject: [PATCH 21/32] regression hand disappeared --- src/devtools.ts | 10 ++++++++++ src/index.ts | 13 +++++++------ src/watchOptions.ts | 1 + 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/devtools.ts b/src/devtools.ts index e534c293..5d0be20b 100644 --- a/src/devtools.ts +++ b/src/devtools.ts @@ -150,3 +150,13 @@ Object.defineProperty(window, 'debugToggle', { customEvents.on('gameLoaded', () => { window.holdingBlock = (viewer.world as WorldRendererThree).holdingBlock }) + +window.clearStorage = (...keysToKeep: string[]) => { + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i) + if (key && !keysToKeep.includes(key)) { + localStorage.removeItem(key) + } + } + return `Cleared ${localStorage.length - keysToKeep.length} items from localStorage. Kept: ${keysToKeep.join(', ')}` +} diff --git a/src/index.ts b/src/index.ts index a21fa001..74bf2f27 100644 --- a/src/index.ts +++ b/src/index.ts @@ -711,6 +711,13 @@ export async function connect (connectOptions: ConnectOptions) { worldInteractions.initBot() setLoadingScreenStatus('Loading world') + + const mcData = MinecraftData(bot.version) + window.PrismarineBlock = PrismarineBlock(mcData.version.minecraftVersion!) + window.PrismarineItem = PrismarineItem(mcData.version.minecraftVersion!) + window.loadedData = mcData + window.Vec3 = Vec3 + window.pathfinder = pathfinder }) const spawnEarlier = !singleplayer && !p2pMultiplayer @@ -731,12 +738,6 @@ export async function connect (connectOptions: ConnectOptions) { } window.focus?.() errorAbortController.abort() - const mcData = MinecraftData(bot.version) - window.PrismarineBlock = PrismarineBlock(mcData.version.minecraftVersion!) - window.PrismarineItem = PrismarineItem(mcData.version.minecraftVersion!) - window.loadedData = mcData - window.Vec3 = Vec3 - window.pathfinder = pathfinder miscUiState.gameLoaded = true miscUiState.loadedServerIndex = connectOptions.serverIndex ?? '' diff --git a/src/watchOptions.ts b/src/watchOptions.ts index acedad71..724fb2ba 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -97,6 +97,7 @@ export const watchOptionsAfterWorldViewInit = () => { if (!worldView) return worldView.keepChunksDistance = o.keepChunksDistance viewer.world.config.renderEars = o.renderEars + viewer.world.config.showHand = o.showHand viewer.world.config.viewBobbing = o.viewBobbing }) } From 44d630b1b3f7ebbb98e1002f3446fc2a927d0e58 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 18 Feb 2025 21:25:18 +0300 Subject: [PATCH 22/32] fix entities apply skin crash fix websocket ping display for ws --- renderer/viewer/lib/entities.ts | 13 +++++-- src/index.ts | 5 ++- src/react/AppStatusProvider.tsx | 1 + src/react/NetworkStatus.module.css | 4 +++ src/react/NetworkStatus.module.css.d.ts | 1 + src/react/NetworkStatus.tsx | 45 +++++++++++++++---------- 6 files changed, 48 insertions(+), 21 deletions(-) diff --git a/renderer/viewer/lib/entities.ts b/renderer/viewer/lib/entities.ts index 21802089..df7ea926 100644 --- a/renderer/viewer/lib/entities.ts +++ b/renderer/viewer/lib/entities.ts @@ -383,19 +383,26 @@ export class Entities extends EventEmitter { if (!playerObject) return let skinTexture: THREE.Texture + let skinCanvas: HTMLCanvasElement if (skinUrl === stevePngUrl) { skinTexture = await steveTexture + const canvas = document.createElement('canvas') + const ctx = canvas.getContext('2d') + if (!ctx) throw new Error('Failed to get context') + ctx.drawImage(skinTexture.image, 0, 0) + skinCanvas = canvas } else { - const { canvas: skinCanvas, image } = await loadSkinImage(skinUrl) + const { canvas, image } = await loadSkinImage(skinUrl) playerCustomSkinImage = image - skinTexture = new THREE.CanvasTexture(skinCanvas) + skinTexture = new THREE.CanvasTexture(canvas) + skinCanvas = canvas } skinTexture.magFilter = THREE.NearestFilter skinTexture.minFilter = THREE.NearestFilter skinTexture.needsUpdate = true playerObject.skin.map = skinTexture as any - playerObject.skin.modelType = inferModelType(skinTexture.image) + playerObject.skin.modelType = inferModelType(skinCanvas) let earsCanvas if (renderEars && playerCustomSkinImage) { diff --git a/src/index.ts b/src/index.ts index 74bf2f27..941b76c2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -644,7 +644,6 @@ export async function connect (connectOptions: ConnectOptions) { }) }) }) - bot.loadPlugin(ping) } // socket setup actually can be delayed because of dns lookup if (bot._client.socket) { @@ -662,6 +661,10 @@ export async function connect (connectOptions: ConnectOptions) { } catch (err) { handleError(err) } + + if (connectOptions.server) { + bot.loadPlugin(ping) + } if (!bot) return const p2pConnectTimeout = p2pMultiplayer ? setTimeout(() => { throw new UserError('Spawn timeout. There might be error on the other side, check console.') }, 20_000) : undefined diff --git a/src/react/AppStatusProvider.tsx b/src/react/AppStatusProvider.tsx index 955a2cc5..09fcb40a 100644 --- a/src/react/AppStatusProvider.tsx +++ b/src/react/AppStatusProvider.tsx @@ -36,6 +36,7 @@ export const resetAppStatusState = () => { export const lastConnectOptions = { value: null as ConnectOptions | null } +globalThis.lastConnectOptions = lastConnectOptions const saveReconnectOptions = (options: ConnectOptions) => { sessionStorage.setItem('reconnectOptions', JSON.stringify({ diff --git a/src/react/NetworkStatus.module.css b/src/react/NetworkStatus.module.css index 3752379e..372ea79f 100644 --- a/src/react/NetworkStatus.module.css +++ b/src/react/NetworkStatus.module.css @@ -13,6 +13,10 @@ justify-items: center; } +.container.websocket { + grid-template-columns: auto auto auto; +} + .iconRow { display: block; } diff --git a/src/react/NetworkStatus.module.css.d.ts b/src/react/NetworkStatus.module.css.d.ts index 13cb6950..bea85a4c 100644 --- a/src/react/NetworkStatus.module.css.d.ts +++ b/src/react/NetworkStatus.module.css.d.ts @@ -7,6 +7,7 @@ interface CssExports { iconRow: string; ping: string; totalRow: string; + websocket: string; } declare const cssExports: CssExports; export default cssExports; diff --git a/src/react/NetworkStatus.tsx b/src/react/NetworkStatus.tsx index 386e08cf..27d619d7 100644 --- a/src/react/NetworkStatus.tsx +++ b/src/react/NetworkStatus.tsx @@ -1,4 +1,5 @@ -import { useEffect, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' +import { parseServerAddress } from '../parseServerAddress' import { lastConnectOptions } from './AppStatusProvider' import PixelartIcon, { pixelartIcons } from './PixelartIcon' import styles from './NetworkStatus.module.css' @@ -7,22 +8,23 @@ export default () => { const [proxyPing, setProxyPing] = useState(null) const [serverPing, setServerPing] = useState(null) - useEffect(() => { - if (!lastConnectOptions.value?.proxy) return + const isWebSocket = useMemo(() => parseServerAddress(lastConnectOptions.value?.server).isWebSocket, [lastConnectOptions.value?.server]) + const serverIp = useMemo(() => lastConnectOptions.value?.server, []) - let update = 0 + useEffect(() => { + if (!serverIp) return const updatePing = async () => { - const currentUpdate = ++update - const updateServerPing = async () => { const ping = await bot.pingServer() if (ping) setServerPing(ping) } const updateProxyPing = async () => { - const ping = await bot.pingProxy() - setProxyPing(ping) + if (!isWebSocket) { + const ping = await bot.pingProxy() + setProxyPing(ping) + } } try { @@ -37,28 +39,37 @@ export default () => { return () => clearInterval(interval) }, []) - if (!lastConnectOptions.value?.proxy) return null + if (!serverIp) return null const { username } = bot.player - const { proxy: proxyUrl, server: serverIp } = lastConnectOptions.value + const { proxy: proxyUrl } = lastConnectOptions.value! const pingTotal = serverPing const ICON_SIZE = 18 + return ( -
+
- - + {!isWebSocket && ( + <> + + + + )} {username} - {proxyPing}ms - {proxyUrl} - {pingTotal ? pingTotal - (proxyPing ?? 0) : '...'}ms + {!isWebSocket && ( + <> + {proxyPing}ms + {proxyUrl} + + )} + {isWebSocket ? (pingTotal || '?') : (pingTotal ? pingTotal - (proxyPing ?? 0) : '...')}ms {serverIp} - Ping: {pingTotal}ms + Ping: {pingTotal || '?'}ms
) } From f8c44ae4f01328bfde5d56e4e3555127287706e9 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 19 Feb 2025 02:57:21 +0300 Subject: [PATCH 23/32] add mirror server for play.mcraft.fun --- config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.json b/config.json index 58b35a75..d6d68b94 100644 --- a/config.json +++ b/config.json @@ -9,6 +9,9 @@ { "ip": "ws://play.mcraft.fun" }, + { + "ip": "ws://play2.mcraft.fun" + }, { "ip": "kaboom.pw", "version": "1.20.3", From a0a01d9a3fa65aaf2f18118168c77a948c706962 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 19 Feb 2025 03:01:52 +0300 Subject: [PATCH 24/32] disable possibly invalid entity checks --- renderer/viewer/lib/entity/EntityMesh.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/renderer/viewer/lib/entity/EntityMesh.ts b/renderer/viewer/lib/entity/EntityMesh.ts index f0b90e19..74023794 100644 --- a/renderer/viewer/lib/entity/EntityMesh.ts +++ b/renderer/viewer/lib/entity/EntityMesh.ts @@ -175,14 +175,14 @@ function addCube ( u = (cube.uv[0] + dot(pos[3] ? u1 : u0, cube.size)) / texWidth v = (cube.uv[1] + dot(pos[4] ? v1 : v0, cube.size)) / texHeight } - if (isNaN(u) || isNaN(v)) { - errors.push(`NaN u: ${u}, v: ${v}`) - continue - } - if (u < 0 || u > 1 || v < 0 || v > 1) { - errors.push(`u: ${u}, v: ${v} out of range`) - continue - } + // if (isNaN(u) || isNaN(v)) { + // errors.push(`NaN u: ${u}, v: ${v}`) + // continue + // } + // if (u < 0 || u > 1 || v < 0 || v > 1) { + // errors.push(`u: ${u}, v: ${v} out of range`) + // continue + // } const posX = eastOrWest && mirror ? pos[0] ^ 1 : pos[0] const posY = pos[1] From b7e6793c07c8aabab3a7b635a487606c703c2d9f Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 19 Feb 2025 03:13:28 +0300 Subject: [PATCH 25/32] do not display invisible ears on steve (default skin) --- renderer/viewer/lib/entities.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/renderer/viewer/lib/entities.ts b/renderer/viewer/lib/entities.ts index df7ea926..a09d57eb 100644 --- a/renderer/viewer/lib/entities.ts +++ b/renderer/viewer/lib/entities.ts @@ -404,14 +404,16 @@ export class Entities extends EventEmitter { playerObject.skin.map = skinTexture as any playerObject.skin.modelType = inferModelType(skinCanvas) - let earsCanvas - if (renderEars && playerCustomSkinImage) { + let earsCanvas: HTMLCanvasElement | undefined + if (!playerCustomSkinImage) { + renderEars = false + } else if (renderEars) { earsCanvas = document.createElement('canvas') loadEarsToCanvasFromSkin(earsCanvas, playerCustomSkinImage) renderEars = !this.isCanvasBlank(earsCanvas) } if (renderEars) { - const earsTexture = new THREE.CanvasTexture(earsCanvas) + const earsTexture = new THREE.CanvasTexture(earsCanvas!) earsTexture.magFilter = THREE.NearestFilter earsTexture.minFilter = THREE.NearestFilter earsTexture.needsUpdate = true From 0bb63010569ceace36234be3fcbf10b03ad74a9d Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 19 Feb 2025 03:26:14 +0300 Subject: [PATCH 26/32] feat: now always focus chat when letter or ctrl+v is pressed (like in discord) feat: hide completions when input is not focused --- src/react/Chat.tsx | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/react/Chat.tsx b/src/react/Chat.tsx index a0fcc241..1752daba 100644 --- a/src/react/Chat.tsx +++ b/src/react/Chat.tsx @@ -70,6 +70,7 @@ export default ({ placeholder }: Props) => { const sendHistoryRef = useRef(JSON.parse(window.sessionStorage.chatHistory || '[]')) + const [isInputFocused, setIsInputFocused] = useState(false) const [completePadText, setCompletePadText] = useState('') const completeRequestValue = useRef('') @@ -127,13 +128,31 @@ export default ({ if (!usingTouch) { chatInput.current.focus() } - const unsubscribe = subscribe(chatInputValueGlobal, () => { + + // Add keyboard event listener for letter keys and paste + const handleKeyDown = (e: KeyboardEvent) => { + // Check if it's a single character key (works with any layout) without modifiers except shift + const isSingleChar = e.key.length === 1 && !e.ctrlKey && !e.altKey && !e.metaKey + // Check if it's paste command + const isPaste = e.code === 'KeyV' && (e.ctrlKey || e.metaKey) + + if ((isSingleChar || isPaste) && document.activeElement !== chatInput.current) { + chatInput.current.focus() + } + } + + window.addEventListener('keydown', handleKeyDown) + const unsubscribeValtio = subscribe(chatInputValueGlobal, () => { if (!chatInputValueGlobal.value) return updateInputValue(chatInputValueGlobal.value) chatInputValueGlobal.value = '' chatInput.current.focus() }) - return unsubscribe + + return () => { + window.removeEventListener('keydown', handleKeyDown) + unsubscribeValtio() + } } }, [opened]) @@ -213,7 +232,7 @@ export default ({ {/* close button */} {usingTouch && - )} {!lockConnect && <> } + {noConnection && ( + + )}
} From 795f241cbd69604f846c9e6a064d611fcc4d5559 Mon Sep 17 00:00:00 2001 From: Max Lee Date: Wed, 19 Feb 2025 01:53:36 +0100 Subject: [PATCH 30/32] fix: floor and ceiling button hitboxes (#282) Co-authored-by: Vitaly --- src/interactionShapesGenerated.json | 832 ++++++++++++++-------------- 1 file changed, 416 insertions(+), 416 deletions(-) diff --git a/src/interactionShapesGenerated.json b/src/interactionShapesGenerated.json index 425cfb0d..8c8c283e 100644 --- a/src/interactionShapesGenerated.json +++ b/src/interactionShapesGenerated.json @@ -1632,20 +1632,20 @@ }, "stone_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -1664,34 +1664,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -1760,20 +1760,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -1792,34 +1792,34 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] @@ -2374,20 +2374,20 @@ }, "oak_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -2406,34 +2406,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -2502,20 +2502,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -2534,54 +2534,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "spruce_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -2600,34 +2600,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -2696,20 +2696,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -2728,54 +2728,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "birch_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -2794,34 +2794,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -2890,20 +2890,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -2922,54 +2922,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "jungle_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -2988,34 +2988,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -3084,20 +3084,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -3116,54 +3116,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "acacia_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -3182,34 +3182,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -3278,20 +3278,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -3310,54 +3310,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "cherry_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -3376,34 +3376,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -3472,20 +3472,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -3504,54 +3504,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "dark_oak_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -3570,34 +3570,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -3666,20 +3666,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -3698,54 +3698,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "mangrove_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -3764,34 +3764,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -3860,20 +3860,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -3892,54 +3892,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "bamboo_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -3958,34 +3958,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -4054,20 +4054,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -4086,34 +4086,34 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] @@ -5813,20 +5813,20 @@ }, "crimson_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -5845,34 +5845,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -5941,20 +5941,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -5973,54 +5973,54 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] }, "warped_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -6039,34 +6039,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -6135,20 +6135,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -6167,34 +6167,34 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] @@ -6303,20 +6303,20 @@ }, "polished_blackstone_button": { "face=floor,facing=north,powered=false": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 2, - 11 + 10 ], "face=floor,facing=north,powered=true": [ - 6, - 0, 5, - 10, + 0, + 6, + 11, 1, - 11 + 10 ], "face=floor,facing=south,powered=false": [ 5, @@ -6335,34 +6335,34 @@ 10 ], "face=floor,facing=west,powered=false": [ - 14, + 6, 0, 5, - 16, + 10, 2, 11 ], "face=floor,facing=west,powered=true": [ - 15, + 6, 0, 5, - 16, + 10, 1, 11 ], "face=floor,facing=east,powered=false": [ - 0, + 6, 0, 5, - 2, + 10, 2, 11 ], "face=floor,facing=east,powered=true": [ - 0, + 6, 0, 5, - 1, + 10, 1, 11 ], @@ -6431,20 +6431,20 @@ 11 ], "face=ceiling,facing=north,powered=false": [ - 6, - 14, 5, - 10, + 14, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=north,powered=true": [ - 6, - 15, 5, - 10, + 15, + 6, + 11, 16, - 11 + 10 ], "face=ceiling,facing=south,powered=false": [ 5, @@ -6463,34 +6463,34 @@ 10 ], "face=ceiling,facing=west,powered=false": [ - 14, + 6, 14, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=west,powered=true": [ - 15, + 6, 15, 5, - 16, + 10, 16, 11 ], "face=ceiling,facing=east,powered=false": [ - 0, + 6, 14, 5, - 2, + 10, 16, 11 ], "face=ceiling,facing=east,powered=true": [ - 0, + 6, 15, 5, - 1, + 10, 16, 11 ] From 3b9503982c2592b41f3f74d397eac2b26a2cc2c1 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 19 Feb 2025 04:03:20 +0300 Subject: [PATCH 31/32] fix: fix custom item display on 1.21.4, fix text component potential crash --- src/chatUtils.test.ts | 18 ------------------ src/mineflayer/items.ts | 7 +++++-- src/react/MessageFormattedString.tsx | 10 ---------- 3 files changed, 5 insertions(+), 30 deletions(-) diff --git a/src/chatUtils.test.ts b/src/chatUtils.test.ts index 3fc563fd..e717da28 100644 --- a/src/chatUtils.test.ts +++ b/src/chatUtils.test.ts @@ -11,24 +11,6 @@ const mapIncludeDefined = (props) => { } } -/* -TODO (nbt) -{ - "extra": [ - { - "italic": 0, - "underlined": 0, - "bold": 0, - "color": "aqua", - "obfuscated": 0, - "strikethrough": 0, - "text": "minecraft:lift" - } - ], - "text": "" -} -*/ - test('formatMessage', () => { const result = formatMessage({ 'json': { diff --git a/src/mineflayer/items.ts b/src/mineflayer/items.ts index f7f78c31..2f1b2f8d 100644 --- a/src/mineflayer/items.ts +++ b/src/mineflayer/items.ts @@ -38,7 +38,7 @@ export const getItemMetadata = (item: GeneralInputItem) => { const customTextComponent = componentMap.get('custom_name') || componentMap.get('item_name') if (customTextComponent) { - customText = customTextComponent.data.value + customText = nbt.simplify(customTextComponent.data) } const customModelComponent = componentMap.get('item_model') if (customModelComponent) { @@ -70,6 +70,9 @@ export const getItemNameRaw = (item: Pick const { customText } = getItemMetadata(item as any) if (!customText) return try { + if (typeof customText === 'object') { + return customText + } const parsed = customText.startsWith('{') && customText.endsWith('}') ? mojangson.simplify(mojangson.parse(customText)) : fromFormattedString(customText) if (parsed.extra) { return parsed as Record @@ -78,7 +81,7 @@ export const getItemNameRaw = (item: Pick } } catch (err) { return { - text: customText + text: JSON.stringify(customText) } } } diff --git a/src/react/MessageFormattedString.tsx b/src/react/MessageFormattedString.tsx index 09797076..f667cdd8 100644 --- a/src/react/MessageFormattedString.tsx +++ b/src/react/MessageFormattedString.tsx @@ -12,16 +12,6 @@ export default ({ message, fallbackColor, className }: { }) => { const messageJson = useMemo(() => { if (!message) return null - // const transformIfNbt = (x) => { - // if (typeof x === 'object' && x?.type) return nbt.simplify(x) as Record - // // if (Array.isArray(x)) return x.map(transformIfNbt) - // // if (typeof x === 'object') return Object.fromEntries(Object.entries(x).map(([k, v]) => [k, transformIfNbt(v)])) - // return x - // } - // if (typeof message === 'object' && message.text?.text?.type) { - // message.text.text = transformIfNbt(message.text.text) - // message.text.extra = transformIfNbt(message.text.extra) - // } try { const texts = formatMessage(typeof message === 'string' ? fromFormattedString(message) : message) return texts.map(text => { From f1c945d22a4315da8eed2451a5af684aa2c9515f Mon Sep 17 00:00:00 2001 From: Max Lee Date: Wed, 19 Feb 2025 15:00:43 +0100 Subject: [PATCH 32/32] fix: baby mobs are not rendered smaller (#283) --- renderer/viewer/lib/entities.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/renderer/viewer/lib/entities.ts b/renderer/viewer/lib/entities.ts index a09d57eb..c4664489 100644 --- a/renderer/viewer/lib/entities.ts +++ b/renderer/viewer/lib/entities.ts @@ -714,7 +714,13 @@ export class Entities extends EventEmitter { } } // --- - // not player + // set baby size + if (meta.baby) { + e.scale.set(0.5, 0.5, 0.5) + } else { + e.scale.set(1, 1, 1) + } + // entity specific meta const textDisplayMeta = getSpecificEntityMetadata('text_display', entity) const displayTextRaw = textDisplayMeta?.text || meta.custom_name_visible && meta.custom_name const displayText = this.parseEntityLabel(displayTextRaw)