From b6c4c0655f2eac8c7ff840bad8fff02f13ecc108 Mon Sep 17 00:00:00 2001 From: Justin Aquadro Date: Sat, 12 Mar 2011 09:27:04 +0000 Subject: [PATCH] Region command updated, ready for test release --- NBToolkit/NBToolkit/ChunkFilter.cs | 10 +- NBToolkit/NBToolkit/Harness.cs | 149 --------------------------- NBToolkit/NBToolkit/NBToolkit.csproj | 1 - NBToolkit/NBToolkit/Replace.cs | 143 +++++++++++++------------ NBToolkit/NBToolkit/TKOptions.cs | 11 ++ 5 files changed, 95 insertions(+), 219 deletions(-) delete mode 100644 NBToolkit/NBToolkit/Harness.cs diff --git a/NBToolkit/NBToolkit/ChunkFilter.cs b/NBToolkit/NBToolkit/ChunkFilter.cs index 67259de..eafaa57 100644 --- a/NBToolkit/NBToolkit/ChunkFilter.cs +++ b/NBToolkit/NBToolkit/ChunkFilter.cs @@ -156,9 +156,15 @@ namespace NBToolkit { _options = new OptionSet () { { "cxr|ChunkXRange=", "Include chunks with X-chunk coord between {0:V1} and {1:V2}, inclusive. V1 or V2 may be left blank.", - (v1, v2) => { _xAboveEq = Convert.ToInt32(v1); _xBelowEq = Convert.ToInt32(v2); } }, + (v1, v2) => { + try { _xAboveEq = Convert.ToInt32(v1); } catch (FormatException) { } + try { _xBelowEq = Convert.ToInt32(v2); } catch (FormatException) { } + } }, { "czr|ChunkZRange=", "Include chunks with Z-chunk coord between {0:V1} and {1:V2}, inclusive. V1 or V2 may be left blank.", - (v1, v2) => { _zAboveEq = Convert.ToInt32(v1); _zBelowEq = Convert.ToInt32(v2); } }, + (v1, v2) => { + try { _zAboveEq = Convert.ToInt32(v1); } catch (FormatException) { } + try { _zBelowEq = Convert.ToInt32(v2); } catch (FormatException) { } + } }, { "crv|ChunkInvertXZ", "Inverts the chunk selection created by --cxr and --czr when both options are used.", v => _invertXZ = true }, { "ci|ChunkInclude=", "Include chunks that contain blocks of type {ID}. This option is repeatable.", diff --git a/NBToolkit/NBToolkit/Harness.cs b/NBToolkit/NBToolkit/Harness.cs deleted file mode 100644 index 982d90b..0000000 --- a/NBToolkit/NBToolkit/Harness.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using NBT; - -namespace NBToolkit -{ - class Harness - { - public void Run (TKOptions opt, TKFilter filter) { - World world = new World(opt.OPT_WORLD); - RegionList regions = new RegionList(world.GetRegionManager()); - - int r = 0; - int c = 0; - //foreach (Region region in regions) { - // Console.WriteLine(region.GetFileName()); - - - foreach (Chunk chunk in new ChunkList(world.GetChunkManager())) { - //Console.WriteLine("Chunk " + chunk.X + ", " + chunk.Z); - c++; - // } - - //foreach (Chunk chunk in new ChunkList(world.GetChunkManager(), region)) { - // c++; - // } - - //r++; - /*for (int x = 0; x < ChunkManager.REGION_XLEN; x++) { - for (int z = 0; z < ChunkManager.REGION_ZLEN; z++) { - if (region.ChunkExists(x, z)) { - c++; - } - } - }*/ - } - Console.WriteLine("Region Count: " + r); - Console.WriteLine("Chunk Count: " + c); - - /*string[] regions = RegionFileCache.GetRegionFileList(opt.OPT_WORLD); - - foreach (string p in regions) { - Console.WriteLine(p); - RegionFile rfile = RegionFileCache.GetRegionFile(opt.OPT_WORLD, p); - - for (int x = 0; x < 32; x++) { - for (int z = 0; z < 32; z++) { - NBT_Tree tree = new NBT_Tree(rfile.GetChunkDataInputStream(x, z)); - - // Check that tree exists - if (tree == null || tree.getRoot() == null) { - continue; - } - - NBT_Tag level = tree.getRoot().findTagByName("Level"); - if (level == null) { - continue; - } - - NBT_Tag tagcx = level.findTagByName("xPos"); - NBT_Tag tagcz = level.findTagByName("zPos"); - - if (tagcx == null || tagcz == null) { - continue; - } - - int cx = tagcx.value.toInt().data; - int cz = tagcz.value.toInt().data; - - // Exclude chunks out of range - if (opt.CH_X_GE != null && cx < opt.CH_X_GE) { - continue; - } - if (opt.CH_X_LE != null && cx > opt.CH_X_LE) { - continue; - } - if (opt.CH_Z_GE != null && cz < opt.CH_Z_GE) { - continue; - } - if (opt.CH_Z_LE != null && cz > opt.CH_Z_LE) { - continue; - } - - // Verify that chunk contains all of the INCLUDE options - bool fail = false; - foreach (int v in opt.OPT_CH_INCLUDE) { - if (!BlockScan(level, v)) { - fail = true; - break; - } - } - - // Verify that chunk does not contain any EXCLUDE options - foreach (int v in opt.OPT_CH_EXCLUDE) { - if (BlockScan(level, v)) { - fail = true; - break; - } - } - - if (fail) { - continue; - } - - if (opt.OPT_V) { - Console.WriteLine("Processing Chunk ({0}, {1})", cx, cz); - } - - filter.ApplyChunk(tree); - - Stream zipStream = RegionFileCache.getChunkDataOutputStream(opt.OPT_WORLD, cx, cz); - tree.WriteTo(zipStream); - zipStream.Close(); - } - } - }*/ - } - - protected bool BlockScan (NBT_Tag level, int val) - { - NBT_Tag blocks = level.findTagByName("Blocks"); - if (blocks == null || blocks.type != NBT_Type.TAG_BYTE_ARRAY) { - return false; - } - - NBT_ByteArray blocks_ary = blocks.value.toByteArray(); - - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < 128; y++) { - int index = BlockIndex(x, y, z); - if (blocks_ary.data[index] == val) { - return true; - } - } - } - } - - return false; - } - - int BlockIndex (int x, int y, int z) - { - return y + (z * 128 + x * 128 * 16); - } - } -} diff --git a/NBToolkit/NBToolkit/NBToolkit.csproj b/NBToolkit/NBToolkit/NBToolkit.csproj index f6bd49c..2c491be 100644 --- a/NBToolkit/NBToolkit/NBToolkit.csproj +++ b/NBToolkit/NBToolkit/NBToolkit.csproj @@ -61,7 +61,6 @@ - diff --git a/NBToolkit/NBToolkit/Replace.cs b/NBToolkit/NBToolkit/Replace.cs index 88dd0a8..faff422 100644 --- a/NBToolkit/NBToolkit/Replace.cs +++ b/NBToolkit/NBToolkit/Replace.cs @@ -6,9 +6,10 @@ using NBT; namespace NBToolkit { - public class ReplaceOptions : TKOptions + public class ReplaceOptions : TKOptions, IChunkFilterable { - private OptionSet filterOpt = null; + private OptionSet _filterOpt = null; + private ChunkFilter _chunkFilter = null; public int? OPT_BEFORE = null; public int? OPT_AFTER = null; @@ -34,9 +35,10 @@ namespace NBToolkit public int? OPT_NEIGHBOR_T = null; public int? OPT_NEIGHBOR_B = null; - public ReplaceOptions (string[] args) : base(args) + public ReplaceOptions () + : base() { - filterOpt = new OptionSet() + _filterOpt = new OptionSet() { { "b|before=", "Replace instances of block type {ID} with another block type", v => OPT_BEFORE = Convert.ToInt32(v) % 256 }, @@ -48,25 +50,34 @@ namespace NBToolkit v => { OPT_PROB = Convert.ToDouble(v); OPT_PROB = Math.Max((double)OPT_PROB, 0.0); OPT_PROB = Math.Min((double)OPT_PROB, 1.0); } }, - { "bxa=", "Update blocks with X-coord equal to or above {VAL}", + /*{ "bxa=", "Update blocks with X-coord equal to or above {VAL}", v => BL_X_GE = Convert.ToInt32(v) }, { "bxb=", "Update blocks with X-coord equal to or below {VAL}", - v => BL_X_LE = Convert.ToInt32(v) }, - { "bxr=", "Update blocks with X-coord between {0:V1} and {1:V2} [inclusive]", - (v1, v2) => { BL_X_GE = Convert.ToInt32(v1); BL_X_LE = Convert.ToInt32(v2); } }, - { "bya=", "Update blocks with Y-coord equal to or above {VAL}", + v => BL_X_LE = Convert.ToInt32(v) },*/ + { "bxr|BlockXRange=", "Update blocks with X-coord between {0:V1} and {1:V2}, inclusive. V1 or V2 may be left blank.", + (v1, v2) => { + try { BL_X_GE = Convert.ToInt32(v1); } catch (FormatException) { } + try { BL_X_LE = Convert.ToInt32(v2); } catch (FormatException) { } + } }, + /*{ "bya=", "Update blocks with Y-coord equal to or above {VAL}", v => BL_Y_GE = Convert.ToInt32(v) }, { "byb=", "Update blocks with Y-coord equal to or below {VAL}", - v => BL_Y_LE = Convert.ToInt32(v) }, - { "byr=", "Update blocks with Y-coord between {0:V1} and {1:V2} [inclusive]", - (v1, v2) => { BL_Y_GE = Convert.ToInt32(v1); BL_Y_LE = Convert.ToInt32(v2); } }, - { "bza=", "Update blocks with Z-coord equal to or above {VAL}", + v => BL_Y_LE = Convert.ToInt32(v) },*/ + { "byr|BlockYRange=", "Update blocks with Y-coord between {0:V1} and {1:V2}, inclusive. V1 or V2 may be left blank", + (v1, v2) => { + try { BL_Y_GE = Convert.ToInt32(v1); } catch (FormatException) { } + try { BL_Y_LE = Convert.ToInt32(v2); } catch (FormatException) { } + } }, + /*{ "bza=", "Update blocks with Z-coord equal to or above {VAL}", v => BL_Z_GE = Convert.ToInt32(v) }, { "bzb=", "Update blocks with Z-coord equal to or below {VAL}", - v => BL_Z_LE = Convert.ToInt32(v) }, - { "bzr=", "Update blocks with Z-coord between {0:V1} and {1:V2} [inclusive]", - (v1, v2) => { BL_Z_GE = Convert.ToInt32(v1); BL_Z_LE = Convert.ToInt32(v2); } }, - { "nb=", "Update blocks that have block type {ID} as any neighbor", + v => BL_Z_LE = Convert.ToInt32(v) },*/ + { "bzr|BlockZRange=", "Update blocks with Z-coord between {0:V1} and {1:V2}, inclusive. V1 or V2 may be left blank", + (v1, v2) => { + try { BL_Z_GE = Convert.ToInt32(v1); } catch (FormatException) { } + try { BL_Z_LE = Convert.ToInt32(v2); } catch (FormatException) { } + } }, + /*{ "nb=", "Update blocks that have block type {ID} as any neighbor", v => OPT_NEIGHBOR = Convert.ToInt32(v) % 256 }, { "nbs=", "Update blocks that have block type {ID} as any x/z neighbor", v => OPT_NEIGHBOR_SIDE = Convert.ToInt32(v) % 256 }, @@ -81,10 +92,24 @@ namespace NBToolkit { "nbza=", "Update blocks that have block type {ID} as their west neighbor", v => OPT_NEIGHBOR_W = Convert.ToInt32(v) % 256 }, { "nbzb=", "Update blocks that have block type {ID} as their east neighbor", - v => OPT_NEIGHBOR_E = Convert.ToInt32(v) % 256 }, + v => OPT_NEIGHBOR_E = Convert.ToInt32(v) % 256 },*/ }; - filterOpt.Parse(args); + _chunkFilter = new ChunkFilter(); + } + + public ReplaceOptions (string[] args) + : this() + { + Parse(args); + } + + public override void Parse (string[] args) + { + base.Parse(args); + + _filterOpt.Parse(args); + _chunkFilter.Parse(args); } public override void PrintUsage () @@ -93,7 +118,10 @@ namespace NBToolkit Console.WriteLine(); Console.WriteLine("Options for command 'replace':"); - filterOpt.WriteOptionDescriptions(Console.Out); + _filterOpt.WriteOptionDescriptions(Console.Out); + + Console.WriteLine(); + _chunkFilter.PrintUsage(); Console.WriteLine(); base.PrintUsage(); @@ -112,6 +140,11 @@ namespace NBToolkit throw new TKOptionException(); } } + + public IChunkFilter GetChunkFilter () + { + return _chunkFilter; + } } class Replace : TKFilter @@ -127,41 +160,23 @@ namespace NBToolkit public override void Run () { - throw new NotImplementedException(); + World world = new World(opt.OPT_WORLD); + + int affectedChunks = 0; + foreach (Chunk chunk in new FilteredChunkList(world.GetChunkManager(), opt.GetChunkFilter())) { + affectedChunks++; + + ApplyChunk(world, chunk); + chunk.Save(); + } + + Console.WriteLine("Affected Chunks: " + affectedChunks); } - public void ApplyChunk (NBT_Tree root) + public void ApplyChunk (World world, Chunk chunk) { - if (root == null || root.getRoot() == null) { - return; - } - - NBT_Tag level = root.getRoot().findTagByName("Level"); - if (level == null || level.type != NBT_Type.TAG_COMPOUND) { - return; - } - - NBT_Tag blocks = level.findTagByName("Blocks"); - if (blocks == null || blocks.type != NBT_Type.TAG_BYTE_ARRAY) { - return; - } - - NBT_Tag data = level.findTagByName("Data"); - if (data == null || data.type != NBT_Type.TAG_BYTE_ARRAY) { - return; - } - - NBT_Tag xPos = level.findTagByName("xPos"); - NBT_Tag zPos = level.findTagByName("zPos"); - if (xPos == null || zPos == null || xPos.type != NBT_Type.TAG_INT || zPos.type != NBT_Type.TAG_INT) { - return; - } - - int xBase = xPos.value.toInt().data * 16; - int zBase = zPos.value.toInt().data * 16; - - NBT_ByteArray blocks_ary = blocks.value.toByteArray(); - NBT_ByteArray data_ary = data.value.toByteArray(); + int xBase = chunk.X * BlockManager.CHUNK_XLEN; + int zBase = chunk.Z * BlockManager.CHUNK_ZLEN; // Determine X range int xmin = 0; @@ -226,32 +241,26 @@ namespace NBToolkit } } + int lx = x & BlockManager.CHUNK_XMASK; + int ly = y & BlockManager.CHUNK_YMASK; + int lz = z & BlockManager.CHUNK_ZMASK; + // Attempt to replace block - int index = BlockIndex(x, y, z); - if (blocks_ary.data[index] == opt.OPT_BEFORE) { - blocks_ary.data[index] = (byte)opt.OPT_AFTER; + int oldBlock = chunk.GetBlockID(lx , ly, lz); + if (oldBlock == opt.OPT_BEFORE) { + chunk.SetBlockID(lx, ly, lz, (int)opt.OPT_AFTER); if (opt.OPT_VV) { - Console.WriteLine("Replaced block at {0},{1},{2}", x, y, z); + Console.WriteLine("Replaced block at {0},{1},{2}", lx, ly, lz); } if (opt.OPT_DATA != null) { - if (index % 2 == 0) { - data_ary.data[index / 2] = (byte)((data_ary.data[index / 2] & 0xF0) | (int)opt.OPT_DATA); - } - else { - data_ary.data[index / 2] = (byte)((data_ary.data[index / 2] & 0x0F) | ((int)opt.OPT_DATA << 4)); - } + chunk.SetBlockData(lx, ly, lz, (int)opt.OPT_DATA); } } } } } } - - int BlockIndex (int x, int y, int z) - { - return y + (z * 128 + x * 128 * 16); - } } } diff --git a/NBToolkit/NBToolkit/TKOptions.cs b/NBToolkit/NBToolkit/TKOptions.cs index 67bb762..5d9796b 100644 --- a/NBToolkit/NBToolkit/TKOptions.cs +++ b/NBToolkit/NBToolkit/TKOptions.cs @@ -17,6 +17,7 @@ namespace NBToolkit private OptionSet commonOpt = null; public string OPT_WORLD = ""; + public string OPT_REGION = "region"; // Verbosity public bool OPT_V = false; @@ -31,6 +32,8 @@ namespace NBToolkit v => OPT_WORLD = v }, { "h|help", "Print this help message", v => OPT_HELP = true }, + { "nether", "Update the Nether instead of the main region", + v => OPT_REGION = "DIM-1/region" }, { "v", "Verbose output", v => OPT_V = true }, { "vv", "Very verbose output", @@ -77,6 +80,14 @@ namespace NBToolkit throw new TKOptionException(); } + + if (!Directory.Exists(Path.Combine(OPT_WORLD, OPT_REGION))) { + Console.WriteLine("Error: The supplied world path does not contain region: " + OPT_REGION); + Console.WriteLine(); + this.PrintUsage(); + + throw new TKOptionException(); + } } }