forked from mirrors/NBTExplorer
Early fluid recalculation support (for water)
This commit is contained in:
parent
da05301983
commit
ff0140d60d
9 changed files with 371 additions and 7 deletions
|
@ -57,6 +57,7 @@ namespace Substrate
|
||||||
private TagList _tileEntities;
|
private TagList _tileEntities;
|
||||||
|
|
||||||
private BlockLight _lightManager;
|
private BlockLight _lightManager;
|
||||||
|
private BlockFluid _fluidManager;
|
||||||
private BlockTileEntities _tileEntityManager;
|
private BlockTileEntities _tileEntityManager;
|
||||||
|
|
||||||
private bool _dirty = false;
|
private bool _dirty = false;
|
||||||
|
@ -71,11 +72,16 @@ namespace Substrate
|
||||||
_lightManager.ResolveNeighbor += delegate(int relx, int rely, int relz) {
|
_lightManager.ResolveNeighbor += delegate(int relx, int rely, int relz) {
|
||||||
return value(relx, rely, relz);
|
return value(relx, rely, relz);
|
||||||
};
|
};
|
||||||
|
_fluidManager.ResolveNeighbor += delegate(int relx, int rely, int relz)
|
||||||
|
{
|
||||||
|
return value(relx, rely, relz);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
remove
|
remove
|
||||||
{
|
{
|
||||||
_lightManager = new BlockLight(this);
|
_lightManager = new BlockLight(this);
|
||||||
|
_fluidManager = new BlockFluid(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +113,7 @@ namespace Substrate
|
||||||
_tileEntities = properties.tileEntities;
|
_tileEntities = properties.tileEntities;
|
||||||
|
|
||||||
_lightManager = new BlockLight(this);
|
_lightManager = new BlockLight(this);
|
||||||
|
_fluidManager = new BlockFluid(this);
|
||||||
_tileEntityManager = new BlockTileEntities(_blocks, _tileEntities);
|
_tileEntityManager = new BlockTileEntities(_blocks, _tileEntities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,6 +459,16 @@ namespace Substrate
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public void ResetBlockFluid ()
|
||||||
|
{
|
||||||
|
_fluidManager.ResetWater();
|
||||||
|
_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RebuildBlockFluid ()
|
||||||
|
{
|
||||||
|
_fluidManager.RebuildWater();
|
||||||
|
_dirty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
321
Substrate/SubstrateCS/Source/BlockFluid.cs
Normal file
321
Substrate/SubstrateCS/Source/BlockFluid.cs
Normal file
|
@ -0,0 +1,321 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Substrate
|
||||||
|
{
|
||||||
|
using Utility;
|
||||||
|
|
||||||
|
public class BlockFluid
|
||||||
|
{
|
||||||
|
private IBoundedDataBlockCollection _blockset;
|
||||||
|
|
||||||
|
private readonly int _xdim;
|
||||||
|
private readonly int _ydim;
|
||||||
|
private readonly int _zdim;
|
||||||
|
|
||||||
|
private Dictionary<ChunkKey, IBoundedDataBlockCollection> _chunks;
|
||||||
|
|
||||||
|
public delegate IBoundedDataBlockCollection NeighborLookupHandler (int relx, int rely, int relz);
|
||||||
|
|
||||||
|
public event NeighborLookupHandler ResolveNeighbor;
|
||||||
|
|
||||||
|
internal class BlockCoord
|
||||||
|
{
|
||||||
|
internal IBoundedDataBlockCollection chunk;
|
||||||
|
internal int lx;
|
||||||
|
internal int ly;
|
||||||
|
internal int lz;
|
||||||
|
|
||||||
|
internal BlockCoord (IBoundedDataBlockCollection _chunk, int _lx, int _ly, int _lz)
|
||||||
|
{
|
||||||
|
chunk = _chunk;
|
||||||
|
lx = _lx;
|
||||||
|
ly = _ly;
|
||||||
|
lz = _lz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockFluid (IBoundedDataBlockCollection blockset)
|
||||||
|
{
|
||||||
|
_blockset = blockset;
|
||||||
|
|
||||||
|
_xdim = _blockset.XDim;
|
||||||
|
_ydim = _blockset.YDim;
|
||||||
|
_zdim = _blockset.ZDim;
|
||||||
|
|
||||||
|
_chunks = new Dictionary<ChunkKey,IBoundedDataBlockCollection>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockFluid (BlockFluid bl)
|
||||||
|
{
|
||||||
|
_blockset = bl._blockset;
|
||||||
|
|
||||||
|
_xdim = bl._xdim;
|
||||||
|
_ydim = bl._ydim;
|
||||||
|
_zdim = bl._zdim;
|
||||||
|
|
||||||
|
_chunks = new Dictionary<ChunkKey, IBoundedDataBlockCollection>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetWater ()
|
||||||
|
{
|
||||||
|
int xdim = _xdim;
|
||||||
|
int ydim = _ydim;
|
||||||
|
int zdim = _zdim;
|
||||||
|
|
||||||
|
for (int x = 0; x < xdim; x++) {
|
||||||
|
for (int z = 0; z < zdim; z++) {
|
||||||
|
for (int y = 0; y < ydim; y++) {
|
||||||
|
IDataBlock block = _blockset.GetBlockRef(x, y, z);
|
||||||
|
if ((block.ID == BlockType.STATIONARY_WATER || block.ID == BlockType.WATER) && block.Data != (int)WaterFlow.FULL) {
|
||||||
|
block.ID = BlockType.AIR;
|
||||||
|
block.Data = 0;
|
||||||
|
}
|
||||||
|
else if (block.ID == BlockType.WATER) {
|
||||||
|
block.ID = BlockType.STATIONARY_WATER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RebuildWater ()
|
||||||
|
{
|
||||||
|
int xdim = _xdim;
|
||||||
|
int ydim = _ydim;
|
||||||
|
int zdim = _zdim;
|
||||||
|
|
||||||
|
List<BlockKey> buildQueue = new List<BlockKey>();
|
||||||
|
|
||||||
|
for (int x = 0; x < xdim; x++) {
|
||||||
|
for (int z = 0; z < zdim; z++) {
|
||||||
|
for (int y = 0; y < ydim; y++) {
|
||||||
|
BlockInfo info = _blockset.GetInfo(x, y, z);
|
||||||
|
if (info.ID == BlockType.STATIONARY_WATER && _blockset.GetData(x, y, z) == (int)WaterFlow.FULL) {
|
||||||
|
buildQueue.Add(new BlockKey(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (BlockKey key in buildQueue) {
|
||||||
|
SpreadWater(key.x, key.y, key.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SpreadWater (int x, int y, int z)
|
||||||
|
{
|
||||||
|
Queue<KeyValuePair<BlockKey, int>> targets = new Queue<KeyValuePair<BlockKey, int>>();
|
||||||
|
targets.Enqueue(new KeyValuePair<BlockKey, int>(new BlockKey(x, y, z), 0));
|
||||||
|
|
||||||
|
while (targets.Count > 0) {
|
||||||
|
KeyValuePair<BlockKey, int> skey = targets.Dequeue();
|
||||||
|
|
||||||
|
BlockKey source = skey.Key;
|
||||||
|
int sourceDist = skey.Value;
|
||||||
|
|
||||||
|
int nearestDrop = 7;
|
||||||
|
bool foundDrop = false;
|
||||||
|
|
||||||
|
Queue<BlockKey> searchQueue = new Queue<BlockKey>();
|
||||||
|
Queue<KeyValuePair<BlockKey, int>> sinkQueue = new Queue<KeyValuePair<BlockKey, int>>();
|
||||||
|
Dictionary<BlockKey, int> marked = new Dictionary<BlockKey, int>();
|
||||||
|
|
||||||
|
searchQueue.Enqueue(source);
|
||||||
|
marked.Add(source, sourceDist);
|
||||||
|
|
||||||
|
// Identify sinks
|
||||||
|
while (searchQueue.Count > 0) {
|
||||||
|
BlockKey branch = searchQueue.Dequeue();
|
||||||
|
int distance = marked[branch] & ~(int)LiquidState.FALLING;
|
||||||
|
bool falling = (marked[branch] & (int)LiquidState.FALLING) > 0;
|
||||||
|
|
||||||
|
// Ignore blocks out of range
|
||||||
|
if (distance > nearestDrop) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore invalid blocks
|
||||||
|
BlockCoord branchHigh = TranslateCoord(branch.x, branch.y, branch.z);
|
||||||
|
if (branchHigh.chunk == null || branch.y == 0) {
|
||||||
|
marked.Remove(branch);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're not the magical source block...
|
||||||
|
if (distance > 0 && !falling) {
|
||||||
|
// Ignore blocks that block fluid (and thus could not become a fluid)
|
||||||
|
BlockInfo branchHighInfo = branchHigh.chunk.GetInfo(branchHigh.lx, branchHigh.ly, branchHigh.lz);
|
||||||
|
if (branchHighInfo.BlocksFluid) {
|
||||||
|
marked.Remove(branch);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore blocks that have a "fuller" fluid level
|
||||||
|
if (branchHighInfo.ID == BlockType.STATIONARY_WATER) {
|
||||||
|
int cmp = branchHigh.chunk.GetData(branchHigh.lx, branchHigh.ly, branchHigh.lz);
|
||||||
|
if (cmp <= distance || (cmp & (int)LiquidState.FALLING) > 0) {
|
||||||
|
marked.Remove(branch);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we found a hole, add as a sink, mark the sink distance.
|
||||||
|
BlockCoord branchLow = TranslateCoord(branch.x, branch.y - 1, branch.z);
|
||||||
|
BlockInfo branchLowInfo = branchLow.chunk.GetInfo(branchLow.lx, branchLow.ly, branchLow.lz);
|
||||||
|
if (!branchLowInfo.BlocksFluid) {
|
||||||
|
foundDrop = true;
|
||||||
|
nearestDrop = falling ? 0 : distance;
|
||||||
|
sinkQueue.Enqueue(new KeyValuePair<BlockKey, int>(branch, falling ? distance | (int)LiquidState.FALLING : distance));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Didn't find a hole, hit the bottom, reset distance
|
||||||
|
if (falling) {
|
||||||
|
distance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand to neighbors
|
||||||
|
if (distance < nearestDrop) {
|
||||||
|
BlockKey[] keys = {
|
||||||
|
new BlockKey(branch.x - 1, branch.y, branch.z),
|
||||||
|
new BlockKey(branch.x + 1, branch.y, branch.z),
|
||||||
|
new BlockKey(branch.x, branch.y, branch.z - 1),
|
||||||
|
new BlockKey(branch.x, branch.y, branch.z + 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (!marked.ContainsKey(keys[i])) {
|
||||||
|
searchQueue.Enqueue(keys[i]);
|
||||||
|
marked.Add(keys[i], distance + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't find any drops, fill out the mark table
|
||||||
|
if (!foundDrop) {
|
||||||
|
foreach (KeyValuePair<BlockKey, int> mark in marked) {
|
||||||
|
BlockKey target = mark.Key;
|
||||||
|
|
||||||
|
BlockCoord targetHigh = TranslateCoord(target.x, target.y, target.z);
|
||||||
|
targetHigh.chunk.SetID(targetHigh.lx, targetHigh.ly, targetHigh.lz, BlockType.STATIONARY_WATER);
|
||||||
|
targetHigh.chunk.SetData(targetHigh.lx, targetHigh.ly, targetHigh.lz, mark.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip sinks and tracing
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new target for each sink
|
||||||
|
Queue<KeyValuePair<BlockKey, int>> traceQueue = new Queue<KeyValuePair<BlockKey, int>>();
|
||||||
|
while (sinkQueue.Count > 0) {
|
||||||
|
KeyValuePair<BlockKey, int> tkey = sinkQueue.Dequeue();
|
||||||
|
BlockKey target = tkey.Key;
|
||||||
|
int distance = tkey.Value;
|
||||||
|
|
||||||
|
//int distance = marked[target];
|
||||||
|
marked.Remove(target);
|
||||||
|
|
||||||
|
targets.Enqueue(new KeyValuePair<BlockKey, int>(new BlockKey(target.x, target.y - 1, target.z), distance | (int)LiquidState.FALLING));
|
||||||
|
traceQueue.Enqueue(new KeyValuePair<BlockKey, int>(target, distance));
|
||||||
|
|
||||||
|
/*BlockCoord targetLow = TranslateCoord(target.x, target.y - 1, target.z);
|
||||||
|
targetLow.chunk.SetID(targetLow.lx, targetLow.ly, targetHigh.lz, BlockType.STATIONARY_WATER);
|
||||||
|
targetLow.chunk.SetData(targetLow.lx, targetLow.ly, targetHigh.lz, tkey.Value);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace back from sinks
|
||||||
|
while (traceQueue.Count > 0) {
|
||||||
|
KeyValuePair<BlockKey, int> tkey = traceQueue.Dequeue();
|
||||||
|
|
||||||
|
BlockKey target = tkey.Key;
|
||||||
|
int distance = tkey.Value & ~(int)LiquidState.FALLING;
|
||||||
|
bool falling = (tkey.Value & (int)LiquidState.FALLING) > 0;
|
||||||
|
|
||||||
|
//if (distance == 0) {
|
||||||
|
// distance |= (int)LiquidState.FALLING;
|
||||||
|
//}
|
||||||
|
|
||||||
|
BlockCoord targetHigh = TranslateCoord(target.x, target.y, target.z);
|
||||||
|
targetHigh.chunk.SetID(targetHigh.lx, targetHigh.ly, targetHigh.lz, BlockType.STATIONARY_WATER);
|
||||||
|
targetHigh.chunk.SetData(targetHigh.lx, targetHigh.ly, targetHigh.lz, tkey.Value);
|
||||||
|
|
||||||
|
if (falling) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockKey[] keys = {
|
||||||
|
new BlockKey(target.x - 1, target.y, target.z),
|
||||||
|
new BlockKey(target.x + 1, target.y, target.z),
|
||||||
|
new BlockKey(target.x, target.y, target.z - 1),
|
||||||
|
new BlockKey(target.x, target.y, target.z + 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int nval;
|
||||||
|
if (!marked.TryGetValue(keys[i], out nval)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ndist = nval & ~(int)LiquidState.FALLING;
|
||||||
|
bool nfall = (nval & (int)LiquidState.FALLING) > 0;
|
||||||
|
|
||||||
|
marked.Remove(keys[i]);
|
||||||
|
if (ndist < distance || nfall) {
|
||||||
|
traceQueue.Enqueue(new KeyValuePair<BlockKey, int>(keys[i], nval));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockCoord TranslateCoord (int x, int y, int z)
|
||||||
|
{
|
||||||
|
IBoundedDataBlockCollection chunk = GetChunk(x, z);
|
||||||
|
|
||||||
|
int lx = ((x % _xdim) + _xdim) % _xdim;
|
||||||
|
int lz = ((z % _zdim) + _zdim) % _zdim;
|
||||||
|
|
||||||
|
return new BlockCoord(chunk, lx, y, lz);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IBoundedDataBlockCollection GetChunk (int x, int z)
|
||||||
|
{
|
||||||
|
int cx = x / _xdim + (x >> 31);
|
||||||
|
int cz = z / _zdim + (z >> 31);
|
||||||
|
|
||||||
|
ChunkKey key = new ChunkKey(cx, cz);
|
||||||
|
|
||||||
|
IBoundedDataBlockCollection chunk;
|
||||||
|
if (!_chunks.TryGetValue(key, out chunk)) {
|
||||||
|
chunk = OnResolveNeighbor(cx, 0, cz);
|
||||||
|
_chunks[key] = chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IBoundedDataBlockCollection OnResolveNeighbor (int relX, int relY, int relZ)
|
||||||
|
{
|
||||||
|
if (ResolveNeighbor != null) {
|
||||||
|
IBoundedDataBlockCollection n = ResolveNeighbor(relX, relY, relZ);
|
||||||
|
|
||||||
|
if (n == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.XDim != _xdim ||
|
||||||
|
n.YDim != _ydim ||
|
||||||
|
n.ZDim != _zdim) {
|
||||||
|
throw new InvalidOperationException("Subscriber returned incompatible IDataBlockCollection");
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -178,6 +178,7 @@ namespace Substrate
|
||||||
private int _opacity = MAX_OPACITY;
|
private int _opacity = MAX_OPACITY;
|
||||||
private int _luminance = MIN_LUMINANCE;
|
private int _luminance = MIN_LUMINANCE;
|
||||||
private bool _transmitLight = false;
|
private bool _transmitLight = false;
|
||||||
|
private bool _blocksFluid = true;
|
||||||
|
|
||||||
private BlockState _state = BlockState.SOLID;
|
private BlockState _state = BlockState.SOLID;
|
||||||
|
|
||||||
|
@ -221,6 +222,11 @@ namespace Substrate
|
||||||
get { return _opacity > MIN_OPACITY || !_transmitLight; }
|
get { return _opacity > MIN_OPACITY || !_transmitLight; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool BlocksFluid
|
||||||
|
{
|
||||||
|
get { return _blocksFluid; }
|
||||||
|
}
|
||||||
|
|
||||||
public BlockState State
|
public BlockState State
|
||||||
{
|
{
|
||||||
get { return _state; }
|
get { return _state; }
|
||||||
|
@ -276,6 +282,20 @@ namespace Substrate
|
||||||
public BlockInfo SetState (BlockState state)
|
public BlockInfo SetState (BlockState state)
|
||||||
{
|
{
|
||||||
_state = state;
|
_state = state;
|
||||||
|
|
||||||
|
if (_state == BlockState.SOLID) {
|
||||||
|
_blocksFluid = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_blocksFluid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockInfo SetBlocksFluid (bool blocks)
|
||||||
|
{
|
||||||
|
_blocksFluid = blocks;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,6 +520,12 @@ namespace Substrate
|
||||||
Farmland.SetLightTransmission(false);
|
Farmland.SetLightTransmission(false);
|
||||||
CobbleStairs.SetLightTransmission(false);
|
CobbleStairs.SetLightTransmission(false);
|
||||||
|
|
||||||
|
// Override default fluid blocking rules
|
||||||
|
|
||||||
|
SignPost.SetBlocksFluid(true);
|
||||||
|
WallSign.SetBlocksFluid(true);
|
||||||
|
Cactus.SetBlocksFluid(false);
|
||||||
|
|
||||||
// Set Tile Entity Data
|
// Set Tile Entity Data
|
||||||
|
|
||||||
Dispenser.SetTileEntity("Trap");
|
Dispenser.SetTileEntity("Trap");
|
||||||
|
|
|
@ -68,7 +68,7 @@ namespace Substrate
|
||||||
BlockKey primary = new BlockKey(lx, ly, lz);
|
BlockKey primary = new BlockKey(lx, ly, lz);
|
||||||
_update.Enqueue(primary);
|
_update.Enqueue(primary);
|
||||||
|
|
||||||
BlockInfo info = _blockset.GetInfo(lx, ly, lz);
|
//BlockInfo info = _blockset.GetInfo(lx, ly, lz);
|
||||||
|
|
||||||
//if (info.Luminance > BlockInfo.MIN_LUMINANCE || info.TransmitsLight) {
|
//if (info.Luminance > BlockInfo.MIN_LUMINANCE || info.TransmitsLight) {
|
||||||
if (ly > 0) {
|
if (ly > 0) {
|
||||||
|
|
|
@ -6,8 +6,8 @@ namespace Substrate
|
||||||
{
|
{
|
||||||
public struct ChunkKey : IEquatable<ChunkKey>
|
public struct ChunkKey : IEquatable<ChunkKey>
|
||||||
{
|
{
|
||||||
readonly int cx;
|
public readonly int cx;
|
||||||
readonly int cz;
|
public readonly int cz;
|
||||||
|
|
||||||
public ChunkKey (int _cx, int _cz)
|
public ChunkKey (int _cx, int _cz)
|
||||||
{
|
{
|
||||||
|
|
|
@ -150,14 +150,12 @@ namespace Substrate
|
||||||
|
|
||||||
public class EntityEnumerator : IEnumerator<Entity>
|
public class EntityEnumerator : IEnumerator<Entity>
|
||||||
{
|
{
|
||||||
private TagList _entities;
|
|
||||||
private IEnumerator<TagValue> _enum;
|
private IEnumerator<TagValue> _enum;
|
||||||
|
|
||||||
private Entity _cur;
|
private Entity _cur;
|
||||||
|
|
||||||
public EntityEnumerator (TagList entities)
|
public EntityEnumerator (TagList entities)
|
||||||
{
|
{
|
||||||
_entities = entities;
|
|
||||||
_enum = entities.GetEnumerator();
|
_enum = entities.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,6 @@ namespace Substrate.NBT
|
||||||
|
|
||||||
private static void SerializeScaler (TagValue tag, StringBuilder str)
|
private static void SerializeScaler (TagValue tag, StringBuilder str)
|
||||||
{
|
{
|
||||||
TagType type = tag.GetTagType();
|
|
||||||
switch (tag.GetTagType()) {
|
switch (tag.GetTagType()) {
|
||||||
case TagType.TAG_STRING:
|
case TagType.TAG_STRING:
|
||||||
str.Append("\"" + tag.ToTagString().Data + "\"");
|
str.Append("\"" + tag.ToTagString().Data + "\"");
|
||||||
|
|
|
@ -279,7 +279,7 @@ namespace Substrate.NBT
|
||||||
{
|
{
|
||||||
TagType type = (TagType)_stream.ReadByte();
|
TagType type = (TagType)_stream.ReadByte();
|
||||||
if (type == TagType.TAG_COMPOUND) {
|
if (type == TagType.TAG_COMPOUND) {
|
||||||
string name = ReadString().ToTagString().Data;
|
ReadString(); // name
|
||||||
return ReadValue(type) as TagCompound;
|
return ReadValue(type) as TagCompound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -187,6 +187,9 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Source\Experimental\" />
|
<Folder Include="Source\Experimental\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="Makefile" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
|
Loading…
Reference in a new issue