diff --git a/NBToolkit/FilteredChunkManager.cs b/NBToolkit/FilteredChunkManager.cs new file mode 100644 index 0000000..0fe81ca --- /dev/null +++ b/NBToolkit/FilteredChunkManager.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Substrate; + +namespace NBToolkit +{ + class FilteredChunkManager : IChunkManager, IEnumerable + { + private IChunkManager _cm; + private IChunkFilter _filter; + + public FilteredChunkManager (IChunkManager cm, IChunkFilter filter) + { + _cm = cm; + _filter = filter; + } + + + #region IEnumerable Members + + public IEnumerator GetEnumerator () + { + return new ChunkEnumerator(_cm, _filter); + } + + #endregion + + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator () + { + return new ChunkEnumerator(_cm, _filter); + } + + #endregion + + + public class ChunkEnumerator : IEnumerator + { + private IChunkManager _cm; + private IChunkFilter _filter; + + private IEnumerator _enum; + + public ChunkEnumerator (IChunkManager cm, IChunkFilter filter) + { + _cm = cm; + _filter = filter; + _enum = _cm.GetEnumerator(); + } + + + #region IEnumerator Members + + public ChunkRef Current + { + get { return _enum.Current; } + } + + #endregion + + + #region IDisposable Members + + public void Dispose () + { + } + + #endregion + + + #region IEnumerator Members + + object IEnumerator.Current + { + get { return _enum.Current; } + } + + public bool MoveNext () + { + while (true) { + if (_enum.MoveNext() == false) { + return false; + } + + // Filter by coordinates + if (_filter.InvertXZ) { + if (_filter.XAboveEq != null && _filter.XBelowEq != null && + _filter.ZAboveEq != null && _filter.ZBelowEq != null && + Current.X >= _filter.XAboveEq && Current.X <= _filter.XBelowEq && + Current.Z >= _filter.ZAboveEq && Current.Z <= _filter.ZBelowEq) { + continue; + } + } + else { + if (_filter.XAboveEq != null && Current.X < _filter.XAboveEq) { + continue; + } + if (_filter.XBelowEq != null && Current.X > _filter.XBelowEq) { + continue; + } + if (_filter.ZAboveEq != null && Current.Z < _filter.ZAboveEq) { + continue; + } + if (_filter.ZBelowEq != null && Current.Z > _filter.ZBelowEq) { + continue; + } + } + + // Filter out chunks that do not contain required blocks (included list) + if (_filter.IncludedBlockCount > 0) { + int matchCount = 0; + foreach (int block in _filter.IncludedBlocks) { + if (Current.CountBlockID(block) > 0) { + matchCount++; + } + } + + if (_filter.IncludeMatchAny && matchCount == 0) { + continue; + } + if (_filter.IncludeMatchAll && matchCount != _filter.IncludedBlockCount) { + continue; + } + } + + // Filter out chunks that contain forbiddon blocks (excluded list) + if (_filter.ExcludedBlockCount > 0) { + int matchCount = 0; + foreach (int block in _filter.ExcludedBlocks) { + if (Current.CountBlockID(block) > 0) { + matchCount++; + } + } + + if (_filter.ExcludeMatchAny && matchCount > 0) { + continue; + } + if (_filter.ExcludeMatchAll && matchCount == _filter.ExcludedBlockCount) { + continue; + } + } + + return true; + } + } + + public void Reset () + { + _enum.Reset(); + } + + #endregion + } + + + #region IChunkContainer Members + + public int ChunkGlobalX (int cx) + { + return _cm.ChunkGlobalX(cx); + } + + public int ChunkGlobalZ (int cz) + { + return _cm.ChunkGlobalZ(cz); + } + + public int ChunkLocalX (int cx) + { + return _cm.ChunkLocalX(cx); + } + + public int ChunkLocalZ (int cz) + { + return _cm.ChunkLocalZ(cz); + } + + public Chunk GetChunk (int cx, int cz) + { + return _cm.GetChunk(cx, cz); + } + + public ChunkRef GetChunkRef (int cx, int cz) + { + return _cm.GetChunkRef(cx, cz); + } + + public bool ChunkExists (int cx, int cz) + { + return _cm.ChunkExists(cx, cz); + } + + public bool DeleteChunk (int cx, int cz) + { + return _cm.DeleteChunk(cx, cz); + } + + public int Save () + { + return _cm.Save(); + } + + public bool SaveChunk (Chunk chunk) + { + return _cm.SaveChunk(chunk); + } + + #endregion + } +} diff --git a/NBToolkit/Oregen.cs b/NBToolkit/Oregen.cs index 150128f..b67931a 100644 --- a/NBToolkit/Oregen.cs +++ b/NBToolkit/Oregen.cs @@ -183,7 +183,7 @@ namespace NBToolkit { World world = new World(opt.OPT_WORLD); - ChunkManager cm = world.GetChunkManager() as ChunkManager; + IChunkManager cm = world.GetChunkManager(); FilteredChunkManager fcm = new FilteredChunkManager(cm, opt.GetChunkFilter()); int affectedChunks = 0; diff --git a/Substrate/SubstrateCS/Source/ChunkFile.cs b/Substrate/SubstrateCS/Source/ChunkFile.cs index 5695a2e..07dd937 100644 --- a/Substrate/SubstrateCS/Source/ChunkFile.cs +++ b/Substrate/SubstrateCS/Source/ChunkFile.cs @@ -6,6 +6,8 @@ using Ionic.Zlib; namespace Substrate { + using Utility; + public class ChunkFile : NBTFile { public ChunkFile (string path) @@ -16,21 +18,23 @@ namespace Substrate public ChunkFile (string path, int cx, int cz) : base("") { - string cx64 = Base64(cx); - string cz64 = Base64(cz); + string cx64 = Base36.Encode(cx); + string cz64 = Base36.Encode(cz); string file = "c." + cx64 + "." + cz64 + ".dat"; - string dir1 = Base64(cx % 64); - string dir2 = Base64(cz % 64); + while (cx < 0) { + cx += (64 * 64); + } + while (cz < 0) { + cz += (64 * 64); + } + + string dir1 = Base36.Encode(cx % 64); + string dir2 = Base36.Encode(cz % 64); _filename = Path.Combine(path, dir1); _filename = Path.Combine(_filename, dir2); _filename = Path.Combine(_filename, file); } - - private string Base64 (int val) - { - return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(val.ToString())); - } } } diff --git a/Substrate/SubstrateCS/Source/ChunkFileManager.cs b/Substrate/SubstrateCS/Source/ChunkFileManager.cs index 2c84706..48a8bbf 100644 --- a/Substrate/SubstrateCS/Source/ChunkFileManager.cs +++ b/Substrate/SubstrateCS/Source/ChunkFileManager.cs @@ -1,11 +1,14 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Text; +using System.Text.RegularExpressions; using System.IO; namespace Substrate { using NBT; + using Utility; public class ChunkFileManager : IChunkManager, IChunkCache { @@ -14,6 +17,11 @@ namespace Substrate protected Dictionary _cache; protected Dictionary _dirty; + public string ChunkPath + { + get { return _mapPath; } + } + public ChunkFileManager (string mapDir) { _mapPath = mapDir; @@ -189,7 +197,7 @@ namespace Substrate public IEnumerator GetEnumerator () { - return null; + return new ChunkEnumerator(this); } #endregion @@ -198,9 +206,156 @@ namespace Substrate System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () { - return null; + return new ChunkEnumerator(this); } #endregion + + + public class ChunkEnumerator : IEnumerator + { + protected ChunkFileManager _cm; + protected Queue _tld; + protected Queue _sld; + protected Queue _chunks; + + private string _curtld; + private string _cursld; + private ChunkRef _curchunk; + + public ChunkEnumerator (ChunkFileManager cfm) + { + _cm = cfm; + + if (!Directory.Exists(_cm.ChunkPath)) { + throw new DirectoryNotFoundException(); + } + + Reset(); + } + + private bool MoveNextTLD () + { + if (_tld.Count == 0) { + return false; + } + + _curtld = _tld.Dequeue(); + + //string path = Path.Combine(_cm.ChunkPath, _curtld); + + string[] files = Directory.GetDirectories(_curtld); + foreach (string file in files) { + _sld.Enqueue(file); + } + + return true; + } + + public bool MoveNextSLD () + { + while (_sld.Count == 0) { + if (MoveNextTLD() == false) { + return false; + } + } + + _cursld = _sld.Dequeue(); + + //string path = Path.Combine(_cm.ChunkPath, _curtld); + //path = Path.Combine(path, _cursld); + + string[] files = Directory.GetFiles(_cursld); + foreach (string file in files) { + int x; + int z; + + string basename = Path.GetFileName(file); + + if (!ParseFileName(basename, out x, out z)) { + continue; + } + + ChunkRef cref = _cm.GetChunkRef(x, z); + if (cref != null) { + _chunks.Enqueue(cref); + } + } + + return true; + } + + public bool MoveNext () + { + while (_chunks.Count == 0) { + if (MoveNextSLD() == false) { + return false; + } + } + + _curchunk = _chunks.Dequeue(); + return true; + } + + public void Reset () + { + _curchunk = null; + + _tld = new Queue(); + _sld = new Queue(); + _chunks = new Queue(); + + string[] files = Directory.GetDirectories(_cm.ChunkPath); + foreach (string file in files) { + _tld.Enqueue(file); + } + } + + void IDisposable.Dispose () { } + + object IEnumerator.Current + { + get + { + return Current; + } + } + + ChunkRef IEnumerator.Current + { + get + { + return Current; + } + } + + public ChunkRef Current + { + get + { + if (_curchunk == null) { + throw new InvalidOperationException(); + } + return _curchunk; + } + } + + private 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 = (int)Base36.Decode(match.Groups[1].Value); + z = (int)Base36.Decode(match.Groups[2].Value); + return true; + } + + protected static Regex _namePattern = new Regex("c\\.(-?[0-9a-zA-Z]+)\\.(-?[0-9a-zA-Z]+)\\.dat$"); + } } } diff --git a/Substrate/SubstrateCS/Source/ChunkManager.cs b/Substrate/SubstrateCS/Source/ChunkManager.cs index 06d2364..be4c243 100644 --- a/Substrate/SubstrateCS/Source/ChunkManager.cs +++ b/Substrate/SubstrateCS/Source/ChunkManager.cs @@ -209,8 +209,6 @@ namespace Substrate private int _x = 0; private int _z = -1; - //protected RegionEnumerator _enum = null; - public ChunkEnumerator (ChunkManager cm) { _cm = cm; diff --git a/Substrate/SubstrateCS/Source/NBTFile.cs b/Substrate/SubstrateCS/Source/NBTFile.cs index 5a89721..fc54727 100644 --- a/Substrate/SubstrateCS/Source/NBTFile.cs +++ b/Substrate/SubstrateCS/Source/NBTFile.cs @@ -28,7 +28,7 @@ namespace Substrate return true; } - public Stream GetDataInputStream () + public virtual Stream GetDataInputStream () { FileStream fstr = new FileStream(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); @@ -43,9 +43,9 @@ namespace Substrate return new GZipStream(new MemoryStream(data), CompressionMode.Decompress); } - public Stream GetDataOutputStream () + public virtual Stream GetDataOutputStream () { - return new ZlibStream(new NBTBuffer(this), CompressionMode.Compress); + return new GZipStream(new NBTBuffer(this), CompressionMode.Compress); } class NBTBuffer : MemoryStream diff --git a/Substrate/SubstrateCS/Source/Utility/Base.cs b/Substrate/SubstrateCS/Source/Utility/Base.cs new file mode 100644 index 0000000..ef2f373 --- /dev/null +++ b/Substrate/SubstrateCS/Source/Utility/Base.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Substrate.Utility +{ + public static class Base36 + { + private const string _alphabet = "0123456789abcdefghijklmnopqrstuvwxyz"; + + public static string Encode (long input) + { + if (input == 0) { + return "0"; + } + + bool neg = (input < 0); + if (neg) { + input *= -1; + } + + Stack result = new Stack(); + while (input != 0) { + result.Push(_alphabet[(int)(input % 36)]); + input /= 36; + } + + string ret = new string(result.ToArray()); + if (neg) { + ret = '-' + ret; + } + + return ret; + } + + public static long Decode (string input) + { + if (input.Length == 0) { + throw new ArgumentOutOfRangeException("input", input); + } + + bool neg = false; + if (input[0] == '-') { + neg = true; + input = input.Substring(1); + } + + input = input.ToLower(); + long result = 0; + + int pos = 0; + for (int i = input.Length - 1; i >= 0; i--) { + result += _alphabet.IndexOf(input[i]) * (long)Math.Pow(36, pos); + pos++; + } + + if (neg) { + result *= -1; + } + return result; + } + } +} diff --git a/Substrate/SubstrateCS/Substrate.csproj b/Substrate/SubstrateCS/Substrate.csproj index c748430..72a9ea2 100644 --- a/Substrate/SubstrateCS/Substrate.csproj +++ b/Substrate/SubstrateCS/Substrate.csproj @@ -60,6 +60,7 @@ + @@ -128,6 +129,7 @@ +