Region command updated, ready for test release

This commit is contained in:
Justin Aquadro 2011-03-12 09:27:04 +00:00
parent 64f3f5e4a9
commit b6c4c0655f
5 changed files with 95 additions and 219 deletions

View file

@ -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.",

View file

@ -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);
}
}
}

View file

@ -61,7 +61,6 @@
<Compile Include="ChunkManager.cs" />
<Compile Include="FilteredChunkEnumerator.cs" />
<Compile Include="GenOres.cs" />
<Compile Include="Harness.cs" />
<Compile Include="MathHelper.cs" />
<Compile Include="NBT.cs" />
<Compile Include="NDesk\Options.cs" />

View file

@ -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();
}
public void ApplyChunk (NBT_Tree root)
Console.WriteLine("Affected Chunks: " + affectedChunks);
}
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,21 +241,21 @@ 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);
}
}
}
@ -248,10 +263,4 @@ namespace NBToolkit
}
}
}
int BlockIndex (int x, int y, int z)
{
return y + (z * 128 + x * 128 * 16);
}
}
}

View file

@ -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();
}
}
}