diff --git a/src/js/net/minecraft/client/Minecraft.js b/src/js/net/minecraft/client/Minecraft.js index 6f4593d..a9f792b 100644 --- a/src/js/net/minecraft/client/Minecraft.js +++ b/src/js/net/minecraft/client/Minecraft.js @@ -224,7 +224,13 @@ window.Minecraft = class { if (!placedBoundingBox.intersects(this.player.boundingBox)) { let typeId = this.inventory.getItemInSelectedSlot(); if (typeId !== 0) { + + // Place block this.world.setBlockAt(x, y, z, typeId); + + // Handle block abilities + let block = Block.getById(typeId); + block.onBlockPlaced(this.world, x, y, z, hitResult.face); } } } diff --git a/src/js/net/minecraft/client/render/BlockRenderer.js b/src/js/net/minecraft/client/render/BlockRenderer.js index 1825c34..ae82c5b 100644 --- a/src/js/net/minecraft/client/render/BlockRenderer.js +++ b/src/js/net/minecraft/client/render/BlockRenderer.js @@ -158,18 +158,44 @@ window.BlockRenderer = class { } renderTorch(world, block, x, y, z) { - let boundingBox = block.getBoundingBox(world, x, y, z); - // Thickness of the torch let size = 1 / 16; + let distortX = 0; + let distortZ = 0; + + // Attach torch at wall + switch (world.getBlockDataAt(x, y, z)) { + case 1: + distortX = -0.2; + break; + case 2: + distortX = 0.2; + break; + case 3: + distortZ = -0.2; + break; + case 4: + distortZ = 0.2; + break; + } + + // Model type + let centerX = 0.5 + distortX * 1.5; + let centerZ = 0.5 + distortZ * 1.5; + + // Lift the torch up + if (distortX !== 0 || distortZ !== 0) { + y += 0.2; + } + // Vertex mappings - let minX = x + 0.5 - size; + let minX = x + centerX - size; let minY = y; - let minZ = z + 0.5 - size; - let maxX = x + 0.5 + size; + let minZ = z + centerZ - size; + let maxX = x + centerX + size; let maxY = y + 10 / 16; - let maxZ = z + 0.5 + size; + let maxZ = z + centerZ + size; // UV Mapping let textureIndex = block.getTextureForFace(EnumBlockFace.NORTH); @@ -191,36 +217,39 @@ window.BlockRenderer = class { // Set color with shading this.tessellator.setColor(1, 1, 1); - // Add faceS to tessellator - this.addFace(world, EnumBlockFace.NORTH, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV); - this.addFace(world, EnumBlockFace.EAST, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV); - this.addFace(world, EnumBlockFace.SOUTH, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV); - this.addFace(world, EnumBlockFace.WEST, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV); + // Add faces to tessellator + this.addDistortFace(world, EnumBlockFace.NORTH, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV, distortX, distortZ); + this.addDistortFace(world, EnumBlockFace.EAST, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV, distortX, distortZ); + this.addDistortFace(world, EnumBlockFace.SOUTH, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV, distortX, distortZ); + this.addDistortFace(world, EnumBlockFace.WEST, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV, distortX, distortZ); this.addFace(world, EnumBlockFace.TOP, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV + 8 / 256); } - renderGuiItem(block) { - // Vertex mappings - let minX = 0; - let minY = 0; - let minZ = 0; - let maxX = 1; - let maxY = 1; - let maxZ = 1; - - // UV Mapping - let textureIndex = block.getTextureForFace(EnumBlockFace.NORTH); - let minU = (textureIndex % 16) / 16.0; - let maxU = minU + (16 / 256); - let minV = Math.floor(textureIndex / 16) / 16.0; - let maxV = minV + (16 / 256); - - // Flip V - minV = 1 - minV; - maxV = 1 - maxV; - - // Render item - this.addFace(null, EnumBlockFace.NORTH, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV); + addDistortFace(world, face, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV, distortX, distortZ) { + if (face === EnumBlockFace.NORTH) { + this.addBlockCorner(world, face, minX, maxY, minZ, minU, minV); + this.addBlockCorner(world, face, minX + distortX, minY, minZ + distortZ, minU, maxV); + this.addBlockCorner(world, face, maxX + distortX, minY, minZ + distortZ, maxU, maxV); + this.addBlockCorner(world, face, maxX, maxY, minZ, maxU, minV); + } + if (face === EnumBlockFace.SOUTH) { + this.addBlockCorner(world, face, minX, maxY, maxZ, maxU, minV); + this.addBlockCorner(world, face, maxX, maxY, maxZ, minU, minV); + this.addBlockCorner(world, face, maxX + distortX, minY, maxZ + distortZ, minU, maxV); + this.addBlockCorner(world, face, minX + distortX, minY, maxZ + distortZ, maxU, maxV); + } + if (face === EnumBlockFace.WEST) { + this.addBlockCorner(world, face, minX + distortX, minY, maxZ + distortZ, minU, maxV); + this.addBlockCorner(world, face, minX + distortX, minY, minZ + distortZ, maxU, maxV); + this.addBlockCorner(world, face, minX, maxY, minZ, maxU, minV); + this.addBlockCorner(world, face, minX, maxY, maxZ, minU, minV); + } + if (face === EnumBlockFace.EAST) { + this.addBlockCorner(world, face, maxX, maxY, maxZ, maxU, minV); + this.addBlockCorner(world, face, maxX, maxY, minZ, minU, minV); + this.addBlockCorner(world, face, maxX + distortX, minY, minZ + distortZ, minU, maxV); + this.addBlockCorner(world, face, maxX + distortX, minY, maxZ + distortZ, maxU, maxV); + } } renderGuiBlock(group, block, x, y, size) { @@ -266,4 +295,28 @@ window.BlockRenderer = class { mesh.scale.y = size; mesh.scale.z = size; } + + renderGuiItem(block) { + // Vertex mappings + let minX = 0; + let minY = 0; + let minZ = 0; + let maxX = 1; + let maxY = 1; + let maxZ = 1; + + // UV Mapping + let textureIndex = block.getTextureForFace(EnumBlockFace.NORTH); + let minU = (textureIndex % 16) / 16.0; + let maxU = minU + (16 / 256); + let minV = Math.floor(textureIndex / 16) / 16.0; + let maxV = minV + (16 / 256); + + // Flip V + minV = 1 - minV; + maxV = 1 - maxV; + + // Render item + this.addFace(null, EnumBlockFace.NORTH, minX, minY, minZ, maxX, maxY, maxZ, minU, minV, maxU, maxV); + } } \ No newline at end of file diff --git a/src/js/net/minecraft/client/render/gui/ScreenRenderer.js b/src/js/net/minecraft/client/render/gui/ScreenRenderer.js index 58a7247..081cfb5 100644 --- a/src/js/net/minecraft/client/render/gui/ScreenRenderer.js +++ b/src/js/net/minecraft/client/render/gui/ScreenRenderer.js @@ -25,7 +25,9 @@ window.ScreenRenderer = class { this.stack2d.clearRect(0, 0, this.window.width, this.window.height); // Render in-game overlay - this.minecraft.ingameOverlay.render(this.stack2d, mouseX, mouseY, partialTicks); + if (this.minecraft.loadingScreen === null) { + this.minecraft.ingameOverlay.render(this.stack2d, mouseX, mouseY, partialTicks); + } // Render current screen if (!(this.minecraft.currentScreen === null)) { diff --git a/src/js/net/minecraft/client/world/Chunk.js b/src/js/net/minecraft/client/world/Chunk.js index 98724e7..a4f0898 100644 --- a/src/js/net/minecraft/client/world/Chunk.js +++ b/src/js/net/minecraft/client/world/Chunk.js @@ -29,7 +29,7 @@ window.Chunk = class { // Calculate height map for (let x = 0; x < 16; x++) { for (let z = 0; z < 16; z++) { - this.setHeightAt(x, z, 0); // TODO set to 0 to calculate proper lightning + this.setHeightAt(x, z, 0); this.updateHeightMap(x, World.TOTAL_HEIGHT, z); } } @@ -238,19 +238,32 @@ window.Chunk = class { section.setLightAt(sourceType, x, y & 15, z, level); } - setBlockAt(x, y, z, typeId) { + setBlockDataAt(x, y, z, data) { + this.setBlockAt(x, y, z, this.getBlockAt(x, y, z), data); + } + + setBlockAt(x, y, z, typeId, data = 0) { + let section = this.getSection(y >> 4); + let yInSection = y & 15; + let height = this.getHeightAt(x, z); - let prevTypeId = this.getBlockAt(x, y, z); - if (prevTypeId === typeId) { + let prevTypeId = section.getBlockAt(x, yInSection, z); + let prevData = section.getBlockDataAt(x, yInSection, z); + + // Check if block type has changed + if (prevTypeId === typeId && prevData === data) { return false; } - this.getSection(y >> 4).setBlockAt(x, y & 15, z, typeId); + // Update block type and data + section.setBlockAt(x, yInSection, z, typeId); + section.setBlockDataAt(x, yInSection, z, data); if (!this.loaded) { return; } + // Update height map let block = Block.getById(typeId); if (typeId !== 0 && block.isSolid()) { if (y >= height) { @@ -263,11 +276,18 @@ window.Chunk = class { let totalX = this.x * 16 + x; let totalZ = this.z * 16 + z; + // Update light this.world.updateLight(EnumSkyBlock.SKY, totalX, y, totalZ, totalX, y, totalZ); this.world.updateLight(EnumSkyBlock.BLOCK, totalX, y, totalZ, totalX, y, totalZ); + // Notify surrounding blocks this.notifyNeighbors(x, z); - this.setModifiedAllSections(); + + // Handle block abilities + if (typeId !== 0) { + block.onBlockAdded(this.world, totalX, y, totalZ); + } + return true; } @@ -279,6 +299,10 @@ window.Chunk = class { return this.getSection(y >> 4).getBlockAt(x, y & 15, z); } + getBlockDataAt(x, y, z) { + return this.getSection(y >> 4).getBlockDataAt(x, y & 15, z); + } + 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 0e6055c..b366aad 100644 --- a/src/js/net/minecraft/client/world/ChunkSection.js +++ b/src/js/net/minecraft/client/world/ChunkSection.js @@ -23,6 +23,7 @@ window.ChunkSection = class { this.isModified = false; this.blocks = []; + this.blocksData = []; this.blockLight = []; this.skyLight = []; @@ -32,6 +33,7 @@ window.ChunkSection = class { for (let tZ = 0; tZ < ChunkSection.SIZE; tZ++) { let index = tY << 8 | tZ << 4 | tX; this.blocks[index] = 0; + this.blocksData[index] = 0; this.blockLight[index] = 0; this.skyLight[index] = 0; } @@ -77,6 +79,11 @@ window.ChunkSection = class { return this.blocks[index]; } + getBlockDataAt(x, y, z) { + let index = y << 8 | z << 4 | x; + return this.blocksData[index]; + } + setBlockAt(x, y, z, typeId) { let index = y << 8 | z << 4 | x; this.blocks[index] = typeId; @@ -84,6 +91,13 @@ window.ChunkSection = class { this.isModified = true; } + setBlockDataAt(x, y, z, data) { + let index = y << 8 | z << 4 | x; + this.blocksData[index] = data; + + this.isModified = true; + } + setLightAt(sourceType, x, y, z, lightLevel) { let index = y << 8 | z << 4 | x; diff --git a/src/js/net/minecraft/client/world/World.js b/src/js/net/minecraft/client/world/World.js index 9681ae3..2c3da68 100644 --- a/src/js/net/minecraft/client/world/World.js +++ b/src/js/net/minecraft/client/world/World.js @@ -278,11 +278,20 @@ window.World = class { this.onBlockChanged(x, y, z); } + setBlockDataAt(x, y, z, data) { + this.getChunkAt(x >> 4, z >> 4).setBlockDataAt(x & 15, y, z & 15, data); + } + getBlockAt(x, y, z) { let chunkSection = this.getChunkAtBlock(x, y, z); return chunkSection == null ? 0 : chunkSection.getBlockAt(x & 15, y & 15, z & 15); } + getBlockDataAt(x, y, z) { + let chunkSection = this.getChunkAtBlock(x, y, z); + return chunkSection == null ? 0 : chunkSection.getBlockDataAt(x & 15, y & 15, z & 15); + } + getBlockAtFace(x, y, z, face) { return this.getBlockAt(x + face.x, y + face.y, z + face.z); } diff --git a/src/js/net/minecraft/client/world/block/Block.js b/src/js/net/minecraft/client/world/block/Block.js index 4a67817..f4eeb18 100644 --- a/src/js/net/minecraft/client/world/block/Block.js +++ b/src/js/net/minecraft/client/world/block/Block.js @@ -64,6 +64,14 @@ window.Block = class { return this.boundingBox; } + onBlockAdded(world, x, y, z) { + + } + + onBlockPlaced(world, x, y, z, face) { + + } + collisionRayTrace(x, y, z, start, end) { start = start.addVector(-x, -y, -z); end = end.addVector(-x, -y, -z); diff --git a/src/js/net/minecraft/client/world/block/BlockTorch.js b/src/js/net/minecraft/client/world/block/BlockTorch.js index da013ea..0ab0cea 100644 --- a/src/js/net/minecraft/client/world/block/BlockTorch.js +++ b/src/js/net/minecraft/client/world/block/BlockTorch.js @@ -4,6 +4,14 @@ window.BlockTorch = class extends Block { super(id, textureSlotId); this.boundingBox = new BoundingBox(0.4, 0.0, 0.4, 0.6, 0.6, 0.6); + + this.dataFaces = [ + EnumBlockFace.WEST, + EnumBlockFace.EAST, + EnumBlockFace.NORTH, + EnumBlockFace.SOUTH, + EnumBlockFace.BOTTOM, + ] } getLightValue() { @@ -17,4 +25,30 @@ window.BlockTorch = class extends Block { getRenderType() { return BlockRenderType.TORCH; } + + onBlockAdded(world, x, y, z) { + for (let i = this.dataFaces.length - 1; i >= 0; i--) { + let dataFace = this.dataFaces[i]; + + if (world.isSolidBlockAt(x + dataFace.x, y + dataFace.y, z + dataFace.z)) { + world.setBlockDataAt(x, y, z, i + 1); + break; + } + } + } + + onBlockPlaced(world, x, y, z, face) { + let meta = world.getBlockDataAt(x, y, z); + + for (let i in this.dataFaces) { + let dataFace = this.dataFaces[i]; + + if (face === dataFace.opposite() && world.isSolidBlockAt(x + dataFace.x, y + dataFace.y, z + dataFace.z)) { + meta = parseInt(i) + 1; + break; + } + } + + world.getChunkSectionAt(x >> 4, y >> 4, z >> 4).setBlockDataAt(x & 15, y & 15, z & 15, meta); + } } \ No newline at end of file diff --git a/src/js/net/minecraft/util/EnumBlockFace.js b/src/js/net/minecraft/util/EnumBlockFace.js index 4183097..ffb362b 100644 --- a/src/js/net/minecraft/util/EnumBlockFace.js +++ b/src/js/net/minecraft/util/EnumBlockFace.js @@ -22,6 +22,31 @@ window.EnumBlockFace = class { return this.z !== 0; } + opposite() { + if (this === EnumBlockFace.TOP) { + return EnumBlockFace.BOTTOM; + } + if (this === EnumBlockFace.BOTTOM) { + return EnumBlockFace.TOP; + } + + if (this === EnumBlockFace.NORTH) { + return EnumBlockFace.SOUTH; + } + if (this === EnumBlockFace.SOUTH) { + return EnumBlockFace.NORTH; + } + + if (this === EnumBlockFace.EAST) { + return EnumBlockFace.WEST; + } + if (this === EnumBlockFace.WEST) { + return EnumBlockFace.EAST; + } + + return null; + } + static values() { return [ EnumBlockFace.TOP,