diff --git a/src/js/net/minecraft/client/render/BlockRenderer.js b/src/js/net/minecraft/client/render/BlockRenderer.js index b402af4..35acc17 100644 --- a/src/js/net/minecraft/client/render/BlockRenderer.js +++ b/src/js/net/minecraft/client/render/BlockRenderer.js @@ -47,7 +47,7 @@ window.BlockRenderer = class { // Classic lightning if (BlockRenderer.CLASSIC_LIGHTNING) { - let brightness = 0.9 / 15.0 * world.getLightAt(minX + face.x, minY + face.y, minZ + face.z) + 0.1; + let brightness = 0.9 / 15.0 * world.getTotalLightAt(minX + face.x, minY + face.y, minZ + face.z) + 0.1; let color = brightness * face.getShading(); this.tessellator.setColor(color, color, color); } diff --git a/src/js/net/minecraft/client/world/Chunk.js b/src/js/net/minecraft/client/world/Chunk.js index 3d51e97..4d4787e 100644 --- a/src/js/net/minecraft/client/world/Chunk.js +++ b/src/js/net/minecraft/client/world/Chunk.js @@ -21,37 +21,37 @@ window.Chunk = class { // Create height map this.heightMap = []; + this.initHeightMapAndLight(); } - setBlockAt(x, y, z, typeId) { - let section = this.getSection(y >> 4); - let prevTypeId = section.getBlockAt(x, y & 15, z); - if (prevTypeId === typeId) { - return; - } + initHeightMapAndLight() { + let highest = World.TOTAL_HEIGHT; + for (let x = 0; x < 16; x++) { + for (let z = 0; z < 16; z++) { + this.heightMap[z << 4 | x] = -1; - // Update block type id - section.setBlockAt(x, y & 15, z, typeId); + this.updateHeightMap(x, World.TOTAL_HEIGHT, z); - let block = Block.getById(typeId); - let heightLevel = this.heightMap[z << 4 | x] & 0xff; - - if (typeId !== 0 && block.isSolid()) { - if (y >= heightLevel) { - // Update height map if it is the new highest block now - this.updateHeightMap(x, y + 1, z); + if ((this.heightMap[z << 4 | x] & 0xff) < highest) { + highest = this.heightMap[z << 4 | x] & 0xff; + } } - } else if (y === heightLevel - 1) { - // Update height map if it is below the highest block because it could block the sun - this.updateHeightMap(x, y, z); + } - // Update light at block - //this.world.updateLight(EnumSkyBlock.SKY, x, y, z, x, y, z); - //this.world.updateLight(EnumSkyBlock.BLOCK, x, y, z, x, y, z); + this.highestY = highest; + for (let k = 0; k < 16; k++) { + for (let i1 = 0; i1 < 16; i1++) { + this.notifyNeighbors(k, i1); + } + + } + + this.queueForRebuild(); + } + + updateBlockLight() { - // Notify neighbors - //this.notifyNeighbors(x, z); } notifyNeighbors(x, z) { @@ -72,6 +72,126 @@ window.Chunk = class { } else if (height < y) { this.world.updateLight(EnumSkyBlock.SKY, x, height, z, x, y, z); } + this.queueForRebuild(); + } + + updateHeightMap(relX, y, relZ) { + let currentHighestY = this.heightMap[relZ << 4 | relX] & 0xff; + let highestY = currentHighestY; + if (y > currentHighestY) { + highestY = y; + } + while (highestY > 0 && Block.lightOpacity[this.getBlockAt(relX, highestY - 1, relZ)] === 0) { + highestY--; + } + if (highestY === currentHighestY) { + return; + } + //this.world.heightLevelChanged(relX, relZ, highestY, currentHighestY); + this.heightMap[relZ << 4 | relX] = highestY; + if (highestY < this.highestY) { + this.highestY = highestY; + } else { + let highest = 127; + for (let cx = 0; cx < 16; cx++) { + for (let cz = 0; cz < 16; cz++) { + if ((this.heightMap[cz << 4 | cx] & 0xff) < highest) { + highest = this.heightMap[cz << 4 | cx] & 0xff; + } + } + + } + + this.highestY = highest; + } + + let x = this.x * 16 + relX; + let z = this.z * 16 + relZ; + + if (highestY < currentHighestY) { + for (let l2 = highestY; l2 < currentHighestY; l2++) { + this.setLightAt(EnumSkyBlock.SKY, relX, l2, relZ, 15); + } + + } else { + this.world.updateLight(EnumSkyBlock.SKY, x, currentHighestY, z, x, highestY, z); + for (let hy = currentHighestY; hy < highestY; hy++) { + this.setLightAt(EnumSkyBlock.SKY, relX, hy, relZ, 0); + } + + } + let lightLevel = 15; + let prevHeight = highestY; + while (highestY > 0 && lightLevel > 0) { + highestY--; + let opacity = Block.lightOpacity[this.getBlockID(relX, highestY, relZ)]; + if (opacity === 0) { + opacity = 1; + } + lightLevel -= opacity; + if (lightLevel < 0) { + lightLevel = 0; + } + this.setLightAt(EnumSkyBlock.SKY, relX, highestY, relZ, lightLevel); + } + for (; highestY > 0 && Block.lightOpacity[this.getBlockID(relX, highestY - 1, relZ)] === 0; highestY--) { + } + if (highestY !== prevHeight) { + this.world.updateLight(EnumSkyBlock.SKY, x - 1, highestY, z - 1, x + 1, prevHeight, z + 1); + } + this.queueForRebuild(); + } + + setLightAt(sourceType, x, y, z, level) { + this.getSection(y >> 4).setLightAt(sourceType, x, y & 15, z, level); + } + + setBlockAt(x, y, z, typeId) { + let byte0 = typeId; + let height = this.heightMap[z << 4 | x] & 0xff; + + let prevTypeId = this.getBlockAt(x, y, z); + if (prevTypeId === typeId) { + return false; + } + + let totalX = this.x * 16 + x; + let totalZ = this.z * 16 + z; + + this.getSection(y >> 4).setBlockAt(x, y & 15, z, byte0); + + //if (k1 !== 0 && !this.worldObj.multiplayerWorld) { + //Block.blocksList[k1].onBlockRemoval(this.world, l1, j, i2); + //} + //this.data.setNibble(i, j, k, i1); + //if (!this.worldObj.worldProvider.field_6478_e) { + + if (Block.lightOpacity[byte0] !== 0) { + if (y >= height) { + this.updateHeightMap(x, y + 1, z); + } + } else if (y === height - 1) { + this.updateHeightMap(x, y, z); + } + + this.world.updateLight(EnumSkyBlock.SKY, totalX, y, totalZ, totalX, y, totalZ); + //} + + this.world.updateLight(EnumSkyBlock.BLOCK, totalX, y, totalZ, totalX, y, totalZ); + this.notifyNeighbors(x, z); + + if (typeId !== 0) { + //Block.blocksList[l].onBlockAdded(this.worldObj, l1, j, i2); + } + + //this.data.setNibble(i, j, k, i1); + + this.queueForRebuild(); + return true; + } + + getBlockID(x, y, z) { + return this.getBlockAt(x, y, z); } getBlockAt(x, y, z) { @@ -86,75 +206,6 @@ window.Chunk = class { return this.heightMap[z << 4 | x] & 0xff; } - updateHeightMap(x, y, z) { - let currentHighestY = this.heightMap[z << 4 | x] & 0xff; - let highestY = currentHighestY; - if (y > currentHighestY) { - highestY = y; - } - - // Find new highest blocks - while (highestY > 0) { - let typeId = this.getBlockAt(x, highestY, z); - let block = Block.getById(typeId); - if (typeId !== 0 && block.isSolid()) { - break; - } - highestY--; - } - - // Check if highest block changed - if (highestY === currentHighestY) { - return; - } - - // Save in height map - this.heightMap[z << 4 | x] = highestY; - - - let totalX = this.x * 16 + x; - let totalZ = this.z * 16 + z; - - if (highestY < currentHighestY) { - for (let hy = highestY; hy < currentHighestY; hy++) { - this.getSection(hy >> 4).setLightAt(EnumSkyBlock.SKY, x, hy, z, 15); - } - } else { - this.world.updateLight(EnumSkyBlock.SKY, totalX, currentHighestY, totalZ, totalX, highestY, totalZ); - - for (let hy = currentHighestY; hy < highestY; hy++) { - this.getSection(hy >> 4).setLightAt(EnumSkyBlock.SKY, x, hy, z, 0); - } - - } - - let lightLevel = 15; - let currentY = highestY; - while (currentY > 0 && lightLevel > 0) { - currentY--; - - let typeId = this.getBlockAt(x, currentY, z); - let block = Block.getById(typeId); - - // Reduce light level by opacity - if (typeId !== 0) { - lightLevel *= (1 - block.getOpacity()); - } - - // Min light level - if (lightLevel < 0) { - lightLevel = 0; - } - - // Update light level - this.getSection(currentY >> 4).setLightAt(EnumSkyBlock.SKY, x & 15, currentY, z & 15, lightLevel); - } - - if (currentY !== highestY) { - this.world.updateLight(EnumSkyBlock.SKY, x - 1, currentY, z - 1, x + 1, currentY, z + 1); - } - } - getSection(y) { return this.sections[y]; } diff --git a/src/js/net/minecraft/client/world/ChunkSection.js b/src/js/net/minecraft/client/world/ChunkSection.js index 90a3779..f9db3ae 100644 --- a/src/js/net/minecraft/client/world/ChunkSection.js +++ b/src/js/net/minecraft/client/world/ChunkSection.js @@ -84,7 +84,13 @@ window.ChunkSection = class { setLightAt(sourceType, x, y, z, lightLevel) { let index = y << 8 | z << 4 | x; - this.blockLight[index] = lightLevel; + + if (sourceType === EnumSkyBlock.SKY) { + this.skyLight[index] = lightLevel; + } + if (sourceType === EnumSkyBlock.BLOCK) { + this.blockLight[index] = lightLevel; + } } getTotalLightAt(x, y, z) { @@ -102,7 +108,7 @@ window.ChunkSection = class { if (sourceType === EnumSkyBlock.SKY) { return this.skyLight[index]; } - if (sourceType === EnumSkyBlock.Block) { + if (sourceType === EnumSkyBlock.BLOCK) { return this.blockLight[index]; } return 0; diff --git a/src/js/net/minecraft/client/world/World.js b/src/js/net/minecraft/client/world/World.js index 760c867..dc85ced 100644 --- a/src/js/net/minecraft/client/world/World.js +++ b/src/js/net/minecraft/client/world/World.js @@ -63,7 +63,12 @@ window.World = class { return; } - this.lightUpdates++; + let centerX = (x2 + x1) / 2; + let centerZ = (z2 + z1) / 2; + + if (!this.blockExists(centerX, 64, centerZ)) { + return; + } let size = this.lightUpdateQueue.length; @@ -72,39 +77,49 @@ window.World = class { if (max > size) { max = size; } - for (let i = 0; i < max; i++) { - let meta = this.lightUpdateQueue[size - i - 1]; + let meta = this.lightUpdateQueue[(this.lightUpdateQueue.length - i - 1)]; if (meta.type === sourceType && meta.isOutsideOf(x1, y1, z1, x2, y2, z2)) { - this.lightUpdates--; return; } } - } - // Push light update to queue + } this.lightUpdateQueue.push(new MetadataChunkBlock(sourceType, x1, y1, z1, x2, y2, z2)); if (this.lightUpdateQueue.length > 0x186a0) { this.lightUpdateQueue = []; } - this.lightUpdates--; } - neighborLightPropagationChanged(sourceType, x, y, z, lightLevel) { + blockExists(x, y, z) { + if (y < 0 || y >= 128) { + return false; + } else { + return this.chunkExists(x >> 4, z >> 4); + } + } + + chunkExists(chunkX, chunkZ) { + let index = chunkX + (chunkZ << 16); + let chunk = this.chunks.get(index); + return typeof chunk !== 'undefined'; + } + + neighborLightPropagationChanged(sourceType, x, y, z, level) { + if (!this.blockExists(x, y, z)) { + return; + } if (sourceType === EnumSkyBlock.SKY) { if (this.isHighestBlock(x, y, z)) { - lightLevel = 15; + level = 15; } } else if (sourceType === EnumSkyBlock.BLOCK) { - let typeId = this.getBlockAt(x, y, z); - let block = Block.getById(typeId); - let blockLight = block.getLightValue(); - - if (blockLight > lightLevel) { - lightLevel = blockLight; + let i1 = this.getBlockAt(x, y, z); + if (0 > level) { // TODO + level = 0; } } - if (this.getSavedLightValue(sourceType, x, y, z) !== lightLevel) { + if (this.getSavedLightValue(sourceType, x, y, z) !== level) { this.updateLight(sourceType, x, y, z, x, y, z); } } @@ -130,6 +145,10 @@ window.World = class { } getHeightAt(x, z) { + if (!this.chunkExists(x >> 4, z >> 4)) { + return 0; + } + return this.getChunkAt(x >> 4, z >> 4).getHeightAt(x & 15, z & 15); } diff --git a/src/js/net/minecraft/client/world/block/Block.js b/src/js/net/minecraft/client/world/block/Block.js index ad1665f..7667b2d 100644 --- a/src/js/net/minecraft/client/world/block/Block.js +++ b/src/js/net/minecraft/client/world/block/Block.js @@ -2,6 +2,8 @@ window.Block = class { static blocks = new Map(); + static lightOpacity = []; + static create() { Block.STONE = new BlockStone(1, 0); Block.GRASS = new BlockGrass(2, 1); @@ -20,6 +22,7 @@ window.Block = class { // Register block Block.blocks.set(id, this); + Block.lightOpacity[id] = this.isSolid() ? 255 : 0; } getId() { diff --git a/src/js/net/minecraft/util/MetadataChunkBlock.js b/src/js/net/minecraft/util/MetadataChunkBlock.js index eedfb99..4ef99d1 100644 --- a/src/js/net/minecraft/util/MetadataChunkBlock.js +++ b/src/js/net/minecraft/util/MetadataChunkBlock.js @@ -11,29 +11,41 @@ window.MetadataChunkBlock = class { } updateBlockLightning(world) { + let centerX = (this.x2 - this.x1) + 1; + let centerY = (this.y2 - this.y1) + 1; + let centerZ = (this.z2 - this.z1) + 1; + let index = centerX * centerY * centerZ; + if (index > 32768) { + return; + } for (let x = this.x1; x <= this.x2; x++) { for (let z = this.z1; z <= this.z2; z++) { + if (!world.blockExists(x, 0, z)) { + continue; + } + for (let y = this.y1; y <= this.y2; y++) { + if (y < 0 || y >= World.TOTAL_HEIGHT) { + continue; + } let savedLightValue = world.getSavedLightValue(this.type, x, y, z); - - let level = 0; let newLevel = 0; - let typeId = world.getBlockAt(x, y, z); - let block = Block.getById(typeId); + let opacity = Block.lightOpacity[typeId]; - let opacity = typeId === 0 ? 0 : (block.getOpacity() * 255); if (opacity === 0) { opacity = 1; } + let level = 0; + if (this.type === EnumSkyBlock.SKY) { if (world.isHighestBlock(x, y, z)) { level = 15; } } else if (this.type === EnumSkyBlock.BLOCK) { - level = typeId === 0 ? 0 : block.getLightValue(); + level = 0; // TODO } if (opacity >= 15 && level === 0) { @@ -63,9 +75,7 @@ window.MetadataChunkBlock = class { if (z2Level > newLevel) { newLevel = z2Level; } - newLevel -= opacity; - if (newLevel < 0) { newLevel = 0; } @@ -73,11 +83,9 @@ window.MetadataChunkBlock = class { newLevel = level; } } - if (savedLightValue === newLevel) { continue; } - world.setLightAt(this.type, x, y, z, newLevel); let decreasedLevel = newLevel - 1;