using System; using System.Collections.Generic; using System.Text; using System.IO; using Substrate.Nbt; using System.Text.RegularExpressions; namespace Substrate.Data { /// <summary> /// Functions to manage all <see cref="Map"/> data resources. /// </summary> /// <remarks>This manager is intended for map files stored in standard compressed NBT format.</remarks> public class MapManager : IMapManager, IEnumerable<Map> { private NbtWorld _world; /// <summary> /// Create a new <see cref="MapManager"/> for a given world. /// </summary> /// <param name="world">World containing data files.</param> public MapManager (NbtWorld world) { _world = world; } /// <summary> /// Gets a <see cref="MapFile"/> representing the backing NBT data stream. /// </summary> /// <param name="id">The id of the map to fetch.</param> /// <returns>A <see cref="MapFile"/> for the given map.</returns> protected MapFile GetMapFile (int id) { return new MapFile(Path.Combine(_world.Path, _world.DataDirectory), id); } /// <summary> /// Gets a raw <see cref="NbtTree"/> of data for the given map. /// </summary> /// <param name="id">The id of the map to fetch.</param> /// <returns>An <see cref="NbtTree"/> containing the given map's raw data.</returns> /// <exception cref="NbtIOException">Thrown when the manager cannot read in an NBT data stream.</exception> public NbtTree GetMapTree (int id) { MapFile mf = GetMapFile(id); Stream nbtstr = mf.GetDataInputStream(); if (nbtstr == null) { throw new NbtIOException("Failed to initialize NBT data stream for input."); } return new NbtTree(nbtstr); } /// <summary> /// Saves a raw <see cref="NbtTree"/> representing a map to the given map's file. /// </summary> /// <param name="id">The id of the map to write data to.</param> /// <param name="tree">The map's data as an <see cref="NbtTree"/>.</param> /// <exception cref="NbtIOException">Thrown when the manager cannot initialize an NBT data stream for output.</exception> public void SetMapTree (int id, NbtTree tree) { MapFile mf = GetMapFile(id); Stream zipstr = mf.GetDataOutputStream(); if (zipstr == null) { throw new NbtIOException("Failed to initialize NBT data stream for output."); } tree.WriteTo(zipstr); zipstr.Close(); } #region IMapManager Members /// <inherit /> /// <exception cref="DataIOException">Thrown when the manager cannot read in a map that should exist.</exception> public Map GetMap (int id) { if (!MapExists(id)) { return null; } try { Map m = new Map().LoadTreeSafe(GetMapTree(id).Root); m.Id = id; return m; } catch (Exception ex) { DataIOException pex = new DataIOException("Could not load map", ex); pex.Data["MapId"] = id; throw pex; } } /// <inherit /> /// <exception cref="DataIOException">Thrown when the manager cannot write out the map</exception> public void SetMap (int id, Map map) { try { SetMapTree(id, new NbtTree(map.BuildTree() as TagNodeCompound)); } catch (Exception ex) { DataIOException pex = new DataIOException("Could not save map", ex); pex.Data["MapId"] = id; throw pex; } } /// <summary> /// Saves a <see cref="Map"/> object's data back to file given the id set in the <see cref="Map"/> object. /// </summary> /// <param name="map">The <see cref="Map"/> object containing the data to write back.</param> /// <exception cref="DataIOException">Thrown when the manager cannot write out the map</exception> public void SetMap (Map map) { SetMap(map.Id, map); } /// <inherit /> public bool MapExists (int id) { return new MapFile(Path.Combine(_world.Path, _world.DataDirectory), id).Exists(); } /// <inherit /> /// <exception cref="DataIOException">Thrown when the manager cannot delete the map.</exception> public void DeleteMap (int id) { try { new MapFile(Path.Combine(_world.Path, _world.DataDirectory), id).Delete(); } catch (Exception ex) { DataIOException pex = new DataIOException("Could not remove map", ex); pex.Data["MapId"] = id; throw pex; } } #endregion #region IEnumerable<Map> Members /// <summary> /// Gets an enumerator that iterates through all the maps in the world's data directory. /// </summary> /// <returns>An enumerator for this manager.</returns> public IEnumerator<Map> GetEnumerator () { string path = Path.Combine(_world.Path, _world.DataDirectory); if (!Directory.Exists(path)) { throw new DirectoryNotFoundException(); } string[] files = Directory.GetFiles(path); foreach (string file in files) { string basename = Path.GetFileName(file); if (!ParseFileName(basename)) { continue; } int id = MapFile.IdFromFilename(basename); yield return GetMap(id); } } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () { return GetEnumerator(); } #endregion private bool ParseFileName (string filename) { Match match = _namePattern.Match(filename); if (!match.Success) { return false; } return true; } private static Regex _namePattern = new Regex("^map_[0-9]+\\.dat$"); } }