forked from mirrors/NBTExplorer
Corrected handling of loading and saving Alpha-style chunks.
This commit is contained in:
parent
0cf047c51d
commit
5be6731bb7
8 changed files with 453 additions and 17 deletions
214
NBToolkit/FilteredChunkManager.cs
Normal file
214
NBToolkit/FilteredChunkManager.cs
Normal file
|
@ -0,0 +1,214 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Substrate;
|
||||
|
||||
namespace NBToolkit
|
||||
{
|
||||
class FilteredChunkManager : IChunkManager, IEnumerable<ChunkRef>
|
||||
{
|
||||
private IChunkManager _cm;
|
||||
private IChunkFilter _filter;
|
||||
|
||||
public FilteredChunkManager (IChunkManager cm, IChunkFilter filter)
|
||||
{
|
||||
_cm = cm;
|
||||
_filter = filter;
|
||||
}
|
||||
|
||||
|
||||
#region IEnumerable<ChunkRef> Members
|
||||
|
||||
public IEnumerator<ChunkRef> GetEnumerator ()
|
||||
{
|
||||
return new ChunkEnumerator(_cm, _filter);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region IEnumerable Members
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return new ChunkEnumerator(_cm, _filter);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public class ChunkEnumerator : IEnumerator<ChunkRef>
|
||||
{
|
||||
private IChunkManager _cm;
|
||||
private IChunkFilter _filter;
|
||||
|
||||
private IEnumerator<ChunkRef> _enum;
|
||||
|
||||
public ChunkEnumerator (IChunkManager cm, IChunkFilter filter)
|
||||
{
|
||||
_cm = cm;
|
||||
_filter = filter;
|
||||
_enum = _cm.GetEnumerator();
|
||||
}
|
||||
|
||||
|
||||
#region IEnumerator<ChunkRef> 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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ChunkKey, WeakReference> _cache;
|
||||
protected Dictionary<ChunkKey, ChunkRef> _dirty;
|
||||
|
||||
public string ChunkPath
|
||||
{
|
||||
get { return _mapPath; }
|
||||
}
|
||||
|
||||
public ChunkFileManager (string mapDir)
|
||||
{
|
||||
_mapPath = mapDir;
|
||||
|
@ -189,7 +197,7 @@ namespace Substrate
|
|||
|
||||
public IEnumerator<ChunkRef> 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<ChunkRef>
|
||||
{
|
||||
protected ChunkFileManager _cm;
|
||||
protected Queue<string> _tld;
|
||||
protected Queue<string> _sld;
|
||||
protected Queue<ChunkRef> _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<string>();
|
||||
_sld = new Queue<string>();
|
||||
_chunks = new Queue<ChunkRef>();
|
||||
|
||||
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<ChunkRef>.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$");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -209,8 +209,6 @@ namespace Substrate
|
|||
private int _x = 0;
|
||||
private int _z = -1;
|
||||
|
||||
//protected RegionEnumerator _enum = null;
|
||||
|
||||
public ChunkEnumerator (ChunkManager cm)
|
||||
{
|
||||
_cm = cm;
|
||||
|
|
|
@ -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
|
||||
|
|
63
Substrate/SubstrateCS/Source/Utility/Base.cs
Normal file
63
Substrate/SubstrateCS/Source/Utility/Base.cs
Normal file
|
@ -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<char> result = new Stack<char>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,6 +60,7 @@
|
|||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Source\Level.cs" />
|
||||
|
@ -128,6 +129,7 @@
|
|||
<Compile Include="Source\TileEntities\TileEntityTrap.cs" />
|
||||
<Compile Include="Source\TileEntity.cs" />
|
||||
<Compile Include="Source\TileEntityFactory.cs" />
|
||||
<Compile Include="Source\Utility\Base.cs" />
|
||||
<Compile Include="Source\Utility\Interface.cs" />
|
||||
<Compile Include="Source\Utility\NibbleArray.cs" />
|
||||
<Compile Include="Source\World.cs" />
|
||||
|
|
Loading…
Reference in a new issue