using System; using System.Collections; using System.Collections.Generic; using System.IO; using Substrate.Core; namespace Substrate { /// /// Manages the regions of a Beta-compatible world. /// public class RegionManager : IRegionManager { private string _regionPath; private Dictionary _cache; private ChunkCache _chunkCache; /// /// 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 Region GetRegion (int rx, int rz) { RegionKey k = new RegionKey(rx, rz); Region r; try { if (_cache.TryGetValue(k, out r) == false) { r = new Region(this, _chunkCache, rx, rz); _cache.Add(k, r); } return r; } catch (FileNotFoundException) { _cache.Add(k, null); return null; } } /// /// Determines if a region exists at the given coordinates. /// /// The global X-coordinate of a region. /// The global Z-coordinate of a region. /// True if a region exists at the given global region coordinates; false otherwise. public bool RegionExists (int rx, int rz) { Region r = GetRegion(rx, rz); return r != null; } /// /// Creates a new empty region at the given coordinates, if no region exists. /// /// The global X-coordinate of a region. /// The global Z-coordinate of a region. /// A new empty object for the given coordinates, or an existing if one exists. public Region CreateRegion (int rx, int rz) { Region r = GetRegion(rx, rz); if (r == null) { string fp = "r." + rx + "." + rz + ".mcr"; using (RegionFile rf = new RegionFile(Path.Combine(_regionPath, fp))) { } r = new Region(this, _chunkCache, rx, rz); RegionKey k = new RegionKey(rx, rz); _cache[k] = r; } return r; } /// /// Gets a for the given region filename. /// /// The filename of the region to get. /// A corresponding to the coordinates encoded in the filename. public Region GetRegion (string filename) { int rx, rz; if (!Region.ParseFileName(filename, out rx, out rz)) { throw new ArgumentException("Malformed region file name: " + filename, "filename"); } return GetRegion(rx, rz); } /// /// Get the current region directory path. /// /// The path to the region directory. public string GetRegionPath () { return _regionPath; } // XXX: Exceptions /// /// Deletes a region at the given coordinates. /// /// The global X-coordinate of a region. /// The global Z-coordinate of a region. /// True if a region was deleted; false otherwise. public bool DeleteRegion (int rx, int rz) { Region r = GetRegion(rx, rz); if (r == null) { return false; } RegionKey k = new RegionKey(rx, rz); _cache.Remove(k); r.Dispose(); 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 { Region 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; } } Region IEnumerator.Current { get { return Current; } } public Region Current { get { try { return _regions[_pos]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } } } }