forked from mirrors/NBTExplorer
Organizational
This commit is contained in:
parent
63e0bc1876
commit
66dfc9da95
8 changed files with 1591 additions and 1601 deletions
82
SubstrateCS/Source/AnvilRegion.cs
Normal file
82
SubstrateCS/Source/AnvilRegion.cs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
using System;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Substrate.Core;
|
||||||
|
using Substrate.Nbt;
|
||||||
|
|
||||||
|
namespace Substrate
|
||||||
|
{
|
||||||
|
public class AnvilRegion : Region
|
||||||
|
{
|
||||||
|
private static Regex _namePattern = new Regex("r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mcr$");
|
||||||
|
|
||||||
|
public AnvilRegion (AnvilRegionManager rm, ChunkCache cache, int rx, int rz)
|
||||||
|
: base(rm, cache, rx, rz)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inherits />
|
||||||
|
public override string GetFileName ()
|
||||||
|
{
|
||||||
|
return "r." + _rx + "." + _rz + ".mcr";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inherits />
|
||||||
|
public override string GetFilePath ()
|
||||||
|
{
|
||||||
|
return System.IO.Path.Combine(_regionMan.GetRegionPath(), GetFileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests if the given filename conforms to the general naming pattern for any region.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The filename to test.</param>
|
||||||
|
/// <returns>True if the filename is a valid region name; false if it does not conform to the pattern.</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses the given filename to extract encoded region coordinates.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The region filename to parse.</param>
|
||||||
|
/// <param name="x">This parameter will contain the X-coordinate of a region.</param>
|
||||||
|
/// <param name="z">This parameter will contain the Z-coordinate of a region.</param>
|
||||||
|
/// <returns>True if the filename could be correctly parse; false otherwise.</returns>
|
||||||
|
protected override bool ParseFileNameCore (string filename, out int x, out int z)
|
||||||
|
{
|
||||||
|
return ParseFileName(filename, out x, out z);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IChunk CreateChunkCore (int cx, int cz)
|
||||||
|
{
|
||||||
|
return AlphaChunk.Create(cz, cz);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IChunk CreateChunkVerifiedCore (NbtTree tree)
|
||||||
|
{
|
||||||
|
return AlphaChunk.CreateVerified(tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
SubstrateCS/Source/AnvilRegionManager.cs
Normal file
43
SubstrateCS/Source/AnvilRegionManager.cs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Substrate.Core;
|
||||||
|
|
||||||
|
namespace Substrate
|
||||||
|
{
|
||||||
|
public class AnvilRegionManager : RegionManager
|
||||||
|
{
|
||||||
|
public AnvilRegionManager (string regionDir, ChunkCache cache)
|
||||||
|
: base(regionDir, cache)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IRegion CreateRegionCore (int rx, int rz)
|
||||||
|
{
|
||||||
|
return new AnvilRegion(this, _chunkCache, rx, rz);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override RegionFile CreateRegionFileCore (int rx, int rz)
|
||||||
|
{
|
||||||
|
string fp = "r." + rx + "." + rz + ".mca";
|
||||||
|
return new RegionFile(Path.Combine(_regionPath, fp));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DeleteRegionCore (IRegion region)
|
||||||
|
{
|
||||||
|
AnvilRegion r = region as AnvilRegion;
|
||||||
|
if (r != null) {
|
||||||
|
r.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IRegion GetRegion (string filename)
|
||||||
|
{
|
||||||
|
int rx, rz;
|
||||||
|
if (!AnvilRegion.ParseFileName(filename, out rx, out rz)) {
|
||||||
|
throw new ArgumentException("Malformed region file name: " + filename, "filename");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetRegion(rx, rz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
SubstrateCS/Source/BetaRegion.cs
Normal file
82
SubstrateCS/Source/BetaRegion.cs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
using System;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Substrate.Core;
|
||||||
|
using Substrate.Nbt;
|
||||||
|
|
||||||
|
namespace Substrate
|
||||||
|
{
|
||||||
|
public class BetaRegion : Region
|
||||||
|
{
|
||||||
|
private static Regex _namePattern = new Regex("r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mcr$");
|
||||||
|
|
||||||
|
public BetaRegion (BetaRegionManager rm, ChunkCache cache, int rx, int rz)
|
||||||
|
: base(rm, cache, rx, rz)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inherits />
|
||||||
|
public override string GetFileName ()
|
||||||
|
{
|
||||||
|
return "r." + _rx + "." + _rz + ".mcr";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inherits />
|
||||||
|
public override string GetFilePath ()
|
||||||
|
{
|
||||||
|
return System.IO.Path.Combine(_regionMan.GetRegionPath(), GetFileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests if the given filename conforms to the general naming pattern for any region.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The filename to test.</param>
|
||||||
|
/// <returns>True if the filename is a valid region name; false if it does not conform to the pattern.</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses the given filename to extract encoded region coordinates.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The region filename to parse.</param>
|
||||||
|
/// <param name="x">This parameter will contain the X-coordinate of a region.</param>
|
||||||
|
/// <param name="z">This parameter will contain the Z-coordinate of a region.</param>
|
||||||
|
/// <returns>True if the filename could be correctly parse; false otherwise.</returns>
|
||||||
|
protected override bool ParseFileNameCore (string filename, out int x, out int z)
|
||||||
|
{
|
||||||
|
return ParseFileName(filename, out x, out z);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IChunk CreateChunkCore (int cx, int cz)
|
||||||
|
{
|
||||||
|
return AlphaChunk.Create(cz, cz);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IChunk CreateChunkVerifiedCore (NbtTree tree)
|
||||||
|
{
|
||||||
|
return AlphaChunk.CreateVerified(tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
SubstrateCS/Source/BetaRegionManager.cs
Normal file
43
SubstrateCS/Source/BetaRegionManager.cs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Substrate.Core;
|
||||||
|
|
||||||
|
namespace Substrate
|
||||||
|
{
|
||||||
|
public class BetaRegionManager : RegionManager
|
||||||
|
{
|
||||||
|
public BetaRegionManager (string regionDir, ChunkCache cache)
|
||||||
|
: base(regionDir, cache)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IRegion CreateRegionCore (int rx, int rz)
|
||||||
|
{
|
||||||
|
return new BetaRegion(this, _chunkCache, rx, rz);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override RegionFile CreateRegionFileCore (int rx, int rz)
|
||||||
|
{
|
||||||
|
string fp = "r." + rx + "." + rz + ".mcr";
|
||||||
|
return new RegionFile(Path.Combine(_regionPath, fp));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DeleteRegionCore (IRegion region)
|
||||||
|
{
|
||||||
|
BetaRegion r = region as BetaRegion;
|
||||||
|
if (r != null) {
|
||||||
|
r.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IRegion GetRegion (string filename)
|
||||||
|
{
|
||||||
|
int rx, rz;
|
||||||
|
if (!BetaRegion.ParseFileName(filename, out rx, out rz)) {
|
||||||
|
throw new ArgumentException("Malformed region file name: " + filename, "filename");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetRegion(rx, rz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,9 +1,120 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
using System.IO;
|
||||||
using System.Text;
|
using Substrate.Nbt;
|
||||||
|
|
||||||
namespace Substrate.Core
|
namespace Substrate.Core
|
||||||
{
|
{
|
||||||
|
public interface IRegion : IChunkContainer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the global X-coordinate of the region.
|
||||||
|
/// </summary>
|
||||||
|
int X { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the global Z-coordinate of the region.
|
||||||
|
/// </summary>
|
||||||
|
int Z { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the appropriate filename for this region.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The filename of the region with encoded coordinates.</returns>
|
||||||
|
string GetFileName ();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the full path of the region's backing file.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Gets the path of the region's file based on the <see cref="IRegionManager"/>'s region path and the region's on filename.</returns>
|
||||||
|
string GetFilePath ();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="NbtTree"/> for a chunk given local coordinates into the region.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lcx">The local X-coordinate of a chunk within the region.</param>
|
||||||
|
/// <param name="lcz">The local Z-coordinate of a chunk within the region.</param>
|
||||||
|
/// <returns>An <see cref="NbtTree"/> for a local chunk, or null if there is no chunk at the given coordinates.</returns>
|
||||||
|
NbtTree GetChunkTree (int lcx, int lcz);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves an <see cref="NbtTree"/> for a chunk back to the region's data store at the given local coordinates.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lcx">The local X-coordinate of the chunk within the region.</param>
|
||||||
|
/// <param name="lcz">The local Z-coordinate of the chunk within the region.</param>
|
||||||
|
/// <param name="tree">The <see cref="NbtTree"/> of a chunk to write back to the region.</param>
|
||||||
|
/// <returns>True if the save succeeded.</returns>
|
||||||
|
/// <remarks>It is up to the programmer to ensure that the global coordinates defined within the chunk's tree
|
||||||
|
/// are consistent with the local coordinates of the region being written into.</remarks>
|
||||||
|
bool SaveChunkTree (int lcx, int lcz, NbtTree tree);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves an <see cref="NbtTree"/> for a chunk back to the region's data store at the given local coordinates and with the given timestamp.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lcx">The local X-coordinate of the chunk within the region.</param>
|
||||||
|
/// <param name="lcz">The local Z-coordinate of the chunk within the region.</param>
|
||||||
|
/// <param name="tree">The <see cref="NbtTree"/> of a chunk to write back to the region.</param>
|
||||||
|
/// <param name="timestamp">The timestamp to write to the underlying region file for this chunk.</param>
|
||||||
|
/// <returns>True if the save succeeded.</returns>
|
||||||
|
/// <remarks>It is up to the programmer to ensure that the global coordinates defined within the chunk's tree
|
||||||
|
/// are consistent with the local coordinates of the region being written into.</remarks>
|
||||||
|
bool SaveChunkTree (int lcx, int lcz, NbtTree tree, int timestamp);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an output stream for replacing chunk data at the given coordinates within the region.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lcx">The local X-coordinate of the chunk to replace within the region.</param>
|
||||||
|
/// <param name="lcz">The local Z-coordinate of the chunk to replace within the region.</param>
|
||||||
|
/// <returns>An output stream that can be written to on demand.</returns>
|
||||||
|
/// <remarks>There is no guarantee that any data will be saved until the stream is closed.</remarks>
|
||||||
|
Stream GetChunkOutStream (int lcx, int lcz);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the count of valid chunks stored in this region.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The count of currently stored chunks.</returns>
|
||||||
|
int ChunkCount ();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="ChunkRef"/> for a chunk at the given local coordinates relative to this region.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
|
||||||
|
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
|
||||||
|
/// <returns>A <see cref="ChunkRef"/> at the given local coordinates, or null if no chunk exists.</returns>
|
||||||
|
/// <remarks>The local coordinates do not strictly need to be within the bounds of the region. If coordinates are detected
|
||||||
|
/// as being out of bounds, the lookup will be delegated to the correct region and the lookup will be performed there
|
||||||
|
/// instead. This allows any <see cref="Region"/> to perform a similar task to <see cref="RegionChunkManager"/>, but with a
|
||||||
|
/// region-local frame of reference instead of a global frame of reference.</remarks>
|
||||||
|
ChunkRef GetChunkRef (int lcx, int lcz);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new chunk at the given local coordinates relative to this region and returns a new <see cref="ChunkRef"/> for it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
|
||||||
|
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
|
||||||
|
/// <returns>A <see cref="ChunkRef"/> for the newly created chunk.</returns>
|
||||||
|
/// <remarks>If the local coordinates are out of bounds for this region, the action will be forwarded to the correct region
|
||||||
|
/// transparently.</remarks>
|
||||||
|
ChunkRef CreateChunk (int lcx, int lcz);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the timestamp of a chunk from the underlying region file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
|
||||||
|
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
|
||||||
|
/// <returns>The timestamp of the chunk slot in the region.</returns>
|
||||||
|
/// <remarks>The value returned may differ from any timestamp stored in the chunk data itself.</remarks>
|
||||||
|
int GetChunkTimestamp (int lcx, int lcz);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the timestamp of a chunk in the underlying region file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
|
||||||
|
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
|
||||||
|
/// <param name="timestamp">The new timestamp value.</param>
|
||||||
|
/// <remarks>This function will only update the timestamp of the chunk slot in the underlying region file. It will not update
|
||||||
|
/// any timestamp information in the chunk data itself.</remarks>
|
||||||
|
void SetChunkTimestamp (int lcx, int lcz, int timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
public interface IRegionContainer
|
public interface IRegionContainer
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,298 +1,219 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Substrate.Core;
|
using Substrate.Core;
|
||||||
|
|
||||||
namespace Substrate
|
namespace Substrate.Core
|
||||||
{
|
{
|
||||||
public class BetaRegionManager : RegionManager
|
/// <summary>
|
||||||
{
|
/// Manages the regions of a Beta-compatible world.
|
||||||
public BetaRegionManager (string regionDir, ChunkCache cache)
|
/// </summary>
|
||||||
: base(regionDir, cache)
|
public abstract class RegionManager : IRegionManager
|
||||||
{
|
{
|
||||||
}
|
protected string _regionPath;
|
||||||
|
|
||||||
protected override IRegion CreateRegionCore (int rx, int rz)
|
protected Dictionary<RegionKey, IRegion> _cache;
|
||||||
{
|
|
||||||
return new BetaRegion(this, _chunkCache, rx, rz);
|
protected ChunkCache _chunkCache;
|
||||||
}
|
|
||||||
|
|
||||||
protected override RegionFile CreateRegionFileCore (int rx, int rz)
|
protected abstract IRegion CreateRegionCore (int rx, int rz);
|
||||||
{
|
|
||||||
string fp = "r." + rx + "." + rz + ".mcr";
|
protected abstract RegionFile CreateRegionFileCore (int rx, int rz);
|
||||||
return new RegionFile(Path.Combine(_regionPath, fp));
|
|
||||||
}
|
protected abstract void DeleteRegionCore (IRegion region);
|
||||||
|
|
||||||
protected override void DeleteRegionCore (IRegion region)
|
public abstract IRegion GetRegion (string filename);
|
||||||
{
|
|
||||||
BetaRegion r = region as BetaRegion;
|
/// <summary>
|
||||||
if (r != null) {
|
/// Creates a new instance of a <see cref="RegionManager"/> for the given region directory and chunk cache.
|
||||||
r.Dispose();
|
/// </summary>
|
||||||
}
|
/// <param name="regionDir">The path to a directory containing region files.</param>
|
||||||
}
|
/// <param name="cache">The shared chunk cache to hold chunk data in.</param>
|
||||||
|
public RegionManager (string regionDir, ChunkCache cache)
|
||||||
public override IRegion GetRegion (string filename)
|
{
|
||||||
{
|
_regionPath = regionDir;
|
||||||
int rx, rz;
|
_chunkCache = cache;
|
||||||
if (!BetaRegion.ParseFileName(filename, out rx, out rz)) {
|
_cache = new Dictionary<RegionKey, IRegion>();
|
||||||
throw new ArgumentException("Malformed region file name: " + filename, "filename");
|
}
|
||||||
}
|
|
||||||
|
/// <inherits />
|
||||||
return GetRegion(rx, rz);
|
public IRegion GetRegion (int rx, int rz)
|
||||||
}
|
{
|
||||||
}
|
RegionKey k = new RegionKey(rx, rz);
|
||||||
|
IRegion r;
|
||||||
public class AnvilRegionManager : RegionManager
|
|
||||||
{
|
try {
|
||||||
public AnvilRegionManager (string regionDir, ChunkCache cache)
|
if (_cache.TryGetValue(k, out r) == false) {
|
||||||
: base(regionDir, cache)
|
r = CreateRegionCore(rz, rz);
|
||||||
{
|
_cache.Add(k, r);
|
||||||
}
|
}
|
||||||
|
return r;
|
||||||
protected override IRegion CreateRegionCore (int rx, int rz)
|
}
|
||||||
{
|
catch (FileNotFoundException) {
|
||||||
return new AnvilRegion(this, _chunkCache, rx, rz);
|
_cache.Add(k, null);
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
protected override RegionFile CreateRegionFileCore (int rx, int rz)
|
}
|
||||||
{
|
|
||||||
string fp = "r." + rx + "." + rz + ".mca";
|
/// <inherits />
|
||||||
return new RegionFile(Path.Combine(_regionPath, fp));
|
public bool RegionExists (int rx, int rz)
|
||||||
}
|
{
|
||||||
|
IRegion r = GetRegion(rx, rz);
|
||||||
protected override void DeleteRegionCore (IRegion region)
|
return r != null;
|
||||||
{
|
}
|
||||||
AnvilRegion r = region as AnvilRegion;
|
|
||||||
if (r != null) {
|
/// <inherits />
|
||||||
r.Dispose();
|
public IRegion CreateRegion (int rx, int rz)
|
||||||
}
|
{
|
||||||
}
|
IRegion r = GetRegion(rx, rz);
|
||||||
|
if (r == null) {
|
||||||
public override IRegion GetRegion (string filename)
|
string fp = "r." + rx + "." + rz + ".mca";
|
||||||
{
|
using (RegionFile rf = CreateRegionFileCore(rx, rz)) {
|
||||||
int rx, rz;
|
|
||||||
if (!AnvilRegion.ParseFileName(filename, out rx, out rz)) {
|
}
|
||||||
throw new ArgumentException("Malformed region file name: " + filename, "filename");
|
|
||||||
}
|
r = CreateRegionCore(rx, rz);
|
||||||
|
|
||||||
return GetRegion(rx, rz);
|
RegionKey k = new RegionKey(rx, rz);
|
||||||
}
|
_cache[k] = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
return r;
|
||||||
/// Manages the regions of a Beta-compatible world.
|
}
|
||||||
/// </summary>
|
|
||||||
public abstract class RegionManager : IRegionManager
|
/// <summary>
|
||||||
{
|
/// Get the current region directory path.
|
||||||
protected string _regionPath;
|
/// </summary>
|
||||||
|
/// <returns>The path to the region directory.</returns>
|
||||||
protected Dictionary<RegionKey, IRegion> _cache;
|
public string GetRegionPath ()
|
||||||
|
{
|
||||||
protected ChunkCache _chunkCache;
|
return _regionPath;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract IRegion CreateRegionCore (int rx, int rz);
|
// XXX: Exceptions
|
||||||
|
/// <inherits />
|
||||||
protected abstract RegionFile CreateRegionFileCore (int rx, int rz);
|
public bool DeleteRegion (int rx, int rz)
|
||||||
|
{
|
||||||
protected abstract void DeleteRegionCore (IRegion region);
|
IRegion r = GetRegion(rx, rz);
|
||||||
|
if (r == null) {
|
||||||
public abstract IRegion GetRegion (string filename);
|
return false;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of a <see cref="RegionManager"/> for the given region directory and chunk cache.
|
RegionKey k = new RegionKey(rx, rz);
|
||||||
/// </summary>
|
_cache.Remove(k);
|
||||||
/// <param name="regionDir">The path to a directory containing region files.</param>
|
|
||||||
/// <param name="cache">The shared chunk cache to hold chunk data in.</param>
|
DeleteRegionCore(r);
|
||||||
public RegionManager (string regionDir, ChunkCache cache)
|
|
||||||
{
|
try {
|
||||||
_regionPath = regionDir;
|
File.Delete(r.GetFilePath());
|
||||||
_chunkCache = cache;
|
}
|
||||||
_cache = new Dictionary<RegionKey, IRegion>();
|
catch (Exception e) {
|
||||||
}
|
Console.WriteLine("NOTICE: " + e.Message);
|
||||||
|
return false;
|
||||||
/// <summary>
|
}
|
||||||
/// Gets a <see cref="Region"/> at the given coordinates.
|
|
||||||
/// </summary>
|
return true;
|
||||||
/// <param name="rx">The global X-coordinate of a region.</param>
|
}
|
||||||
/// <param name="rz">The global Z-coordinate of a region.</param>
|
|
||||||
/// <returns>A <see cref="Region"/> representing a region at the given coordinates, or null if the region does not exist.</returns>
|
#region IEnumerable<IRegion> Members
|
||||||
public IRegion GetRegion (int rx, int rz)
|
|
||||||
{
|
/// <summary>
|
||||||
RegionKey k = new RegionKey(rx, rz);
|
/// Returns an enumerator that iterates over all of the regions in the underlying dimension.
|
||||||
IRegion r;
|
/// </summary>
|
||||||
|
/// <returns>An enumerator instance.</returns>
|
||||||
try {
|
public IEnumerator<IRegion> GetEnumerator ()
|
||||||
if (_cache.TryGetValue(k, out r) == false) {
|
{
|
||||||
r = CreateRegionCore(rz, rz);
|
return new Enumerator(this);
|
||||||
_cache.Add(k, r);
|
}
|
||||||
}
|
|
||||||
return r;
|
#endregion
|
||||||
}
|
|
||||||
catch (FileNotFoundException) {
|
#region IEnumerable Members
|
||||||
_cache.Add(k, null);
|
|
||||||
return null;
|
/// <summary>
|
||||||
}
|
/// Returns an enumerator that iterates over all of the regions in the underlying dimension.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <returns>An enumerator instance.</returns>
|
||||||
/// <inherits />
|
IEnumerator IEnumerable.GetEnumerator ()
|
||||||
public bool RegionExists (int rx, int rz)
|
{
|
||||||
{
|
return new Enumerator(this);
|
||||||
IRegion r = GetRegion(rx, rz);
|
}
|
||||||
return r != null;
|
|
||||||
}
|
#endregion
|
||||||
|
|
||||||
/// <inherits />
|
|
||||||
public IRegion CreateRegion (int rx, int rz)
|
private struct Enumerator : IEnumerator<IRegion>
|
||||||
{
|
{
|
||||||
IRegion r = GetRegion(rx, rz);
|
private List<IRegion> _regions;
|
||||||
if (r == null) {
|
private int _pos;
|
||||||
string fp = "r." + rx + "." + rz + ".mca";
|
|
||||||
using (RegionFile rf = CreateRegionFileCore(rx, rz)) {
|
public Enumerator (RegionManager rm)
|
||||||
|
{
|
||||||
}
|
_regions = new List<IRegion>();
|
||||||
|
_pos = -1;
|
||||||
r = CreateRegionCore(rx, rz);
|
|
||||||
|
if (!Directory.Exists(rm.GetRegionPath())) {
|
||||||
RegionKey k = new RegionKey(rx, rz);
|
throw new DirectoryNotFoundException();
|
||||||
_cache[k] = r;
|
}
|
||||||
}
|
|
||||||
|
string[] files = Directory.GetFiles(rm.GetRegionPath());
|
||||||
return r;
|
_regions.Capacity = files.Length;
|
||||||
}
|
|
||||||
|
foreach (string file in files) {
|
||||||
/// <summary>
|
try {
|
||||||
/// Get the current region directory path.
|
IRegion r = rm.GetRegion(file);
|
||||||
/// </summary>
|
_regions.Add(r);
|
||||||
/// <returns>The path to the region directory.</returns>
|
}
|
||||||
public string GetRegionPath ()
|
catch (ArgumentException) {
|
||||||
{
|
continue;
|
||||||
return _regionPath;
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// XXX: Exceptions
|
|
||||||
/// <inherits />
|
public bool MoveNext ()
|
||||||
public bool DeleteRegion (int rx, int rz)
|
{
|
||||||
{
|
_pos++;
|
||||||
IRegion r = GetRegion(rx, rz);
|
return (_pos < _regions.Count);
|
||||||
if (r == null) {
|
}
|
||||||
return false;
|
|
||||||
}
|
public void Reset ()
|
||||||
|
{
|
||||||
RegionKey k = new RegionKey(rx, rz);
|
_pos = -1;
|
||||||
_cache.Remove(k);
|
}
|
||||||
|
|
||||||
DeleteRegionCore(r);
|
void IDisposable.Dispose () { }
|
||||||
|
|
||||||
try {
|
object IEnumerator.Current
|
||||||
File.Delete(r.GetFilePath());
|
{
|
||||||
}
|
get
|
||||||
catch (Exception e) {
|
{
|
||||||
Console.WriteLine("NOTICE: " + e.Message);
|
return Current;
|
||||||
return false;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
IRegion IEnumerator<IRegion>.Current
|
||||||
}
|
{
|
||||||
|
get
|
||||||
#region IEnumerable<IRegion> Members
|
{
|
||||||
|
return Current;
|
||||||
/// <summary>
|
}
|
||||||
/// Returns an enumerator that iterates over all of the regions in the underlying dimension.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <returns>An enumerator instance.</returns>
|
public IRegion Current
|
||||||
public IEnumerator<IRegion> GetEnumerator ()
|
{
|
||||||
{
|
get
|
||||||
return new Enumerator(this);
|
{
|
||||||
}
|
try {
|
||||||
|
return _regions[_pos];
|
||||||
#endregion
|
}
|
||||||
|
catch (IndexOutOfRangeException) {
|
||||||
#region IEnumerable Members
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
/// <summary>
|
}
|
||||||
/// Returns an enumerator that iterates over all of the regions in the underlying dimension.
|
}
|
||||||
/// </summary>
|
}
|
||||||
/// <returns>An enumerator instance.</returns>
|
|
||||||
IEnumerator IEnumerable.GetEnumerator ()
|
}
|
||||||
{
|
}
|
||||||
return new Enumerator(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
private struct Enumerator : IEnumerator<IRegion>
|
|
||||||
{
|
|
||||||
private List<IRegion> _regions;
|
|
||||||
private int _pos;
|
|
||||||
|
|
||||||
public Enumerator (RegionManager rm)
|
|
||||||
{
|
|
||||||
_regions = new List<IRegion>();
|
|
||||||
_pos = -1;
|
|
||||||
|
|
||||||
if (!Directory.Exists(rm.GetRegionPath())) {
|
|
||||||
throw new DirectoryNotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] files = Directory.GetFiles(rm.GetRegionPath());
|
|
||||||
_regions.Capacity = files.Length;
|
|
||||||
|
|
||||||
foreach (string file in files) {
|
|
||||||
try {
|
|
||||||
IRegion 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IRegion IEnumerator<IRegion>.Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IRegion Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return _regions[_pos];
|
|
||||||
}
|
|
||||||
catch (IndexOutOfRangeException) {
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,466 +1,466 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Substrate.Core;
|
using Substrate.Core;
|
||||||
|
|
||||||
namespace Substrate
|
namespace Substrate
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a Beta-compatible interface for globally managing chunks.
|
/// Represents a Beta-compatible interface for globally managing chunks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RegionChunkManager : IChunkManager, IEnumerable<ChunkRef>
|
public class RegionChunkManager : IChunkManager, IEnumerable<ChunkRef>
|
||||||
{
|
{
|
||||||
private const int REGION_XLEN = 32;
|
private const int REGION_XLEN = 32;
|
||||||
private const int REGION_ZLEN = 32;
|
private const int REGION_ZLEN = 32;
|
||||||
|
|
||||||
private const int REGION_XLOG = 5;
|
private const int REGION_XLOG = 5;
|
||||||
private const int REGION_ZLOG = 5;
|
private const int REGION_ZLOG = 5;
|
||||||
|
|
||||||
private const int REGION_XMASK = 0x1F;
|
private const int REGION_XMASK = 0x1F;
|
||||||
private const int REGION_ZMASK = 0x1F;
|
private const int REGION_ZMASK = 0x1F;
|
||||||
|
|
||||||
private IRegionManager _regionMan;
|
private IRegionManager _regionMan;
|
||||||
|
|
||||||
private ChunkCache _cache;
|
private ChunkCache _cache;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="RegionChunkManager"/> instance given a backing <see cref="RegionManager"/> and <see cref="ChunkCache"/>.
|
/// Creates a new <see cref="RegionChunkManager"/> instance given a backing <see cref="RegionManager"/> and <see cref="ChunkCache"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rm">A <see cref="RegionManager"/> exposing access to regions.</param>
|
/// <param name="rm">A <see cref="RegionManager"/> exposing access to regions.</param>
|
||||||
/// <param name="cache">A shared cache for storing chunks read in.</param>
|
/// <param name="cache">A shared cache for storing chunks read in.</param>
|
||||||
public RegionChunkManager (IRegionManager rm, ChunkCache cache)
|
public RegionChunkManager (IRegionManager rm, ChunkCache cache)
|
||||||
{
|
{
|
||||||
_regionMan = rm;
|
_regionMan = rm;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="RegionChunkManager"/> instance from another.
|
/// Creates a new <see cref="RegionChunkManager"/> instance from another.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cm">A <see cref="RegionChunkManager"/> to get a <see cref="RegionManager"/> and <see cref="ChunkCache"/> from.</param>
|
/// <param name="cm">A <see cref="RegionChunkManager"/> to get a <see cref="RegionManager"/> and <see cref="ChunkCache"/> from.</param>
|
||||||
public RegionChunkManager (RegionChunkManager cm)
|
public RegionChunkManager (RegionChunkManager cm)
|
||||||
{
|
{
|
||||||
_regionMan = cm._regionMan;
|
_regionMan = cm._regionMan;
|
||||||
_cache = cm._cache;
|
_cache = cm._cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="RegionManager"/> backing this manager.
|
/// Gets the <see cref="RegionManager"/> backing this manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IRegionManager RegionManager
|
public IRegionManager RegionManager
|
||||||
{
|
{
|
||||||
get { return _regionMan; }
|
get { return _regionMan; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IChunkContainer
|
#region IChunkContainer
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int ChunkGlobalX (int cx)
|
public int ChunkGlobalX (int cx)
|
||||||
{
|
{
|
||||||
return cx;
|
return cx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int ChunkGlobalZ (int cz)
|
public int ChunkGlobalZ (int cz)
|
||||||
{
|
{
|
||||||
return cz;
|
return cz;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int ChunkLocalX (int cx)
|
public int ChunkLocalX (int cx)
|
||||||
{
|
{
|
||||||
return cx & REGION_XMASK;
|
return cx & REGION_XMASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int ChunkLocalZ (int cz)
|
public int ChunkLocalZ (int cz)
|
||||||
{
|
{
|
||||||
return cz & REGION_ZMASK;
|
return cz & REGION_ZMASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IChunk GetChunk (int cx, int cz)
|
public IChunk GetChunk (int cx, int cz)
|
||||||
{
|
{
|
||||||
IRegion r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.GetChunk(cx & REGION_XMASK, cz & REGION_ZMASK);
|
return r.GetChunk(cx & REGION_XMASK, cz & REGION_ZMASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ChunkRef GetChunkRef (int cx, int cz)
|
public ChunkRef GetChunkRef (int cx, int cz)
|
||||||
{
|
{
|
||||||
IRegion r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.GetChunkRef(cx & REGION_XMASK, cz & REGION_ZMASK);
|
return r.GetChunkRef(cx & REGION_XMASK, cz & REGION_ZMASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool ChunkExists (int cx, int cz)
|
public bool ChunkExists (int cx, int cz)
|
||||||
{
|
{
|
||||||
IRegion r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.ChunkExists(cx & REGION_XMASK, cz & REGION_ZMASK);
|
return r.ChunkExists(cx & REGION_XMASK, cz & REGION_ZMASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ChunkRef CreateChunk (int cx, int cz)
|
public ChunkRef CreateChunk (int cx, int cz)
|
||||||
{
|
{
|
||||||
IRegion r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
int rx = cx >> REGION_XLOG;
|
int rx = cx >> REGION_XLOG;
|
||||||
int rz = cz >> REGION_ZLOG;
|
int rz = cz >> REGION_ZLOG;
|
||||||
r = _regionMan.CreateRegion(rx, rz);
|
r = _regionMan.CreateRegion(rx, rz);
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.CreateChunk(cx & REGION_XMASK, cz & REGION_ZMASK);
|
return r.CreateChunk(cx & REGION_XMASK, cz & REGION_ZMASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ChunkRef SetChunk (int cx, int cz, IChunk chunk)
|
public ChunkRef SetChunk (int cx, int cz, IChunk chunk)
|
||||||
{
|
{
|
||||||
IRegion r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
int rx = cx >> REGION_XLOG;
|
int rx = cx >> REGION_XLOG;
|
||||||
int rz = cz >> REGION_ZLOG;
|
int rz = cz >> REGION_ZLOG;
|
||||||
r = _regionMan.CreateRegion(rx, rz);
|
r = _regionMan.CreateRegion(rx, rz);
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk.SetLocation(cx, cz);
|
chunk.SetLocation(cx, cz);
|
||||||
r.SaveChunk(chunk);
|
r.SaveChunk(chunk);
|
||||||
|
|
||||||
return r.GetChunkRef(cx & REGION_XMASK, cz & REGION_ZMASK);
|
return r.GetChunkRef(cx & REGION_XMASK, cz & REGION_ZMASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int Save ()
|
public int Save ()
|
||||||
{
|
{
|
||||||
_cache.SyncDirty();
|
_cache.SyncDirty();
|
||||||
|
|
||||||
int saved = 0;
|
int saved = 0;
|
||||||
IEnumerator<ChunkRef> en = _cache.GetDirtyEnumerator();
|
IEnumerator<ChunkRef> en = _cache.GetDirtyEnumerator();
|
||||||
while (en.MoveNext()) {
|
while (en.MoveNext()) {
|
||||||
ChunkRef chunk = en.Current;
|
ChunkRef chunk = en.Current;
|
||||||
|
|
||||||
IRegion r = GetRegion(chunk.X, chunk.Z);
|
IRegion r = GetRegion(chunk.X, chunk.Z);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk.Save(r.GetChunkOutStream(chunk.LocalX, chunk.LocalZ));
|
chunk.Save(r.GetChunkOutStream(chunk.LocalX, chunk.LocalZ));
|
||||||
saved++;
|
saved++;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cache.ClearDirty();
|
_cache.ClearDirty();
|
||||||
return saved;
|
return saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool SaveChunk (IChunk chunk)
|
public bool SaveChunk (IChunk chunk)
|
||||||
{
|
{
|
||||||
IRegion r = GetRegion(chunk.X, chunk.Z);
|
IRegion r = GetRegion(chunk.X, chunk.Z);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.SaveChunk(chunk);
|
return r.SaveChunk(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool DeleteChunk (int cx, int cz)
|
public bool DeleteChunk (int cx, int cz)
|
||||||
{
|
{
|
||||||
IRegion r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!r.DeleteChunk(cx & REGION_XMASK, cz & REGION_ZMASK)) {
|
if (!r.DeleteChunk(cx & REGION_XMASK, cz & REGION_ZMASK)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.ChunkCount() == 0) {
|
if (r.ChunkCount() == 0) {
|
||||||
_regionMan.DeleteRegion(r.X, r.Z);
|
_regionMan.DeleteRegion(r.X, r.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool CanDelegateCoordinates
|
public bool CanDelegateCoordinates
|
||||||
{
|
{
|
||||||
get { return true; }
|
get { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copies a chunk from one location to another.
|
/// Copies a chunk from one location to another.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="src_cx">The global X-coordinate of the source chunk.</param>
|
/// <param name="src_cx">The global X-coordinate of the source chunk.</param>
|
||||||
/// <param name="src_cz">The global Z-coordinate of the source chunk.</param>
|
/// <param name="src_cz">The global Z-coordinate of the source chunk.</param>
|
||||||
/// <param name="dst_cx">The global X-coordinate of the destination chunk.</param>
|
/// <param name="dst_cx">The global X-coordinate of the destination chunk.</param>
|
||||||
/// <param name="dst_cz">The global Z-coordinate of the destination chunk.</param>
|
/// <param name="dst_cz">The global Z-coordinate of the destination chunk.</param>
|
||||||
/// <returns>A <see cref="ChunkRef"/> for the destination chunk.</returns>
|
/// <returns>A <see cref="ChunkRef"/> for the destination chunk.</returns>
|
||||||
public ChunkRef CopyChunk (int src_cx, int src_cz, int dst_cx, int dst_cz)
|
public ChunkRef CopyChunk (int src_cx, int src_cz, int dst_cx, int dst_cz)
|
||||||
{
|
{
|
||||||
IRegion src_r = GetRegion(src_cx, src_cz);
|
IRegion src_r = GetRegion(src_cx, src_cz);
|
||||||
if (src_r == null) {
|
if (src_r == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
IRegion dst_r = GetRegion(dst_cx, dst_cz);
|
IRegion dst_r = GetRegion(dst_cx, dst_cz);
|
||||||
if (dst_r == null) {
|
if (dst_r == null) {
|
||||||
int rx = dst_cx >> REGION_XLOG;
|
int rx = dst_cx >> REGION_XLOG;
|
||||||
int rz = dst_cz >> REGION_ZLOG;
|
int rz = dst_cz >> REGION_ZLOG;
|
||||||
dst_r = _regionMan.CreateRegion(rx, rz);
|
dst_r = _regionMan.CreateRegion(rx, rz);
|
||||||
}
|
}
|
||||||
|
|
||||||
IChunk c = src_r.GetChunk(src_cx & REGION_XMASK, src_cz & REGION_ZMASK);
|
IChunk c = src_r.GetChunk(src_cx & REGION_XMASK, src_cz & REGION_ZMASK);
|
||||||
c.SetLocation(dst_cx, dst_cz);
|
c.SetLocation(dst_cx, dst_cz);
|
||||||
|
|
||||||
dst_r.SaveChunk(c);
|
dst_r.SaveChunk(c);
|
||||||
|
|
||||||
return dst_r.GetChunkRef(dst_cx & REGION_XMASK, dst_cz & REGION_ZMASK);
|
return dst_r.GetChunkRef(dst_cx & REGION_XMASK, dst_cz & REGION_ZMASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a full chunk relight sequence on all modified chunks.
|
/// Performs a full chunk relight sequence on all modified chunks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void RelightDirtyChunks ()
|
public void RelightDirtyChunks ()
|
||||||
{
|
{
|
||||||
//List<ChunkRef> dirty = new List<ChunkRef>();
|
//List<ChunkRef> dirty = new List<ChunkRef>();
|
||||||
Dictionary<ChunkKey, ChunkRef> dirty = new Dictionary<ChunkKey, ChunkRef>();
|
Dictionary<ChunkKey, ChunkRef> dirty = new Dictionary<ChunkKey, ChunkRef>();
|
||||||
|
|
||||||
_cache.SyncDirty();
|
_cache.SyncDirty();
|
||||||
|
|
||||||
IEnumerator<ChunkRef> en = _cache.GetDirtyEnumerator();
|
IEnumerator<ChunkRef> en = _cache.GetDirtyEnumerator();
|
||||||
while (en.MoveNext()) {
|
while (en.MoveNext()) {
|
||||||
ChunkKey key = new ChunkKey(en.Current.X, en.Current.Z);
|
ChunkKey key = new ChunkKey(en.Current.X, en.Current.Z);
|
||||||
dirty[key] = en.Current;
|
dirty[key] = en.Current;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ChunkRef chunk in dirty.Values) {
|
foreach (ChunkRef chunk in dirty.Values) {
|
||||||
chunk.Blocks.ResetBlockLight();
|
chunk.Blocks.ResetBlockLight();
|
||||||
chunk.Blocks.ResetSkyLight();
|
chunk.Blocks.ResetSkyLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ChunkRef chunk in dirty.Values) {
|
foreach (ChunkRef chunk in dirty.Values) {
|
||||||
chunk.Blocks.RebuildBlockLight();
|
chunk.Blocks.RebuildBlockLight();
|
||||||
chunk.Blocks.RebuildSkyLight();
|
chunk.Blocks.RebuildSkyLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ChunkRef chunk in dirty.Values) {
|
foreach (ChunkRef chunk in dirty.Values) {
|
||||||
if (!dirty.ContainsKey(new ChunkKey(chunk.X, chunk.Z - 1))) {
|
if (!dirty.ContainsKey(new ChunkKey(chunk.X, chunk.Z - 1))) {
|
||||||
ChunkRef east = chunk.GetEastNeighbor();
|
ChunkRef east = chunk.GetEastNeighbor();
|
||||||
chunk.Blocks.StitchBlockLight(east.Blocks, BlockCollectionEdge.EAST);
|
chunk.Blocks.StitchBlockLight(east.Blocks, BlockCollectionEdge.EAST);
|
||||||
chunk.Blocks.StitchSkyLight(east.Blocks, BlockCollectionEdge.EAST);
|
chunk.Blocks.StitchSkyLight(east.Blocks, BlockCollectionEdge.EAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dirty.ContainsKey(new ChunkKey(chunk.X, chunk.Z + 1))) {
|
if (!dirty.ContainsKey(new ChunkKey(chunk.X, chunk.Z + 1))) {
|
||||||
ChunkRef west = chunk.GetWestNeighbor();
|
ChunkRef west = chunk.GetWestNeighbor();
|
||||||
chunk.Blocks.StitchBlockLight(west.Blocks, BlockCollectionEdge.WEST);
|
chunk.Blocks.StitchBlockLight(west.Blocks, BlockCollectionEdge.WEST);
|
||||||
chunk.Blocks.StitchSkyLight(west.Blocks, BlockCollectionEdge.WEST);
|
chunk.Blocks.StitchSkyLight(west.Blocks, BlockCollectionEdge.WEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dirty.ContainsKey(new ChunkKey(chunk.X - 1, chunk.Z))) {
|
if (!dirty.ContainsKey(new ChunkKey(chunk.X - 1, chunk.Z))) {
|
||||||
ChunkRef north = chunk.GetNorthNeighbor();
|
ChunkRef north = chunk.GetNorthNeighbor();
|
||||||
chunk.Blocks.StitchBlockLight(north.Blocks, BlockCollectionEdge.NORTH);
|
chunk.Blocks.StitchBlockLight(north.Blocks, BlockCollectionEdge.NORTH);
|
||||||
chunk.Blocks.StitchSkyLight(north.Blocks, BlockCollectionEdge.NORTH);
|
chunk.Blocks.StitchSkyLight(north.Blocks, BlockCollectionEdge.NORTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dirty.ContainsKey(new ChunkKey(chunk.X + 1, chunk.Z))) {
|
if (!dirty.ContainsKey(new ChunkKey(chunk.X + 1, chunk.Z))) {
|
||||||
ChunkRef south = chunk.GetSouthNeighbor();
|
ChunkRef south = chunk.GetSouthNeighbor();
|
||||||
chunk.Blocks.StitchBlockLight(south.Blocks, BlockCollectionEdge.SOUTH);
|
chunk.Blocks.StitchBlockLight(south.Blocks, BlockCollectionEdge.SOUTH);
|
||||||
chunk.Blocks.StitchSkyLight(south.Blocks, BlockCollectionEdge.SOUTH);
|
chunk.Blocks.StitchSkyLight(south.Blocks, BlockCollectionEdge.SOUTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the timestamp of the chunk from its underlying region file.
|
/// Gets the timestamp of the chunk from its underlying region file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cx">The global X-coordinate of a chunk.</param>
|
/// <param name="cx">The global X-coordinate of a chunk.</param>
|
||||||
/// <param name="cz">The global Z-coordinate of a chunk.</param>
|
/// <param name="cz">The global Z-coordinate of a chunk.</param>
|
||||||
/// <returns>The timestamp of the chunk from its underlying region file.</returns>
|
/// <returns>The timestamp of the chunk from its underlying region file.</returns>
|
||||||
/// <remarks>The value returned may differ from any timestamp stored in the chunk data itself.</remarks>
|
/// <remarks>The value returned may differ from any timestamp stored in the chunk data itself.</remarks>
|
||||||
public int GetChunkTimestamp (int cx, int cz)
|
public int GetChunkTimestamp (int cx, int cz)
|
||||||
{
|
{
|
||||||
IRegion r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.GetChunkTimestamp(cx & REGION_XMASK, cz & REGION_ZMASK);
|
return r.GetChunkTimestamp(cx & REGION_XMASK, cz & REGION_ZMASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the timestamp of the chunk in its underlying region file.
|
/// Sets the timestamp of the chunk in its underlying region file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cx">The global X-coordinate of a chunk.</param>
|
/// <param name="cx">The global X-coordinate of a chunk.</param>
|
||||||
/// <param name="cz">The global Z-coordinate of a chunk.</param>
|
/// <param name="cz">The global Z-coordinate of a chunk.</param>
|
||||||
/// <param name="timestamp">The new timestamp value.</param>
|
/// <param name="timestamp">The new timestamp value.</param>
|
||||||
/// <remarks>This function will only update the timestamp of the chunk slot in the underlying region file. It will not update
|
/// <remarks>This function will only update the timestamp of the chunk slot in the underlying region file. It will not update
|
||||||
/// any timestamp information in the chunk data itself.</remarks>
|
/// any timestamp information in the chunk data itself.</remarks>
|
||||||
public void SetChunkTimestamp (int cx, int cz, int timestamp)
|
public void SetChunkTimestamp (int cx, int cz, int timestamp)
|
||||||
{
|
{
|
||||||
IRegion r = GetRegion(cx, cz);
|
IRegion r = GetRegion(cx, cz);
|
||||||
if (r == null) {
|
if (r == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
r.SetChunkTimestamp(cx & REGION_XMASK, cz & REGION_ZMASK, timestamp);
|
r.SetChunkTimestamp(cx & REGION_XMASK, cz & REGION_ZMASK, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChunkRef GetChunkRefInRegion (IRegion r, int lcx, int lcz)
|
private ChunkRef GetChunkRefInRegion (IRegion r, int lcx, int lcz)
|
||||||
{
|
{
|
||||||
int cx = r.X * REGION_XLEN + lcx;
|
int cx = r.X * REGION_XLEN + lcx;
|
||||||
int cz = r.Z * REGION_ZLEN + lcz;
|
int cz = r.Z * REGION_ZLEN + lcz;
|
||||||
return GetChunkRef(cx, cz);
|
return GetChunkRef(cx, cz);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IRegion GetRegion (int cx, int cz)
|
private IRegion GetRegion (int cx, int cz)
|
||||||
{
|
{
|
||||||
cx >>= REGION_XLOG;
|
cx >>= REGION_XLOG;
|
||||||
cz >>= REGION_ZLOG;
|
cz >>= REGION_ZLOG;
|
||||||
return _regionMan.GetRegion(cx, cz);
|
return _regionMan.GetRegion(cx, cz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region IEnumerable<ChunkRef> Members
|
#region IEnumerable<ChunkRef> Members
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns an enumerator that iterates through all chunks in all regions of the world.
|
/// Returns an enumerator that iterates through all chunks in all regions of the world.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>An enumerator for this manager.</returns>
|
/// <returns>An enumerator for this manager.</returns>
|
||||||
public IEnumerator<ChunkRef> GetEnumerator ()
|
public IEnumerator<ChunkRef> GetEnumerator ()
|
||||||
{
|
{
|
||||||
return new Enumerator(this);
|
return new Enumerator(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region IEnumerable Members
|
#region IEnumerable Members
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
|
||||||
{
|
{
|
||||||
return new Enumerator(this);
|
return new Enumerator(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
private class Enumerator : IEnumerator<ChunkRef>
|
private class Enumerator : IEnumerator<ChunkRef>
|
||||||
{
|
{
|
||||||
private RegionChunkManager _cm;
|
private RegionChunkManager _cm;
|
||||||
|
|
||||||
private IEnumerator<IRegion> _enum;
|
private IEnumerator<IRegion> _enum;
|
||||||
private IRegion _region;
|
private IRegion _region;
|
||||||
private ChunkRef _chunk;
|
private ChunkRef _chunk;
|
||||||
|
|
||||||
private int _x = 0;
|
private int _x = 0;
|
||||||
private int _z = -1;
|
private int _z = -1;
|
||||||
|
|
||||||
public Enumerator (RegionChunkManager cm)
|
public Enumerator (RegionChunkManager cm)
|
||||||
{
|
{
|
||||||
_cm = cm;
|
_cm = cm;
|
||||||
_enum = _cm.RegionManager.GetEnumerator();
|
_enum = _cm.RegionManager.GetEnumerator();
|
||||||
_enum.MoveNext();
|
_enum.MoveNext();
|
||||||
_region = _enum.Current;
|
_region = _enum.Current;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool MoveNext ()
|
public virtual bool MoveNext ()
|
||||||
{
|
{
|
||||||
if (_enum == null) {
|
if (_enum == null) {
|
||||||
return MoveNextInRegion();
|
return MoveNextInRegion();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (_x >= RegionChunkManager.REGION_XLEN) {
|
if (_x >= RegionChunkManager.REGION_XLEN) {
|
||||||
if (!_enum.MoveNext()) {
|
if (!_enum.MoveNext()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_x = 0;
|
_x = 0;
|
||||||
_z = -1;
|
_z = -1;
|
||||||
_region = _enum.Current;
|
_region = _enum.Current;
|
||||||
}
|
}
|
||||||
if (MoveNextInRegion()) {
|
if (MoveNextInRegion()) {
|
||||||
_chunk = _region.GetChunkRef(_x, _z);
|
_chunk = _region.GetChunkRef(_x, _z);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool MoveNextInRegion ()
|
protected bool MoveNextInRegion ()
|
||||||
{
|
{
|
||||||
for (; _x < RegionChunkManager.REGION_XLEN; _x++) {
|
for (; _x < RegionChunkManager.REGION_XLEN; _x++) {
|
||||||
for (_z++; _z < RegionChunkManager.REGION_ZLEN; _z++) {
|
for (_z++; _z < RegionChunkManager.REGION_ZLEN; _z++) {
|
||||||
if (_region.ChunkExists(_x, _z)) {
|
if (_region.ChunkExists(_x, _z)) {
|
||||||
goto FoundNext;
|
goto FoundNext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_z = -1;
|
_z = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
FoundNext:
|
FoundNext:
|
||||||
|
|
||||||
return (_x < RegionChunkManager.REGION_XLEN);
|
return (_x < RegionChunkManager.REGION_XLEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset ()
|
public void Reset ()
|
||||||
{
|
{
|
||||||
if (_enum != null) {
|
if (_enum != null) {
|
||||||
_enum.Reset();
|
_enum.Reset();
|
||||||
_enum.MoveNext();
|
_enum.MoveNext();
|
||||||
_region = _enum.Current;
|
_region = _enum.Current;
|
||||||
}
|
}
|
||||||
_x = 0;
|
_x = 0;
|
||||||
_z = -1;
|
_z = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IDisposable.Dispose () { }
|
void IDisposable.Dispose () { }
|
||||||
|
|
||||||
object IEnumerator.Current
|
object IEnumerator.Current
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Current;
|
return Current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunkRef IEnumerator<ChunkRef>.Current
|
ChunkRef IEnumerator<ChunkRef>.Current
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Current;
|
return Current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChunkRef Current
|
public ChunkRef Current
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_x >= RegionChunkManager.REGION_XLEN) {
|
if (_x >= RegionChunkManager.REGION_XLEN) {
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
return _chunk;
|
return _chunk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MissingChunkException : Exception
|
public class MissingChunkException : Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue