forked from mirrors/NBTExplorer
Chunk caching moved into regions, region is now the primary chunk container of chunkrefs. Caching seems to have degraded with the transition, may need to implement explicit caching.
This commit is contained in:
parent
25f429f0cf
commit
895178d5d3
9 changed files with 366 additions and 284 deletions
|
@ -7,19 +7,6 @@ namespace NBToolkit.Map
|
|||
using NBT;
|
||||
using Utility;
|
||||
|
||||
public interface IBlock
|
||||
{
|
||||
BlockInfo Info { get; }
|
||||
int ID { get; set; }
|
||||
int Data { get; set; }
|
||||
int BlockLight { get; set; }
|
||||
int SkyLight { get; set; }
|
||||
|
||||
TileEntity GetTileEntity ();
|
||||
bool SetTileEntity (TileEntity te);
|
||||
bool ClearTileEntity ();
|
||||
}
|
||||
|
||||
public class Block : IBlock, ICopyable<Block>
|
||||
{
|
||||
private int _id;
|
||||
|
|
52
NBToolkit/NBToolkit/Map/BlockInterface.cs
Normal file
52
NBToolkit/NBToolkit/Map/BlockInterface.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace NBToolkit.Map
|
||||
{
|
||||
|
||||
public interface IBlock
|
||||
{
|
||||
BlockInfo Info { get; }
|
||||
int ID { get; set; }
|
||||
int Data { get; set; }
|
||||
int BlockLight { get; set; }
|
||||
int SkyLight { get; set; }
|
||||
|
||||
TileEntity GetTileEntity ();
|
||||
bool SetTileEntity (TileEntity te);
|
||||
bool ClearTileEntity ();
|
||||
}
|
||||
|
||||
public interface IBlockContainer
|
||||
{
|
||||
int BlockGlobalX (int x);
|
||||
int BlockGlobalY (int y);
|
||||
int BlockGlobalZ (int z);
|
||||
|
||||
int BlockLocalX (int x);
|
||||
int BlockLocalY (int y);
|
||||
int BlockLocalZ (int z);
|
||||
|
||||
Block GetBlock (int lx, int ly, int lz);
|
||||
BlockRef GetBlockRef (int lx, int ly, int lz);
|
||||
|
||||
BlockInfo GetBlockInfo (int lx, int ly, int lz);
|
||||
|
||||
int GetBlockID (int lx, int ly, int lz);
|
||||
int GetBlockData (int lx, int ly, int lz);
|
||||
int GetBlockLight (int lx, int ly, int lz);
|
||||
int GetBlockSkyLight (int lx, int ly, int lz);
|
||||
|
||||
void SetBlock (int lx, int ly, int lz, Block block);
|
||||
|
||||
bool SetBlockID (int lx, int ly, int lz, int id);
|
||||
bool SetBlockData (int lx, int ly, int lz, int data);
|
||||
bool SetBlockLight (int lx, int ly, int lz, int light);
|
||||
bool SetBlockSkyLight (int lx, int ly, int lz, int light);
|
||||
|
||||
TileEntity GetTileEntity (int lx, int ly, int lz);
|
||||
bool SetTileEntity (int lx, int ly, int lz, TileEntity te);
|
||||
bool ClearTileEntity (int lx, int ly, int lz);
|
||||
}
|
||||
}
|
|
@ -50,32 +50,32 @@ namespace NBToolkit.Map
|
|||
_chunkMan = bm._chunkMan;
|
||||
}
|
||||
|
||||
public int GlobalX (int x)
|
||||
public int BlockGlobalX (int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
public int GlobalY (int y)
|
||||
public int BlockGlobalY (int y)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
public int GlobalZ (int z)
|
||||
public int BlockGlobalZ (int z)
|
||||
{
|
||||
return z;
|
||||
}
|
||||
|
||||
public int LocalX (int x)
|
||||
public int BlockLocalX (int x)
|
||||
{
|
||||
return x & CHUNK_XMASK;
|
||||
}
|
||||
|
||||
public int LocalY (int y)
|
||||
public int BlockLocalY (int y)
|
||||
{
|
||||
return y & CHUNK_YMASK;
|
||||
}
|
||||
|
||||
public int LocalZ (int z)
|
||||
public int BlockLocalZ (int z)
|
||||
{
|
||||
return z & CHUNK_ZMASK;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ namespace NBToolkit.Map
|
|||
return null;
|
||||
}
|
||||
|
||||
return new Block(_cache, x & CHUNK_XMASK, y, z & CHUNK_ZMASK);
|
||||
return _cache.GetBlock(x & CHUNK_XMASK, y, z & CHUNK_ZMASK);
|
||||
}
|
||||
|
||||
public virtual BlockRef GetBlockRef (int x, int y, int z)
|
||||
|
@ -97,7 +97,7 @@ namespace NBToolkit.Map
|
|||
return null;
|
||||
}
|
||||
|
||||
return new BlockRef(_cache, x, y, z);
|
||||
return _cache.GetBlockRef(x & CHUNK_XMASK, y, z & CHUNK_ZMASK);
|
||||
}
|
||||
|
||||
public virtual BlockInfo GetBlockInfo (int x, int y, int z)
|
||||
|
|
|
@ -14,27 +14,27 @@ namespace NBToolkit.Map
|
|||
|
||||
public int X
|
||||
{
|
||||
get { return _container.GlobalX(_x); }
|
||||
get { return _container.BlockGlobalX(_x); }
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get { return _container.GlobalY(_y); }
|
||||
get { return _container.BlockGlobalY(_y); }
|
||||
}
|
||||
|
||||
public int Z
|
||||
{
|
||||
get { return _container.GlobalZ(_z); }
|
||||
get { return _container.BlockGlobalZ(_z); }
|
||||
}
|
||||
|
||||
public int LocalX
|
||||
{
|
||||
get { return _container.LocalX(_x); }
|
||||
get { return _container.BlockLocalX(_x); }
|
||||
}
|
||||
|
||||
public int LocalY
|
||||
{
|
||||
get { return _container.LocalZ(_z); }
|
||||
get { return _container.BlockLocalZ(_z); }
|
||||
}
|
||||
|
||||
public int LocalZ
|
||||
|
|
|
@ -6,53 +6,6 @@ namespace NBToolkit.Map
|
|||
using NBT;
|
||||
using Utility;
|
||||
|
||||
public interface IBlockContainer
|
||||
{
|
||||
int GlobalX (int x);
|
||||
int GlobalY (int y);
|
||||
int GlobalZ (int z);
|
||||
|
||||
int LocalX (int x);
|
||||
int LocalY (int y);
|
||||
int LocalZ (int z);
|
||||
|
||||
Block GetBlock (int lx, int ly, int lz);
|
||||
BlockRef GetBlockRef (int lx, int ly, int lz);
|
||||
|
||||
BlockInfo GetBlockInfo (int lx, int ly, int lz);
|
||||
|
||||
int GetBlockID (int lx, int ly, int lz);
|
||||
int GetBlockData (int lx, int ly, int lz);
|
||||
int GetBlockLight (int lx, int ly, int lz);
|
||||
int GetBlockSkyLight (int lx, int ly, int lz);
|
||||
|
||||
void SetBlock (int lx, int ly, int lz, Block block);
|
||||
|
||||
bool SetBlockID (int lx, int ly, int lz, int id);
|
||||
bool SetBlockData (int lx, int ly, int lz, int data);
|
||||
bool SetBlockLight (int lx, int ly, int lz, int light);
|
||||
bool SetBlockSkyLight (int lx, int ly, int lz, int light);
|
||||
|
||||
TileEntity GetTileEntity (int lx, int ly, int lz);
|
||||
bool SetTileEntity (int lx, int ly, int lz, TileEntity te);
|
||||
bool ClearTileEntity (int lx, int ly, int lz);
|
||||
}
|
||||
|
||||
public interface IChunk : IBlockContainer
|
||||
{
|
||||
int X { get; }
|
||||
int Z { get; }
|
||||
|
||||
bool IsTerrainPopulated { get; set; }
|
||||
|
||||
bool Save (Stream outStream);
|
||||
|
||||
int CountBlockID (int id);
|
||||
int CountBlockData (int id, int data);
|
||||
|
||||
int GetHeight (int lx, int lz);
|
||||
}
|
||||
|
||||
public class Chunk : IChunk, ICopyable<Chunk>
|
||||
{
|
||||
private NBT_Tree _tree;
|
||||
|
@ -149,32 +102,32 @@ namespace NBToolkit.Map
|
|||
_tree.Root.Add("Level", level);
|
||||
}
|
||||
|
||||
public int GlobalX (int x)
|
||||
public int BlockGlobalX (int x)
|
||||
{
|
||||
return _cx * BlockManager.CHUNK_XLEN + x;
|
||||
}
|
||||
|
||||
public int GlobalY (int y)
|
||||
public int BlockGlobalY (int y)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
public int GlobalZ (int z)
|
||||
public int BlockGlobalZ (int z)
|
||||
{
|
||||
return _cz * BlockManager.CHUNK_ZLEN + z;
|
||||
}
|
||||
|
||||
public int LocalX (int x)
|
||||
public int BlockLocalX (int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
public int LocalY (int y)
|
||||
public int BlockLocalY (int y)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
public int LocalZ (int z)
|
||||
public int BlockLocalZ (int z)
|
||||
{
|
||||
return z;
|
||||
}
|
||||
|
|
47
NBToolkit/NBToolkit/Map/ChunkInterface.cs
Normal file
47
NBToolkit/NBToolkit/Map/ChunkInterface.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace NBToolkit.Map
|
||||
{
|
||||
|
||||
public interface IChunk : IBlockContainer
|
||||
{
|
||||
int X { get; }
|
||||
int Z { get; }
|
||||
|
||||
bool IsTerrainPopulated { get; set; }
|
||||
|
||||
bool Save (Stream outStream);
|
||||
|
||||
int CountBlockID (int id);
|
||||
int CountBlockData (int id, int data);
|
||||
|
||||
int GetHeight (int lx, int lz);
|
||||
}
|
||||
|
||||
public interface IChunkCache
|
||||
{
|
||||
bool MarkChunkDirty (ChunkRef chunk);
|
||||
bool MarkChunkClean (int cx, int cz);
|
||||
}
|
||||
|
||||
public interface IChunkContainer
|
||||
{
|
||||
int ChunkGlobalX (int cx);
|
||||
int ChunkGlobalZ (int cz);
|
||||
|
||||
int ChunkLocalX (int cx);
|
||||
int ChunkLocalZ (int cz);
|
||||
|
||||
Chunk GetChunk (int cx, int cz);
|
||||
ChunkRef GetChunkRef (int cx, int cz);
|
||||
|
||||
bool ChunkExists (int cx, int cz);
|
||||
|
||||
bool DeleteChunk (int cx, int cz);
|
||||
|
||||
int Save ();
|
||||
bool SaveChunk (Chunk chunk);
|
||||
}
|
||||
}
|
|
@ -4,27 +4,8 @@ using System.Text;
|
|||
|
||||
namespace NBToolkit.Map
|
||||
{
|
||||
public interface IChunkManager
|
||||
{
|
||||
Chunk GetChunk (int cx, int cz);
|
||||
ChunkRef GetChunkRef (int cx, int cz);
|
||||
|
||||
bool ChunkExists (int cx, int cz);
|
||||
|
||||
bool MarkChunkDirty (int cx, int cz);
|
||||
bool MarkChunkClean (int cx, int cz);
|
||||
|
||||
int Save ();
|
||||
bool Save (Chunk chunk);
|
||||
|
||||
ChunkRef CreateChunk (int cx, int cz);
|
||||
bool DeleteChunk (int cx, int cz);
|
||||
|
||||
bool CopyChunk (int cx1, int cz1, int cx2, int cz2);
|
||||
bool MoveChunk (int cx1, int cz1, int cx2, int cz2);
|
||||
}
|
||||
|
||||
public class ChunkManager
|
||||
public class ChunkManager : IChunkContainer, IChunkCache
|
||||
{
|
||||
public const int REGION_XLEN = 32;
|
||||
public const int REGION_ZLEN = 32;
|
||||
|
@ -37,55 +18,54 @@ namespace NBToolkit.Map
|
|||
|
||||
protected RegionManager _regionMan;
|
||||
|
||||
protected Dictionary<ChunkKey, WeakReference> _cache;
|
||||
protected Dictionary<ChunkKey, ChunkRef> _dirty;
|
||||
protected Dictionary<RegionKey, Region> _cache;
|
||||
protected Dictionary<RegionKey, Region> _dirty;
|
||||
|
||||
public ChunkManager (RegionManager rm)
|
||||
{
|
||||
_regionMan = rm;
|
||||
_cache = new Dictionary<ChunkKey, WeakReference>();
|
||||
_dirty = new Dictionary<ChunkKey, ChunkRef>();
|
||||
_cache = new Dictionary<RegionKey, Region>();
|
||||
_dirty = new Dictionary<RegionKey, Region>();
|
||||
}
|
||||
|
||||
public int ChunkGlobalX (int cx)
|
||||
{
|
||||
return cx;
|
||||
}
|
||||
|
||||
public int ChunkGlobalZ (int cz)
|
||||
{
|
||||
return cz;
|
||||
}
|
||||
|
||||
public int ChunkLocalX (int cx)
|
||||
{
|
||||
return cx & REGION_XMASK;
|
||||
}
|
||||
|
||||
public int ChunkLocalZ (int cz)
|
||||
{
|
||||
return cz & REGION_ZMASK;
|
||||
}
|
||||
|
||||
public Chunk GetChunk (int cx, int cz)
|
||||
{
|
||||
int lcx = cx & REGION_XMASK;
|
||||
int lcz = cz & REGION_ZMASK;
|
||||
|
||||
Region r = GetRegion(cx, cz);
|
||||
if (r == null || !r.ChunkExists(lcx, lcz)) {
|
||||
if (r == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Chunk(r.GetChunkTree(lcx, lcz));
|
||||
return r.GetChunk(cx & REGION_XMASK, cz & REGION_ZMASK);
|
||||
}
|
||||
|
||||
public ChunkRef GetChunkRef (int cx, int cz)
|
||||
{
|
||||
ChunkKey k = new ChunkKey(cx, cz);
|
||||
|
||||
ChunkRef c = null;
|
||||
|
||||
WeakReference chunkref = null;
|
||||
if (_cache.TryGetValue(k, out chunkref)) {
|
||||
c = chunkref.Target as ChunkRef;
|
||||
}
|
||||
else {
|
||||
_cache.Add(k, new WeakReference(null));
|
||||
}
|
||||
|
||||
if (c != null) {
|
||||
return c;
|
||||
}
|
||||
|
||||
try {
|
||||
c = new ChunkRef(this, cx, cz);
|
||||
_cache[k].Target = c;
|
||||
return c;
|
||||
}
|
||||
catch (MissingChunkException) {
|
||||
Region r = GetRegion(cx, cz);
|
||||
if (r == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return r.GetChunkRef(cx & REGION_XMASK, cz & REGION_ZMASK, this);
|
||||
}
|
||||
|
||||
public bool ChunkExists (int cx, int cz)
|
||||
|
@ -98,55 +78,51 @@ namespace NBToolkit.Map
|
|||
return r.ChunkExists(cx & REGION_XMASK, cz & REGION_ZMASK);
|
||||
}
|
||||
|
||||
public bool MarkChunkDirty (int cx, int cz)
|
||||
{
|
||||
ChunkKey k = new ChunkKey(cx, cz);
|
||||
if (!_dirty.ContainsKey(k)) {
|
||||
_dirty.Add(k, GetChunkRef(cx, cz));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool MarkChunkClean (int cx, int cz)
|
||||
{
|
||||
ChunkKey k = new ChunkKey(cx, cz);
|
||||
if (_dirty.ContainsKey(k)) {
|
||||
_dirty.Remove(k);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int Save ()
|
||||
{
|
||||
int saved = 0;
|
||||
foreach (ChunkRef c in _dirty.Values) {
|
||||
int lcx = ChunkLocalX(c.X);
|
||||
int lcz = ChunkLocalZ(c.Z);
|
||||
|
||||
Region r = GetRegion(c.X, c.Z);
|
||||
if (r == null || !r.ChunkExists(lcx, lcz)) {
|
||||
throw new MissingChunkException();
|
||||
}
|
||||
|
||||
if (c.Save(r.GetChunkOutStream(lcx, lcz))) {
|
||||
saved++;
|
||||
}
|
||||
}
|
||||
|
||||
_dirty.Clear();
|
||||
return saved;
|
||||
}
|
||||
|
||||
public bool Save (Chunk chunk)
|
||||
public bool MarkChunkDirty (ChunkRef chunk)
|
||||
{
|
||||
Region r = GetRegion(chunk.X, chunk.Z);
|
||||
if (r == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return chunk.Save(r.GetChunkOutStream(chunk.X & REGION_XLEN, chunk.Z & REGION_ZLEN));
|
||||
RegionKey k = new RegionKey(r.X, r.Z);
|
||||
_dirty[k] = r;
|
||||
|
||||
r.MarkChunkDirty(chunk);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool MarkChunkClean (int cx, int cz)
|
||||
{
|
||||
Region r = GetRegion(cx, cz);
|
||||
if (r == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RegionKey k = new RegionKey(r.X, r.Z);
|
||||
return _dirty.Remove(k);
|
||||
}
|
||||
|
||||
public int Save ()
|
||||
{
|
||||
int saved = 0;
|
||||
foreach (Region r in _dirty.Values) {
|
||||
saved += r.Save();
|
||||
}
|
||||
|
||||
_dirty.Clear();
|
||||
return saved;
|
||||
}
|
||||
|
||||
public bool SaveChunk (Chunk chunk)
|
||||
{
|
||||
Region r = GetRegion(chunk.X, chunk.Z);
|
||||
if (r == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return r.SaveChunk(chunk);
|
||||
}
|
||||
|
||||
public bool DeleteChunk (int cx, int cz)
|
||||
|
@ -160,11 +136,11 @@ namespace NBToolkit.Map
|
|||
return false;
|
||||
}
|
||||
|
||||
ChunkKey k = new ChunkKey(cx, cz);
|
||||
_cache.Remove(k);
|
||||
_dirty.Remove(k);
|
||||
|
||||
if (r.ChunkCount() == 0) {
|
||||
RegionKey k = new RegionKey(r.X, r.Z);
|
||||
_cache.Remove(k);
|
||||
_dirty.Remove(k);
|
||||
|
||||
_regionMan.DeleteRegion(r.X, r.Z);
|
||||
}
|
||||
|
||||
|
@ -183,16 +159,6 @@ namespace NBToolkit.Map
|
|||
return GetChunkRef(cx, cz);
|
||||
}
|
||||
|
||||
protected int ChunkLocalX (int cx)
|
||||
{
|
||||
return cx & REGION_XMASK;
|
||||
}
|
||||
|
||||
protected int ChunkLocalZ (int cz)
|
||||
{
|
||||
return cz & REGION_ZMASK;
|
||||
}
|
||||
|
||||
protected Region GetRegion (int cx, int cz)
|
||||
{
|
||||
cx >>= REGION_XLOG;
|
||||
|
|
|
@ -9,7 +9,8 @@ namespace NBToolkit.Map
|
|||
|
||||
public class ChunkRef : IChunk
|
||||
{
|
||||
private ChunkManager _chunkMan;
|
||||
private IChunkContainer _container;
|
||||
private IChunkCache _cache;
|
||||
private Chunk _chunk;
|
||||
|
||||
private int _cx;
|
||||
|
@ -19,51 +20,62 @@ namespace NBToolkit.Map
|
|||
|
||||
public int X
|
||||
{
|
||||
get { return _cx; }
|
||||
get { return _container.ChunkGlobalX(_cx); }
|
||||
}
|
||||
|
||||
public int Z
|
||||
{
|
||||
get { return _cz; }
|
||||
get { return _container.ChunkGlobalZ(_cz); }
|
||||
}
|
||||
|
||||
public ChunkRef (ChunkManager cm, int cx, int cz)
|
||||
public int LocalX
|
||||
{
|
||||
_chunkMan = cm;
|
||||
get { return _container.ChunkLocalX(_cx); }
|
||||
}
|
||||
|
||||
public int LocalZ
|
||||
{
|
||||
get { return _container.ChunkLocalZ(_cz); }
|
||||
}
|
||||
|
||||
public ChunkRef (IChunkContainer container, IChunkCache cache, int cx, int cz)
|
||||
{
|
||||
_container = container;
|
||||
_cache = cache;
|
||||
_cx = cx;
|
||||
_cz = cz;
|
||||
|
||||
if (!_chunkMan.ChunkExists(cx, cz)) {
|
||||
if (!_container.ChunkExists(cx, cz)) {
|
||||
throw new MissingChunkException();
|
||||
}
|
||||
}
|
||||
|
||||
public int GlobalX (int x)
|
||||
public int BlockGlobalX (int x)
|
||||
{
|
||||
return _cx * BlockManager.CHUNK_XLEN + x;
|
||||
return _container.ChunkGlobalX(_cx) * BlockManager.CHUNK_XLEN + x;
|
||||
}
|
||||
|
||||
public int GlobalY (int y)
|
||||
public int BlockGlobalY (int y)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
public int GlobalZ (int z)
|
||||
public int BlockGlobalZ (int z)
|
||||
{
|
||||
return _cz * BlockManager.CHUNK_ZLEN + z;
|
||||
return _container.ChunkGlobalZ(_cz) * BlockManager.CHUNK_ZLEN + z;
|
||||
}
|
||||
|
||||
public int LocalX (int x)
|
||||
public int BlockLocalX (int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
public int LocalY (int y)
|
||||
public int BlockLocalY (int y)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
public int LocalZ (int z)
|
||||
public int BlockLocalZ (int z)
|
||||
{
|
||||
return z;
|
||||
}
|
||||
|
@ -71,20 +83,11 @@ namespace NBToolkit.Map
|
|||
private Chunk GetChunk ()
|
||||
{
|
||||
if (_chunk == null) {
|
||||
_chunk = _chunkMan.GetChunk(_cx, _cz);
|
||||
_chunk = _container.GetChunk(_cx, _cz);
|
||||
}
|
||||
return _chunk;
|
||||
}
|
||||
|
||||
/*private NBT_Tree GetTree ()
|
||||
{
|
||||
if (!_chunkMan.ChunkExists(_cx, _cz)) {
|
||||
throw new MissingChunkException();
|
||||
}
|
||||
|
||||
return r.GetChunkTree(LocalX, LocalZ);
|
||||
}*/
|
||||
|
||||
private bool MarkDirty ()
|
||||
{
|
||||
if (_dirty) {
|
||||
|
@ -92,45 +95,28 @@ namespace NBToolkit.Map
|
|||
}
|
||||
|
||||
_dirty = true;
|
||||
_chunkMan.MarkChunkDirty(_cx, _cz);
|
||||
_cache.MarkChunkDirty(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*public bool Save ()
|
||||
{
|
||||
if (_dirty) {
|
||||
Region r = _chunkMan.GetRegion(_cx, _cz);
|
||||
if (r == null || !r.ChunkExists(LocalX, LocalZ)) {
|
||||
throw new MissingChunkException();
|
||||
}
|
||||
|
||||
if (GetChunk().Save(r.GetChunkOutStream(_cx, _cz))) {
|
||||
_dirty = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}*/
|
||||
|
||||
public ChunkRef GetNorthNeighbor ()
|
||||
{
|
||||
return _chunkMan.GetChunkRef(_cx - 1, _cz);
|
||||
return _container.GetChunkRef(_cx - 1, _cz);
|
||||
}
|
||||
|
||||
public ChunkRef GetSouthNeighbor ()
|
||||
{
|
||||
return _chunkMan.GetChunkRef(_cx + 1, _cz);
|
||||
return _container.GetChunkRef(_cx + 1, _cz);
|
||||
}
|
||||
|
||||
public ChunkRef GetEastNeighbor ()
|
||||
{
|
||||
return _chunkMan.GetChunkRef(_cx, _cz - 1);
|
||||
return _container.GetChunkRef(_cx, _cz - 1);
|
||||
}
|
||||
|
||||
public ChunkRef GetWestNeighbor ()
|
||||
{
|
||||
return _chunkMan.GetChunkRef(_cx, _cz + 1);
|
||||
return _container.GetChunkRef(_cx, _cz + 1);
|
||||
}
|
||||
|
||||
public Chunk GetChunkCopy ()
|
||||
|
|
|
@ -8,37 +8,7 @@ namespace NBToolkit.Map
|
|||
{
|
||||
using NBT;
|
||||
|
||||
public interface IChunkContainer
|
||||
{
|
||||
int GlobalX (int cx);
|
||||
int GlobalZ (int cz);
|
||||
|
||||
int LocalX (int cx);
|
||||
int LocalZ (int cz);
|
||||
|
||||
Chunk GetChunk (int cx, int cz);
|
||||
ChunkRef GetChunkRef (int cx, int cz);
|
||||
|
||||
bool ChunkExists (int cx, int cz);
|
||||
|
||||
bool DeleteChunk (int cx, int cz);
|
||||
|
||||
bool Save ();
|
||||
bool SaveChunk (Chunk chunk);
|
||||
|
||||
bool MarkChunkDirty (int cx, int cz);
|
||||
bool MarkChunkClean (int cx, int cz);
|
||||
}
|
||||
|
||||
public interface IRegion : IChunkContainer
|
||||
{
|
||||
int X { get; }
|
||||
int Z { get; }
|
||||
|
||||
int ChunkCount ();
|
||||
}
|
||||
|
||||
public class Region : IDisposable
|
||||
public class Region : IDisposable, IChunkContainer, IChunkCache
|
||||
{
|
||||
protected int _rx;
|
||||
protected int _rz;
|
||||
|
@ -50,6 +20,9 @@ namespace NBToolkit.Map
|
|||
|
||||
protected WeakReference _regionFile;
|
||||
|
||||
protected Dictionary<ChunkKey, WeakReference> _cache;
|
||||
protected Dictionary<ChunkKey, ChunkRef> _dirty;
|
||||
|
||||
public int X
|
||||
{
|
||||
get { return _rx; }
|
||||
|
@ -67,6 +40,9 @@ namespace NBToolkit.Map
|
|||
_rx = rx;
|
||||
_rz = rz;
|
||||
|
||||
_cache = new Dictionary<ChunkKey, WeakReference>();
|
||||
_dirty = new Dictionary<ChunkKey, ChunkRef>();
|
||||
|
||||
if (!File.Exists(GetFilePath())) {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
|
@ -112,20 +88,6 @@ namespace NBToolkit.Map
|
|||
_disposed = true;
|
||||
}
|
||||
|
||||
public Chunk GetChunk (int lcx, int lcz)
|
||||
{
|
||||
if (!ChunkExists(lcx, lcz)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Chunk(GetChunkTree(lcx, lcz));
|
||||
}
|
||||
|
||||
//public ChunkRef GetChunkRef (int lcx, int lcz)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
public string GetFileName ()
|
||||
{
|
||||
return "r." + _rx + "." + _rz + ".mcr";
|
||||
|
@ -204,12 +166,6 @@ namespace NBToolkit.Map
|
|||
return rf.GetChunkDataOutputStream(lcx, lcz);
|
||||
}
|
||||
|
||||
public bool ChunkExists (int lcx, int lcz)
|
||||
{
|
||||
RegionFile rf = GetRegionFile();
|
||||
return rf.HasChunk(lcx, lcz);
|
||||
}
|
||||
|
||||
public int ChunkCount ()
|
||||
{
|
||||
RegionFile rf = GetRegionFile();
|
||||
|
@ -226,6 +182,77 @@ namespace NBToolkit.Map
|
|||
return count;
|
||||
}
|
||||
|
||||
public ChunkRef GetChunkRef (int lcx, int lcz, IChunkCache cache)
|
||||
{
|
||||
ChunkKey k = new ChunkKey(lcx, lcz);
|
||||
|
||||
ChunkRef c = null;
|
||||
|
||||
WeakReference chunkref = null;
|
||||
if (_cache.TryGetValue(k, out chunkref)) {
|
||||
c = chunkref.Target as ChunkRef;
|
||||
}
|
||||
else {
|
||||
_cache.Add(k, new WeakReference(null));
|
||||
}
|
||||
|
||||
if (c != null) {
|
||||
return c;
|
||||
}
|
||||
|
||||
try {
|
||||
c = new ChunkRef(this, cache, lcx, lcz);
|
||||
_cache[k].Target = c;
|
||||
return c;
|
||||
}
|
||||
catch (MissingChunkException) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region IChunkCollection Members
|
||||
|
||||
public int ChunkGlobalX (int cx)
|
||||
{
|
||||
return cx;
|
||||
}
|
||||
|
||||
public int ChunkGlobalZ (int cz)
|
||||
{
|
||||
return cz;
|
||||
}
|
||||
|
||||
public int ChunkLocalX (int cx)
|
||||
{
|
||||
return cx & ChunkManager.REGION_XMASK;
|
||||
}
|
||||
|
||||
public int ChunkLocalZ (int cz)
|
||||
{
|
||||
return cz & ChunkManager.REGION_ZMASK;
|
||||
}
|
||||
|
||||
public Chunk GetChunk (int lcx, int lcz)
|
||||
{
|
||||
if (!ChunkExists(lcx, lcz)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Chunk(GetChunkTree(lcx, lcz));
|
||||
}
|
||||
|
||||
public ChunkRef GetChunkRef (int lcx, int lcz)
|
||||
{
|
||||
return GetChunkRef(lcx, lcz, this);
|
||||
}
|
||||
|
||||
public bool ChunkExists (int lcx, int lcz)
|
||||
{
|
||||
RegionFile rf = GetRegionFile();
|
||||
return rf.HasChunk(lcx, lcz);
|
||||
}
|
||||
|
||||
public bool DeleteChunk (int lcx, int lcz)
|
||||
{
|
||||
RegionFile rf = GetRegionFile();
|
||||
|
@ -234,7 +261,71 @@ namespace NBToolkit.Map
|
|||
}
|
||||
|
||||
rf.DeleteChunk(lcx, lcz);
|
||||
|
||||
ChunkKey k = new ChunkKey(lcx, lcz);
|
||||
_cache.Remove(k);
|
||||
_dirty.Remove(k);
|
||||
|
||||
if (ChunkCount() == 0) {
|
||||
_regionMan.DeleteRegion(X, Z);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int Save ()
|
||||
{
|
||||
int saved = 0;
|
||||
foreach (ChunkRef c in _dirty.Values) {
|
||||
int lcx = ChunkLocalX(c.X);
|
||||
int lcz = ChunkLocalZ(c.Z);
|
||||
|
||||
if (!ChunkExists(lcx, lcz)) {
|
||||
throw new MissingChunkException();
|
||||
}
|
||||
|
||||
if (c.Save(GetChunkOutStream(lcx, lcz))) {
|
||||
saved++;
|
||||
}
|
||||
}
|
||||
|
||||
_dirty.Clear();
|
||||
return saved;
|
||||
}
|
||||
|
||||
public bool SaveChunk (Chunk chunk)
|
||||
{
|
||||
return chunk.Save(GetChunkOutStream(ChunkLocalX(chunk.X), ChunkLocalZ(chunk.Z)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region IChunkCache Members
|
||||
|
||||
public bool MarkChunkDirty (ChunkRef chunk)
|
||||
{
|
||||
int lcx = chunk.LocalX;
|
||||
int lcz = chunk.LocalZ;
|
||||
|
||||
ChunkKey k = new ChunkKey(lcx, lcz);
|
||||
if (!_dirty.ContainsKey(k)) {
|
||||
_dirty.Add(k, GetChunkRef(lcx, lcz));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool MarkChunkClean (int lcx, int lcz)
|
||||
{
|
||||
ChunkKey k = new ChunkKey(lcx, lcz);
|
||||
if (_dirty.ContainsKey(k)) {
|
||||
_dirty.Remove(k);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue