diff --git a/NBToolkit/NBToolkit/BlockManager.cs b/NBToolkit/NBToolkit/BlockManager.cs new file mode 100644 index 0000000..e505510 --- /dev/null +++ b/NBToolkit/NBToolkit/BlockManager.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NBToolkit +{ + public class BlockManager + { + public const int MIN_X = -32000000; + public const int MAX_X = 32000000; + public const int MIN_Y = 0; + public const int MAX_Y = 128; + public const int MIN_Z = -32000000; + public const int MAX_Z = 32000000; + + public const int CHUNK_XLEN = 16; + public const int CHUNK_YLEN = 128; + public const int CHUNK_ZLEN = 16; + + public const int CHUNK_XLOG = 4; + public const int CHUNK_YLOG = 7; + public const int CHUNK_ZLOG = 4; + + public const int CHUNK_XMASK = 0xF; + public const int CHUNK_YMASK = 0x7F; + public const int CHUNK_ZMASK = 0xF; + + protected ChunkManager _chunkMan; + + public BlockManager (ChunkManager cm) + { + _chunkMan = cm; + } + + public int GetBlockID (int x, int y, int z) + { + if (x < MIN_X || x >= MAX_X) + return 0; + if (y < MIN_Y || y >= MAX_Y) + return 0; + if (z < MIN_Z || z >= MAX_Z) + return 0; + + Chunk c = GetChunk(x, y, z); + if (c == null) { + return 0; + } + + return c.GetBlockID(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); + } + + int GetBlockData (int x, int y, int z) { return 0; } + + int GetBlockLight (int x, int y, int z) { return 0; } + + int GetBlockSkylight (int x, int y, int z) { return 0; } + + void SetBlock (int x, int y, int z, int id, int data) { } + + public bool SetBlockID (int x, int y, int z, int id) + { + if (x < MIN_X || x >= MAX_X) + return false; + if (y < MIN_Y || y >= MAX_Y) + return false; + if (z < MIN_Z || z >= MAX_Z) + return false; + + Chunk c = GetChunk(x, y, z); + if (c == null) { + return false; + } + + return c.SetBlockID(x & CHUNK_XMASK, y, z & CHUNK_ZMASK, id); + } + + void SetBlockData (int x, int y, int z, int data) { } + + public Chunk GetChunk (int x, int y, int z) + { + x >>= CHUNK_XLOG; + z >>= CHUNK_ZLOG; + return _chunkMan.GetChunk(x, z); + } + } +} diff --git a/NBToolkit/NBToolkit/Chunk.cs b/NBToolkit/NBToolkit/Chunk.cs new file mode 100644 index 0000000..777ca08 --- /dev/null +++ b/NBToolkit/NBToolkit/Chunk.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Text; +using NBT; + +namespace NBToolkit +{ + public class Chunk + { + protected int _cx; + protected int _cz; + + protected NBT_Tree _nbt = null; + protected NBT_ByteArray _blocks = null; + + protected bool _dirty = false; + + protected ChunkManager _chunkMan; + + public Chunk (ChunkManager cm, int cx, int cz) + { + _chunkMan = cm; + _cx = cx; + _cz = cz; + } + + public int X + { + get + { + return _cx; + } + } + + public int Z + { + get + { + return _cz; + } + } + + public bool Save () + { + if (_dirty) { + if (SaveTree()) { + _dirty = false; + return true; + } + return false; + } + + return true; + } + + protected NBT_Tree GetTree () + { + if (_nbt != null) { + return _nbt; + } + + Region r = _chunkMan.GetRegion(_cx, _cz); + _nbt = r.GetChunkTree(_cx & ChunkManager.REGION_XMASK, _cz & ChunkManager.REGION_ZMASK); + + return _nbt; + } + + protected bool SaveTree () + { + if (_nbt != null) { + _blocks = null; + + Region r = _chunkMan.GetRegion(_cx, _cz); + return r.SaveChunkTree(_cx & ChunkManager.REGION_XMASK, _cz & ChunkManager.REGION_ZMASK, _nbt); + } + + return false; + } + + public int GetBlockID (int x, int y, int z) + { + if (_blocks == null) { + _blocks = GetTree().getRoot().findTagByName("Level").findTagByName("Blocks").value.toByteArray(); + } + + return _blocks.data[x << 11 | z << 7 | y]; + } + + public bool SetBlockID (int x, int y, int z, int id) + { + if (_blocks == null) { + _blocks = GetTree().getRoot().findTagByName("Level").findTagByName("Blocks").value.toByteArray(); + } + + int index = x << 11 | z << 7 | y; + if (_blocks.data[index] == id) { + return false; + } + + _blocks.data[index] = (byte)id; + + return true; + } + } +} diff --git a/NBToolkit/NBToolkit/ChunkEnumerator.cs b/NBToolkit/NBToolkit/ChunkEnumerator.cs new file mode 100644 index 0000000..b9e4909 --- /dev/null +++ b/NBToolkit/NBToolkit/ChunkEnumerator.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.IO; + +namespace NBToolkit +{ + public class ChunkList : IEnumerable + { + //private List _regions; + + private ChunkManager _cm = null; + private Region _region = null; + + // Constructor to enumerate a single region + public ChunkList (ChunkManager cm, Region region) + { + _cm = cm; + _region = region; + } + + // Constructor to enumerate all regions + public ChunkList (ChunkManager cm) + { + _cm = cm; + } + + IEnumerator IEnumerable.GetEnumerator () + { + return (IEnumerator)GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return (IEnumerator)GetEnumerator(); + } + + public ChunkEnumerator GetEnumerator () + { + return new ChunkEnumerator(_cm, _region); + } + } + + public class ChunkEnumerator : IEnumerator + { + protected Region _region; + protected ChunkManager _cm; + + protected RegionEnumerator _enum = null; + protected int _x = 0; + protected int _z = -1; + + public ChunkEnumerator (ChunkManager cm, Region region) + { + _cm = cm; + _region = region; + + if (_region == null) { + _enum = new RegionEnumerator(_cm.GetRegionManager()); + _enum.MoveNext(); + _region = _enum.Current; + } + } + + public bool MoveNext () + { + if (_enum == null) { + return MoveNextInRegion(); + } + else { + while (true) { + if (_x >= ChunkManager.REGION_XLEN) { + if (!_enum.MoveNext()) { + return false; + } + _x = 0; + _z = -1; + } + if (MoveNextInRegion()) { + return true; + } + } + } + } + + protected bool MoveNextInRegion () + { + for (; _x < ChunkManager.REGION_XLEN; _x++) { + for (_z++; _z < ChunkManager.REGION_ZLEN; _z++) { + if (_region.ChunkExists(_x, _z)) { + goto FoundNext; + } + } + _z = 0; + } + + FoundNext: + + return (_x < ChunkManager.REGION_XLEN); + } + + public void Reset () + { + if (_enum != null) { + _enum.Reset(); + _enum.MoveNext(); + _region = _enum.Current; + } + _x = 0; + _z = -1; + } + + void IDisposable.Dispose () { } + + object IEnumerator.Current + { + get + { + return Current; + } + } + + Chunk IEnumerator.Current + { + get + { + return Current; + } + } + + public Chunk Current + { + get + { + if (_x >= ChunkManager.REGION_XLEN) { + throw new InvalidOperationException(); + } + + return _cm.GetChunkInRegion(_region, _x, _z); + } + } + } +} diff --git a/NBToolkit/NBToolkit/ChunkKey.cs b/NBToolkit/NBToolkit/ChunkKey.cs new file mode 100644 index 0000000..7fb8e54 --- /dev/null +++ b/NBToolkit/NBToolkit/ChunkKey.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NBToolkit +{ + public class ChunkKey : IEquatable + { + protected int cx; + protected int cz; + + public ChunkKey (int _cx, int _cz) + { + cx = _cx; + cz = _cz; + } + + public bool Equals (ChunkKey ck) + { + return this.cx == ck.cx && this.cz == ck.cz; + } + + public override int GetHashCode () + { + return cx ^ cz; + } + } +} diff --git a/NBToolkit/NBToolkit/ChunkManager.cs b/NBToolkit/NBToolkit/ChunkManager.cs new file mode 100644 index 0000000..88943c9 --- /dev/null +++ b/NBToolkit/NBToolkit/ChunkManager.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NBToolkit +{ + public class ChunkManager + { + public const int REGION_XLEN = 32; + public const int REGION_ZLEN = 32; + + public const int REGION_XLOG = 5; + public const int REGION_ZLOG = 5; + + public const int REGION_XMASK = 0x1F; + public const int REGION_ZMASK = 0x1F; + + protected RegionManager _regionMan; + + protected Dictionary _cache; + + public ChunkManager (RegionManager rm) + { + _regionMan = rm; + _cache = new Dictionary(); + } + + public Chunk GetChunk (int cx, int cz) + { + ChunkKey k = new ChunkKey(cx, cz); + + Chunk c = null; + if (_cache.ContainsKey(k)) { + c = _cache[k].Target as Chunk; + } + else { + _cache.Add(k, new WeakReference(null)); + } + + if (c != null) { + return c; + } + + c = new Chunk(this, cx, cz); + _cache[k].Target = c; + + return c; + } + + public Chunk GetChunkInRegion (Region r, int lcx, int lcz) + { + int cx = r.X * REGION_XLEN + lcx; + int cz = r.Z * REGION_ZLEN + lcz; + return GetChunk(cx, cz); + } + + public Region GetRegion (int cx, int cz) + { + cx >>= REGION_XLOG; + cz >>= REGION_ZLOG; + return _regionMan.GetRegion(cx, cz); + } + + public RegionManager GetRegionManager () + { + return _regionMan; + } + } +} diff --git a/NBToolkit/NBToolkit/Harness.cs b/NBToolkit/NBToolkit/Harness.cs index 7dfdec5..8e5a422 100644 --- a/NBToolkit/NBToolkit/Harness.cs +++ b/NBToolkit/NBToolkit/Harness.cs @@ -9,7 +9,22 @@ namespace NBToolkit class Harness { public void Run (TKOptions opt, TKFilter filter) { - string[] regions = RegionFileCache.GetRegionFileList(opt.OPT_WORLD); + World world = new World(opt.OPT_WORLD); + RegionList regions = new RegionList(world.GetRegionManager()); + + foreach (Region region in regions) { + Console.WriteLine(region.GetFileName()); + + for (int x = 0; x < ChunkManager.REGION_XLEN; x++) { + for (int z = 0; z < ChunkManager.REGION_ZLEN; z++) { + if (!region.ChunkExists(x, z)) { + continue; + } + } + } + } + + /*string[] regions = RegionFileCache.GetRegionFileList(opt.OPT_WORLD); foreach (string p in regions) { Console.WriteLine(p); @@ -85,7 +100,7 @@ namespace NBToolkit zipStream.Close(); } } - } + }*/ } protected bool BlockScan (NBT_Tag level, int val) diff --git a/NBToolkit/NBToolkit/NBToolkit.csproj b/NBToolkit/NBToolkit/NBToolkit.csproj index 73d1615..09fb896 100644 --- a/NBToolkit/NBToolkit/NBToolkit.csproj +++ b/NBToolkit/NBToolkit/NBToolkit.csproj @@ -10,7 +10,7 @@ Properties NBToolkit NBToolkit - v3.0 + v2.0 512 publish\ true @@ -53,10 +53,17 @@ + + + + + + + @@ -64,6 +71,7 @@ + diff --git a/NBToolkit/NBToolkit/NBToolkit.suo b/NBToolkit/NBToolkit/NBToolkit.suo deleted file mode 100644 index ccc7273..0000000 Binary files a/NBToolkit/NBToolkit/NBToolkit.suo and /dev/null differ diff --git a/NBToolkit/NBToolkit/Oregen.cs b/NBToolkit/NBToolkit/Oregen.cs index 5a9351e..b49a87d 100644 --- a/NBToolkit/NBToolkit/Oregen.cs +++ b/NBToolkit/NBToolkit/Oregen.cs @@ -59,7 +59,7 @@ namespace NBToolkit { "max=", "Generates deposits no higher than depth {VAL} (0-127)", v => OPT_MAX = Convert.ToInt32(v) % 128 }, { "s|size=", "Generates deposits containing roughly up to {VAL} blocks", - v => OPT_MIN = Convert.ToInt32(v) % 128 }, + v => OPT_SIZE = Convert.ToInt32(v) % 128 }, { "oo=", "Generated deposits can replace other existing ores", v => OPT_OO = true }, { "oa=", "Generated deposits can replace any existing block (incl. air)", @@ -140,6 +140,95 @@ namespace NBToolkit } } + public class MathHelper + { + private static float[] trigTable = new float[65536]; + + static MathHelper () + { + for (int i = 0; i < 65536; i++) { + trigTable[i] = (float)Math.Sin(i * Math.PI * 2.0D / 65536.0D); + } + } + + public static float Sin(float angle) + { + return trigTable[((int)(angle * 10430.378F) & 0xFFFF)]; + } + + public static float Cos(float angle) { + return trigTable[((int)(angle * 10430.378F + 16384.0F) & 0xFFFF)]; + } + } + + public class NativeOreGen { + private int _blockId; + private int _size; + + private static Random rand = new Random(); + + public NativeOreGen(int blockId, int size) + { + _blockId = blockId; + _size = size; + } + + public bool GenerateDeposit (NBT_ByteArray blocks, NBT_ByteArray data, int x, int y, int z) + { + float rpi = (float)(rand.NextDouble() * Math.PI); + + double x1 = x + 8 + MathHelper.Sin(rpi) * _size / 8.0F; + double x2 = x + 8 - MathHelper.Sin(rpi) * _size / 8.0F; + double z1 = z + 8 + MathHelper.Cos(rpi) * _size / 8.0F; + double z2 = z + 8 - MathHelper.Cos(rpi) * _size / 8.0F; + + double y1 = y + rand.Next(3) + 2; + double y2 = y + rand.Next(3) + 2; + + for (int i = 0; i <= _size; i++) { + double xPos = x1 + (x2 - x1) * i / _size; + double yPos = y1 + (y2 - y1) * i / _size; + double zPos = z1 + (z2 - z1) * i / _size; + + double fuzz = rand.NextDouble() * _size / 16.0D; + double fuzzXZ = (MathHelper.Sin((float)(i * Math.PI / _size)) + 1.0F) * fuzz + 1.0D; + double fuzzY = (MathHelper.Sin((float)(i * Math.PI / _size)) + 1.0F) * fuzz + 1.0D; + + int xStart = (int)(xPos - fuzzXZ / 2.0D); + int yStart = (int)(yPos - fuzzY / 2.0D); + int zStart = (int)(zPos - fuzzXZ / 2.0D); + + int xEnd = (int)(xPos + fuzzXZ / 2.0D); + int yEnd = (int)(yPos + fuzzY / 2.0D); + int zEnd = (int)(zPos + fuzzXZ / 2.0D); + + for (int ix = xStart; ix <= xEnd; ix++) { + double xThresh = (ix + 0.5D - xPos) / (fuzzXZ / 2.0D); + if (xThresh * xThresh < 1.0D) { + for (int iy = yStart; iy <= yEnd; iy++) { + double yThresh = (iy + 0.5D - yPos) / (fuzzY / 2.0D); + if (xThresh * xThresh + yThresh * yThresh < 1.0D) { + for (int iz = zStart; iz <= zEnd; iz++) { + double zThresh = (iz + 0.5D - zPos) / (fuzzXZ / 2.0D); + if (xThresh * xThresh + yThresh * yThresh + zThresh * zThresh < 1.0D) { + //Apply + } + } + } + } + } + } + } + + return true; + } + + int BlockIndex (int x, int y, int z) + { + return y + (z * 128 + x * 128 * 16); + } + } + public class Oregen : TKFilter { public const int BLOCK_STONE = 1; diff --git a/NBToolkit/NBToolkit/Properties/AssemblyInfo.cs b/NBToolkit/NBToolkit/Properties/AssemblyInfo.cs index 08af08c..497ab97 100644 --- a/NBToolkit/NBToolkit/Properties/AssemblyInfo.cs +++ b/NBToolkit/NBToolkit/Properties/AssemblyInfo.cs @@ -8,9 +8,9 @@ using System.Runtime.InteropServices; [assembly: AssemblyTitle("NBToolkit")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyCompany("")] [assembly: AssemblyProduct("NBToolkit")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyCopyright("Copyright © Justin Aquadro 2011")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/NBToolkit/NBToolkit/Region.cs b/NBToolkit/NBToolkit/Region.cs new file mode 100644 index 0000000..ac56d89 --- /dev/null +++ b/NBToolkit/NBToolkit/Region.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.IO; +using NBT; + +namespace NBToolkit +{ + public class Region + { + protected int _rx; + protected int _rz; + + protected RegionManager _regionMan; + + protected static Regex _namePattern = new Regex("r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mcr$"); + + protected WeakReference _regionFile; + + public Region (RegionManager rm, int rx, int rz) + { + _regionMan = rm; + _regionFile = new WeakReference(null); + _rx = rx; + _rz = rz; + + if (!File.Exists(GetFilePath())) { + throw new FileNotFoundException(); + } + } + + public Region (RegionManager rm, string filename) + { + _regionMan = rm; + _regionFile = new WeakReference(null); + + ParseFileName(filename, out _rx, out _rz); + + if (!File.Exists(Path.Combine(_regionMan.GetRegionPath(), filename))) { + throw new FileNotFoundException(); + } + } + + public int X + { + get + { + return _rx; + } + } + + public int Z + { + get + { + return _rz; + } + } + + public string GetFileName () + { + return "r." + _rx + "." + _rz + ".mcr"; + + } + + public static bool TestFileName (string filename) + { + Match match = _namePattern.Match(filename); + if (!match.Success) { + return false; + } + + return true; + } + + public static bool ParseFileName (string filename, out int x, out int z) + { + x = 0; + z = 0; + + Match match = _namePattern.Match(filename); + if (!match.Success) { + return false; + } + + x = Convert.ToInt32(match.Groups[1].Value); + z = Convert.ToInt32(match.Groups[2].Value); + return true; + } + + public string GetFilePath () + { + return System.IO.Path.Combine(_regionMan.GetRegionPath(), GetFileName()); + } + + protected RegionFile GetRegionFile () + { + RegionFile rf = _regionFile.Target as RegionFile; + if (rf == null) { + rf = new RegionFile(GetFilePath()); + _regionFile.Target = rf; + } + + return rf; + } + + public NBT_Tree GetChunkTree (int lcx, int lcz) + { + RegionFile rf = GetRegionFile(); + Stream nbtstr = rf.GetChunkDataInputStream(lcx, lcz); + if (nbtstr == null) { + return null; + } + + return new NBT_Tree(nbtstr); + } + + public bool SaveChunkTree (int lcx, int lcz, NBT_Tree tree) + { + RegionFile rf = GetRegionFile(); + Stream zipstr = rf.GetChunkDataOutputStream(lcx, lcz); + if (zipstr == null) { + return false; + } + + tree.WriteTo(zipstr); + zipstr.Close(); + + return true; + } + + public bool ChunkExists (int lcx, int lcz) + { + RegionFile rf = GetRegionFile(); + return rf.HasChunk(lcx, lcz); + } + + public int ChunkCount () + { + RegionFile rf = GetRegionFile(); + + int count = 0; + for (int x = 0; x < ChunkManager.REGION_XLEN; x++) { + for (int z = 0; z < ChunkManager.REGION_ZLEN; z++) { + if (rf.HasChunk(x, z)) { + count++; + } + } + } + + return count; + } + } +} diff --git a/NBToolkit/NBToolkit/RegionEnumerator.cs b/NBToolkit/NBToolkit/RegionEnumerator.cs new file mode 100644 index 0000000..c05d74d --- /dev/null +++ b/NBToolkit/NBToolkit/RegionEnumerator.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using System.IO; + +namespace NBToolkit +{ + public class RegionList : IEnumerable + { + private List _regions; + + public RegionList (List regs) + { + _regions = regs; + } + + public RegionList (RegionManager rm) + { + _regions = new List(); + + if (!Directory.Exists(rm.GetRegionPath())) { + throw new DirectoryNotFoundException(); + } + + string[] files = Directory.GetFiles(rm.GetRegionPath()); + _regions.Capacity = files.Length; + + foreach (string file in files) { + try { + Region r = rm.GetRegion(file); + _regions.Add(r); + } + catch (ArgumentException) { + continue; + } + } + } + + IEnumerator IEnumerable.GetEnumerator () { + return (IEnumerator)GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator () + { + return (IEnumerator)GetEnumerator(); + } + + public RegionEnumerator GetEnumerator () + { + return new RegionEnumerator(_regions); + } + } + + public class RegionEnumerator : IEnumerator + { + protected List _regions; + + protected int _pos = -1; + + public RegionEnumerator (List regs) + { + _regions = regs; + } + + public RegionEnumerator (RegionManager rm) + { + _regions = new List(); + + if (!Directory.Exists(rm.GetRegionPath())) { + throw new DirectoryNotFoundException(); + } + + string[] files = Directory.GetFiles(rm.GetRegionPath()); + _regions.Capacity = files.Length; + + foreach (string file in files) { + try { + Region r = rm.GetRegion(file); + _regions.Add(r); + } + catch (ArgumentException) { + continue; + } + } + } + + public bool MoveNext () + { + _pos++; + return (_pos < _regions.Count); + } + + public void Reset () + { + _pos = -1; + } + + void IDisposable.Dispose () { } + + object IEnumerator.Current + { + get + { + return Current; + } + } + + Region IEnumerator.Current + { + get + { + return Current; + } + } + + public Region Current + { + get + { + try { + return _regions[_pos]; + } + catch (IndexOutOfRangeException) { + throw new InvalidOperationException(); + } + } + } + } +} diff --git a/NBToolkit/NBToolkit/RegionFileCache.cs b/NBToolkit/NBToolkit/RegionFileCache.cs index 44da49f..758390f 100644 --- a/NBToolkit/NBToolkit/RegionFileCache.cs +++ b/NBToolkit/NBToolkit/RegionFileCache.cs @@ -5,18 +5,25 @@ using System.IO; namespace NBToolkit { - public class RegionFileCache + /*public class RegionFileCache { private const int MAX_CACHE_SIZE = 256; - private static Dictionary cache = new Dictionary(); + private string _regionPath; + + private Dictionary cache = new Dictionary(); - private RegionFileCache() { + public RegionFileCache (string path) { + _regionPath = path; + + if (!Directory.Exists(_regionPath)) { + throw new DirectoryNotFoundException(); + } } - public static RegionFile GetRegionFile(string basePath, string fileName) { - string regionDir = Path.Combine(basePath, "region"); - string file = Path.Combine(regionDir, fileName); + public RegionFile GetRegionFile (string fileName) { + //string regionDir = basePath; // Path.Combine(basePath, "region"); + string file = Path.Combine(_regionPath, fileName); RegionFile rf = null; if (cache.ContainsKey(file)) { @@ -27,10 +34,6 @@ namespace NBToolkit return rf; } - if (!Directory.Exists(regionDir)) { - Directory.CreateDirectory(regionDir); - } - if (cache.Count >= MAX_CACHE_SIZE) { RegionFileCache.Clear(); } @@ -40,32 +43,11 @@ namespace NBToolkit return reg; } - public static RegionFile GetRegionFile (string basePath, int chunkX, int chunkZ) + public RegionFile GetRegionFile (int chunkX, int chunkZ) { - string regionDir = Path.Combine(basePath, "region"); - string fileName = Path.Combine(regionDir, "r." + (chunkX >> 5) + "." + (chunkZ >> 5) + ".mcr"); + string fileName = "r." + (chunkX >> 5) + "." + (chunkZ >> 5) + ".mcr"; - return GetRegionFile(basePath, fileName); - } - - public static string[] GetRegionFileList (string basePath) - { - string regionDir = Path.Combine(basePath, "region"); - - if (!Directory.Exists(regionDir)) { - Directory.CreateDirectory(regionDir); - } - - string[] files = Directory.GetFiles(regionDir); - List valid = new List(); - - foreach (string file in files) { - if (System.Text.RegularExpressions.Regex.IsMatch(file, "r\\.-?[0-9]+\\.-?[0-9]+\\.mcr$")) { - valid.Add(Path.GetFileName(file)); - } - } - - return valid.ToArray(); + return GetRegionFile(fileName); } public static void Clear() { @@ -92,5 +74,5 @@ namespace NBToolkit RegionFile r = GetRegionFile(basePath, chunkX, chunkZ); return r.GetChunkDataOutputStream(chunkX & 31, chunkZ & 31); } - } + }*/ } diff --git a/NBToolkit/NBToolkit/RegionKey.cs b/NBToolkit/NBToolkit/RegionKey.cs new file mode 100644 index 0000000..0dfb8c1 --- /dev/null +++ b/NBToolkit/NBToolkit/RegionKey.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NBToolkit +{ + public class RegionKey : IEquatable + { + protected int rx; + protected int rz; + + public RegionKey (int _rx, int _rz) + { + rx = _rx; + rz = _rz; + } + + public bool Equals (RegionKey ck) + { + return this.rx == ck.rx && this.rz == ck.rz; + } + + public override int GetHashCode () + { + return rx ^ rz; + } + } +} diff --git a/NBToolkit/NBToolkit/RegionManager.cs b/NBToolkit/NBToolkit/RegionManager.cs new file mode 100644 index 0000000..36fcba9 --- /dev/null +++ b/NBToolkit/NBToolkit/RegionManager.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NBToolkit +{ + public class RegionManager + { + protected string _regionPath; + + protected Dictionary _cache; + + public RegionManager (string regionDir) + { + _regionPath = regionDir; + _cache = new Dictionary(); + } + + public Region GetRegion (int rx, int rz) + { + RegionKey k = new RegionKey(rx, rz); + Region r; + + if (_cache.TryGetValue(k, out r) == false) { + r = new Region(this, rx, rz); + _cache.Add(k, r); + } + + return r; + } + + public Region GetRegion (string filename) + { + int rx, rz; + if (!Region.ParseFileName(filename, out rx, out rz)) { + throw new ArgumentException(); + } + + return GetRegion(rx, rz); + } + + public string GetRegionPath () + { + return _regionPath; + } + } +} diff --git a/NBToolkit/NBToolkit/Replace.cs b/NBToolkit/NBToolkit/Replace.cs index 6067f39..4746506 100644 --- a/NBToolkit/NBToolkit/Replace.cs +++ b/NBToolkit/NBToolkit/Replace.cs @@ -16,6 +16,24 @@ namespace NBToolkit public int? OPT_DATA = null; public double? OPT_PROB = null; + // Block coordinate conditions + public int? BL_X_GE = null; + public int? BL_X_LE = null; + public int? BL_Y_GE = null; + public int? BL_Y_LE = null; + public int? BL_Z_GE = null; + public int? BL_Z_LE = null; + + // Neighbor conditions + public int? OPT_NEIGHBOR = null; + public int? OPT_NEIGHBOR_SIDE = null; + public int? OPT_NEIGHBOR_E = null; + public int? OPT_NEIGHBOR_W = null; + public int? OPT_NEIGHBOR_N = null; + public int? OPT_NEIGHBOR_S = null; + public int? OPT_NEIGHBOR_T = null; + public int? OPT_NEIGHBOR_B = null; + public ReplaceOptions (string[] args) : base(args) { filterOpt = new OptionSet() @@ -30,6 +48,40 @@ 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}", + 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_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_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 => 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 }, + { "nbxa=", "Update blocks that have block type {ID} as their south neighbor", + v => OPT_NEIGHBOR_S = Convert.ToInt32(v) % 256 }, + { "nbxb=", "Update blocks that have block type {ID} as their north neighbor", + v => OPT_NEIGHBOR_N = Convert.ToInt32(v) % 256 }, + { "nbya=", "Update blocks that have block type {ID} as their top neighbor", + v => OPT_NEIGHBOR_T = Convert.ToInt32(v) % 256 }, + { "nbyb=", "Update blocks that have block type {ID} as their bottom neighbor", + v => OPT_NEIGHBOR_B = Convert.ToInt32(v) % 256 }, + { "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 }, }; filterOpt.Parse(args); @@ -94,15 +146,74 @@ namespace NBToolkit 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(); + // Determine X range + int xmin = 0; + int xmax = 15; + + if (opt.BL_X_GE != null) { + xmin = (int)opt.BL_X_GE - xBase; + } + if (opt.BL_X_LE != null) { + xmax = (int)opt.BL_X_LE - xBase; + } + + xmin = (xmin < 0) ? 0 : xmin; + xmax = (xmin > 15) ? 15 : xmax; + + if (xmin > 15 || xmax < 0 || xmin > xmax) { + return; + } + + // Determine Y range int ymin = 0; int ymax = 127; + if (opt.BL_Y_GE != null) { + ymin = (int)opt.BL_Y_GE; + } + if (opt.BL_Y_LE != null) { + ymax = (int)opt.BL_Y_LE; + } + + if (ymin > ymax) { + return; + } + + // Determine X range + int zmin = 0; + int zmax = 15; + + if (opt.BL_Z_GE != null) { + zmin = (int)opt.BL_Z_GE - zBase; + } + if (opt.BL_Z_LE != null) { + zmax = (int)opt.BL_Z_LE - zBase; + } + + zmin = (zmin < 0) ? 0 : zmin; + zmax = (zmin > 15) ? 15 : zmax; + + if (zmin > 15 || zmax < 0 || zmin > zmax) { + return; + } + + // Process Chunk for (int y = ymin; y <= ymax; y++) { - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { + for (int x = xmin; x <= xmax; x++) { + for (int z = zmin; z <= zmax; z++) { + // Probability test if (opt.OPT_PROB != null) { double c = rand.NextDouble(); if (c > opt.OPT_PROB) { @@ -110,6 +221,7 @@ namespace NBToolkit } } + // 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; diff --git a/NBToolkit/NBToolkit/TKOptions.cs b/NBToolkit/NBToolkit/TKOptions.cs index c2ba2b6..14258cc 100644 --- a/NBToolkit/NBToolkit/TKOptions.cs +++ b/NBToolkit/NBToolkit/TKOptions.cs @@ -27,12 +27,6 @@ namespace NBToolkit public int? CH_Z_GE = null; public int? CH_Z_LE = null; - // Block coordinate conditions - public int? BL_X_GE = null; - public int? BL_X_LE = null; - public int? BL_Z_GE = null; - public int? BL_Z_LE = null; - public TKOptions (string[] args) { commonOpt = new OptionSet() @@ -83,7 +77,7 @@ namespace NBToolkit throw new TKOptionException(); } - if (!File.Exists(Path.Combine(OPT_WORLD, "Level.dat"))) { + if (!File.Exists(Path.Combine(OPT_WORLD, "level.dat"))) { Console.WriteLine("Error: The supplied world path is invalid"); Console.WriteLine(); this.PrintUsage(); diff --git a/NBToolkit/NBToolkit/World.cs b/NBToolkit/NBToolkit/World.cs new file mode 100644 index 0000000..1ff2bb2 --- /dev/null +++ b/NBToolkit/NBToolkit/World.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace NBToolkit +{ + class World + { + protected RegionManager _regionMan; + protected ChunkManager _chunkMan; + protected BlockManager _blockMan; + + protected string _worldPath; + + public World (string world) + { + _worldPath = world; + + _regionMan = new RegionManager(Path.Combine(world, "region")); + _chunkMan = new ChunkManager(_regionMan); + _blockMan = new BlockManager(_chunkMan); + } + + public RegionManager GetRegionManager () + { + return _regionMan; + } + + public ChunkManager GetChunkManager () + { + return _chunkMan; + } + + public BlockManager GetBlockManager () + { + return _blockMan; + } + } +}