Forking Substrate to separate source tree

This commit is contained in:
Justin Aquadro 2011-04-06 04:43:54 +00:00
parent 496cd18b07
commit 99e986b338
31 changed files with 6828 additions and 0 deletions

View file

@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
using NBT;
using Utility;
public class Block : IBlock, ICopyable<Block>
{
private int _id;
private int _data;
private int _skylight;
private int _blocklight;
private TileEntity _tileEntity;
public BlockInfo Info
{
get { return BlockInfo.BlockTable[_id]; }
}
public int ID
{
get { return _id; }
set
{
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;
}
}
public int Data
{
get { return _data; }
set
{
if (BlockManager.EnforceDataLimits && BlockInfo.BlockTable[_id] != null) {
if (!BlockInfo.BlockTable[_id].TestData(value)) {
return;
}
}
_data = value;
}
}
public int SkyLight
{
get { return _skylight; }
set { _skylight = value; }
}
public int BlockLight
{
get { return _blocklight; }
set { _blocklight = value; }
}
public Block (int id)
{
_id = id;
}
public Block (int id, int data)
{
_id = id;
_data = data;
}
public Block (IChunk chunk, int lx, int ly, int lz)
{
_id = chunk.GetBlockID(lx, ly, lz);
_data = chunk.GetBlockData(lx, ly, lz);
_skylight = chunk.GetBlockSkyLight(lx, ly, lz);
_blocklight = chunk.GetBlockLight(lx, ly, lz);
_tileEntity = chunk.GetTileEntity(lx, ly, lz).Copy();
}
public TileEntity GetTileEntity ()
{
return _tileEntity;
}
public bool SetTileEntity (TileEntity te)
{
BlockInfoEx info = BlockInfo.BlockTable[_id] as BlockInfoEx;
if (info == null) {
return false;
}
if (te.GetType() != TileEntityFactory.Lookup(info.TileEntityName)) {
return false;
}
_tileEntity = te;
return true;
}
public bool ClearTileEntity ()
{
_tileEntity = null;
return true;
}
#region ICopyable<Block> Members
public Block Copy ()
{
Block block = new Block(_id, _data);
block._blocklight = _blocklight;
block._skylight = _skylight;
block._tileEntity = _tileEntity.Copy();
return block;
}
#endregion
}
}

View file

@ -0,0 +1,499 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
using NBT;
public enum BlockType
{
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
{
public const int MAX_BLOCKS = 256;
public const int MAX_OPACITY = 15;
public const int MIN_OPACITY = 0;
public const int MAX_LUMINANCE = 15;
public const int MIN_LUMINANCE = 0;
private static BlockInfo[] _blockTable;
private static int[] _opacityTable;
private static int[] _luminanceTable;
public class ItemCache<T>
{
private T[] _cache;
public T this[int index]
{
get { return _cache[index]; }
}
public ItemCache (T[] cache)
{
_cache = cache;
}
}
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;
public static ItemCache<int> LuminanceTable;
public static ItemCache<NBTCompoundNode> SchemaTable;
public int ID
{
get { return _id; }
}
public string Name
{
get { return _name; }
}
public int Opacity
{
get { return _opacity; }
}
public int Luminance
{
get { return _luminance; }
}
public BlockInfo (int id)
{
_id = id;
_blockTable[_id] = this;
}
public BlockInfo (int id, string name)
{
_id = id;
_name = name;
_blockTable[_id] = this;
}
public BlockInfo SetOpacity (int opacity)
{
_opacity = MIN_OPACITY + opacity;
_opacityTable[_id] = _opacity;
return this;
}
public BlockInfo SetLuminance (int luminance)
{
_luminance = luminance;
_luminanceTable[_id] = _luminance;
return this;
}
public BlockInfo SetDataLimits (int low, int high, int bitmask)
{
_dataLimits = new DataLimits(low, high, bitmask);
return this;
}
public bool TestData (int data)
{
if (_dataLimits == null) {
return true;
}
return _dataLimits.Test(data);
}
public static BlockInfo Air;
public static BlockInfo Stone;
public static BlockInfo Grass;
public static BlockInfo Dirt;
public static BlockInfo Cobblestone;
public static BlockInfo WoodPlank;
public static BlockInfo Sapling;
public static BlockInfo Bedrock;
public static BlockInfo Water;
public static BlockInfo StationaryWater;
public static BlockInfo Lava;
public static BlockInfo StationaryLava;
public static BlockInfo Sand;
public static BlockInfo Gravel;
public static BlockInfo GoldOre;
public static BlockInfo IronOre;
public static BlockInfo CoalOre;
public static BlockInfo Wood;
public static BlockInfo Leaves;
public static BlockInfo Sponge;
public static BlockInfo Glass;
public static BlockInfo LapisOre;
public static BlockInfo LapisBlock;
public static BlockInfoEx Dispenser;
public static BlockInfo Sandstone;
public static BlockInfoEx NoteBlock;
public static BlockInfo Bed;
public static BlockInfo Wool;
public static BlockInfo YellowFlower;
public static BlockInfo RedRose;
public static BlockInfo BrownMushroom;
public static BlockInfo RedMushroom;
public static BlockInfo GoldBlock;
public static BlockInfo IronBlock;
public static BlockInfo DoubleSlab;
public static BlockInfo Slab;
public static BlockInfo BrickBlock;
public static BlockInfo TNT;
public static BlockInfo Bookshelf;
public static BlockInfo MossStone;
public static BlockInfo Obsidian;
public static BlockInfo Torch;
public static BlockInfo Fire;
public static BlockInfoEx MonsterSpawner;
public static BlockInfo WoodStairs;
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 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 BlockInfoEx WallSign;
public static BlockInfo Lever;
public static BlockInfo StonePlate;
public static BlockInfo IronDoor;
public static BlockInfo WoodPlate;
public static BlockInfo RedstoneOre;
public static BlockInfo GlowRedstoneOre;
public static BlockInfo RedstoneTorch;
public static BlockInfo RedstoneTorchOn;
public static BlockInfo StoneButton;
public static BlockInfo Snow;
public static BlockInfo Ice;
public static BlockInfo SnowBlock;
public static BlockInfo Cactus;
public static BlockInfo ClayBlock;
public static BlockInfo SugarCane;
public static BlockInfo Jukebox;
public static BlockInfo Fence;
public static BlockInfo Pumpkin;
public static BlockInfo Netherrack;
public static BlockInfo SoulSand;
public static BlockInfo Glowstone;
public static BlockInfo Portal;
public static BlockInfo JackOLantern;
public static BlockInfo CakeBlock;
public static BlockInfo RedstoneRepeater;
public static BlockInfo RedstoneRepeaterOn;
static BlockInfo ()
{
_blockTable = new BlockInfo[MAX_BLOCKS];
_opacityTable = new int[MAX_BLOCKS];
_luminanceTable = new int[MAX_BLOCKS];
BlockTable = new ItemCache<BlockInfo>(_blockTable);
OpacityTable = new ItemCache<int>(_opacityTable);
LuminanceTable = new ItemCache<int>(_luminanceTable);
Air = new BlockInfo(0, "Air").SetOpacity(0);
Stone = new BlockInfo(1, "Stone");
Grass = new BlockInfo(2, "Grass");
Dirt = new BlockInfo(3, "Dirt");
Cobblestone = new BlockInfo(4, "Cobblestone");
WoodPlank = new BlockInfo(5, "Wooden Plank");
Sapling = new BlockInfo(6, "Sapling").SetOpacity(0);
Bedrock = new BlockInfo(7, "Bedrock");
Water = new BlockInfo(8, "Water").SetOpacity(3);
StationaryWater = new BlockInfo(9, "Stationary Water").SetOpacity(3);
Lava = new BlockInfo(10, "Lava").SetLuminance(MAX_LUMINANCE);
StationaryLava = new BlockInfo(11, "Stationary Lava").SetLuminance(MAX_LUMINANCE);
Sand = new BlockInfo(12, "Sand");
Gravel = new BlockInfo(13, "Gravel");
GoldOre = new BlockInfo(14, "Gold Ore");
IronOre = new BlockInfo(15, "Iron Ore");
CoalOre = new BlockInfo(16, "Coal Ore");
Wood = new BlockInfo(17, "Wood");
Leaves = new BlockInfo(18, "Leaves").SetOpacity(1);
Sponge = new BlockInfo(19, "Sponge");
Glass = new BlockInfo(20, "Glass").SetOpacity(0);
LapisOre = new BlockInfo(21, "Lapis Lazuli Ore");
LapisBlock = new BlockInfo(22, "Lapis Lazuli Block");
Dispenser = new BlockInfoEx(23, "Dispenser");
Sandstone = new BlockInfo(24, "Sandstone");
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);
RedRose = new BlockInfo(38, "Red Rose").SetOpacity(0);
BrownMushroom = new BlockInfo(39, "Brown Mushroom").SetOpacity(0).SetLuminance(1);
RedMushroom = new BlockInfo(40, "Red Mushroom").SetOpacity(0).SetLuminance(1);
GoldBlock = new BlockInfo(41, "Gold Block");
IronBlock = new BlockInfo(42, "Iron Block");
DoubleSlab = new BlockInfo(43, "Double Slab");
Slab = new BlockInfo(44, "Slab");
BrickBlock = new BlockInfo(45, "Brick Block");
TNT = new BlockInfo(46, "TNT");
Bookshelf = new BlockInfo(47, "Bookshelf");
MossStone = new BlockInfo(48, "Moss Stone");
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 = (BlockInfoEx)new BlockInfoEx(52, "Monster Spawner").SetOpacity(0);
WoodStairs = new BlockInfo(53, "Wooden Stairs").SetOpacity(0);
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 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 = (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);
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);
RedstoneTorchOn = new BlockInfo(76, "Redstone Torch (On)").SetOpacity(0).SetLuminance(7);
StoneButton = new BlockInfo(77, "Stone Button").SetOpacity(0);
Snow = new BlockInfo(78, "Snow").SetOpacity(0);
Ice = new BlockInfo(79, "Ice").SetOpacity(3);
SnowBlock = new BlockInfo(80, "Snow Block");
Cactus = new BlockInfo(81, "Cactus").SetOpacity(0);
ClayBlock = new BlockInfo(82, "Clay Block");
SugarCane = new BlockInfo(83, "Sugar Cane").SetOpacity(0);
Jukebox = new BlockInfo(84, "Jukebox");
Fence = new BlockInfo(85, "Fence").SetOpacity(0);
Pumpkin = new BlockInfo(86, "Pumpkin");
Netherrack = new BlockInfo(87, "Netherrack");
SoulSand = new BlockInfo(88, "Soul Sand");
Glowstone = new BlockInfo(89, "Glowstone Block").SetLuminance(MAX_LUMINANCE);
Portal = new BlockInfo(90, "Portal").SetOpacity(0).SetLuminance(11);
JackOLantern = new BlockInfo(91, "Jack-O-Lantern").SetLuminance(MAX_LUMINANCE);
CakeBlock = new BlockInfo(92, "Cake Block").SetOpacity(0);
RedstoneRepeater = new BlockInfo(93, "Redstone Repeater (Off)").SetOpacity(0);
RedstoneRepeaterOn = new BlockInfo(94, "Redstone Repeater (On)").SetOpacity(0).SetLuminance(7);
for (int i = 0; i < MAX_BLOCKS; i++) {
if (_blockTable[i] == null) {
_blockTable[i] = new BlockInfo(i, "Uknown Block");
}
}
// Set Tile Entity Data
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
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);
}
}
public class BlockInfoEx : BlockInfo
{
private string _tileEntityName;
public string TileEntityName
{
get { return _tileEntityName; }
}
public BlockInfoEx (int id) : base(id) { }
public BlockInfoEx (int id, string name) : base(id, name) { }
public BlockInfo SetTileEntity (string name) {
_tileEntityName = name;
return this;
}
}
}

View file

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
public interface IBlock
{
BlockInfo Info { get; }
int ID { get; set; }
int Data { get; set; }
int BlockLight { get; set; }
int SkyLight { get; set; }
TileEntity GetTileEntity ();
bool SetTileEntity (TileEntity te);
bool ClearTileEntity ();
}
public interface IBlockContainer
{
int BlockGlobalX (int x);
int BlockGlobalY (int y);
int BlockGlobalZ (int z);
int BlockLocalX (int x);
int BlockLocalY (int y);
int BlockLocalZ (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 IEntity
{
}
public interface IEntityCollection
{
List<Entity> FindAll (Predicate<Entity> match);
}
}

View file

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
public struct BlockKey : IEquatable<BlockKey>
{
readonly int x;
readonly int y;
readonly int z;
public BlockKey (int _x, int _y, int _z)
{
x = _x;
y = _y;
z = _z;
}
public bool Equals (BlockKey bk)
{
return this.x == bk.x && this.y == bk.y && this.z == bk.z;
}
public override bool Equals (Object o)
{
try {
return this == (BlockKey)o;
}
catch {
return false;
}
}
public override int GetHashCode ()
{
int hash = 23;
hash = hash * 37 + x;
hash = hash * 37 + y;
hash = hash * 37 + z;
return hash;
}
public static bool operator == (BlockKey k1, BlockKey k2)
{
return k1.x == k2.x && k1.y == k2.y && k1.z == k2.z;
}
public static bool operator != (BlockKey k1, BlockKey k2)
{
return k1.x != k2.x || k1.y != k2.y || k1.z != k2.z;
}
}
}

View file

@ -0,0 +1,251 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
/*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;
public const int MIN_Y = 0;
public const int MAX_Y = 128;
public const int MIN_Z = -32000000;
public const int MAX_Z = 32000000;
public const int CHUNK_XLEN = 16;
public const int CHUNK_YLEN = 128;
public const int CHUNK_ZLEN = 16;
public const int CHUNK_XLOG = 4;
public const int CHUNK_YLOG = 7;
public const int CHUNK_ZLOG = 4;
public const int CHUNK_XMASK = 0xF;
public const int CHUNK_YMASK = 0x7F;
public const int CHUNK_ZMASK = 0xF;
public static bool EnforceDataLimits = true;
protected ChunkManager _chunkMan;
protected ChunkRef _cache;
public BlockManager (ChunkManager cm)
{
_chunkMan = cm;
}
public BlockManager (BlockManager bm)
{
_chunkMan = bm._chunkMan;
}
public int BlockGlobalX (int x)
{
return x;
}
public int BlockGlobalY (int y)
{
return y;
}
public int BlockGlobalZ (int z)
{
return z;
}
public int BlockLocalX (int x)
{
return x & CHUNK_XMASK;
}
public int BlockLocalY (int y)
{
return y & CHUNK_YMASK;
}
public int BlockLocalZ (int z)
{
return z & CHUNK_ZMASK;
}
public virtual Block GetBlock (int x, int y, int z)
{
_cache = GetChunk(x, y, z);
if (_cache == null || !Check(x, y, z)) {
return null;
}
return _cache.GetBlock(x & CHUNK_XMASK, y, z & CHUNK_ZMASK);
}
public virtual BlockRef GetBlockRef (int x, int y, int z)
{
_cache = GetChunk(x, y, z);
if (_cache == null || !Check(x, y, z)) {
return null;
}
return _cache.GetBlockRef(x & CHUNK_XMASK, y, z & CHUNK_ZMASK);
}
public virtual BlockInfo GetBlockInfo (int x, int y, int z)
{
_cache = GetChunk(x, y, z);
if (_cache == null || !Check(x, y, z)) {
return null;
}
return _cache.GetBlockInfo(x & CHUNK_XMASK, y, z & CHUNK_ZMASK);
}
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)) {
return;
}
_cache.SetBlock(x & CHUNK_XMASK, y, z & CHUNK_ZMASK, block);
}
public virtual bool SetBlockID (int x, int y, int z, int id)
{
_cache = GetChunk(x, y, z);
if (_cache == null || !Check(x, y, z)) {
return false;
}
return _cache.SetBlockID(x & CHUNK_XMASK, y, z & CHUNK_ZMASK, id);
}
public virtual bool SetBlockData (int x, int y, int z, int data)
{
_cache = GetChunk(x, y, z);
if (_cache == null || !Check(x, y, z)) {
return false;
}
return _cache.SetBlockData(x & CHUNK_XMASK, y, z & CHUNK_ZMASK, data);
}
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.GetChunkRef(x, z);
}
/// <summary>
/// Called by other block-specific 'get' and 'set' functions to filter
/// out operations on some blocks. Override this method in derrived
/// classes to filter the entire BlockManager.
/// </summary>
protected virtual bool Check (int x, int y, int z) {
return (x >= MIN_X) && (x < MAX_X) &&
(y >= MIN_Y) && (y < MAX_Y) &&
(z >= MIN_Z) && (z < MAX_Z);
}
}
}

View file

@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
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.BlockGlobalX(_x); }
}
public int Y
{
get { return _container.BlockGlobalY(_y); }
}
public int Z
{
get { return _container.BlockGlobalZ(_z); }
}
public int LocalX
{
get { return _container.BlockLocalX(_x); }
}
public int LocalY
{
get { return _container.BlockLocalZ(_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;
protected int _lx;
protected int _ly;
protected int _lz;
public int X
{
get { return _lx + (_chunk.X * BlockManager.CHUNK_XLEN); }
}
public int Y
{
get { return _ly; }
}
public int Z
{
get { return _lz + (_chunk.Z * BlockManager.CHUNK_ZLEN); }
}
public int LocalX
{
get { return _lx; }
}
public int LocalY
{
get { return _ly; }
}
public int LocalZ
{
get { return _lz; }
}
public BlockInfo Info
{
get { return BlockInfo.BlockTable[_chunk.GetBlockID(_lx, _ly, _lz)]; }
}
public int ID
{
get { return _chunk.GetBlockID(_lx, _ly, _lz); }
set { _chunk.SetBlockID(_lx, _ly, _lz, value); }
}
public int Data
{
get { return _chunk.GetBlockData(_lx, _ly, _lz); }
set { _chunk.SetBlockData(_lx, _ly, _lz, value); }
}
public int BlockLight
{
get { return _chunk.GetBlockLight(_lx, _ly, _lz); }
set { _chunk.SetBlockLight(_lx, _ly, _lz, value); }
}
public int SkyLight
{
get { return _chunk.GetBlockSkyLight(_lx, _ly, _lz); }
set { _chunk.SetBlockSkyLight(_lx, _ly, _lz, value); }
}
public BlockRef (IChunk c, int lx, int ly, int lz)
{
_chunk = c;
_lx = lx;
_ly = ly;
_lz = lz;
}
public void CopyFrom (IBlock block)
{
ID = block.ID;
Data = block.Data;
BlockLight = block.BlockLight;
SkyLight = block.SkyLight;
}
public TileEntity GetTileEntity ()
{
return _chunk.GetTileEntity(_lx, _ly, _lz);
}
public bool SetTileEntity (TileEntity te)
{
return _chunk.SetTileEntity(_lx, _ly, _lz, te);
}
public bool ClearTileEntity ()
{
return _chunk.ClearTileEntity(_lx, _ly, _lz);
}
}*/
}

View file

@ -0,0 +1,524 @@
using System;
using System.IO;
namespace NBToolkit.Map
{
using NBT;
using Utility;
using System.Collections.Generic;
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;
private int _cz;
protected NBT_ByteArray _blocks;
protected NibbleArray _data;
protected NibbleArray _blockLight;
protected NibbleArray _skyLight;
protected NBT_ByteArray _heightMap;
protected NBT_List _entities;
protected NBT_List _tileEntities;
protected Dictionary<BlockKey, NBT_Compound> _tileEntityTable;
public int X
{
get { return _cx; }
}
public int Z
{
get { return _cz; }
}
public NBT_Tree Tree
{
get { return _tree; }
}
public bool IsTerrainPopulated
{
get { return _tree.Root["Level"].ToNBTCompound()["TerrainPopulated"].ToNBTByte() == 1; }
set { _tree.Root["Level"].ToNBTCompound()["TerrainPopulated"].ToNBTByte().Data = (byte)(value ? 1 : 0); }
}
public Chunk (int x, int z)
{
_cx = x;
_cz = z;
BuildNBTTree();
BuildTileEntityCache();
}
public Chunk (NBT_Tree tree)
{
if (LoadTreeSafe(tree.Root) == null) {
throw new InvalidNBTObjectException();
}
}
private void BuildNBTTree ()
{
int elements2 = BlockManager.CHUNK_XLEN * BlockManager.CHUNK_ZLEN;
int elements3 = elements2 * BlockManager.CHUNK_YLEN;
_blocks = new NBT_ByteArray(new byte[elements3]);
NBT_ByteArray data = new NBT_ByteArray(new byte[elements3 >> 1]);
NBT_ByteArray blocklight = new NBT_ByteArray(new byte[elements3 >> 1]);
NBT_ByteArray skylight = new NBT_ByteArray(new byte[elements3 >> 1]);
_heightMap = new NBT_ByteArray(new byte[elements2]);
_entities = new NBT_List(NBT_Type.TAG_COMPOUND);
_tileEntities = new NBT_List(NBT_Type.TAG_COMPOUND);
_data = new NibbleArray(data.Data);
_blockLight = new NibbleArray(blocklight.Data);
_skyLight = new NibbleArray(skylight.Data);
NBT_Compound level = new NBT_Compound();
level.Add("Blocks", _blocks);
level.Add("Data", data);
level.Add("SkyLight", blocklight);
level.Add("BlockLight", skylight);
level.Add("HeightMap", _heightMap);
level.Add("Entities", _entities);
level.Add("TileEntities", _tileEntities);
level.Add("LastUpdate", new NBT_Long());
level.Add("xPos", new NBT_Int());
level.Add("zPos", new NBT_Int());
level.Add("TerrainPopulated", new NBT_Byte());
_tree = new NBT_Tree();
_tree.Root.Add("Level", level);
}
public int BlockGlobalX (int x)
{
return _cx * BlockManager.CHUNK_XLEN + x;
}
public int BlockGlobalY (int y)
{
return y;
}
public int BlockGlobalZ (int z)
{
return _cz * BlockManager.CHUNK_ZLEN + z;
}
public int BlockLocalX (int x)
{
return x;
}
public int BlockLocalY (int y)
{
return y;
}
public int BlockLocalZ (int z)
{
return z;
}
public bool Save (Stream outStream)
{
if (outStream == null || !outStream.CanWrite) {
return false;
}
_tree.WriteTo(outStream);
outStream.Close();
return true;
}
public Block GetBlock (int lx, int ly, int lz)
{
return new Block(this, lx, ly, lz);
}
public BlockRef GetBlockRef (int lx, int ly, int lz)
{
return new BlockRef(this, lx, ly, lz);
}
public BlockInfo GetBlockInfo (int lx, int ly, int lz)
{
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];
}
public int GetBlockData (int lx, int ly, int lz)
{
return _data[lx << 11 | lz << 7 | ly];
}
public int GetBlockLight (int lx, int ly, int lz)
{
return _blockLight[lx << 11 | lz << 7 | ly];
}
public int GetBlockSkyLight (int lx, int ly, int lz)
{
return _skyLight[lx << 11 | lz << 7 | ly];
}
public bool SetBlockID (int lx, int ly, int lz, int id)
{
int index = lx << 11 | lz << 7 | ly;
int oldid = _blocks.Data[index];
if (oldid == id) {
return false;
}
// Update value
_blocks.Data[index] = (byte)id;
// Update tile entities
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);
}
if (BlockInfo.SchemaTable[id] != null) {
TileEntity te = new TileEntity(BlockInfo.SchemaTable[id]);
te.X = BlockGlobalX(lx);
te.Y = BlockGlobalY(ly);
te.Z = BlockGlobalZ(lz);
_tileEntities.Add(te.Root);
}
}*/
// Update height map
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;
}
}
}
}
return true;
}
public bool SetBlockData (int lx, int ly, int lz, int data)
{
int index = lx << 11 | lz << 7 | ly;
if (_data[index] == data) {
return false;
}
if (BlockManager.EnforceDataLimits && BlockInfo.BlockTable[_blocks[index]] != null) {
if (!BlockInfo.BlockTable[_blocks[index]].TestData(data)) {
return false;
}
}
_data[index] = data;
return true;
}
public bool SetBlockLight (int lx, int ly, int lz, int light)
{
int index = lx << 11 | lz << 7 | ly;
if (_blockLight[index] == light) {
return false;
}
_blockLight[index] = light;
return true;
}
public bool SetBlockSkyLight (int lx, int ly, int lz, int light)
{
int index = lx << 11 | lz << 7 | ly;
if (_skyLight[index] == light) {
return false;
}
_skyLight[index] = light;
return true;
}
public int CountBlockID (int id)
{
int c = 0;
for (int i = 0; i < _blocks.Length; i++) {
if (_blocks[i] == id) {
c++;
}
}
return c;
}
public int CountBlockData (int id, int data)
{
int c = 0;
for (int i = 0; i < _blocks.Length; i++) {
if (_blocks[i] == id && _data[i] == data) {
c++;
}
}
return c;
}
public int GetHeight (int lx, int lz)
{
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);
BlockKey key = new BlockKey(x, y, z);
NBT_Compound te;
if (!_tileEntityTable.TryGetValue(key, out te)) {
return null;
}
return TileEntityFactory.Create(te);
}
public bool SetTileEntity (int lx, int ly, int lz, TileEntity te)
{
BlockInfoEx info = GetBlockInfo(lx, ly, lz) as BlockInfoEx;
if (info == null) {
return false;
}
if (te.GetType() != TileEntityFactory.Lookup(info.TileEntityName)) {
return false;
}
int x = BlockGlobalX(lx);
int y = BlockGlobalY(ly);
int z = BlockGlobalZ(lz);
BlockKey key = new BlockKey(x, y, z);
NBT_Compound oldte;
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)
{
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;
}
_tileEntities.Remove(te);
_tileEntityTable.Remove(key);
return true;
}
public virtual void SetLocation (int x, int z)
{
int diffx = x - _cx;
int diffz = z - _cz;
_cx = x;
_cz = z;
BuildTileEntityCache();
}
private void BuildTileEntityCache ()
{
_tileEntityTable = new Dictionary<BlockKey, NBT_Compound>();
foreach (NBT_Compound te in _tileEntities) {
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;
}
}
#region ICopyable<Chunk> Members
public Chunk Copy ()
{
return new Chunk(_tree.Copy());
}
#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

@ -0,0 +1,156 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
namespace NBToolkit.Map
{
public class ChunkList : IEnumerable<ChunkRef>
{
//private List<Region> _regions;
protected ChunkManager _cm = null;
protected Region _region = null;
// Constructor to enumerate a single region
public ChunkList (ChunkManager cm, Region region)
{
_cm = cm;
_region = region;
}
// Constructor to enumerate all regions
public ChunkList (ChunkManager cm)
{
_cm = cm;
}
IEnumerator IEnumerable.GetEnumerator ()
{
return (IEnumerator)GetEnumerator();
}
IEnumerator<ChunkRef> IEnumerable<ChunkRef>.GetEnumerator ()
{
return (IEnumerator<ChunkRef>)GetEnumerator();
}
public virtual ChunkEnumerator GetEnumerator ()
{
return new ChunkEnumerator(_cm, _region);
}
}
public class ChunkEnumerator : IEnumerator<ChunkRef>
{
protected Region _region;
protected ChunkManager _cm;
protected ChunkRef _chunk;
protected RegionEnumerator _enum = null;
protected int _x = 0;
protected int _z = -1;
public ChunkEnumerator (ChunkManager cm, Region region)
{
_cm = cm;
_region = region;
if (_region == null) {
_enum = new RegionEnumerator(_cm.GetRegionManager());
_enum.MoveNext();
_region = _enum.Current;
}
}
public ChunkEnumerator (ChunkManager cm)
{
_cm = cm;
_enum = new RegionEnumerator(_cm.GetRegionManager());
_enum.MoveNext();
_region = _enum.Current;
}
public virtual bool MoveNext ()
{
if (_enum == null) {
return MoveNextInRegion();
}
else {
while (true) {
if (_x >= ChunkManager.REGION_XLEN) {
if (!_enum.MoveNext()) {
return false;
}
_x = 0;
_z = -1;
_region = _enum.Current;
}
if (MoveNextInRegion()) {
_chunk = _cm.GetChunkRefInRegion(_region, _x, _z);
return true;
}
}
}
}
protected bool MoveNextInRegion ()
{
for (; _x < ChunkManager.REGION_XLEN; _x++) {
for (_z++; _z < ChunkManager.REGION_ZLEN; _z++) {
if (_region.ChunkExists(_x, _z)) {
goto FoundNext;
}
}
_z = -1;
}
FoundNext:
return (_x < ChunkManager.REGION_XLEN);
}
public void Reset ()
{
if (_enum != null) {
_enum.Reset();
_enum.MoveNext();
_region = _enum.Current;
}
_x = 0;
_z = -1;
}
void IDisposable.Dispose () { }
object IEnumerator.Current
{
get
{
return Current;
}
}
ChunkRef IEnumerator<ChunkRef>.Current
{
get
{
return Current;
}
}
public ChunkRef Current
{
get
{
if (_x >= ChunkManager.REGION_XLEN) {
throw new InvalidOperationException();
}
return _chunk;
}
}
}
}

View file

@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Ionic.Zlib;
namespace NBToolkit.Map
{
class ChunkFile
{
private string _filename;
public ChunkFile (string path)
{
_filename = path;
}
public ChunkFile (string path, int cx, int cz)
{
string cx64 = Base64(cx);
string cz64 = Base64(cz);
string file = "c." + cx64 + "." + cz64 + ".dat";
string dir1 = Base64(cx % 64);
string dir2 = Base64(cz % 64);
_filename = Path.Combine(path, dir1);
_filename = Path.Combine(_filename, dir2);
_filename = Path.Combine(_filename, file);
}
private string Base64 (int val)
{
return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(val.ToString()));
}
public bool Exists ()
{
return File.Exists(_filename);
}
public bool Delete ()
{
File.Delete(_filename);
return true;
}
public Stream GetChunkDataInputStream ()
{
FileStream fstr = new FileStream(_filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
long length = fstr.Seek(0, SeekOrigin.End);
fstr.Seek(0, SeekOrigin.Begin);
byte[] data = new byte[length];
fstr.Read(data, 0, data.Length);
fstr.Close();
return new GZipStream(new MemoryStream(data), CompressionMode.Decompress);
}
public Stream GetChunkDataOutputStream ()
{
return new ZlibStream(new ChunkBuffer(this), CompressionMode.Compress);
}
class ChunkBuffer : MemoryStream
{
private ChunkFile region;
public ChunkBuffer (ChunkFile c)
: base(8096)
{
this.region = c;
}
public override void Close ()
{
FileStream fstr = new FileStream(region._filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
fstr.Write(this.GetBuffer(), 0, (int)this.Length);
fstr.Close();
}
}
}
}

View file

@ -0,0 +1,188 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace NBToolkit.Map
{
using NBT;
class ChunkFileManager : IChunkContainer, IChunkCache
{
protected string _mapPath;
protected Dictionary<ChunkKey, WeakReference> _cache;
protected Dictionary<ChunkKey, ChunkRef> _dirty;
public ChunkFileManager (string mapDir)
{
_mapPath = mapDir;
_cache = new Dictionary<ChunkKey, WeakReference>();
_dirty = new Dictionary<ChunkKey, ChunkRef>();
}
protected ChunkFile GetChunkFile (int cx, int cz)
{
return new ChunkFile(_mapPath, cx, cz);
}
protected NBT_Tree GetChunkTree (int cx, int cz)
{
ChunkFile cf = GetChunkFile(cx, cz);
Stream nbtstr = cf.GetChunkDataInputStream();
if (nbtstr == null) {
return null;
}
return new NBT_Tree(nbtstr);
}
protected bool SaveChunkTree (int cx, int cz, NBT_Tree tree)
{
ChunkFile cf = GetChunkFile(cx, cz);
Stream zipstr = cf.GetChunkDataOutputStream();
if (zipstr == null) {
return false;
}
tree.WriteTo(zipstr);
zipstr.Close();
return true;
}
protected Stream GetChunkOutStream (int cx, int cz)
{
return new ChunkFile(_mapPath, cx, cz).GetChunkDataOutputStream();
}
#region IChunkContainer Members
public int ChunkGlobalX (int cx)
{
return cx;
}
public int ChunkGlobalZ (int cz)
{
return cz;
}
public int ChunkLocalX (int cx)
{
return cx;
}
public int ChunkLocalZ (int cz)
{
return cz;
}
public Chunk GetChunk (int cx, int cz)
{
if (!ChunkExists(cx, cz)) {
return null;
}
return new Chunk(GetChunkTree(cx, cz));
}
public ChunkRef GetChunkRef (int cx, int cz)
{
ChunkKey k = new ChunkKey(cx, cz);
ChunkRef c = null;
WeakReference chunkref = null;
if (_cache.TryGetValue(k, out chunkref)) {
c = chunkref.Target as ChunkRef;
}
else {
_cache.Add(k, new WeakReference(null));
}
if (c != null) {
return c;
}
try {
c = new ChunkRef(this, this, cx, cz);
_cache[k].Target = c;
return c;
}
catch (MissingChunkException) {
return null;
}
}
public bool ChunkExists (int cx, int cz)
{
return new ChunkFile(_mapPath, cx, cz).Exists();
}
public bool DeleteChunk (int cx, int cz)
{
new ChunkFile(_mapPath, cx, cz).Delete();
ChunkKey k = new ChunkKey(cx, cz);
_cache.Remove(k);
_dirty.Remove(k);
return true;
}
public int Save ()
{
int saved = 0;
foreach (ChunkRef c in _dirty.Values) {
int cx = ChunkGlobalX(c.X);
int cz = ChunkGlobalZ(c.Z);
if (c.Save(GetChunkOutStream(cx, cz))) {
saved++;
}
}
_dirty.Clear();
return saved;
}
public bool SaveChunk (Chunk chunk)
{
return chunk.Save(GetChunkOutStream(ChunkGlobalX(chunk.X), ChunkGlobalZ(chunk.Z)));
}
#endregion
#region IChunkCache Members
public bool MarkChunkDirty (ChunkRef chunk)
{
int cx = chunk.X;
int cz = chunk.Z;
ChunkKey k = new ChunkKey(cx, cz);
if (!_dirty.ContainsKey(k)) {
_dirty.Add(k, GetChunkRef(cx, cz));
return true;
}
return false;
}
public bool MarkChunkClean (ChunkRef chunk)
{
int cx = chunk.X;
int cz = chunk.Z;
ChunkKey k = new ChunkKey(cx, cz);
if (_dirty.ContainsKey(k)) {
_dirty.Remove(k);
return true;
}
return false;
}
#endregion
}
}

View file

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace NBToolkit.Map
{
public interface IChunk : IBlockContainer
{
int X { get; }
int Z { get; }
bool IsTerrainPopulated { get; set; }
bool Save (Stream outStream);
int CountBlockID (int id);
int CountBlockData (int id, int data);
int GetHeight (int lx, int lz);
}
public interface IChunkCache
{
bool MarkChunkDirty (ChunkRef chunk);
bool MarkChunkClean (ChunkRef chunk);
}
public interface IChunkContainer
{
int ChunkGlobalX (int cx);
int ChunkGlobalZ (int cz);
int ChunkLocalX (int cx);
int ChunkLocalZ (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);
int Save ();
bool SaveChunk (Chunk chunk);
}
}

View file

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
public struct ChunkKey : IEquatable<ChunkKey>
{
readonly int cx;
readonly int cz;
public ChunkKey (int _cx, int _cz)
{
cx = _cx;
cz = _cz;
}
public bool Equals (ChunkKey ck)
{
return this.cx == ck.cx && this.cz == ck.cz;
}
public override bool Equals (Object o)
{
try {
return this == (ChunkKey)o;
}
catch {
return false;
}
}
public override int GetHashCode ()
{
int hash = 23;
hash = hash * 37 + cx;
hash = hash * 37 + cz;
return hash;
}
public static bool operator == (ChunkKey k1, ChunkKey k2)
{
return k1.cx == k2.cx && k1.cz == k2.cz;
}
public static bool operator != (ChunkKey k1, ChunkKey k2)
{
return k1.cx != k2.cx || k1.cz != k2.cz;
}
}
}

View file

@ -0,0 +1,196 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
public class ChunkManager : IChunkContainer, IChunkCache, IEnumerable<ChunkRef>
{
public const int REGION_XLEN = 32;
public const int REGION_ZLEN = 32;
public const int REGION_XLOG = 5;
public const int REGION_ZLOG = 5;
public const int REGION_XMASK = 0x1F;
public const int REGION_ZMASK = 0x1F;
protected RegionManager _regionMan;
protected Dictionary<RegionKey, Region> _cache;
protected Dictionary<RegionKey, Region> _dirty;
public ChunkManager (RegionManager rm)
{
_regionMan = rm;
_cache = new Dictionary<RegionKey, Region>();
_dirty = new Dictionary<RegionKey, Region>();
}
public int ChunkGlobalX (int cx)
{
return cx;
}
public int ChunkGlobalZ (int cz)
{
return cz;
}
public int ChunkLocalX (int cx)
{
return cx & REGION_XMASK;
}
public int ChunkLocalZ (int cz)
{
return cz & REGION_ZMASK;
}
public Chunk GetChunk (int cx, int cz)
{
Region r = GetRegion(cx, cz);
if (r == null) {
return null;
}
return r.GetChunk(cx & REGION_XMASK, cz & REGION_ZMASK);
}
public ChunkRef GetChunkRef (int cx, int cz)
{
Region r = GetRegion(cx, cz);
if (r == null) {
return null;
}
return r.GetChunkRef(cx & REGION_XMASK, cz & REGION_ZMASK, this);
}
public bool ChunkExists (int cx, int cz)
{
Region r = GetRegion(cx, cz);
if (r == null) {
return false;
}
return r.ChunkExists(cx & REGION_XMASK, cz & REGION_ZMASK);
}
public bool MarkChunkDirty (ChunkRef chunk)
{
Region r = GetRegion(chunk.X, chunk.Z);
if (r == null) {
return false;
}
RegionKey k = new RegionKey(r.X, r.Z);
_dirty[k] = r;
r.MarkChunkDirty(chunk);
return true;
}
public bool MarkChunkClean (ChunkRef chunk)
{
Region r = GetRegion(chunk.X, chunk.Z);
if (r == null) {
return false;
}
RegionKey k = new RegionKey(r.X, r.Z);
_dirty.Remove(k);
r.MarkChunkClean(chunk);
return true;
}
public int Save ()
{
int saved = 0;
foreach (Region r in _dirty.Values) {
saved += r.Save();
}
_dirty.Clear();
return saved;
}
public bool SaveChunk (Chunk chunk)
{
Region r = GetRegion(chunk.X, chunk.Z);
if (r == null) {
return false;
}
return r.SaveChunk(chunk);
}
public bool DeleteChunk (int cx, int cz)
{
Region r = GetRegion(cx, cz);
if (r == null) {
return false;
}
if (!r.DeleteChunk(cx & REGION_XMASK, cz & REGION_ZMASK)) {
return false;
}
if (r.ChunkCount() == 0) {
RegionKey k = new RegionKey(r.X, r.Z);
_cache.Remove(k);
_dirty.Remove(k);
_regionMan.DeleteRegion(r.X, r.Z);
}
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 Region GetRegion (int cx, int cz)
{
cx >>= REGION_XLOG;
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

@ -0,0 +1,328 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace NBToolkit.Map
{
using NBT;
public class ChunkRef : IChunk
{
private IChunkContainer _container;
private IChunkCache _cache;
private Chunk _chunk;
private int _cx;
private int _cz;
private bool _dirty;
public int X
{
get { return _container.ChunkGlobalX(_cx); }
}
public int Z
{
get { return _container.ChunkGlobalZ(_cz); }
}
public int LocalX
{
get { return _container.ChunkLocalX(_cx); }
}
public int LocalZ
{
get { return _container.ChunkLocalZ(_cz); }
}
public ChunkRef (IChunkContainer container, IChunkCache cache, int cx, int cz)
{
_container = container;
_cache = cache;
_cx = cx;
_cz = cz;
if (!_container.ChunkExists(cx, cz)) {
throw new MissingChunkException();
}
}
public int BlockGlobalX (int x)
{
return _container.ChunkGlobalX(_cx) * BlockManager.CHUNK_XLEN + x;
}
public int BlockGlobalY (int y)
{
return y;
}
public int BlockGlobalZ (int z)
{
return _container.ChunkGlobalZ(_cz) * BlockManager.CHUNK_ZLEN + z;
}
public int BlockLocalX (int x)
{
return x;
}
public int BlockLocalY (int y)
{
return y;
}
public int BlockLocalZ (int z)
{
return z;
}
private Chunk GetChunk ()
{
if (_chunk == null) {
_chunk = _container.GetChunk(_cx, _cz);
}
return _chunk;
}
private bool MarkDirty ()
{
if (_dirty) {
return false;
}
_dirty = true;
_cache.MarkChunkDirty(this);
return true;
}
public ChunkRef GetNorthNeighbor ()
{
return _container.GetChunkRef(_cx - 1, _cz);
}
public ChunkRef GetSouthNeighbor ()
{
return _container.GetChunkRef(_cx + 1, _cz);
}
public ChunkRef GetEastNeighbor ()
{
return _container.GetChunkRef(_cx, _cz - 1);
}
public ChunkRef GetWestNeighbor ()
{
return _container.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
public bool IsTerrainPopulated
{
get { return GetChunk().IsTerrainPopulated; }
set
{
if (GetChunk().IsTerrainPopulated != value) {
GetChunk().IsTerrainPopulated = value;
MarkDirty();
}
}
}
public bool Save (Stream outStream)
{
if (_dirty) {
if (GetChunk().Save(outStream)) {
_dirty = false;
return true;
}
return false;
}
return true;
}
public Block GetBlock (int lx, int ly, int lz)
{
return new Block(this, lx, ly, lz);
}
public BlockRef GetBlockRef (int lx, int ly, int lz)
{
return new BlockRef(this, lx, ly, lz);
}
public BlockInfo GetBlockInfo (int lx, int ly, int lz)
{
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);
}
public int GetBlockData (int lx, int ly, int lz)
{
return GetChunk().GetBlockData(lx, ly, lz);
}
public int GetBlockLight (int lx, int ly, int lz)
{
return GetChunk().GetBlockSkyLight(lx, ly, lz);
}
public int GetBlockSkyLight (int lx, int ly, int lz)
{
return GetChunk().GetBlockSkyLight(lx, ly, lz);
}
public bool SetBlockID (int lx, int ly, int lz, int id)
{
if (GetChunk().SetBlockID(lx, ly, lz, id)) {
MarkDirty();
return true;
}
return false;
}
public bool SetBlockData (int lx, int ly, int lz, int data)
{
if (GetChunk().SetBlockData(lx, ly, lz, data)) {
MarkDirty();
return true;
}
return false;
}
public bool SetBlockLight (int lx, int ly, int lz, int light)
{
if (GetChunk().SetBlockLight(lx, ly, lz, light)) {
MarkDirty();
return true;
}
return false;
}
public bool SetBlockSkyLight (int lx, int ly, int lz, int light)
{
if (GetChunk().SetBlockSkyLight(lx, ly, lz, light)) {
MarkDirty();
return true;
}
return false;
}
public int CountBlockID (int id)
{
return GetChunk().CountBlockID(id);
}
public int CountBlockData (int id, int data)
{
return GetChunk().CountBlockData(id, data);
}
public int GetHeight (int lx, int lz)
{
return GetChunk().GetHeight(lx, lz);
}
public TileEntity GetTileEntity (int lx, int ly, int lz)
{
return GetChunk().GetTileEntity(lx, ly, lz);
}
public bool SetTileEntity (int lx, int ly, int lz, TileEntity te)
{
if (GetChunk().SetTileEntity(lx, ly, lz, te)) {
MarkDirty();
return true;
}
return false;
}
public bool ClearTileEntity (int lx, int ly, int lz)
{
if (GetChunk().ClearTileEntity(lx, ly, lz)) {
MarkDirty();
return true;
}
return false;
}
#endregion
}
/*public bool VerifyTileEntities ()
{
bool pass = true;
NBT_List telist = GetTree().Root["Level"].ToNBTCompound()["TileEntities"].ToNBTList();
foreach (NBT_Value val in telist) {
NBT_Compound tree = val as NBT_Compound;
if (tree == null) {
pass = false;
continue;
}
if (new NBTVerifier(tree, TileEntity.BaseSchema).Verify() == false) {
pass = false;
continue;
}
int x = tree["x"].ToNBTInt() & BlockManager.CHUNK_XMASK;
int y = tree["y"].ToNBTInt() & BlockManager.CHUNK_YMASK;
int z = tree["z"].ToNBTInt() & BlockManager.CHUNK_ZMASK;
int id = GetBlockID(x, y, z);
NBTCompoundNode schema = BlockInfo.SchemaTable[id];
if (schema == null) {
pass = false;
continue;
}
pass = new NBTVerifier(tree, schema).Verify() && pass;
}
return pass;
}
private static bool LocalBounds (int lx, int ly, int lz)
{
return lx >= 0 && lx < BlockManager.CHUNK_XLEN &&
ly >= 0 && ly < BlockManager.CHUNK_YLEN &&
lz >= 0 && lz < BlockManager.CHUNK_ZLEN;
}*/
public class MalformedNBTTreeException : Exception { }
}

View file

@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
using NBT;
using Utility;
public class Entity
{
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;
#region Predefined Schemas
public static readonly NBTCompoundNode BaseSchema = new NBTCompoundNode("")
{
new NBTScalerNode("id", NBT_Type.TAG_STRING),
new NBTListNode("Pos", NBT_Type.TAG_DOUBLE, 3),
new NBTListNode("Motion", NBT_Type.TAG_DOUBLE, 3),
new NBTListNode("Rotation", NBT_Type.TAG_FLOAT, 2),
new NBTScalerNode("FallDistance", NBT_Type.TAG_FLOAT),
new NBTScalerNode("Fire", NBT_Type.TAG_SHORT),
new NBTScalerNode("Air", NBT_Type.TAG_SHORT),
new NBTScalerNode("OnGround", NBT_Type.TAG_BYTE),
};
public static readonly NBTCompoundNode MobSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Mob"),
new NBTScalerNode("AttackTime", NBT_Type.TAG_SHORT),
new NBTScalerNode("DeathTime", NBT_Type.TAG_SHORT),
new NBTScalerNode("Health", NBT_Type.TAG_SHORT),
new NBTScalerNode("HurtTime", NBT_Type.TAG_SHORT),
});
public static readonly NBTCompoundNode MonsterSchema = MobSchema.MergeInto(new NBTCompoundNode("")
{
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

@ -0,0 +1,227 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
using NBT;
using Utility;
public interface IItemContainer
{
ItemCollection Items { get; }
}
public class Item : INBTObject<Item>, ICopyable<Item>
{
public static readonly NBTCompoundNode ItemSchema = new NBTCompoundNode("")
{
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 _id; }
set { _id = (short)value; }
}
public int Damage
{
get { return _damage; }
set { _damage = (short)value; }
}
public int Count
{
get { return _count; }
set { _count = (byte)value; }
}
public Item ()
{
}
#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 : INBTObject<ItemCollection>, ICopyable<ItemCollection>
{
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 (int capacity)
{
_capacity = capacity;
_items = new Dictionary<int, Item>();
}
public int Capacity
{
get { return _capacity; }
}
public int Count
{
get { return _items.Count; }
}
public Item this [int slot]
{
get
{
Item item;
_items.TryGetValue(slot, out item);
return item;
}
set
{
if (slot < 0 || slot >= _capacity) {
return;
}
_items[slot] = value;
}
}
public bool ItemExists (int slot)
{
return _items.ContainsKey(slot);
}
public bool Clear (int slot)
{
return _items.Remove(slot);
}
public void ClearAllItems ()
{
_items.Clear();
}
#region ICopyable<ItemCollection> Members
public ItemCollection Copy ()
{
ItemCollection ic = new ItemCollection(_capacity);
foreach (KeyValuePair<int, Item> item in _items) {
ic[item.Key] = item.Value.Copy();
}
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

@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map.NBT
{
class JSONSerializer
{
public static string Serialize (NBT_Value tag)
{
return Serialize(tag, 0);
}
public static string Serialize (NBT_Value tag, int level)
{
StringBuilder str = new StringBuilder();
if (tag.GetNBTType() == NBT_Type.TAG_COMPOUND) {
SerializeCompound(tag as NBT_Compound, str, level);
}
else if (tag.GetNBTType() == NBT_Type.TAG_LIST) {
SerializeList(tag as NBT_List, str, level);
}
else {
SerializeScaler(tag, str);
}
return str.ToString();
}
private static void SerializeCompound (NBT_Compound tag, StringBuilder str, int level)
{
if (tag.Count == 0) {
str.Append("{ }");
return;
}
str.AppendLine();
AddLine(str, "{", level);
IEnumerator<KeyValuePair<string, NBT_Value>> en = tag.GetEnumerator();
bool first = true;
while (en.MoveNext()) {
if (!first) {
str.Append(",");
str.AppendLine();
}
KeyValuePair<string, NBT_Value> item = en.Current;
Add(str, "\"" + item.Key + "\": ", level + 1);
if (item.Value.GetNBTType() == NBT_Type.TAG_COMPOUND) {
SerializeCompound(item.Value as NBT_Compound, str, level + 1);
}
else if (item.Value.GetNBTType() == NBT_Type.TAG_LIST) {
SerializeList(item.Value as NBT_List, str, level + 1);
}
else {
SerializeScaler(item.Value, str);
}
first = false;
}
str.AppendLine();
Add(str, "}", level);
}
private static void SerializeList (NBT_List tag, StringBuilder str, int level)
{
if (tag.Count == 0) {
str.Append("[ ]");
return;
}
str.AppendLine();
AddLine(str, "[", level);
IEnumerator<NBT_Value> en = tag.GetEnumerator();
bool first = true;
while (en.MoveNext()) {
if (!first) {
str.Append(",");
}
NBT_Value item = en.Current;
if (item.GetNBTType() == NBT_Type.TAG_COMPOUND) {
SerializeCompound(item as NBT_Compound, str, level + 1);
}
else if (item.GetNBTType() == NBT_Type.TAG_LIST) {
SerializeList(item as NBT_List, str, level + 1);
}
else {
if (!first) {
str.AppendLine();
}
Indent(str, level + 1);
SerializeScaler(item, str);
}
first = false;
}
str.AppendLine();
Add(str, "]", level);
}
private static void SerializeScaler (NBT_Value tag, StringBuilder str)
{
NBT_Type type = tag.GetNBTType();
switch (tag.GetNBTType()) {
case NBT_Type.TAG_STRING:
str.Append("\"" + tag.ToNBTString().Data + "\"");
break;
case NBT_Type.TAG_BYTE:
str.Append(tag.ToNBTByte().Data);
break;
case NBT_Type.TAG_SHORT:
str.Append(tag.ToNBTShort().Data);
break;
case NBT_Type.TAG_INT:
str.Append(tag.ToNBTInt().Data);
break;
case NBT_Type.TAG_LONG:
str.Append(tag.ToNBTLong().Data);
break;
case NBT_Type.TAG_FLOAT:
str.Append(tag.ToNBTFloat().Data);
break;
case NBT_Type.TAG_DOUBLE:
str.Append(tag.ToNBTDouble().Data);
break;
case NBT_Type.TAG_BYTE_ARRAY:
str.Append(Convert.ToBase64String(tag.ToNBTByteArray().Data));
break;
}
}
private static void AddLine (StringBuilder str, string line, int level)
{
Indent(str, level);
str.AppendLine(line);
}
private static void Add (StringBuilder str, string line, int level)
{
Indent(str, level);
str.Append(line);
}
private static void Indent (StringBuilder str, int count)
{
for (int i = 0; i < count; i++) {
str.Append("\t");
}
}
}
}

View file

@ -0,0 +1,510 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.IO.Compression;
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;
private NBT_Compound _root = null;
private static NBT_Null _nulltag = new NBT_Null();
public NBT_Compound Root
{
get { return _root; }
}
public NBT_Tree ()
{
_root = new NBT_Compound();
}
public NBT_Tree (NBT_Compound tree)
{
_root = tree;
}
public NBT_Tree (Stream s)
{
ReadFrom(s);
}
public void ReadFrom (Stream s)
{
if (s != null) {
_stream = s;
_root = ReadRoot();
_stream = null;
}
}
public void WriteTo (Stream s)
{
if (s != null) {
_stream = s;
if (_root != null) {
WriteTag("", _root);
}
_stream = null;
}
}
private NBT_Value ReadValue (NBT_Type type)
{
switch (type) {
case NBT_Type.TAG_END:
return null;
case NBT_Type.TAG_BYTE:
return ReadByte();
case NBT_Type.TAG_SHORT:
return ReadShort();
case NBT_Type.TAG_INT:
return ReadInt();
case NBT_Type.TAG_LONG:
return ReadLong();
case NBT_Type.TAG_FLOAT:
return ReadFloat();
case NBT_Type.TAG_DOUBLE:
return ReadDouble();
case NBT_Type.TAG_BYTE_ARRAY:
return ReadByteArray();
case NBT_Type.TAG_STRING:
return ReadString();
case NBT_Type.TAG_LIST:
return ReadList();
case NBT_Type.TAG_COMPOUND:
return ReadCompound();
}
throw new Exception();
}
private NBT_Value ReadByte ()
{
int gzByte = _stream.ReadByte();
if (gzByte == -1) {
throw new NBTException(NBTException.MSG_GZIP_ENDOFSTREAM);
}
NBT_Byte val = new NBT_Byte((byte)gzByte);
return val;
}
private NBT_Value ReadShort ()
{
byte[] gzBytes = new byte[2];
_stream.Read(gzBytes, 0, 2);
if (BitConverter.IsLittleEndian) {
Array.Reverse(gzBytes);
}
NBT_Short val = new NBT_Short(BitConverter.ToInt16(gzBytes, 0));
return val;
}
private NBT_Value ReadInt ()
{
byte[] gzBytes = new byte[4];
_stream.Read(gzBytes, 0, 4);
if (BitConverter.IsLittleEndian) {
Array.Reverse(gzBytes);
}
NBT_Int val = new NBT_Int(BitConverter.ToInt32(gzBytes, 0));
return val;
}
private NBT_Value ReadLong ()
{
byte[] gzBytes = new byte[8];
_stream.Read(gzBytes, 0, 8);
if (BitConverter.IsLittleEndian) {
Array.Reverse(gzBytes);
}
NBT_Long val = new NBT_Long(BitConverter.ToInt64(gzBytes, 0));
return val;
}
private NBT_Value ReadFloat ()
{
byte[] gzBytes = new byte[4];
_stream.Read(gzBytes, 0, 4);
if (BitConverter.IsLittleEndian) {
Array.Reverse(gzBytes);
}
NBT_Float val = new NBT_Float(BitConverter.ToSingle(gzBytes, 0));
return val;
}
private NBT_Value ReadDouble ()
{
byte[] gzBytes = new byte[8];
_stream.Read(gzBytes, 0, 8);
if (BitConverter.IsLittleEndian) {
Array.Reverse(gzBytes);
}
NBT_Double val = new NBT_Double(BitConverter.ToDouble(gzBytes, 0));
return val;
}
private NBT_Value ReadByteArray ()
{
byte[] lenBytes = new byte[4];
_stream.Read(lenBytes, 0, 4);
if (BitConverter.IsLittleEndian) {
Array.Reverse(lenBytes);
}
int length = BitConverter.ToInt32(lenBytes, 0);
if (length < 0) {
throw new NBTException(NBTException.MSG_READ_NEG);
}
byte[] data = new byte[length];
_stream.Read(data, 0, length);
NBT_ByteArray val = new NBT_ByteArray(data);
return val;
}
private NBT_Value ReadString ()
{
byte[] lenBytes = new byte[2];
_stream.Read(lenBytes, 0, 2);
if (BitConverter.IsLittleEndian) {
Array.Reverse(lenBytes);
}
short len = BitConverter.ToInt16(lenBytes, 0);
if (len < 0) {
throw new NBTException(NBTException.MSG_READ_NEG);
}
byte[] strBytes = new byte[len];
_stream.Read(strBytes, 0, len);
System.Text.Encoding str = Encoding.GetEncoding(28591);
NBT_String val = new NBT_String(str.GetString(strBytes));
return val;
}
private NBT_Value ReadList ()
{
int gzByte = _stream.ReadByte();
if (gzByte == -1) {
throw new NBTException(NBTException.MSG_GZIP_ENDOFSTREAM);
}
NBT_List val = new NBT_List((NBT_Type)gzByte);
if (val.ValueType > (NBT_Type)Enum.GetValues(typeof(NBT_Type)).GetUpperBound(0)) {
throw new NBTException(NBTException.MSG_READ_TYPE);
}
byte[] lenBytes = new byte[4];
_stream.Read(lenBytes, 0, 4);
if (BitConverter.IsLittleEndian) {
Array.Reverse(lenBytes);
}
int length = BitConverter.ToInt32(lenBytes, 0);
if (length < 0) {
throw new NBTException(NBTException.MSG_READ_NEG);
}
for (int i = 0; i < length; i++) {
val.Add(ReadValue(val.ValueType));
}
return val;
}
private NBT_Value ReadCompound ()
{
NBT_Compound val = new NBT_Compound();
while (ReadTag(val)) ;
return val;
}
private NBT_Compound ReadRoot ()
{
NBT_Type type = (NBT_Type)_stream.ReadByte();
if (type == NBT_Type.TAG_COMPOUND) {
string name = ReadString().ToNBTString().Data;
return ReadValue(type) as NBT_Compound;
}
return null;
}
private bool ReadTag (NBT_Compound parent)
{
//NBT_Tag tag = new NBT_Tag();
NBT_Type type = (NBT_Type)_stream.ReadByte();
if (type != NBT_Type.TAG_END) {
string name = ReadString().ToNBTString().Data;
parent[name] = ReadValue(type);
return true;
}
return false;
//tag.Value = ReadValue(type);
//return tag;
}
private void WriteValue (NBT_Value val)
{
switch (val.GetNBTType()) {
case NBT_Type.TAG_END:
break;
case NBT_Type.TAG_BYTE:
WriteByte(val.ToNBTByte());
break;
case NBT_Type.TAG_SHORT:
WriteShort(val.ToNBTShort());
break;
case NBT_Type.TAG_INT:
WriteInt(val.ToNBTInt());
break;
case NBT_Type.TAG_LONG:
WriteLong(val.ToNBTLong());
break;
case NBT_Type.TAG_FLOAT:
WriteFloat(val.ToNBTFloat());
break;
case NBT_Type.TAG_DOUBLE:
WriteDouble(val.ToNBTDouble());
break;
case NBT_Type.TAG_BYTE_ARRAY:
WriteByteArray(val.ToNBTByteArray());
break;
case NBT_Type.TAG_STRING:
WriteString(val.ToNBTString());
break;
case NBT_Type.TAG_LIST:
WriteList(val.ToNBTList());
break;
case NBT_Type.TAG_COMPOUND:
WriteCompound(val.ToNBTCompound());
break;
}
}
private void WriteByte (NBT_Byte val)
{
_stream.WriteByte(val.Data);
}
private void WriteShort (NBT_Short val)
{
byte[] gzBytes = BitConverter.GetBytes(val.Data);
if (BitConverter.IsLittleEndian) {
Array.Reverse(gzBytes);
}
_stream.Write(gzBytes, 0, 2);
}
private void WriteInt (NBT_Int val)
{
byte[] gzBytes = BitConverter.GetBytes(val.Data);
if (BitConverter.IsLittleEndian) {
Array.Reverse(gzBytes);
}
_stream.Write(gzBytes, 0, 4);
}
private void WriteLong (NBT_Long val)
{
byte[] gzBytes = BitConverter.GetBytes(val.Data);
if (BitConverter.IsLittleEndian) {
Array.Reverse(gzBytes);
}
_stream.Write(gzBytes, 0, 8);
}
private void WriteFloat (NBT_Float val)
{
byte[] gzBytes = BitConverter.GetBytes(val.Data);
if (BitConverter.IsLittleEndian) {
Array.Reverse(gzBytes);
}
_stream.Write(gzBytes, 0, 4);
}
private void WriteDouble (NBT_Double val)
{
byte[] gzBytes = BitConverter.GetBytes(val.Data);
if (BitConverter.IsLittleEndian) {
Array.Reverse(gzBytes);
}
_stream.Write(gzBytes, 0, 8);
}
private void WriteByteArray (NBT_ByteArray val)
{
byte[] lenBytes = BitConverter.GetBytes(val.Length);
if (BitConverter.IsLittleEndian) {
Array.Reverse(lenBytes);
}
_stream.Write(lenBytes, 0, 4);
_stream.Write(val.Data, 0, val.Length);
}
private void WriteString (NBT_String val)
{
byte[] lenBytes = BitConverter.GetBytes((short)val.Length);
if (BitConverter.IsLittleEndian) {
Array.Reverse(lenBytes);
}
_stream.Write(lenBytes, 0, 2);
System.Text.Encoding str = Encoding.GetEncoding(28591);
byte[] gzBytes = str.GetBytes(val.Data);
_stream.Write(gzBytes, 0, gzBytes.Length);
}
private void WriteList (NBT_List val)
{
byte[] lenBytes = BitConverter.GetBytes(val.Count);
if (BitConverter.IsLittleEndian) {
Array.Reverse(lenBytes);
}
_stream.WriteByte((byte)val.ValueType);
_stream.Write(lenBytes, 0, 4);
foreach (NBT_Value v in val) {
WriteValue(v);
}
}
private void WriteCompound (NBT_Compound val)
{
foreach (KeyValuePair<string, NBT_Value> item in val) {
WriteTag(item.Key, item.Value);
}
WriteTag(null, _nulltag);
}
private void WriteTag (string name, NBT_Value val)
{
_stream.WriteByte((byte)val.GetNBTType());
if (val.GetNBTType() != NBT_Type.TAG_END) {
WriteString(name);
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
{
public const String MSG_GZIP_ENDOFSTREAM = "Gzip Error: Unexpected end of stream";
public const String MSG_READ_NEG = "Read Error: Negative length";
public const String MSG_READ_TYPE = "Read Error: Invalid value type";
public NBTException () { }
public NBTException (String msg) : base(msg) { }
public NBTException (String msg, Exception innerException) : base(msg, innerException) { }
}
public class InvalidNBTObjectException : Exception { }
public class InvalidTagException : Exception { }
public class InvalidValueException : Exception { }
}

View file

@ -0,0 +1,295 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map.NBT
{
public abstract class NBTSchemaNode
{
private string _name;
public string Name
{
get { return _name; }
}
public NBTSchemaNode (string name)
{
_name = name;
}
public virtual NBT_Value BuildDefaultTree ()
{
return null;
}
}
public class NBTScalerNode : NBTSchemaNode
{
private NBT_Type _type;
public NBT_Type Type
{
get { return _type; }
}
public NBTScalerNode (string name, NBT_Type type)
: base(name)
{
_type = type;
}
public override NBT_Value BuildDefaultTree ()
{
switch (_type) {
case NBT_Type.TAG_STRING:
return new NBT_String();
case NBT_Type.TAG_BYTE:
return new NBT_Byte();
case NBT_Type.TAG_SHORT:
return new NBT_Short();
case NBT_Type.TAG_INT:
return new NBT_Int();
case NBT_Type.TAG_LONG:
return new NBT_Long();
case NBT_Type.TAG_FLOAT:
return new NBT_Float();
case NBT_Type.TAG_DOUBLE:
return new NBT_Double();
}
return null;
}
}
public class NBTStringNode : NBTSchemaNode
{
private string _value = "";
private int _length;
public int Length
{
get { return _length; }
}
public string Value
{
get { return _value; }
}
public NBTStringNode (string name, string value)
: base(name)
{
_value = value;
}
public NBTStringNode (string name, int length)
: base(name)
{
_length = length;
}
public override NBT_Value BuildDefaultTree ()
{
if (_value.Length > 0) {
return new NBT_String(_value);
}
return new NBT_String();
}
}
public class NBTArrayNode : NBTSchemaNode
{
private int _length;
public int Length
{
get { return _length; }
}
public NBTArrayNode (string name)
: base(name)
{
_length = 0;
}
public NBTArrayNode (string name, int length)
: base(name)
{
_length = length;
}
public override NBT_Value BuildDefaultTree ()
{
return new NBT_ByteArray(new byte[_length]);
}
}
public class NBTListNode : NBTSchemaNode
{
private NBT_Type _type;
private int _length;
private NBTSchemaNode _subschema;
public int Length
{
get { return _length; }
}
public NBT_Type Type
{
get { return _type; }
}
public NBTSchemaNode SubSchema
{
get { return _subschema; }
}
public NBTListNode (string name, NBT_Type type)
: base(name)
{
_type = type;
}
public NBTListNode (string name, NBT_Type type, int length)
: base(name)
{
_type = type;
_length = length;
}
public NBTListNode (string name, NBT_Type type, NBTSchemaNode subschema)
: base(name)
{
_type = type;
_subschema = subschema;
}
public NBTListNode (string name, NBT_Type type, int length, NBTSchemaNode subschema)
: base(name)
{
_type = type;
_length = length;
_subschema = subschema;
}
public override NBT_Value BuildDefaultTree ()
{
if (_length == 0) {
return new NBT_List(_type);
}
NBT_List list = new NBT_List(_type);
for (int i = 0; i < _length; i++) {
list.Add(_subschema.BuildDefaultTree());
}
return list;
}
}
public class NBTCompoundNode : NBTSchemaNode, ICollection<NBTSchemaNode>
{
private List<NBTSchemaNode> _subnodes;
#region ICollection<NBTSchemaNode> Members
public void Add (NBTSchemaNode item)
{
_subnodes.Add(item);
}
public void Clear ()
{
_subnodes.Clear();
}
public bool Contains (NBTSchemaNode item)
{
return _subnodes.Contains(item);
}
public void CopyTo (NBTSchemaNode[] array, int arrayIndex)
{
_subnodes.CopyTo(array, arrayIndex);
}
public int Count
{
get { return _subnodes.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove (NBTSchemaNode item)
{
return _subnodes.Remove(item);
}
#endregion
#region IEnumerable<NBTSchemaNode> Members
public IEnumerator<NBTSchemaNode> GetEnumerator ()
{
return _subnodes.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{
return _subnodes.GetEnumerator();
}
#endregion
public NBTCompoundNode ()
: base("")
{
_subnodes = new List<NBTSchemaNode>();
}
public NBTCompoundNode (string name)
: base(name)
{
_subnodes = new List<NBTSchemaNode>();
}
public NBTCompoundNode MergeInto (NBTCompoundNode tree)
{
foreach (NBTSchemaNode node in _subnodes) {
NBTSchemaNode f = tree._subnodes.Find(n => n.Name == node.Name);
if (f != null) {
continue;
}
tree.Add(node);
}
return tree;
}
public override NBT_Value BuildDefaultTree ()
{
NBT_Compound list = new NBT_Compound();
foreach (NBTSchemaNode node in _subnodes) {
list[node.Name] = node.BuildDefaultTree();
}
return list;
}
}
}

View file

@ -0,0 +1,630 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map.NBT {
using Map.Utility;
/// <summary>
/// Describes the type of value held by an NBT_Tag
/// </summary>
public enum NBT_Type
{
TAG_END = 0,
TAG_BYTE = 1, // 8 bits signed
TAG_SHORT = 2, // 16 bits signed
TAG_INT = 3, // 32 bits signed
TAG_LONG = 4, // 64 bits signed
TAG_FLOAT = 5,
TAG_DOUBLE = 6,
TAG_BYTE_ARRAY = 7,
TAG_STRING = 8,
TAG_LIST = 9,
TAG_COMPOUND = 10
}
public abstract class NBT_Value : ICopyable<NBT_Value>
{
virtual public NBT_Null ToNBTNull () { throw new InvalidCastException(); }
virtual public NBT_Byte ToNBTByte () { throw new InvalidCastException(); }
virtual public NBT_Short ToNBTShort () { throw new InvalidCastException(); }
virtual public NBT_Int ToNBTInt () { throw new InvalidCastException(); }
virtual public NBT_Long ToNBTLong () { throw new InvalidCastException(); }
virtual public NBT_Float ToNBTFloat () { throw new InvalidCastException(); }
virtual public NBT_Double ToNBTDouble () { throw new InvalidCastException(); }
virtual public NBT_ByteArray ToNBTByteArray () { throw new InvalidCastException(); }
virtual public NBT_String ToNBTString () { throw new InvalidCastException(); }
virtual public NBT_List ToNBTList () { throw new InvalidCastException(); }
virtual public NBT_Compound ToNBTCompound () { throw new InvalidCastException(); }
virtual public NBT_Type GetNBTType () { return NBT_Type.TAG_END; }
public virtual NBT_Value Copy ()
{
return null;
}
}
public class NBT_Null : NBT_Value
{
override public NBT_Null ToNBTNull () { return this; }
override public NBT_Type GetNBTType () { return NBT_Type.TAG_END; }
public override NBT_Value Copy ()
{
return new NBT_Null();
}
}
public class NBT_Byte : NBT_Value
{
private byte _data = 0;
override public NBT_Byte ToNBTByte () { return this; }
override public NBT_Type GetNBTType () { return NBT_Type.TAG_BYTE; }
public byte Data
{
get { return _data; }
set { _data = value; }
}
public NBT_Byte () { }
public NBT_Byte (byte d)
{
_data = d;
}
public override NBT_Value Copy ()
{
return new NBT_Byte(_data);
}
public static implicit operator NBT_Byte (byte b)
{
return new NBT_Byte(b);
}
public static implicit operator byte (NBT_Byte b)
{
return b._data;
}
}
public class NBT_Short : NBT_Value
{
private short _data = 0;
override public NBT_Short ToNBTShort () { return this; }
override public NBT_Type GetNBTType () { return NBT_Type.TAG_SHORT; }
public short Data
{
get { return _data; }
set { _data = value; }
}
public NBT_Short () { }
public NBT_Short (short d)
{
_data = d;
}
public override NBT_Value Copy ()
{
return new NBT_Short(_data);
}
public static implicit operator NBT_Short (short s)
{
return new NBT_Short(s);
}
public static implicit operator short (NBT_Short s)
{
return s._data;
}
}
public class NBT_Int : NBT_Value
{
private int _data = 0;
override public NBT_Int ToNBTInt () { return this; }
override public NBT_Type GetNBTType () { return NBT_Type.TAG_INT; }
public int Data
{
get { return _data; }
set { _data = value; }
}
public NBT_Int () { }
public NBT_Int (int d)
{
_data = d;
}
public override NBT_Value Copy ()
{
return new NBT_Int(_data);
}
public static implicit operator NBT_Int (int i)
{
return new NBT_Int(i);
}
public static implicit operator int (NBT_Int i)
{
return i._data;
}
}
public class NBT_Long : NBT_Value
{
private long _data = 0;
override public NBT_Long ToNBTLong () { return this; }
override public NBT_Type GetNBTType () { return NBT_Type.TAG_LONG; }
public long Data
{
get { return _data; }
set { _data = value; }
}
public NBT_Long () { }
public NBT_Long (long d)
{
_data = d;
}
public override NBT_Value Copy ()
{
return new NBT_Long(_data);
}
public static implicit operator NBT_Long (long l)
{
return new NBT_Long(l);
}
public static implicit operator long (NBT_Long l)
{
return l._data;
}
}
public class NBT_Float : NBT_Value
{
private float _data = 0;
override public NBT_Float ToNBTFloat () { return this; }
override public NBT_Type GetNBTType () { return NBT_Type.TAG_FLOAT; }
public float Data
{
get { return _data; }
set { _data = value; }
}
public NBT_Float () { }
public NBT_Float (float d)
{
_data = d;
}
public override NBT_Value Copy ()
{
return new NBT_Float(_data);
}
public static implicit operator NBT_Float (float f)
{
return new NBT_Float(f);
}
public static implicit operator float (NBT_Float f)
{
return f._data;
}
}
public class NBT_Double : NBT_Value
{
private double _data = 0;
override public NBT_Double ToNBTDouble () { return this; }
override public NBT_Type GetNBTType () { return NBT_Type.TAG_DOUBLE; }
public double Data
{
get { return _data; }
set { _data = value; }
}
public NBT_Double () { }
public NBT_Double (double d)
{
_data = d;
}
public override NBT_Value Copy ()
{
return new NBT_Double(_data);
}
public static implicit operator NBT_Double (double d)
{
return new NBT_Double(d);
}
public static implicit operator double (NBT_Double d)
{
return d._data;
}
}
public class NBT_ByteArray : NBT_Value
{
private byte[] _data = null;
override public NBT_ByteArray ToNBTByteArray () { return this; }
override public NBT_Type GetNBTType () { return NBT_Type.TAG_BYTE_ARRAY; }
public byte[] Data
{
get { return _data; }
set { _data = value; }
}
public int Length
{
get { return _data.Length; }
}
public NBT_ByteArray () { }
public NBT_ByteArray (byte[] d)
{
_data = d;
}
public override NBT_Value Copy ()
{
byte[] arr = new byte[_data.Length];
_data.CopyTo(arr, 0);
return new NBT_ByteArray(arr);
}
public byte this [int index] {
get { return _data[index]; }
set { _data[index] = value; }
}
public static implicit operator NBT_ByteArray (byte[] b)
{
return new NBT_ByteArray(b);
}
}
public class NBT_String : NBT_Value
{
private string _data = "";
override public NBT_String ToNBTString () { return this; }
override public NBT_Type GetNBTType () { return NBT_Type.TAG_STRING; }
public string Data
{
get { return _data; }
set { _data = value; }
}
public int Length
{
get { return _data.Length; }
}
public NBT_String () { }
public NBT_String (string d)
{
_data = d;
}
public override NBT_Value Copy ()
{
return new NBT_String(_data);
}
public static implicit operator NBT_String (string s)
{
return new NBT_String(s);
}
public static implicit operator string (NBT_String s)
{
return s._data;
}
}
public class NBT_List : NBT_Value, IList<NBT_Value>
{
private NBT_Type _type = NBT_Type.TAG_END;
private List<NBT_Value> _items = null;
override public NBT_List ToNBTList () { return this; }
override public NBT_Type GetNBTType () { return NBT_Type.TAG_LIST; }
public int Count
{
get { return _items.Count; }
}
public NBT_Type ValueType
{
get { return _type; }
}
public NBT_List (NBT_Type type)
{
_type = type;
_items = new List<NBT_Value>();
}
public NBT_List (NBT_Type type, List<NBT_Value> items)
{
_type = type;
_items = items;
}
public override NBT_Value Copy ()
{
NBT_List list = new NBT_List(_type);
foreach (NBT_Value item in _items) {
list.Add(item.Copy());
}
return list;
}
#region IList<NBT_Value> Members
public int IndexOf (NBT_Value item)
{
return _items.IndexOf(item);
}
public void Insert (int index, NBT_Value item)
{
_items.Insert(index, item);
}
public void RemoveAt (int index)
{
_items.RemoveAt(index);
}
public NBT_Value this[int index]
{
get
{
return _items[index];
}
set
{
_items[index] = value;
}
}
#endregion
#region ICollection<NBT_Value> Members
public void Add (NBT_Value item)
{
_items.Add(item);
}
public void Clear ()
{
_items.Clear();
}
public bool Contains (NBT_Value item)
{
return _items.Contains(item);
}
public void CopyTo (NBT_Value[] array, int arrayIndex)
{
_items.CopyTo(array, arrayIndex);
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove (NBT_Value item)
{
return _items.Remove(item);
}
#endregion
#region IEnumerable<NBT_Value> Members
public IEnumerator<NBT_Value> GetEnumerator ()
{
return _items.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{
return _items.GetEnumerator();
}
#endregion
}
public class NBT_Compound : NBT_Value, IDictionary<string, NBT_Value>
{
private Dictionary<string, NBT_Value> _tags;
override public NBT_Compound ToNBTCompound () { return this; }
override public NBT_Type GetNBTType () { return NBT_Type.TAG_COMPOUND; }
public int Count
{
get { return _tags.Count; }
}
public NBT_Compound ()
{
_tags = new Dictionary<string, NBT_Value>();
}
public override NBT_Value Copy ()
{
NBT_Compound list = new NBT_Compound();
foreach (KeyValuePair<string, NBT_Value> item in _tags) {
list[item.Key] = item.Value.Copy();
}
return list;
}
#region IDictionary<string,NBT_Value> Members
public void Add (string key, NBT_Value value)
{
_tags.Add(key, value);
}
public bool ContainsKey (string key)
{
return _tags.ContainsKey(key);
}
public ICollection<string> Keys
{
get { return _tags.Keys; }
}
public bool Remove (string key)
{
return _tags.Remove(key);
}
public bool TryGetValue (string key, out NBT_Value value)
{
return _tags.TryGetValue(key, out value);
}
public ICollection<NBT_Value> Values
{
get { return _tags.Values; }
}
public NBT_Value this[string key]
{
get
{
return _tags[key];
}
set
{
_tags[key] = value;
}
}
#endregion
#region ICollection<KeyValuePair<string,NBT_Value>> Members
public void Add (KeyValuePair<string, NBT_Value> item)
{
_tags.Add(item.Key, item.Value);
}
public void Clear ()
{
_tags.Clear();
}
public bool Contains (KeyValuePair<string, NBT_Value> item)
{
NBT_Value value;
if (!_tags.TryGetValue(item.Key, out value)) {
return false;
}
return value == item.Value;
}
public void CopyTo (KeyValuePair<string, NBT_Value>[] array, int arrayIndex)
{
if (array == null) {
throw new ArgumentNullException();
}
if (arrayIndex < 0) {
throw new ArgumentOutOfRangeException();
}
if (array.Length - arrayIndex < _tags.Count) {
throw new ArgumentException();
}
foreach (KeyValuePair<string, NBT_Value> item in _tags) {
array[arrayIndex] = item;
arrayIndex++;
}
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove (KeyValuePair<string, NBT_Value> item)
{
if (Contains(item)) {
_tags.Remove(item.Key);
return true;
}
return false;
}
#endregion
#region IEnumerable<KeyValuePair<string,NBT_Value>> Members
public IEnumerator<KeyValuePair<string, NBT_Value>> GetEnumerator ()
{
return _tags.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
{
return _tags.GetEnumerator();
}
#endregion
}
}

View file

@ -0,0 +1,241 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map.NBT
{
public delegate void MissingTagHandler (Object o, TagEventArgs e);
public delegate void InvalidTagTypeHandler (Object o, TagEventArgs e);
public delegate void InvalidTagValueHandler (Object o, TagEventArgs e);
public interface INBTVerifier
{
event MissingTagHandler MissingTag;
event InvalidTagTypeHandler InvalidTagType;
event InvalidTagValueHandler InvalidTagValue;
bool Verify ();
}
public class TagEventArgs : EventArgs
{
protected string _tagName;
protected NBT_Value _tag;
protected NBTSchemaNode _schema;
public string TagName
{
get { return _tagName; }
}
public TagEventArgs (string tagName)
: base()
{
_tagName = tagName;
}
public TagEventArgs (string tagName, NBT_Value tag)
: base()
{
_tag = tag;
_tagName = tagName;
}
public TagEventArgs (NBTSchemaNode schema, NBT_Value tag)
: base()
{
_tag = tag;
_schema = schema;
}
}
public class NBTVerifier : INBTVerifier
{
private NBT_Value _root;
private NBTSchemaNode _schema;
public event MissingTagHandler MissingTag;
public event InvalidTagTypeHandler InvalidTagType;
public event InvalidTagValueHandler InvalidTagValue;
public NBTVerifier () { }
public NBTVerifier (NBT_Value root, NBTSchemaNode schema)
{
_root = root;
_schema = schema;
}
public bool Verify ()
{
return Verify(_root, _schema);
}
static 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),
};
private bool Verify (NBT_Value tag, NBTSchemaNode schema)
{
if (tag == null) {
OnMissingTag(new TagEventArgs(schema.Name));
return false;
}
NBTScalerNode scaler = schema as NBTScalerNode;
if (scaler != null) {
return VerifyScaler(tag, scaler);
}
NBTStringNode str = schema as NBTStringNode;
if (str != null) {
return VerifyString(tag, str);
}
NBTArrayNode array = schema as NBTArrayNode;
if (array != null) {
return VerifyArray(tag, array);
}
NBTListNode list = schema as NBTListNode;
if (list != null) {
return VerifyList(tag, list);
}
NBTCompoundNode compound = schema as NBTCompoundNode;
if (compound != null) {
return VerifyCompound(tag, compound);
}
return false;
}
private bool VerifyScaler (NBT_Value tag, NBTScalerNode schema)
{
if (tag.GetNBTType() != schema.Type) {
OnInvalidTagType(new TagEventArgs(schema.Name, tag));
return false;
}
return true;
}
private bool VerifyString (NBT_Value tag, NBTStringNode schema)
{
NBT_String stag = tag as NBT_String;
if (stag == null) {
OnInvalidTagType(new TagEventArgs(schema, tag));
return false;
}
if (schema.Length > 0 && stag.Length > schema.Length) {
OnInvalidTagValue(new TagEventArgs(schema, tag));
return false;
}
if (schema.Value != null && stag.Data != schema.Value) {
OnInvalidTagValue(new TagEventArgs(schema, tag));
return false;
}
return true;
}
private bool VerifyArray (NBT_Value tag, NBTArrayNode schema)
{
NBT_ByteArray atag = tag as NBT_ByteArray;
if (atag == null) {
OnInvalidTagType(new TagEventArgs(schema, tag));
return false;
}
if (schema.Length > 0 && atag.Length != schema.Length) {
OnInvalidTagValue(new TagEventArgs(schema, tag));
return false;
}
return true;
}
private bool VerifyList (NBT_Value tag, NBTListNode schema)
{
NBT_List ltag = tag as NBT_List;
if (ltag == null) {
OnInvalidTagType(new TagEventArgs(schema, tag));
return false;
}
if (ltag.Count > 0 && ltag.ValueType != schema.Type) {
OnInvalidTagValue(new TagEventArgs(schema, tag));
return false;
}
if (schema.Length > 0 && ltag.Count != schema.Length) {
OnInvalidTagValue(new TagEventArgs(schema, tag));
return false;
}
// Patch up empty lists
//if (schema.Length == 0) {
// tag = new NBT_List(schema.Type);
//}
bool pass = true;
// If a subschema is set, test all items in list against it
if (schema.SubSchema != null) {
foreach (NBT_Value v in ltag) {
pass = Verify(v, schema.SubSchema) && pass;
}
}
return pass;
}
private bool VerifyCompound (NBT_Value tag, NBTCompoundNode schema)
{
NBT_Compound ctag = tag as NBT_Compound;
if (ctag == null) {
OnInvalidTagType(new TagEventArgs(schema, tag));
return false;
}
bool pass = true;
foreach (NBTSchemaNode node in schema) {
NBT_Value value;
ctag.TryGetValue(node.Name, out value);
pass = Verify(value, node) && pass;
}
return pass;
}
#region Event Handlers
protected void OnMissingTag (TagEventArgs e)
{
if (MissingTag != null) {
MissingTag(this, e);
}
}
protected void OnInvalidTagType (TagEventArgs e)
{
if (InvalidTagType != null) {
InvalidTagType(this, e);
}
}
protected void OnInvalidTagValue (TagEventArgs e)
{
if (InvalidTagValue != null) {
InvalidTagValue(this, e);
}
}
#endregion
}
}

View file

@ -0,0 +1,334 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
namespace NBToolkit.Map
{
using NBT;
public class Region : IDisposable, IChunkContainer, IChunkCache
{
protected int _rx;
protected int _rz;
protected bool _disposed = false;
protected RegionManager _regionMan;
protected static Regex _namePattern = new Regex("r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mcr$");
protected WeakReference _regionFile;
protected Dictionary<ChunkKey, WeakReference> _cache;
protected Dictionary<ChunkKey, ChunkRef> _dirty;
public int X
{
get { return _rx; }
}
public int Z
{
get { return _rz; }
}
public Region (RegionManager rm, int rx, int rz)
{
_regionMan = rm;
_regionFile = new WeakReference(null);
_rx = rx;
_rz = rz;
_cache = new Dictionary<ChunkKey, WeakReference>();
_dirty = new Dictionary<ChunkKey, ChunkRef>();
if (!File.Exists(GetFilePath())) {
throw new FileNotFoundException();
}
}
public Region (RegionManager rm, string filename)
{
_regionMan = rm;
_regionFile = new WeakReference(null);
ParseFileName(filename, out _rx, out _rz);
if (!File.Exists(Path.Combine(_regionMan.GetRegionPath(), filename))) {
throw new FileNotFoundException();
}
}
~Region ()
{
Dispose(false);
}
public void Dispose ()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
protected virtual void Dispose (bool disposing)
{
if (!_disposed) {
if (disposing) {
// Cleanup managed resources
RegionFile rf = _regionFile.Target as RegionFile;
if (rf != null) {
rf.Dispose();
rf = null;
}
}
// Cleanup unmanaged resources
}
_disposed = true;
}
public string GetFileName ()
{
return "r." + _rx + "." + _rz + ".mcr";
}
public static bool TestFileName (string filename)
{
Match match = _namePattern.Match(filename);
if (!match.Success) {
return false;
}
return true;
}
public static bool ParseFileName (string filename, out int x, out int z)
{
x = 0;
z = 0;
Match match = _namePattern.Match(filename);
if (!match.Success) {
return false;
}
x = Convert.ToInt32(match.Groups[1].Value);
z = Convert.ToInt32(match.Groups[2].Value);
return true;
}
public string GetFilePath ()
{
return System.IO.Path.Combine(_regionMan.GetRegionPath(), GetFileName());
}
protected RegionFile GetRegionFile ()
{
RegionFile rf = _regionFile.Target as RegionFile;
if (rf == null) {
rf = new RegionFile(GetFilePath());
_regionFile.Target = rf;
}
return rf;
}
public NBT_Tree GetChunkTree (int lcx, int lcz)
{
RegionFile rf = GetRegionFile();
Stream nbtstr = rf.GetChunkDataInputStream(lcx, lcz);
if (nbtstr == null) {
return null;
}
return new NBT_Tree(nbtstr);
}
public bool SaveChunkTree (int lcx, int lcz, NBT_Tree tree)
{
RegionFile rf = GetRegionFile();
Stream zipstr = rf.GetChunkDataOutputStream(lcx, lcz);
if (zipstr == null) {
return false;
}
tree.WriteTo(zipstr);
zipstr.Close();
return true;
}
public Stream GetChunkOutStream (int lcx, int lcz)
{
RegionFile rf = GetRegionFile();
return rf.GetChunkDataOutputStream(lcx, lcz);
}
public int ChunkCount ()
{
RegionFile rf = GetRegionFile();
int count = 0;
for (int x = 0; x < ChunkManager.REGION_XLEN; x++) {
for (int z = 0; z < ChunkManager.REGION_ZLEN; z++) {
if (rf.HasChunk(x, z)) {
count++;
}
}
}
return count;
}
public ChunkRef GetChunkRef (int lcx, int lcz, IChunkCache cache)
{
ChunkKey k = new ChunkKey(lcx, lcz);
ChunkRef c = null;
WeakReference chunkref = null;
if (_cache.TryGetValue(k, out chunkref)) {
c = chunkref.Target as ChunkRef;
}
else {
_cache.Add(k, new WeakReference(null));
}
if (c != null) {
return c;
}
try {
c = new ChunkRef(this, cache, lcx, lcz);
_cache[k].Target = c;
return c;
}
catch (MissingChunkException) {
return null;
}
}
#region IChunkCollection Members
public int ChunkGlobalX (int cx)
{
return _rx * ChunkManager.REGION_XLEN + cx;
}
public int ChunkGlobalZ (int cz)
{
return _rz * ChunkManager.REGION_ZLEN + cz;
}
public int ChunkLocalX (int cx)
{
return cx;
}
public int ChunkLocalZ (int cz)
{
return cz;
}
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)
{
return GetChunkRef(lcx, lcz, this);
}
public bool ChunkExists (int lcx, int lcz)
{
RegionFile rf = GetRegionFile();
return rf.HasChunk(lcx, lcz);
}
public bool DeleteChunk (int lcx, int lcz)
{
RegionFile rf = GetRegionFile();
if (!rf.HasChunk(lcx, lcz)) {
return false;
}
rf.DeleteChunk(lcx, lcz);
ChunkKey k = new ChunkKey(lcx, lcz);
_cache.Remove(k);
_dirty.Remove(k);
if (ChunkCount() == 0) {
_regionMan.DeleteRegion(X, Z);
}
return true;
}
public int Save ()
{
int saved = 0;
foreach (ChunkRef c in _dirty.Values) {
int lcx = c.LocalX;
int lcz = c.LocalZ;
if (!ChunkExists(lcx, lcz)) {
throw new MissingChunkException();
}
if (c.Save(GetChunkOutStream(lcx, lcz))) {
saved++;
}
}
_dirty.Clear();
return saved;
}
public bool SaveChunk (Chunk chunk)
{
return chunk.Save(GetChunkOutStream(ChunkLocalX(chunk.X), ChunkLocalZ(chunk.Z)));
}
#endregion
#region IChunkCache Members
public bool MarkChunkDirty (ChunkRef chunk)
{
int lcx = chunk.LocalX;
int lcz = chunk.LocalZ;
ChunkKey k = new ChunkKey(lcx, lcz);
if (!_dirty.ContainsKey(k)) {
_dirty.Add(k, GetChunkRef(lcx, lcz));
return true;
}
return false;
}
public bool MarkChunkClean (ChunkRef chunk)
{
int lcx = chunk.LocalX;
int lcz = chunk.LocalZ;
ChunkKey k = new ChunkKey(lcx, lcz);
if (_dirty.ContainsKey(k)) {
_dirty.Remove(k);
return true;
}
return false;
}
#endregion
}
}

View file

@ -0,0 +1,131 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
namespace NBToolkit.Map
{
public class RegionList : IEnumerable<Region>
{
private List<Region> _regions;
public RegionList (List<Region> regs)
{
_regions = regs;
}
public RegionList (RegionManager rm)
{
_regions = new List<Region>();
if (!Directory.Exists(rm.GetRegionPath())) {
throw new DirectoryNotFoundException();
}
string[] files = Directory.GetFiles(rm.GetRegionPath());
_regions.Capacity = files.Length;
foreach (string file in files) {
try {
Region r = rm.GetRegion(file);
_regions.Add(r);
}
catch (ArgumentException) {
continue;
}
}
}
IEnumerator IEnumerable.GetEnumerator () {
return (IEnumerator)GetEnumerator();
}
IEnumerator<Region> IEnumerable<Region>.GetEnumerator ()
{
return (IEnumerator<Region>)GetEnumerator();
}
public RegionEnumerator GetEnumerator ()
{
return new RegionEnumerator(_regions);
}
}
public class RegionEnumerator : IEnumerator<Region>
{
protected List<Region> _regions;
protected int _pos = -1;
public RegionEnumerator (List<Region> regs)
{
_regions = regs;
}
public RegionEnumerator (RegionManager rm)
{
_regions = new List<Region>();
if (!Directory.Exists(rm.GetRegionPath())) {
throw new DirectoryNotFoundException();
}
string[] files = Directory.GetFiles(rm.GetRegionPath());
_regions.Capacity = files.Length;
foreach (string file in files) {
try {
Region r = rm.GetRegion(file);
_regions.Add(r);
}
catch (ArgumentException) {
continue;
}
}
}
public bool MoveNext ()
{
_pos++;
return (_pos < _regions.Count);
}
public void Reset ()
{
_pos = -1;
}
void IDisposable.Dispose () { }
object IEnumerator.Current
{
get
{
return Current;
}
}
Region IEnumerator<Region>.Current
{
get
{
return Current;
}
}
public Region Current
{
get
{
try {
return _regions[_pos];
}
catch (IndexOutOfRangeException) {
throw new InvalidOperationException();
}
}
}
}
}

View file

@ -0,0 +1,442 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Ionic.Zlib;
using System.Collections;
namespace NBToolkit.Map
{
public class RegionFile : IDisposable {
private const int VERSION_GZIP = 1;
private const int VERSION_DEFLATE = 2;
private const int SECTOR_BYTES = 4096;
private const int SECTOR_INTS = SECTOR_BYTES / 4;
const int CHUNK_HEADER_SIZE = 5;
private static byte[] emptySector = new byte[4096];
private string fileName;
private FileStream file;
private int[] offsets;
private int[] chunkTimestamps;
private List<Boolean> sectorFree;
private int sizeDelta;
private long lastModified = 0;
protected bool _disposed = false;
public RegionFile(string path) {
offsets = new int[SECTOR_INTS];
chunkTimestamps = new int[SECTOR_INTS];
fileName = path;
Debugln("REGION LOAD " + fileName);
sizeDelta = 0;
ReadFile();
}
~RegionFile ()
{
Dispose(false);
}
public void Dispose ()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
protected virtual void Dispose (bool disposing)
{
if (!_disposed) {
if (disposing) {
// Cleanup managed resources
}
// Cleanup unmanaged resources
if (file != null) {
file.Close();
file = null;
}
}
_disposed = true;
}
protected void ReadFile ()
{
// Get last udpate time
long newModified = 0;
try {
if (File.Exists(fileName)) {
newModified = Timestamp(File.GetLastWriteTime(fileName));
}
}
catch (UnauthorizedAccessException e) {
Console.WriteLine(e.Message);
return;
}
// If it hasn't been modified, we don't need to do anything
if (newModified == lastModified) {
return;
}
try {
file = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
//using (file) {
if (file.Length < SECTOR_BYTES) {
byte[] int0 = BitConverter.GetBytes((int)0);
/* we need to write the chunk offset table */
for (int i = 0; i < SECTOR_INTS; ++i) {
file.Write(int0, 0, 4);
}
// write another sector for the timestamp info
for (int i = 0; i < SECTOR_INTS; ++i) {
file.Write(int0, 0, 4);
}
sizeDelta += SECTOR_BYTES * 2;
}
if ((file.Length & 0xfff) != 0) {
/* the file size is not a multiple of 4KB, grow it */
for (int i = 0; i < (file.Length & 0xfff); ++i) {
file.WriteByte(0);
}
}
/* set up the available sector map */
int nSectors = (int)file.Length / SECTOR_BYTES;
sectorFree = new List<Boolean>(nSectors);
for (int i = 0; i < nSectors; ++i) {
sectorFree.Add(true);
}
sectorFree[0] = false; // chunk offset table
sectorFree[1] = false; // for the last modified info
file.Seek(0, SeekOrigin.Begin);
for (int i = 0; i < SECTOR_INTS; ++i) {
byte[] offsetBytes = new byte[4];
file.Read(offsetBytes, 0, 4);
if (BitConverter.IsLittleEndian) {
Array.Reverse(offsetBytes);
}
int offset = BitConverter.ToInt32(offsetBytes, 0);
offsets[i] = offset;
if (offset != 0 && (offset >> 8) + (offset & 0xFF) <= sectorFree.Count) {
for (int sectorNum = 0; sectorNum < (offset & 0xFF); ++sectorNum) {
sectorFree[(offset >> 8) + sectorNum] = false;
}
}
}
for (int i = 0; i < SECTOR_INTS; ++i) {
byte[] modBytes = new byte[4];
file.Read(modBytes, 0, 4);
if (BitConverter.IsLittleEndian) {
Array.Reverse(modBytes);
}
int lastModValue = BitConverter.ToInt32(modBytes, 0);
chunkTimestamps[i] = lastModValue;
}
//}
}
catch (IOException e) {
System.Console.WriteLine(e.Message);
System.Console.WriteLine(e.StackTrace);
}
}
/* the modification date of the region file when it was first opened */
public long LastModified() {
return lastModified;
}
/* gets how much the region file has grown since it was last checked */
public int GetSizeDelta() {
int ret = sizeDelta;
sizeDelta = 0;
return ret;
}
// various small debug printing helpers
private void Debug(String str) {
// System.Consle.Write(str);
}
private void Debugln(String str) {
Debug(str + "\n");
}
private void Debug(String mode, int x, int z, String str) {
Debug("REGION " + mode + " " + fileName + "[" + x + "," + z + "] = " + str);
}
private void Debug(String mode, int x, int z, int count, String str) {
Debug("REGION " + mode + " " + fileName + "[" + x + "," + z + "] " + count + "B = " + str);
}
private void Debugln(String mode, int x, int z, String str) {
Debug(mode, x, z, str + "\n");
}
/*
* gets an (uncompressed) stream representing the chunk data returns null if
* the chunk is not found or an error occurs
*/
public Stream GetChunkDataInputStream(int x, int z) {
if (OutOfBounds(x, z)) {
Debugln("READ", x, z, "out of bounds");
return null;
}
try {
int offset = GetOffset(x, z);
if (offset == 0) {
// Debugln("READ", x, z, "miss");
return null;
}
int sectorNumber = offset >> 8;
int numSectors = offset & 0xFF;
if (sectorNumber + numSectors > sectorFree.Count) {
Debugln("READ", x, z, "invalid sector");
return null;
}
file.Seek(sectorNumber * SECTOR_BYTES, SeekOrigin.Begin);
byte[] lengthBytes = new byte[4];
file.Read(lengthBytes, 0, 4);
if (BitConverter.IsLittleEndian) {
Array.Reverse(lengthBytes);
}
int length = BitConverter.ToInt32(lengthBytes, 0);
if (length > SECTOR_BYTES * numSectors) {
Debugln("READ", x, z, "invalid length: " + length + " > 4096 * " + numSectors);
return null;
}
byte version = (byte)file.ReadByte();
if (version == VERSION_GZIP) {
byte[] data = new byte[length - 1];
file.Read(data, 0, data.Length);
Stream ret = new GZipStream(new MemoryStream(data), CompressionMode.Decompress);
// Debug("READ", x, z, " = found");
return ret;
} else if (version == VERSION_DEFLATE) {
byte[] data = new byte[length - 1];
file.Read(data, 0, data.Length);
Stream ret = new ZlibStream(new MemoryStream(data), CompressionMode.Decompress, true);
// Debug("READ", x, z, " = found");
return ret;
}
Debugln("READ", x, z, "unknown version " + version);
return null;
} catch (IOException) {
Debugln("READ", x, z, "exception");
return null;
}
}
public Stream GetChunkDataOutputStream(int x, int z) {
if (OutOfBounds(x, z)) return null;
return new ZlibStream(new ChunkBuffer(this, x, z), CompressionMode.Compress);
}
/*
* lets chunk writing be multithreaded by not locking the whole file as a
* chunk is serializing -- only writes when serialization is over
*/
class ChunkBuffer : MemoryStream {
private int x, z;
private RegionFile region;
public ChunkBuffer(RegionFile r, int x, int z) : base(8096) {
// super(8096); // initialize to 8KB
this.region = r;
this.x = x;
this.z = z;
}
public override void Close() {
region.Write(x, z, this.GetBuffer(), (int)this.Length);
}
}
/* write a chunk at (x,z) with length bytes of data to disk */
protected void Write(int x, int z, byte[] data, int length) {
try {
int offset = GetOffset(x, z);
int sectorNumber = offset >> 8;
int sectorsAllocated = offset & 0xFF;
int sectorsNeeded = (length + CHUNK_HEADER_SIZE) / SECTOR_BYTES + 1;
// maximum chunk size is 1MB
if (sectorsNeeded >= 256) {
return;
}
if (sectorNumber != 0 && sectorsAllocated == sectorsNeeded) {
/* we can simply overwrite the old sectors */
Debug("SAVE", x, z, length, "rewrite");
Write(sectorNumber, data, length);
} else {
/* we need to allocate new sectors */
/* mark the sectors previously used for this chunk as free */
for (int i = 0; i < sectorsAllocated; ++i) {
sectorFree[sectorNumber + i] = true;
}
/* scan for a free space large enough to store this chunk */
int runStart = sectorFree.FindIndex(b => b == true);
int runLength = 0;
if (runStart != -1) {
for (int i = runStart; i < sectorFree.Count; ++i) {
if (runLength != 0) {
if (sectorFree[i]) runLength++;
else runLength = 0;
} else if (sectorFree[i]) {
runStart = i;
runLength = 1;
}
if (runLength >= sectorsNeeded) {
break;
}
}
}
if (runLength >= sectorsNeeded) {
/* we found a free space large enough */
Debug("SAVE", x, z, length, "reuse");
sectorNumber = runStart;
SetOffset(x, z, (sectorNumber << 8) | sectorsNeeded);
for (int i = 0; i < sectorsNeeded; ++i) {
sectorFree[sectorNumber + i] = false;
}
Write(sectorNumber, data, length);
} else {
/*
* no free space large enough found -- we need to grow the
* file
*/
Debug("SAVE", x, z, length, "grow");
file.Seek(0, SeekOrigin.End);
sectorNumber = sectorFree.Count;
for (int i = 0; i < sectorsNeeded; ++i) {
file.Write(emptySector, 0, emptySector.Length);
sectorFree.Add(false);
}
sizeDelta += SECTOR_BYTES * sectorsNeeded;
Write(sectorNumber, data, length);
SetOffset(x, z, (sectorNumber << 8) | sectorsNeeded);
}
}
SetTimestamp(x, z, Timestamp());
} catch (IOException e) {
Console.WriteLine(e.StackTrace);
}
}
/* write a chunk data to the region file at specified sector number */
private void Write(int sectorNumber, byte[] data, int length) {
Debugln(" " + sectorNumber);
file.Seek(sectorNumber * SECTOR_BYTES, SeekOrigin.Begin);
byte[] bytes = BitConverter.GetBytes(length + 1);
if (BitConverter.IsLittleEndian) {;
Array.Reverse(bytes);
}
file.Write(bytes, 0, 4); // chunk length
file.WriteByte(VERSION_DEFLATE); // chunk version number
file.Write(data, 0, length); // chunk data
}
public void DeleteChunk (int x, int z)
{
int offset = GetOffset(x, z);
int sectorNumber = offset >> 8;
int sectorsAllocated = offset & 0xFF;
file.Seek(sectorNumber * SECTOR_BYTES, SeekOrigin.Begin);
for (int i = 0; i < sectorsAllocated; i++) {
file.Write(emptySector, 0, SECTOR_BYTES);
}
SetOffset(x, z, 0);
SetTimestamp(x, z, 0);
}
/* is this an invalid chunk coordinate? */
private bool OutOfBounds (int x, int z)
{
return x < 0 || x >= 32 || z < 0 || z >= 32;
}
private int GetOffset(int x, int z) {
return offsets[x + z * 32];
}
public bool HasChunk(int x, int z) {
return GetOffset(x, z) != 0;
}
private void SetOffset(int x, int z, int offset) {
offsets[x + z * 32] = offset;
file.Seek((x + z * 32) * 4, SeekOrigin.Begin);
byte[] bytes = BitConverter.GetBytes(offset);
if (BitConverter.IsLittleEndian) {;
Array.Reverse(bytes);
}
file.Write(bytes, 0, 4);
}
private int Timestamp () {
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);
return (int)((DateTime.UtcNow - epoch).Ticks / (10000L * 1000L));
}
private int Timestamp (DateTime time)
{
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);
return (int)((time - epoch).Ticks / (10000L * 1000L));
}
private void SetTimestamp(int x, int z, int value) {
chunkTimestamps[x + z * 32] = value;
file.Seek(SECTOR_BYTES + (x + z * 32) * 4, SeekOrigin.Begin);
byte[] bytes = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian) {;
Array.Reverse(bytes);
}
file.Write(bytes, 0, 4);
}
public void Close() {
file.Close();
}
}
}

View file

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
public struct RegionKey : IEquatable<RegionKey>
{
readonly int rx;
readonly int rz;
public RegionKey (int _rx, int _rz)
{
rx = _rx;
rz = _rz;
}
public bool Equals (RegionKey ck)
{
return this.rx == ck.rx && this.rz == ck.rz;
}
public override bool Equals (Object o)
{
try {
return this == (RegionKey)o;
}
catch {
return false;
}
}
public override int GetHashCode ()
{
int hash = 23;
hash = hash * 37 + rx;
hash = hash * 37 + rz;
return hash;
}
public static bool operator == (RegionKey k1, RegionKey k2)
{
return k1.rx == k2.rx && k1.rz == k2.rz;
}
public static bool operator != (RegionKey k1, RegionKey k2)
{
return k1.rx != k2.rx || k1.rz != k2.rz;
}
}
}

View file

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace NBToolkit.Map
{
public class RegionManager
{
protected string _regionPath;
protected Dictionary<RegionKey, Region> _cache;
public RegionManager (string regionDir)
{
_regionPath = regionDir;
_cache = new Dictionary<RegionKey, Region>();
}
public Region GetRegion (int rx, int rz)
{
RegionKey k = new RegionKey(rx, rz);
Region r;
try {
if (_cache.TryGetValue(k, out r) == false) {
r = new Region(this, rx, rz);
_cache.Add(k, r);
}
return r;
}
catch (FileNotFoundException) {
_cache.Add(k, null);
return null;
}
}
public Region GetRegion (string filename)
{
int rx, rz;
if (!Region.ParseFileName(filename, out rx, out rz)) {
throw new ArgumentException("Malformed region file name: " + filename, "filename");
}
return GetRegion(rx, rz);
}
public string GetRegionPath ()
{
return _regionPath;
}
public bool DeleteRegion (int rx, int rz)
{
Region r = GetRegion(rx, rz);
if (r == null) {
return false;
}
RegionKey k = new RegionKey(rx, rz);
_cache.Remove(k);
r.Dispose();
try {
File.Delete(r.GetFilePath());
}
catch (Exception e) {
Console.WriteLine("NOTICE: " + e.Message);
return false;
}
return true;
}
}
}

View file

@ -0,0 +1,631 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map
{
using NBT;
using Utility;
public class TileEntity : INBTObject<TileEntity>, ICopyable<TileEntity>
{
public static readonly NBTCompoundNode BaseSchema = new NBTCompoundNode("")
{
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),
};
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, 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"),
new NBTScalerNode("Text1", NBT_Type.TAG_STRING),
new NBTScalerNode("Text2", NBT_Type.TAG_STRING),
new NBTScalerNode("Text3", NBT_Type.TAG_STRING),
new NBTScalerNode("Text4", NBT_Type.TAG_STRING),
});
private string _text1 = "";
private string _text2 = "";
private string _text3 = "";
private string _text4 = "";
public string Text1
{
get { return _text1; }
set { _text1 = value.Substring(0, 12); }
}
public string Text2
{
get { return _text2; }
set { _text2 = value.Substring(0, 12); }
}
public string Text3
{
get { return _text3; }
set { _text3 = value.Substring(0, 12); }
}
public string Text4
{
get { return _text4; }
set { _text4 = value.Substring(0, 12); }
}
public TileEntitySign ()
: base("Sign")
{
}
public TileEntitySign (TileEntity te)
: base(te)
{
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(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
}
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 _delay; }
set { _delay = (short)value; }
}
public string EntityID
{
get { return _entityID; }
set { _entityID = value; }
}
public TileEntityMobSpawner ()
: base("MobSpawner")
{
}
public TileEntityMobSpawner (TileEntity te)
: base(te)
{
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(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
}
public class TileEntityChest : TileEntity, IItemContainer
{
public static readonly NBTCompoundNode ChestSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Chest"),
new NBTListNode("Items", NBT_Type.TAG_COMPOUND, ItemCollection.ListSchema),
});
private const int _CAPACITY = 27;
private ItemCollection _items;
public TileEntityChest ()
: base("Chest")
{
_items = new ItemCollection(_CAPACITY);
}
public TileEntityChest (TileEntity te)
: base(te)
{
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(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;
}
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 _note; }
set { _note = (byte)value; }
}
public TileEntityMusic ()
: base("Music")
{
}
public TileEntityMusic (TileEntity te)
: base(te)
{
TileEntityMusic tes = te as TileEntityMusic;
if (tes != null) {
_note = tes._note;
}
}
#region ICopyable<TileEntity> Members
public override TileEntity Copy ()
{
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
}
public class TileEntityTrap : TileEntity, IItemContainer
{
public static readonly NBTCompoundNode TrapSchema = BaseSchema.MergeInto(new NBTCompoundNode("")
{
new NBTStringNode("id", "Trap"),
new NBTListNode("Items", NBT_Type.TAG_COMPOUND, ItemCollection.ListSchema),
});
private const int _CAPACITY = 8;
private ItemCollection _items;
public TileEntityTrap ()
: base("Trap")
{
_items = new ItemCollection(_CAPACITY);
}
public TileEntityTrap (TileEntity te)
: base(te)
{
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(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;
}
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

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map.Utility
{
public interface ICopyable <T>
{
T Copy ();
}
}

View file

@ -0,0 +1,62 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace NBToolkit.Map.Utility
{
public class NibbleArray : ICopyable<NibbleArray>
{
protected readonly byte[] _data = null;
public NibbleArray (byte[] data)
{
_data = data;
}
public int this[int index]
{
get
{
int subs = index >> 1;
if ((index & 1) == 0) {
return _data[subs] & 0x0F;
}
else {
return (_data[subs] >> 4) & 0x0F;
}
}
set
{
int subs = index >> 1;
if ((index & 1) == 0) {
_data[subs] = (byte)((_data[subs] & 0xF0) | (value & 0x0F));
}
else {
_data[subs] = (byte)((_data[subs] & 0x0F) | ((value & 0x0F) << 4));
}
}
}
public int Length
{
get
{
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
}
}

View file

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace NBToolkit.Map
{
public class World
{
protected RegionManager _regionMan;
protected ChunkManager _chunkMan;
protected BlockManager _blockMan;
protected string _worldPath;
public World (string world)
{
_worldPath = world;
_regionMan = new RegionManager(Path.Combine(world, "region"));
_chunkMan = new ChunkManager(_regionMan);
_blockMan = new BlockManager(_chunkMan);
}
public RegionManager GetRegionManager ()
{
return _regionMan;
}
public ChunkManager GetChunkManager ()
{
return _chunkMan;
}
public BlockManager GetBlockManager ()
{
return _blockMan;
}
}
}