diff --git a/src/js/net/minecraft/client/GameWindow.js b/src/js/net/minecraft/client/GameWindow.js index 92b2cd8..aaff7f4 100644 --- a/src/js/net/minecraft/client/GameWindow.js +++ b/src/js/net/minecraft/client/GameWindow.js @@ -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 diff --git a/src/js/net/minecraft/client/Minecraft.js b/src/js/net/minecraft/client/Minecraft.js index 92a31f0..7fb2f03 100644 --- a/src/js/net/minecraft/client/Minecraft.js +++ b/src/js/net/minecraft/client/Minecraft.js @@ -11,6 +11,9 @@ window.Minecraft = class { this.frames = 0; this.lastTime = Date.now(); + // Create all blocks + Block.create(); + // Create world this.world = new World(); this.worldRenderer.scene.add(this.world.group); @@ -23,9 +26,6 @@ window.Minecraft = class { } init() { - // Create all blocks - Block.create(); - // Start render loop this.running = true; this.requestNextFrame(); diff --git a/src/js/net/minecraft/client/entity/Player.js b/src/js/net/minecraft/client/entity/Player.js index bf0e2dc..55179fd 100644 --- a/src/js/net/minecraft/client/entity/Player.js +++ b/src/js/net/minecraft/client/entity/Player.js @@ -47,7 +47,7 @@ window.Player = class { } resetPos() { - this.setPos(0, 25, 0); + this.setPos(0, 80, 0); } setPos(x, y, z) { @@ -182,7 +182,7 @@ window.Player = class { this.motionY = 0.42; if (this.sprinting) { - let radiansYaw = this.yaw * (Math.PI / 180) + Math.PI; + let radiansYaw = MathHelper.toRadians(this.yaw + 180); this.motionX -= Math.sin(radiansYaw) * 0.2; this.motionZ += Math.cos(radiansYaw) * 0.2; } @@ -281,7 +281,7 @@ window.Player = class { up = up * distance; forward = forward * distance; - let yawRadians = this.yaw * (Math.PI / 180) + Math.PI; + let yawRadians = MathHelper.toRadians(this.yaw + 180); let sin = Math.sin(yawRadians); let cos = Math.cos(yawRadians); diff --git a/src/js/net/minecraft/client/render/WorldRenderer.js b/src/js/net/minecraft/client/render/WorldRenderer.js index c66ac13..f55bf38 100644 --- a/src/js/net/minecraft/client/render/WorldRenderer.js +++ b/src/js/net/minecraft/client/render/WorldRenderer.js @@ -14,6 +14,8 @@ window.WorldRenderer = class { this.camera.rotation.order = 'ZYX'; this.camera.up = new THREE.Vector3(0, 0, 1); + this.frustum = new THREE.Frustum(); + // Create scene this.scene = new THREE.Scene(); this.scene.matrixAutoUpdate = false; @@ -42,6 +44,8 @@ window.WorldRenderer = class { // Block Renderer this.blockRenderer = new BlockRenderer(this); + + this.chunkSectionUpdateQueue = []; } render(partialTicks) { @@ -49,7 +53,10 @@ window.WorldRenderer = class { this.orientCamera(partialTicks); // Render chunks - this.renderChunks(this, partialTicks); + let player = this.minecraft.player; + let cameraChunkX = Math.floor(player.x >> 4); + let cameraChunkZ = Math.floor(player.z >> 4); + this.renderChunks(cameraChunkX, cameraChunkZ, EnumWorldBlockLayer.SOLID); // Render window this.webRenderer.render(this.scene, this.camera); @@ -59,8 +66,8 @@ window.WorldRenderer = class { let player = this.minecraft.player; // Rotation - this.camera.rotation.y = -player.yaw * (Math.PI / 180) + Math.PI; - this.camera.rotation.x = -player.pitch * (Math.PI / 180); + this.camera.rotation.y = -MathHelper.toRadians(player.yaw + 180); + this.camera.rotation.x = -MathHelper.toRadians(player.pitch); // Position let x = player.prevX + (player.x - player.prevX) * partialTicks; @@ -68,6 +75,9 @@ window.WorldRenderer = class { let z = player.prevZ + (player.z - player.prevZ) * partialTicks; this.camera.position.set(x, y + player.getEyeHeight(), z); + // Update frustum + this.frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(this.camera.projectionMatrix, this.camera.matrixWorldInverse)); + // Update FOV this.camera.fov = 85 + player.getFOVModifier(); this.camera.updateProjectionMatrix(); @@ -88,17 +98,68 @@ window.WorldRenderer = class { } } - renderChunks(renderer, partialTicks) { + renderChunks(cameraChunkX, cameraChunkZ, renderLayer) { let world = this.minecraft.world; - for(let i in world.chunks) { + for (let i in world.chunks) { let chunk = world.chunks[i]; - for (let y = 0; y < chunk.sections.length; y++) { - let section = chunk.sections[y]; + let distanceX = Math.abs(cameraChunkX - chunk.x); + let distanceZ = Math.abs(cameraChunkZ - chunk.z); - if (section.dirty) { - section.rebuild(renderer); + // Is in render distance check + if (distanceX < WorldRenderer.RENDER_DISTANCE && distanceZ < WorldRenderer.RENDER_DISTANCE) { + // Make chunk visible + chunk.group.visible = true; + + + // For all chunk sections + for (let y in chunk.sections) { + let chunkSection = chunk.sections[y]; + + // Is in camera view check + if (this.frustum.intersectsBox(chunkSection.boundingBox)) { + // Make section visible + chunkSection.group.visible = true; + + // Render chunk section + chunkSection.render(renderLayer); + + // Queue for rebuild + if (chunkSection.isQueuedForRebuild() && !this.chunkSectionUpdateQueue.includes(chunkSection)) { + this.chunkSectionUpdateQueue.push(chunkSection); + } + } else { + // Hide section + chunkSection.group.visible = false; + } + } + } else { + // Hide chunk + chunk.group.visible = false; + } + } + + // Sort update queue, chunk sections that are closer to the camera get a higher priority + this.chunkSectionUpdateQueue.sort((section1, section2) => { + let distance1 = Math.floor(Math.pow(section1.x - cameraChunkX, 2) + Math.pow(section1.z - cameraChunkZ, 2)); + let distance2 = Math.floor(Math.pow(section2.x - cameraChunkX, 2) + Math.pow(section2.z - cameraChunkZ, 2)); + return distance1 - distance2; + }); + + // Rebuild 16 chunk sections per frame (An entire chunk) + for (let i = 0; i < 16; i++) { + if (this.chunkSectionUpdateQueue.length !== 0) { + let chunkSection = this.chunkSectionUpdateQueue.shift(); + if (chunkSection != null) { + // Load chunk + let chunk = chunkSection.chunk; + if (!chunk.isLoaded()) { + world.loadChunk(chunk); + } + + // Rebuild chunk + chunkSection.rebuild(this); } } } diff --git a/src/js/net/minecraft/client/world/Chunk.js b/src/js/net/minecraft/client/world/Chunk.js index ec6b414..428c061 100644 --- a/src/js/net/minecraft/client/world/Chunk.js +++ b/src/js/net/minecraft/client/world/Chunk.js @@ -8,16 +8,22 @@ window.Chunk = class { this.group = new THREE.Object3D(); this.group.matrixAutoUpdate = false; + this.loaded = false; + // Initialize sections this.sections = []; for (let y = 0; y < 16; y++) { - let section = new ChunkSection(world, x, y, z); + let section = new ChunkSection(world, this, x, y, z); this.sections[y] = section; this.group.add(section.group); } } + setBlockAt(x, y, z, typeId) { + this.getSection(y >> 4).setBlockAt(x, y & 15, z, typeId); + } + getSection(y) { return this.sections[y]; } @@ -34,4 +40,12 @@ window.Chunk = class { } } + load() { + this.loaded = true; + } + + isLoaded() { + return this.loaded; + } + } \ No newline at end of file diff --git a/src/js/net/minecraft/client/world/ChunkSection.js b/src/js/net/minecraft/client/world/ChunkSection.js index bb87cc8..01f7fb6 100644 --- a/src/js/net/minecraft/client/world/ChunkSection.js +++ b/src/js/net/minecraft/client/world/ChunkSection.js @@ -2,15 +2,24 @@ window.ChunkSection = class { static SIZE = 16; - constructor(world, x, y, z) { + constructor(world, chunk, x, y, z) { this.world = world; + this.chunk = chunk; this.x = x; this.y = y; this.z = z; + this.boundingBox = new THREE.Box3(); + this.boundingBox.min.x = x * ChunkSection.SIZE; + this.boundingBox.min.y = y * ChunkSection.SIZE; + this.boundingBox.min.z = z * ChunkSection.SIZE; + this.boundingBox.max.x = x * ChunkSection.SIZE + ChunkSection.SIZE; + this.boundingBox.max.y = y * ChunkSection.SIZE + ChunkSection.SIZE; + this.boundingBox.max.z = z * ChunkSection.SIZE + ChunkSection.SIZE; + this.group = new THREE.Object3D(); this.group.matrixAutoUpdate = false; - this.dirty = true; + this.queuedForRebuild = true; this.blocks = []; for (let x = 0; x < ChunkSection.SIZE; x++) { @@ -22,8 +31,12 @@ window.ChunkSection = class { } } + render(renderLayer) { + + } + rebuild(renderer) { - this.dirty = false; + this.queuedForRebuild = false; this.group.clear(); // Start drawing chunk section @@ -62,6 +75,10 @@ window.ChunkSection = class { } queueForRebuild() { - this.dirty = true; + this.queuedForRebuild = true; + } + + isQueuedForRebuild() { + return this.queuedForRebuild; } } \ No newline at end of file diff --git a/src/js/net/minecraft/client/world/World.js b/src/js/net/minecraft/client/world/World.js index e72613e..9d8ffb9 100644 --- a/src/js/net/minecraft/client/world/World.js +++ b/src/js/net/minecraft/client/world/World.js @@ -7,15 +7,19 @@ window.World = class { this.group.matrixAutoUpdate = false; this.chunks = []; - // Debug world - for (let x = -16; x < 16; x++) { - for (let y = 0; y < 16; y++) { - for (let z = -16; z < 16; z++) { - this.setBlockAt(x, y, z, y === 15 ? 2 : 3); - } - } - } - this.setBlockAt(0, 16, -2, 17); + // Load world + this.generator = new WorldGenerator(this, Date.now() % 100000); + } + + loadChunk(chunk) { + // Load chunk + chunk.load(); + + // Generate new chunk + this.generator.generateChunk(chunk); + + // Populate chunk + this.generator.populateChunk(chunk.x, chunk.z); } getChunkAtBlock(x, y, z) { @@ -56,10 +60,9 @@ window.World = class { chunkSection.setBlockAt(x & 15, y & 15, z & 15, type); } - this.blockChanged(x, y, z); + this.onBlockChanged(x, y, z); } - getBlockAt(x, y, z) { let chunkSection = this.getChunkAtBlock(x, y, z); return chunkSection == null ? 0 : chunkSection.getBlockAt(x & 15, y & 15, z & 15); @@ -79,11 +82,20 @@ window.World = class { return chunk; } - blockChanged(x, y, z) { - this.setDirty(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1); + getHighestBlockYAt(x, z) { + for (let y = World.TOTAL_HEIGHT; y > 0; y--) { + if (this.isSolidBlockAt(x, y, z)) { + return y; + } + } + return 0; } - setDirty(minX, minY, minZ, maxX, maxY, maxZ) { + onBlockChanged(x, y, z) { + this.queueForRebuildInRegion(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1); + } + + queueForRebuildInRegion(minX, minY, minZ, maxX, maxY, maxZ) { // To chunk coordinates minX = minX >> 4; maxX = maxX >> 4; diff --git a/src/js/net/minecraft/client/world/generator/NoiseGenerator.js b/src/js/net/minecraft/client/world/generator/NoiseGenerator.js new file mode 100644 index 0000000..d69ae96 --- /dev/null +++ b/src/js/net/minecraft/client/world/generator/NoiseGenerator.js @@ -0,0 +1,5 @@ +window.NoiseGenerator = class { + perlin(x, z) { + + } +} \ No newline at end of file diff --git a/src/js/net/minecraft/client/world/generator/WorldGenerator.js b/src/js/net/minecraft/client/world/generator/WorldGenerator.js new file mode 100644 index 0000000..d0119fb --- /dev/null +++ b/src/js/net/minecraft/client/world/generator/WorldGenerator.js @@ -0,0 +1,170 @@ +window.WorldGenerator = class { + + constructor(world, seed) { + this.world = world; + this.random = new Random(seed); + + this.waterLevel = 64; + + // Create noise for the ground height + this.groundHeightNoise = new NoiseGeneratorOctaves(this.random, 8); + this.hillNoise = new NoiseGeneratorCombined(new NoiseGeneratorOctaves(this.random, 4), + new NoiseGeneratorCombined(new NoiseGeneratorOctaves(this.random, 4), + new NoiseGeneratorOctaves(this.random, 4))); + + // Water noise + this.sandInWaterNoise = new NoiseGeneratorOctaves(this.random, 8); + + // Hole in hills and islands + this.holeNoise = new NoiseGeneratorOctaves(this.random, 3); + this.islandNoise = new NoiseGeneratorOctaves(this.random, 3); + + // Caves + this.caveNoise = new NoiseGeneratorOctaves(this.random, 8); + + // Population + this.forestNoise = new NoiseGeneratorOctaves(this.random, 8); + } + + generateChunk(chunk) { + // For each block in the chunk + for (let relX = 0; relX < ChunkSection.SIZE; relX++) { + for (let relZ = 0; relZ < ChunkSection.SIZE; relZ++) { + + // Absolute position of the block + let x = chunk.x * ChunkSection.SIZE + relX; + let z = chunk.z * ChunkSection.SIZE + relZ; + + // Extract height value of the noise + let heightValue = this.groundHeightNoise.perlin(x, z); + let hillValue = Math.max(0, this.hillNoise.perlin(x / 18, z / 18) * 6); + + // Calculate final height for this position + let groundHeightY = Math.floor(heightValue / 10 + this.waterLevel + hillValue); + + if (groundHeightY < this.waterLevel) { + // Generate water + for (let y = 0; y <= this.waterLevel; y++) { + // Use noise to place sand in water + let sandInWater = this.sandInWaterNoise.perlin(x, z) < 0; + let block = y > groundHeightY ? Block.WATER : groundHeightY - y < 3 && sandInWater ? Block.SAND : Block.STONE; + + // Send water, sand and stone + chunk.setBlockAt(x & 15, y, z & 15, block.getId()); + } + } else { + // Generate height, the highest block is grass + for (let y = 0; y <= groundHeightY; y++) { + // Use the height map to determine the start of the water by shifting it + let isBeach = heightValue < 5 && y < this.waterLevel + 2; + let block = y === groundHeightY ? isBeach ? Block.SAND : Block.GRASS : groundHeightY - y < 3 ? Block.DIRT : Block.STONE; + + // Set sand, grass, dirt and stone + chunk.setBlockAt(x & 15, y, z & 15, block.getId()); + } + } + + /* + int holeY = (int) (this.holeNouse.perlin(-x / 20F, -z / 20F) * 3F + this.waterLevel + 10); + int holeHeight = (int) this.holeNouse.perlin(x / 4F, -z / 4F); + if (holeHeight > 0) { + for (int y = holeY - holeHeight; y <= holeY + holeHeight; y++) { + chunk.setBlockAt(x & 15, y, z & 15, 1); + } + } + */ + + // Random holes in hills + let holePositionY = Math.floor(this.holeNoise.perlin(-x / 20, -z / 20) * 3 + this.waterLevel + 10); + let holeHeight = Math.floor(this.holeNoise.perlin(x / 4, -z / 4)); + + if (holeHeight > 0) { + for (let y = holePositionY - holeHeight; y <= holePositionY + holeHeight; y++) { + if (y > this.waterLevel) { + chunk.setBlockAt(x & 15, y, z & 15, 0); + } + } + } + + // Floating islands + let islandPositionY = Math.floor(this.islandNoise.perlin(-x / 10, -z / 10) * 3 + this.waterLevel + 10); + let islandHeight = Math.floor(this.islandNoise.perlin(x / 4, -z / 4) * 4); + let islandRarity = Math.floor(this.islandNoise.perlin(x / 40, z / 40) * 4) - 10; + + if (islandHeight > 0 && islandRarity > 0) { + for (let y = islandPositionY - islandHeight; y <= islandPositionY + islandHeight; y++) { + let block = y === islandPositionY + islandHeight ? Block.GRASS : (islandPositionY + islandHeight) - y < 2 ? Block.DIRT : Block.STONE; + chunk.setBlockAt(x & 15, y, z & 15, block.getId()); + } + } + + // Caves + } + } + } + + populateChunk(chunkX, chunkZ) { + for (let index = 0; index < 10; index++) { + let x = this.random.nextInt(ChunkSection.SIZE); + let z = this.random.nextInt(ChunkSection.SIZE); + + // Absolute position of the block + let absoluteX = chunkX * ChunkSection.SIZE + x; + let absoluteZ = chunkZ * ChunkSection.SIZE + z; + + // Use noise for a forest pattern + 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); + + // Don't place a tree if there is no grass + if (this.world.getBlockAt(absoluteX, highestY, absoluteZ) === Block.GRASS.getId() + && this.world.getBlockAt(absoluteX, highestY + 1, absoluteZ) === 0) { + let treeHeight = this.random.nextInt(2) + 5; + + // Create tree log + for (let i = 0; i < treeHeight; i++) { + this.world.setBlockAt(absoluteX, highestY + i + 1, absoluteZ, Block.LOG.getId()); + } + + // Create big leave ring + for (let tx = -2; tx <= 2; tx++) { + for (let ty = 0; ty < 2; ty++) { + for (let tz = -2; tz <= 2; tz++) { + let isCorner = Math.abs(tx) === 2 && Math.abs(tz) === 2; + if (isCorner && this.random.nextBoolean()) { + continue; + } + + // Place leave if there is no block yet + if (!this.world.isSolidBlockAt(absoluteX + tx, highestY + treeHeight + ty - 2, absoluteZ + tz)) { + this.world.setBlockAt(absoluteX + tx, highestY + treeHeight + ty - 2, absoluteZ + tz, Block.LEAVE.getId()); + } + } + } + } + + // Create small leave ring on top + for (let tx = -1; tx <= 1; tx++) { + for (let ty = 0; ty < 2; ty++) { + for (let tz = -1; tz <= 1; tz++) { + let isCorner = Math.abs(tx) === 1 && Math.abs(tz) === 1; + if (isCorner && (ty === 1 || this.random.nextBoolean())) { + continue; + } + + // Place leave if there is no block yet + if (!this.world.isSolidBlockAt(absoluteX + tx, highestY + treeHeight + ty, absoluteZ + tz)) { + this.world.setBlockAt(absoluteX + tx, highestY + treeHeight + ty, absoluteZ + tz, Block.LEAVE.getId()); + } + } + } + } + } + } + } + + } +} \ No newline at end of file diff --git a/src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorCombined.js b/src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorCombined.js new file mode 100644 index 0000000..e29885f --- /dev/null +++ b/src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorCombined.js @@ -0,0 +1,14 @@ +window.NoiseGeneratorCombined = class extends NoiseGenerator { + + constructor(firstGenerator, secondGenerator) { + super(); + + this.firstGenerator = firstGenerator; + this.secondGenerator = secondGenerator; + } + + perlin(x, z) { + return this.firstGenerator.perlin(x + this.secondGenerator.perlin(x, z), z); + } + +} \ No newline at end of file diff --git a/src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorOctaves.js b/src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorOctaves.js new file mode 100644 index 0000000..59f5123 --- /dev/null +++ b/src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorOctaves.js @@ -0,0 +1,24 @@ +window.NoiseGeneratorOctaves = class extends NoiseGenerator { + + constructor(random, octaves) { + super(); + + this.octaves = octaves; + this.generatorCollection = []; + + for (let i = 0; i < octaves; i++) { + this.generatorCollection[i] = new NoiseGeneratorPerlin(random); + } + } + + perlin(x, z) { + let total = 0.0; + let frequency = 1.0; + for (let i = 0; i < this.octaves; i++) { + total += this.generatorCollection[i].perlin(x / frequency, z / frequency) * frequency; + frequency *= 2.0; + } + return total; + } + +} \ No newline at end of file diff --git a/src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorPerlin.js b/src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorPerlin.js new file mode 100644 index 0000000..f5bf6f3 --- /dev/null +++ b/src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorPerlin.js @@ -0,0 +1,85 @@ +window.NoiseGeneratorPerlin = class extends NoiseGenerator { + + constructor(random) { + super(); + + this.permutations = []; + for (let i = 0; i < 256; i++) { + this.permutations[i] = i; + } + for (let i = 0; i < 256; i++) { + let n = random.nextInt(256 - i) + i; + let n2 = this.permutations[i]; + this.permutations[i] = this.permutations[n]; + this.permutations[n] = n2; + this.permutations[i + 256] = this.permutations[i]; + } + } + + fade(t) { + // Fade function as defined by Ken Perlin. This eases coordinate values + // so that they will "ease" towards integral values. This ends up smoothing + // the final output. + return t * t * t * (t * (t * 6 - 15) + 10); // 6t^5 - 15t^4 + 10t^3 + } + + lerp(x, a, b) { + return a + x * (b - a); + } + + grad(hash, x, y, z) { + let h = hash & 15; // Take the hashed value and take the first 4 bits of it (15 == 0b1111) + let u = h < 8 /* 0b1000 */ ? x : y; // If the most significant bit (MSB) of the hash is 0 then set u = x. Otherwise y. + + let v; // In Ken Perlin's original implementation this was another conditional operator (?:). I + // expanded it for readability. + if (h < 4 /* 0b0100 */) // If the first and second significant bits are 0 set v = y + v = y; + else if (h === 12 /* 0b1100 */ || h === 14 /* 0b1110*/) // If the first and second significant bits are 1 set v = x + v = x; + else // If the first and second significant bits are not equal (0/1, 1/0) set v = z + v = z; + + return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v); // Use the last 2 bits to decide if u and v are positive or negative. Then return their addition. + } + + perlin(x, z) { + let y; + + let xi = Math.floor(x) & 0xFF; + let zi = Math.floor(z) & 0xFF; + let yi = Math.floor(0.0) & 0xFF; + + x -= Math.floor(x); + z -= Math.floor(z); + y = 0.0 - Math.floor(0.0); + + let u = this.fade(x); + let w = this.fade(z); + let v = this.fade(y); + + let xzi = this.permutations[xi] + zi; + let xzyi = this.permutations[xzi] + yi; + + xzi = this.permutations[xzi + 1] + yi; + xi = this.permutations[xi + 1] + zi; + zi = this.permutations[xi] + yi; + xi = this.permutations[xi + 1] + yi; + + return this.lerp(v, + this.lerp(w, + this.lerp(u, + this.grad(this.permutations[xzyi], x, z, y), + this.grad(this.permutations[zi], x - 1.0, z, y)), + this.lerp(u, + this.grad(this.permutations[xzi], x, z - 1.0, y), + this.grad(this.permutations[xi], x - 1.0, z - 1.0, y))), + this.lerp(w, + this.lerp(u, + this.grad(this.permutations[xzyi + 1], x, z, y - 1.0), + this.grad(this.permutations[zi + 1], x - 1.0, z, y - 1.0)), + this.lerp(u, + this.grad(this.permutations[xzi + 1], x, z - 1.0, y - 1.0), + this.grad(this.permutations[xi + 1], x - 1.0, z - 1.0, y - 1.0)))); + } +} \ No newline at end of file diff --git a/src/js/net/minecraft/util/EnumWorldBlockLayer.js b/src/js/net/minecraft/util/EnumWorldBlockLayer.js new file mode 100644 index 0000000..aebac37 --- /dev/null +++ b/src/js/net/minecraft/util/EnumWorldBlockLayer.js @@ -0,0 +1,4 @@ +window.EnumWorldBlockLayer = class { + static SOLID = 0; + static CUTOUT = 0; +} \ No newline at end of file diff --git a/src/js/net/minecraft/util/MathHelper.js b/src/js/net/minecraft/util/MathHelper.js index 796f7c9..d1f96a7 100644 --- a/src/js/net/minecraft/util/MathHelper.js +++ b/src/js/net/minecraft/util/MathHelper.js @@ -8,4 +8,12 @@ window.MathHelper = class { return value < i ? i - 1 : i; } + static toDegrees(angle) { + return angle * (180 / Math.PI); + } + + static toRadians(degree) { + return degree * (Math.PI / 180); + }; + } \ No newline at end of file diff --git a/src/js/net/minecraft/util/Random.js b/src/js/net/minecraft/util/Random.js new file mode 100644 index 0000000..11b7c68 --- /dev/null +++ b/src/js/net/minecraft/util/Random.js @@ -0,0 +1,25 @@ +window.Random = class { + + constructor(seed) { + this.mask = 0xffffffff; + this.m_w = (123456789 + seed) & this.mask; + this.m_z = (987654321 - seed) & this.mask; + } + + nextBoolean() { + return this.nextFloat() > 0.5; + } + + nextInt(max) { + return Math.floor(this.nextFloat() * (max + 1)); + } + + nextFloat() { + this.m_z = (36969 * (this.m_z & 65535) + (this.m_z >>> 16)) & this.mask; + this.m_w = (18000 * (this.m_w & 65535) + (this.m_w >>> 16)) & this.mask; + + let result = ((this.m_z << 16) + (this.m_w & 65535)) >>> 0; + result /= 4294967296; + return result; + } +} \ No newline at end of file diff --git a/src/start.js b/src/start.js index 9ce744e..59aff2a 100644 --- a/src/start.js +++ b/src/start.js @@ -50,7 +50,9 @@ loadScripts([ // Minecraft Source "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/Vector3.js", + "src/js/net/minecraft/util/EnumWorldBlockLayer.js", "src/js/net/minecraft/util/MovingObjectPosition.js", "src/js/net/minecraft/util/MathHelper.js", "src/js/net/minecraft/util/BoundingBox.js", @@ -67,6 +69,11 @@ loadScripts([ "src/js/net/minecraft/client/world/ChunkSection.js", "src/js/net/minecraft/client/world/Chunk.js", "src/js/net/minecraft/client/world/World.js", + "src/js/net/minecraft/client/world/generator/NoiseGenerator.js", + "src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorPerlin.js", + "src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorOctaves.js", + "src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorCombined.js", + "src/js/net/minecraft/client/world/generator/WorldGenerator.js", "src/js/net/minecraft/client/entity/Player.js", "src/js/net/minecraft/client/Minecraft.js", "src/js/net/minecraft/client/render/Tessellator.js",