From 77f076401384421c08c9bf3f98de1406cbec6957 Mon Sep 17 00:00:00 2001 From: Justin Aquadro Date: Sun, 13 Mar 2011 09:57:45 +0000 Subject: [PATCH] Added purge command to delete chunks --- NBToolkit/NBToolkit/ChunkManager.cs | 22 +++++++ NBToolkit/NBToolkit/NBToolkit.csproj | 1 + NBToolkit/NBToolkit/Program.cs | 13 +++++ NBToolkit/NBToolkit/Purge.cs | 85 ++++++++++++++++++++++++++++ NBToolkit/NBToolkit/Region.cs | 42 +++++++++++++- NBToolkit/NBToolkit/RegionFile.cs | 18 +++++- NBToolkit/NBToolkit/RegionManager.cs | 23 ++++++++ 7 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 NBToolkit/NBToolkit/Purge.cs diff --git a/NBToolkit/NBToolkit/ChunkManager.cs b/NBToolkit/NBToolkit/ChunkManager.cs index 8dd2eff..cf59256 100644 --- a/NBToolkit/NBToolkit/ChunkManager.cs +++ b/NBToolkit/NBToolkit/ChunkManager.cs @@ -99,6 +99,28 @@ namespace NBToolkit { return _regionMan; } + + public bool DeleteChunk (int cx, int cz) + { + Region r = GetRegion(cx, cz); + if (r == null) { + return false; + } + + if (!r.DeleteChunk(cx & REGION_XMASK, cz & REGION_ZMASK)) { + return false; + } + + ChunkKey k = new ChunkKey(cx, cz); + _cache.Remove(k); + _dirty.Remove(k); + + if (r.ChunkCount() == 0) { + _regionMan.DeleteRegion(r.X, r.Z); + } + + return true; + } } public class MissingChunkException : Exception diff --git a/NBToolkit/NBToolkit/NBToolkit.csproj b/NBToolkit/NBToolkit/NBToolkit.csproj index 2c491be..b50acf4 100644 --- a/NBToolkit/NBToolkit/NBToolkit.csproj +++ b/NBToolkit/NBToolkit/NBToolkit.csproj @@ -66,6 +66,7 @@ + diff --git a/NBToolkit/NBToolkit/Program.cs b/NBToolkit/NBToolkit/Program.cs index 41d5dab..29fa19a 100644 --- a/NBToolkit/NBToolkit/Program.cs +++ b/NBToolkit/NBToolkit/Program.cs @@ -28,6 +28,12 @@ namespace NBToolkit options.SetDefaults(); filter.Run(); } + else if (args[0] == "purge") { + PurgeOptions options = new PurgeOptions(args); + Purge filter = new Purge(options); + options.SetDefaults(); + filter.Run(); + } else if (args[0] == "help") { if (args.Length < 2) { args = new string[2] { "help", "help" }; @@ -52,6 +58,13 @@ namespace NBToolkit Console.WriteLine(); options.PrintUsage(); } + else if (args[1] == "purge") { + options = new PurgeOptions(args); + + WriteBlock("Deletes all chunks matching the chunk filtering options. If no options are specified, all world chunks will be deleted. Region files that have all of their chunks purged will also be deleted from the world directory."); + Console.WriteLine(); + options.PrintUsage(); + } else { WriteBlock("Prints help and usage information for another command. Available commands are 'oregen' and 'replace'."); Console.WriteLine(); diff --git a/NBToolkit/NBToolkit/Purge.cs b/NBToolkit/NBToolkit/Purge.cs new file mode 100644 index 0000000..8729c8d --- /dev/null +++ b/NBToolkit/NBToolkit/Purge.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Text; +using NDesk.Options; +using NBT; + +namespace NBToolkit +{ + public class PurgeOptions : TKOptions, IChunkFilterable + { + private OptionSet _filterOpt = null; + private ChunkFilter _chunkFilter = null; + + public PurgeOptions () + : base() + { + _filterOpt = new OptionSet(); + _chunkFilter = new ChunkFilter(); + } + + public PurgeOptions (string[] args) + : this() + { + Parse(args); + } + + public override void Parse (string[] args) + { + base.Parse(args); + + _filterOpt.Parse(args); + _chunkFilter.Parse(args); + } + + public override void PrintUsage () + { + Console.WriteLine("Usage: nbtoolkit purge [options]"); + Console.WriteLine(); + Console.WriteLine("Options for command 'purge':"); + + _filterOpt.WriteOptionDescriptions(Console.Out); + + Console.WriteLine(); + _chunkFilter.PrintUsage(); + + Console.WriteLine(); + base.PrintUsage(); + } + + public override void SetDefaults () + { + base.SetDefaults(); + } + + public IChunkFilter GetChunkFilter () + { + return _chunkFilter; + } + } + + class Purge : TKFilter + { + private PurgeOptions opt; + + private static Random rand = new Random(); + + public Purge (PurgeOptions o) + { + opt = o; + } + + public override void Run () + { + World world = new World(opt.OPT_WORLD); + + int affectedChunks = 0; + foreach (Chunk chunk in new FilteredChunkList(world.GetChunkManager(), opt.GetChunkFilter())) { + affectedChunks++; + world.GetChunkManager().DeleteChunk(chunk.X, chunk.Z); + } + + Console.WriteLine("Purged Chunks: " + affectedChunks); + } + } +} diff --git a/NBToolkit/NBToolkit/Region.cs b/NBToolkit/NBToolkit/Region.cs index ac56d89..f6f2f55 100644 --- a/NBToolkit/NBToolkit/Region.cs +++ b/NBToolkit/NBToolkit/Region.cs @@ -7,10 +7,11 @@ using NBT; namespace NBToolkit { - public class Region + public class Region : IDisposable { protected int _rx; protected int _rz; + protected bool _disposed = false; protected RegionManager _regionMan; @@ -58,6 +59,34 @@ namespace NBToolkit } } + ~Region () + { + Dispose(false); + } + + public void Dispose () + { + Dispose(true); + System.GC.SuppressFinalize(this); + } + + protected virtual void Dispose (bool disposing) + { + if (!_disposed) { + if (disposing) { + // Cleanup managed resources + RegionFile rf = _regionFile.Target as RegionFile; + if (rf != null) { + rf.Dispose(); + rf = null; + } + } + + // Cleanup unmanaged resources + } + _disposed = true; + } + public string GetFileName () { return "r." + _rx + "." + _rz + ".mcr"; @@ -151,5 +180,16 @@ namespace NBToolkit return count; } + + public bool DeleteChunk (int lcx, int lcz) + { + RegionFile rf = GetRegionFile(); + if (!rf.HasChunk(lcx, lcz)) { + return false; + } + + rf.DeleteChunk(lcx, lcz); + return true; + } } } diff --git a/NBToolkit/NBToolkit/RegionFile.cs b/NBToolkit/NBToolkit/RegionFile.cs index 4aea55c..f854440 100644 --- a/NBToolkit/NBToolkit/RegionFile.cs +++ b/NBToolkit/NBToolkit/RegionFile.cs @@ -371,8 +371,24 @@ namespace NBToolkit file.Write(data, 0, length); // chunk data } + public void DeleteChunk (int x, int z) + { + int offset = GetOffset(x, z); + int sectorNumber = offset >> 8; + int sectorsAllocated = offset & 0xFF; + + file.Seek(sectorNumber * SECTOR_BYTES, SeekOrigin.Begin); + for (int i = 0; i < sectorsAllocated; i++) { + file.Write(emptySector, 0, SECTOR_BYTES); + } + + SetOffset(x, z, 0); + SetTimestamp(x, z, 0); + } + /* is this an invalid chunk coordinate? */ - private bool OutOfBounds(int x, int z) { + private bool OutOfBounds (int x, int z) + { return x < 0 || x >= 32 || z < 0 || z >= 32; } diff --git a/NBToolkit/NBToolkit/RegionManager.cs b/NBToolkit/NBToolkit/RegionManager.cs index 382bc97..ee1bec0 100644 --- a/NBToolkit/NBToolkit/RegionManager.cs +++ b/NBToolkit/NBToolkit/RegionManager.cs @@ -49,5 +49,28 @@ namespace NBToolkit { return _regionPath; } + + 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; + } } }