From 25f429f0cfcaa7b712ec56cc3c884d9308a3ce95 Mon Sep 17 00:00:00 2001 From: Justin Aquadro Date: Sun, 3 Apr 2011 05:22:12 +0000 Subject: [PATCH] More major interface untangling. Introduction of generic IxContainer interfaces. --- NBToolkit/NBToolkit/Map/Block.cs | 10 +- NBToolkit/NBToolkit/Map/BlockInfo.cs | 191 ++++++++++++++++-- NBToolkit/NBToolkit/Map/BlockManager.cs | 162 ++++++++++++--- NBToolkit/NBToolkit/Map/BlockRef.cs | 103 +++++++++- NBToolkit/NBToolkit/Map/Chunk.cs | 135 ++++++++++--- NBToolkit/NBToolkit/Map/ChunkEnumerator.cs | 2 +- NBToolkit/NBToolkit/Map/ChunkManager.cs | 111 ++++++++-- NBToolkit/NBToolkit/Map/ChunkRef.cs | 91 ++++++--- NBToolkit/NBToolkit/Map/NBT/NBT.cs | 14 +- NBToolkit/NBToolkit/Map/Region.cs | 70 +++++-- NBToolkit/NBToolkit/Map/TileEntity.cs | 11 +- .../NBToolkit/Map/Utility/NibbleArray.cs | 16 +- 12 files changed, 778 insertions(+), 138 deletions(-) diff --git a/NBToolkit/NBToolkit/Map/Block.cs b/NBToolkit/NBToolkit/Map/Block.cs index b230808..e1027e7 100644 --- a/NBToolkit/NBToolkit/Map/Block.cs +++ b/NBToolkit/NBToolkit/Map/Block.cs @@ -49,7 +49,15 @@ namespace NBToolkit.Map public int Data { get { return _data; } - set { _data = value; } + set + { + if (BlockManager.EnforceDataLimits && BlockInfo.BlockTable[_id] != null) { + if (!BlockInfo.BlockTable[_id].TestData(value)) { + return; + } + } + _data = value; + } } public int SkyLight diff --git a/NBToolkit/NBToolkit/Map/BlockInfo.cs b/NBToolkit/NBToolkit/Map/BlockInfo.cs index 499d4b1..bf49e05 100644 --- a/NBToolkit/NBToolkit/Map/BlockInfo.cs +++ b/NBToolkit/NBToolkit/Map/BlockInfo.cs @@ -6,11 +6,95 @@ namespace NBToolkit.Map { using NBT; - public interface IBlockTileEntity + public enum BlockType { - string TileEntityName { get; } - - NBTCompoundNode TileEntitySchema { get; } + AIR = 0, + STONE = 1, + GRASS = 2, + DIRT = 3, + COBBLESTONE = 4, + WOOD_PLANK = 5, + SAPLING = 6, + BEDROCK = 7, + WATER = 8, + STATIONARY_WATER = 9, + LAVA = 10, + STATIONARY_LAVA = 11, + SAND = 12, + GRAVEL = 13, + GOLD_ORE = 14, + IRON_ORE = 15, + COAL_ORE = 16, + WOOD = 17, + LEAVES = 18, + SPONGE = 19, + GLASS = 20, + LAPIS_ORE = 21, + LAPIS_BLOCK = 22, + DISPENSER = 23, + SANDSTONE = 24, + NOTE_BLOCK = 25, + BED = 26, + WOOL = 35, + YELLOW_FLOWER = 37, + RED_ROSE = 38, + BROWN_MUSHROOM = 39, + RED_MUSHROOM = 40, + GOLD_BLOCK = 41, + IRON_BLOCK = 42, + DOUBLE_SLAB = 43, + SLAB = 44, + BRICK_BLOCK = 45, + TNT = 46, + BOOKSHELF = 47, + MOSS_STONE = 48, + OBSIDIAN = 49, + TORCH = 50, + FIRE = 51, + MONSTER_SPAWNER = 52, + WOOD_STAIRS = 53, + CHEST = 54, + REDSTONE_WIRE = 55, + DIAMOND_ORE = 56, + DIAMOND_BLOCK = 57, + CRAFTING_TABLE = 58, + CROPS = 59, + FARMLAND = 60, + FURNACE = 61, + BURNING_FURNACE = 62, + SIGN_POST = 63, + WOOD_DOOR = 64, + LADDER = 65, + RAILS = 66, + COBBLESTONE_STAIRS = 67, + WALL_SIGN = 68, + LEVER = 69, + STONE_PLATE = 70, + IRON_DOOR = 71, + WOOD_PLATE = 72, + REDSTONE_ORE = 73, + GLOWING_REDSTONE_ORE = 74, + REDSTONE_TORCH_OFF = 75, + REDSTONE_TORCH_ON = 76, + STONE_BUTTON = 77, + SNOW = 78, + ICE = 79, + SNOW_BLOCK = 80, + CACTUS = 81, + CLAY_BLOCK = 82, + SUGAR_CANE = 83, + JUKEBOX = 84, + FENCE = 85, + PUMPKIN = 86, + NETHERRACK = 87, + SOUL_SAND = 88, + GLOWSTONE_BLOCK = 89, + PORTAL = 90, + JACK_O_LANTERN = 91, + CAKE_BLOCK = 92, + REDSTONE_REPEATER_ON = 93, + REDSTONE_REPEATER_OFF = 94, + LOCKED_CHEST = 95, } public class BlockInfo @@ -43,11 +127,48 @@ namespace NBToolkit.Map } } + private class DataLimits + { + private int _low; + private int _high; + private int _bitmask; + + public int Low + { + get { return _low; } + } + + public int High + { + get { return _high; } + } + + public int Bitmask + { + get { return _bitmask; } + } + + public DataLimits (int low, int high, int bitmask) + { + _low = low; + _high = high; + _bitmask = bitmask; + } + + public bool Test (int data) + { + int rdata = data & ~_bitmask; + return rdata >= _low && rdata <= _high; + } + } + private int _id = 0; private string _name = ""; private int _opacity = MAX_OPACITY; private int _luminance = MIN_LUMINANCE; + private DataLimits _dataLimits; + public static ItemCache BlockTable; public static ItemCache OpacityTable; @@ -103,16 +224,19 @@ namespace NBToolkit.Map return this; } - protected static NBTCompoundNode tileEntitySchema = new NBTCompoundNode("") + public BlockInfo SetDataLimits (int low, int high, int bitmask) { - new NBTScalerNode("id", NBT_Type.TAG_STRING), - new NBTScalerNode("x", NBT_Type.TAG_INT), - new NBTScalerNode("y", NBT_Type.TAG_INT), - new NBTScalerNode("z", NBT_Type.TAG_INT), - }; + _dataLimits = new DataLimits(low, high, bitmask); + return this; + } - public const int AIR = 0; - public const int FURNACE = 61; + public bool TestData (int data) + { + if (_dataLimits == null) { + return true; + } + return _dataLimits.Test(data); + } public static BlockInfo Air; public static BlockInfo Stone; @@ -276,7 +400,7 @@ namespace NBToolkit.Map Lever = new BlockInfo(69, "Lever").SetOpacity(0); StonePlate = new BlockInfo(70, "Stone Pressure Plate").SetOpacity(0); IronDoor = new BlockInfo(71, "Iron Door").SetOpacity(0); - WoodPlank = new BlockInfo(72, "Wooden Pressure Plate").SetOpacity(0); + WoodPlate = new BlockInfo(72, "Wooden Pressure Plate").SetOpacity(0); RedstoneOre = new BlockInfo(73, "Redstone Ore"); GlowRedstoneOre = new BlockInfo(74, "Glowing Redstone Ore").SetLuminance(9); RedstoneTorch = new BlockInfo(75, "Redstone Torch (Off)").SetOpacity(0); @@ -306,6 +430,8 @@ namespace NBToolkit.Map } } + // Set Tile Entity Data + Dispenser.SetTileEntity("Trap", TileEntity.TrapSchema); NoteBlock.SetTileEntity("Music", TileEntity.MusicSchema); MonsterSpawner.SetTileEntity("MonsterSpawner", TileEntity.MonsterSpawnerSchema); @@ -314,6 +440,45 @@ namespace NBToolkit.Map BurningFurnace.SetTileEntity("Furnace", TileEntity.FurnaceSchema); SignPost.SetTileEntity("Sign", TileEntity.SignSchema); WallSign.SetTileEntity("Sign", TileEntity.SignSchema); + + // Set Data Limits + + Wood.SetDataLimits(0, 2, 0); + Leaves.SetDataLimits(0, 2, 0); + Jukebox.SetDataLimits(0, 2, 0); + Sapling.SetDataLimits(0, 15, 0); + Cactus.SetDataLimits(0, 15, 0); + SugarCane.SetDataLimits(0, 15, 0); + Water.SetDataLimits(0, 7, 0x8); + Lava.SetDataLimits(0, 7, 0x8); + Crops.SetDataLimits(0, 7, 0); + Wool.SetDataLimits(0, 15, 0); + Torch.SetDataLimits(1, 5, 0); + RedstoneTorch.SetDataLimits(0, 5, 0); + RedstoneTorchOn.SetDataLimits(0, 5, 0); + Rails.SetDataLimits(0, 9, 0); + Ladder.SetDataLimits(2, 5, 0); + WoodStairs.SetDataLimits(0, 3, 0); + CobbleStairs.SetDataLimits(0, 3, 0); + Lever.SetDataLimits(0, 6, 0x8); + WoodDoor.SetDataLimits(0, 3, 0xC); + IronDoor.SetDataLimits(0, 3, 0xC); + StoneButton.SetDataLimits(1, 4, 0x8); + SignPost.SetDataLimits(0, 15, 0); + WallSign.SetDataLimits(2, 5, 0); + Furnace.SetDataLimits(2, 5, 0); + BurningFurnace.SetDataLimits(2, 5, 0); + Dispenser.SetDataLimits(2, 5, 0); + Pumpkin.SetDataLimits(0, 3, 0); + JackOLantern.SetDataLimits(0, 3, 0); + StonePlate.SetDataLimits(0, 0, 0x1); + WoodPlate.SetDataLimits(0, 0, 0x1); + Slab.SetDataLimits(0, 3, 0); + DoubleSlab.SetDataLimits(0, 3, 0); + Cactus.SetDataLimits(0, 5, 0); + Bed.SetDataLimits(0, 3, 0x8); + RedstoneRepeater.SetDataLimits(0, 0, 0xF); + RedstoneRepeaterOn.SetDataLimits(0, 0, 0xF); } } diff --git a/NBToolkit/NBToolkit/Map/BlockManager.cs b/NBToolkit/NBToolkit/Map/BlockManager.cs index fbcc5a2..fa603a3 100644 --- a/NBToolkit/NBToolkit/Map/BlockManager.cs +++ b/NBToolkit/NBToolkit/Map/BlockManager.cs @@ -4,7 +4,16 @@ using System.Text; namespace NBToolkit.Map { - public class BlockManager + /*public interface IBlockManager : IBlockContainer + { + Block GetBlock (int x, int y, int z); + BlockRef GetBlockRef (int x, int y, int z); + BlockInfo GetBlockInfo (int x, int y, int z); + + bool SetBlock (int x, int y, int z, Block block); + }*/ + + public class BlockManager : IBlockContainer { public const int MIN_X = -32000000; public const int MAX_X = 32000000; @@ -25,6 +34,8 @@ namespace NBToolkit.Map public const int CHUNK_YMASK = 0x7F; public const int CHUNK_ZMASK = 0xF; + public static bool EnforceDataLimits = true; + protected ChunkManager _chunkMan; protected ChunkRef _cache; @@ -39,6 +50,36 @@ namespace NBToolkit.Map _chunkMan = bm._chunkMan; } + public int GlobalX (int x) + { + return x; + } + + public int GlobalY (int y) + { + return y; + } + + public int GlobalZ (int z) + { + return z; + } + + public int LocalX (int x) + { + return x & CHUNK_XMASK; + } + + public int LocalY (int y) + { + return y & CHUNK_YMASK; + } + + public int LocalZ (int z) + { + return z & CHUNK_ZMASK; + } + public virtual Block GetBlock (int x, int y, int z) { _cache = GetChunk(x, y, z); @@ -56,52 +97,67 @@ namespace NBToolkit.Map return null; } - return new BlockRef(_cache, x & CHUNK_XMASK, y, z & CHUNK_ZMASK); + return new BlockRef(_cache, x, y, z); } - - public virtual bool GetBlockID (int x, int y, int z, out int id) + + public virtual BlockInfo GetBlockInfo (int x, int y, int z) { _cache = GetChunk(x, y, z); if (_cache == null || !Check(x, y, z)) { - id = 0; - return false; + return null; } - id = _cache.GetBlockID(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); - return true; + return _cache.GetBlockInfo(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); } - public virtual bool GetBlockData (int x, int y, int z, out int data) { + public virtual int GetBlockID (int x, int y, int z) + { _cache = GetChunk(x, y, z); - if (_cache == null || !Check(x, y, z)) { - data = 0; - return false; + if (_cache == null) { + return 0; } - data = _cache.GetBlockData(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); - return true; + return _cache.GetBlockID(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); } - public virtual bool GetBlockLight (int x, int y, int z, out int light) { + public virtual int GetBlockData (int x, int y, int z) + { _cache = GetChunk(x, y, z); - if (_cache == null || !Check(x, y, z)) { - light = 0; - return false; + if (_cache == null) { + return 0; } - light = _cache.GetBlockLight(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); - return true; + return _cache.GetBlockData(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); } - public virtual bool GetBlockSkyLight (int x, int y, int z, out int light) { + public virtual int GetBlockLight (int x, int y, int z) + { _cache = GetChunk(x, y, z); - if (_cache == null || !Check(x, y, z)) { - light = 0; - return false; + if (_cache == null) { + return 0; } - light = _cache.GetBlockSkyLight(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); - return true; + return _cache.GetBlockLight(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); + } + + public virtual int GetBlockSkyLight (int x, int y, int z) + { + _cache = GetChunk(x, y, z); + if (_cache == null) { + return 0; + } + + return _cache.GetBlockSkyLight(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); + } + + public virtual void SetBlock (int x, int y, int z, Block block) + { + _cache = GetChunk(x, y, z); + if (_cache == null || !Check(x, y, z)) { + return; + } + + _cache.SetBlock(x & CHUNK_XMASK, y, z & CHUNK_ZMASK, block); } public virtual bool SetBlockID (int x, int y, int z, int id) @@ -124,11 +180,61 @@ namespace NBToolkit.Map return _cache.SetBlockData(x & CHUNK_XMASK, y, z & CHUNK_ZMASK, data); } - public ChunkRef GetChunk (int x, int y, int z) + public bool SetBlockLight (int x, int y, int z, int light) + { + _cache = GetChunk(x, y, z); + if (_cache == null || !Check(x, y, z)) { + return false; + } + + return _cache.SetBlockID(x & CHUNK_XMASK, y, z & CHUNK_ZMASK, light); + } + + public bool SetBlockSkyLight (int x, int y, int z, int light) + { + _cache = GetChunk(x, y, z); + if (_cache == null || !Check(x, y, z)) { + return false; + } + + return _cache.SetBlockSkyLight(x & CHUNK_XMASK, y, z & CHUNK_ZMASK, light); + } + + public virtual TileEntity GetTileEntity (int x, int y, int z) + { + _cache = GetChunk(x, y, z); + if (_cache == null || !Check(x, y, z)) { + return null; + } + + return _cache.GetTileEntity(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); + } + + public virtual bool SetTileEntity (int x, int y, int z, TileEntity te) + { + _cache = GetChunk(x, y, z); + if (_cache == null || !Check(x, y, z)) { + return false; + } + + return _cache.SetTileEntity(x & CHUNK_XMASK, y, z & CHUNK_ZMASK, te); + } + + public virtual bool ClearTileEntity (int x, int y, int z) + { + _cache = GetChunk(x, y, z); + if (_cache == null || !Check(x, y, z)) { + return false; + } + + return _cache.ClearTileEntity(x & CHUNK_XMASK, y, z & CHUNK_ZMASK); + } + + protected ChunkRef GetChunk (int x, int y, int z) { x >>= CHUNK_XLOG; z >>= CHUNK_ZLOG; - return _chunkMan.GetChunk(x, z); + return _chunkMan.GetChunkRef(x, z); } /// diff --git a/NBToolkit/NBToolkit/Map/BlockRef.cs b/NBToolkit/NBToolkit/Map/BlockRef.cs index d3ca969..ca4a3c3 100644 --- a/NBToolkit/NBToolkit/Map/BlockRef.cs +++ b/NBToolkit/NBToolkit/Map/BlockRef.cs @@ -5,6 +5,107 @@ using System.Text; namespace NBToolkit.Map { public class BlockRef : IBlock + { + protected IBlockContainer _container; + + protected int _x; + protected int _y; + protected int _z; + + public int X + { + get { return _container.GlobalX(_x); } + } + + public int Y + { + get { return _container.GlobalY(_y); } + } + + public int Z + { + get { return _container.GlobalZ(_z); } + } + + public int LocalX + { + get { return _container.LocalX(_x); } + } + + public int LocalY + { + get { return _container.LocalZ(_z); } + } + + public int LocalZ + { + get { return _z; } + } + + public BlockInfo Info + { + get { return BlockInfo.BlockTable[_container.GetBlockID(_x, _y, _z)]; } + } + + public int ID + { + get { return _container.GetBlockID(_x, _y, _z); } + set { _container.SetBlockID(_x, _y, _z, value); } + } + + public int Data + { + get { return _container.GetBlockData(_x, _y, _z); } + set { _container.SetBlockData(_x, _y, _z, value); } + } + + public int BlockLight + { + get { return _container.GetBlockLight(_x, _y, _z); } + set { _container.SetBlockLight(_x, _y, _z, value); } + } + + public int SkyLight + { + get { return _container.GetBlockSkyLight(_x, _y, _z); } + set { _container.SetBlockSkyLight(_x, _y, _z, value); } + } + + public BlockRef (IBlockContainer container, int x, int y, int z) + { + _container = container; + _x = x; + _y = y; + _z = z; + } + + public void CopyFrom (IBlock block) + { + ID = block.ID; + Data = block.Data; + BlockLight = block.BlockLight; + SkyLight = block.SkyLight; + + SetTileEntity(block.GetTileEntity().Copy()); + } + + public TileEntity GetTileEntity () + { + return _container.GetTileEntity(_x, _y, _z); + } + + public bool SetTileEntity (TileEntity te) + { + return _container.SetTileEntity(_x, _y, _z, te); + } + + public bool ClearTileEntity () + { + return _container.ClearTileEntity(_x, _y, _z); + } + } + + /*public class BlockRef : IBlock { protected IChunk _chunk; @@ -101,5 +202,5 @@ namespace NBToolkit.Map { return _chunk.ClearTileEntity(_lx, _ly, _lz); } - } + }*/ } diff --git a/NBToolkit/NBToolkit/Map/Chunk.cs b/NBToolkit/NBToolkit/Map/Chunk.cs index 2bb976f..39838d0 100644 --- a/NBToolkit/NBToolkit/Map/Chunk.cs +++ b/NBToolkit/NBToolkit/Map/Chunk.cs @@ -4,8 +4,41 @@ using System.IO; namespace NBToolkit.Map { using NBT; + using Utility; - public interface IChunk + public interface IBlockContainer + { + int GlobalX (int x); + int GlobalY (int y); + int GlobalZ (int z); + + int LocalX (int x); + int LocalY (int y); + int LocalZ (int z); + + Block GetBlock (int lx, int ly, int lz); + BlockRef GetBlockRef (int lx, int ly, int lz); + + BlockInfo GetBlockInfo (int lx, int ly, int lz); + + int GetBlockID (int lx, int ly, int lz); + int GetBlockData (int lx, int ly, int lz); + int GetBlockLight (int lx, int ly, int lz); + int GetBlockSkyLight (int lx, int ly, int lz); + + void SetBlock (int lx, int ly, int lz, Block block); + + bool SetBlockID (int lx, int ly, int lz, int id); + bool SetBlockData (int lx, int ly, int lz, int data); + bool SetBlockLight (int lx, int ly, int lz, int light); + bool SetBlockSkyLight (int lx, int ly, int lz, int light); + + TileEntity GetTileEntity (int lx, int ly, int lz); + bool SetTileEntity (int lx, int ly, int lz, TileEntity te); + bool ClearTileEntity (int lx, int ly, int lz); + } + + public interface IChunk : IBlockContainer { int X { get; } int Z { get; } @@ -14,31 +47,13 @@ namespace NBToolkit.Map bool Save (Stream outStream); - Block GetBlock (int lx, int ly, int lz); - BlockRef GetBlockRef (int lx, int ly, int lz); - BlockInfo GetBlockInfo (int lx, int ly, int lz); - - int GetBlockID (int lx, int ly, int lz); - int GetBlockData (int lx, int ly, int lz); - int GetBlockLight (int lx, int ly, int lz); - int GetBlockSkyLight (int lx, int ly, int lz); - - bool SetBlockID (int lx, int ly, int lz, int id); - bool SetBlockData (int lx, int ly, int lz, int data); - bool SetBlockLight (int lx, int ly, int lz, int light); - bool SetBlockSkyLight (int lx, int ly, int lz, int light); - int CountBlockID (int id); int CountBlockData (int id, int data); int GetHeight (int lx, int lz); - - TileEntity GetTileEntity (int lx, int ly, int lz); - bool SetTileEntity (int lx, int ly, int lz, TileEntity te); - bool ClearTileEntity (int lx, int ly, int lz); } - public class Chunk : IChunk + public class Chunk : IChunk, ICopyable { private NBT_Tree _tree; @@ -134,6 +149,36 @@ namespace NBToolkit.Map _tree.Root.Add("Level", level); } + public int GlobalX (int x) + { + return _cx * BlockManager.CHUNK_XLEN + x; + } + + public int GlobalY (int y) + { + return y; + } + + public int GlobalZ (int z) + { + return _cz * BlockManager.CHUNK_ZLEN + z; + } + + public int LocalX (int x) + { + return x; + } + + public int LocalY (int y) + { + return y; + } + + public int LocalZ (int z) + { + return z; + } + public bool Save (Stream outStream) { if (outStream == null || !outStream.CanWrite) { @@ -161,6 +206,19 @@ namespace NBToolkit.Map return BlockInfo.BlockTable[GetBlockID(lx, ly, lz)]; } + public void SetBlock (int lx, int ly, int lz, Block block) + { + int index = lx << 11 | lz << 7 | ly; + + SetBlockID(lx, ly, lz, block.ID); + SetBlockData(lx, ly, lz, block.Data); + + _blockLight[index] = block.BlockLight; + _skyLight[index] = block.SkyLight; + + SetTileEntity(lx, ly, lz, block.GetTileEntity().Copy()); + } + public int GetBlockID (int lx, int ly, int lz) { return _blocks.Data[lx << 11 | lz << 7 | ly]; @@ -197,17 +255,19 @@ namespace NBToolkit.Map // Update height map - int tileHeight = GetHeight(lx, lz); - int newOpacity = BlockInfo.BlockTable[id].Opacity; + if (BlockInfo.BlockTable[id] != null) { + int tileHeight = GetHeight(lx, lz); + int newOpacity = BlockInfo.BlockTable[id].Opacity; - if (ly > tileHeight && newOpacity > BlockInfo.MIN_OPACITY) { - _heightMap[lz << 4 | lx] = (byte)ly; - } - else if (ly == tileHeight && newOpacity == BlockInfo.MIN_OPACITY) { - for (int i = ly - 1; i >= 0; i--) { - if (BlockInfo.BlockTable[GetBlockID(lx, i, lz)].Opacity > BlockInfo.MIN_OPACITY) { - _heightMap[lz << 4 | lx] = (byte)i; - break; + if (ly > tileHeight && newOpacity > BlockInfo.MIN_OPACITY) { + _heightMap[lz << 4 | lx] = (byte)ly; + } + else if (ly == tileHeight && newOpacity == BlockInfo.MIN_OPACITY) { + for (int i = ly - 1; i >= 0; i--) { + if (BlockInfo.BlockTable[GetBlockID(lx, i, lz)].Opacity > BlockInfo.MIN_OPACITY) { + _heightMap[lz << 4 | lx] = (byte)i; + break; + } } } } @@ -225,6 +285,12 @@ namespace NBToolkit.Map return false; } + if (BlockManager.EnforceDataLimits && BlockInfo.BlockTable[_blocks[index]] != null) { + if (!BlockInfo.BlockTable[_blocks[index]].TestData(data)) { + return false; + } + } + _data[index] = data; return true; } @@ -360,5 +426,14 @@ namespace NBToolkit.Map { return _cz * BlockManager.CHUNK_ZLEN + lz; } + + #region ICopyable Members + + public Chunk Copy () + { + return new Chunk(_tree.Copy()); + } + + #endregion } } diff --git a/NBToolkit/NBToolkit/Map/ChunkEnumerator.cs b/NBToolkit/NBToolkit/Map/ChunkEnumerator.cs index 8807749..d2d804d 100644 --- a/NBToolkit/NBToolkit/Map/ChunkEnumerator.cs +++ b/NBToolkit/NBToolkit/Map/ChunkEnumerator.cs @@ -90,7 +90,7 @@ namespace NBToolkit.Map _region = _enum.Current; } if (MoveNextInRegion()) { - _chunk = _cm.GetChunkInRegion(_region, _x, _z); + _chunk = _cm.GetChunkRefInRegion(_region, _x, _z); return true; } } diff --git a/NBToolkit/NBToolkit/Map/ChunkManager.cs b/NBToolkit/NBToolkit/Map/ChunkManager.cs index 0cf4418..59f5eb3 100644 --- a/NBToolkit/NBToolkit/Map/ChunkManager.cs +++ b/NBToolkit/NBToolkit/Map/ChunkManager.cs @@ -4,6 +4,26 @@ using System.Text; namespace NBToolkit.Map { + public interface IChunkManager + { + Chunk GetChunk (int cx, int cz); + ChunkRef GetChunkRef (int cx, int cz); + + bool ChunkExists (int cx, int cz); + + bool MarkChunkDirty (int cx, int cz); + bool MarkChunkClean (int cx, int cz); + + int Save (); + bool Save (Chunk chunk); + + ChunkRef CreateChunk (int cx, int cz); + bool DeleteChunk (int cx, int cz); + + bool CopyChunk (int cx1, int cz1, int cx2, int cz2); + bool MoveChunk (int cx1, int cz1, int cx2, int cz2); + } + public class ChunkManager { public const int REGION_XLEN = 32; @@ -27,7 +47,20 @@ namespace NBToolkit.Map _dirty = new Dictionary(); } - public ChunkRef GetChunk (int cx, int cz) + public Chunk GetChunk (int cx, int cz) + { + int lcx = cx & REGION_XMASK; + int lcz = cz & REGION_ZMASK; + + Region r = GetRegion(cx, cz); + if (r == null || !r.ChunkExists(lcx, lcz)) { + return null; + } + + return new Chunk(r.GetChunkTree(lcx, lcz)); + } + + public ChunkRef GetChunkRef (int cx, int cz) { ChunkKey k = new ChunkKey(cx, cz); @@ -55,45 +88,49 @@ namespace NBToolkit.Map } } - public ChunkRef GetChunkInRegion (Region r, int lcx, int lcz) + public bool ChunkExists (int cx, int cz) { - int cx = r.X * REGION_XLEN + lcx; - int cz = r.Z * REGION_ZLEN + lcz; - return GetChunk(cx, cz); - } + Region r = GetRegion(cx, cz); + if (r == null) { + return false; + } - public Region GetRegion (int cx, int cz) - { - cx >>= REGION_XLOG; - cz >>= REGION_ZLOG; - return _regionMan.GetRegion(cx, cz); + return r.ChunkExists(cx & REGION_XMASK, cz & REGION_ZMASK); } public bool MarkChunkDirty (int cx, int cz) { ChunkKey k = new ChunkKey(cx, cz); if (!_dirty.ContainsKey(k)) { - _dirty.Add(k, GetChunk(cx, cz)); + _dirty.Add(k, GetChunkRef(cx, cz)); return true; } return false; } - public bool MarkChunkDirty (ChunkRef chunk) + public bool MarkChunkClean (int cx, int cz) { - ChunkKey k = new ChunkKey(chunk.X, chunk.Z); - if (!_dirty.ContainsKey(k)) { - _dirty.Add(k, chunk); + ChunkKey k = new ChunkKey(cx, cz); + if (_dirty.ContainsKey(k)) { + _dirty.Remove(k); return true; } return false; } - public int SaveDirtyChunks () + public int Save () { int saved = 0; foreach (ChunkRef c in _dirty.Values) { - if (c.Save()) { + int lcx = ChunkLocalX(c.X); + int lcz = ChunkLocalZ(c.Z); + + Region r = GetRegion(c.X, c.Z); + if (r == null || !r.ChunkExists(lcx, lcz)) { + throw new MissingChunkException(); + } + + if (c.Save(r.GetChunkOutStream(lcx, lcz))) { saved++; } } @@ -102,9 +139,14 @@ namespace NBToolkit.Map return saved; } - public RegionManager GetRegionManager () + public bool Save (Chunk chunk) { - return _regionMan; + Region r = GetRegion(chunk.X, chunk.Z); + if (r == null) { + return false; + } + + return chunk.Save(r.GetChunkOutStream(chunk.X & REGION_XLEN, chunk.Z & REGION_ZLEN)); } public bool DeleteChunk (int cx, int cz) @@ -128,6 +170,35 @@ namespace NBToolkit.Map return true; } + + public RegionManager GetRegionManager () + { + return _regionMan; + } + + public ChunkRef GetChunkRefInRegion (Region r, int lcx, int lcz) + { + int cx = r.X * REGION_XLEN + lcx; + int cz = r.Z * REGION_ZLEN + lcz; + return GetChunkRef(cx, cz); + } + + protected int ChunkLocalX (int cx) + { + return cx & REGION_XMASK; + } + + protected int ChunkLocalZ (int cz) + { + return cz & REGION_ZMASK; + } + + protected Region GetRegion (int cx, int cz) + { + cx >>= REGION_XLOG; + cz >>= REGION_ZLOG; + return _regionMan.GetRegion(cx, cz); + } } public class MissingChunkException : Exception diff --git a/NBToolkit/NBToolkit/Map/ChunkRef.cs b/NBToolkit/NBToolkit/Map/ChunkRef.cs index 868767c..9159dca 100644 --- a/NBToolkit/NBToolkit/Map/ChunkRef.cs +++ b/NBToolkit/NBToolkit/Map/ChunkRef.cs @@ -27,45 +27,63 @@ namespace NBToolkit.Map get { return _cz; } } - public int LocalX - { - get { return _cx & ChunkManager.REGION_XMASK; } - } - - public int LocalZ - { - get { return _cz & ChunkManager.REGION_ZMASK; } - } - public ChunkRef (ChunkManager cm, int cx, int cz) { _chunkMan = cm; _cx = cx; _cz = cz; - Region r = cm.GetRegion(cx, cz); - if (r == null || !r.ChunkExists(LocalX, LocalZ)) { + if (!_chunkMan.ChunkExists(cx, cz)) { throw new MissingChunkException(); } } + public int GlobalX (int x) + { + return _cx * BlockManager.CHUNK_XLEN + x; + } + + public int GlobalY (int y) + { + return y; + } + + public int GlobalZ (int z) + { + return _cz * BlockManager.CHUNK_ZLEN + z; + } + + public int LocalX (int x) + { + return x; + } + + public int LocalY (int y) + { + return y; + } + + public int LocalZ (int z) + { + return z; + } + private Chunk GetChunk () { if (_chunk == null) { - _chunk = new Chunk(GetTree()); + _chunk = _chunkMan.GetChunk(_cx, _cz); } return _chunk; } - private NBT_Tree GetTree () + /*private NBT_Tree GetTree () { - Region r = _chunkMan.GetRegion(_cx, _cz); - if (r == null || !r.ChunkExists(LocalX, LocalZ)) { + if (!_chunkMan.ChunkExists(_cx, _cz)) { throw new MissingChunkException(); } return r.GetChunkTree(LocalX, LocalZ); - } + }*/ private bool MarkDirty () { @@ -74,11 +92,11 @@ namespace NBToolkit.Map } _dirty = true; - _chunkMan.MarkChunkDirty(this); + _chunkMan.MarkChunkDirty(_cx, _cz); return true; } - public bool Save () + /*public bool Save () { if (_dirty) { Region r = _chunkMan.GetRegion(_cx, _cz); @@ -93,26 +111,46 @@ namespace NBToolkit.Map return false; } return true; - } + }*/ public ChunkRef GetNorthNeighbor () { - return _chunkMan.GetChunk(_cx - 1, _cz); + return _chunkMan.GetChunkRef(_cx - 1, _cz); } public ChunkRef GetSouthNeighbor () { - return _chunkMan.GetChunk(_cx + 1, _cz); + return _chunkMan.GetChunkRef(_cx + 1, _cz); } public ChunkRef GetEastNeighbor () { - return _chunkMan.GetChunk(_cx, _cz - 1); + return _chunkMan.GetChunkRef(_cx, _cz - 1); } public ChunkRef GetWestNeighbor () { - return _chunkMan.GetChunk(_cx, _cz + 1); + return _chunkMan.GetChunkRef(_cx, _cz + 1); + } + + public Chunk GetChunkCopy () + { + return GetChunk().Copy(); + } + + public Chunk GetChunkRef () + { + Chunk chunk = GetChunk(); + _chunk = null; + + return chunk; + } + + public void SetChunkRef (Chunk chunk) + { + _chunk = chunk; + _chunk.SetLocation(_cx, _cz); + MarkDirty(); } #region IChunk Members @@ -156,6 +194,11 @@ namespace NBToolkit.Map return GetChunk().GetBlockInfo(lx, ly, lz); } + public void SetBlock (int lx, int ly, int lz, Block block) + { + GetChunk().SetBlock(lx, ly, lz, block); + } + public int GetBlockID (int lx, int ly, int lz) { return GetChunk().GetBlockID(lx, ly, lz); diff --git a/NBToolkit/NBToolkit/Map/NBT/NBT.cs b/NBToolkit/NBToolkit/Map/NBT/NBT.cs index 1e0e9a8..339e5f0 100644 --- a/NBToolkit/NBToolkit/Map/NBT/NBT.cs +++ b/NBToolkit/NBToolkit/Map/NBT/NBT.cs @@ -8,7 +8,7 @@ namespace NBToolkit.Map.NBT { using Map.Utility; - public class NBT_Tree + public class NBT_Tree : ICopyable { private Stream _stream = null; private NBT_Compound _root = null; @@ -459,6 +459,18 @@ namespace NBToolkit.Map.NBT WriteValue(val); } } + + #region ICopyable Members + + public NBT_Tree Copy () + { + NBT_Tree tree = new NBT_Tree(); + tree._root = _root.Copy() as NBT_Compound; + + return tree; + } + + #endregion } public class NBTException : Exception diff --git a/NBToolkit/NBToolkit/Map/Region.cs b/NBToolkit/NBToolkit/Map/Region.cs index 83ef8dd..3815f66 100644 --- a/NBToolkit/NBToolkit/Map/Region.cs +++ b/NBToolkit/NBToolkit/Map/Region.cs @@ -8,6 +8,36 @@ namespace NBToolkit.Map { using NBT; + public interface IChunkContainer + { + int GlobalX (int cx); + int GlobalZ (int cz); + + int LocalX (int cx); + int LocalZ (int cz); + + Chunk GetChunk (int cx, int cz); + ChunkRef GetChunkRef (int cx, int cz); + + bool ChunkExists (int cx, int cz); + + bool DeleteChunk (int cx, int cz); + + bool Save (); + bool SaveChunk (Chunk chunk); + + bool MarkChunkDirty (int cx, int cz); + bool MarkChunkClean (int cx, int cz); + } + + public interface IRegion : IChunkContainer + { + int X { get; } + int Z { get; } + + int ChunkCount (); + } + public class Region : IDisposable { protected int _rx; @@ -20,6 +50,16 @@ namespace NBToolkit.Map protected WeakReference _regionFile; + public int X + { + get { return _rx; } + } + + public int Z + { + get { return _rz; } + } + public Region (RegionManager rm, int rx, int rz) { _regionMan = rm; @@ -44,22 +84,6 @@ namespace NBToolkit.Map } } - public int X - { - get - { - return _rx; - } - } - - public int Z - { - get - { - return _rz; - } - } - ~Region () { Dispose(false); @@ -88,6 +112,20 @@ namespace NBToolkit.Map _disposed = true; } + public Chunk GetChunk (int lcx, int lcz) + { + if (!ChunkExists(lcx, lcz)) { + return null; + } + + return new Chunk(GetChunkTree(lcx, lcz)); + } + + //public ChunkRef GetChunkRef (int lcx, int lcz) + //{ + + //} + public string GetFileName () { return "r." + _rx + "." + _rz + ".mcr"; diff --git a/NBToolkit/NBToolkit/Map/TileEntity.cs b/NBToolkit/NBToolkit/Map/TileEntity.cs index 06945c0..af34c1a 100644 --- a/NBToolkit/NBToolkit/Map/TileEntity.cs +++ b/NBToolkit/NBToolkit/Map/TileEntity.cs @@ -16,6 +16,15 @@ namespace NBToolkit.Map get { return _tree; } } + public TileEntity (string id) + { + _tree = new NBT_Compound(); + _tree["id"] = new NBT_String(id); + _tree["x"] = new NBT_Int(); + _tree["y"] = new NBT_Int(); + _tree["z"] = new NBT_Int(); + } + public TileEntity (NBT_Compound tree) { _tree = tree; @@ -77,7 +86,7 @@ namespace NBToolkit.Map new NBTStringNode("id", "Furnace"), new NBTScalerNode("BurnTime", NBT_Type.TAG_SHORT), new NBTScalerNode("CookTime", NBT_Type.TAG_SHORT), - new NBTListNode("Items", NBT_Type.TAG_COMPOUND), + new NBTListNode("Items", NBT_Type.TAG_COMPOUND, InventorySchema), }); public static readonly NBTCompoundNode SignSchema = BaseSchema.MergeInto(new NBTCompoundNode("") diff --git a/NBToolkit/NBToolkit/Map/Utility/NibbleArray.cs b/NBToolkit/NBToolkit/Map/Utility/NibbleArray.cs index 0fca489..ffecf27 100644 --- a/NBToolkit/NBToolkit/Map/Utility/NibbleArray.cs +++ b/NBToolkit/NBToolkit/Map/Utility/NibbleArray.cs @@ -3,9 +3,9 @@ using System.Collections; using System.Collections.Generic; using System.Text; -namespace NBToolkit +namespace NBToolkit.Map.Utility { - public class NibbleArray + public class NibbleArray : ICopyable { protected readonly byte[] _data = null; @@ -46,5 +46,17 @@ namespace NBToolkit return _data.Length << 1; } } + + #region ICopyable Members + + public NibbleArray Copy () + { + byte[] data = new byte[_data.Length]; + _data.CopyTo(data, 0); + + return new NibbleArray(data); + } + + #endregion } }