From 72872dcd2997817b5c5bcd738e040fbeee26abb4 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 18 Sep 2023 18:34:37 +0300 Subject: [PATCH 1/9] add missing texture texture instead of rendering nothing --- viewer/lib/atlas.js | 11 ++++++++++- viewer/lib/missing_texture.png | Bin 0 -> 339 bytes viewer/lib/models.js | 8 +++++--- viewer/lib/modelsBuilder.js | 14 ++++++++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 viewer/lib/missing_texture.png diff --git a/viewer/lib/atlas.js b/viewer/lib/atlas.js index 7f45f03c..d36ccca3 100644 --- a/viewer/lib/atlas.js +++ b/viewer/lib/atlas.js @@ -13,9 +13,18 @@ function nextPowerOfTwo (n) { return n + 1 } +function readTexture (basePath, name) { + if (name === 'missing_texture.png') { + // grab ./missing_texture.png + basePath = __dirname + } + return fs.readFileSync(path.join(basePath, name), 'base64') +} + function makeTextureAtlas (mcAssets) { const blocksTexturePath = path.join(mcAssets.directory, '/blocks') const textureFiles = fs.readdirSync(blocksTexturePath).filter(file => file.endsWith('.png')) + textureFiles.unshift('missing_texture.png') const texSize = nextPowerOfTwo(Math.ceil(Math.sqrt(textureFiles.length))) const tileSize = 16 @@ -35,7 +44,7 @@ function makeTextureAtlas (mcAssets) { texturesIndex[name] = { u: x / imgSize, v: y / imgSize, su: tileSize / imgSize, sv: tileSize / imgSize } const img = new Image() - img.src = 'data:image/png;base64,' + fs.readFileSync(path.join(blocksTexturePath, textureFiles[i]), 'base64') + img.src = 'data:image/png;base64,' + readTexture(blocksTexturePath, textureFiles[i]) g.drawImage(img, 0, 0, 16, 16, x, y, 16, 16) } diff --git a/viewer/lib/missing_texture.png b/viewer/lib/missing_texture.png new file mode 100644 index 0000000000000000000000000000000000000000..affd9d681b58040ad59418a3f30de7bdb9922ed3 GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!55w`jv*HQb0;VAH7oG6a#v|I#>XA2VEwwi zYGda|KkmNk56tGi_~I?Ku)%D5d`HSCne_|i6zoox0 zQ)sK zA#9Yr$d(~PZPxPMXETpmlr(rA_*d4#z4?2A2E#PXHy@|G+<8Fo4a3$$kFF*#{+DtM j6#3IP{fX$EKTE{xUndAny_zWq^fQB}tDnm{r-UW|2}qEH literal 0 HcmV?d00001 diff --git a/viewer/lib/models.js b/viewer/lib/models.js index 5ae9535b..43cacee3 100644 --- a/viewer/lib/models.js +++ b/viewer/lib/models.js @@ -264,8 +264,8 @@ function renderElement (world, cursor, element, doAO, attr, globalMatrix, global if (block.name === 'redstone_wire') { tint = tints.redstone[`${block.getProperties().power}`] } else if (block.name === 'birch_leaves' || - block.name === 'spruce_leaves' || - block.name === 'lily_pad') { + block.name === 'spruce_leaves' || + block.name === 'lily_pad') { tint = tints.constant[block.name] } else if (block.name.includes('leaves') || block.name === 'vine') { tint = tints.foliage[biome] @@ -478,7 +478,9 @@ function matchProperties (block, properties) { } function getModelVariants (block, blockStates) { - const state = blockStates[block.name] + // air, cave_air, void_air and so on... + if (block.name.includes('air')) return [] + const state = blockStates[block.name] ?? blockStates['missing_texture'] if (!state) return [] if (state.variants) { for (const [properties, variant] of Object.entries(state.variants)) { diff --git a/viewer/lib/modelsBuilder.js b/viewer/lib/modelsBuilder.js index ecd1bc35..58aca167 100644 --- a/viewer/lib/modelsBuilder.js +++ b/viewer/lib/modelsBuilder.js @@ -34,6 +34,7 @@ function getModel (name, blocksModels) { } function prepareModel (model, texturesJson) { + // resolve texture names eg west: #all -> blocks/stone for (const tex in model.textures) { let root = model.textures[tex] while (root.charAt(0) === '#') { @@ -94,6 +95,19 @@ function resolveModel (name, blocksModels, texturesJson) { function prepareBlocksStates (mcAssets, atlas) { const blocksStates = mcAssets.blocksStates + mcAssets.blocksStates["missing_texture"] = { + "variants": { + "normal": { + "model": "missing_texture" + } + } + }, + mcAssets.blocksModels["missing_texture"] = { + "parent": "block/cube_all", + "textures": { + "all": "blocks/missing_texture" + } + } for (const block of Object.values(blocksStates)) { if (!block) continue if (block.variants) { From dbba29fd75a2aaaac333ec39254d8db8ed0ad476 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 18 Sep 2023 18:34:52 +0300 Subject: [PATCH 2/9] utils: load browser version if in browser --- viewer/lib/utils.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/viewer/lib/utils.js b/viewer/lib/utils.js index e91ff69f..382c0573 100644 --- a/viewer/lib/utils.js +++ b/viewer/lib/utils.js @@ -10,7 +10,12 @@ const THREE = require('three') const path = require('path') const textureCache = {} +// todo not ideal, export different functions for browser and node function loadTexture (texture, cb) { + if (process.platform === 'browser') { + return require('./utils.web').loadTexture(texture, cb) + } + if (textureCache[texture]) { cb(textureCache[texture]) } else { @@ -22,6 +27,9 @@ function loadTexture (texture, cb) { } function loadJSON (json, cb) { + if (process.platform === 'browser') { + return require('./utils.web').loadJSON(json, cb) + } cb(require(path.resolve(__dirname, '../../public/' + json))) } From bba99431c4ea14792966292530e9df9a8b045276 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 18 Sep 2023 18:36:40 +0300 Subject: [PATCH 3/9] support for sneaking --- viewer/lib/viewer.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/viewer/lib/viewer.js b/viewer/lib/viewer.js index adcb5b62..6b9236f2 100644 --- a/viewer/lib/viewer.js +++ b/viewer/lib/viewer.js @@ -28,6 +28,8 @@ class Viewer { this.primitives = new Primitives(this.scene, this.camera) this.domElement = renderer.domElement + this.playerHeight = 1.6 + this.isSneaking = false } setVersion (version) { @@ -60,7 +62,11 @@ class Viewer { } setFirstPersonCamera (pos, yaw, pitch) { - if (pos) new TWEEN.Tween(this.camera.position).to({ x: pos.x, y: pos.y + 1.6, z: pos.z }, 50).start() + if (pos) { + let y = pos.y + this.playerHeight + if (this.isSneaking) y -= 0.3 + new TWEEN.Tween(this.camera.position).to({ x: pos.x, y, z: pos.z }, 50).start() + } this.camera.rotation.set(pitch, yaw, 0, 'ZYX') } From 81f39931d2b0482b10f77ea0dbefcd6b6b4c432a Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 18 Sep 2023 18:39:19 +0300 Subject: [PATCH 4/9] allow forcefully reload chunks --- viewer/lib/worldView.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/viewer/lib/worldView.js b/viewer/lib/worldView.js index ad0ffa44..ec2ccd98 100644 --- a/viewer/lib/worldView.js +++ b/viewer/lib/worldView.js @@ -102,10 +102,10 @@ class WorldView extends EventEmitter { delete this.loadedChunks[`${pos.x},${pos.z}`] } - async updatePosition (pos) { + async updatePosition (pos, force = false) { const [lastX, lastZ] = chunkPos(this.lastPos) const [botX, botZ] = chunkPos(pos) - if (lastX !== botX || lastZ !== botZ) { + if (lastX !== botX || lastZ !== botZ || force) { const newView = new ViewRect(botX, botZ, this.viewDistance) for (const coords of Object.keys(this.loadedChunks)) { const x = parseInt(coords.split(',')[0]) From 8d671e180d3b97211888a7260bffb28435e64e1a Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 18 Sep 2023 18:42:07 +0300 Subject: [PATCH 5/9] add a way to dispose world renderer resources (exit) --- viewer/lib/viewer.js | 6 ++++++ viewer/lib/worker.js | 3 +++ viewer/lib/worldrenderer.js | 14 +++++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/viewer/lib/viewer.js b/viewer/lib/viewer.js index 6b9236f2..8fe613a4 100644 --- a/viewer/lib/viewer.js +++ b/viewer/lib/viewer.js @@ -32,6 +32,12 @@ class Viewer { this.isSneaking = false } + resetAll () { + this.world.resetWorld() + this.entities.clear() + this.primitives.clear() + } + setVersion (version) { version = getVersion(version) console.log('Using version: ' + version) diff --git a/viewer/lib/worker.js b/viewer/lib/worker.js index ad76d37e..b7431677 100644 --- a/viewer/lib/worker.js +++ b/viewer/lib/worker.js @@ -54,6 +54,9 @@ self.onmessage = ({ data }) => { } else if (data.type === 'blockUpdate') { const loc = new Vec3(data.pos.x, data.pos.y, data.pos.z).floored() world.setBlockStateId(loc, data.stateId) + } else if (data.type === 'reset') { + world = null + blocksStates = null } } diff --git a/viewer/lib/worldrenderer.js b/viewer/lib/worldrenderer.js index b464401d..6f707726 100644 --- a/viewer/lib/worldrenderer.js +++ b/viewer/lib/worldrenderer.js @@ -12,6 +12,8 @@ function mod (x, n) { class WorldRenderer { constructor (scene, numWorkers = 4) { this.sectionMeshs = {} + this.active = false + this.version = undefined this.scene = scene this.loadedChunks = {} this.sectionsOutstanding = new Set() @@ -60,11 +62,21 @@ class WorldRenderer { } } - setVersion (version) { + resetWorld () { + this.active = false for (const mesh of Object.values(this.sectionMeshs)) { this.scene.remove(mesh) } this.sectionMeshs = {} + for (const worker of this.workers) { + worker.postMessage({ type: 'reset' }) + } + } + + setVersion (version) { + this.version = version + this.resetWorld() + this.active = true for (const worker of this.workers) { worker.postMessage({ type: 'version', version }) } From 457608c0624889be766bc71ba41d1e175cd13c86 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 18 Sep 2023 18:42:52 +0300 Subject: [PATCH 6/9] [doubt] skip rendering if folder already is here (speedup pm commands) --- viewer/prerender.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/viewer/prerender.js b/viewer/prerender.js index 089bf501..796c5652 100644 --- a/viewer/prerender.js +++ b/viewer/prerender.js @@ -5,14 +5,14 @@ const mcAssets = require('minecraft-assets') const fs = require('fs-extra') const texturesPath = path.resolve(__dirname, '../public/textures') -if (!fs.existsSync(texturesPath)) { - fs.mkdirSync(texturesPath) +if (fs.existsSync(texturesPath) && !process.argv.includes('-f')) { + console.log('textures folder already exists, skipping...') + process.exit(0) } +fs.mkdirSync(texturesPath, { recursive: true }) const blockStatesPath = path.resolve(__dirname, '../public/blocksStates') -if (!fs.existsSync(blockStatesPath)) { - fs.mkdirSync(blockStatesPath) -} +fs.mkdirSync(blockStatesPath, { recursive: true }) for (const version of mcAssets.versions) { const assets = mcAssets(version) From ed75585a281bf7d8b7cac886075f241e45707250 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 18 Sep 2023 18:46:21 +0300 Subject: [PATCH 7/9] support for resource packs (texturepacks) --- viewer/lib/worldrenderer.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/viewer/lib/worldrenderer.js b/viewer/lib/worldrenderer.js index 6f707726..744224a7 100644 --- a/viewer/lib/worldrenderer.js +++ b/viewer/lib/worldrenderer.js @@ -18,6 +18,8 @@ class WorldRenderer { this.loadedChunks = {} this.sectionsOutstanding = new Set() this.renderUpdateEmitter = new EventEmitter() + this.blockStatesData = undefined + this.texturesDataUrl = undefined this.material = new THREE.MeshLambertMaterial({ vertexColors: true, transparent: true, alphaTest: 0.1 }) @@ -81,14 +83,24 @@ class WorldRenderer { worker.postMessage({ type: 'version', version }) } - loadTexture(`textures/${version}.png`, texture => { + this.updateTexturesData() + } + + updateTexturesData () { + loadTexture(this.texturesDataUrl || `textures/${this.version}.png`, texture => { texture.magFilter = THREE.NearestFilter texture.minFilter = THREE.NearestFilter texture.flipY = false this.material.map = texture }) - loadJSON(`blocksStates/${version}.json`, blockStates => { + const loadBlockStates = () => { + return new Promise(resolve => { + if (this.blockStatesData) return resolve(this.blockStatesData) + return loadJSON(`blocksStates/${this.version}.json`, resolve) + }) + } + loadBlockStates().then((blockStates) => { for (const worker of this.workers) { worker.postMessage({ type: 'blockStates', json: blockStates }) } From cfb88434c576b17cb270e04d2024f2ca24d6543e Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 18 Sep 2023 20:46:21 +0300 Subject: [PATCH 8/9] standard fix --- examples/proxy.js | 8 ++++---- viewer/lib/models.js | 2 +- viewer/lib/modelsBuilder.js | 20 ++++++++++---------- viewer/lib/viewer.js | 1 - 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/examples/proxy.js b/examples/proxy.js index 5b18773c..12fff770 100644 --- a/examples/proxy.js +++ b/examples/proxy.js @@ -27,7 +27,7 @@ const srv = mc.createServer({ 'online-mode': false, port: 25566, keepAlive: false, - version: version + version }) srv.on('login', function (client) { @@ -47,11 +47,11 @@ srv.on('login', function (client) { if (!endedTargetClient) { targetClient.end('Error') } }) const targetClient = mc.createClient({ - host: host, - port: port, + host, + port, username: client.username, keepAlive: false, - version: version + version }) client.on('packet', function (data, meta) { if (targetClient.state === states.PLAY && meta.state === states.PLAY) { diff --git a/viewer/lib/models.js b/viewer/lib/models.js index 43cacee3..9f8938ec 100644 --- a/viewer/lib/models.js +++ b/viewer/lib/models.js @@ -480,7 +480,7 @@ function matchProperties (block, properties) { function getModelVariants (block, blockStates) { // air, cave_air, void_air and so on... if (block.name.includes('air')) return [] - const state = blockStates[block.name] ?? blockStates['missing_texture'] + const state = blockStates[block.name] ?? blockStates.missing_texture if (!state) return [] if (state.variants) { for (const [properties, variant] of Object.entries(state.variants)) { diff --git a/viewer/lib/modelsBuilder.js b/viewer/lib/modelsBuilder.js index 58aca167..1a6ab5cb 100644 --- a/viewer/lib/modelsBuilder.js +++ b/viewer/lib/modelsBuilder.js @@ -95,19 +95,19 @@ function resolveModel (name, blocksModels, texturesJson) { function prepareBlocksStates (mcAssets, atlas) { const blocksStates = mcAssets.blocksStates - mcAssets.blocksStates["missing_texture"] = { - "variants": { - "normal": { - "model": "missing_texture" + mcAssets.blocksStates.missing_texture = { + variants: { + normal: { + model: 'missing_texture' } } - }, - mcAssets.blocksModels["missing_texture"] = { - "parent": "block/cube_all", - "textures": { - "all": "blocks/missing_texture" - } + } + mcAssets.blocksModels.missing_texture = { + parent: 'block/cube_all', + textures: { + all: 'blocks/missing_texture' } + } for (const block of Object.values(blocksStates)) { if (!block) continue if (block.variants) { diff --git a/viewer/lib/viewer.js b/viewer/lib/viewer.js index 8fe613a4..696394ba 100644 --- a/viewer/lib/viewer.js +++ b/viewer/lib/viewer.js @@ -1,4 +1,3 @@ - const THREE = require('three') const TWEEN = require('@tweenjs/tween.js') const { WorldRenderer } = require('./worldrenderer') From 39b0849f91f84db49114a296fefd503bd5123fb4 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Sun, 17 Dec 2023 21:15:28 +0300 Subject: [PATCH 9/9] retrigger ci