using System; using System.Collections; using System.Collections.Generic; 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); } } 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); } } /// /// Manages the regions of a Beta-compatible world. /// public abstract class RegionManager : IRegionManager { protected string _regionPath; protected Dictionary _cache; protected ChunkCache _chunkCache; protected abstract IRegion CreateRegionCore (int rx, int rz); protected abstract RegionFile CreateRegionFileCore (int rx, int rz); protected abstract void DeleteRegionCore (IRegion region); public abstract IRegion GetRegion (string filename); /// /// Creates a new instance of a for the given region directory and chunk cache. /// /// The path to a directory containing region files. /// The shared chunk cache to hold chunk data in. public RegionManager (string regionDir, ChunkCache cache) { _regionPath = regionDir; _chunkCache = cache; _cache = new Dictionary(); } /// /// Gets a at the given coordinates. /// /// The global X-coordinate of a region. /// The global Z-coordinate of a region. /// A representing a region at the given coordinates, or null if the region does not exist. public IRegion GetRegion (int rx, int rz) { RegionKey k = new RegionKey(rx, rz); IRegion r; try { if (_cache.TryGetValue(k, out r) == false) { r = CreateRegionCore(rz, rz); _cache.Add(k, r); } return r; } catch (FileNotFoundException) { _cache.Add(k, null); return null; } } /// public bool RegionExists (int rx, int rz) { IRegion r = GetRegion(rx, rz); return r != null; } /// public IRegion CreateRegion (int rx, int rz) { IRegion r = GetRegion(rx, rz); if (r == null) { string fp = "r." + rx + "." + rz + ".mca"; using (RegionFile rf = CreateRegionFileCore(rx, rz)) { } r = CreateRegionCore(rx, rz); RegionKey k = new RegionKey(rx, rz); _cache[k] = r; } return r; } /// /// Get the current region directory path. /// /// The path to the region directory. public string GetRegionPath () { return _regionPath; } // XXX: Exceptions /// public bool DeleteRegion (int rx, int rz) { IRegion r = GetRegion(rx, rz); if (r == null) { return false; } RegionKey k = new RegionKey(rx, rz); _cache.Remove(k); DeleteRegionCore(r); try { File.Delete(r.GetFilePath()); } catch (Exception e) { Console.WriteLine("NOTICE: " + e.Message); return false; } return true; } #region IEnumerable Members /// /// Returns an enumerator that iterates over all of the regions in the underlying dimension. /// /// An enumerator instance. public IEnumerator GetEnumerator () { return new Enumerator(this); } #endregion #region IEnumerable Members /// /// Returns an enumerator that iterates over all of the regions in the underlying dimension. /// /// An enumerator instance. IEnumerator IEnumerable.GetEnumerator () { return new Enumerator(this); } #endregion private struct Enumerator : IEnumerator { private List _regions; private int _pos; public Enumerator (RegionManager rm) { _regions = new List(); _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.Current { get { return Current; } } public IRegion Current { get { try { return _regions[_pos]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } } } }