implement mojang lightning of a1.2.6
This commit is contained in:
@@ -12,7 +12,7 @@ window.GameWindow = class {
|
||||
|
||||
// Stats
|
||||
this.stats = new Stats()
|
||||
this.stats.showPanel(0);
|
||||
this.stats.showPanel(1);
|
||||
wrapper.appendChild(this.stats.dom);
|
||||
|
||||
// Add web renderer canvas to wrapper
|
||||
|
||||
@@ -81,6 +81,8 @@ window.Minecraft = class {
|
||||
|
||||
// Render the game
|
||||
this.worldRenderer.render(partialTicks);
|
||||
|
||||
while (this.world.updateLights()) ;
|
||||
}
|
||||
|
||||
onTick() {
|
||||
@@ -99,7 +101,6 @@ window.Minecraft = class {
|
||||
if (button === 0) {
|
||||
if (hitResult != null) {
|
||||
this.world.setBlockAt(hitResult.x, hitResult.y, hitResult.z, 0);
|
||||
this.world.updateBlockLightAt(hitResult.x, hitResult.y, hitResult.z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +126,6 @@ window.Minecraft = class {
|
||||
// Don't place blocks if the player is standing there
|
||||
if (!placedBoundingBox.intersects(this.player.boundingBox)) {
|
||||
this.world.setBlockAt(x, y, z, this.pickedBlock);
|
||||
this.world.updateBlockLightAt(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
window.BlockRenderer = class {
|
||||
|
||||
static CLASSIC_LIGHTNING = false;
|
||||
static CLASSIC_LIGHTNING = true;
|
||||
|
||||
constructor(worldRenderer) {
|
||||
this.worldRenderer = worldRenderer;
|
||||
@@ -125,7 +125,7 @@ window.BlockRenderer = class {
|
||||
if (typeId === 0 || Block.getById(typeId).isTransparent()) {
|
||||
|
||||
// Sum up the light levels
|
||||
totalLightLevel += world.getLightAt(x + offsetX, y + offsetY, z + offsetZ);
|
||||
totalLightLevel += world.getTotalLightAt(x + offsetX, y + offsetY, z + offsetZ);
|
||||
totalBlocks++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,8 +103,7 @@ window.WorldRenderer = class {
|
||||
renderChunks(cameraChunkX, cameraChunkZ) {
|
||||
let world = this.minecraft.world;
|
||||
|
||||
for (let i in world.chunks) {
|
||||
let chunk = world.chunks[i];
|
||||
for (let [index, chunk] of world.chunks) {
|
||||
|
||||
let distanceX = Math.abs(cameraChunkX - chunk.x);
|
||||
let distanceZ = Math.abs(cameraChunkZ - chunk.z);
|
||||
|
||||
@@ -18,10 +18,141 @@ window.Chunk = class {
|
||||
this.sections[y] = section;
|
||||
this.group.add(section.group);
|
||||
}
|
||||
|
||||
// Create height map
|
||||
this.heightMap = [];
|
||||
}
|
||||
|
||||
setBlockAt(x, y, z, typeId) {
|
||||
this.getSection(y >> 4).setBlockAt(x, y & 15, z, typeId);
|
||||
let section = this.getSection(y >> 4);
|
||||
let prevTypeId = section.getBlockAt(x, y & 15, z);
|
||||
if (prevTypeId === typeId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update block type id
|
||||
section.setBlockAt(x, y & 15, z, typeId);
|
||||
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
|
||||
// Notify neighbors
|
||||
//this.notifyNeighbors(x, z);
|
||||
}
|
||||
|
||||
notifyNeighbors(x, z) {
|
||||
let height = this.getHeightAt(x, z);
|
||||
let totalX = this.x * 16 + x;
|
||||
let totalZ = this.z * 16 + z;
|
||||
|
||||
this.updateSkyLight(totalX - 1, totalZ, height);
|
||||
this.updateSkyLight(totalX + 1, totalZ, height);
|
||||
this.updateSkyLight(totalX, totalZ - 1, height);
|
||||
this.updateSkyLight(totalX, totalZ + 1, height);
|
||||
}
|
||||
|
||||
updateSkyLight(x, z, y) {
|
||||
let height = this.world.getHeightAt(x, z);
|
||||
if (height > y) {
|
||||
this.world.updateLight(EnumSkyBlock.SKY, x, y, z, x, height, z);
|
||||
} else if (height < y) {
|
||||
this.world.updateLight(EnumSkyBlock.SKY, x, height, z, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
getBlockAt(x, y, z) {
|
||||
return this.getSection(y >> 4).getBlockAt(x, y & 15, z);
|
||||
}
|
||||
|
||||
isHighestBlock(x, y, z) {
|
||||
return y >= (this.heightMap[z << 4 | x] & 0xff);
|
||||
}
|
||||
|
||||
getHeightAt(x, z) {
|
||||
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) {
|
||||
|
||||
@@ -24,15 +24,16 @@ window.ChunkSection = class {
|
||||
|
||||
this.blocks = [];
|
||||
this.blockLight = [];
|
||||
this.skyLight = [];
|
||||
|
||||
// Fill chunk with air and light
|
||||
for (let lightX = 0; lightX < ChunkSection.SIZE; lightX++) {
|
||||
for (let lightY = 0; lightY < ChunkSection.SIZE; lightY++) {
|
||||
for (let lightZ = 0; lightZ < ChunkSection.SIZE; lightZ++) {
|
||||
let index = lightY << 8 | lightZ << 4 | lightX;
|
||||
|
||||
for (let tX = 0; tX < ChunkSection.SIZE; tX++) {
|
||||
for (let tY = 0; tY < ChunkSection.SIZE; tY++) {
|
||||
for (let tZ = 0; tZ < ChunkSection.SIZE; tZ++) {
|
||||
let index = tY << 8 | tZ << 4 | tX;
|
||||
this.blocks[index] = 0;
|
||||
this.blockLight[index] = 15;
|
||||
this.blockLight[index] = 0;
|
||||
this.skyLight[index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,14 +82,30 @@ window.ChunkSection = class {
|
||||
this.blocks[index] = typeId;
|
||||
}
|
||||
|
||||
setLightAt(x, y, z, lightLevel) {
|
||||
setLightAt(sourceType, x, y, z, lightLevel) {
|
||||
let index = y << 8 | z << 4 | x;
|
||||
this.blockLight[index] = lightLevel;
|
||||
}
|
||||
|
||||
getLightAt(x, y, z) {
|
||||
getTotalLightAt(x, y, z) {
|
||||
let index = y << 8 | z << 4 | x;
|
||||
return this.blockLight[index];
|
||||
let skyLight = this.skyLight[index];
|
||||
let blockLight = this.blockLight[index];
|
||||
if (blockLight > skyLight) {
|
||||
skyLight = blockLight;
|
||||
}
|
||||
return skyLight;
|
||||
}
|
||||
|
||||
getLightAt(sourceType, x, y, z) {
|
||||
let index = y << 8 | z << 4 | x;
|
||||
if (sourceType === EnumSkyBlock.SKY) {
|
||||
return this.skyLight[index];
|
||||
}
|
||||
if (sourceType === EnumSkyBlock.Block) {
|
||||
return this.blockLight[index];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
|
||||
@@ -5,32 +5,19 @@ window.World = class {
|
||||
constructor() {
|
||||
this.group = new THREE.Object3D();
|
||||
this.group.matrixAutoUpdate = false;
|
||||
this.chunks = [];
|
||||
this.chunks = new Map();
|
||||
|
||||
// Load world
|
||||
this.generator = new WorldGenerator(this, Date.now() % 100000);
|
||||
|
||||
this.lightUpdateQueue = [];
|
||||
|
||||
this.lightUpdateProcesses = 0;
|
||||
this.lightUpdates = 0;
|
||||
}
|
||||
|
||||
onTick() {
|
||||
// Handle 128 light updates per tick
|
||||
for (let i = 0; i < 128; i++) {
|
||||
|
||||
// Light updates
|
||||
if (this.lightUpdateQueue.length !== 0) {
|
||||
|
||||
// Get next position to update
|
||||
let positionIndex = this.lightUpdateQueue.shift();
|
||||
if (positionIndex != null) {
|
||||
let z = positionIndex >> 16;
|
||||
let x = positionIndex - (z << 16);
|
||||
this.updateBlockLightsAtXZ(x, z);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadChunk(chunk) {
|
||||
@@ -71,6 +58,113 @@ window.World = class {
|
||||
return boundingBoxList;
|
||||
}
|
||||
|
||||
updateLight(sourceType, x1, y1, z1, x2, y2, z2, notifyNeighbor = true) {
|
||||
if (this.lightUpdates >= 50) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lightUpdates++;
|
||||
|
||||
let size = this.lightUpdateQueue.length;
|
||||
|
||||
if (notifyNeighbor) {
|
||||
let max = 4;
|
||||
if (max > size) {
|
||||
max = size;
|
||||
}
|
||||
|
||||
for (let i = 0; i < max; i++) {
|
||||
let meta = this.lightUpdateQueue[size - 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) {
|
||||
if (sourceType === EnumSkyBlock.SKY) {
|
||||
if (this.isHighestBlock(x, y, z)) {
|
||||
lightLevel = 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;
|
||||
}
|
||||
}
|
||||
if (this.getSavedLightValue(sourceType, x, y, z) !== lightLevel) {
|
||||
this.updateLight(sourceType, x, y, z, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
updateLights() {
|
||||
if (this.lightUpdateProcesses >= 50) {
|
||||
return false;
|
||||
}
|
||||
this.lightUpdateProcesses++;
|
||||
|
||||
// Update lights in queue
|
||||
let i = 5000;
|
||||
while (this.lightUpdateQueue.length > 0) {
|
||||
if (i <= 0) {
|
||||
return true;
|
||||
}
|
||||
this.lightUpdateQueue.shift().updateBlockLightning(this);
|
||||
i--;
|
||||
}
|
||||
|
||||
this.lightUpdateProcesses--;
|
||||
return false;
|
||||
}
|
||||
|
||||
getHeightAt(x, z) {
|
||||
return this.getChunkAt(x >> 4, z >> 4).getHeightAt(x & 15, z & 15);
|
||||
}
|
||||
|
||||
isHighestBlock(x, y, z) {
|
||||
let chunk = this.getChunkAt(x >> 4, z >> 4)
|
||||
return y >= chunk.getHeightAt(x & 15, z & 15);
|
||||
}
|
||||
|
||||
getTotalLightAt(x, y, z) {
|
||||
if (y < 0) {
|
||||
return 15;
|
||||
}
|
||||
|
||||
let section = this.getChunkSectionAt(x >> 4, y >> 4, z >> 4)
|
||||
return section.getTotalLightAt(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
getSavedLightValue(sourceType, x, y, z) {
|
||||
if (y < 0) {
|
||||
return 15;
|
||||
}
|
||||
|
||||
let section = this.getChunkSectionAt(x >> 4, y >> 4, z >> 4)
|
||||
return section.getLightAt(sourceType, x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
setLightAt(sourceType, x, y, z, lightLevel) {
|
||||
if (y < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let section = this.getChunkSectionAt(x >> 4, y >> 4, z >> 4)
|
||||
section.setLightAt(sourceType, x & 15, y & 15, z & 15, lightLevel);
|
||||
}
|
||||
|
||||
isSolidBlockAt(x, y, z) {
|
||||
let typeId = this.getBlockAt(x, y, z);
|
||||
return typeId !== 0 && Block.getById(typeId).isSolid();
|
||||
@@ -82,11 +176,10 @@ window.World = class {
|
||||
}
|
||||
|
||||
setBlockAt(x, y, z, type) {
|
||||
let chunkSection = this.getChunkAtBlock(x, y, z);
|
||||
if (chunkSection != null) {
|
||||
chunkSection.setBlockAt(x & 15, y & 15, z & 15, type);
|
||||
}
|
||||
let chunk = this.getChunkAt(x >> 4, z >> 4);
|
||||
chunk.setBlockAt(x & 15, y, z & 15, type);
|
||||
|
||||
// Rebuild chunk
|
||||
this.onBlockChanged(x, y, z);
|
||||
}
|
||||
|
||||
@@ -105,127 +198,14 @@ window.World = class {
|
||||
|
||||
getChunkAt(x, z) {
|
||||
let index = x + (z << 16);
|
||||
let chunk = this.chunks[index];
|
||||
let chunk = this.chunks.get(index);
|
||||
if (typeof chunk === 'undefined') {
|
||||
this.chunks[index] = chunk = new Chunk(this, x, z);
|
||||
this.chunks.set(index, chunk = new Chunk(this, x, z));
|
||||
this.group.add(chunk.group);
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
getHighestBlockYAt(x, z) {
|
||||
for (let y = World.TOTAL_HEIGHT; y > 0; y--) {
|
||||
if (this.isSolidBlockAt(x, y, z)) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
updateBlockLightAt(x, y, z) {
|
||||
// Calculate brightness for target block
|
||||
let lightLevel = this.isHighestBlockAt(x, y, z) ? 15 : this.calculateLightAt(x, y, z);
|
||||
|
||||
// Update target block light
|
||||
this.getChunkAtBlock(x, y, z).setLightAt(x & 15, y & 15, z & 15, lightLevel);
|
||||
|
||||
// Update block lights below the target block and the surrounding blocks
|
||||
for (let offsetX = -1; offsetX <= 1; offsetX++) {
|
||||
for (let offsetZ = -1; offsetZ <= 1; offsetZ++) {
|
||||
this.updateBlockLightsAtXZ(x + offsetX, z + offsetZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateBlockLightsAtXZ(x, z) {
|
||||
let lightChanged = false;
|
||||
let skyLevel = 15;
|
||||
|
||||
// Scan from the top to the bottom
|
||||
for (let y = World.TOTAL_HEIGHT; y >= 0; y--) {
|
||||
if (!this.isTransparentBlockAt(x, y, z)) {
|
||||
// Sun is blocked because of solid block
|
||||
skyLevel = 0;
|
||||
} else {
|
||||
// Get opacity of this block
|
||||
let typeId = this.getBlockAt(x, y, z);
|
||||
let translucence = typeId === 0 ? 1.0 : 1.0 - Block.getById(typeId).getOpacity();
|
||||
|
||||
// Decrease strength of the skylight by the opacity of the block
|
||||
skyLevel *= translucence;
|
||||
|
||||
// Get previous block light
|
||||
let prevBlockLight = this.getLightAt(x, y, z);
|
||||
|
||||
// Combine skylight with the calculated block light and decrease strength by the opacity of the block
|
||||
let blockLight = Math.floor(Math.max(skyLevel, this.calculateLightAt(x, y, z)) * translucence);
|
||||
|
||||
// Did one of the light change inside of the range?
|
||||
if (prevBlockLight !== blockLight) {
|
||||
lightChanged = true;
|
||||
}
|
||||
|
||||
// Apply the new light to the block
|
||||
this.setLightAt(x, y, z, blockLight);
|
||||
}
|
||||
}
|
||||
|
||||
// Chain reaction, update next affected blocks
|
||||
if (lightChanged && this.lightUpdateQueue.length < 512) {
|
||||
for (let offsetX = -1; offsetX <= 1; offsetX++) {
|
||||
for (let offsetZ = -1; offsetZ <= 1; offsetZ++) {
|
||||
let positionIndex = (x + offsetX) + ((z + offsetZ) << 16);
|
||||
|
||||
// Add block range to update queue
|
||||
if (!this.lightUpdateQueue.includes(positionIndex)) {
|
||||
this.lightUpdateQueue.push(positionIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setLightAt(x, y, z, light) {
|
||||
let chunkSection = this.getChunkAtBlock(x, y, z);
|
||||
if (chunkSection != null) {
|
||||
chunkSection.setLightAt(x & 15, y & 15, z & 15, light);
|
||||
chunkSection.queueForRebuild();
|
||||
}
|
||||
}
|
||||
|
||||
getLightAt(x, y, z) {
|
||||
let chunkSection = this.getChunkAtBlock(x, y, z);
|
||||
return chunkSection == null ? 15 : chunkSection.getLightAt(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
isHighestBlockAt(x, y, z) {
|
||||
for (let i = y + 1; i < World.TOTAL_HEIGHT; i++) {
|
||||
if (this.isSolidBlockAt(x, i, z)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
calculateLightAt(x, y, z) {
|
||||
let maxBrightness = 0;
|
||||
|
||||
// Get maximal brightness of surround blocks
|
||||
let values = EnumBlockFace.values();
|
||||
for (let i in values) {
|
||||
let face = values[i];
|
||||
|
||||
if (this.isTransparentBlockAt(x + face.x, y + face.y, z + face.z)) {
|
||||
let brightness = this.getLightAt(x + face.x, y + face.y, z + face.z);
|
||||
|
||||
maxBrightness = Math.max(maxBrightness, brightness);
|
||||
}
|
||||
}
|
||||
|
||||
// Decrease maximum brightness by 6%
|
||||
return Math.max(0, maxBrightness - 1);
|
||||
}
|
||||
|
||||
onBlockChanged(x, y, z) {
|
||||
this.queueForRebuildInRegion(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
window.Block = class {
|
||||
|
||||
static blocks = [];
|
||||
static blocks = new Map();
|
||||
|
||||
static create() {
|
||||
Block.STONE = new BlockStone(1, 0);
|
||||
@@ -19,7 +19,7 @@ window.Block = class {
|
||||
this.boundingBox = new BoundingBox(0.0, 0.0, 0.0, 1.0, 1.0, 1.0);
|
||||
|
||||
// Register block
|
||||
Block.blocks[id] = this;
|
||||
Block.blocks.set(id, this);
|
||||
}
|
||||
|
||||
getId() {
|
||||
@@ -39,6 +39,10 @@ window.Block = class {
|
||||
return typeId === 0 || Block.getById(typeId).isTransparent();
|
||||
}
|
||||
|
||||
getLightValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
isSolid() {
|
||||
return true;
|
||||
}
|
||||
@@ -167,7 +171,7 @@ window.Block = class {
|
||||
}
|
||||
|
||||
static getById(typeId) {
|
||||
return Block.blocks[typeId];
|
||||
return Block.blocks.get(typeId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -116,8 +116,8 @@ window.WorldGenerator = class {
|
||||
let perlin = this.forestNoise.perlin(absoluteX * 10, absoluteZ * 10);
|
||||
if (perlin > 0 && this.random.nextInt(2) === 0) {
|
||||
|
||||
// Get highest block at this position
|
||||
let highestY = this.world.getHighestBlockYAt(absoluteX, absoluteZ);
|
||||
// Get the highest block at this position
|
||||
let highestY = this.world.getHeightAt(absoluteX, absoluteZ);
|
||||
|
||||
// Don't place a tree if there is no grass
|
||||
if (this.world.getBlockAt(absoluteX, highestY, absoluteZ) === Block.GRASS.getId()
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
window.EnumSkyBlock = class {
|
||||
static SKY = 0;
|
||||
static BLOCK = 1;
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
window.MetadataChunkBlock = class {
|
||||
|
||||
constructor(type, x1, y1, z1, x2, y2, z2) {
|
||||
this.type = type;
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.z1 = z1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
this.z2 = z2;
|
||||
}
|
||||
|
||||
updateBlockLightning(world) {
|
||||
for (let x = this.x1; x <= this.x2; x++) {
|
||||
for (let z = this.z1; z <= this.z2; z++) {
|
||||
for (let y = this.y1; y <= this.y2; y++) {
|
||||
|
||||
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 = typeId === 0 ? 0 : (block.getOpacity() * 255);
|
||||
if (opacity === 0) {
|
||||
opacity = 1;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
if (opacity >= 15 && level === 0) {
|
||||
newLevel = 0;
|
||||
} else {
|
||||
let x1Level = world.getSavedLightValue(this.type, x - 1, y, z);
|
||||
let x2Level = world.getSavedLightValue(this.type, x + 1, y, z);
|
||||
let bottomLevel = world.getSavedLightValue(this.type, x, y - 1, z);
|
||||
let topLevel = world.getSavedLightValue(this.type, x, y + 1, z);
|
||||
let z1Level = world.getSavedLightValue(this.type, x, y, z - 1);
|
||||
let z2Level = world.getSavedLightValue(this.type, x, y, z + 1);
|
||||
|
||||
newLevel = x1Level;
|
||||
|
||||
if (x2Level > newLevel) {
|
||||
newLevel = x2Level;
|
||||
}
|
||||
if (bottomLevel > newLevel) {
|
||||
newLevel = bottomLevel;
|
||||
}
|
||||
if (topLevel > newLevel) {
|
||||
newLevel = topLevel;
|
||||
}
|
||||
if (z1Level > newLevel) {
|
||||
newLevel = z1Level;
|
||||
}
|
||||
if (z2Level > newLevel) {
|
||||
newLevel = z2Level;
|
||||
}
|
||||
|
||||
newLevel -= opacity;
|
||||
|
||||
if (newLevel < 0) {
|
||||
newLevel = 0;
|
||||
}
|
||||
if (level > newLevel) {
|
||||
newLevel = level;
|
||||
}
|
||||
}
|
||||
|
||||
if (savedLightValue === newLevel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
world.setLightAt(this.type, x, y, z, newLevel);
|
||||
|
||||
let decreasedLevel = newLevel - 1;
|
||||
if (decreasedLevel < 0) {
|
||||
decreasedLevel = 0;
|
||||
}
|
||||
|
||||
world.neighborLightPropagationChanged(this.type, x - 1, y, z, decreasedLevel);
|
||||
world.neighborLightPropagationChanged(this.type, x, y - 1, z, decreasedLevel);
|
||||
world.neighborLightPropagationChanged(this.type, x, y, z - 1, decreasedLevel);
|
||||
|
||||
if (x + 1 >= this.x2) {
|
||||
world.neighborLightPropagationChanged(this.type, x + 1, y, z, decreasedLevel);
|
||||
}
|
||||
if (y + 1 >= this.y2) {
|
||||
world.neighborLightPropagationChanged(this.type, x, y + 1, z, decreasedLevel);
|
||||
}
|
||||
if (z + 1 >= this.z2) {
|
||||
world.neighborLightPropagationChanged(this.type, x, y, z + 1, decreasedLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isOutsideOf(x1, y1, z1, x2, y2, z2) {
|
||||
if (x1 >= this.x1 && y1 >= this.y1 && z1 >= this.z1 && x2 <= this.x2 && y2 <= this.y2 && z2 <= this.z2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let radius = 1;
|
||||
if (x1 >= this.x1 - radius
|
||||
&& y1 >= this.y1 - radius
|
||||
&& z1 >= this.z1 - radius
|
||||
&& x2 <= this.x2 + radius
|
||||
&& y2 <= this.y2 + radius
|
||||
&& z2 <= this.z2 + radius) {
|
||||
|
||||
let distanceX = this.x2 - this.x1;
|
||||
let distanceY = this.y2 - this.y1;
|
||||
let distanceZ = this.z2 - this.z1;
|
||||
|
||||
if (x1 > this.x1) {
|
||||
x1 = this.x1;
|
||||
}
|
||||
if (y1 > this.y1) {
|
||||
y1 = this.y1;
|
||||
}
|
||||
if (z1 > this.z1) {
|
||||
z1 = this.z1;
|
||||
}
|
||||
if (x2 < this.x2) {
|
||||
x2 = this.x2;
|
||||
}
|
||||
if (y2 < this.y2) {
|
||||
y2 = this.y2;
|
||||
}
|
||||
if (z2 < this.z2) {
|
||||
z2 = this.z2;
|
||||
}
|
||||
|
||||
let newDistanceX = x2 - x1;
|
||||
let newDistanceY = y2 - y1;
|
||||
let newDistanceZ = z2 - z1;
|
||||
|
||||
let size = distanceX * distanceY * distanceZ;
|
||||
let newSize = newDistanceX * newDistanceY * newDistanceZ;
|
||||
|
||||
if (newSize - size <= 2) {
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.z1 = z1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
this.z2 = z2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -51,6 +51,9 @@ loadScripts([
|
||||
"src/js/net/minecraft/util/EnumBlockFace.js",
|
||||
"src/js/net/minecraft/util/Timer.js",
|
||||
"src/js/net/minecraft/util/Random.js",
|
||||
"src/js/net/minecraft/util/EnumBlockFace.js",
|
||||
"src/js/net/minecraft/util/EnumSkyBlock.js",
|
||||
"src/js/net/minecraft/util/MetadataChunkBlock.js",
|
||||
"src/js/net/minecraft/util/Vector3.js",
|
||||
"src/js/net/minecraft/util/MovingObjectPosition.js",
|
||||
"src/js/net/minecraft/util/MathHelper.js",
|
||||
|
||||
Reference in New Issue
Block a user