Corrected handling of loading and saving Alpha-style chunks.

This commit is contained in:
Justin Aquadro 2011-04-08 23:16:04 +00:00
parent 0cf047c51d
commit 5be6731bb7
8 changed files with 453 additions and 17 deletions

View 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
}
}

View file

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

View file

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

View file

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

View file

@ -209,8 +209,6 @@ namespace Substrate
private int _x = 0;
private int _z = -1;
//protected RegionEnumerator _enum = null;
public ChunkEnumerator (ChunkManager cm)
{
_cm = cm;

View file

@ -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

View 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;
}
}
}

View file

@ -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" />