private void RenderChunk(Chunk c, Bitmap b, int offsetX, int offsetY) { int[] heightmap = (int[])c.Root["Level"]["HeightMap"]; TAG_Compound[] sections = new TAG_Compound[16]; int highest = -1; foreach (TAG t in (TAG[])c.Root["Level"]["Sections"]) { byte index = (byte)t["Y"]; if (index > highest) highest = index; sections[index] = (TAG_Compound)t; } //chunk exists but all blocks are air if (highest < 0) return; highest = ((highest + 1) * 16) - 1; if (highest > UpperLimit) highest = UpperLimit; if (highest < LowerLimit) highest = LowerLimit; TAG biomes = null; c.Root["Level"].TryGetValue("Biomes", out biomes); for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { int y = GetHeight(sections, x, z, highest, LowerLimit, Only, Exclude); if (y < LowerLimit) continue; byte id, data; GetBlock(sections, x, y, z, out id, out data); byte biome = 255; if(ConsiderBiomes && biomes != null) biome = ((byte[])biomes)[x + z * 16]; Color color = ColorPalette.Lookup(id, data, biome); if (Transparency) { y--; while (color.A < 255 && y >= LowerLimit) { GetBlock(sections, x, y, z, out id, out data); if (Only != null && !Only.Contains(id)) id = 0; if (Exclude != null && Exclude.Contains(id)) id = 0; Color c2 = ColorPalette.Lookup(id, data, biome); color = Blend(color, c2); y--; } } else color = Color.FromArgb(255, color.R, color.G, color.B); if (ShowHeight) { //brighten/darken by height; arbitrary value, but /seems/ to look okay color = AddtoColor(color, (int)(y / 1.7 - 42)); } b.SetPixel(offsetX + x, offsetY + z, color); } } }
private void RenderChunkBiomes(Chunk c, Bitmap b, int offsetX, int offsetY) { TAG t = null; if (c.Root["Level"].TryGetValue("Biomes", out t)) { byte[] biomes = (byte[])t; for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { byte biome = biomes[x + z * 16]; Color color = ColorPalette.Lookup(biome); b.SetPixel(offsetX + x, offsetY + z, color); } } } else { Color color = ColorPalette.Lookup(255); for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { b.SetPixel(offsetX + x, offsetY + z, color); } } } }
//http://www.minecraftwiki.net/wiki/Region_file_format public void Read(String path, int startX, int endX, int startZ, int endZ) { Chunks = new Chunk[32, 32]; Match m = Regex.Match(path, @"r\.(-?\d+)\.(-?\d+)\.mca"); Coords.X = int.Parse(m.Groups[1].Value); Coords.Z = int.Parse(m.Groups[2].Value); if (!File.Exists(path)) return; signal = new ManualResetEvent(false); taskCount = (endX - startX + 1) * (endZ - startZ + 1); byte[] header = new byte[8192]; using (MemoryMappedFile file = MemoryMappedFile.CreateFromFile(path, FileMode.Open)) { using (MemoryMappedViewStream reader = file.CreateViewStream()) { reader.Read(header, 0, 8192); for (int chunkZ = startZ; chunkZ <= endZ; chunkZ++) { for (int chunkX = startX; chunkX <= endX; chunkX++) { Chunk c = new Chunk(); c.Coords.X = Coords.X; c.Coords.Z = Coords.Z; c.Coords.RegiontoChunk(); c.Coords.Add(chunkX, chunkZ); int i = 4 * (chunkX + chunkZ * 32); byte[] temp = new byte[4]; temp[0] = 0; Array.Copy(header, i, temp, 1, 3); if (BitConverter.IsLittleEndian) Array.Reverse(temp); long offset = ((long)BitConverter.ToInt32(temp, 0)) * 4096; int length = header[i + 3] * 4096; temp = new byte[4]; Array.Copy(header, i + 4096, temp, 0, 4); if (BitConverter.IsLittleEndian) Array.Reverse(temp); c.Timestamp = BitConverter.ToInt32(temp, 0); if (offset == 0 && length == 0) { Chunks[chunkX, chunkZ] = c; if (Interlocked.Decrement(ref taskCount) == 0) signal.Set(); continue; } reader.Seek(offset, SeekOrigin.Begin); temp = new byte[4]; reader.Read(temp, 0, 4); if (BitConverter.IsLittleEndian) Array.Reverse(temp); int exactLength = BitConverter.ToInt32(temp, 0); c.CompressionType = (byte)reader.ReadByte(); c.RawData = new byte[exactLength - 1]; reader.Read(c.RawData, 0, exactLength - 1); Chunks[chunkX, chunkZ] = c; ThreadPool.QueueUserWorkItem(Decompress, c); } } reader.Close(); } } signal.WaitOne(); signal.Dispose(); signal = null; }
// DIRTY: this class can be done in a less confusing way! public static void AddToMesh(Chunk chunk, int x, int y, int z, int id, List<Vector3> vertices, List<int> triangles, List<Vector2> uv) { // top if (chunk == null || chunk.IsTransparent(x, y + 1, z)) AddFace(new Vector3(x, y + 1, z), id, Vector3.up, vertices, triangles, uv); // bottom if (chunk == null || chunk.IsTransparent(x,y - 1,z)) AddFace(new Vector3(x, y, z), id, Vector3.down, vertices, triangles, uv); // left if (chunk == null || chunk.IsTransparent(x - 1, y, z)) AddFace(new Vector3(x, y, z + 1), id, Vector3.left, vertices, triangles, uv); // right if (chunk == null || chunk.IsTransparent(x + 1, y, z)) AddFace(new Vector3(x + 1, y, z + 1), id, Vector3.right, vertices, triangles, uv); // front if (chunk == null || chunk.IsTransparent(x, y, z + 1)) AddFace(new Vector3(x, y, z + 1), id, Vector3.forward, vertices, triangles, uv); // back if (chunk == null || chunk.IsTransparent(x, y, z - 1)) AddFace(new Vector3(x, y, z), id, Vector3.back, vertices, triangles, uv); }
//http://www.minecraftwiki.net/wiki/Region_file_format public void Read(String path) { Chunks = new Chunk[32, 32]; Match m = Regex.Match(path, @"r\.(-?\d+)\.(-?\d+)\.mc[ar]"); Coords.X = int.Parse(m.Groups[1].Value); Coords.Z = int.Parse(m.Groups[2].Value); byte[] header = new byte[8192]; using (BinaryReader file = new BinaryReader(File.Open(path, FileMode.Open))) { file.Read(header, 0, 8192); for (int chunkZ = 0; chunkZ < 32; chunkZ++) { for (int chunkX = 0; chunkX < 32; chunkX++) { Chunk c = new Chunk(); c.Coords.X = Coords.X; c.Coords.Z = Coords.Z; c.Coords.RegiontoChunk(); c.Coords.Add(chunkX, chunkZ); int i = 4 * (chunkX + chunkZ * 32); byte[] temp = new byte[4]; temp[0] = 0; Array.Copy(header, i, temp, 1, 3); if (BitConverter.IsLittleEndian) Array.Reverse(temp); long offset = ((long)BitConverter.ToInt32(temp, 0)) * 4096; int length = header[i + 3] * 4096; temp = new byte[4]; Array.Copy(header, i + 4096, temp, 0, 4); if (BitConverter.IsLittleEndian) Array.Reverse(temp); c.Timestamp = BitConverter.ToInt32(temp, 0); if (offset == 0 && length == 0) { Chunks[chunkX, chunkZ] = c; continue; } file.BaseStream.Seek(offset, SeekOrigin.Begin); temp = new byte[4]; file.Read(temp, 0, 4); if (BitConverter.IsLittleEndian) Array.Reverse(temp); int exactLength = BitConverter.ToInt32(temp, 0); c.CompressionType = file.ReadByte(); if (c.CompressionType == 1) //GZip { c.RawData = new byte[exactLength - 1]; file.Read(c.RawData, 0, exactLength - 1); GZipStream decompress = new GZipStream(new MemoryStream(c.RawData), CompressionMode.Decompress); MemoryStream mem = new MemoryStream(); decompress.CopyTo(mem); mem.Seek(0, SeekOrigin.Begin); c.Root = new TAG_Compound(mem); } else if (c.CompressionType == 2) //Zlib { c.RawData = new byte[exactLength - 1]; file.Read(c.RawData, 0, exactLength - 1); ZlibStream decompress = new ZlibStream(new MemoryStream(c.RawData), CompressionMode.Decompress); MemoryStream mem = new MemoryStream(); decompress.CopyTo(mem); mem.Seek(0, SeekOrigin.Begin); c.Root = new TAG_Compound(mem); } else { throw new Exception("Unrecognized compression type"); } Chunks[chunkX, chunkZ] = c; } } file.Close(); } }
private static void RenderChunktobePopulated(Chunk c, Graphics g, Brush brush, int offsetX, int offsetY) { if (((byte)c.Root["Level"]["TerrainPopulated"]) == 0) { g.FillRectangle(brush, offsetX, offsetY, 16, 16); } }
private static void RenderChunkBiomes(Chunk c, Bitmap b, String[,] toolTips, int offsetX, int offsetY) { TAG t = null; if (c.Root["Level"].TryGetValue("Biomes", out t)) { byte[] biomes = (byte[])t; for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { byte biome = biomes[x + z * 16]; Color color; if (BiomeType.Biomes[biome] != null) { color = BiomeType.Biomes[biome].Color; toolTips[offsetX + x, offsetY + z] = BiomeType.Biomes[biome].Name; } else { color = Color.Black; toolTips[offsetX + x, offsetY + z] = String.Format("Unknown biome: {0}", biome); } b.SetPixel(offsetX + x, offsetY + z, color); } } } else { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { toolTips[offsetX + x, offsetY + z] = BiomeType.Biomes[(int)Biome.Unspecified].Name; b.SetPixel(offsetX + x, offsetY + z, BiomeType.Biomes[(int)Biome.Unspecified].Color); } } } }