From 86a4ac68f5169722e5aaf4d81a9ce46bb21782b4 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Wed, 17 Jan 2024 06:32:38 +0530 Subject: [PATCH] feat: support fetching skins by username for players! Use popular skinview3 for rendering players, so things like ears should render propertly feat: Add support for head rotation. feat: add `window.cursorEntity` for inspecting or watching entity props you're looking at fix: fix entity in playground --- prismarine-viewer/buildWorker.mjs | 4 +- prismarine-viewer/esbuild.mjs | 3 + prismarine-viewer/examples/playground.ts | 85 +++++++---- prismarine-viewer/playground.html | 1 + prismarine-viewer/viewer/lib/entities.js | 136 ++++++++++++++++-- prismarine-viewer/viewer/lib/entity/Entity.js | 53 +++++-- prismarine-viewer/viewer/lib/utils.js | 3 +- prismarine-viewer/viewer/lib/viewer.ts | 15 +- src/devtools.ts | 6 + src/entities.ts | 55 +++++++ src/globals.js | 3 +- src/index.ts | 8 +- src/worldInteractions.ts | 50 ++++--- 13 files changed, 334 insertions(+), 88 deletions(-) create mode 100644 src/entities.ts diff --git a/prismarine-viewer/buildWorker.mjs b/prismarine-viewer/buildWorker.mjs index 14c6d482..a8a5c138 100644 --- a/prismarine-viewer/buildWorker.mjs +++ b/prismarine-viewer/buildWorker.mjs @@ -23,7 +23,7 @@ const buildOptions = { entryPoints: [path.join(__dirname, './viewer/lib/worker.js')], minify: true, logLevel: 'info', - drop: watch ? [ + drop: !watch ? [ 'debugger' ] : [], sourcemap: 'linked', @@ -121,7 +121,7 @@ const buildOptions = { ], } -if (process.argv.includes('-w')) { +if (watch) { const ctx = await context(buildOptions) await ctx.watch() } else { diff --git a/prismarine-viewer/esbuild.mjs b/prismarine-viewer/esbuild.mjs index 33cafdd2..91b787db 100644 --- a/prismarine-viewer/esbuild.mjs +++ b/prismarine-viewer/esbuild.mjs @@ -50,6 +50,9 @@ const buildOptions = { }, inject: [], metafile: true, + loader: { + '.png': 'dataurl', + }, plugins: [ { name: 'minecraft-data', diff --git a/prismarine-viewer/examples/playground.ts b/prismarine-viewer/examples/playground.ts index d38d9939..ae26c9c5 100644 --- a/prismarine-viewer/examples/playground.ts +++ b/prismarine-viewer/examples/playground.ts @@ -10,6 +10,8 @@ import { GUI } from 'lil-gui' import { toMajor } from '../viewer/lib/version' import { loadScript } from '../viewer/lib/utils' import JSZip from 'jszip' +import { TWEEN_DURATION } from '../viewer/lib/entities' +import Entity from '../viewer/lib/entity/Entity' globalThis.THREE = THREE //@ts-ignore @@ -82,14 +84,15 @@ async function main () { gui.add(params, 'block', mcData.blocksArray.map(b => b.name).sort((a, b) => a.localeCompare(b))) const metadataGui = gui.add(params, 'metadata') gui.add(params, 'supportBlock') - gui.add(params, 'entity', mcData.entitiesArray.map(b => b.name)).listen() + gui.add(params, 'entity', mcData.entitiesArray.map(b => b.name).sort((a, b) => a.localeCompare(b))).listen() gui.add(params, 'removeEntity') gui.add(params, 'entityRotate') gui.add(params, 'skip') gui.add(params, 'playSound') gui.add(params, 'blockIsomorphicRenderBundle') gui.open(false) - let folder = gui.addFolder('metadata') + let metadataFolder = gui.addFolder('metadata') + let entityRotationFolder = gui.addFolder('entity rotation') const Chunk = ChunkLoader(version) const Block = BlockLoader(version) @@ -293,19 +296,44 @@ async function main () { controls.update() let blockProps = {} + let entityOverrides = {} const getBlock = () => { return mcData.blocksByName[params.block || 'air'] } + const entityUpdateShared = () => { + viewer.entities.clear() + if (!params.entity) return + worldView.emit('entity', { + id: 'id', name: params.entity, pos: targetPos.offset(0.5, 1, 0.5), width: 1, height: 1, username: 'username', yaw: Math.PI, pitch: 0 + }) + const enableSkeletonDebug = (obj) => { + const {children, isSkeletonHelper} = obj + if (!Array.isArray(children)) return + if (isSkeletonHelper) { + obj.visible = true + return + } + for (const child of children) { + if (typeof child === 'object') enableSkeletonDebug(child) + } + } + enableSkeletonDebug(viewer.entities.entities['id']) + setTimeout(() => { + viewer.update() + viewer.render() + }, TWEEN_DURATION) + } + const onUpdate = { block () { - folder.destroy() + metadataFolder.destroy() const block = mcData.blocksByName[params.block] if (!block) return const props = new Block(block.id, 0, 0).getProperties() //@ts-ignore const { states } = mcData.blocksByStateId[getBlock()?.minStateId] ?? {} - folder = gui.addFolder('metadata') + metadataFolder = gui.addFolder('metadata') if (states) { for (const state of states) { let defaultValue @@ -328,25 +356,31 @@ async function main () { } blockProps[state.name] = defaultValue if (state.type === 'enum') { - folder.add(blockProps, state.name, state.values) + metadataFolder.add(blockProps, state.name, state.values) } else { - folder.add(blockProps, state.name) + metadataFolder.add(blockProps, state.name) } } } else { for (const [name, value] of Object.entries(props)) { blockProps[name] = value - folder.add(blockProps, name) + metadataFolder.add(blockProps, name) } } - folder.open() + metadataFolder.open() }, entity () { - viewer.entities.clear() + entityUpdateShared() if (!params.entity) return - worldView.emit('entity', { - id: 'id', name: params.entity, pos: targetPos.offset(0, 1, 0), width: 1, height: 1, username: 'username' - }) + + Entity.getStaticData(params.entity) + entityRotationFolder.destroy() + entityRotationFolder = gui.addFolder('entity rotation') + entityRotationFolder.add(params, 'entityRotate') + entityRotationFolder.open() + }, + supportBlock () { + viewer.setBlockStateId(targetPos.offset(0, -1, 0), params.supportBlock ? 1 : 0) } } @@ -357,7 +391,7 @@ async function main () { if (metadataUpdate) { block = new Block(blockId, 0, params.metadata) Object.assign(blockProps, block.getProperties()) - for (const _child of folder.children) { + for (const _child of metadataFolder.children) { const child = _child as import('lil-gui').Controller child.updateDisplay() } @@ -373,18 +407,21 @@ async function main () { //@ts-ignore viewer.setBlockStateId(targetPos, block.stateId) - console.log('up', block.stateId) + console.log('up stateId', block.stateId) params.metadata = block.metadata metadataGui.updateDisplay() - // viewer.setBlockStateId(targetPos.offset(0, -1, 0), params.supportBlock ? 1 : 0) if (!skipQs) { setQs() } } - gui.onChange(({ property }) => { - if (property === 'camera') return - onUpdate[property]?.() - applyChanges(property === 'metadata') + gui.onChange(({ property, object }) => { + if (object === params) { + if (property === 'camera') return + onUpdate[property]?.() + applyChanges(property === 'metadata') + } else { + applyChanges() + } }) viewer.waitForChunksToRender().then(async () => { await new Promise(resolve => { @@ -395,12 +432,8 @@ async function main () { } applyChanges(true) gui.openAnimated() - // worldView.emit('entity', { - // id: 'id', name: 'player', pos: targetPos.offset(1, -2, 0), width: 1, height: 1, username: 'username' - // }) }) - // Browser animation loop const animate = () => { // if (controls) controls.update() // worldView.updatePosition(controls.target) @@ -455,11 +488,5 @@ async function main () { params.playSound() } }, { capture: true }) - - setTimeout(() => { - // worldView.emit('entity', { - // id: 'id', name: 'player', pos: center.offset(1, -2, 0), width: 1, height: 1, username: 'username' - // }) - }, 1500) } main() diff --git a/prismarine-viewer/playground.html b/prismarine-viewer/playground.html index 798f8532..fd92009a 100644 --- a/prismarine-viewer/playground.html +++ b/prismarine-viewer/playground.html @@ -6,6 +6,7 @@