From 9b8e7f8a41f066d8ddd01e884c74ea3546971987 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 22 Oct 2024 02:24:15 +0300 Subject: [PATCH 01/11] true hand display --- prismarine-viewer/viewer/lib/holdingBlock.ts | 34 ++++++++++++++++--- prismarine-viewer/viewer/lib/viewer.ts | 14 +++----- .../viewer/lib/worldrendererThree.ts | 7 ++-- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/prismarine-viewer/viewer/lib/holdingBlock.ts b/prismarine-viewer/viewer/lib/holdingBlock.ts index f5a0ca799..48ea10349 100644 --- a/prismarine-viewer/viewer/lib/holdingBlock.ts +++ b/prismarine-viewer/viewer/lib/holdingBlock.ts @@ -1,7 +1,9 @@ import * as THREE from 'three' import * as tweenJs from '@tweenjs/tween.js' import worldBlockProvider from 'mc-assets/dist/worldBlockProvider' +import GUI from 'lil-gui' import { getThreeBlockModelGroup, renderBlockThree, setBlockPosition } from './mesher/standaloneRenderer' +import { getMyHand } from './hand' export type HandItemBlock = { name @@ -167,12 +169,13 @@ export default class HoldingBlock { } const blockProvider = worldBlockProvider(blockstatesModels, blocksAtlases, 'latest') const models = blockProvider.getAllResolvedModels0_1(block, true) - const blockInner = getThreeBlockModelGroup(material, models, undefined, 'plains', loadedData) + // const blockInner = getThreeBlockModelGroup(material, models, undefined, 'plains', loadedData) // const { mesh: itemMesh } = viewer.entities.getItemMesh({ // itemId: 541, // })! // itemMesh.position.set(0.5, 0.5, 0.5) // const blockInner = itemMesh + const blockInner = await getMyHand() blockInner.name = 'holdingBlock' const blockOuterGroup = new THREE.Group() blockOuterGroup.add(blockInner) @@ -190,9 +193,32 @@ export default class HoldingBlock { this.objectOuterGroup.add(this.objectInnerGroup) this.cameraGroup.add(this.objectOuterGroup) - const rotation = -45 + -90 - // const rotation = -45 // should be for item - this.holdingBlock.rotation.set(0, THREE.MathUtils.degToRad(rotation), 0, 'ZYX') + // const rotation = -45 + -90 + const yRot = 45 // should be for item + const xRot = -90 + // this.holdingBlock.rotation.set(THREE.MathUtils.degToRad(xRot), THREE.MathUtils.degToRad(yRot), THREE.MathUtils.degToRad(xRot), 'ZYX') + const handRotation = { + x: 166.7, + // y: -180, + y: -165.2, + // z: -156.3, + z: -134.2, + yOuter: -81.1 + } + const rotationDeg = handRotation + const setRotation = () => { + this.holdingBlock!.rotation.x = THREE.MathUtils.degToRad(rotationDeg.x) + this.holdingBlock!.rotation.y = THREE.MathUtils.degToRad(rotationDeg.y) + this.holdingBlock!.rotation.z = THREE.MathUtils.degToRad(rotationDeg.z) + this.objectOuterGroup.rotation.y = THREE.MathUtils.degToRad(rotationDeg.yOuter) + } + // const gui = new GUI() + // gui.add(rotationDeg, 'x', -180, 180, 0.1) + // gui.add(rotationDeg, 'y', -180, 180, 0.1) + // gui.add(rotationDeg, 'z', -180, 180, 0.1) + // gui.add(rotationDeg, 'yOuter', -180, 180, 0.1) + // gui.onChange(setRotation) + setRotation() // const scale = window.scale ?? 0.2 const scale = 0.2 diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts index 44366d862..592563a83 100644 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ b/prismarine-viewer/viewer/lib/viewer.ts @@ -3,12 +3,14 @@ import * as THREE from 'three' import { Vec3 } from 'vec3' import { generateSpiralMatrix } from 'flying-squid/dist/utils' import worldBlockProvider from 'mc-assets/dist/worldBlockProvider' +import stevePng from 'mc-assets/dist/other-textures/latest/entity/player/wide/steve.png' import { Entities } from './entities' import { Primitives } from './primitives' import { WorldRendererThree } from './worldrendererThree' import { WorldRendererCommon, WorldRendererConfig, defaultWorldRendererConfig } from './worldrendererCommon' import { getThreeBlockModelGroup, renderBlockThree, setBlockPosition } from './mesher/standaloneRenderer' import { addNewStat } from './ui/newStats' +import { getMyHand } from './hand' export class Viewer { scene: THREE.Scene @@ -101,18 +103,12 @@ export class Viewer { this.world.setBlockStateId(pos, stateId) } - demoModel () { + async demoModel () { //@ts-expect-error const pos = cursorBlockRel(0, 1, 0).position const blockProvider = worldBlockProvider(this.world.blockstatesModels, this.world.blocksAtlases, 'latest') - const models = blockProvider.getAllResolvedModels0_1({ - name: 'item_frame', - properties: { - // map: false - } - }, true) - const { material } = this.world - const mesh = getThreeBlockModelGroup(material, models, undefined, 'plains', loadedData) + + const mesh = await getMyHand() // mesh.rotation.y = THREE.MathUtils.degToRad(90) setBlockPosition(mesh, pos) const helper = new THREE.BoxHelper(mesh, 0xff_ff_00) diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index e8769c888..0352233a4 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -37,7 +37,7 @@ export class WorldRendererThree extends WorldRendererCommon { this.holdingBlock = new HoldingBlock(this.scene) this.renderUpdateEmitter.on('textureDownloaded', () => { - if (this.holdingBlock.toBeRenderedItem) { + if (this.holdingBlock.toBeRenderedItem || true) { this.onHandItemSwitch(this.holdingBlock.toBeRenderedItem) this.holdingBlock.toBeRenderedItem = undefined } @@ -51,7 +51,10 @@ export class WorldRendererThree extends WorldRendererCommon { this.holdingBlock.toBeRenderedItem = item return } - void this.holdingBlock.initHandObject(this.material, this.blockstatesModels, this.blocksAtlases, item) + void this.holdingBlock.initHandObject(this.material, this.blockstatesModels, this.blocksAtlases, { + name: 'furnace', + properties: {}, + }) } changeHandSwingingState (isAnimationPlaying: boolean) { From c43fda777034de283c6abf28ebf7f55f8eebfc4c Mon Sep 17 00:00:00 2001 From: Vitaly Date: Wed, 23 Oct 2024 00:45:32 +0300 Subject: [PATCH 02/11] test From 2553d5eed329976a0a30efd4bd4ae304fd43c136 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Wed, 23 Oct 2024 01:00:58 +0300 Subject: [PATCH 03/11] test2 From 5a42a98c989e819c0b07955f6d1bdab721577dae Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 26 Nov 2024 15:13:54 +0300 Subject: [PATCH 04/11] add hand --- prismarine-viewer/viewer/lib/hand.ts | 96 ++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 prismarine-viewer/viewer/lib/hand.ts diff --git a/prismarine-viewer/viewer/lib/hand.ts b/prismarine-viewer/viewer/lib/hand.ts new file mode 100644 index 000000000..6c9aacc53 --- /dev/null +++ b/prismarine-viewer/viewer/lib/hand.ts @@ -0,0 +1,96 @@ +import * as THREE from 'three' +import { loadSkinToCanvas } from 'skinview-utils' +import stevePng from 'mc-assets/dist/other-textures/latest/entity/player/wide/steve.png' + +let steveTexture: THREE.Texture +export const getMyHand = async (image?: string) => { + let newMap: THREE.Texture + if (!image && steveTexture) { + newMap = steveTexture + } else { + image ??= stevePng + const skinCanvas = document.createElement('canvas') + const img = new Image() + img.src = image + await new Promise(resolve => { + img.onload = () => { + resolve() + } + }) + loadSkinToCanvas(skinCanvas, img) + newMap = new THREE.CanvasTexture(skinCanvas) + // newMap.flipY = false + newMap.magFilter = THREE.NearestFilter + newMap.minFilter = THREE.NearestFilter + if (!image) { + steveTexture = newMap + } + } + + // right arm + const box = new THREE.BoxGeometry() + const material = new THREE.MeshStandardMaterial() + const slim = false + const mesh = new THREE.Mesh(box, material) + mesh.scale.x = slim ? 3 : 4 + mesh.scale.y = 12 + mesh.scale.z = 4 + setSkinUVs(box, 40, 16, slim ? 3 : 4, 12, 4) + material.map = newMap + material.needsUpdate = true + const group = new THREE.Group() + group.add(mesh) + group.scale.set(0.1, 0.1, 0.1) + mesh.rotation.z = Math.PI + return group +} + +function setUVs ( + box: THREE.BoxGeometry, + u: number, + v: number, + width: number, + height: number, + depth: number, + textureWidth: number, + textureHeight: number +): void { + const toFaceVertices = (x1: number, y1: number, x2: number, y2: number) => [ + new THREE.Vector2(x1 / textureWidth, 1 - y2 / textureHeight), + new THREE.Vector2(x2 / textureWidth, 1 - y2 / textureHeight), + new THREE.Vector2(x2 / textureWidth, 1 - y1 / textureHeight), + new THREE.Vector2(x1 / textureWidth, 1 - y1 / textureHeight), + ] + + const top = toFaceVertices(u + depth, v, u + width + depth, v + depth) + const bottom = toFaceVertices(u + width + depth, v, u + width * 2 + depth, v + depth) + const left = toFaceVertices(u, v + depth, u + depth, v + depth + height) + const front = toFaceVertices(u + depth, v + depth, u + width + depth, v + depth + height) + const right = toFaceVertices(u + width + depth, v + depth, u + width + depth * 2, v + height + depth) + const back = toFaceVertices(u + width + depth * 2, v + depth, u + width * 2 + depth * 2, v + height + depth) + + const uvAttr = box.attributes.uv as THREE.BufferAttribute + const uvRight = [right[3], right[2], right[0], right[1]] + const uvLeft = [left[3], left[2], left[0], left[1]] + const uvTop = [top[3], top[2], top[0], top[1]] + const uvBottom = [bottom[0], bottom[1], bottom[3], bottom[2]] + const uvFront = [front[3], front[2], front[0], front[1]] + const uvBack = [back[3], back[2], back[0], back[1]] + + // Create a new array to hold the modified UV data + const newUVData = [] as number[] + + // Iterate over the arrays and copy the data to uvData + for (const uvArray of [uvRight, uvLeft, uvTop, uvBottom, uvFront, uvBack]) { + for (const uv of uvArray) { + newUVData.push(uv.x, uv.y) + } + } + + uvAttr.set(new Float32Array(newUVData)) + uvAttr.needsUpdate = true +} + +function setSkinUVs (box: THREE.BoxGeometry, u: number, v: number, width: number, height: number, depth: number): void { + setUVs(box, u, v, width, height, depth, 64, 64) +} From 88dff13c7eb7ae39beda3e3f9c3244d92b68219a Mon Sep 17 00:00:00 2001 From: Vitaly Date: Thu, 12 Dec 2024 14:16:57 +0300 Subject: [PATCH 05/11] finish everything --- prismarine-viewer/viewer/lib/holdingBlock.ts | 252 ++++++++++++++---- prismarine-viewer/viewer/lib/viewer.ts | 1 + .../viewer/lib/worldrendererThree.ts | 6 +- src/devtools.ts | 2 +- src/topRightStats.ts | 37 ++- 5 files changed, 239 insertions(+), 59 deletions(-) diff --git a/prismarine-viewer/viewer/lib/holdingBlock.ts b/prismarine-viewer/viewer/lib/holdingBlock.ts index 48ea10349..65da71ab1 100644 --- a/prismarine-viewer/viewer/lib/holdingBlock.ts +++ b/prismarine-viewer/viewer/lib/holdingBlock.ts @@ -8,9 +8,11 @@ import { getMyHand } from './hand' export type HandItemBlock = { name properties + type: 'block' | 'item' | 'hand' } export default class HoldingBlock { + // TODO refactor with the tree builder for better visual understanding holdingBlock: THREE.Object3D | undefined = undefined swingAnimation: tweenJs.Group | undefined = undefined blockSwapAnimation: { @@ -18,22 +20,22 @@ export default class HoldingBlock { hidden: boolean } | undefined = undefined cameraGroup = new THREE.Mesh() - objectOuterGroup = new THREE.Group() - objectInnerGroup = new THREE.Group() - camera: THREE.Group | THREE.PerspectiveCamera + objectOuterGroup = new THREE.Group() // 3 + objectInnerGroup = new THREE.Group() // 4 + holdingBlockInnerGroup = new THREE.Group() // 5 + camera = new THREE.PerspectiveCamera(75, 1, 0.1, 100) stopUpdate = false lastHeldItem: HandItemBlock | undefined toBeRenderedItem: HandItemBlock | undefined isSwinging = false nextIterStopCallbacks: Array<() => void> | undefined - constructor (public scene: THREE.Scene) { + constructor () { this.initCameraGroup() } initCameraGroup () { this.cameraGroup = new THREE.Mesh() - this.scene.add(this.cameraGroup) } startSwing () { @@ -46,17 +48,18 @@ export default class HoldingBlock { // const DURATION = 1000 * 0.35 / 2 const DURATION = 1000 * 0.35 / 3 // const DURATION = 1000 + const { position, rotation, object } = this.getFinalSwingPositionRotation() const initialPos = { - x: this.objectInnerGroup.position.x, - y: this.objectInnerGroup.position.y, - z: this.objectInnerGroup.position.z + x: object.position.x, + y: object.position.y, + z: object.position.z } const initialRot = { - x: this.objectInnerGroup.rotation.x, - y: this.objectInnerGroup.rotation.y, - z: this.objectInnerGroup.rotation.z + x: object.rotation.x, + y: object.rotation.y, + z: object.rotation.z } - const mainAnim = new tweenJs.Tween(this.objectInnerGroup.position, this.swingAnimation).to({ y: this.objectInnerGroup.position.y - this.objectInnerGroup.scale.y / 2 }, DURATION).yoyo(true).repeat(Infinity).start() + const mainAnim = new tweenJs.Tween(object.position, this.swingAnimation).to(position, DURATION).yoyo(true).repeat(Infinity).start() let i = 0 mainAnim.onRepeat(() => { i++ @@ -69,14 +72,66 @@ export default class HoldingBlock { this.swingAnimation!.removeAll() this.swingAnimation = undefined // todo refactor to be more generic for animations - this.objectInnerGroup.position.set(initialPos.x, initialPos.y, initialPos.z) - // this.objectInnerGroup.rotation.set(initialRot.x, initialRot.y, initialRot.z) - Object.assign(this.objectInnerGroup.rotation, initialRot) + object.position.set(initialPos.x, initialPos.y, initialPos.z) + // object.rotation.set(initialRot.x, initialRot.y, initialRot.z) + Object.assign(object.rotation, initialRot) } }) - new tweenJs.Tween(this.objectInnerGroup.rotation, this.swingAnimation).to({ z: THREE.MathUtils.degToRad(90) }, DURATION).yoyo(true).repeat(Infinity).start() - new tweenJs.Tween(this.objectInnerGroup.rotation, this.swingAnimation).to({ x: -THREE.MathUtils.degToRad(90) }, DURATION).yoyo(true).repeat(Infinity).start() + new tweenJs.Tween(object.rotation, this.swingAnimation).to(rotation, DURATION).yoyo(true).repeat(Infinity).start() + } + } + + getFinalSwingPositionRotation (origPosition?: THREE.Vector3) { + const object = this.objectInnerGroup + if (this.lastHeldItem?.type === 'block') { + origPosition ??= object.position + return { + position: { y: origPosition.y - this.objectInnerGroup.scale.y / 2 }, + rotation: { z: THREE.MathUtils.degToRad(90), x: -THREE.MathUtils.degToRad(90) }, + object + } + } + if (this.lastHeldItem?.type === 'item') { + const object = this.holdingBlockInnerGroup + origPosition ??= object.position + return { + position: { + y: origPosition.y - object.scale.y * 2, + // z: origPosition.z - window.zFinal, + // x: origPosition.x - window.xFinal, + }, + // rotation: { z: THREE.MathUtils.degToRad(90), x: -THREE.MathUtils.degToRad(90) } + rotation: { + // z: THREE.MathUtils.degToRad(window.zRotationFinal ?? 0), + // x: THREE.MathUtils.degToRad(window.xRotationFinal ?? 0), + // y: THREE.MathUtils.degToRad(window.yRotationFinal ?? 0), + x: THREE.MathUtils.degToRad(-120) + }, + object + } + } + if (this.lastHeldItem?.type === 'hand') { + const object = this.holdingBlockInnerGroup + origPosition ??= object.position + return { + position: { + y: origPosition.y - window.yFinal, + z: origPosition.z - window.zFinal, + x: origPosition.x - window.xFinal, + }, + rotation: { + x: THREE.MathUtils.degToRad(window.xRotationFinal || -10), + y: THREE.MathUtils.degToRad(window.yRotationFinal || 30), + z: THREE.MathUtils.degToRad(window.zRotationFinal || -36), + }, + object + } + } + return { + position: {}, + rotation: {}, + object } } @@ -91,11 +146,24 @@ export default class HoldingBlock { }) } - update (camera: typeof this.camera) { - this.camera = camera + render (originalCamera: THREE.PerspectiveCamera, renderer: THREE.WebGLRenderer, ambientLight: THREE.AmbientLight, directionalLight: THREE.DirectionalLight) { + if (!this.lastHeldItem) return this.swingAnimation?.update() this.blockSwapAnimation?.tween.update() + + const scene = new THREE.Scene() + scene.add(this.cameraGroup) + this.cameraGroup.renderOrder = 10_000 + if (this.camera.aspect !== originalCamera.aspect) { + this.camera.aspect = originalCamera.aspect + this.camera.updateProjectionMatrix() + } this.updateCameraGroup() + scene.add(ambientLight.clone()) + scene.add(directionalLight.clone()) + renderer.autoClear = false + renderer.clearDepth() + renderer.render(scene, this.camera) } // worldTest () { @@ -145,10 +213,21 @@ export default class HoldingBlock { this.cameraGroup.rotation.copy(camera.rotation) const viewerSize = viewer.renderer.getSize(new THREE.Vector2()) - // const x = window.x ?? 0.25 * viewerSize.width / viewerSize.height - // const x = 0 * viewerSize.width / viewerSize.height - const x = 0.2 * viewerSize.width / viewerSize.height - this.objectOuterGroup.position.set(x, -0.3, -0.45) + const aspect = viewerSize.width / viewerSize.height + + + // Adjust the position based on the aspect ratio + const { position, scale: scaleData } = getHandHeld3d(this.lastHeldItem?.type ?? 'hand') + const distance = -position.z + this.objectOuterGroup.position.set( + distance * position.x * aspect, + distance * position.y, + -distance + ) + + // const scale = Math.min(0.8, Math.max(1, 1 * aspect)) + const scale = scaleData * 2.22 * 0.2 + this.objectOuterGroup.scale.set(scale, scale, scale) } async initHandObject (material: THREE.Material, blockstatesModels: any, blocksAtlases: any, block?: HandItemBlock) { @@ -169,16 +248,23 @@ export default class HoldingBlock { } const blockProvider = worldBlockProvider(blockstatesModels, blocksAtlases, 'latest') const models = blockProvider.getAllResolvedModels0_1(block, true) + // const type: 'block' | 'item' | 'hand' = 'block' // const blockInner = getThreeBlockModelGroup(material, models, undefined, 'plains', loadedData) + // const type: 'block' | 'item' | 'hand' = 'item' // const { mesh: itemMesh } = viewer.entities.getItemMesh({ - // itemId: 541, + // itemId: 532, // })! // itemMesh.position.set(0.5, 0.5, 0.5) // const blockInner = itemMesh const blockInner = await getMyHand() + const type = 'hand' + this.lastHeldItem!.type = type blockInner.name = 'holdingBlock' const blockOuterGroup = new THREE.Group() - blockOuterGroup.add(blockInner) + this.holdingBlockInnerGroup.removeFromParent() + this.holdingBlockInnerGroup = new THREE.Group() + this.holdingBlockInnerGroup.add(blockInner) + blockOuterGroup.add(this.holdingBlockInnerGroup) this.holdingBlock = blockInner this.objectInnerGroup = new THREE.Group() this.objectInnerGroup.add(blockOuterGroup) @@ -193,41 +279,107 @@ export default class HoldingBlock { this.objectOuterGroup.add(this.objectInnerGroup) this.cameraGroup.add(this.objectOuterGroup) - // const rotation = -45 + -90 - const yRot = 45 // should be for item - const xRot = -90 - // this.holdingBlock.rotation.set(THREE.MathUtils.degToRad(xRot), THREE.MathUtils.degToRad(yRot), THREE.MathUtils.degToRad(xRot), 'ZYX') - const handRotation = { - x: 166.7, - // y: -180, - y: -165.2, - // z: -156.3, - z: -134.2, - yOuter: -81.1 - } - const rotationDeg = handRotation + const rotationDeg = getHandHeld3d(type).rotation + let origPosition const setRotation = () => { + // const final = this.getFinalSwingPositionRotation(origPosition) + // origPosition ??= final.object.position.clone() + // if (window.displayFinal) { + // Object.assign(final.object.position, final.position) + // Object.assign(final.object.rotation, final.rotation) + // } + this.holdingBlock!.rotation.x = THREE.MathUtils.degToRad(rotationDeg.x) this.holdingBlock!.rotation.y = THREE.MathUtils.degToRad(rotationDeg.y) this.holdingBlock!.rotation.z = THREE.MathUtils.degToRad(rotationDeg.z) this.objectOuterGroup.rotation.y = THREE.MathUtils.degToRad(rotationDeg.yOuter) } - // const gui = new GUI() - // gui.add(rotationDeg, 'x', -180, 180, 0.1) - // gui.add(rotationDeg, 'y', -180, 180, 0.1) - // gui.add(rotationDeg, 'z', -180, 180, 0.1) - // gui.add(rotationDeg, 'yOuter', -180, 180, 0.1) - // gui.onChange(setRotation) + const gui = new GUI() + gui.add(rotationDeg, 'x', -180, 180, 0.1) + gui.add(rotationDeg, 'y', -180, 180, 0.1) + gui.add(rotationDeg, 'z', -180, 180, 0.1) + gui.add(rotationDeg, 'yOuter', -180, 180, 0.1) + Object.assign(window, { xFinal: 0, yFinal: 0, zFinal: 0, xRotationFinal: 0, yRotationFinal: 0, zRotationFinal: 0, displayFinal: true }) + gui.add(window, 'xFinal', -10, 10, 0.05) + gui.add(window, 'yFinal', -10, 10, 0.05) + gui.add(window, 'zFinal', -10, 10, 0.05) + gui.add(window, 'xRotationFinal', -180, 180, 0.05) + gui.add(window, 'yRotationFinal', -180, 180, 0.05) + gui.add(window, 'zRotationFinal', -180, 180, 0.05) + gui.add(window, 'displayFinal') + gui.onChange(setRotation) setRotation() - // const scale = window.scale ?? 0.2 - const scale = 0.2 - this.objectOuterGroup.scale.set(scale, scale, scale) - // this.objectOuterGroup.position.set(x, window.y ?? -0.41, window.z ?? -0.45) - // this.objectOuterGroup.position.set(x, 0, -0.45) - if (animatingCurrent) { await this.playBlockSwapAnimation() } } } + +const getHandHeld3d = (type: 'block' | 'item' | 'hand') => { + let scale = type === 'item' ? 0.68 : 0.45 + + const position = { + x: window.x ?? 0.4, + y: window.y ?? -0.7, + z: -0.45 + } + + if (type === 'item') { + position.x = 0.1 + // position.y -= 3.2 / 10 + // position.z += 1.13 / 10 + } + + if (type === 'hand') { + // position.x = viewer.camera.aspect > 1 ? 0.7 : 1.1 + scale = 0.8 + } + + const rotations = { + block: { + x: 0, + y: -45 + 90, + z: 0, + yOuter: 0 + }, + // hand: { + // x: 166.7, + // // y: -180, + // y: -165.2, + // // z: -156.3, + // z: -134.2, + // yOuter: -81.1 + // }, + hand: { + x: -36.8, + // y: 25.1 + y: 40, + z: -36.8, + yOuter: 0 + }, + // item: { + // x: -174, + // y: 47.3, + // z: -134.2, + // yOuter: -41.2 + // } + item: { + // x: -174, + // y: 47.3, + // z: -134.2, + // yOuter: -41.2 + x: 0, + // y: -90, // todo thats the correct one but we don't make it look too cheap because of no depth + y: -70, + z: window.z ?? 25, + yOuter: 0 + } + } + + return { + rotation: rotations[type], + position, + scale + } +} diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts index 10a9e8209..20f10284e 100644 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ b/prismarine-viewer/viewer/lib/viewer.ts @@ -90,6 +90,7 @@ export class Viewer { return new THREE.TextureLoader().loadAsync(this.world.itemsAtlasParser!.latestImage) }).then((texture) => { this.entities.itemsTexture = texture + this.world.renderUpdateEmitter.emit('itemsTextureDownloaded') }) } diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 442a583aa..1e2248d1d 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -37,9 +37,9 @@ export class WorldRendererThree extends WorldRendererCommon { super(config) this.rendererDevice = String(WorldRendererThree.getRendererInfo(this.renderer)) this.starField = new StarField(scene) - this.holdingBlock = new HoldingBlock(this.scene) + this.holdingBlock = new HoldingBlock() - this.renderUpdateEmitter.on('textureDownloaded', () => { + this.renderUpdateEmitter.on('itemsTextureDownloaded', () => { if (this.holdingBlock.toBeRenderedItem || true) { this.onHandItemSwitch(this.holdingBlock.toBeRenderedItem) this.holdingBlock.toBeRenderedItem = undefined @@ -226,10 +226,10 @@ export class WorldRendererThree extends WorldRendererCommon { render () { tweenJs.update() - this.holdingBlock.update(this.camera) // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style const cam = this.camera instanceof THREE.Group ? this.camera.children.find(child => child instanceof THREE.PerspectiveCamera) as THREE.PerspectiveCamera : this.camera this.renderer.render(this.scene, cam) + this.holdingBlock.render(this.camera, this.renderer, viewer.ambientLight, viewer.directionalLight) } renderSign (position: Vec3, rotation: number, isWall: boolean, isHanging: boolean, blockEntity) { diff --git a/src/devtools.ts b/src/devtools.ts index 16337c1d7..e87b6d333 100644 --- a/src/devtools.ts +++ b/src/devtools.ts @@ -46,7 +46,7 @@ customEvents.on('gameLoaded', () => { window.inspectPacket = (packetName, full = false) => { const listener = (...args) => console.log('packet', packetName, full ? args : args[0]) const attach = () => { - bot?._client.on(packetName, listener) + bot?._client.prependListener(packetName, listener) } attach() customEvents.on('mineflayerBotCreated', attach) diff --git a/src/topRightStats.ts b/src/topRightStats.ts index 4bcd7264e..fd717ef48 100644 --- a/src/topRightStats.ts +++ b/src/topRightStats.ts @@ -88,13 +88,40 @@ export const statsEnd = () => { // for advanced debugging, use with watch expression +window.statsPerSecAvg = {} +let currentStatsPerSec = {} as Record +const waitingStatsPerSec = {} +window.markStart = (label) => { + waitingStatsPerSec[label] ??= [] + waitingStatsPerSec[label][0] = performance.now() +} +window.markEnd = (label) => { + if (!waitingStatsPerSec[label]?.[0]) return + currentStatsPerSec[label] ??= [] + currentStatsPerSec[label].push(performance.now() - waitingStatsPerSec[label][0]) + delete waitingStatsPerSec[label] +} +const updateStatsPerSecAvg = () => { + window.statsPerSecAvg = Object.fromEntries(Object.entries(currentStatsPerSec).map(([key, value]) => { + return [key, { + avg: value.reduce((a, b) => a + b, 0) / value.length, + count: value.length + }] + })) + currentStatsPerSec = {} +} + + window.statsPerSec = {} -let statsPerSec = {} +let statsPerSecCurrent = {} window.addStatPerSec = (name) => { - statsPerSec[name] ??= 0 - statsPerSec[name]++ + statsPerSecCurrent[name] ??= 0 + statsPerSecCurrent[name]++ } +window.statsPerSecCurrent = statsPerSecCurrent setInterval(() => { - window.statsPerSec = statsPerSec - statsPerSec = {} + window.statsPerSec = statsPerSecCurrent + statsPerSecCurrent = {} + window.statsPerSecCurrent = statsPerSecCurrent + updateStatsPerSecAvg() }, 1000) From ecafcbd2e8bc730e5b777b025e53831e1061621b Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 13 Dec 2024 12:08:15 +0300 Subject: [PATCH 06/11] [skip ci] todo --- prismarine-viewer/viewer/lib/holdingBlock.ts | 8 ++++---- src/optionsStorage.ts | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/prismarine-viewer/viewer/lib/holdingBlock.ts b/prismarine-viewer/viewer/lib/holdingBlock.ts index 65da71ab1..84776932b 100644 --- a/prismarine-viewer/viewer/lib/holdingBlock.ts +++ b/prismarine-viewer/viewer/lib/holdingBlock.ts @@ -154,10 +154,10 @@ export default class HoldingBlock { const scene = new THREE.Scene() scene.add(this.cameraGroup) this.cameraGroup.renderOrder = 10_000 - if (this.camera.aspect !== originalCamera.aspect) { - this.camera.aspect = originalCamera.aspect - this.camera.updateProjectionMatrix() - } + // if (this.camera.aspect !== originalCamera.aspect) { + // this.camera.aspect = originalCamera.aspect + // this.camera.updateProjectionMatrix() + // } this.updateCameraGroup() scene.add(ambientLight.clone()) scene.add(directionalLight.clone()) diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index 618d99e88..a242107c6 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -80,6 +80,7 @@ const defaultOptions = { autoParkour: false, vrSupport: true, // doesn't directly affect the VR mode, should only disable the button which is annoying to android users renderDebug: (isDev ? 'advanced' : 'basic') as 'none' | 'advanced' | 'basic', + autoVersionSelect: '1.20.4', // advanced bot options autoRespawn: false, From dec9ab5ba2e40d7f8e57b7bf76b90db25a58f012 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 13 Dec 2024 12:08:31 +0300 Subject: [PATCH 07/11] todo need sounds support --- src/defaultLocalServerOptions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defaultLocalServerOptions.js b/src/defaultLocalServerOptions.js index 130726e0f..3bc2ac7ef 100644 --- a/src/defaultLocalServerOptions.js +++ b/src/defaultLocalServerOptions.js @@ -33,6 +33,6 @@ module.exports = { keepAlive: false, 'everybody-op': true, 'max-entities': 100, - 'version': '1.14.4', + 'version': '1.20.4', versionMajor: '1.14' } From 6d71575c2d5daaa9bd69b38e94c52c1800e2ebbd Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 13 Dec 2024 20:22:59 +0300 Subject: [PATCH 08/11] finish hand --- prismarine-viewer/viewer/lib/holdingBlock.ts | 245 ++++++++++-------- .../viewer/lib/worldDataEmitter.ts | 3 +- .../viewer/lib/worldrendererThree.ts | 8 +- src/flyingSquidUtils.ts | 2 + 4 files changed, 144 insertions(+), 114 deletions(-) diff --git a/prismarine-viewer/viewer/lib/holdingBlock.ts b/prismarine-viewer/viewer/lib/holdingBlock.ts index 84776932b..5fc3e03c0 100644 --- a/prismarine-viewer/viewer/lib/holdingBlock.ts +++ b/prismarine-viewer/viewer/lib/holdingBlock.ts @@ -1,14 +1,15 @@ import * as THREE from 'three' import * as tweenJs from '@tweenjs/tween.js' import worldBlockProvider from 'mc-assets/dist/worldBlockProvider' -import GUI from 'lil-gui' +import { GUI } from 'lil-gui' import { getThreeBlockModelGroup, renderBlockThree, setBlockPosition } from './mesher/standaloneRenderer' import { getMyHand } from './hand' export type HandItemBlock = { - name - properties + name? + properties? type: 'block' | 'item' | 'hand' + id?: number } export default class HoldingBlock { @@ -29,6 +30,9 @@ export default class HoldingBlock { toBeRenderedItem: HandItemBlock | undefined isSwinging = false nextIterStopCallbacks: Array<() => void> | undefined + rightSide = true + + debug = {} as Record constructor () { this.initCameraGroup() @@ -116,14 +120,14 @@ export default class HoldingBlock { origPosition ??= object.position return { position: { - y: origPosition.y - window.yFinal, + y: origPosition.y - (window.yFinal ?? 0.15), z: origPosition.z - window.zFinal, x: origPosition.x - window.xFinal, }, rotation: { - x: THREE.MathUtils.degToRad(window.xRotationFinal || -10), - y: THREE.MathUtils.degToRad(window.yRotationFinal || 30), - z: THREE.MathUtils.degToRad(window.zRotationFinal || -36), + x: THREE.MathUtils.degToRad(window.xRotationFinal || -14.7), + y: THREE.MathUtils.degToRad(window.yRotationFinal || 33.95), + z: THREE.MathUtils.degToRad(window.zRotationFinal || -28), }, object } @@ -153,7 +157,6 @@ export default class HoldingBlock { const scene = new THREE.Scene() scene.add(this.cameraGroup) - this.cameraGroup.renderOrder = 10_000 // if (this.camera.aspect !== originalCamera.aspect) { // this.camera.aspect = originalCamera.aspect // this.camera.updateProjectionMatrix() @@ -161,9 +164,21 @@ export default class HoldingBlock { this.updateCameraGroup() scene.add(ambientLight.clone()) scene.add(directionalLight.clone()) + + const viewerSize = renderer.getSize(new THREE.Vector2()) + const minSize = Math.min(viewerSize.width, viewerSize.height) + renderer.autoClear = false renderer.clearDepth() + if (this.rightSide) { + const x = viewerSize.width - minSize + // if (x) x -= x / 4 + renderer.setViewport(x, 0, minSize, minSize) + } else { + renderer.setViewport(0, 0, minSize, minSize) + } renderer.render(scene, this.camera) + renderer.setViewport(0, 0, viewerSize.width, viewerSize.height) } // worldTest () { @@ -212,15 +227,17 @@ export default class HoldingBlock { this.cameraGroup.position.copy(camera.position) this.cameraGroup.rotation.copy(camera.rotation) - const viewerSize = viewer.renderer.getSize(new THREE.Vector2()) - const aspect = viewerSize.width / viewerSize.height + // const viewerSize = viewer.renderer.getSize(new THREE.Vector2()) + // const aspect = viewerSize.width / viewerSize.height + const aspect = 1 // Adjust the position based on the aspect ratio - const { position, scale: scaleData } = getHandHeld3d(this.lastHeldItem?.type ?? 'hand') + const { position, scale: scaleData } = this.getHandHeld3d() const distance = -position.z + const side = this.rightSide ? 1 : -1 this.objectOuterGroup.position.set( - distance * position.x * aspect, + distance * position.x * aspect * side, distance * position.y, -distance ) @@ -230,16 +247,16 @@ export default class HoldingBlock { this.objectOuterGroup.scale.set(scale, scale, scale) } - async initHandObject (material: THREE.Material, blockstatesModels: any, blocksAtlases: any, block?: HandItemBlock) { + async initHandObject (material: THREE.Material, blockstatesModels: any, blocksAtlases: any, handItem?: HandItemBlock) { let animatingCurrent = false - if (!this.swingAnimation && !this.blockSwapAnimation && this.isDifferentItem(block)) { + if (!this.swingAnimation && !this.blockSwapAnimation && this.isDifferentItem(handItem)) { animatingCurrent = true await this.playBlockSwapAnimation() this.holdingBlock?.removeFromParent() this.holdingBlock = undefined } - this.lastHeldItem = block - if (!block) { + this.lastHeldItem = handItem + if (!handItem) { this.holdingBlock?.removeFromParent() this.holdingBlock = undefined this.swingAnimation = undefined @@ -247,18 +264,22 @@ export default class HoldingBlock { return } const blockProvider = worldBlockProvider(blockstatesModels, blocksAtlases, 'latest') - const models = blockProvider.getAllResolvedModels0_1(block, true) - // const type: 'block' | 'item' | 'hand' = 'block' - // const blockInner = getThreeBlockModelGroup(material, models, undefined, 'plains', loadedData) - // const type: 'block' | 'item' | 'hand' = 'item' - // const { mesh: itemMesh } = viewer.entities.getItemMesh({ - // itemId: 532, - // })! - // itemMesh.position.set(0.5, 0.5, 0.5) - // const blockInner = itemMesh - const blockInner = await getMyHand() - const type = 'hand' - this.lastHeldItem!.type = type + let blockInner + if (handItem.type === 'block') { + const models = blockProvider.getAllResolvedModels0_1({ + name: handItem.name, + properties: handItem.properties ?? {} + }, true) + blockInner = getThreeBlockModelGroup(material, models, undefined, 'plains', loadedData) + } else if (handItem.type === 'item') { + const { mesh: itemMesh } = viewer.entities.getItemMesh({ + itemId: handItem.id, + })! + itemMesh.position.set(0.5, 0.5, 0.5) + blockInner = itemMesh + } else { + blockInner = await getMyHand() + } blockInner.name = 'holdingBlock' const blockOuterGroup = new THREE.Group() this.holdingBlockInnerGroup.removeFromParent() @@ -279,107 +300,113 @@ export default class HoldingBlock { this.objectOuterGroup.add(this.objectInnerGroup) this.cameraGroup.add(this.objectOuterGroup) - const rotationDeg = getHandHeld3d(type).rotation + const rotationDeg = this.getHandHeld3d().rotation let origPosition const setRotation = () => { - // const final = this.getFinalSwingPositionRotation(origPosition) - // origPosition ??= final.object.position.clone() - // if (window.displayFinal) { - // Object.assign(final.object.position, final.position) - // Object.assign(final.object.rotation, final.rotation) - // } + const final = this.getFinalSwingPositionRotation(origPosition) + origPosition ??= final.object.position.clone() + if (this.debug.displayFinal) { + Object.assign(final.object.position, final.position) + Object.assign(final.object.rotation, final.rotation) + } else if (this.debug.displayFinal === false) { + final.object.rotation.set(0, 0, 0) + } this.holdingBlock!.rotation.x = THREE.MathUtils.degToRad(rotationDeg.x) this.holdingBlock!.rotation.y = THREE.MathUtils.degToRad(rotationDeg.y) this.holdingBlock!.rotation.z = THREE.MathUtils.degToRad(rotationDeg.z) this.objectOuterGroup.rotation.y = THREE.MathUtils.degToRad(rotationDeg.yOuter) } - const gui = new GUI() - gui.add(rotationDeg, 'x', -180, 180, 0.1) - gui.add(rotationDeg, 'y', -180, 180, 0.1) - gui.add(rotationDeg, 'z', -180, 180, 0.1) - gui.add(rotationDeg, 'yOuter', -180, 180, 0.1) - Object.assign(window, { xFinal: 0, yFinal: 0, zFinal: 0, xRotationFinal: 0, yRotationFinal: 0, zRotationFinal: 0, displayFinal: true }) - gui.add(window, 'xFinal', -10, 10, 0.05) - gui.add(window, 'yFinal', -10, 10, 0.05) - gui.add(window, 'zFinal', -10, 10, 0.05) - gui.add(window, 'xRotationFinal', -180, 180, 0.05) - gui.add(window, 'yRotationFinal', -180, 180, 0.05) - gui.add(window, 'zRotationFinal', -180, 180, 0.05) - gui.add(window, 'displayFinal') - gui.onChange(setRotation) + // const gui = new GUI() + // gui.add(rotationDeg, 'x', -180, 180, 0.1) + // gui.add(rotationDeg, 'y', -180, 180, 0.1) + // gui.add(rotationDeg, 'z', -180, 180, 0.1) + // gui.add(rotationDeg, 'yOuter', -180, 180, 0.1) + // Object.assign(window, { xFinal: 0, yFinal: 0, zFinal: 0, xRotationFinal: 0, yRotationFinal: 0, zRotationFinal: 0, displayFinal: true }) + // gui.add(window, 'xFinal', -10, 10, 0.05) + // gui.add(window, 'yFinal', -10, 10, 0.05) + // gui.add(window, 'zFinal', -10, 10, 0.05) + // gui.add(window, 'xRotationFinal', -180, 180, 0.05) + // gui.add(window, 'yRotationFinal', -180, 180, 0.05) + // gui.add(window, 'zRotationFinal', -180, 180, 0.05) + // gui.add(window, 'displayFinal') + // gui.onChange(setRotation) setRotation() if (animatingCurrent) { await this.playBlockSwapAnimation() } } -} -const getHandHeld3d = (type: 'block' | 'item' | 'hand') => { - let scale = type === 'item' ? 0.68 : 0.45 + getHandHeld3d () { + const type = this.lastHeldItem?.type ?? 'hand' + const { debug } = this - const position = { - x: window.x ?? 0.4, - y: window.y ?? -0.7, - z: -0.45 - } + let scale = type === 'item' ? 0.68 : 0.45 - if (type === 'item') { - position.x = 0.1 - // position.y -= 3.2 / 10 - // position.z += 1.13 / 10 - } + const position = { + x: debug.x ?? 0.4, + y: debug.y ?? -0.7, + z: -0.45 + } - if (type === 'hand') { - // position.x = viewer.camera.aspect > 1 ? 0.7 : 1.1 - scale = 0.8 - } + if (type === 'item') { + position.x = -0.05 + // position.y -= 3.2 / 10 + // position.z += 1.13 / 10 + } - const rotations = { - block: { - x: 0, - y: -45 + 90, - z: 0, - yOuter: 0 - }, - // hand: { - // x: 166.7, - // // y: -180, - // y: -165.2, - // // z: -156.3, - // z: -134.2, - // yOuter: -81.1 - // }, - hand: { - x: -36.8, - // y: 25.1 - y: 40, - z: -36.8, - yOuter: 0 - }, - // item: { - // x: -174, - // y: 47.3, - // z: -134.2, - // yOuter: -41.2 - // } - item: { - // x: -174, - // y: 47.3, - // z: -134.2, - // yOuter: -41.2 - x: 0, - // y: -90, // todo thats the correct one but we don't make it look too cheap because of no depth - y: -70, - z: window.z ?? 25, - yOuter: 0 + if (type === 'hand') { + // position.x = viewer.camera.aspect > 1 ? 0.7 : 1.1 + position.y = -0.8 + scale = 0.8 + } + + const rotations = { + block: { + x: 0, + y: -45 + 90, + z: 0, + yOuter: 0 + }, + // hand: { + // x: 166.7, + // // y: -180, + // y: -165.2, + // // z: -156.3, + // z: -134.2, + // yOuter: -81.1 + // }, + hand: { + x: -32.4, + // y: 25.1 + y: 42.8, + z: -41.3, + yOuter: 0 + }, + // item: { + // x: -174, + // y: 47.3, + // z: -134.2, + // yOuter: -41.2 + // } + item: { + // x: -174, + // y: 47.3, + // z: -134.2, + // yOuter: -41.2 + x: 0, + // y: -90, // todo thats the correct one but we don't make it look too cheap because of no depth + y: -70, + z: window.z ?? 25, + yOuter: 0 + } } - } - return { - rotation: rotations[type], - position, - scale + return { + rotation: rotations[type], + position, + scale + } } } diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index 0223b855b..20543538a 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -120,7 +120,8 @@ export class WorldDataEmitter extends EventEmitter { const block = loadedData.blocksByName[newItem.name] // todo clean types const blockProperties = block ? new window.PrismarineBlock(block.id, 'void', newItem.metadata).getProperties() : {} - viewer.world.onHandItemSwitch({ name: newItem.name, properties: blockProperties }) + // todo item props + viewer.world.onHandItemSwitch({ name: newItem.name, properties: blockProperties, id: newItem.type, type: block ? 'block' : 'item', }) }, } satisfies Partial this.eventListeners.heldItemChanged() diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 1e2248d1d..0f3190d34 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -50,14 +50,14 @@ export class WorldRendererThree extends WorldRendererCommon { } onHandItemSwitch (item: HandItemBlock | undefined) { + item ??= { + type: 'hand', + } if (!this.currentTextureImage) { this.holdingBlock.toBeRenderedItem = item return } - void this.holdingBlock.initHandObject(this.material, this.blockstatesModels, this.blocksAtlases, { - name: 'furnace', - properties: {}, - }) + void this.holdingBlock.initHandObject(this.material, this.blockstatesModels, this.blocksAtlases, item) } changeHandSwingingState (isAnimationPlaying: boolean) { diff --git a/src/flyingSquidUtils.ts b/src/flyingSquidUtils.ts index 78254cf23..012830d9f 100644 --- a/src/flyingSquidUtils.ts +++ b/src/flyingSquidUtils.ts @@ -27,8 +27,10 @@ export async function savePlayers (autoSave: boolean) { export const saveServer = async (autoSave = true) => { if (!localServer || fsState.isReadonly) return // todo + console.time('save server') const worlds = [(localServer as any).overworld] as Array await Promise.all([localServer.writeLevelDat(), savePlayers(autoSave), ...worlds.map(async world => world.saveNow())]) + console.timeEnd('save server') } export const disconnect = async () => { if (localServer) { From 7841ba9d921c5f773c41588b0af1fd80d15a7212 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 13 Dec 2024 20:39:41 +0300 Subject: [PATCH 09/11] implement offhand --- .../viewer/lib/worldDataEmitter.ts | 41 +++++++++++-------- .../viewer/lib/worldrendererCommon.ts | 4 +- .../viewer/lib/worldrendererThree.ts | 30 ++++++++++---- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index 20543538a..371ef8f58 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -107,24 +107,33 @@ export class WorldDataEmitter extends EventEmitter { time: () => { this.emitter.emit('time', bot.time.timeOfDay) }, - heldItemChanged: () => { - if (!this.handDisplay) { - viewer.world.onHandItemSwitch(undefined) - return - } - const newItem = bot.heldItem - if (!newItem) { - viewer.world.onHandItemSwitch(undefined) - return - } - const block = loadedData.blocksByName[newItem.name] - // todo clean types - const blockProperties = block ? new window.PrismarineBlock(block.id, 'void', newItem.metadata).getProperties() : {} - // todo item props - viewer.world.onHandItemSwitch({ name: newItem.name, properties: blockProperties, id: newItem.type, type: block ? 'block' : 'item', }) + heldItemChanged () { + handChanged(false) }, } satisfies Partial - this.eventListeners.heldItemChanged() + const handChanged = (isLeftHand: boolean) => { + if (!this.handDisplay) { + viewer.world.onHandItemSwitch(undefined, isLeftHand) + return + } + const newItem = isLeftHand ? bot.inventory.slots[45] : bot.heldItem + if (!newItem) { + viewer.world.onHandItemSwitch(undefined, isLeftHand) + return + } + const block = loadedData.blocksByName[newItem.name] + // todo clean types + const blockProperties = block ? new window.PrismarineBlock(block.id, 'void', newItem.metadata).getProperties() : {} + // todo item props + viewer.world.onHandItemSwitch({ name: newItem.name, properties: blockProperties, id: newItem.type, type: block ? 'block' : 'item', }, isLeftHand) + } + bot.inventory.on('updateSlot', (index) => { + if (index === 45) { + handChanged(true) + } + }) + handChanged(false) + handChanged(true) bot._client.on('update_light', ({ chunkX, chunkZ }) => { diff --git a/prismarine-viewer/viewer/lib/worldrendererCommon.ts b/prismarine-viewer/viewer/lib/worldrendererCommon.ts index 71c094b4f..a7c3972c1 100644 --- a/prismarine-viewer/viewer/lib/worldrendererCommon.ts +++ b/prismarine-viewer/viewer/lib/worldrendererCommon.ts @@ -217,8 +217,8 @@ export abstract class WorldRendererCommon } } - onHandItemSwitch (item: HandItemBlock | undefined): void { } - changeHandSwingingState (isAnimationPlaying: boolean): void { } + onHandItemSwitch (item: HandItemBlock | undefined, isLeftHand: boolean): void { } + changeHandSwingingState (isAnimationPlaying: boolean, isLeftHand: boolean): void { } abstract handleWorkerMessage (data: WorkerReceive): void diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 0f3190d34..de1116908 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -23,6 +23,7 @@ export class WorldRendererThree extends WorldRendererCommon { starField: StarField cameraSectionPos: Vec3 = new Vec3(0, 0, 0) holdingBlock: HoldingBlock + holdingBlockLeft: HoldingBlock rendererDevice = '...' get tilesRendered () { @@ -38,33 +39,43 @@ export class WorldRendererThree extends WorldRendererCommon { this.rendererDevice = String(WorldRendererThree.getRendererInfo(this.renderer)) this.starField = new StarField(scene) this.holdingBlock = new HoldingBlock() + this.holdingBlockLeft = new HoldingBlock() + this.holdingBlockLeft.rightSide = false this.renderUpdateEmitter.on('itemsTextureDownloaded', () => { - if (this.holdingBlock.toBeRenderedItem || true) { + if (this.holdingBlock.toBeRenderedItem) { this.onHandItemSwitch(this.holdingBlock.toBeRenderedItem) this.holdingBlock.toBeRenderedItem = undefined } + if (this.holdingBlockLeft.toBeRenderedItem) { + this.onHandItemSwitch(this.holdingBlock.toBeRenderedItem, true) + this.holdingBlockLeft.toBeRenderedItem = undefined + } }) this.addDebugOverlay() } - onHandItemSwitch (item: HandItemBlock | undefined) { - item ??= { - type: 'hand', + onHandItemSwitch (item: HandItemBlock | undefined, isLeft = false) { + if (!isLeft) { + item ??= { + type: 'hand', + } } + const holdingBlock = isLeft ? this.holdingBlockLeft : this.holdingBlock if (!this.currentTextureImage) { - this.holdingBlock.toBeRenderedItem = item + holdingBlock.toBeRenderedItem = item return } - void this.holdingBlock.initHandObject(this.material, this.blockstatesModels, this.blocksAtlases, item) + void holdingBlock.initHandObject(this.material, this.blockstatesModels, this.blocksAtlases, item) } - changeHandSwingingState (isAnimationPlaying: boolean) { + changeHandSwingingState (isAnimationPlaying: boolean, isLeft = false) { + const holdingBlock = isLeft ? this.holdingBlockLeft : this.holdingBlock if (isAnimationPlaying) { - this.holdingBlock.startSwing() + holdingBlock.startSwing() } else { - void this.holdingBlock.stopSwing() + void holdingBlock.stopSwing() } } @@ -230,6 +241,7 @@ export class WorldRendererThree extends WorldRendererCommon { const cam = this.camera instanceof THREE.Group ? this.camera.children.find(child => child instanceof THREE.PerspectiveCamera) as THREE.PerspectiveCamera : this.camera this.renderer.render(this.scene, cam) this.holdingBlock.render(this.camera, this.renderer, viewer.ambientLight, viewer.directionalLight) + this.holdingBlockLeft.render(this.camera, this.renderer, viewer.ambientLight, viewer.directionalLight) } renderSign (position: Vec3, rotation: number, isWall: boolean, isHanging: boolean, blockEntity) { From 3a10f24f84b2d8b22e0ac90a95817c9f8220972e Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 13 Dec 2024 20:58:17 +0300 Subject: [PATCH 10/11] fix ts --- src/worldInteractions.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index d6674ce31..1134d7f89 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -257,8 +257,8 @@ class WorldInteraction { bot.lookAt = oldLookAt }).catch(console.warn) } - viewer.world.changeHandSwingingState(true) - viewer.world.changeHandSwingingState(false) + viewer.world.changeHandSwingingState(true, false) + viewer.world.changeHandSwingingState(false, false) } else if (!stop) { const offhand = activate ? false : activatableItems(bot.inventory.slots[45]?.name ?? '') bot.activateItem(offhand) // todo offhand @@ -317,14 +317,14 @@ class WorldInteraction { }) customEvents.emit('digStart') this.lastDigged = Date.now() - viewer.world.changeHandSwingingState(true) + viewer.world.changeHandSwingingState(true, false) } else if (performance.now() - this.lastSwing > 200) { bot.swingArm('right') this.lastSwing = performance.now() } } if (!this.buttons[0] && this.lastButtons[0]) { - viewer.world.changeHandSwingingState(false) + viewer.world.changeHandSwingingState(false, false) } this.prevOnGround = onGround From 374b40bf25ed52067d92c3415132a1b0d9de26da Mon Sep 17 00:00:00 2001 From: Vitaly Date: Fri, 13 Dec 2024 21:04:11 +0300 Subject: [PATCH 11/11] Update defaultLocalServerOptions.js --- src/defaultLocalServerOptions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defaultLocalServerOptions.js b/src/defaultLocalServerOptions.js index 3bc2ac7ef..130726e0f 100644 --- a/src/defaultLocalServerOptions.js +++ b/src/defaultLocalServerOptions.js @@ -33,6 +33,6 @@ module.exports = { keepAlive: false, 'everybody-op': true, 'max-entities': 100, - 'version': '1.20.4', + 'version': '1.14.4', versionMajor: '1.14' }