private static Schematic LoadSchematic(NbtFile nbtFile) { RawSchematic raw = LoadRaw(nbtFile); HashSet <Block> blocks = GetBlocks(raw); string name = Path.GetFileNameWithoutExtension(nbtFile.FileName); Schematic schematic = new Schematic(name, raw.Width, raw.Heigth, raw.Length, blocks); schematic.Width *= (short)_scale; schematic.Heigth *= (short)_scale; schematic.Length *= (short)_scale; return(schematic); }
private static HashSet <Block> GetBlocks(RawSchematic rawSchematic) { if (rawSchematic.Heigth > 2016 || rawSchematic.Length > 2016 || rawSchematic.Width > 2016) { throw new Exception("Schematic is too big"); } Console.WriteLine($"[LOG] Started to read all blocks of the schematic..."); Console.WriteLine($"[INFO] Raw schematic Width: {rawSchematic.Width}"); Console.WriteLine($"[INFO] Raw schematic Length: {rawSchematic.Length}"); Console.WriteLine($"[INFO] Raw schematic Height: {rawSchematic.Heigth}"); Console.WriteLine($"[INFO] Raw schematic total blocks: {rawSchematic.Data.Length}"); Console.WriteLine($"[INFO] Memory: {rawSchematic.Data.Length * Marshal.SizeOf(typeof(Block))} bytes"); WidthSchematic = (short)(rawSchematic.Width * _scale); LengthSchematic = (short)(rawSchematic.Length * _scale); HeightSchematic = (short)(rawSchematic.Heigth * _scale); //Sorted by height (bottom to top) then length then width -- the index of the block at X,Y,Z is (Y×length + Z)×width + X. ConcurrentBag <Block> blocks = new ConcurrentBag <Block>(); int minY = Math.Max(_ignoreMinY, 0); int maxY = Math.Min(_ignoreMaxY, rawSchematic.Heigth); Parallel.For(minY, (maxY * _scale), y => { for (int z = 0; z < (rawSchematic.Length * _scale); z++) { for (int x = 0; x < (rawSchematic.Width * _scale); x++) { int yProgress = (y / _scale); int zProgress = (z / _scale); int xProgress = (x / _scale); int index = (yProgress * rawSchematic.Length + zProgress) * rawSchematic.Width + xProgress; int blockId = rawSchematic.Blocks[index]; if (blockId != 0) { Block block = new Block((short)x, (short)y, (short)z, Extensions.Extensions.GetBlockColor(rawSchematic.Blocks[index], rawSchematic.Data[index]).ColorToUInt()); if ((_excavate && IsBlockConnectedToAir(rawSchematic, block, minY, maxY) || !_excavate)) { blocks.Add(block); } } } } }); return(blocks.ToHashSet()); }
private static RawSchematic LoadRaw(NbtFile nbtFile) { RawSchematic raw = new RawSchematic(); var rootTag = nbtFile.RootTag; foreach (NbtTag tag in rootTag.Tags) { switch (tag.Name) { case "Width": //Short raw.Width = tag.ShortValue; WidthSchematic = raw.Width; break; case "Height": //Short raw.Heigth = tag.ShortValue; HeightSchematic = raw.Heigth; break; case "Length": //Short raw.Length = tag.ShortValue; break; case "Blocks": //ByteArray raw.Blocks = tag.ByteArrayValue; break; case "Data": //ByteArray raw.Data = tag.ByteArrayValue; break; case "Entities": //List break; //Ignore case "TileEntities": //List break; case "Icon": //Compound break; //Ignore case "SchematicaMapping": //Compound tag.ToString(); break; //Ignore default: break; } } return(raw); }
private static bool IsBlockConnectedToAir(RawSchematic rawSchematic, Block block, int minY, int maxY) { if (block.X - 1 >= 0 && block.X + 1 < rawSchematic.Width && block.Y - 1 >= minY && block.Y + 1 < maxY && block.Z - 1 >= 0 && block.Z < rawSchematic.Length) { int indexLeftX = (block.Y * rawSchematic.Length + block.Z) * rawSchematic.Width + (block.X - 1); int indexRightX = (block.Y * rawSchematic.Length + block.Z) * rawSchematic.Width + (block.X + 1); int indexTop = ((block.Y + 1) * rawSchematic.Length + block.Z) * rawSchematic.Width + block.X; int indexBottom = ((block.Y - 1) * rawSchematic.Length + block.Z) * rawSchematic.Width + block.X; int indexAhead = (block.Y * rawSchematic.Length + block.Z + 1) * rawSchematic.Width + block.X; int indexBehind = (block.Y * rawSchematic.Length + block.Z - 1) * rawSchematic.Width + block.X; return(rawSchematic.Blocks[indexLeftX] == 0 || rawSchematic.Blocks[indexRightX] == 0 || rawSchematic.Blocks[indexTop] == 0 || rawSchematic.Blocks[indexBottom] == 0 || rawSchematic.Blocks[indexAhead] == 0 || rawSchematic.Blocks[indexBehind] == 0); } return(false); }