forked from mirrors/NBTExplorer
More major interface untangling. Introduction of generic IxContainer interfaces.
This commit is contained in:
parent
3afb2238ef
commit
25f429f0cf
12 changed files with 778 additions and 138 deletions
|
@ -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
|
||||
|
|
|
@ -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<BlockInfo> BlockTable;
|
||||
|
||||
public static ItemCache<int> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _cache.GetBlockID(x & CHUNK_XMASK, y, z & CHUNK_ZMASK);
|
||||
}
|
||||
|
||||
public virtual int GetBlockData (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _cache.GetBlockData(x & CHUNK_XMASK, y, z & CHUNK_ZMASK);
|
||||
}
|
||||
|
||||
public virtual int GetBlockLight (int x, int y, int z)
|
||||
{
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)) {
|
||||
data = 0;
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
data = _cache.GetBlockData(x & CHUNK_XMASK, y, z & CHUNK_ZMASK);
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool GetBlockLight (int x, int y, int z, out int light) {
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
light = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
light = _cache.GetBlockLight(x & CHUNK_XMASK, y, z & CHUNK_ZMASK);
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool GetBlockSkyLight (int x, int y, int z, out int light) {
|
||||
_cache = GetChunk(x, y, z);
|
||||
if (_cache == null || !Check(x, y, z)) {
|
||||
light = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
light = _cache.GetBlockSkyLight(x & CHUNK_XMASK, y, z & CHUNK_ZMASK);
|
||||
return true;
|
||||
_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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -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<Chunk>
|
||||
{
|
||||
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,6 +255,7 @@ namespace NBToolkit.Map
|
|||
|
||||
// Update height map
|
||||
|
||||
if (BlockInfo.BlockTable[id] != null) {
|
||||
int tileHeight = GetHeight(lx, lz);
|
||||
int newOpacity = BlockInfo.BlockTable[id].Opacity;
|
||||
|
||||
|
@ -211,6 +270,7 @@ namespace NBToolkit.Map
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update value
|
||||
|
||||
|
@ -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<Chunk> Members
|
||||
|
||||
public Chunk Copy ()
|
||||
{
|
||||
return new Chunk(_tree.Copy());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ChunkKey, ChunkRef>();
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace NBToolkit.Map.NBT
|
|||
{
|
||||
using Map.Utility;
|
||||
|
||||
public class NBT_Tree
|
||||
public class NBT_Tree : ICopyable<NBT_Tree>
|
||||
{
|
||||
private Stream _stream = null;
|
||||
private NBT_Compound _root = null;
|
||||
|
@ -459,6 +459,18 @@ namespace NBToolkit.Map.NBT
|
|||
WriteValue(val);
|
||||
}
|
||||
}
|
||||
|
||||
#region ICopyable<NBT_Tree> 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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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("")
|
||||
|
|
|
@ -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<NibbleArray>
|
||||
{
|
||||
protected readonly byte[] _data = null;
|
||||
|
||||
|
@ -46,5 +46,17 @@ namespace NBToolkit
|
|||
return _data.Length << 1;
|
||||
}
|
||||
}
|
||||
|
||||
#region ICopyable<NibbleArray> Members
|
||||
|
||||
public NibbleArray Copy ()
|
||||
{
|
||||
byte[] data = new byte[_data.Length];
|
||||
_data.CopyTo(data, 0);
|
||||
|
||||
return new NibbleArray(data);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue