public int PopulateChunk(ChunkColumn chunk) { //var random = new CryptoRandom(); //var stones = new byte[16*16*16]; int h = 0; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { h = 0; chunk.SetBlock(x, h++, z, 7); // Bedrock //stones[i + h++] = 1; // Stone //stones[i + h++] = 1; // Stone //switch (random.Next(0, 20)) //{ // case 0: // stones[i + h++] = 3; // Dirt // stones[i + h++] = 3; // break; // case 1: // stones[i + h++] = 1; // Stone // stones[i + h++] = 1; // Stone // break; // case 2: // stones[i + h++] = 13; // Gravel // stones[i + h++] = 13; // Gravel // break; // case 3: // stones[i + h++] = 14; // Gold // stones[i + h++] = 14; // Gold // break; // case 4: // stones[i + h++] = 16; // Cole // stones[i + h++] = 16; // Cole // break; // case 5: // stones[i + h++] = 56; // Dimond // stones[i + h++] = 56; // Dimond // break; // default: // stones[i + h++] = 1; // Stone // stones[i + h++] = 1; // Stone // break; //} chunk.SetBlock(x, h++, z, 3); // Dirt chunk.SetBlock(x, h++, z, 3); // Dirt chunk.SetBlock(x, h++, z, 2); // Grass chunk.SetHeight(x, z, (short)h); } } return(h); }
private void BuildStructures(ChunkColumn chunk) { if (chunk.x == 0 && chunk.z == 1) { for (int x = 3; x < 6; x++) { for (int y = 4; y < 7; y++) { if (x == 4 && y < 6) { continue; } for (int z = 1; z < 15; z++) { chunk.SetBlock(x, y, z, 3); } } } chunk.SetBlock(4, 4, 14, 3); chunk.SetBlock(4, 5, 14, 3); } //if (chunk.x == 0 && chunk.z == 0) //{ // for (int x = 1; x < 16; x++) // { // for (int z = 0; z < 16; z++) // { // chunk.SetBlock(x, 8, z, 3); // } // } //} //if (chunk.x == 1 && chunk.z == 0) //{ // for (int x = 0; x < 15; x++) // { // for (int z = 0; z < 16; z++) // { // chunk.SetBlock(x, 8, z, 3); // } // } //} if (chunk.x == -1 && chunk.z == 0) { for (int x = 1; x < 15; x++) { for (int z = 1; z < 15; z++) { chunk.SetBlock(x, 8, z, 3); } } } }
private void GenerateLake(Random random, ChunkColumn chunk, Block block) { int h = FindGroundLevel(); if (h < 0) { return; } Vector2 center = new Vector2(7, 8); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { Vector2 v = new Vector2(x, z); if (random.Next((int)Vector2.DistanceSquared(center, v)) < 4) { if (Dimension == Dimension.Overworld) { chunk.SetBlock(x, h, z, block.Id); } else if (Dimension == Dimension.Nether) { chunk.SetBlock(x, h, z, block.Id); if (random.Next(30) == 0) { for (int i = h; i < BlockLayers.Count - 1; i++) { chunk.SetBlock(x, i, z, block.Id); } } } else if (Dimension == Dimension.TheEnd) { for (int i = 0; i < BlockLayers.Count; i++) { chunk.SetBlock(x, i, z, 0); } } } else if (Dimension == Dimension.TheEnd && random.Next((int)Vector2.DistanceSquared(center, v)) < 15) { chunk.SetBlock(x, h, z, 0); } } } }
public void PopulateChunk(ChunkColumn chunk) { var layers = BlockLayers; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { int h = 0; foreach (var layer in layers) { chunk.SetBlock(x, h, z, layer.Id); chunk.SetMetadata(x, h, z, layer.Metadata); h++; } chunk.SetHeight(x, z, (short)h); for (int i = h + Dimension == Dimension.Overworld ? 1 : 0; i >= 0; i--) { chunk.SetSkyLight(x, i, z, 0); } // need to take care of skylight for non overworld to make it 0. chunk.SetBiome(x, z, 1); // use pattern for this } } }
public void SetBlock(Block block, bool broadcast = true, bool applyPhysics = true) { ChunkColumn chunk = _worldProvider.GenerateChunkColumn(new ChunkCoordinates(block.Coordinates.X >> 4, block.Coordinates.Z >> 4)); chunk.SetBlock(block.Coordinates.X & 0x0f, block.Coordinates.Y & 0x7f, block.Coordinates.Z & 0x0f, block.Id); chunk.SetMetadata(block.Coordinates.X & 0x0f, block.Coordinates.Y & 0x7f, block.Coordinates.Z & 0x0f, block.Metadata); if (applyPhysics) { ApplyPhysics(block.Coordinates.X, block.Coordinates.Y, block.Coordinates.Z); } if (!broadcast) { return; } Block sendBlock = new Block(block.Id) { Coordinates = block.Coordinates, Metadata = (byte)(0xb << 4 | (block.Metadata & 0xf)) }; var message = McpeUpdateBlock.CreateObject(); message.blocks = new BlockRecords { sendBlock }; RelayBroadcast(message); }
public void SetBlock(Block block, bool broadcast = true, bool applyPhysics = true, bool calculateLight = true) { if (block.Coordinates.Y < 0) { return; } ChunkColumn chunk = _worldProvider.GenerateChunkColumn(new ChunkCoordinates(block.Coordinates.X >> 4, block.Coordinates.Z >> 4)); chunk.SetBlock(block.Coordinates.X & 0x0f, block.Coordinates.Y & 0xff, block.Coordinates.Z & 0x0f, block.Id); chunk.SetMetadata(block.Coordinates.X & 0x0f, block.Coordinates.Y & 0xff, block.Coordinates.Z & 0x0f, block.Metadata); if (applyPhysics) { ApplyPhysics(block.Coordinates.X, block.Coordinates.Y, block.Coordinates.Z); } if (block.LightLevel > 0) { block.BlockLight = (byte)block.LightLevel; chunk.SetBlocklight(block.Coordinates.X & 0x0f, block.Coordinates.Y & 0xff, block.Coordinates.Z & 0x0f, (byte)block.LightLevel); BlockLightCalculations.Calculate(this, block); } if (!broadcast) { return; } var message = McpeUpdateBlock.CreateObject(); message.blockId = block.Id; message.coordinates = block.Coordinates; message.blockMetaAndPriority = (byte)(0xb << 4 | (block.Metadata & 0xf)); RelayBroadcast(message); }
public void SetBlock(Block block, bool broadcast = true, bool applyPhysics = true) { ChunkColumn chunk = _worldProvider.GenerateChunkColumn(new ChunkCoordinates(block.Coordinates.X >> 4, block.Coordinates.Z >> 4)); chunk.SetBlock(block.Coordinates.X & 0x0f, block.Coordinates.Y & 0x7f, block.Coordinates.Z & 0x0f, block.Id); chunk.SetMetadata(block.Coordinates.X & 0x0f, block.Coordinates.Y & 0x7f, block.Coordinates.Z & 0x0f, block.Metadata); if (applyPhysics) { ApplyPhysics(block.Coordinates.X, block.Coordinates.Y, block.Coordinates.Z); } if (!broadcast) { return; } var message = McpeUpdateBlock.CreateObject(); message.blockId = block.Id; message.x = block.Coordinates.X; message.y = (byte)block.Coordinates.Y; message.z = block.Coordinates.Z; message.blockMetaAndPriority = (byte)(0xb << 4 | (block.Metadata & 0xf)); RelayBroadcast(message); }
private void GenerateGlowStone(Random random, ChunkColumn chunk) { if (Dimension != Dimension.Nether) { return; } int h = FindGroundLevel(); if (h < 0) { return; } Vector2 center = new Vector2(7, 8); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { Vector2 v = new Vector2(x, z); if (random.Next((int)Vector2.DistanceSquared(center, v)) < 1) { chunk.SetBlock(x, BlockLayers.Count - 2, z, new Glowstone().Id); if (random.NextDouble() > 0.85) { chunk.SetBlock(x, BlockLayers.Count - 3, z, new Glowstone().Id); if (random.NextDouble() > 0.50) { chunk.SetBlock(x, BlockLayers.Count - 4, z, new Glowstone().Id); } } } } } }
public void ShowHeights(ChunkColumn chunk) { if (chunk == null) { return; } for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (byte y = 255; y > 0; y--) { if (chunk.GetSkylight(x, y, z) == 0) { chunk.SetBlock(x, y, z, 41); } } } } }
public void ShowHeights(ChunkColumn chunk) { if (chunk == null) { return; } for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { var y = chunk.GetHeight(x, z); chunk.SetBlock(x, y, z, 41); //for (byte y = 255; y > 0; y--) //{ // if (chunk.GetSkylight(x, y, z) == 0) // { // chunk.SetBlock(x, y, z, 41); // break; // } //} } } }
public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates) { lock (_chunkCache) { ChunkColumn cachedChunk; if (_chunkCache.TryGetValue(chunkCoordinates, out cachedChunk)) { return(cachedChunk); } ChunkColumn chunk = new ChunkColumn(); chunk.x = chunkCoordinates.X; chunk.z = chunkCoordinates.Z; //chunk.biomeId = ArrayOf<byte>.Create(256, (byte) rand.Next(0, 37)); int h = PopulateChunk(chunk); //chunk.SetBlock(0, h + 1, 0, 7); //chunk.SetBlock(1, h + 1, 0, 41); //chunk.SetBlock(2, h + 1, 0, 41); //chunk.SetBlock(3, h + 1, 0, 41); //chunk.SetBlock(3, h + 1, 0, 41); ////chunk.SetBlock(6, h + 1, 6, 57); //chunk.SetBlock(9, h, 3, 31); //chunk.SetBiome(9, 3, 30); //chunk.SetBlock(0, h, 1, 161); //chunk.SetBlock(0, h, 2, 18); //chunk.SetBlock(0, h, 15, 31); //chunk.SetBlock(0, h, 14, 161); //chunk.SetBlock(5, h, 13, 18); //chunk.SetBiome(5, 13, 30); //chunk.SetBlock(6, h, 9, 63); //chunk.SetMetadata(6, h, 9, 12); //var blockEntity = GetBlockEntity((chunkCoordinates.X*16) + 6, h, (chunkCoordinates.Z*16) + 9); //chunk.SetBlockEntity(blockEntity.Coordinates, blockEntity.GetCompound()); if (chunkCoordinates.X == 1 && chunkCoordinates.Z == 1) { for (int x = 0; x < 10; x++) { for (int z = 0; z < 10; z++) { for (int y = h - 2; y < h; y++) { chunk.SetBlock(x, y, z, 8); } } } } if (chunkCoordinates.X == 3 && chunkCoordinates.Z == 1) { for (int x = 0; x < 10; x++) { for (int z = 0; z < 10; z++) { for (int y = h - 1; y < h; y++) { chunk.SetBlock(x, y, z, 10); } } } } for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 127; y > 0; y--) { if (chunk.GetBlock(x, y, z) == 0x00) { chunk.SetSkylight(x, y, z, 0xff); } else { chunk.SetSkylight(x, y, z, 0x00); } } } } // Cache chunk.GetBatch(); _chunkCache[chunkCoordinates] = chunk; return(chunk); } }
private void PopulateChunk(ChunkColumn chunk) { int trees = new Random().Next(0, 10); int[,] treeBasePositions = new int[trees, 2]; for (int t = 0; t < trees; t++) { int x = new Random().Next(1, 16); int z = new Random().Next(1, 16); treeBasePositions[t, 0] = x; treeBasePositions[t, 1] = z; } var bottom = new SimplexOctaveGenerator(_seed.GetHashCode(), 8); var overhang = new SimplexOctaveGenerator(_seed.GetHashCode(), 8); overhang.SetScale(1 / 64.0); bottom.SetScale(1 / 128.0); double overhangsMagnitude = 16; double bottomsMagnitude = 32; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { float ox = x + chunk.x * 16; float oz = z + chunk.z * 16; int bottomHeight = (int)((bottom.Noise(ox, oz, 0.5, 0.5) * bottomsMagnitude) + 64.0); int maxHeight = (int)((overhang.Noise(ox, oz, 0.5, 0.5) * overhangsMagnitude) + bottomHeight + 32.0); double threshold = 0.0; maxHeight = Math.Max(1, maxHeight); for (int y = 0; y < maxHeight && y < 255; y++) { if (y <= 1) { chunk.SetBlock(x, y, z, 7); continue; } if (y > bottomHeight) { //part where we do the overhangs double density = overhang.Noise(ox, y, oz, 0.5, 0.5); if (density > threshold) { chunk.SetBlock(x, y, z, (byte)Material.Stone); } } else { chunk.SetBlock(x, y, z, (byte)Material.Stone); } } //turn the tops into grass chunk.SetBlock(x, bottomHeight, z, (byte)Material.Grass); //the top of the base hills chunk.SetBlock(x, bottomHeight - 1, z, (byte)Material.Dirt); chunk.SetBlock(x, bottomHeight - 2, z, (byte)Material.Dirt); for (int y = bottomHeight + 1; y > bottomHeight && y < maxHeight && y < 255; y++) { //the overhang int thisblock = chunk.GetBlock(x, y, z); int blockabove = chunk.GetBlock(x, y + 1, z); if (thisblock != (decimal)Material.Air && blockabove == (decimal)Material.Air) { if (chunk.GetBlock(x, y, z) == (byte)Material.Dirt || chunk.GetBlock(x, y, z) == (byte)Material.Air || chunk.GetBlock(x, y, z) == (byte)Material.Stone) { chunk.SetBlock(x, y, z, (byte)Material.Grass); } if (chunk.GetBlock(x, y - 1, z) != (decimal)Material.Air) { chunk.SetBlock(x, y - 1, z, (byte)Material.Dirt); } if (chunk.GetBlock(x, y - 2, z) != (decimal)Material.Air) { chunk.SetBlock(x, y - 2, z, (byte)Material.Dirt); } } } for (int y = 0; y < WaterLevel; y++) { //Lake generation if (y < WaterLevel) { if (chunk.GetBlock(x, y, z) == (decimal)Material.Grass || chunk.GetBlock(x, y, z) == (decimal)Material.Dirt) //Grass or Dirt? { if (GetRandomNumber(1, 40) == 1 && y < WaterLevel - 4) { chunk.SetBlock(x, y, z, 82); //Clay } else { chunk.SetBlock(x, y, z, 12); //Sand } } if (chunk.GetBlock(x, y + 1, z) == (decimal)Material.Air) { if (y < WaterLevel - 3) { chunk.SetBlock(x, y + 1, z, 8); //FlowingWater } } } } for (int y = 0; y < 255; y++) { int thisblock = chunk.GetBlock(x, y, z); int blockabove = chunk.GetBlock(x, y + 1, z); if (thisblock == (decimal)Material.Grass && blockabove == (decimal)Material.Air && y > WaterLevel) { //Grass if (GetRandomNumber(0, 5) == 1) { chunk.SetBlock(x, y + 1, z, 31); chunk.SetMetadata(x, y + 1, z, 1); } //Flowers if (GetRandomNumber(0, 65) == 1) { int meta = GetRandomNumber(0, 8); chunk.SetBlock(x, y + 1, z, 38); chunk.SetMetadata(x, y + 1, z, (byte)meta); } //Trees for (int pos = 0; pos < trees; pos++) { if (treeBasePositions[pos, 0] < 14 && treeBasePositions[pos, 0] > 4 && treeBasePositions[pos, 1] < 14 && treeBasePositions[pos, 1] > 4) { if (chunk.GetBlock(treeBasePositions[pos, 0], y + 1, treeBasePositions[pos, 1]) == 2) { if (y >= bottomHeight) { GenerateTree(chunk, treeBasePositions[pos, 0], y + 1, treeBasePositions[pos, 1], WoodType.Oak); } } } } } } } } }
private void GenerateTree(ChunkColumn chunk, int x, int treebase, int z) { int treeheight = GetRandomNumber(4, 5); chunk.SetBlock(x, treebase + treeheight + 2, z, 18); //Top leave chunk.SetBlock(x, treebase + treeheight + 1, z + 1, 18); chunk.SetBlock(x, treebase + treeheight + 1, z - 1, 18); chunk.SetBlock(x + 1, treebase + treeheight + 1, z, 18); chunk.SetBlock(x - 1, treebase + treeheight + 1, z, 18); chunk.SetBlock(x, treebase + treeheight, z + 1, 18); chunk.SetBlock(x, treebase + treeheight, z - 1, 18); chunk.SetBlock(x + 1, treebase + treeheight, z, 18); chunk.SetBlock(x - 1, treebase + treeheight, z, 18); chunk.SetBlock(x + 1, treebase + treeheight, z + 1, 18); chunk.SetBlock(x - 1, treebase + treeheight, z - 1, 18); chunk.SetBlock(x + 1, treebase + treeheight, z - 1, 18); chunk.SetBlock(x - 1, treebase + treeheight, z + 1, 18); for (int i = 0; i <= treeheight; i++) { chunk.SetBlock(x, treebase + i, z, 17); } }
private void ReadSection(int yoffset, NbtTag sectionTag, ChunkColumn chunk) { int sy = sectionTag["Y"].ByteValue * 16; byte[] blocks = sectionTag["Blocks"].ByteArrayValue; byte[] data = sectionTag["Data"].ByteArrayValue; NbtTag addTag = sectionTag["Add"]; byte[] adddata = new byte[2048]; if (addTag != null) { adddata = addTag.ByteArrayValue; } byte[] blockLight = sectionTag["BlockLight"].ByteArrayValue; byte[] skyLight = sectionTag["SkyLight"].ByteArrayValue; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { int yi = sy + y - yoffset; if (yi < 0 || yi >= 256) { continue; } int anvilIndex = y * 16 * 16 + z * 16 + x; int blockId = blocks[anvilIndex] + (Nibble4(adddata, anvilIndex) << 8); // Anvil to PE friendly converstion Func <int, byte, byte> dataConverter = (i, b) => b; // Default no-op converter if (Convert.ContainsKey(blockId)) { dataConverter = Convert[blockId].Item2; blockId = Convert[blockId].Item1; } else { if (BlockFactory.GetBlockById((byte)blockId).GetType() == typeof(Block)) { Log.Warn($"No block implemented for block ID={blockId}, Meta={data}"); //blockId = 57; } } chunk.isAllAir = chunk.isAllAir && blockId == 0; if (blockId > 255) { Log.Warn($"Failed mapping for block ID={blockId}, Meta={data}"); blockId = 41; } //if (yi == 127 && blockId != 0) blockId = 30; if (yi == 0 && (blockId == 8 || blockId == 9)) { blockId = 7; } chunk.SetBlock(x, yi, z, (byte)blockId); byte metadata = Nibble4(data, anvilIndex); metadata = dataConverter(blockId, metadata); chunk.SetMetadata(x, yi, z, metadata); chunk.SetBlocklight(x, yi, z, Nibble4(blockLight, anvilIndex)); chunk.SetSkyLight(x, yi, z, Nibble4(skyLight, anvilIndex)); //if (block is BlockStairs || block is StoneSlab || block is WoodSlab) //{ // chunk.SetSkylight(x, yi, z, 0xff); //} if (blockId == 43 && chunk.GetMetadata(x, yi, z) == 7) { chunk.SetMetadata(x, yi, z, 6); } else if (blockId == 44 && chunk.GetMetadata(x, yi, z) == 7) { chunk.SetMetadata(x, yi, z, 6); } else if (blockId == 44 && chunk.GetMetadata(x, yi, z) == 15) { chunk.SetMetadata(x, yi, z, 14); } else if (blockId == 3 && chunk.GetMetadata(x, yi, z) == 1) { // Dirt Course => (Grass Path) chunk.SetBlock(x, yi, z, 198); chunk.SetMetadata(x, yi, z, 0); } else if (blockId == 3 && chunk.GetMetadata(x, yi, z) == 2) { // Dirt Podzol => (Podzol) chunk.SetBlock(x, yi, z, 243); chunk.SetMetadata(x, yi, z, 0); } var block = BlockFactory.GetBlockById(chunk.GetBlock(x, yi, z)); if (block.LightLevel > 0) { block.Coordinates = new BlockCoordinates(x + (16 * chunk.x), yi, z + (16 * chunk.z)); LightSources.Enqueue(block); } } } } }
private void PopulateChunk(ChunkColumn chunk) { int trees = new Random().Next(0, 10); int[,] treeBasePositions = new int[trees, 2]; for (int t = 0; t < trees; t++) { int x = new Random().Next(1, 16); int z = new Random().Next(1, 16); treeBasePositions[t, 0] = x; treeBasePositions[t, 1] = z; } for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { int stoneHeight = (int)Math.Floor(stoneBaseHeight); stoneHeight += GetNoise(chunk.x * 16 + x, chunk.z * 16 + z, stoneMountainFrequency, (int)Math.Floor(stoneMountainHeight)); if (stoneHeight < stoneMinHeight) { stoneHeight = (int)Math.Floor(stoneMinHeight); } stoneHeight += GetNoise(chunk.x * 16 + x, chunk.z * 16 + z, stoneBaseNoise, (int)Math.Floor(stoneBaseNoiseHeight)); int dirtHeight = stoneHeight + (int)Math.Floor(dirtBaseHeight); dirtHeight += GetNoise(chunk.x * 16 + x, chunk.z * 16 + z, dirtNoise, (int)Math.Floor(dirtNoiseHeight)); for (int y = 0; y < 256; y++) { //float y2 = Get3DNoise(chunk.X*16, y, chunk.Z*16, stoneBaseNoise, (int) Math.Floor(stoneBaseNoiseHeight)); if (y <= stoneHeight) { chunk.SetBlock(x, y, z, 1); //Diamond ore if (GetRandomNumber(0, 2500) < 5) { chunk.SetBlock(x, y, z, 56); } //Coal Ore if (GetRandomNumber(0, 1500) < 50) { chunk.SetBlock(x, y, z, 16); } //Iron Ore if (GetRandomNumber(0, 2500) < 30) { chunk.SetBlock(x, y, z, 15); } //Gold Ore if (GetRandomNumber(0, 2500) < 20) { chunk.SetBlock(x, y, z, 14); } } if (y < waterLevel) //FlowingWater :) { if (chunk.GetBlock(x, y, z) == 2 || chunk.GetBlock(x, y, z) == 3) //Grass or Dirt? { if (GetRandomNumber(1, 40) == 5 && y < waterLevel - 4) { chunk.SetBlock(x, y, z, 82); //Clay } else { chunk.SetBlock(x, y, z, 12); //Sand } } if (y < waterLevel - 3) { chunk.SetBlock(x, y + 1, z, 8); //FlowingWater } } if (y <= dirtHeight && y >= stoneHeight) { chunk.SetBlock(x, y, z, 3); //Dirt chunk.SetBlock(x, y + 1, z, 2); //Grass Block if (y > waterLevel) { //Grass if (GetRandomNumber(0, 5) == 2) { chunk.SetBlock(x, y + 2, z, 31); chunk.SetMetadata(x, y + 2, z, 1); } //flower if (GetRandomNumber(0, 65) == 8) { int meta = GetRandomNumber(0, 8); chunk.SetBlock(x, y + 2, z, 38); chunk.SetMetadata(x, y + 2, z, (byte)meta); } for (int pos = 0; pos < trees; pos++) { if (treeBasePositions[pos, 0] < 14 && treeBasePositions[pos, 0] > 4 && treeBasePositions[pos, 1] < 14 && treeBasePositions[pos, 1] > 4) { if (y < waterLevel + 2) { break; } if (chunk.GetBlock(treeBasePositions[pos, 0], y + 1, treeBasePositions[pos, 1]) == 2) { if (y == dirtHeight) { GenerateTree(chunk, treeBasePositions[pos, 0], y + 1, treeBasePositions[pos, 1]); } } } } } } if (y == 0) { chunk.SetBlock(x, y, z, 7); } } } } }
public static ChunkColumn GetChunk(ChunkCoordinates coordinates, string basePath, IWorldProvider generator, int yoffset) { int width = 32; int depth = 32; int rx = coordinates.X >> 5; int rz = coordinates.Z >> 5; string filePath = Path.Combine(basePath, string.Format(@"region\r.{0}.{1}.mca", rx, rz)); if (!File.Exists(filePath)) { return(generator.GenerateChunkColumn(coordinates)); } using (var regionFile = File.OpenRead(filePath)) { byte[] buffer = new byte[8192]; regionFile.Read(buffer, 0, 8192); int xi = (coordinates.X % width); if (xi < 0) { xi += 32; } int zi = (coordinates.Z % depth); if (zi < 0) { zi += 32; } int tableOffset = (xi + zi * width) * 4; regionFile.Seek(tableOffset, SeekOrigin.Begin); byte[] offsetBuffer = new byte[4]; regionFile.Read(offsetBuffer, 0, 3); Array.Reverse(offsetBuffer); int offset = BitConverter.ToInt32(offsetBuffer, 0) << 4; int length = regionFile.ReadByte(); if (offset == 0 || length == 0) { return(generator.GenerateChunkColumn(coordinates)); } regionFile.Seek(offset, SeekOrigin.Begin); byte[] waste = new byte[4]; regionFile.Read(waste, 0, 4); int compressionMode = regionFile.ReadByte(); var nbt = new NbtFile(); nbt.LoadFromStream(regionFile, NbtCompression.ZLib); NbtTag dataTag = nbt.RootTag["Level"]; NbtList sections = dataTag["Sections"] as NbtList; ChunkColumn chunk = new ChunkColumn { x = coordinates.X, z = coordinates.Z, biomeId = dataTag["Biomes"].ByteArrayValue }; for (int i = 0; i < chunk.biomeId.Length; i++) { if (chunk.biomeId[i] > 22) { chunk.biomeId[i] = 0; } } if (chunk.biomeId.Length > 256) { throw new Exception(); } // This will turn into a full chunk column foreach (NbtTag sectionTag in sections) { int sy = sectionTag["Y"].ByteValue * 16; byte[] blocks = sectionTag["Blocks"].ByteArrayValue; byte[] data = sectionTag["Data"].ByteArrayValue; NbtTag addTag = sectionTag["Add"]; byte[] adddata = new byte[2048]; if (addTag != null) { adddata = addTag.ByteArrayValue; } byte[] blockLight = sectionTag["BlockLight"].ByteArrayValue; byte[] skyLight = sectionTag["SkyLight"].ByteArrayValue; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { int yi = sy + y - yoffset; if (yi < 0 || yi >= 128) { continue; } int anvilIndex = y * 16 * 16 + z * 16 + x; int blockId = blocks[anvilIndex] + (Nibble4(adddata, anvilIndex) << 8); // Anvil to PE friendly converstion if (blockId == 125) { blockId = 5; } else if (blockId == 126) { blockId = 158; } else if (blockId == 75) { blockId = 50; } else if (blockId == 76) { blockId = 50; } else if (blockId == 123) { blockId = 89; } else if (blockId == 124) { blockId = 89; } else if (blockId == 152) { blockId = 73; } else if (_ignore.BinarySearch(blockId) >= 0) { blockId = 0; } else if (_gaps.BinarySearch(blockId) >= 0) { Debug.WriteLine("Missing material: " + blockId); blockId = 133; } if (blockId > 255) { blockId = 41; } if (yi == 127 && blockId != 0) { blockId = 30; } if (yi == 0 && (blockId == 8 || blockId == 9 /*|| blockId == 0*/)) { blockId = 7; } //if (blockId != 0) blockId = 41; chunk.SetBlock(x, yi, z, (byte)blockId); chunk.SetMetadata(x, yi, z, Nibble4(data, anvilIndex)); chunk.SetBlocklight(x, yi, z, Nibble4(blockLight, anvilIndex)); chunk.SetSkylight(x, yi, z, Nibble4(skyLight, anvilIndex)); } } } } NbtList entities = dataTag["Entities"] as NbtList; NbtList blockEntities = dataTag["TileEntities"] as NbtList; if (blockEntities != null) { foreach (var nbtTag in blockEntities) { var blockEntityTag = (NbtCompound)nbtTag; string entityId = blockEntityTag["id"].StringValue; int x = blockEntityTag["x"].IntValue; int y = blockEntityTag["y"].IntValue - yoffset; int z = blockEntityTag["z"].IntValue; blockEntityTag["y"] = new NbtInt("y", y); BlockEntity blockEntity = BlockEntityFactory.GetBlockEntityById(entityId); if (blockEntity != null) { blockEntityTag.Name = string.Empty; chunk.SetBlockEntity(new BlockCoordinates(x, y, z), blockEntityTag); } } } NbtList tileTicks = dataTag["TileTicks"] as NbtList; chunk.isDirty = false; return(chunk); } }
public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates) { lock (_chunkCache) { ChunkColumn cachedChunk; if (_chunkCache.TryGetValue(chunkCoordinates, out cachedChunk)) { return(cachedChunk); } ChunkColumn chunk = new ChunkColumn(); chunk.x = chunkCoordinates.X; chunk.z = chunkCoordinates.Z; int h = PopulateChunk(chunk); chunk.SetBlock(0, h + 1, 0, 7); chunk.SetBlock(1, h + 1, 0, 41); chunk.SetBlock(2, h + 1, 0, 41); chunk.SetBlock(3, h + 1, 0, 41); chunk.SetBlock(3, h + 1, 0, 41); //chunk.SetBlock(6, h + 1, 6, 57); chunk.SetBlock(6, h, 9, 63); chunk.SetMetadata(6, h, 9, 12); var blockEntity = GetBlockEntity((chunkCoordinates.X * 16) + 6, h, (chunkCoordinates.Z * 16) + 9); chunk.SetBlockEntity(blockEntity.Coordinates, blockEntity.GetCompound()); if (chunkCoordinates.X == 1 && chunkCoordinates.Z == 1) { for (int x = 0; x < 10; x++) { for (int z = 0; z < 10; z++) { for (int y = h - 2; y < h; y++) { chunk.SetBlock(x, y, z, 8); } } } } if (chunkCoordinates.X == 3 && chunkCoordinates.Z == 1) { for (int x = 0; x < 10; x++) { for (int z = 0; z < 10; z++) { for (int y = h - 1; y < h; y++) { chunk.SetBlock(x, y, z, 10); } } } } for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 127; y != 0; y--) { if (chunk.GetBlock(x, y, z) == 0x00) { chunk.SetSkylight(x, y, z, 0xff); } else { chunk.SetSkylight(x, y, z, 0x00); } } } } // Cache chunk.GetBatch(); _chunkCache[chunkCoordinates] = chunk; return(chunk); } }
public static ChunkColumn GetChunk(ChunkCoordinates coordinates, string basePath, IWorldProvider generator, int yoffset) { int width = 32; int depth = 32; int rx = coordinates.X >> 5; int rz = coordinates.Z >> 5; string filePath = Path.Combine(basePath, string.Format(@"region{2}r.{0}.{1}.mca", rx, rz, Path.DirectorySeparatorChar)); if (!File.Exists(filePath)) { return(generator?.GenerateChunkColumn(coordinates)); //return new ChunkColumn //{ // x = coordinates.X, // z = coordinates.Z, //}; } using (var regionFile = File.OpenRead(filePath)) { byte[] buffer = new byte[8192]; regionFile.Read(buffer, 0, 8192); int xi = (coordinates.X % width); if (xi < 0) { xi += 32; } int zi = (coordinates.Z % depth); if (zi < 0) { zi += 32; } int tableOffset = (xi + zi * width) * 4; regionFile.Seek(tableOffset, SeekOrigin.Begin); byte[] offsetBuffer = new byte[4]; regionFile.Read(offsetBuffer, 0, 3); Array.Reverse(offsetBuffer); int offset = BitConverter.ToInt32(offsetBuffer, 0) << 4; int length = regionFile.ReadByte(); if (offset == 0 || length == 0) { return(generator?.GenerateChunkColumn(coordinates)); //return new ChunkColumn //{ // x = coordinates.X, // z = coordinates.Z, //}; } regionFile.Seek(offset, SeekOrigin.Begin); byte[] waste = new byte[4]; regionFile.Read(waste, 0, 4); int compressionMode = regionFile.ReadByte(); var nbt = new NbtFile(); nbt.LoadFromStream(regionFile, NbtCompression.ZLib); NbtTag dataTag = nbt.RootTag["Level"]; NbtList sections = dataTag["Sections"] as NbtList; ChunkColumn chunk = new ChunkColumn { x = coordinates.X, z = coordinates.Z, biomeId = dataTag["Biomes"].ByteArrayValue }; for (int i = 0; i < chunk.biomeId.Length; i++) { if (chunk.biomeId[i] > 22) { chunk.biomeId[i] = 0; } } if (chunk.biomeId.Length > 256) { throw new Exception(); } // This will turn into a full chunk column foreach (NbtTag sectionTag in sections) { int sy = sectionTag["Y"].ByteValue * 16; byte[] blocks = sectionTag["Blocks"].ByteArrayValue; byte[] data = sectionTag["Data"].ByteArrayValue; NbtTag addTag = sectionTag["Add"]; byte[] adddata = new byte[2048]; if (addTag != null) { adddata = addTag.ByteArrayValue; } byte[] blockLight = sectionTag["BlockLight"].ByteArrayValue; byte[] skyLight = sectionTag["SkyLight"].ByteArrayValue; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { int yi = sy + y - yoffset; if (yi < 0 || yi >= 128) { continue; } int anvilIndex = y * 16 * 16 + z * 16 + x; int blockId = blocks[anvilIndex] + (Nibble4(adddata, anvilIndex) << 8); Func <int, byte, byte> dataConverter = (i, b) => b; // Anvil to PE friendly converstion if (Convert.ContainsKey(blockId)) { dataConverter = Convert[blockId].Item2; blockId = Convert[blockId].Item1; } else if (Ignore.BinarySearch(blockId) >= 0) { blockId = 0; } else if (Gaps.BinarySearch(blockId) >= 0) { Log.WarnFormat("Missing material on convert: {0}", blockId); blockId = 133; } if (blockId > 255) { blockId = 41; } //if (yi == 127 && blockId != 0) blockId = 30; if (yi == 0 && (blockId == 8 || blockId == 9)) { blockId = 7; } chunk.SetBlock(x, yi, z, (byte)blockId); byte metadata = Nibble4(data, anvilIndex); metadata = dataConverter(blockId, metadata); chunk.SetMetadata(x, yi, z, metadata); chunk.SetBlocklight(x, yi, z, Nibble4(blockLight, anvilIndex)); chunk.SetSkylight(x, yi, z, Nibble4(skyLight, anvilIndex)); var block = BlockFactory.GetBlockById(chunk.GetBlock(x, yi, z)); if (block is BlockStairs || block is StoneSlab || block is WoodSlab) { chunk.SetSkylight(x, yi, z, 0xff); } if (blockId == 43 && chunk.GetMetadata(x, yi, z) == 7) { chunk.SetMetadata(x, yi, z, 6); } else if (blockId == 44 && chunk.GetMetadata(x, yi, z) == 7) { chunk.SetMetadata(x, yi, z, 6); } else if (blockId == 44 && chunk.GetMetadata(x, yi, z) == 15) { chunk.SetMetadata(x, yi, z, 14); } else if (blockId == 3 && chunk.GetMetadata(x, yi, z) == 1) { chunk.SetBlock(x, yi, z, 198); chunk.SetMetadata(x, yi, z, 0); } else if (blockId == 3 && chunk.GetMetadata(x, yi, z) == 2) { chunk.SetBlock(x, yi, z, 143); //Coarse Dirt => Pat chunk.SetMetadata(x, yi, z, 0); // Podzol => (Podzol) } } } } } NbtList entities = dataTag["Entities"] as NbtList; NbtList blockEntities = dataTag["TileEntities"] as NbtList; if (blockEntities != null) { foreach (var nbtTag in blockEntities) { var blockEntityTag = (NbtCompound)nbtTag.Clone(); string entityId = blockEntityTag["id"].StringValue; int x = blockEntityTag["x"].IntValue; int y = blockEntityTag["y"].IntValue - yoffset; int z = blockEntityTag["z"].IntValue; blockEntityTag["y"] = new NbtInt("y", y); BlockEntity blockEntity = BlockEntityFactory.GetBlockEntityById(entityId); if (blockEntity != null) { blockEntityTag.Name = string.Empty; if (blockEntity is Sign) { // Remove the JSON stuff and get the text out of extra data. // TAG_String("Text2"): "{"extra":["10c a loaf!"],"text":""}" CleanSignText(blockEntityTag, "Text1"); CleanSignText(blockEntityTag, "Text2"); CleanSignText(blockEntityTag, "Text3"); CleanSignText(blockEntityTag, "Text4"); } chunk.SetBlockEntity(new BlockCoordinates(x, y, z), blockEntityTag); } } } //NbtList tileTicks = dataTag["TileTicks"] as NbtList; chunk.isDirty = false; return(chunk); } }