diff --git a/NBToolkit/ChunkFilter.cs b/NBToolkit/ChunkFilter.cs index eafaa57..c832f3a 100644 --- a/NBToolkit/ChunkFilter.cs +++ b/NBToolkit/ChunkFilter.cs @@ -29,6 +29,8 @@ namespace NBToolkit bool IncludeMatchAll { get; } bool ExcludeMatchAny { get; } bool ExcludeMatchAll { get; } + + double? ProbMatch { get; } } public class ChunkFilter : IOptions, IChunkFilter @@ -46,110 +48,78 @@ namespace NBToolkit protected bool _includeAny = true; protected bool _excludeAny = true; + protected double? _prob = null; + protected OptionSet _options; public int? XAboveEq { - get - { - return _xAboveEq; - } + get { return _xAboveEq; } } public int? XBelowEq { - get - { - return _xBelowEq; - } + get { return _xBelowEq; } } public int? ZAboveEq { - get - { - return _zAboveEq; - } + get { return _zAboveEq; } } public int? ZBelowEq { - get - { - return _zBelowEq; - } + get { return _zBelowEq; } } public bool InvertXZ { - get - { - return _invertXZ; - } + get { return _invertXZ; } } public IEnumerable IncludedBlocks { - get - { - return _includedBlocks; - } + get { return _includedBlocks; } } public IEnumerable ExcludedBlocks { - get - { - return _excludedBlocks; - } + get { return _excludedBlocks; } } public int IncludedBlockCount { - get - { - return _includedBlocks.Count; - } + get { return _includedBlocks.Count; } } public int ExcludedBlockCount { - get - { - return _excludedBlocks.Count; - } + get { return _excludedBlocks.Count; } } public bool IncludeMatchAny { - get - { - return _includeAny; - } + get { return _includeAny; } } public bool IncludeMatchAll { - get - { - return !_includeAny; - } + get { return !_includeAny; } } public bool ExcludeMatchAny { - get - { - return _excludeAny; - } + get { return _excludeAny; } } public bool ExcludeMatchAll { - get - { - return !_excludeAny; - } + get { return !_excludeAny; } + } + + public double? ProbMatch + { + get { return _prob; } } public ChunkFilter () @@ -179,6 +149,8 @@ namespace NBToolkit v => _includeAny = false }, { "cxy|ChunkExcludeAny", "If multiple --cx options, chunk can match any of them to be excluded. (default)", v => _includeAny = true }, + { "cp|ChunkProbability=", "Selects a matching chunk with probability {VAL} (0.0-1.0)", + v => _prob = Convert.ToDouble(v) }, }; } diff --git a/NBToolkit/FilteredChunkManager.cs b/NBToolkit/FilteredChunkManager.cs index e23a3b3..b6169b1 100644 --- a/NBToolkit/FilteredChunkManager.cs +++ b/NBToolkit/FilteredChunkManager.cs @@ -45,6 +45,8 @@ namespace NBToolkit private IEnumerator _enum; + private static Random _rand = new Random(); + public ChunkEnumerator (IChunkManager cm, IChunkFilter filter) { _cm = cm; @@ -144,6 +146,14 @@ namespace NBToolkit } } + // Filter out randomly matching chunks (according to probability value) + if (_filter.ProbMatch != null) { + double r = _rand.NextDouble(); + if (r > _filter.ProbMatch) { + continue; + } + } + return true; } } @@ -214,6 +224,11 @@ namespace NBToolkit return _cm.SaveChunk(chunk); } + public ChunkRef SetChunk (int cx, int cz, Chunk chunk) + { + return _cm.SetChunk(cx, cz, chunk); + } + #endregion } } diff --git a/NBToolkit/NBToolkit.csproj b/NBToolkit/NBToolkit.csproj index dc5148c..7ec9529 100644 --- a/NBToolkit/NBToolkit.csproj +++ b/NBToolkit/NBToolkit.csproj @@ -57,6 +57,7 @@ + diff --git a/NBToolkit/Relight.cs b/NBToolkit/Relight.cs index 4bdc806..5bf5dcc 100644 --- a/NBToolkit/Relight.cs +++ b/NBToolkit/Relight.cs @@ -139,10 +139,10 @@ namespace NBToolkit } if (opt.BlockLight) { - //chunk.UpdateEdgeBlockLight(); + chunk.Blocks.StitchBlockLight(); } if (opt.SkyLight) { - //chunk.UpdateEdgeSkyLight(); + chunk.Blocks.StitchSkyLight(); } fcm.Save(); } diff --git a/NBToolkit/Replace.cs b/NBToolkit/Replace.cs index b375b8b..327f300 100644 --- a/NBToolkit/Replace.cs +++ b/NBToolkit/Replace.cs @@ -7,10 +7,11 @@ using Substrate; namespace NBToolkit { - public class ReplaceOptions : TKOptions, IChunkFilterable + public class ReplaceOptions : TKOptions, IChunkFilterable, IBlockFilterable { private OptionSet _filterOpt = null; private ChunkFilter _chunkFilter = null; + private BlockFilter _blockFilter = null; public int? OPT_BEFORE = null; public int? OPT_AFTER = null; @@ -41,13 +42,13 @@ namespace NBToolkit { _filterOpt = new OptionSet() { - { "b|before=", "Replace instances of block type {ID} with another block type", - v => OPT_BEFORE = Convert.ToInt32(v) % 256 }, + /*{ "b|before=", "Replace instances of block type {ID} with another block type. This option is repeatable.", + v => _includedBlocks.Add(Convert.ToInt32(v) % 256) },*/ { "a|after=", "Replace the selected blocks with block type {ID}", v => OPT_AFTER = Convert.ToInt32(v) % 256 }, { "d|data=", "Set the new block's data value to {VAL} (0-15)", v => OPT_DATA = Convert.ToInt32(v) % 16 }, - { "p|prob=", "Replace any matching block with probability {VAL} (0.0-1.0)", + /*{ "p|prob=", "Replace any matching block with probability {VAL} (0.0-1.0)", v => { OPT_PROB = Convert.ToDouble(v, new CultureInfo("en-US")); OPT_PROB = Math.Max((double)OPT_PROB, 0.0); OPT_PROB = Math.Min((double)OPT_PROB, 1.0); } }, @@ -65,7 +66,7 @@ namespace NBToolkit (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", @@ -85,6 +86,7 @@ namespace NBToolkit }; _chunkFilter = new ChunkFilter(); + _blockFilter = new BlockFilter(); } public ReplaceOptions (string[] args) @@ -99,11 +101,12 @@ namespace NBToolkit _filterOpt.Parse(args); _chunkFilter.Parse(args); + _blockFilter.Parse(args); } public override void PrintUsage () { - Console.WriteLine("Usage: nbtoolkit replace -b -a [options]"); + Console.WriteLine("Usage: nbtoolkit replace -a [options]"); Console.WriteLine(); Console.WriteLine("Options for command 'replace':"); @@ -112,6 +115,9 @@ namespace NBToolkit Console.WriteLine(); _chunkFilter.PrintUsage(); + Console.WriteLine(); + _blockFilter.PrintUsage(); + Console.WriteLine(); base.PrintUsage(); } @@ -121,8 +127,8 @@ namespace NBToolkit base.SetDefaults(); // Check for required parameters - if (OPT_BEFORE == null || OPT_AFTER == null) { - Console.WriteLine("Error: You must specify a before and after Block ID"); + if (OPT_AFTER == null) { + Console.WriteLine("Error: You must specify a replacement Block ID"); Console.WriteLine(); PrintUsage(); @@ -134,6 +140,11 @@ namespace NBToolkit { return _chunkFilter; } + + public IBlockFilter GetBlockFilter () + { + return _blockFilter; + } } public class Replace : TKFilter @@ -167,6 +178,8 @@ namespace NBToolkit public void ApplyChunk (INBTWorld world, ChunkRef chunk) { + IBlockFilter opt_b = opt.GetBlockFilter(); + int xBase = chunk.X * chunk.Blocks.XDim; int zBase = chunk.Z * chunk.Blocks.ZDim; @@ -174,11 +187,11 @@ namespace NBToolkit int xmin = 0; int xmax = 15; - if (opt.BL_X_GE != null) { - xmin = (int)opt.BL_X_GE - xBase; + if (opt_b.XAboveEq != null) { + xmin = (int)opt_b.XAboveEq - xBase; } - if (opt.BL_X_LE != null) { - xmax = (int)opt.BL_X_LE - xBase; + if (opt_b.XBelowEq != null) { + xmax = (int)opt_b.XBelowEq - xBase; } xmin = (xmin < 0) ? 0 : xmin; @@ -192,11 +205,11 @@ namespace NBToolkit int ymin = 0; int ymax = 127; - if (opt.BL_Y_GE != null) { - ymin = (int)opt.BL_Y_GE; + if (opt_b.YAboveEq != null) { + ymin = (int)opt_b.YAboveEq; } - if (opt.BL_Y_LE != null) { - ymax = (int)opt.BL_Y_LE; + if (opt_b.YBelowEq != null) { + ymax = (int)opt_b.YBelowEq; } if (ymin > ymax) { @@ -207,11 +220,11 @@ namespace NBToolkit int zmin = 0; int zmax = 15; - if (opt.BL_Z_GE != null) { - zmin = (int)opt.BL_Z_GE - zBase; + if (opt_b.ZAboveEq != null) { + zmin = (int)opt_b.ZAboveEq - zBase; } - if (opt.BL_Z_LE != null) { - zmax = (int)opt.BL_Z_LE - zBase; + if (opt_b.ZBelowEq != null) { + zmax = (int)opt_b.ZBelowEq - zBase; } zmin = (zmin < 0) ? 0 : zmin; @@ -221,35 +234,70 @@ namespace NBToolkit return; } + int xdim = chunk.Blocks.XDim; + int ydim = chunk.Blocks.YDim; + int zdim = chunk.Blocks.ZDim; + // Process Chunk for (int y = ymin; y <= ymax; y++) { for (int x = xmin; x <= xmax; x++) { for (int z = zmin; z <= zmax; z++) { // Probability test - if (opt.OPT_PROB != null) { + if (opt_b.ProbMatch != null) { double c = rand.NextDouble(); - if (c > opt.OPT_PROB) { + if (c > opt_b.ProbMatch) { continue; } } - int lx = x & (chunk.Blocks.XDim - 1); - int ly = y & (chunk.Blocks.YDim - 1); - int lz = z & (chunk.Blocks.ZDim - 1); + int lx = x % xdim; + int ly = y % ydim; + int lz = z % zdim; - // Attempt to replace block + // Get the old block int oldBlock = chunk.Blocks.GetID(lx , ly, lz); - if (oldBlock == opt.OPT_BEFORE) { - chunk.Blocks.SetID(lx, ly, lz, (int)opt.OPT_AFTER); - /*if (opt.OPT_VV) { - Console.WriteLine("Replaced block at {0},{1},{2}", - chunk.BlockGlobalX(lx), chunk.BlockGlobalY(ly), chunk.BlockGlobalZ(lz)); - }*/ - - if (opt.OPT_DATA != null) { - chunk.Blocks.SetData(lx, ly, lz, (int)opt.OPT_DATA); + // Skip block if it doesn't match the inclusion list + if (opt_b.IncludedBlockCount > 0) { + bool match = false; + foreach (int ib in opt_b.IncludedBlocks) { + if (oldBlock == ib) { + match = true; + break; + } } + + if (!match) { + continue; + } + } + + // Skip block if it does match the exclusion list + if (opt_b.ExcludedBlockCount > 0) { + bool match = false; + foreach (int xb in opt_b.ExcludedBlocks) { + if (oldBlock == xb) { + match = true; + break; + } + } + + if (match) { + continue; + } + } + + // Replace the block + chunk.Blocks.SetID(lx, ly, lz, (int)opt.OPT_AFTER); + + if (opt.OPT_VV) { + int gx = chunk.X * xdim + lx; + int gz = chunk.Z * zdim + lz; + Console.WriteLine("Replaced block at {0},{1},{2}", gx, ly, gz); + } + + if (opt.OPT_DATA != null) { + chunk.Blocks.SetData(lx, ly, lz, (int)opt.OPT_DATA); } } }