import { Vector3 } from 'three' import { ChunkTerrain } from './ChunkTerrain.js' import { AnimatedTextureAtlas } from './AnimatedTextureAtlas.js' import { SectionComputer } from './SectionComputer.js' import { ChunkManager } from './ChunkManager.js' import ChunkWorker from './chunk.worker.js' class World { constructor (game) { this.game = game this.blocksDef = this.game.al.get('blocksDef') this.chunkTerrain = new ChunkTerrain({ blocksDef: this.blocksDef }) this.ATA = new AnimatedTextureAtlas(this.game) this.material = this.ATA.material this.cellUpdateTime = null this.lastPlayerChunk = null this.blocksUpdate = false this.chunkManager = new ChunkManager(this.game) this.chunkWorker = new ChunkWorker() this.chunkWorker.onmessage = (message) => { if (message.data.type === 'cellGeo') { const cellId = this.chunkTerrain.vecToStr(...message.data.data.info) const vert = message.data.data.cell this.chunkManager.addChunk(cellId, vert) } else if (message.data.type === 'removeCell') { this.chunkManager.removeChunk(message.data.data) } } this.chunkWorker.postMessage({ type: 'init', data: { blocksMapping: this.game.al.get('blocksMapping'), toxelSize: this.game.toxelSize, blocksTex: this.game.al.get('blocksTex'), blocksDef: this.blocksDef } }) } setChunk (chunkX, chunkY, chunkZ, buffer) { this.cellUpdateTime = window.performance.now() this.chunkWorker.postMessage({ type: 'setChunk', data: [chunkX, chunkY, chunkZ, buffer] }) this.chunkTerrain.setChunk(chunkX, chunkY, chunkZ, buffer) } setBlock (voxelX, voxelY, voxelZ, value) { voxelX = parseInt(voxelX) voxelY = parseInt(voxelY) voxelZ = parseInt(voxelZ) this.blocksUpdate = true if (this.chunkTerrain.getVoxel(voxelX, voxelY, voxelZ) !== value) { this.chunkWorker.postMessage({ type: 'setVoxel', data: [voxelX, voxelY, voxelZ, value] }) this.chunkTerrain.setVoxel(voxelX, voxelY, voxelZ, value) } } resetWorld () { this.chunkManager.reset() this.chunkTerrain.reset() this.chunkWorker.postMessage({ type: 'resetWorld', data: null }) } getRayBlock () { const start = new Vector3().setFromMatrixPosition(this.game.camera.matrixWorld) const end = new Vector3().set(0, 0, 1).unproject(this.game.camera) const intersection = this.chunkTerrain.intersectsRay(start, end) if (intersection) { const posPlace = intersection.position.map(function (v, ndx) { return Math.floor(v + intersection.normal[ndx] * 0.5) }) const posBreak = intersection.position.map(function (v, ndx) { return Math.floor(v + intersection.normal[ndx] * -0.5) }) return { posPlace, posBreak } } else { return false } } updateChunksAroundPlayer (radius) { this.chunkManager.update() const pos = this.game.camera.position const cell = this.chunkTerrain.computeChunkForVoxel( Math.floor(pos.x + 0.5), Math.floor(pos.y + 0.5), Math.floor(pos.z + 0.5) ) if (this.blocksUpdate) { this.blocksUpdate = false this.chunkWorker.postMessage({ type: 'updateChunksAroundPlayer', data: [cell, radius] }) } else if (this.lastPlayerChunk !== JSON.stringify(cell)) { if ( this.cellUpdateTime !== null && window.performance.now() - this.cellUpdateTime > 100 ) { this.chunkManager.updateRenderOrder(cell) this.lastPlayerChunk = JSON.stringify(cell) this.chunkWorker.postMessage({ type: 'updateChunksAroundPlayer', data: [cell, radius] }) } } } computeSections (sections, biomes, x, z) { const result = SectionComputer({ sections, x, z }) const results = [] for (const i in result) { const j = result[i] if (j !== null) { results.push(this.setChunk(j.x, j.y, j.z, j.cell)) } else { results.push(undefined) } } return results } } export { World }