Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
java-version: 21
java-package: jre
- name: Install xi
run: sudo apt-get install -y libxi-dev libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev build-essential libglu1-mesa-dev libglew-dev
run: sudo apt-get update && sudo apt-get install -y libxi-dev libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev build-essential libglu1-mesa-dev libglew-dev
- run: npm install
- run: npm run jestTest -- -t ${{ matrix.mcVersion }}
- uses: actions/upload-artifact@v4
Expand Down
2 changes: 1 addition & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ socket.on('version', (version) => {
viewer.setFirstPersonCamera(pos, yaw, pitch)
return
}
if (pos.y > 0 && firstPositionUpdate) {
if (firstPositionUpdate) {
controls.target.set(pos.x, pos.y, pos.z)
viewer.camera.position.set(pos.x, pos.y + 20, pos.z + 20)
controls.update()
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
"@tweenjs/tween.js": "^23.1.1",
"compression": "^1.7.4",
"express": "^4.17.1",
"minecraft-data": "^3.0.0",
"minecraft-data": "github:mneuhaus/node-minecraft-data#add-26.1.2-data-wrapper",
"prismarine-block": "^1.7.3",
"prismarine-chunk": "^1.22.0",
"prismarine-chunk": "github:mneuhaus/prismarine-chunk#pc26_1_2-fluid-count",
"prismarine-world": "^3.3.1",
"socket.io": "^4.0.0",
"socket.io-client": "^4.0.0",
Expand All @@ -42,7 +42,7 @@
"fs-extra": "^11.0.0",
"jest": "^29.7.0",
"jest-puppeteer": "^11.0.0",
"minecraft-assets": "^1.9.0",
"minecraft-assets": "github:mneuhaus/node-minecraft-assets#add-26.1.2-assets",
"minecraft-wrap": "^1.3.0",
"minecrafthawkeye": "^1.2.5",
"mineflayer": "^4.0.0",
Expand Down
43 changes: 28 additions & 15 deletions viewer/lib/modelsBuilder.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
function cleanupBlockName (name) {
name = getTextureName(name)
if (name === null) return 'missing_texture'
if (name.startsWith('block') || name.startsWith('minecraft:block')) return name.split('/')[1]
return name
}

function getTextureName (texture) {
if (texture === null || texture === undefined) return null
if (typeof texture === 'string') return texture
if (typeof texture.sprite === 'string') return texture.sprite
if (typeof texture.texture === 'string') return texture.texture
return null
}

function resolveTexture (texture, texturesJson) {
const name = cleanupBlockName(texture)
return JSON.parse(JSON.stringify(texturesJson[name] || texturesJson.missing_texture))
}

function getModel (name, blocksModels) {
name = cleanupBlockName(name)
const data = blocksModels[name]
Expand Down Expand Up @@ -36,32 +51,30 @@ 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) === '#') {
root = model.textures[root.substr(1)]
let root = getTextureName(model.textures[tex])
while (root && root.charAt(0) === '#') {
root = getTextureName(model.textures[root.substr(1)])
}
model.textures[tex] = root
model.textures[tex] = root || 'missing_texture'
}
for (const tex in model.textures) {
let name = model.textures[tex]
name = cleanupBlockName(name)
model.textures[tex] = texturesJson[name]
model.textures[tex] = resolveTexture(model.textures[tex], texturesJson)
}
for (const elem of model.elements) {
for (const sideName of Object.keys(elem.faces)) {
const face = elem.faces[sideName]
const faceTextureName = getTextureName(face.texture)

if (face.texture.charAt(0) === '#') {
face.texture = JSON.parse(JSON.stringify(model.textures[face.texture.substr(1)]))
if (faceTextureName && faceTextureName.charAt(0) === '#') {
face.texture = JSON.parse(JSON.stringify(model.textures[faceTextureName.substr(1)]))
} else if (
!(cleanupBlockName(face.texture) in texturesJson) &&
face.texture in model.textures
!(cleanupBlockName(faceTextureName) in texturesJson) &&
faceTextureName &&
faceTextureName in model.textures
) {
face.texture = JSON.parse(JSON.stringify(model.textures[face.texture]))
face.texture = JSON.parse(JSON.stringify(model.textures[faceTextureName]))
} else {
let name = face.texture
name = cleanupBlockName(name)
face.texture = JSON.parse(JSON.stringify(texturesJson[name]))
face.texture = resolveTexture(faceTextureName, texturesJson)
}

let uv = face.uv
Expand Down
2 changes: 1 addition & 1 deletion viewer/lib/version.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const supportedVersions = ['1.8.8', '1.9.4', '1.10.2', '1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.1', '1.16.4', '1.17.1', '1.18.1', '1.19', '1.20.1', '1.21.1', '1.21.4']
const supportedVersions = ['1.8.8', '1.9.4', '1.10.2', '1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.1', '1.16.4', '1.17.1', '1.18.1', '1.19', '1.20.1', '1.21.1', '1.21.4', '1.21.11', '26.1.2']

const lastOfMajor = {}
for (const version of supportedVersions) {
Expand Down
10 changes: 8 additions & 2 deletions viewer/lib/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function setSectionDirty (pos, value = true) {
if (!value) {
delete dirtySections[key]
postMessage({ type: 'sectionFinished', key })
} else if (chunk && chunk.sections[Math.floor(y / 16)]) {
} else if (hasSection(chunk, y)) {
dirtySections[key] = value
} else {
postMessage({ type: 'sectionFinished', key })
Expand Down Expand Up @@ -74,7 +74,7 @@ setInterval(() => {
y = parseInt(y, 10)
z = parseInt(z, 10)
const chunk = world.getColumn(x, z)
if (chunk && chunk.sections[Math.floor(y / 16)]) {
if (hasSection(chunk, y)) {
delete dirtySections[key]
const geometry = getSectionGeometry(x, y, z, world, blocksStates)
const transferable = [geometry.positions.buffer, geometry.normals.buffer, geometry.colors.buffer, geometry.uvs.buffer]
Expand All @@ -85,3 +85,9 @@ setInterval(() => {
// const time = performance.now() - start
// console.log(`Processed ${sections.length} sections in ${time} ms (${time / sections.length} ms/section)`)
}, 50)

function hasSection (chunk, y) {
if (!chunk) return false
const minY = chunk.minY ?? 0
return Boolean(chunk.sections[(y - minY) >> 4])
}
19 changes: 17 additions & 2 deletions viewer/lib/worldrenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class WorldRenderer {
this.version = undefined
this.scene = scene
this.loadedChunks = {}
this.loadedChunkRanges = {}
this.sectionsOutstanding = new Set()
this.renderUpdateEmitter = new EventEmitter()
this.blockStatesData = undefined
Expand Down Expand Up @@ -70,6 +71,8 @@ class WorldRenderer {
this.scene.remove(mesh)
}
this.sectionMeshs = {}
this.loadedChunks = {}
this.loadedChunkRanges = {}
for (const worker of this.workers) {
worker.postMessage({ type: 'reset' })
}
Expand Down Expand Up @@ -109,10 +112,12 @@ class WorldRenderer {

addColumn (x, z, chunk) {
this.loadedChunks[`${x},${z}`] = true
const range = getChunkVerticalRange(chunk)
this.loadedChunkRanges[`${x},${z}`] = range
for (const worker of this.workers) {
worker.postMessage({ type: 'chunk', x, z, chunk })
}
for (let y = 0; y < 256; y += 16) {
for (let y = range.minY; y < range.maxY; y += 16) {
const loc = new Vec3(x, y, z)
this.setSectionDirty(loc)
this.setSectionDirty(loc.offset(-16, 0, 0))
Expand All @@ -124,10 +129,12 @@ class WorldRenderer {

removeColumn (x, z) {
delete this.loadedChunks[`${x},${z}`]
const range = this.loadedChunkRanges[`${x},${z}`] || { minY: 0, maxY: 256 }
delete this.loadedChunkRanges[`${x},${z}`]
for (const worker of this.workers) {
worker.postMessage({ type: 'unloadChunk', x, z })
}
for (let y = 0; y < 256; y += 16) {
for (let y = range.minY; y < range.maxY; y += 16) {
this.setSectionDirty(new Vec3(x, y, z), false)
const key = `${x},${y},${z}`
const mesh = this.sectionMeshs[key]
Expand Down Expand Up @@ -181,4 +188,12 @@ class WorldRenderer {
}
}

function getChunkVerticalRange (chunk) {
if (!chunk) return { minY: 0, maxY: 256 }
const data = typeof chunk === 'string' ? JSON.parse(chunk) : chunk
const minY = data.minY ?? 0
const worldHeight = data.worldHeight ?? 256
return { minY, maxY: minY + worldHeight }
}

module.exports = { WorldRenderer }
8 changes: 8 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const path = require('path')
const blockedIndexFiles = ['blocksB2J', 'blocksJ2B', 'blockMappings', 'steve', 'recipes']
const allowedWorkerFiles = ['blocks', 'blockCollisionShapes', 'tints', 'blockStates',
'biomes', 'features', 'version', 'legacy', 'versions', 'version', 'protocolVersions']
const allowedWorkerBedrockFiles = ['legacy', 'versions', 'protocolVersions']

const indexConfig = {
entry: './lib/index.js',
Expand All @@ -18,6 +19,7 @@ const indexConfig = {
},
resolve: {
fallback: {
assert: require.resolve('assert/'),
zlib: false
}
},
Expand Down Expand Up @@ -59,6 +61,7 @@ const workerConfig = {
},
resolve: {
fallback: {
assert: require.resolve('assert/'),
zlib: false
}
},
Expand All @@ -74,7 +77,12 @@ const workerConfig = {
externals: [
function (req, cb) {
if (req.context.includes('minecraft-data') && req.request.endsWith('.json')) {
const requestPath = `${req.context}/${req.request}`
const fileName = req.request.split('/').pop().replace('.json', '')
if (requestPath.match(/[\\/]data[\\/]bedrock[\\/]/) && !allowedWorkerBedrockFiles.includes(fileName)) {
cb(null, [])
return
}
if (!allowedWorkerFiles.includes(fileName)) {
cb(null, [])
return
Expand Down
Loading