2014-12-27 12:34:55 -07:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using fNbt;
|
|
|
|
using fNbt.Serialization;
|
|
|
|
using TrueCraft.API.World;
|
|
|
|
using TrueCraft.API;
|
2015-03-01 00:24:29 -05:00
|
|
|
using TrueCraft.Core.Logic.Blocks;
|
2014-12-27 12:34:55 -07:00
|
|
|
|
|
|
|
namespace TrueCraft.Core.World
|
|
|
|
{
|
|
|
|
public class Chunk : INbtSerializable, IChunk
|
|
|
|
{
|
2014-12-27 18:19:42 -07:00
|
|
|
public const int Width = 16, Height = 128, Depth = 16;
|
2014-12-27 12:34:55 -07:00
|
|
|
|
|
|
|
private static readonly NbtSerializer Serializer = new NbtSerializer(typeof(Chunk));
|
|
|
|
|
|
|
|
[NbtIgnore]
|
|
|
|
public DateTime LastAccessed { get; set; }
|
2014-12-27 18:19:42 -07:00
|
|
|
[NbtIgnore]
|
2014-12-27 12:34:55 -07:00
|
|
|
public bool IsModified { get; set; }
|
2014-12-27 18:19:42 -07:00
|
|
|
[NbtIgnore]
|
|
|
|
public byte[] Blocks { get; set; }
|
|
|
|
[NbtIgnore]
|
|
|
|
public NibbleArray Metadata { get; set; }
|
|
|
|
[NbtIgnore]
|
|
|
|
public NibbleArray BlockLight { get; set; }
|
|
|
|
[NbtIgnore]
|
|
|
|
public NibbleArray SkyLight { get; set; }
|
2014-12-27 12:34:55 -07:00
|
|
|
public byte[] Biomes { get; set; }
|
|
|
|
public int[] HeightMap { get; set; }
|
|
|
|
[TagName("xPos")]
|
|
|
|
public int X { get; set; }
|
|
|
|
[TagName("zPos")]
|
|
|
|
public int Z { get; set; }
|
2015-05-03 12:44:05 -06:00
|
|
|
public Dictionary<Coordinates3D, NbtCompound> TileEntities { get; set; }
|
2014-12-27 12:34:55 -07:00
|
|
|
|
|
|
|
public Coordinates2D Coordinates
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return new Coordinates2D(X, Z);
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
X = value.X;
|
|
|
|
Z = value.Z;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public long LastUpdate { get; set; }
|
|
|
|
|
|
|
|
public bool TerrainPopulated { get; set; }
|
|
|
|
|
|
|
|
[NbtIgnore]
|
|
|
|
public Region ParentRegion { get; set; }
|
|
|
|
|
|
|
|
public Chunk()
|
|
|
|
{
|
|
|
|
TerrainPopulated = true;
|
|
|
|
Biomes = new byte[Width * Depth];
|
|
|
|
HeightMap = new int[Width * Depth];
|
|
|
|
LastAccessed = DateTime.Now;
|
2015-05-03 12:44:05 -06:00
|
|
|
TileEntities = new Dictionary<Coordinates3D, NbtCompound>();
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public Chunk(Coordinates2D coordinates) : this()
|
|
|
|
{
|
|
|
|
X = coordinates.X;
|
|
|
|
Z = coordinates.Z;
|
2014-12-27 18:19:42 -07:00
|
|
|
const int size = Width * Height * Depth;
|
|
|
|
Blocks = new byte[size];
|
|
|
|
Metadata = new NibbleArray(size);
|
|
|
|
BlockLight = new NibbleArray(size);
|
|
|
|
SkyLight = new NibbleArray(size);
|
|
|
|
for (int i = 0; i < size; i++)
|
|
|
|
SkyLight[i] = 0xFF;
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
|
|
|
|
2014-12-27 12:51:45 -07:00
|
|
|
public byte GetBlockID(Coordinates3D coordinates)
|
2014-12-27 12:34:55 -07:00
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
2014-12-27 18:19:42 -07:00
|
|
|
int index = coordinates.Y + (coordinates.Z * Height) + (coordinates.X * Height * Width);
|
|
|
|
return Blocks[index];
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public byte GetMetadata(Coordinates3D coordinates)
|
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
2014-12-27 18:19:42 -07:00
|
|
|
int index = coordinates.Y + (coordinates.Z * Height) + (coordinates.X * Height * Width);
|
|
|
|
return Metadata[index];
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public byte GetSkyLight(Coordinates3D coordinates)
|
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
2014-12-27 18:19:42 -07:00
|
|
|
int index = coordinates.Y + (coordinates.Z * Height) + (coordinates.X * Height * Width);
|
|
|
|
return SkyLight[index];
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public byte GetBlockLight(Coordinates3D coordinates)
|
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
2014-12-27 18:19:42 -07:00
|
|
|
int index = coordinates.Y + (coordinates.Z * Height) + (coordinates.X * Height * Width);
|
|
|
|
return BlockLight[index];
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
|
|
|
|
2014-12-28 11:17:14 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Sets the block ID at specific coordinates relative to this chunk.
|
|
|
|
/// Warning: The parent world's BlockChanged event handler does not get called.
|
|
|
|
/// </summary>
|
2014-12-27 12:51:45 -07:00
|
|
|
public void SetBlockID(Coordinates3D coordinates, byte value)
|
2014-12-27 12:34:55 -07:00
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
|
|
|
IsModified = true;
|
2014-12-27 18:19:42 -07:00
|
|
|
int index = coordinates.Y + (coordinates.Z * Height) + (coordinates.X * Height * Width);
|
|
|
|
Blocks[index] = value;
|
2015-03-01 00:24:29 -05:00
|
|
|
if (value == AirBlock.BlockID)
|
|
|
|
Metadata[index] = 0x0;
|
2014-12-27 12:34:55 -07:00
|
|
|
var oldHeight = GetHeight((byte)coordinates.X, (byte)coordinates.Z);
|
2015-03-01 00:24:29 -05:00
|
|
|
if (value == AirBlock.BlockID)
|
2014-12-27 12:34:55 -07:00
|
|
|
{
|
|
|
|
if (oldHeight <= coordinates.Y)
|
|
|
|
{
|
|
|
|
// Shift height downwards
|
|
|
|
while (coordinates.Y > 0)
|
|
|
|
{
|
|
|
|
coordinates.Y--;
|
|
|
|
if (GetBlockID(coordinates) != 0)
|
|
|
|
SetHeight((byte)coordinates.X, (byte)coordinates.Z, coordinates.Y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (oldHeight < coordinates.Y)
|
|
|
|
SetHeight((byte)coordinates.X, (byte)coordinates.Z, coordinates.Y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-28 11:17:14 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Sets the metadata at specific coordinates relative to this chunk.
|
|
|
|
/// Warning: The parent world's BlockChanged event handler does not get called.
|
|
|
|
/// </summary>
|
2014-12-27 12:34:55 -07:00
|
|
|
public void SetMetadata(Coordinates3D coordinates, byte value)
|
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
|
|
|
IsModified = true;
|
2014-12-27 18:19:42 -07:00
|
|
|
int index = coordinates.Y + (coordinates.Z * Height) + (coordinates.X * Height * Width);
|
|
|
|
Metadata[index] = value;
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
|
|
|
|
2014-12-28 11:17:14 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Sets the sky light at specific coordinates relative to this chunk.
|
|
|
|
/// Warning: The parent world's BlockChanged event handler does not get called.
|
|
|
|
/// </summary>
|
2014-12-27 12:34:55 -07:00
|
|
|
public void SetSkyLight(Coordinates3D coordinates, byte value)
|
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
|
|
|
IsModified = true;
|
2014-12-27 18:19:42 -07:00
|
|
|
int index = coordinates.Y + (coordinates.Z * Height) + (coordinates.X * Height * Width);
|
|
|
|
SkyLight[index] = value;
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
|
|
|
|
2014-12-28 11:17:14 -07:00
|
|
|
/// <summary>
|
|
|
|
/// Sets the block light at specific coordinates relative to this chunk.
|
|
|
|
/// Warning: The parent world's BlockChanged event handler does not get called.
|
|
|
|
/// </summary>
|
2014-12-27 12:34:55 -07:00
|
|
|
public void SetBlockLight(Coordinates3D coordinates, byte value)
|
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
|
|
|
IsModified = true;
|
2014-12-27 18:19:42 -07:00
|
|
|
int index = coordinates.Y + (coordinates.Z * Height) + (coordinates.X * Height * Width);
|
|
|
|
BlockLight[index] = value;
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
2015-05-03 12:44:05 -06:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the tile entity for the given coordinates. May return null.
|
|
|
|
/// </summary>
|
|
|
|
public NbtCompound GetTileEntity(Coordinates3D coordinates)
|
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
|
|
|
if (TileEntities.ContainsKey(coordinates))
|
|
|
|
return TileEntities[coordinates];
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Sets the tile entity at the given coordinates to the given value.
|
|
|
|
/// </summary>
|
|
|
|
public void SetTileEntity(Coordinates3D coordinates, NbtCompound value)
|
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
|
|
|
TileEntities[coordinates] = value;
|
|
|
|
IsModified = true;
|
|
|
|
}
|
2014-12-27 12:34:55 -07:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the height of the specified column.
|
|
|
|
/// </summary>
|
|
|
|
public int GetHeight(byte x, byte z)
|
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
2015-01-26 00:38:58 -05:00
|
|
|
return HeightMap[(byte)(x * Width) + z];
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private void SetHeight(byte x, byte z, int value)
|
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
|
|
|
IsModified = true;
|
2015-01-26 00:38:58 -05:00
|
|
|
HeightMap[(byte)(x * Width) + z] = value;
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public NbtFile ToNbt()
|
|
|
|
{
|
|
|
|
LastAccessed = DateTime.Now;
|
|
|
|
var serializer = new NbtSerializer(typeof(Chunk));
|
|
|
|
var compound = serializer.Serialize(this, "Level") as NbtCompound;
|
|
|
|
var file = new NbtFile();
|
|
|
|
file.RootTag.Add(compound);
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Chunk FromNbt(NbtFile nbt)
|
|
|
|
{
|
|
|
|
var serializer = new NbtSerializer(typeof(Chunk));
|
|
|
|
var chunk = (Chunk)serializer.Deserialize(nbt.RootTag["Level"]);
|
|
|
|
return chunk;
|
|
|
|
}
|
|
|
|
|
|
|
|
public NbtTag Serialize(string tagName)
|
|
|
|
{
|
2015-05-03 15:12:10 -06:00
|
|
|
var chunk = new NbtCompound(tagName);
|
2014-12-27 12:34:55 -07:00
|
|
|
var entities = new NbtList("Entities", NbtTagType.Compound);
|
|
|
|
chunk.Add(entities);
|
2015-05-03 15:12:10 -06:00
|
|
|
chunk.Add(new NbtInt("X", X));
|
|
|
|
chunk.Add(new NbtInt("Z", Z));
|
2015-02-02 15:52:25 -07:00
|
|
|
chunk.Add(new NbtByteArray("Blocks", Blocks));
|
|
|
|
chunk.Add(new NbtByteArray("Data", Metadata.Data));
|
|
|
|
chunk.Add(new NbtByteArray("SkyLight", SkyLight.Data));
|
|
|
|
chunk.Add(new NbtByteArray("BlockLight", BlockLight.Data));
|
2015-05-03 12:44:05 -06:00
|
|
|
|
|
|
|
var tiles = new NbtList("TileEntities", NbtTagType.Compound);
|
|
|
|
foreach (var kvp in TileEntities)
|
|
|
|
{
|
|
|
|
var c = new NbtCompound();
|
|
|
|
c.Add(new NbtList("coordinates", new[] {
|
|
|
|
new NbtInt(kvp.Key.X),
|
|
|
|
new NbtInt(kvp.Key.Y),
|
|
|
|
new NbtInt(kvp.Key.Z)
|
|
|
|
}));
|
|
|
|
c.Add(new NbtList("value", new[] { kvp.Value }));
|
|
|
|
tiles.Add(c);
|
|
|
|
}
|
|
|
|
chunk.Add(tiles);
|
|
|
|
|
|
|
|
// TODO: Entities
|
2014-12-27 12:34:55 -07:00
|
|
|
return chunk;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Deserialize(NbtTag value)
|
|
|
|
{
|
2015-05-03 15:12:10 -06:00
|
|
|
var chunk = new Chunk();
|
2015-02-02 15:52:25 -07:00
|
|
|
var tag = (NbtCompound)value;
|
|
|
|
|
|
|
|
Biomes = chunk.Biomes;
|
|
|
|
HeightMap = chunk.HeightMap;
|
|
|
|
LastUpdate = chunk.LastUpdate;
|
|
|
|
TerrainPopulated = chunk.TerrainPopulated;
|
|
|
|
X = tag["xPos"].IntValue;
|
|
|
|
Z = tag["zPos"].IntValue;
|
|
|
|
Blocks = tag["Blocks"].ByteArrayValue;
|
|
|
|
Metadata = new NibbleArray();
|
|
|
|
Metadata.Data = tag["Data"].ByteArrayValue;
|
|
|
|
BlockLight = new NibbleArray();
|
|
|
|
BlockLight.Data = tag["BlockLight"].ByteArrayValue;
|
|
|
|
SkyLight = new NibbleArray();
|
|
|
|
SkyLight.Data = tag["SkyLight"].ByteArrayValue;
|
2015-05-03 12:44:05 -06:00
|
|
|
|
|
|
|
if (tag.Contains("TileEntities"))
|
|
|
|
{
|
|
|
|
foreach (var entity in tag["TileEntities"] as NbtList)
|
|
|
|
{
|
|
|
|
TileEntities[new Coordinates3D(entity["coordinates"][0].IntValue,
|
|
|
|
entity["coordinates"][1].IntValue,
|
|
|
|
entity["coordinates"][2].IntValue)] = entity["value"][0] as NbtCompound;
|
|
|
|
}
|
|
|
|
}
|
2015-02-02 15:52:25 -07:00
|
|
|
|
|
|
|
// TODO: Tile entities, entities
|
2014-12-27 12:34:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|