diff --git a/.gitignore b/.gitignore index fe44a853..609b7604 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules package-lock.json /test/*.png +/test/server_* versions/ public/index.js* public/worker.js* diff --git a/viewer/lib/entities.js b/viewer/lib/entities.js index 660a3244..8aa8c2fa 100644 --- a/viewer/lib/entities.js +++ b/viewer/lib/entities.js @@ -7,7 +7,9 @@ const { dispose3 } = require('./dispose') function getEntityMesh (entity, scene) { if (entity.name) { try { - const e = new Entity('1.16.4', entity.name, scene) + // Old versions of minecraft use titlecase entity names (e.g. 'Zombie' instead of 'zombie') + // TODO old version name support. "entityhorse" instead of "horse" in some versions, causing a pink box to render instead + const e = new Entity('1.16.4', entity.name.toLowerCase(), scene) if (entity.username !== undefined) { const canvas = document.createElement('canvas') diff --git a/viewer/lib/viewer.js b/viewer/lib/viewer.js index 14d64a45..01a31274 100644 --- a/viewer/lib/viewer.js +++ b/viewer/lib/viewer.js @@ -10,6 +10,7 @@ class Viewer { constructor (renderer) { this.scene = new THREE.Scene() this.scene.background = new THREE.Color('lightblue') + this.skyColour = this.scene.background.getHexString() this.ambientLight = new THREE.AmbientLight(0xcccccc) this.scene.add(this.ambientLight) @@ -91,6 +92,10 @@ class Viewer { this.setBlockStateId(new Vec3(pos.x, pos.y, pos.z), stateId) }) + emitter.on('timecycleUpdate', ({ timeOfDay, moonPhase }) => { + this.updateTimecycleLighting(timeOfDay, moonPhase) + }) + this.domElement.addEventListener('pointerdown', (evt) => { const raycaster = new THREE.Raycaster() const mouse = new THREE.Vector2() @@ -102,6 +107,53 @@ class Viewer { }) } + updateTimecycleLighting (timeOfDay, moonPhase) { + if (timeOfDay === undefined) { return } + const lightIntensity = this.calculateIntensity(timeOfDay) + const newSkyColor = `#${this.darkenSkyColour(lightIntensity).padStart(6, 0)}` + + function timeToRads (time) { + return time * (Math.PI / 12000) + } + + // Update colours + this.scene.background = new THREE.Color(newSkyColor) + const newAmbientIntensity = Math.min(0.43, lightIntensity * 0.75) + (0.04 - (moonPhase / 100)) + const newDirectionalIntensity = Math.min(0.63, lightIntensity) + (0.06 - (moonPhase / 100)) + this.ambientLight.itensity = newAmbientIntensity + this.directionalLight.intensity = newDirectionalIntensity + this.directionalLight.position.set( + Math.cos(timeToRads(timeOfDay)), + Math.sin(timeToRads(timeOfDay)), + 0.2 + ).normalize() + } + + calculateIntensity (currentTicks) { + const transitionStart = 12000 + const transitionEnd = 18000 + const timeInDay = (currentTicks % 24000) + let lightIntensity + + if (timeInDay < transitionStart) { + lightIntensity = 1.0 + } else if (timeInDay < transitionEnd) { + lightIntensity = 1 - (timeInDay - transitionStart) / (transitionEnd - transitionStart) + } else { + lightIntensity = (timeInDay - transitionEnd) / (24000 - transitionEnd) + } + + return lightIntensity + } + + // Darken by factor (0 to black, 0.5 half as bright, 1 unchanged) + darkenSkyColour (factor) { + const skyColour = parseInt(this.skyColour, 16) + return (Math.round((skyColour & 0x0000FF) * factor) | + (Math.round(((skyColour >> 8) & 0x00FF) * factor) << 8) | + (Math.round((skyColour >> 16) * factor) << 16)).toString(16) + } + update () { TWEEN.update() } diff --git a/viewer/lib/worldView.js b/viewer/lib/worldView.js index ad0ffa44..3939533b 100644 --- a/viewer/lib/worldView.js +++ b/viewer/lib/worldView.js @@ -10,6 +10,7 @@ class WorldView extends EventEmitter { this.loadedChunks = {} this.lastPos = new Vec3(0, 0, 0).update(position) this.emitter = emitter || this + this._timecycleUpdateInterval = null this.listeners = {} this.emitter.on('mouseClick', async (click) => { @@ -54,6 +55,10 @@ class WorldView extends EventEmitter { this.emitter.emit('entity', { id: e.id, name: e.name, pos: e.position, width: e.width, height: e.height, username: e.username }) } } + + this._timecycleUpdateInterval = setInterval(() => { + this.emitter.emit('timecycleUpdate', { timeOfDay: bot.time.timeOfDay, moonPhase: bot.time.moonPhase }) + }, 1000) } removeListenersFromBot (bot) { @@ -61,6 +66,9 @@ class WorldView extends EventEmitter { bot.removeListener(evt, listener) } delete this.listeners[bot.username] + + clearInterval(this._timecycleUpdateInterval) + this._timecycleUpdateInterval = null } async init (pos) {