improve mojang lightning
This commit is contained in:
@@ -12,7 +12,7 @@ window.GameWindow = class {
|
||||
|
||||
// Stats
|
||||
this.stats = new Stats()
|
||||
this.stats.showPanel(1);
|
||||
this.stats.showPanel(0);
|
||||
wrapper.appendChild(this.stats.dom);
|
||||
|
||||
// Add web renderer canvas to wrapper
|
||||
|
||||
@@ -27,6 +27,10 @@ window.Minecraft = class {
|
||||
}
|
||||
|
||||
init() {
|
||||
// Load spawn chunk
|
||||
this.world.getChunkAt(0, 0);
|
||||
this.player.respawn();
|
||||
|
||||
// Start render loop
|
||||
this.running = true;
|
||||
this.requestNextFrame();
|
||||
|
||||
@@ -42,22 +42,33 @@ window.Player = class {
|
||||
this.prevFovModifier = 0;
|
||||
this.fovModifier = 0;
|
||||
this.timeFovChanged = 0;
|
||||
|
||||
this.resetPos();
|
||||
}
|
||||
|
||||
resetPos() {
|
||||
this.setPos(0, 80, 0);
|
||||
respawn() {
|
||||
let spawnY = this.world.getHeightAt(0, 0);
|
||||
this.setPosition(0, spawnY + 8, 0);
|
||||
}
|
||||
|
||||
setPos(x, y, z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
setPosition(x, y, z) {
|
||||
let width = 0.3;
|
||||
let height = 0.9;
|
||||
this.boundingBox = new BoundingBox(
|
||||
x - width,
|
||||
y - height,
|
||||
z - width,
|
||||
x + width,
|
||||
y + height,
|
||||
z + width
|
||||
);
|
||||
|
||||
let w = 0.3;
|
||||
let h = 0.9;
|
||||
this.boundingBox = new BoundingBox(x - w, y - h, z - w, x + w, y + h, z + w);
|
||||
this.motionX = 0;
|
||||
this.motionY = 0;
|
||||
this.motionZ = 0;
|
||||
|
||||
// Update position
|
||||
this.x = (this.boundingBox.minX + this.boundingBox.maxX) / 2.0;
|
||||
this.y = this.boundingBox.minY;
|
||||
this.z = (this.boundingBox.minZ + this.boundingBox.maxZ) / 2.0;
|
||||
}
|
||||
|
||||
turn(motionX, motionY) {
|
||||
@@ -299,7 +310,7 @@ window.Player = class {
|
||||
let sneaking = false;
|
||||
|
||||
if (Keyboard.isKeyDown("KeyR")) { // R
|
||||
this.resetPos();
|
||||
this.respawn();
|
||||
}
|
||||
if (Keyboard.isKeyDown("KeyW")) { // W
|
||||
moveForward++;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
window.BlockRenderer = class {
|
||||
|
||||
static CLASSIC_LIGHTNING = true;
|
||||
static CLASSIC_LIGHTNING = false;
|
||||
|
||||
constructor(worldRenderer) {
|
||||
this.worldRenderer = worldRenderer;
|
||||
|
||||
@@ -26,27 +26,22 @@ window.Chunk = class {
|
||||
}
|
||||
|
||||
generateSkylightMap() {
|
||||
let highest = World.TOTAL_HEIGHT;
|
||||
// Calculate height map
|
||||
for (let x = 0; x < 16; x++) {
|
||||
for (let z = 0; z < 16; z++) {
|
||||
this.heightMap[z << 4 | x] = -1;
|
||||
|
||||
this.setHeightAt(x, z, 0); // TODO set to 0 to calculate proper lightning
|
||||
this.updateHeightMap(x, World.TOTAL_HEIGHT, z);
|
||||
|
||||
if ((this.heightMap[z << 4 | x] & 0xff) < highest) {
|
||||
highest = this.heightMap[z << 4 | x] & 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.highestY = highest;
|
||||
for (let k = 0; k < 16; k++) {
|
||||
for (let i1 = 0; i1 < 16; i1++) {
|
||||
this.notifyNeighbors(k, i1);
|
||||
// Update light of neighbor blocks
|
||||
for (let x = 0; x < 16; x++) {
|
||||
for (let z = 0; z < 16; z++) {
|
||||
this.notifyNeighbors(x, z);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Rebuild all sections
|
||||
this.setModifiedAllSections();
|
||||
}
|
||||
|
||||
@@ -76,57 +71,34 @@ window.Chunk = class {
|
||||
}
|
||||
|
||||
updateHeightMap(relX, y, relZ) {
|
||||
let currentHighestY = this.heightMap[relZ << 4 | relX] & 0xff;
|
||||
let currentHighestY = this.getHeightAt(relX, relZ);
|
||||
let highestY = currentHighestY;
|
||||
if (y > currentHighestY) {
|
||||
highestY = y;
|
||||
}
|
||||
while (highestY > 0) {
|
||||
let typeId = this.getBlockAt(relX, highestY, relZ);
|
||||
let block = Block.getById(typeId);
|
||||
|
||||
if (typeId !== 0 && block.getOpacity() !== 0) {
|
||||
break;
|
||||
}
|
||||
highestY = this.calculateHeightAt(relX, relZ, highestY);
|
||||
|
||||
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;
|
||||
}
|
||||
this.setHeightAt(relX, relZ, highestY);
|
||||
|
||||
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);
|
||||
for (let hy = highestY; hy < currentHighestY; hy++) {
|
||||
this.setLightAt(EnumSkyBlock.SKY, relX, hy, 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) {
|
||||
@@ -147,15 +119,7 @@ window.Chunk = class {
|
||||
this.setLightAt(EnumSkyBlock.SKY, relX, highestY, relZ, lightLevel);
|
||||
}
|
||||
|
||||
while (highestY > 0) {
|
||||
let typeId = this.getBlockID(relX, highestY - 1, relZ);
|
||||
let block = Block.getById(typeId);
|
||||
|
||||
if (typeId !== 0 && block.isSolid()) {
|
||||
break;
|
||||
}
|
||||
highestY--;
|
||||
}
|
||||
highestY = this.calculateHeightAt(relX, relZ, highestY);
|
||||
|
||||
if (highestY !== prevHeight) {
|
||||
this.world.updateLight(EnumSkyBlock.SKY, x - 1, highestY, z - 1, x + 1, prevHeight, z + 1);
|
||||
@@ -163,34 +127,76 @@ window.Chunk = class {
|
||||
this.setModifiedAllSections();
|
||||
}
|
||||
|
||||
calculateHeightAt(x, z, startY) {
|
||||
let y = startY;
|
||||
while (y > 0) {
|
||||
let typeId = this.getBlockAt(x, y - 1, z);
|
||||
let block = Block.getById(typeId);
|
||||
let opacity = typeId === 0 ? 0 : block.getOpacity();
|
||||
|
||||
if (opacity !== 0) {
|
||||
break;
|
||||
}
|
||||
y--;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
updateHeightMapAt(x, z) {
|
||||
let y = this.calculateHeightAt(x, z, World.TOTAL_HEIGHT);
|
||||
this.setHeightAt(x, z, y);
|
||||
}
|
||||
|
||||
setHeightAt(x, z, height) {
|
||||
this.heightMap[z << 4 | x] = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the highest solid block or above
|
||||
*/
|
||||
isHighestBlock(x, y, z) {
|
||||
return y >= this.getHighestBlockAt(x, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is above the highest solid block
|
||||
*/
|
||||
isAboveGround(x, y, z) {
|
||||
return y >= this.getHeightAt(x, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first non-solid block
|
||||
*/
|
||||
getHeightAt(x, z) {
|
||||
return this.heightMap[z << 4 | x];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the highest solid block
|
||||
*/
|
||||
getHighestBlockAt(x, z) {
|
||||
return this.getHeightAt(x, z) - 1;
|
||||
}
|
||||
|
||||
setLightAt(sourceType, x, y, z, level) {
|
||||
this.getSection(y >> 4).setLightAt(sourceType, x, y & 15, z, level);
|
||||
let section = this.getSection(y >> 4);
|
||||
section.setLightAt(sourceType, x, y & 15, z, level);
|
||||
}
|
||||
|
||||
setBlockAt(x, y, z, typeId) {
|
||||
let byte0 = typeId;
|
||||
let height = this.heightMap[z << 4 | x] & 0xff;
|
||||
|
||||
let height = this.getHeightAt(x, z);
|
||||
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);
|
||||
this.getSection(y >> 4).setBlockAt(x, y & 15, z, typeId);
|
||||
|
||||
if (!this.loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
//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) {
|
||||
|
||||
let block = Block.getById(typeId);
|
||||
if (typeId !== 0 && block.isSolid()) {
|
||||
if (y >= height) {
|
||||
@@ -200,18 +206,13 @@ window.Chunk = class {
|
||||
this.updateHeightMap(x, y, z);
|
||||
}
|
||||
|
||||
let totalX = this.x * 16 + x;
|
||||
let totalZ = this.z * 16 + 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.setModifiedAllSections();
|
||||
return true;
|
||||
}
|
||||
@@ -224,14 +225,6 @@ window.Chunk = class {
|
||||
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;
|
||||
}
|
||||
|
||||
getSection(y) {
|
||||
return this.sections[y];
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
window.World = class {
|
||||
|
||||
static TOTAL_HEIGHT = ChunkSection.SIZE * 16 - 1;
|
||||
static TOTAL_HEIGHT = ChunkSection.SIZE * 8 - 1; // ChunkSection.SIZE * 16 - 1;
|
||||
|
||||
constructor(minecraft) {
|
||||
this.minecrat = minecraft;
|
||||
|
||||
this.group = new THREE.Object3D();
|
||||
this.group.matrixAutoUpdate = false;
|
||||
|
||||
this.chunks = new Map();
|
||||
this.lightUpdateQueue = [];
|
||||
|
||||
// Load world
|
||||
this.generator = new WorldGenerator(this, Date.now() % 100000);
|
||||
|
||||
this.lightUpdateQueue = [];
|
||||
}
|
||||
|
||||
onTick() {
|
||||
@@ -81,14 +81,35 @@ window.World = class {
|
||||
}
|
||||
|
||||
updateLights() {
|
||||
// Update lights in queue
|
||||
let i = 5000;
|
||||
while (this.lightUpdateQueue.length > 0) {
|
||||
if (i <= 0) {
|
||||
return true;
|
||||
let scope = this;
|
||||
|
||||
if (this.lightUpdateQueue.length > 10) {
|
||||
// Update lights async
|
||||
setTimeout(function () {
|
||||
// Update lights in queue
|
||||
let i = 5000;
|
||||
while (scope.lightUpdateQueue.length > 0) {
|
||||
if (i <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
let meta = scope.lightUpdateQueue.shift();
|
||||
meta.updateBlockLightning(scope);
|
||||
i--;
|
||||
}
|
||||
}, 0);
|
||||
} else {
|
||||
// Update lights in queue
|
||||
let i = 10;
|
||||
while (scope.lightUpdateQueue.length > 0) {
|
||||
if (i <= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let meta = scope.lightUpdateQueue.shift();
|
||||
meta.updateBlockLightning(scope);
|
||||
i--;
|
||||
}
|
||||
this.lightUpdateQueue.shift().updateBlockLightning(this);
|
||||
i--;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -116,8 +137,11 @@ window.World = class {
|
||||
}
|
||||
}
|
||||
|
||||
// Add light update region to queue
|
||||
this.lightUpdateQueue.push(new MetadataChunkBlock(sourceType, x1, y1, z1, x2, y2, z2));
|
||||
if (this.lightUpdateQueue.length > 0x186a0) {
|
||||
|
||||
// Max light updates in queue
|
||||
if (this.lightUpdateQueue.length > 100000) {
|
||||
this.lightUpdateQueue = [];
|
||||
}
|
||||
}
|
||||
@@ -141,7 +165,7 @@ window.World = class {
|
||||
return;
|
||||
}
|
||||
if (sourceType === EnumSkyBlock.SKY) {
|
||||
if (this.isHighestBlock(x, y, z)) {
|
||||
if (this.isAboveGround(x, y, z)) {
|
||||
level = 15;
|
||||
}
|
||||
} else if (sourceType === EnumSkyBlock.BLOCK) {
|
||||
@@ -155,17 +179,40 @@ window.World = class {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first non-solid block
|
||||
*/
|
||||
getHeightAt(x, z) {
|
||||
if (!this.chunkExists(x >> 4, z >> 4)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.getChunkAt(x >> 4, z >> 4).getHeightAt(x & 15, z & 15);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the highest solid block
|
||||
*/
|
||||
getHighestBlockAt(x, z) {
|
||||
if (!this.chunkExists(x >> 4, z >> 4)) {
|
||||
return 0;
|
||||
}
|
||||
return this.getChunkAt(x >> 4, z >> 4).getHighestBlockAt(x & 15, z & 15);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the highest solid block or above
|
||||
*/
|
||||
isHighestBlock(x, y, z) {
|
||||
let chunk = this.getChunkAt(x >> 4, z >> 4)
|
||||
return y >= chunk.getHeightAt(x & 15, z & 15);
|
||||
return chunk.isHighestBlock(x & 15, y, z & 15);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is above the highest solid block
|
||||
*/
|
||||
isAboveGround(x, y, z) {
|
||||
let chunk = this.getChunkAt(x >> 4, z >> 4)
|
||||
return chunk.isAboveGround(x & 15, y, z & 15);
|
||||
}
|
||||
|
||||
getTotalLightAt(x, y, z) {
|
||||
|
||||
@@ -5,7 +5,7 @@ window.BlockWater = class extends Block {
|
||||
}
|
||||
|
||||
getOpacity() {
|
||||
return 0.93;
|
||||
return 0.01;
|
||||
}
|
||||
|
||||
isSolid() {
|
||||
|
||||
@@ -117,7 +117,7 @@ window.WorldGenerator = class {
|
||||
if (perlin > 0 && this.random.nextInt(2) === 0) {
|
||||
|
||||
// Get the highest block at this position
|
||||
let highestY = this.world.getHeightAt(absoluteX, absoluteZ);
|
||||
let highestY = this.world.getHighestBlockAt(absoluteX, absoluteZ);
|
||||
|
||||
// Don't place a tree if there is no grass
|
||||
if (this.world.getBlockAt(absoluteX, highestY, absoluteZ) === Block.GRASS.getId()
|
||||
|
||||
@@ -42,7 +42,7 @@ window.MetadataChunkBlock = class {
|
||||
let level = 0;
|
||||
|
||||
if (this.type === EnumSkyBlock.SKY) {
|
||||
if (world.isHighestBlock(x, y, z)) {
|
||||
if (world.isAboveGround(x, y, z)) {
|
||||
level = 15;
|
||||
}
|
||||
} else if (this.type === EnumSkyBlock.BLOCK) {
|
||||
|
||||
Reference in New Issue
Block a user