NBT validation threaded through NBT "backing objects", which includes chunks, tile entities, and items.

This commit is contained in:
Justin Aquadro 2011-04-06 04:38:23 +00:00
parent f60a1f3f77
commit 25fa319c5c
14 changed files with 1020 additions and 498 deletions

View file

@ -26,9 +26,19 @@ namespace NBToolkit.Map
get { return _id; }
set
{
if (BlockInfo.SchemaTable[_id] != BlockInfo.SchemaTable[value]) {
_tileEntity = null;
BlockInfoEx info1 = BlockInfo.BlockTable[_id] as BlockInfoEx;
BlockInfoEx info2 = BlockInfo.BlockTable[value] as BlockInfoEx;
if (info1 != info2) {
if (info1 != null) {
_tileEntity = null;
}
if (info2 != null) {
_tileEntity = TileEntityFactory.Create(info2.TileEntityName);
}
}
_id = value;
}
}
@ -86,12 +96,12 @@ namespace NBToolkit.Map
public bool SetTileEntity (TileEntity te)
{
NBTCompoundNode schema = BlockInfo.SchemaTable[_id];
if (schema == null) {
BlockInfoEx info = BlockInfo.BlockTable[_id] as BlockInfoEx;
if (info == null) {
return false;
}
if (te.Verify(schema) == false) {
if (te.GetType() != TileEntityFactory.Lookup(info.TileEntityName)) {
return false;
}

View file

@ -110,8 +110,6 @@ namespace NBToolkit.Map
private static int[] _opacityTable;
private static int[] _luminanceTable;
protected internal static NBTCompoundNode[] _schemaTable;
public class ItemCache<T>
{
private T[] _cache;
@ -261,9 +259,9 @@ namespace NBToolkit.Map
public static BlockInfo Glass;
public static BlockInfo LapisOre;
public static BlockInfo LapisBlock;
public static TileEntityBlockInfo Dispenser;
public static BlockInfoEx Dispenser;
public static BlockInfo Sandstone;
public static TileEntityBlockInfo NoteBlock;
public static BlockInfoEx NoteBlock;
public static BlockInfo Bed;
public static BlockInfo Wool;
public static BlockInfo YellowFlower;
@ -281,23 +279,23 @@ namespace NBToolkit.Map
public static BlockInfo Obsidian;
public static BlockInfo Torch;
public static BlockInfo Fire;
public static TileEntityBlockInfo MonsterSpawner;
public static BlockInfoEx MonsterSpawner;
public static BlockInfo WoodStairs;
public static TileEntityBlockInfo Chest;
public static BlockInfoEx Chest;
public static BlockInfo RedstoneWire;
public static BlockInfo DiamondOre;
public static BlockInfo DiamondBlock;
public static BlockInfo CraftTable;
public static BlockInfo Crops;
public static BlockInfo Farmland;
public static TileEntityBlockInfo Furnace;
public static TileEntityBlockInfo BurningFurnace;
public static TileEntityBlockInfo SignPost;
public static BlockInfoEx Furnace;
public static BlockInfoEx BurningFurnace;
public static BlockInfoEx SignPost;
public static BlockInfo WoodDoor;
public static BlockInfo Ladder;
public static BlockInfo Rails;
public static BlockInfo CobbleStairs;
public static TileEntityBlockInfo WallSign;
public static BlockInfoEx WallSign;
public static BlockInfo Lever;
public static BlockInfo StonePlate;
public static BlockInfo IronDoor;
@ -330,12 +328,10 @@ namespace NBToolkit.Map
_blockTable = new BlockInfo[MAX_BLOCKS];
_opacityTable = new int[MAX_BLOCKS];
_luminanceTable = new int[MAX_BLOCKS];
_schemaTable = new NBTCompoundNode[MAX_BLOCKS];
BlockTable = new ItemCache<BlockInfo>(_blockTable);
OpacityTable = new ItemCache<int>(_opacityTable);
LuminanceTable = new ItemCache<int>(_luminanceTable);
SchemaTable = new ItemCache<NBTCompoundNode>(_schemaTable);
Air = new BlockInfo(0, "Air").SetOpacity(0);
Stone = new BlockInfo(1, "Stone");
@ -360,9 +356,9 @@ namespace NBToolkit.Map
Glass = new BlockInfo(20, "Glass").SetOpacity(0);
LapisOre = new BlockInfo(21, "Lapis Lazuli Ore");
LapisBlock = new BlockInfo(22, "Lapis Lazuli Block");
Dispenser = new TileEntityBlockInfo(23, "Dispenser");
Dispenser = new BlockInfoEx(23, "Dispenser");
Sandstone = new BlockInfo(24, "Sandstone");
NoteBlock = new TileEntityBlockInfo(25, "Note Block");
NoteBlock = new BlockInfoEx(25, "Note Block");
Bed = new BlockInfo(26, "Bed").SetOpacity(0);
Wool = new BlockInfo(35, "Wool");
YellowFlower = new BlockInfo(37, "Yellow Flower").SetOpacity(0);
@ -380,23 +376,23 @@ namespace NBToolkit.Map
Obsidian = new BlockInfo(49, "Obsidian");
Torch = new BlockInfo(50, "Torch").SetOpacity(0).SetLuminance(MAX_LUMINANCE - 1);
Fire = new BlockInfo(51, "Fire").SetOpacity(0).SetLuminance(MAX_LUMINANCE);
MonsterSpawner = (TileEntityBlockInfo)new TileEntityBlockInfo(52, "Monster Spawner").SetOpacity(0);
MonsterSpawner = (BlockInfoEx)new BlockInfoEx(52, "Monster Spawner").SetOpacity(0);
WoodStairs = new BlockInfo(53, "Wooden Stairs").SetOpacity(0);
Chest = new TileEntityBlockInfo(54, "Chest");
Chest = new BlockInfoEx(54, "Chest");
RedstoneWire = new BlockInfo(55, "Redstone Wire").SetOpacity(0);
DiamondOre = new BlockInfo(56, "Diamond Ore");
DiamondBlock = new BlockInfo(57, "Diamond Block");
CraftTable = new BlockInfo(58, "Crafting Table");
Crops = new BlockInfo(59, "Crops").SetOpacity(0);
Farmland = new BlockInfo(60, "Farmland").SetOpacity(0);
Furnace = new TileEntityBlockInfo(61, "Furnace");
BurningFurnace = (TileEntityBlockInfo)new TileEntityBlockInfo(62, "Burning Furnace").SetLuminance(MAX_LUMINANCE - 1);
SignPost = (TileEntityBlockInfo)new TileEntityBlockInfo(63, "Sign Post").SetOpacity(0);
Furnace = new BlockInfoEx(61, "Furnace");
BurningFurnace = (BlockInfoEx)new BlockInfoEx(62, "Burning Furnace").SetLuminance(MAX_LUMINANCE - 1);
SignPost = (BlockInfoEx)new BlockInfoEx(63, "Sign Post").SetOpacity(0);
WoodDoor = new BlockInfo(64, "Wooden Door").SetOpacity(0);
Ladder = new BlockInfo(65, "Ladder").SetOpacity(0);
Rails = new BlockInfo(66, "Rails").SetOpacity(0);
CobbleStairs = new BlockInfo(67, "Cobblestone Stairs").SetOpacity(0);
WallSign = (TileEntityBlockInfo)new TileEntityBlockInfo(68, "Wall Sign").SetOpacity(0);
WallSign = (BlockInfoEx)new BlockInfoEx(68, "Wall Sign").SetOpacity(0);
Lever = new BlockInfo(69, "Lever").SetOpacity(0);
StonePlate = new BlockInfo(70, "Stone Pressure Plate").SetOpacity(0);
IronDoor = new BlockInfo(71, "Iron Door").SetOpacity(0);
@ -432,14 +428,14 @@ namespace NBToolkit.Map
// Set Tile Entity Data
Dispenser.SetTileEntity("Trap", TileEntity.TrapSchema);
NoteBlock.SetTileEntity("Music", TileEntity.MusicSchema);
MonsterSpawner.SetTileEntity("MonsterSpawner", TileEntity.MobSpawnerSchema);
Chest.SetTileEntity("Chest", TileEntity.ChestSchema);
Furnace.SetTileEntity("Furnace", TileEntity.FurnaceSchema);
BurningFurnace.SetTileEntity("Furnace", TileEntity.FurnaceSchema);
SignPost.SetTileEntity("Sign", TileEntity.SignSchema);
WallSign.SetTileEntity("Sign", TileEntity.SignSchema);
Dispenser.SetTileEntity("Trap");
NoteBlock.SetTileEntity("Music");
MonsterSpawner.SetTileEntity("MobSpawner");
Chest.SetTileEntity("Chest");
Furnace.SetTileEntity("Furnace");
BurningFurnace.SetTileEntity("Furnace");
SignPost.SetTileEntity("Sign");
WallSign.SetTileEntity("Sign");
// Set Data Limits
@ -482,29 +478,21 @@ namespace NBToolkit.Map
}
}
public class TileEntityBlockInfo : BlockInfo
public class BlockInfoEx : BlockInfo
{
private string _tileEntityName;
private NBTSchemaNode _tileEntitySchema;
public string TileEntityName
{
get { return _tileEntityName; }
}
public NBTSchemaNode TileEntitySchema
{
get { return _tileEntitySchema; }
}
public BlockInfoEx (int id) : base(id) { }
public TileEntityBlockInfo (int id) : base(id) { }
public BlockInfoEx (int id, string name) : base(id, name) { }
public TileEntityBlockInfo (int id, string name) : base(id, name) { }
public BlockInfo SetTileEntity (string name, NBTCompoundNode schema) {
public BlockInfo SetTileEntity (string name) {
_tileEntityName = name;
_tileEntitySchema = schema;
_schemaTable[ID] = schema;
return this;
}
}

View file

@ -49,4 +49,14 @@ namespace NBToolkit.Map
bool SetTileEntity (int lx, int ly, int lz, TileEntity te);
bool ClearTileEntity (int lx, int ly, int lz);
}
public interface IEntity
{
}
public interface IEntityCollection
{
List<Entity> FindAll (Predicate<Entity> match);
}
}

View file

@ -5,9 +5,28 @@ namespace NBToolkit.Map
{
using NBT;
using Utility;
using System.Collections.Generic;
public class Chunk : IChunk, ICopyable<Chunk>
public class Chunk : IChunk, INBTObject<Chunk>, ICopyable<Chunk>
{
public static NBTCompoundNode LevelSchema = new NBTCompoundNode()
{
new NBTCompoundNode("Level")
{
new NBTArrayNode("Blocks", 32768),
new NBTArrayNode("Data", 16384),
new NBTArrayNode("SkyLight", 16384),
new NBTArrayNode("BlockLight", 16384),
new NBTArrayNode("HeightMap", 256),
new NBTListNode("Entities", NBT_Type.TAG_COMPOUND),
new NBTListNode("TileEntities", NBT_Type.TAG_COMPOUND, TileEntity.BaseSchema),
new NBTScalerNode("LastUpdate", NBT_Type.TAG_LONG),
new NBTScalerNode("xPos", NBT_Type.TAG_INT),
new NBTScalerNode("zPos", NBT_Type.TAG_INT),
new NBTScalerNode("TerrainPopulated", NBT_Type.TAG_BYTE),
},
};
private NBT_Tree _tree;
private int _cx;
@ -22,6 +41,8 @@ namespace NBToolkit.Map
protected NBT_List _entities;
protected NBT_List _tileEntities;
protected Dictionary<BlockKey, NBT_Compound> _tileEntityTable;
public int X
{
get { return _cx; }
@ -49,39 +70,15 @@ namespace NBToolkit.Map
_cz = z;
BuildNBTTree();
BuildTileEntityCache();
}
public Chunk (NBT_Tree tree)
{
_tree = tree;
if (new ChunkVerifier(tree).Verify() == false) {
throw new MalformedNBTTreeException();
if (LoadTreeSafe(tree.Root) == null) {
throw new InvalidNBTObjectException();
}
NBT_Compound level = tree.Root["Level"] as NBT_Compound;
_blocks = level["Blocks"] as NBT_ByteArray;
_data = new NibbleArray(level["Data"].ToNBTByteArray().Data);
_blockLight = new NibbleArray(level["BlockLight"].ToNBTByteArray().Data);
_skyLight = new NibbleArray(level["SkyLight"].ToNBTByteArray().Data);
_heightMap = level["HeightMap"] as NBT_ByteArray;
_entities = level["Entities"] as NBT_List;
_tileEntities = level["TileEntities"] as NBT_List;
// List-type patch up
if (_entities.Count == 0) {
level["Entities"] = new NBT_List(NBT_Type.TAG_COMPOUND);
_entities = level["Entities"] as NBT_List;
}
if (_tileEntities.Count == 0) {
level["TileEntities"] = new NBT_List(NBT_Type.TAG_COMPOUND);
_tileEntities = level["TileEntities"] as NBT_List;
}
_cx = level["xPos"].ToNBTInt();
_cz = level["zPos"].ToNBTInt();
}
private void BuildNBTTree ()
@ -211,13 +208,32 @@ namespace NBToolkit.Map
public bool SetBlockID (int lx, int ly, int lz, int id)
{
int index = lx << 11 | lz << 7 | ly;
if (_blocks.Data[index] == id) {
int oldid = _blocks.Data[index];
if (oldid == id) {
return false;
}
// Update value
_blocks.Data[index] = (byte)id;
// Update tile entities
if (BlockInfo.SchemaTable[_blocks[index]] != BlockInfo.SchemaTable[id]) {
BlockInfoEx info1 = BlockInfo.BlockTable[oldid] as BlockInfoEx;
BlockInfoEx info2 = BlockInfo.BlockTable[id] as BlockInfoEx;
if (info1 != info2) {
if (info1 != null) {
ClearTileEntity(lx, ly, lz);
}
if (info2 != null) {
CreateTileEntity(lx, ly, lz);
}
}
/*if (BlockInfo.SchemaTable[_blocks[index]] != BlockInfo.SchemaTable[id]) {
if (BlockInfo.SchemaTable[_blocks[index]] != null) {
ClearTileEntity(lx, ly, lz);
}
@ -229,7 +245,7 @@ namespace NBToolkit.Map
te.Z = BlockGlobalZ(lz);
_tileEntities.Add(te.Root);
}
}
}*/
// Update height map
@ -250,9 +266,6 @@ namespace NBToolkit.Map
}
}
// Update value
_blocks.Data[index] = (byte)id;
return true;
}
@ -324,55 +337,92 @@ namespace NBToolkit.Map
return _heightMap[lz << 4 | lx];
}
private void CreateTileEntity (int lx, int ly, int lz)
{
BlockInfoEx info = GetBlockInfo(lx, ly, lz) as BlockInfoEx;
if (info == null) {
return;
}
TileEntity te = TileEntityFactory.Create(info.TileEntityName);
if (te == null) {
return;
}
te.X = BlockGlobalX(lx);
te.Y = BlockGlobalY(ly);
te.Z = BlockGlobalZ(lz);
_tileEntities.Add(te.BuildTree());
}
public TileEntity GetTileEntity (int lx, int ly, int lz)
{
int x = BlockGlobalX(lx);
int y = BlockGlobalY(ly);
int z = BlockGlobalZ(lz);
foreach (NBT_Compound te in _tileEntities) {
if (te["x"].ToNBTInt().Data == x &&
te["y"].ToNBTInt().Data == y &&
te["z"].ToNBTInt().Data == z) {
return new TileEntity(te);
}
BlockKey key = new BlockKey(x, y, z);
NBT_Compound te;
if (!_tileEntityTable.TryGetValue(key, out te)) {
return null;
}
return null;
return TileEntityFactory.Create(te);
}
public bool SetTileEntity (int lx, int ly, int lz, TileEntity te)
{
int id = GetBlockID(lx, ly, lz);
NBTCompoundNode schema = BlockInfo.SchemaTable[id];
if (schema == null) {
BlockInfoEx info = GetBlockInfo(lx, ly, lz) as BlockInfoEx;
if (info == null) {
return false;
}
if (!te.Verify(schema)) {
if (te.GetType() != TileEntityFactory.Lookup(info.TileEntityName)) {
return false;
}
ClearTileEntity(lx, ly, lz);
int x = BlockGlobalX(lx);
int y = BlockGlobalY(ly);
int z = BlockGlobalZ(lz);
te.X = BlockGlobalX(lx);
te.Y = BlockGlobalY(ly);
te.Z = BlockGlobalZ(lz);
BlockKey key = new BlockKey(x, y, z);
NBT_Compound oldte;
_tileEntities.Add(te.Root);
if (_tileEntityTable.TryGetValue(key, out oldte)) {
_tileEntities.Remove(oldte);
}
te.X = x;
te.Y = y;
te.Z = z;
NBT_Compound tree = te.BuildTree() as NBT_Compound;
_tileEntities.Add(tree);
_tileEntityTable[key] = tree;
return true;
}
public bool ClearTileEntity (int lx, int ly, int lz)
{
TileEntity te = GetTileEntity(lx, ly, lz);
if (te == null) {
int x = BlockGlobalX(lx);
int y = BlockGlobalY(ly);
int z = BlockGlobalZ(lz);
BlockKey key = new BlockKey(x, y, z);
NBT_Compound te;
if (!_tileEntityTable.TryGetValue(key, out te)) {
return false;
}
return _tileEntities.Remove(te.Root);
_tileEntities.Remove(te);
_tileEntityTable.Remove(key);
return true;
}
public virtual void SetLocation (int x, int z)
@ -383,9 +433,20 @@ namespace NBToolkit.Map
_cx = x;
_cz = z;
BuildTileEntityCache();
}
private void BuildTileEntityCache ()
{
_tileEntityTable = new Dictionary<BlockKey, NBT_Compound>();
foreach (NBT_Compound te in _tileEntities) {
te["x"].ToNBTInt().Data += diffx * BlockManager.CHUNK_XLEN;
te["z"].ToNBTInt().Data += diffz * BlockManager.CHUNK_ZLEN;
int tex = te["x"].ToNBTInt();
int tey = te["y"].ToNBTInt();
int tez = te["z"].ToNBTInt();
BlockKey key = new BlockKey(tex, tey, tez);
_tileEntityTable[key] = te;
}
}
@ -397,5 +458,67 @@ namespace NBToolkit.Map
}
#endregion
#region INBTObject<Chunk> Members
public Chunk LoadTree (NBT_Value tree)
{
NBT_Compound ctree = tree as NBT_Compound;
if (ctree == null) {
return null;
}
_tree = new NBT_Tree(ctree);
NBT_Compound level = _tree.Root["Level"] as NBT_Compound;
_blocks = level["Blocks"] as NBT_ByteArray;
_data = new NibbleArray(level["Data"].ToNBTByteArray().Data);
_blockLight = new NibbleArray(level["BlockLight"].ToNBTByteArray().Data);
_skyLight = new NibbleArray(level["SkyLight"].ToNBTByteArray().Data);
_heightMap = level["HeightMap"] as NBT_ByteArray;
_entities = level["Entities"] as NBT_List;
_tileEntities = level["TileEntities"] as NBT_List;
// List-type patch up
if (_entities.Count == 0) {
level["Entities"] = new NBT_List(NBT_Type.TAG_COMPOUND);
_entities = level["Entities"] as NBT_List;
}
if (_tileEntities.Count == 0) {
level["TileEntities"] = new NBT_List(NBT_Type.TAG_COMPOUND);
_tileEntities = level["TileEntities"] as NBT_List;
}
_cx = level["xPos"].ToNBTInt();
_cz = level["zPos"].ToNBTInt();
BuildTileEntityCache();
return this;
}
public Chunk LoadTreeSafe (NBT_Value tree)
{
if (!ValidateTree(tree)) {
return null;
}
return LoadTree(tree);
}
public NBT_Value BuildTree ()
{
return _tree.Root;
}
public bool ValidateTree (NBT_Value tree)
{
return new NBTVerifier(tree, LevelSchema).Verify();
}
#endregion
}
}

View file

@ -5,7 +5,7 @@ using System.Text;
namespace NBToolkit.Map
{
public class ChunkManager : IChunkContainer, IChunkCache
public class ChunkManager : IChunkContainer, IChunkCache, IEnumerable<ChunkRef>
{
public const int REGION_XLEN = 32;
public const int REGION_ZLEN = 32;
@ -169,6 +169,24 @@ namespace NBToolkit.Map
cz >>= REGION_ZLOG;
return _regionMan.GetRegion(cx, cz);
}
#region IEnumerable<ChunkRef> Members
public IEnumerator<ChunkRef> GetEnumerator ()
{
return new ChunkEnumerator(this);
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{
return new ChunkEnumerator(this);
}
#endregion
}
public class MissingChunkException : Exception

View file

@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
using NBT;
public class ChunkVerifier : NBTVerifier
{
protected static NBTCompoundNode levelSchema = new NBTCompoundNode()
{
new NBTCompoundNode("Level")
{
new NBTArrayNode("Blocks", 32768),
new NBTArrayNode("Data", 16384),
new NBTArrayNode("SkyLight", 16384),
new NBTArrayNode("BlockLight", 16384),
new NBTArrayNode("HeightMap", 256),
new NBTListNode("Entities", NBT_Type.TAG_COMPOUND),
new NBTListNode("TileEntities", NBT_Type.TAG_COMPOUND),
new NBTScalerNode("LastUpdate", NBT_Type.TAG_LONG),
new NBTScalerNode("xPos", NBT_Type.TAG_INT),
new NBTScalerNode("zPos", NBT_Type.TAG_INT),
new NBTScalerNode("TerrainPopulated", NBT_Type.TAG_BYTE),
},
};
public ChunkVerifier (NBT_Tree tree)
: base(tree.Root, levelSchema)
{
}
}
}

View file

@ -9,12 +9,22 @@ namespace NBToolkit.Map
public class Entity
{
private NBT_Compound _tree;
private string _entityID;
private double _posX;
private double _posY;
private double _posZ;
private double _motionX;
private double _motionY;
private double _motionZ;
private float _rotationYaw;
private float _rotationPitch;
private float _fallDistance;
private short _fire;
private short _air;
private byte _onGround;
public NBT_Compound Root
{
get { return _tree; }
}
#region Predefined Schemas
public static readonly NBTCompoundNode BaseSchema = new NBTCompoundNode("")
{
@ -42,28 +52,79 @@ namespace NBToolkit.Map
new NBTStringNode("id", "Monster"),
});
public static readonly NBTCompoundNode CreeperSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Creeper"),
});
public static readonly NBTCompoundNode SkeletonSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Skeleton"),
});
public static readonly NBTCompoundNode SpiderSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Spider"),
});
public static readonly NBTCompoundNode GiantSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Giant"),
});
public static readonly NBTCompoundNode ZombieSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Zombie"),
});
public static readonly NBTCompoundNode PigZombieSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "PigZombie"),
});
public static readonly NBTCompoundNode GhastSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Ghast"),
});
public static readonly NBTCompoundNode PigSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Pig"),
new NBTScalerNode("Saddle", NBT_Type.TAG_BYTE),
});
public static readonly NBTCompoundNode SheepSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Sheep"),
new NBTScalerNode("Sheared", NBT_Type.TAG_BYTE),
new NBTScalerNode("Color", NBT_Type.TAG_BYTE),
});
public static readonly NBTCompoundNode CowSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Cow"),
});
public static readonly NBTCompoundNode ChickenSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Chicken"),
});
public static readonly NBTCompoundNode Slimechema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Slime"),
new NBTScalerNode("Size", NBT_Type.TAG_INT),
});
public static readonly NBTCompoundNode WolfSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Wolf"),
new NBTScalerNode("Owner", NBT_Type.TAG_STRING),
new NBTScalerNode("Sitting", NBT_Type.TAG_BYTE),
new NBTScalerNode("Angry", NBT_Type.TAG_BYTE),
});
#endregion
}
public class MobEntity : Entity

View file

@ -5,54 +5,121 @@ using System.Text;
namespace NBToolkit.Map
{
using NBT;
using Utility;
public interface IItemContainer
{
ItemCollection Items { get; }
}
public class Item
public class Item : INBTObject<Item>, ICopyable<Item>
{
protected NBT_Compound _tree;
public NBT_Compound Root
public static readonly NBTCompoundNode ItemSchema = new NBTCompoundNode("")
{
get { return _tree; }
}
new NBTScalerNode("id", NBT_Type.TAG_SHORT),
new NBTScalerNode("Damage", NBT_Type.TAG_SHORT),
new NBTScalerNode("Count", NBT_Type.TAG_BYTE),
};
private short _id;
private byte _count;
private short _damage;
public int ID
{
get { return _tree["id"].ToNBTShort(); }
set { _tree["id"].ToNBTShort().Data = (short)value; }
get { return _id; }
set { _id = (short)value; }
}
public int Damage
{
get { return _tree["Damage"].ToNBTShort(); }
set { _tree["Count"].ToNBTShort().Data = (short)value; }
get { return _damage; }
set { _damage = (short)value; }
}
public int Count
{
get { return _tree["Count"].ToNBTByte(); }
set { _tree["Count"].ToNBTByte().Data = (byte) value; }
get { return _count; }
set { _count = (byte)value; }
}
public Item (NBT_Compound tree)
public Item ()
{
_tree = tree;
}
#region ICopyable<Item> Members
public Item Copy ()
{
Item item = new Item();
item._id = _id;
item._count = _count;
item._damage = _damage;
return item;
}
#endregion
#region INBTObject<Item> Members
public Item LoadTree (NBT_Value tree)
{
NBT_Compound ctree = tree as NBT_Compound;
if (ctree == null) {
return null;
}
_id = ctree["id"].ToNBTShort();
_count = ctree["Count"].ToNBTByte();
_damage = ctree["Damage"].ToNBTShort();
return this;
}
public Item LoadTreeSafe (NBT_Value tree)
{
if (!ValidateTree(tree)) {
return null;
}
return LoadTree(tree);
}
public NBT_Value BuildTree ()
{
NBT_Compound tree = new NBT_Compound();
tree["id"] = new NBT_Short(_id);
tree["Count"] = new NBT_Byte(_count);
tree["Damage"] = new NBT_Short(_damage);
return tree;
}
public bool ValidateTree (NBT_Value tree)
{
return new NBTVerifier(tree, ItemSchema).Verify();
}
#endregion
}
public class ItemCollection
public class ItemCollection : INBTObject<ItemCollection>, ICopyable<ItemCollection>
{
protected NBT_List _list;
public static readonly NBTCompoundNode InventorySchema = Item.ItemSchema.MergeInto(new NBTCompoundNode("")
{
new NBTScalerNode("Slot", NBT_Type.TAG_BYTE),
});
public static readonly NBTListNode ListSchema = new NBTListNode("", NBT_Type.TAG_COMPOUND, InventorySchema);
protected Dictionary<int, Item> _items;
protected int _capacity;
public ItemCollection (NBT_List list, int capacity)
public ItemCollection (int capacity)
{
_list = list;
_capacity = capacity;
_items = new Dictionary<int, Item>();
}
public int Capacity
@ -62,19 +129,16 @@ namespace NBToolkit.Map
public int Count
{
get { return _list.Count; }
get { return _items.Count; }
}
public Item this [int slot]
{
get
{
foreach (NBT_Compound tag in _list) {
if (tag["Slot"].ToNBTByte() == slot) {
return new Item(tag);
}
}
return null;
Item item;
_items.TryGetValue(slot, out item);
return item;
}
set
@ -82,109 +146,82 @@ namespace NBToolkit.Map
if (slot < 0 || slot >= _capacity) {
return;
}
foreach (NBT_Compound tag in _list) {
if (tag["Slot"].ToNBTByte() == slot) {
_list.Remove(tag);
break;
}
}
_list.Add(value.Root);
_items[slot] = value;
}
}
public int GetItemID (int slot)
{
NBT_Compound tag = FindTag(slot);
if (tag == null) {
return 0;
}
return tag["id"].ToNBTShort();
}
public int GetItemCount (int slot)
{
NBT_Compound tag = FindTag(slot);
if (tag == null) {
return 0;
}
return tag["Count"].ToNBTByte();
}
public int GetItemDamage (int slot)
{
NBT_Compound tag = FindTag(slot);
if (tag == null) {
return 0;
}
return tag["Damage"].ToNBTShort();
}
public bool SetItemID (int slot, int id)
{
NBT_Compound tag = FindTag(slot);
if (tag == null) {
return false;
}
tag["id"].ToNBTShort().Data = (short) id;
return true;
}
public bool SetItemCount (int slot, int count)
{
NBT_Compound tag = FindTag(slot);
if (tag == null) {
return false;
}
tag["Count"].ToNBTByte().Data = (byte) count;
return true;
}
public bool SetItemDamage (int slot, int damage)
{
NBT_Compound tag = FindTag(slot);
if (tag == null) {
return false;
}
tag["Damage"].ToNBTShort().Data = (short)damage;
return true;
}
public bool ClearItem (int slot)
{
foreach (NBT_Compound tag in _list) {
if (tag["Slot"].ToNBTByte() == slot) {
_list.Remove(tag);
return true;
}
}
return false;
}
public bool ItemExists (int slot)
{
return FindTag(slot) != null;
return _items.ContainsKey(slot);
}
public bool Clear (int slot)
{
return _items.Remove(slot);
}
public void ClearAllItems ()
{
_list.Clear();
_items.Clear();
}
private NBT_Compound FindTag (int slot)
#region ICopyable<ItemCollection> Members
public ItemCollection Copy ()
{
foreach (NBT_Compound tag in _list) {
if (tag["Slot"].ToNBTByte() == slot) {
return tag;
}
ItemCollection ic = new ItemCollection(_capacity);
foreach (KeyValuePair<int, Item> item in _items) {
ic[item.Key] = item.Value.Copy();
}
return null;
return ic;
}
#endregion
#region INBTObject<ItemCollection> Members
public ItemCollection LoadTree (NBT_Value tree)
{
NBT_List ltree = tree as NBT_List;
if (ltree == null) {
return null;
}
foreach (NBT_Compound item in ltree) {
int slot = item["Slot"].ToNBTByte();
_items[slot] = new Item().LoadTree(item);
}
return this;
}
public ItemCollection LoadTreeSafe (NBT_Value tree)
{
if (!ValidateTree(tree)) {
return null;
}
return LoadTree(tree);
}
public NBT_Value BuildTree ()
{
NBT_List list = new NBT_List(NBT_Type.TAG_COMPOUND);
foreach (KeyValuePair<int, Item> item in _items) {
NBT_Compound itemtree = item.Value.BuildTree() as NBT_Compound;
itemtree["Slot"] = new NBT_Byte((byte)item.Key);
list.Add(itemtree);
}
return list;
}
public bool ValidateTree (NBT_Value tree)
{
return new NBTVerifier(tree, ListSchema).Verify();
}
#endregion
}
}

View file

@ -8,6 +8,16 @@ namespace NBToolkit.Map.NBT
{
using Map.Utility;
public interface INBTObject<T>
{
T LoadTree (NBT_Value tree);
T LoadTreeSafe (NBT_Value tree);
NBT_Value BuildTree ();
bool ValidateTree (NBT_Value tree);
}
public class NBT_Tree : ICopyable<NBT_Tree>
{
private Stream _stream = null;
@ -25,6 +35,11 @@ namespace NBToolkit.Map.NBT
_root = new NBT_Compound();
}
public NBT_Tree (NBT_Compound tree)
{
_root = tree;
}
public NBT_Tree (Stream s)
{
ReadFrom(s);
@ -487,6 +502,8 @@ namespace NBToolkit.Map.NBT
public NBTException (String msg, Exception innerException) : base(msg, innerException) { }
}
public class InvalidNBTObjectException : Exception { }
public class InvalidTagException : Exception { }
public class InvalidValueException : Exception { }

View file

@ -135,7 +135,7 @@ namespace NBToolkit.Map.NBT
OnInvalidTagValue(new TagEventArgs(schema, tag));
return false;
}
if (schema.Name != null && stag.Data != schema.Value) {
if (schema.Value != null && stag.Data != schema.Value) {
OnInvalidTagValue(new TagEventArgs(schema, tag));
return false;
}

View file

@ -7,95 +7,8 @@ namespace NBToolkit.Map
using NBT;
using Utility;
public class TileEntity : ICopyable<TileEntity>
public class TileEntity : INBTObject<TileEntity>, ICopyable<TileEntity>
{
protected NBT_Compound _tree;
public NBT_Compound Root
{
get { return _tree; }
}
public string ID
{
get { return _tree["id"].ToNBTString(); }
}
public int X
{
get { return _tree["x"].ToNBTInt(); }
set { _tree["x"] = new NBT_Int(value); }
}
public int Y
{
get { return _tree["y"].ToNBTInt(); }
set { _tree["y"] = new NBT_Int(value); }
}
public int Z
{
get { return _tree["z"].ToNBTInt(); }
set { _tree["z"] = new NBT_Int(value); }
}
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;
}
public TileEntity (NBTSchemaNode schema)
{
_tree = schema.BuildDefaultTree() as NBT_Compound;
}
public virtual bool Verify ()
{
NBTVerifier v = new NBTVerifier(Root, BaseSchema);
return v.Verify();
}
public bool Verify (NBTSchemaNode schema)
{
NBTVerifier v = new NBTVerifier(Root, schema);
return v.Verify();
}
public bool LocatedAt (int x, int y, int z)
{
return _tree["x"].ToNBTInt().Data == x &&
_tree["y"].ToNBTInt().Data == y &&
_tree["z"].ToNBTInt().Data == z;
}
#region ICopyable<TileEntity> Members
public virtual TileEntity Copy ()
{
return new TileEntity(_tree.Copy() as NBT_Compound);
}
#endregion
#region Predefined Schemas
public static readonly NBTCompoundNode InventorySchema = new NBTCompoundNode("")
{
new NBTScalerNode("id", NBT_Type.TAG_SHORT),
new NBTScalerNode("Damage", NBT_Type.TAG_SHORT),
new NBTScalerNode("Count", NBT_Type.TAG_BYTE),
new NBTScalerNode("Slot", NBT_Type.TAG_BYTE),
};
public static readonly NBTCompoundNode BaseSchema = new NBTCompoundNode("")
{
new NBTScalerNode("id", NBT_Type.TAG_STRING),
@ -104,14 +17,211 @@ namespace NBToolkit.Map
new NBTScalerNode("z", NBT_Type.TAG_INT),
};
private string _id;
private int _x;
private int _y;
private int _z;
public string ID
{
get { return _id; }
}
public int X
{
get { return _x; }
set { _x = value; }
}
public int Y
{
get { return _y; }
set { _y = value; }
}
public int Z
{
get { return _z; }
set { _z = value; }
}
public TileEntity (string id)
{
_id = id;
}
public TileEntity (TileEntity te)
{
_id = te._id;
_x = te._x;
_y = te._y;
_z = te._z;
}
public bool LocatedAt (int x, int y, int z)
{
return _x == x && _y == y && _z == z;
}
#region ICopyable<TileEntity> Members
public virtual TileEntity Copy ()
{
return new TileEntity(this);
}
#endregion
#region INBTObject<TileEntity> Members
public virtual TileEntity LoadTree (NBT_Value tree)
{
NBT_Compound ctree = tree as NBT_Compound;
if (ctree == null) {
return null;
}
_id = ctree["id"].ToNBTString();
_x = ctree["x"].ToNBTInt();
_y = ctree["y"].ToNBTInt();
_z = ctree["z"].ToNBTInt();
return this;
}
public virtual TileEntity LoadTreeSafe (NBT_Value tree)
{
if (!ValidateTree(tree)) {
return null;
}
return LoadTree(tree);
}
public virtual NBT_Value BuildTree ()
{
NBT_Compound tree = new NBT_Compound();
tree["id"] = new NBT_String(_id);
tree["x"] = new NBT_Int(_x);
tree["y"] = new NBT_Int(_y);
tree["z"] = new NBT_Int(_z);
return tree;
}
public virtual bool ValidateTree (NBT_Value tree)
{
return new NBTVerifier(tree, BaseSchema).Verify();
}
#endregion
}
public class TileEntityFurnace : TileEntity, IItemContainer
{
public static readonly NBTCompoundNode FurnaceSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
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, InventorySchema),
new NBTListNode("Items", NBT_Type.TAG_COMPOUND, ItemCollection.ListSchema),
});
private const int _CAPACITY = 3;
private short _burnTime;
private short _cookTime;
private ItemCollection _items;
public int BurnTime
{
get { return _burnTime; }
set { _burnTime = (short)value; }
}
public int CookTime
{
get { return _cookTime; }
set { _cookTime = (short)value; }
}
public TileEntityFurnace ()
: base("Furnace")
{
_items = new ItemCollection(_CAPACITY);
}
public TileEntityFurnace (TileEntity te)
: base (te)
{
TileEntityFurnace tec = te as TileEntityFurnace;
if (tec != null) {
_cookTime = tec._cookTime;
_burnTime = tec._burnTime;
_items = tec._items.Copy();
}
else {
_items = new ItemCollection(_CAPACITY);
}
}
#region ICopyable<TileEntity> Members
public override TileEntity Copy ()
{
return new TileEntityFurnace(this);
}
#endregion
#region IItemContainer Members
public ItemCollection Items
{
get { return _items; }
}
#endregion
#region INBTObject<TileEntity> Members
public override TileEntity LoadTree (NBT_Value tree)
{
NBT_Compound ctree = tree as NBT_Compound;
if (ctree == null || base.LoadTree(tree) == null) {
return null;
}
_burnTime = ctree["BurnTime"].ToNBTShort();
_cookTime = ctree["CookTime"].ToNBTShort();
NBT_List items = ctree["Items"].ToNBTList();
_items = new ItemCollection(_CAPACITY).LoadTree(items);
return this;
}
public override NBT_Value BuildTree ()
{
NBT_Compound tree = base.BuildTree() as NBT_Compound;
tree["BurnTime"] = new NBT_Short(_burnTime);
tree["CookTime"] = new NBT_Short(_cookTime);
tree["Items"] = _items.BuildTree();
return tree;
}
public override bool ValidateTree (NBT_Value tree)
{
return new NBTVerifier(tree, FurnaceSchema).Verify();
}
#endregion
}
public class TileEntitySign : TileEntity
{
public static readonly NBTCompoundNode SignSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Sign"),
@ -121,132 +231,92 @@ namespace NBToolkit.Map
new NBTScalerNode("Text4", NBT_Type.TAG_STRING),
});
public static readonly NBTCompoundNode MobSpawnerSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "MobSpawner"),
new NBTScalerNode("EntityId", NBT_Type.TAG_STRING),
new NBTScalerNode("Delay", NBT_Type.TAG_SHORT),
});
private string _text1 = "";
private string _text2 = "";
private string _text3 = "";
private string _text4 = "";
public static readonly NBTCompoundNode ChestSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Chest"),
new NBTListNode("Items", NBT_Type.TAG_COMPOUND, InventorySchema),
});
public static readonly NBTCompoundNode MusicSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Music"),
new NBTScalerNode("note", NBT_Type.TAG_BYTE),
});
public static readonly NBTCompoundNode TrapSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Trap"),
new NBTListNode("Items", NBT_Type.TAG_COMPOUND, InventorySchema),
});
#endregion
}
public class TileEntityFurnace : TileEntity, IItemContainer
{
protected const int _capacity = 3;
protected ItemCollection _items;
public int BurnTime
{
get { return _tree["BurnTime"].ToNBTShort(); }
set { _tree["BurnTime"] = new NBT_Short((short)value); }
}
public int CookTime
{
get { return _tree["CookTime"].ToNBTShort(); }
set { _tree["CookTime"] = new NBT_Short((short)value); }
}
public TileEntityFurnace (NBT_Compound tree)
: base(tree)
{
NBT_List items = tree["Items"].ToNBTList();
if (items.Count == 0) {
tree["Items"] = new NBT_List(NBT_Type.TAG_COMPOUND);
items = _tree["Items"].ToNBTList();
}
_items = new ItemCollection(items, _capacity);
}
public override bool Verify ()
{
NBTVerifier v = new NBTVerifier(Root, TileEntity.FurnaceSchema);
return v.Verify();
}
#region ICopyable<TileEntity> Members
public override TileEntity Copy ()
{
return new TileEntityFurnace(_tree.Copy() as NBT_Compound);
}
#endregion
#region IItemContainer Members
public ItemCollection Items
{
get { return _items; }
}
#endregion
}
public class TileEntitySign : TileEntity
{
public string Text1
{
get { return _tree["Text1"].ToNBTString(); }
set { _tree["Text1"] = new NBT_String(value.Substring(0, 12)); }
get { return _text1; }
set { _text1 = value.Substring(0, 12); }
}
public string Text2
{
get { return _tree["Text2"].ToNBTString(); }
set { _tree["Text2"] = new NBT_String(value.Substring(0, 12)); }
get { return _text2; }
set { _text2 = value.Substring(0, 12); }
}
public string Text3
{
get { return _tree["Text3"].ToNBTString(); }
set { _tree["Text3"] = new NBT_String(value.Substring(0, 12)); }
get { return _text3; }
set { _text3 = value.Substring(0, 12); }
}
public string Text4
{
get { return _tree["Text4"].ToNBTString(); }
set { _tree["Text4"] = new NBT_String(value.Substring(0, 12)); }
get { return _text4; }
set { _text4 = value.Substring(0, 12); }
}
public TileEntitySign (NBT_Compound tree)
: base(tree)
public TileEntitySign ()
: base("Sign")
{
}
public override bool Verify ()
public TileEntitySign (TileEntity te)
: base(te)
{
NBTVerifier v = new NBTVerifier(Root, TileEntity.SignSchema);
return v.Verify();
TileEntitySign tes = te as TileEntitySign;
if (tes != null) {
_text1 = tes._text1;
_text2 = tes._text2;
_text3 = tes._text3;
_text4 = tes._text4;
}
}
#region ICopyable<TileEntity> Members
public override TileEntity Copy ()
{
return new TileEntitySign(_tree.Copy() as NBT_Compound);
return new TileEntitySign(this);
}
#endregion
#region INBTObject<TileEntity> Members
public override TileEntity LoadTree (NBT_Value tree)
{
NBT_Compound ctree = tree as NBT_Compound;
if (ctree == null || base.LoadTree(tree) == null) {
return null;
}
_text1 = ctree["Text1"].ToNBTString();
_text2 = ctree["Text2"].ToNBTString();
_text3 = ctree["Text3"].ToNBTString();
_text4 = ctree["Text4"].ToNBTString();
return this;
}
public override NBT_Value BuildTree ()
{
NBT_Compound tree = base.BuildTree() as NBT_Compound;
tree["Text1"] = new NBT_String(_text1);
tree["Text2"] = new NBT_String(_text2);
tree["Text3"] = new NBT_String(_text3);
tree["Text4"] = new NBT_String(_text4);
return tree;
}
public override bool ValidateTree (NBT_Value tree)
{
return new NBTVerifier(tree, SignSchema).Verify();
}
#endregion
@ -254,34 +324,79 @@ namespace NBToolkit.Map
public class TileEntityMobSpawner : TileEntity
{
public static readonly NBTCompoundNode MobSpawnerSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "MobSpawner"),
new NBTScalerNode("EntityId", NBT_Type.TAG_STRING),
new NBTScalerNode("Delay", NBT_Type.TAG_SHORT),
});
private short _delay;
private string _entityID;
public int Delay
{
get { return _tree["Delay"].ToNBTShort(); }
set { _tree["Delay"] = new NBT_Short((short)value); }
get { return _delay; }
set { _delay = (short)value; }
}
public string EntityID
{
get { return _tree["EntityID"].ToNBTString(); }
set { _tree["EntityID"] = new NBT_String(value); }
get { return _entityID; }
set { _entityID = value; }
}
public TileEntityMobSpawner (NBT_Compound tree)
: base(tree)
public TileEntityMobSpawner ()
: base("MobSpawner")
{
}
public override bool Verify ()
public TileEntityMobSpawner (TileEntity te)
: base(te)
{
NBTVerifier v = new NBTVerifier(Root, TileEntity.MobSpawnerSchema);
return v.Verify();
TileEntityMobSpawner tes = te as TileEntityMobSpawner;
if (tes != null) {
_delay = tes._delay;
_entityID = tes._entityID;
}
}
#region ICopyable<TileEntity> Members
public override TileEntity Copy ()
{
return new TileEntityMobSpawner(_tree.Copy() as NBT_Compound);
return new TileEntityMobSpawner(this);
}
#endregion
#region INBTObject<TileEntity> Members
public override TileEntity LoadTree (NBT_Value tree)
{
NBT_Compound ctree = tree as NBT_Compound;
if (ctree == null || base.LoadTree(tree) == null) {
return null;
}
_delay = ctree["Delay"].ToNBTShort();
_entityID = ctree["EntityID"].ToNBTString();
return this;
}
public override NBT_Value BuildTree ()
{
NBT_Compound tree = base.BuildTree() as NBT_Compound;
tree["EntityID"] = new NBT_String(_entityID);
tree["Delay"] = new NBT_Short(_delay);
return tree;
}
public override bool ValidateTree (NBT_Value tree)
{
return new NBTVerifier(tree, MobSpawnerSchema).Verify();
}
#endregion
@ -289,34 +404,39 @@ namespace NBToolkit.Map
public class TileEntityChest : TileEntity, IItemContainer
{
protected const int _capacity = 27;
protected ItemCollection _items;
public TileEntityChest (NBT_Compound tree)
: base(tree)
public static readonly NBTCompoundNode ChestSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
NBT_List items = tree["Items"].ToNBTList();
new NBTStringNode("id", "Chest"),
new NBTListNode("Items", NBT_Type.TAG_COMPOUND, ItemCollection.ListSchema),
});
if (items.Count == 0) {
tree["Items"] = new NBT_List(NBT_Type.TAG_COMPOUND);
items = _tree["Items"].ToNBTList();
}
private const int _CAPACITY = 27;
_items = new ItemCollection(items, _capacity);
private ItemCollection _items;
public TileEntityChest ()
: base("Chest")
{
_items = new ItemCollection(_CAPACITY);
}
public override bool Verify ()
public TileEntityChest (TileEntity te)
: base(te)
{
NBTVerifier v = new NBTVerifier(Root, TileEntity.ChestSchema);
return v.Verify();
TileEntityChest tec = te as TileEntityChest;
if (tec != null) {
_items = tec._items.Copy();
}
else {
_items = new ItemCollection(_CAPACITY);
}
}
#region ICopyable<TileEntity> Members
public override TileEntity Copy ()
{
return new TileEntityChest(_tree.Copy() as NBT_Compound);
return new TileEntityChest(this);
}
#endregion
@ -329,32 +449,102 @@ namespace NBToolkit.Map
}
#endregion
#region INBTObject<TileEntity> Members
public override TileEntity LoadTree (NBT_Value tree)
{
NBT_Compound ctree = tree as NBT_Compound;
if (ctree == null || base.LoadTree(tree) == null) {
return null;
}
NBT_List items = ctree["Items"].ToNBTList();
_items = new ItemCollection(_CAPACITY).LoadTree(items);
return this;
}
public override NBT_Value BuildTree ()
{
NBT_Compound tree = base.BuildTree() as NBT_Compound;
tree["Items"] = _items.BuildTree();
return tree;
}
public override bool ValidateTree (NBT_Value tree)
{
return new NBTVerifier(tree, ChestSchema).Verify();
}
#endregion
}
public class TileEntityMusic : TileEntity
{
public static readonly NBTCompoundNode MusicSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Music"),
new NBTScalerNode("note", NBT_Type.TAG_BYTE),
});
private byte _note;
public int Note
{
get { return _tree["Note"].ToNBTByte(); }
set { _tree["Note"] = new NBT_Byte((byte)value); }
get { return _note; }
set { _note = (byte)value; }
}
public TileEntityMusic (NBT_Compound tree)
: base(tree)
public TileEntityMusic ()
: base("Music")
{
}
public override bool Verify ()
public TileEntityMusic (TileEntity te)
: base(te)
{
NBTVerifier v = new NBTVerifier(Root, TileEntity.MusicSchema);
return v.Verify();
TileEntityMusic tes = te as TileEntityMusic;
if (tes != null) {
_note = tes._note;
}
}
#region ICopyable<TileEntity> Members
public override TileEntity Copy ()
{
return new TileEntityMusic(_tree.Copy() as NBT_Compound);
return new TileEntityMusic(this);
}
#endregion
#region INBTObject<TileEntity> Members
public override TileEntity LoadTree (NBT_Value tree)
{
NBT_Compound ctree = tree as NBT_Compound;
if (ctree == null || base.LoadTree(tree) == null) {
return null;
}
_note = ctree["Note"].ToNBTByte();
return this;
}
public override NBT_Value BuildTree ()
{
NBT_Compound tree = base.BuildTree() as NBT_Compound;
tree["Note"] = new NBT_Byte(_note);
return tree;
}
public override bool ValidateTree (NBT_Value tree)
{
return new NBTVerifier(tree, MusicSchema).Verify();
}
#endregion
@ -362,34 +552,39 @@ namespace NBToolkit.Map
public class TileEntityTrap : TileEntity, IItemContainer
{
protected const int _capacity = 8;
protected ItemCollection _items;
public TileEntityTrap (NBT_Compound tree)
: base(tree)
public static readonly NBTCompoundNode TrapSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
NBT_List items = tree["Items"].ToNBTList();
new NBTStringNode("id", "Trap"),
new NBTListNode("Items", NBT_Type.TAG_COMPOUND, ItemCollection.ListSchema),
});
if (items.Count == 0) {
tree["Items"] = new NBT_List(NBT_Type.TAG_COMPOUND);
items = _tree["Items"].ToNBTList();
}
private const int _CAPACITY = 8;
_items = new ItemCollection(items, _capacity);
private ItemCollection _items;
public TileEntityTrap ()
: base("Trap")
{
_items = new ItemCollection(_CAPACITY);
}
public override bool Verify ()
public TileEntityTrap (TileEntity te)
: base(te)
{
NBTVerifier v = new NBTVerifier(Root, TileEntity.TrapSchema);
return v.Verify();
TileEntityTrap tec = te as TileEntityTrap;
if (tec != null) {
_items = tec._items.Copy();
}
else {
_items = new ItemCollection(_CAPACITY);
}
}
#region ICopyable<TileEntity> Members
public override TileEntity Copy ()
{
return new TileEntityTrap(_tree.Copy() as NBT_Compound);
return new TileEntityTrap(this);
}
#endregion
@ -402,5 +597,35 @@ namespace NBToolkit.Map
}
#endregion
#region INBTObject<TileEntity> Members
public override TileEntity LoadTree (NBT_Value tree)
{
NBT_Compound ctree = tree as NBT_Compound;
if (ctree == null || base.LoadTree(tree) == null) {
return null;
}
NBT_List items = ctree["Items"].ToNBTList();
_items = new ItemCollection(_CAPACITY).LoadTree(items);
return this;
}
public override NBT_Value BuildTree ()
{
NBT_Compound tree = base.BuildTree() as NBT_Compound;
tree["Items"] = _items.BuildTree();
return tree;
}
public override bool ValidateTree (NBT_Value tree)
{
return new NBTVerifier(tree, TrapSchema).Verify();
}
#endregion
}
}

View file

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
using NBT;
public class TileEntityFactory
{
private static Dictionary<string, Type> _registry;
public static TileEntity Create (string type)
{
Type t;
if (!_registry.TryGetValue(type, out t)) {
return null;
}
return Activator.CreateInstance(t) as TileEntity;
}
public static TileEntity Create (NBT_Compound tree)
{
string type = tree["id"].ToNBTString();
Type t;
if (!_registry.TryGetValue(type, out t)) {
return null;
}
TileEntity te = Activator.CreateInstance(t, new object[] { tree }) as TileEntity;
return te.LoadTreeSafe(tree);
}
public static Type Lookup (string type)
{
Type t;
if (!_registry.TryGetValue(type, out t)) {
return null;
}
return t;
}
public static void Register (string id, Type subtype)
{
_registry[id] = subtype;
}
static TileEntityFactory ()
{
_registry = new Dictionary<string, Type>();
_registry["Chest"] = typeof(TileEntityChest);
_registry["Furnace"] = typeof(TileEntityFurnace);
_registry["MobSpawner"] = typeof(TileEntityMobSpawner);
_registry["Music"] = typeof(TileEntityMusic);
_registry["Sign"] = typeof(TileEntitySign);
_registry["Trap"] = typeof(TileEntityTrap);
}
}
}

View file

@ -73,11 +73,13 @@
<Compile Include="ChunkFilter.cs" />
<Compile Include="Map\ChunkKey.cs" />
<Compile Include="Map\ChunkManager.cs" />
<Compile Include="Map\ChunkVerifier.cs" />
<Compile Include="FilteredChunkEnumerator.cs" />
<Compile Include="GenOres.cs" />
<Compile Include="Map\Entity.cs" />
<Compile Include="Map\Item.cs" />
<Compile Include="Map\NBT\JSONSerializer.cs" />
<Compile Include="Map\TileEntity.cs" />
<Compile Include="Map\TileEntityFactory.cs" />
<Compile Include="Map\Utility\Interface.cs" />
<Compile Include="MathHelper.cs" />
<Compile Include="Map\NBT\NBT.cs" />

View file

@ -7,6 +7,7 @@ namespace NBToolkit
{
using Map;
using Map.NBT;
using System.Globalization;
public class ReplaceOptions : TKOptions, IChunkFilterable
{
@ -49,7 +50,7 @@ namespace NBToolkit
{ "d|data=", "Set the new block's data value to {VAL} (0-15)",
v => OPT_DATA = Convert.ToInt32(v) % 16 },
{ "p|prob=", "Replace any matching block with probability {VAL} (0.0-1.0)",
v => { OPT_PROB = Convert.ToDouble(v);
v => { OPT_PROB = Convert.ToDouble(v, new CultureInfo("en-US"));
OPT_PROB = Math.Max((double)OPT_PROB, 0.0);
OPT_PROB = Math.Min((double)OPT_PROB, 1.0); } },
{ "bxr|BlockXRange=", "Update blocks with X-coord between {0:V1} and {1:V2}, inclusive. V1 or V2 may be left blank.",