Port NBT impl from LibAC Dart
This commit is contained in:
parent
0a022634c1
commit
ad7b619706
55 changed files with 3226 additions and 2983 deletions
188
Hashing.cs
188
Hashing.cs
|
@ -1,188 +0,0 @@
|
||||||
using LibAC.Serialization;
|
|
||||||
using LibAC.Serialization.ACFile;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC
|
|
||||||
{
|
|
||||||
public class Hash : Serializable
|
|
||||||
{
|
|
||||||
public byte[] hashed;
|
|
||||||
private readonly byte signature = 0x9f;
|
|
||||||
public int passnum = 0;
|
|
||||||
|
|
||||||
public Hash(int len)
|
|
||||||
{
|
|
||||||
hashed = new byte[len];
|
|
||||||
//hashed[0] = signature;
|
|
||||||
|
|
||||||
passnum = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte get_sig_at_pass(int pass)
|
|
||||||
{
|
|
||||||
byte start = signature;
|
|
||||||
for (int i = 0; i < pass; i++)
|
|
||||||
{
|
|
||||||
start = (byte)wrap_add((int)start, (int)signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Hash(byte[] bs, int pass)
|
|
||||||
{
|
|
||||||
hashed = bs;
|
|
||||||
passnum = pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Hash compute(int len, byte[] data)
|
|
||||||
{
|
|
||||||
if (len <= 0) throw new ArgumentOutOfRangeException();
|
|
||||||
byte[] arr = new byte[len];
|
|
||||||
int p = 0;//pointer to position in [arr]
|
|
||||||
|
|
||||||
foreach (byte b in data)
|
|
||||||
{
|
|
||||||
//arr[p] += b;// treat as a number.
|
|
||||||
int exist = arr[p];
|
|
||||||
exist += b;
|
|
||||||
while (exist > 255) exist -= 255;
|
|
||||||
|
|
||||||
if (exist < 0) exist *= -1;
|
|
||||||
arr[p] = (byte)exist;
|
|
||||||
|
|
||||||
p++;
|
|
||||||
if (p >= len)
|
|
||||||
{
|
|
||||||
p = 0;// reset the pointer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return new Hash(arr, 1);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Hash operator +(Hash a, Hash b)
|
|
||||||
{
|
|
||||||
Hash ret = new Hash(a.hashed, a.passnum);
|
|
||||||
int p = 2; // We do want to add the position signed bit. As that information is unique to a piece of source data
|
|
||||||
|
|
||||||
for (p = 0; p < b.hashed.Length; p++)
|
|
||||||
{
|
|
||||||
int exist = a.hashed[p];
|
|
||||||
exist = wrap_add(exist, b.hashed[p]);
|
|
||||||
|
|
||||||
ret.hashed[p] = (byte)exist;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.passnum++;
|
|
||||||
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wrap adds, with a cap at 255
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a"></param>
|
|
||||||
/// <param name="b"></param>
|
|
||||||
/// <returns>Wrapped integer</returns>
|
|
||||||
public static int wrap_add(int a, int b)
|
|
||||||
{
|
|
||||||
a = a + b;
|
|
||||||
while (a > 255) a -= 255;
|
|
||||||
if (a < 0) a *= -1;
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Wrap subtracts with a cap of 255
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a"></param>
|
|
||||||
/// <param name="b"></param>
|
|
||||||
/// <returns>Wrapped integer</returns>
|
|
||||||
public static int wrap_sub(int a, int b)
|
|
||||||
{
|
|
||||||
int ret = a - b;
|
|
||||||
if (ret < 0) ret += 255;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Hash operator -(Hash a, Hash b)
|
|
||||||
{
|
|
||||||
Hash ret = new Hash(a.hashed, a.passnum);
|
|
||||||
int p = 1; // We do want to add the position signed bit. As that information is unique to a piece of source data
|
|
||||||
|
|
||||||
for (p = 0; p < b.hashed.Length; p++)
|
|
||||||
{
|
|
||||||
int exist = a.hashed[p];
|
|
||||||
exist = wrap_sub(exist, b.hashed[p]);
|
|
||||||
|
|
||||||
ret.hashed[p] = (byte)exist;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.passnum--;
|
|
||||||
/*
|
|
||||||
if (ret.get_sig_at_pass(ret.passnum) == ret.hashed[0])
|
|
||||||
{
|
|
||||||
// success
|
|
||||||
}
|
|
||||||
else throw new Exception("Fatal error in pass. Validation failed");
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
foreach (byte b in serialize())
|
|
||||||
{
|
|
||||||
sb.Append(b.ToString("X2"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] serialize()
|
|
||||||
{
|
|
||||||
MemoryStream ms = new MemoryStream();
|
|
||||||
BinaryWriter bw = new BinaryWriter(ms);
|
|
||||||
bw.Write(passnum);
|
|
||||||
bw.Write(hashed.Length);
|
|
||||||
bw.Write(hashed);
|
|
||||||
|
|
||||||
return ms.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deserialize(byte[] streams)
|
|
||||||
{
|
|
||||||
MemoryStream ms = new MemoryStream(streams);
|
|
||||||
BinaryReader br = new BinaryReader(ms);
|
|
||||||
passnum = br.ReadInt32();
|
|
||||||
hashed = br.ReadBytes(br.ReadInt32());
|
|
||||||
|
|
||||||
br.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void save(Folder f)
|
|
||||||
{
|
|
||||||
f.Add(new IntTag("pass", passnum));
|
|
||||||
f.Add(new ByteArrayTag("hash",hashed));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void load(Folder f)
|
|
||||||
{
|
|
||||||
passnum = f["pass"].IntValue;
|
|
||||||
hashed = (f["hash"] as ByteArrayTag).Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<Configurations>Debug;Release;DebPub;KVPBuild</Configurations>
|
<Configurations>Debug;Release;DebPub;KVPBuild</Configurations>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MySqlConnector" Version="2.1.11" />
|
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.Threading.Channels" Version="6.0.0" />
|
<PackageReference Include="System.Threading.Channels" Version="9.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
358
NBT/API/ByteLayer.cs
Normal file
358
NBT/API/ByteLayer.cs
Normal file
|
@ -0,0 +1,358 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Linq;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
public class ByteLayer
|
||||||
|
{
|
||||||
|
private byte[] _byteBuffer;
|
||||||
|
private int _position;
|
||||||
|
|
||||||
|
public ByteLayer()
|
||||||
|
{
|
||||||
|
_byteBuffer = new byte[0];
|
||||||
|
_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Length => _byteBuffer.Length;
|
||||||
|
|
||||||
|
public int CurrentPosition => _position;
|
||||||
|
|
||||||
|
public byte[] Bytes => _byteBuffer.Take(_position).ToArray();
|
||||||
|
|
||||||
|
private void EnsureCapacity(int additionalBytes)
|
||||||
|
{
|
||||||
|
int requiredCapacity = _position + additionalBytes;
|
||||||
|
if (requiredCapacity > _byteBuffer.Length)
|
||||||
|
{
|
||||||
|
Array.Resize(ref _byteBuffer, requiredCapacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteInt(int value)
|
||||||
|
{
|
||||||
|
EnsureCapacity(4);
|
||||||
|
Array.Copy(BitConverter.GetBytes(value), 0, _byteBuffer, _position, 4);
|
||||||
|
if (BitConverter.IsLittleEndian)
|
||||||
|
Array.Reverse(_byteBuffer, _position, 4);
|
||||||
|
_position += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ReadInt()
|
||||||
|
{
|
||||||
|
if (_position + 4 > _byteBuffer.Length) throw new InvalidOperationException("Buffer overflow.");
|
||||||
|
var value = _byteBuffer.Skip(_position).Take(4).ToArray();
|
||||||
|
if (BitConverter.IsLittleEndian) Array.Reverse(value);
|
||||||
|
_position += 4;
|
||||||
|
return BitConverter.ToInt32(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteDouble(double value)
|
||||||
|
{
|
||||||
|
EnsureCapacity(8);
|
||||||
|
var bytes = BitConverter.GetBytes(value);
|
||||||
|
if (BitConverter.IsLittleEndian)
|
||||||
|
Array.Reverse(bytes);
|
||||||
|
Array.Copy(bytes, 0, _byteBuffer, _position, 8);
|
||||||
|
_position += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double ReadDouble()
|
||||||
|
{
|
||||||
|
if (_position + 8 > _byteBuffer.Length) throw new InvalidOperationException("Buffer overflow.");
|
||||||
|
var value = _byteBuffer.Skip(_position).Take(8).ToArray();
|
||||||
|
if (BitConverter.IsLittleEndian) Array.Reverse(value);
|
||||||
|
_position += 8;
|
||||||
|
return BitConverter.ToDouble(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteFloat(float value)
|
||||||
|
{
|
||||||
|
EnsureCapacity(4);
|
||||||
|
var bytes = BitConverter.GetBytes(value);
|
||||||
|
if(BitConverter.IsLittleEndian)
|
||||||
|
Array.Reverse(bytes);
|
||||||
|
|
||||||
|
Array.Copy(bytes, 0, _byteBuffer, _position, 4);
|
||||||
|
_position += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float ReadFloat()
|
||||||
|
{
|
||||||
|
if (_position + 4 > _byteBuffer.Length) throw new InvalidOperationException("Buffer overflow.");
|
||||||
|
var value = _byteBuffer.Skip(_position).Take(4).ToArray();
|
||||||
|
if (BitConverter.IsLittleEndian) Array.Reverse(value);
|
||||||
|
_position += 4;
|
||||||
|
return BitConverter.ToSingle(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteString(string value)
|
||||||
|
{
|
||||||
|
var encoded = Encoding.UTF8.GetBytes(value);
|
||||||
|
WriteShort((short)encoded.Length);
|
||||||
|
EnsureCapacity(encoded.Length);
|
||||||
|
Array.Copy(encoded, 0, _byteBuffer, _position, encoded.Length);
|
||||||
|
_position += encoded.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ReadString()
|
||||||
|
{
|
||||||
|
int length = ReadShort();
|
||||||
|
if (_position + length > _byteBuffer.Length) throw new InvalidOperationException("Buffer overflow.");
|
||||||
|
var value = Encoding.UTF8.GetString(_byteBuffer, _position, length);
|
||||||
|
_position += length;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteShort(short value)
|
||||||
|
{
|
||||||
|
EnsureCapacity(2);
|
||||||
|
var bytes = BitConverter.GetBytes((short)value);
|
||||||
|
if (BitConverter.IsLittleEndian)
|
||||||
|
Array.Reverse(bytes);
|
||||||
|
Array.Copy(bytes, 0, _byteBuffer, _position, 2);
|
||||||
|
_position += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short ReadShort()
|
||||||
|
{
|
||||||
|
if (_position + 2 > _byteBuffer.Length) throw new InvalidOperationException("Buffer overflow.");
|
||||||
|
var value = _byteBuffer.Skip(_position).Take(2).ToArray();
|
||||||
|
if (BitConverter.IsLittleEndian) Array.Reverse(value);
|
||||||
|
_position += 2;
|
||||||
|
return BitConverter.ToInt16(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteByte(byte value)
|
||||||
|
{
|
||||||
|
EnsureCapacity(1);
|
||||||
|
_byteBuffer[_position] = value;
|
||||||
|
_position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteBytes(List<byte> bytes)
|
||||||
|
{
|
||||||
|
EnsureCapacity(bytes.Count);
|
||||||
|
Array.Copy(bytes.ToArray(), 0, _byteBuffer, _position, bytes.Count);
|
||||||
|
_position += bytes.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte ReadByte()
|
||||||
|
{
|
||||||
|
if (_position >= _byteBuffer.Length) throw new InvalidOperationException("Buffer overflow.");
|
||||||
|
return _byteBuffer[_position++];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetPosition() => _position = 0;
|
||||||
|
|
||||||
|
public void RestorePosition(int position)
|
||||||
|
{
|
||||||
|
if (position < 0 || position > _byteBuffer.Length)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(position));
|
||||||
|
_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_position = 0;
|
||||||
|
_byteBuffer = new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteToFile(string filePath)
|
||||||
|
{
|
||||||
|
File.WriteAllBytes(filePath, Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReadFromFile(string filePath)
|
||||||
|
{
|
||||||
|
if (!File.Exists(filePath)) throw new FileNotFoundException("File does not exist.", filePath);
|
||||||
|
_byteBuffer = File.ReadAllBytes(filePath);
|
||||||
|
ResetPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Compress()
|
||||||
|
{
|
||||||
|
using var memoryStream = new MemoryStream();
|
||||||
|
using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress))
|
||||||
|
{
|
||||||
|
gzipStream.Write(_byteBuffer, 0, _byteBuffer.Length);
|
||||||
|
}
|
||||||
|
_byteBuffer = memoryStream.ToArray();
|
||||||
|
_position = _byteBuffer.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Decompress()
|
||||||
|
{
|
||||||
|
using var memoryStream = new MemoryStream(_byteBuffer);
|
||||||
|
using var gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress);
|
||||||
|
using var decompressedStream = new MemoryStream();
|
||||||
|
gzipStream.CopyTo(decompressedStream);
|
||||||
|
_byteBuffer = decompressedStream.ToArray();
|
||||||
|
_position = _byteBuffer.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteVarInt(int value)
|
||||||
|
{
|
||||||
|
while ((value & ~0x7F) != 0)
|
||||||
|
{
|
||||||
|
WriteByte((byte)((value & 0x7F) | 0x80));
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
WriteByte((byte)(value & 0x7F));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ReadVarInt()
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
int shift = 0;
|
||||||
|
int byteRead;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
byteRead = ReadByte();
|
||||||
|
result |= (byteRead & 0x7F) << shift;
|
||||||
|
shift += 7;
|
||||||
|
} while ((byteRead & 0x80) != 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteVarIntNoZigZag(int value)
|
||||||
|
{
|
||||||
|
while ((value & ~0x7F) != 0)
|
||||||
|
{
|
||||||
|
WriteByte((byte)((value & 0x7F) | 0x80));
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
WriteByte((byte)(value & 0x7F));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ReadVarIntNoZigZag()
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
int shift = 0;
|
||||||
|
int byteRead;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
byteRead = ReadByte();
|
||||||
|
result |= (byteRead & 0x7F) << shift;
|
||||||
|
shift += 7;
|
||||||
|
} while ((byteRead & 0x80) != 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteLong(long value)
|
||||||
|
{
|
||||||
|
EnsureCapacity(8);
|
||||||
|
Array.Copy(BitConverter.GetBytes(value), 0, _byteBuffer, _position, 8);
|
||||||
|
if (BitConverter.IsLittleEndian)
|
||||||
|
Array.Reverse(_byteBuffer, _position, 8);
|
||||||
|
_position += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ReadLong()
|
||||||
|
{
|
||||||
|
if (_position + 8 > _byteBuffer.Length) throw new InvalidOperationException("Buffer overflow.");
|
||||||
|
var value = _byteBuffer.Skip(_position).Take(8).ToArray();
|
||||||
|
if (BitConverter.IsLittleEndian) Array.Reverse(value);
|
||||||
|
_position += 8;
|
||||||
|
return BitConverter.ToInt64(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteVarLongZigZag(long value)
|
||||||
|
{
|
||||||
|
value = (value << 1) ^ (value >> 63);
|
||||||
|
WriteVarLongNoZigZag(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteVarLongNoZigZag(long value)
|
||||||
|
{
|
||||||
|
while ((value & ~0x7F) != 0)
|
||||||
|
{
|
||||||
|
WriteByte((byte)((value & 0x7F) | 0x80));
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
WriteByte((byte)(value & 0x7F));
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ReadVarLongZigZag()
|
||||||
|
{
|
||||||
|
long result = ReadVarLongNoZigZag();
|
||||||
|
return (result >> 1) ^ -(result & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ReadVarLongNoZigZag()
|
||||||
|
{
|
||||||
|
long result = 0;
|
||||||
|
int shift = 0;
|
||||||
|
int byteRead;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
byteRead = ReadByte();
|
||||||
|
result |= (byteRead & 0x7F) << shift;
|
||||||
|
shift += 7;
|
||||||
|
} while ((byteRead & 0x80) != 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBit(int position, byte maskToSet)
|
||||||
|
{
|
||||||
|
if (position < _byteBuffer.Length)
|
||||||
|
{
|
||||||
|
Seek(position);
|
||||||
|
byte current = ReadByte();
|
||||||
|
Seek(position);
|
||||||
|
current |= maskToSet;
|
||||||
|
WriteByte(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearBit(int position, byte maskToClear)
|
||||||
|
{
|
||||||
|
if (position < _byteBuffer.Length)
|
||||||
|
{
|
||||||
|
Seek(position);
|
||||||
|
byte current = ReadByte();
|
||||||
|
current &= (byte)~maskToClear;
|
||||||
|
Seek(position);
|
||||||
|
WriteByte(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CheckBit(int position, byte mask)
|
||||||
|
{
|
||||||
|
if (position < _byteBuffer.Length)
|
||||||
|
{
|
||||||
|
Seek(position);
|
||||||
|
byte current = ReadByte();
|
||||||
|
return (current & mask) == mask;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte GetBit(int position)
|
||||||
|
{
|
||||||
|
if (position < _byteBuffer.Length)
|
||||||
|
{
|
||||||
|
Seek(position);
|
||||||
|
return ReadByte();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Seek(int position)
|
||||||
|
{
|
||||||
|
if (position < 0 || position > _byteBuffer.Length)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(position));
|
||||||
|
_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertRandomBytes(int count)
|
||||||
|
{
|
||||||
|
Random rng = new Random();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
WriteByte((byte)rng.Next(256));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
NBT/API/InvalidNbtDataException.cs
Normal file
8
NBT/API/InvalidNbtDataException.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LibAC.NBT.API
|
||||||
|
{
|
||||||
|
public class InvalidNbtDataException : Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
32
NBT/API/NBTAccountant.cs
Normal file
32
NBT/API/NBTAccountant.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
namespace LibAC.NBT.API;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
public class NBTAccountant
|
||||||
|
{
|
||||||
|
private static int _prettyIndex = 0;
|
||||||
|
|
||||||
|
public static void PrintRead(Tag tag)
|
||||||
|
{
|
||||||
|
tag.PrettyPrint(_prettyIndex, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void VisitTag()
|
||||||
|
{
|
||||||
|
_prettyIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LeaveTag(Tag tag)
|
||||||
|
{
|
||||||
|
if (tag is CompoundTag ct)
|
||||||
|
{
|
||||||
|
ct.EndPrettyPrint(_prettyIndex);
|
||||||
|
}
|
||||||
|
else if (tag is ListTag lt)
|
||||||
|
{
|
||||||
|
lt.EndPrettyPrint(_prettyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
_prettyIndex--;
|
||||||
|
}
|
||||||
|
}
|
132
NBT/API/NbtIo.cs
Normal file
132
NBT/API/NbtIo.cs
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using LibAC.NBT;
|
||||||
|
|
||||||
|
|
||||||
|
namespace LibAC.NBT.API
|
||||||
|
{
|
||||||
|
public class NbtIo
|
||||||
|
{
|
||||||
|
private static ByteLayer _io = new ByteLayer();
|
||||||
|
|
||||||
|
private static void _Read(string file)
|
||||||
|
{
|
||||||
|
_io = new ByteLayer();
|
||||||
|
_io.ReadFromFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompoundTag Read(string file)
|
||||||
|
{
|
||||||
|
_Read(file);
|
||||||
|
if (_io.ReadByte() == (byte)TagType.Compound)
|
||||||
|
{
|
||||||
|
_io.ResetPosition();
|
||||||
|
return (CompoundTag)Tag.ReadNamedTag(_io);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ReadCompressed(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompoundTag ReadCompressed(string file)
|
||||||
|
{
|
||||||
|
_io = new ByteLayer();
|
||||||
|
_io.ReadFromFile(file);
|
||||||
|
_io.Decompress();
|
||||||
|
_io.ResetPosition();
|
||||||
|
return (CompoundTag)Tag.ReadNamedTag(_io);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Write(string file, CompoundTag tag)
|
||||||
|
{
|
||||||
|
_io = new ByteLayer();
|
||||||
|
Tag.WriteNamedTag(tag, _io);
|
||||||
|
_io.WriteToFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteCompressedAsync(string file, CompoundTag tag)
|
||||||
|
{
|
||||||
|
_io = new ByteLayer();
|
||||||
|
Tag.WriteNamedTag(tag, _io);
|
||||||
|
_io.Compress();
|
||||||
|
_io.WriteToFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteLayer GetStream()
|
||||||
|
{
|
||||||
|
return _io;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string WriteBase64String(CompoundTag tag)
|
||||||
|
{
|
||||||
|
_io = new ByteLayer();
|
||||||
|
Tag.WriteNamedTag(tag, _io);
|
||||||
|
_io.Compress();
|
||||||
|
return Convert.ToBase64String(_io.Bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompoundTag ReadBase64String(string encoded)
|
||||||
|
{
|
||||||
|
_io = new ByteLayer();
|
||||||
|
byte[] bytes = Convert.FromBase64String(encoded);
|
||||||
|
foreach (byte b in bytes)
|
||||||
|
{
|
||||||
|
_io.WriteByte(b);
|
||||||
|
}
|
||||||
|
_io.Decompress();
|
||||||
|
_io.ResetPosition();
|
||||||
|
return (CompoundTag)Tag.ReadNamedTag(_io);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] WriteToStreamCompressed(CompoundTag tag)
|
||||||
|
{
|
||||||
|
_io = new ByteLayer();
|
||||||
|
Tag.WriteNamedTag(tag, _io);
|
||||||
|
_io.Compress();
|
||||||
|
return _io.Bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompoundTag ReadFromStreamCompressed(byte[] list)
|
||||||
|
{
|
||||||
|
_io = new ByteLayer();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_io.WriteBytes(list.ToList());
|
||||||
|
_io.ResetPosition();
|
||||||
|
_io.Decompress();
|
||||||
|
_io.ResetPosition();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
return (CompoundTag)Tag.ReadNamedTag(_io);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<byte[]> WriteToStreamAsync(CompoundTag tag)
|
||||||
|
{
|
||||||
|
_io = new ByteLayer();
|
||||||
|
Tag.WriteNamedTag(tag, _io);
|
||||||
|
return _io.Bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompoundTag ReadFromStream(byte[] list)
|
||||||
|
{
|
||||||
|
_io = new ByteLayer();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_io.WriteBytes(list.ToList());
|
||||||
|
_io.ResetPosition();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
return (CompoundTag)Tag.ReadNamedTag(_io);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
NBT/API/NbtUUID.cs
Normal file
43
NBT/API/NbtUUID.cs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using LibAC.Utilities;
|
||||||
|
|
||||||
|
namespace LibAC.NBT.API
|
||||||
|
{
|
||||||
|
public class NbtUUID
|
||||||
|
{
|
||||||
|
public long MSB { get; }
|
||||||
|
public long LSB { get; }
|
||||||
|
|
||||||
|
public static readonly NbtUUID ZERO = new NbtUUID(UUID.ZERO);
|
||||||
|
|
||||||
|
public NbtUUID(long msb, long lsb)
|
||||||
|
{
|
||||||
|
MSB = msb;
|
||||||
|
LSB = lsb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NbtUUID(UUID uuid)
|
||||||
|
{
|
||||||
|
byte[] uuidBytes = uuid.GetBytes();
|
||||||
|
MSB = BitConverter.ToInt64(uuidBytes, 0);
|
||||||
|
LSB = BitConverter.ToInt64(uuidBytes, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long GetMostSignificantBits() => MSB;
|
||||||
|
|
||||||
|
public long GetLeastSignificantBits() => LSB;
|
||||||
|
|
||||||
|
public UUID ToUUID()
|
||||||
|
{
|
||||||
|
byte[] bytes = new byte[16];
|
||||||
|
BitConverter.GetBytes(MSB).CopyTo(bytes, 0);
|
||||||
|
BitConverter.GetBytes(LSB).CopyTo(bytes, 8);
|
||||||
|
return new UUID(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return ToUUID().ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
142
NBT/API/NbtUtils.cs
Normal file
142
NBT/API/NbtUtils.cs
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
using LibAC.Utilities;
|
||||||
|
|
||||||
|
namespace LibAC.NBT.API
|
||||||
|
{
|
||||||
|
public static class NbtUtils
|
||||||
|
{
|
||||||
|
public static void WriteBoolean(CompoundTag tag, string name, bool value)
|
||||||
|
{
|
||||||
|
tag.Put(name, ByteTag.ValueOf(value ? (byte)1 : (byte)0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ReadBoolean(CompoundTag tag, string name)
|
||||||
|
{
|
||||||
|
if (tag.ContainsKey(name))
|
||||||
|
{
|
||||||
|
return tag.Get(name).AsByte() == 1;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteVector2d(CompoundTag tag, string name, Vector2d pos)
|
||||||
|
{
|
||||||
|
var posTag = new ListTag();
|
||||||
|
posTag.Add(DoubleTag.ValueOf(pos.X));
|
||||||
|
posTag.Add(DoubleTag.ValueOf(pos.Z));
|
||||||
|
tag.Put(name, posTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2d ReadVector2d(CompoundTag tag, string name)
|
||||||
|
{
|
||||||
|
if (tag.ContainsKey(name))
|
||||||
|
{
|
||||||
|
var listTag = (ListTag)tag.Get(name);
|
||||||
|
return new Vector2d(listTag.Get(0).AsDouble(), listTag.Get(1).AsDouble());
|
||||||
|
}
|
||||||
|
return Vector2d.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteVector2i(CompoundTag tag, string name, Vector2i pos)
|
||||||
|
{
|
||||||
|
var posTag = new ListTag();
|
||||||
|
posTag.Add(IntTag.ValueOf(pos.X));
|
||||||
|
posTag.Add(IntTag.ValueOf(pos.Z));
|
||||||
|
tag.Put(name, posTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2i ReadVector2i(CompoundTag tag, string name)
|
||||||
|
{
|
||||||
|
if (tag.ContainsKey(name))
|
||||||
|
{
|
||||||
|
var listTag = (ListTag)tag.Get(name);
|
||||||
|
return new Vector2i(listTag.Get(0).AsInt(), listTag.Get(1).AsInt());
|
||||||
|
}
|
||||||
|
return Vector2i.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteVector3d(CompoundTag tag, string name, Vector3d pos)
|
||||||
|
{
|
||||||
|
var posTag = new ListTag();
|
||||||
|
posTag.Add(DoubleTag.ValueOf(pos.X));
|
||||||
|
posTag.Add(DoubleTag.ValueOf(pos.Y));
|
||||||
|
posTag.Add(DoubleTag.ValueOf(pos.Z));
|
||||||
|
tag.Put(name, posTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3d ReadVector3d(CompoundTag tag, string name)
|
||||||
|
{
|
||||||
|
if (tag.ContainsKey(name))
|
||||||
|
{
|
||||||
|
var listTag = (ListTag)tag.Get(name);
|
||||||
|
return new Vector3d(
|
||||||
|
listTag.Get(0).AsDouble(),
|
||||||
|
listTag.Get(1).AsDouble(),
|
||||||
|
listTag.Get(2).AsDouble());
|
||||||
|
}
|
||||||
|
return Vector3d.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteVector3i(CompoundTag tag, string name, Vector3i pos)
|
||||||
|
{
|
||||||
|
var posTag = new ListTag();
|
||||||
|
posTag.Add(IntTag.ValueOf(pos.X));
|
||||||
|
posTag.Add(IntTag.ValueOf(pos.Y));
|
||||||
|
posTag.Add(IntTag.ValueOf(pos.Z));
|
||||||
|
tag.Put(name, posTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3i ReadVector3i(CompoundTag tag, string name)
|
||||||
|
{
|
||||||
|
if (tag.ContainsKey(name))
|
||||||
|
{
|
||||||
|
var listTag = (ListTag)tag.Get(name);
|
||||||
|
return new Vector3i(
|
||||||
|
listTag.Get(0).AsInt(),
|
||||||
|
listTag.Get(1).AsInt(),
|
||||||
|
listTag.Get(2).AsInt());
|
||||||
|
}
|
||||||
|
return Vector3i.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] MsbLsbToIntArray(long msb, long lsb)
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
(int)(msb >> 32),
|
||||||
|
(int)msb,
|
||||||
|
(int)(lsb >> 32),
|
||||||
|
(int)lsb
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] UuidToIntArray(NbtUUID id)
|
||||||
|
{
|
||||||
|
return MsbLsbToIntArray(id.GetMostSignificantBits(), id.GetLeastSignificantBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NbtUUID UuidFromIntArray(int[] values)
|
||||||
|
{
|
||||||
|
return new NbtUUID(
|
||||||
|
((long)values[0] << 32) | (values[1] & 0xFFFFFFFFL),
|
||||||
|
((long)values[2] << 32) | (values[3] & 0xFFFFFFFFL));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteUUID(CompoundTag tag, string name, NbtUUID id)
|
||||||
|
{
|
||||||
|
tag.Put(name, IntArrayTag.ValueOf(UuidToIntArray(id).ToList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NbtUUID ReadUUID(CompoundTag tag, string name)
|
||||||
|
{
|
||||||
|
if (!tag.ContainsKey(name))
|
||||||
|
{
|
||||||
|
return NbtUUID.ZERO;
|
||||||
|
}
|
||||||
|
return UuidFromIntArray(tag.Get(name).AsIntArray().ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
92
NBT/API/SnbtIo.cs
Normal file
92
NBT/API/SnbtIo.cs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Text;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT.API
|
||||||
|
{
|
||||||
|
public static class SnbtIo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a CompoundTag to a file in SNBT format.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file">The file path to write to.</param>
|
||||||
|
/// <param name="tag">The CompoundTag to write.</param>
|
||||||
|
public static async Task WriteToFile(string file, CompoundTag tag)
|
||||||
|
{
|
||||||
|
var fileInfo = new FileInfo(file);
|
||||||
|
|
||||||
|
if (fileInfo.Exists)
|
||||||
|
{
|
||||||
|
fileInfo.Delete(); // Ensure the file is reset to 0 bytes.
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
Tag.WriteStringifiedNamedTag(tag, builder, 0);
|
||||||
|
|
||||||
|
using (var writer = new StreamWriter(file))
|
||||||
|
{
|
||||||
|
await writer.WriteAsync(builder.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a tag from a file in SNBT format.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file">The file path to read from.</param>
|
||||||
|
/// <returns>A Task resolving to the read Tag.</returns>
|
||||||
|
public static async Task<Tag> ReadFromFile(string file)
|
||||||
|
{
|
||||||
|
var fileInfo = new FileInfo(file);
|
||||||
|
if (!fileInfo.Exists)
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException($"File not found: {file}");
|
||||||
|
}
|
||||||
|
|
||||||
|
string data;
|
||||||
|
using (var reader = new StreamReader(file))
|
||||||
|
{
|
||||||
|
data = await reader.ReadToEndAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
var stringReader = new StringReader(data);
|
||||||
|
Tag tag = new CompoundTag();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tag = Tag.ReadStringifiedNamedTag(stringReader);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"FATAL ERROR OCCURRED AT LOCATION:\n{stringReader.GetSnapshot()}");
|
||||||
|
Console.WriteLine(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a CompoundTag to its SNBT string representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The CompoundTag to convert.</param>
|
||||||
|
/// <returns>A string representing the CompoundTag in SNBT format.</returns>
|
||||||
|
public static string WriteToString(CompoundTag tag)
|
||||||
|
{
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
Tag.WriteStringifiedNamedTag(tag, builder, 0);
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a Tag from an SNBT string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The SNBT string to read.</param>
|
||||||
|
/// <returns>A Task resolving to the read Tag.</returns>
|
||||||
|
public static Task<Tag> ReadFromString(string data)
|
||||||
|
{
|
||||||
|
var stringReader = new StringReader(data);
|
||||||
|
return Task.FromResult(Tag.ReadStringifiedNamedTag(stringReader));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
NBT/API/StringBuilder.cs
Normal file
32
NBT/API/StringBuilder.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LibAC.NBT.API
|
||||||
|
{
|
||||||
|
public class StringBuilder
|
||||||
|
{
|
||||||
|
private string _buffer = string.Empty;
|
||||||
|
|
||||||
|
public StringBuilder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEmpty => string.IsNullOrEmpty(_buffer);
|
||||||
|
|
||||||
|
public int Length => _buffer.Length;
|
||||||
|
|
||||||
|
public void Append(string value)
|
||||||
|
{
|
||||||
|
_buffer += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_buffer = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return _buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
196
NBT/API/StringReader.cs
Normal file
196
NBT/API/StringReader.cs
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LibAC.NBT.API
|
||||||
|
{
|
||||||
|
public class StringReader
|
||||||
|
{
|
||||||
|
private readonly string _buffer;
|
||||||
|
private int _position = 0;
|
||||||
|
private int _lastPosition = 0;
|
||||||
|
private bool _quotedString = false;
|
||||||
|
|
||||||
|
public StringReader(string buffer)
|
||||||
|
{
|
||||||
|
_buffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there's more to read
|
||||||
|
public bool CanRead => _CanRead();
|
||||||
|
|
||||||
|
private bool _CanRead()
|
||||||
|
{
|
||||||
|
SkipWhitespace();
|
||||||
|
return _position < _buffer.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the number of chars seeked
|
||||||
|
public int Seeked => _lastPosition - _position;
|
||||||
|
|
||||||
|
// Read the next character
|
||||||
|
public char Next()
|
||||||
|
{
|
||||||
|
if (CanRead)
|
||||||
|
{
|
||||||
|
SkipWhitespace();
|
||||||
|
return _buffer[_position++];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("End of buffer reached");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a snapshot of the text location if applicable
|
||||||
|
public string GetSnapshot()
|
||||||
|
{
|
||||||
|
if (CanRead)
|
||||||
|
{
|
||||||
|
if (_position + 64 < _buffer.Length)
|
||||||
|
{
|
||||||
|
return _buffer.Substring(_position, 64);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _buffer.Substring(_position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peek the next character without advancing the position
|
||||||
|
public char Peek()
|
||||||
|
{
|
||||||
|
SkipWhitespace();
|
||||||
|
if (CanRead)
|
||||||
|
{
|
||||||
|
return _buffer[_position];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("End of buffer reached");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip any whitespace characters
|
||||||
|
public void SkipWhitespace()
|
||||||
|
{
|
||||||
|
if (_quotedString) return; // We need whitespace for strings
|
||||||
|
while (_position < _buffer.Length && IsWhitespace(_buffer[_position]))
|
||||||
|
{
|
||||||
|
_position++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a character is a whitespace
|
||||||
|
private bool IsWhitespace(char character)
|
||||||
|
{
|
||||||
|
return char.IsWhiteSpace(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read until a specific character is found
|
||||||
|
public string ReadUntil(char stopChar, int maxChars)
|
||||||
|
{
|
||||||
|
var result = new StringBuilder();
|
||||||
|
int index = 0;
|
||||||
|
while (CanRead && Peek() != stopChar && index < maxChars)
|
||||||
|
{
|
||||||
|
result.Append(Next().ToString());
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a string enclosed in double quotes
|
||||||
|
public string ReadQuotedString()
|
||||||
|
{
|
||||||
|
_quotedString = true;
|
||||||
|
if (Next() != '"')
|
||||||
|
{
|
||||||
|
throw new Exception("Expected double quotes at the start of a string");
|
||||||
|
}
|
||||||
|
var result = new StringBuilder();
|
||||||
|
while (CanRead)
|
||||||
|
{
|
||||||
|
char character = Next();
|
||||||
|
if (character == '"')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result.Append(character.ToString());
|
||||||
|
}
|
||||||
|
_quotedString = false;
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a number (int or double)
|
||||||
|
public string ReadNumber()
|
||||||
|
{
|
||||||
|
var result = new StringBuilder();
|
||||||
|
while (CanRead && (IsDigit(Peek()) || Peek() == '.' || Peek() == '-'))
|
||||||
|
{
|
||||||
|
result.Append(Next().ToString());
|
||||||
|
}
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a character is a digit
|
||||||
|
private bool IsDigit(char character)
|
||||||
|
{
|
||||||
|
return char.IsDigit(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read an unquoted string (used for keys in SNBT)
|
||||||
|
public string ReadUnquotedString()
|
||||||
|
{
|
||||||
|
var result = new StringBuilder();
|
||||||
|
while (CanRead &&
|
||||||
|
!IsWhitespace(Peek()) &&
|
||||||
|
Peek() != ':' &&
|
||||||
|
Peek() != ',' &&
|
||||||
|
Peek() != '{' &&
|
||||||
|
Peek() != '}' &&
|
||||||
|
Peek() != '[' &&
|
||||||
|
Peek() != ']')
|
||||||
|
{
|
||||||
|
result.Append(Next().ToString());
|
||||||
|
}
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ReadString()
|
||||||
|
{
|
||||||
|
if (Peek() == '"')
|
||||||
|
{
|
||||||
|
return ReadQuotedString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ReadUnquotedString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a specific character and throw an exception if it's not found
|
||||||
|
public void Expect(char expectedChar)
|
||||||
|
{
|
||||||
|
if (char.ToLower(Next()) != char.ToLower(expectedChar))
|
||||||
|
{
|
||||||
|
throw new Exception($"Expected {expectedChar}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartSeek()
|
||||||
|
{
|
||||||
|
_lastPosition = _position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndSeek()
|
||||||
|
{
|
||||||
|
_position = _lastPosition;
|
||||||
|
_lastPosition = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
280
NBT/API/Tag.cs
Normal file
280
NBT/API/Tag.cs
Normal file
|
@ -0,0 +1,280 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace LibAC.NBT.API;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
public abstract class Tag
|
||||||
|
{
|
||||||
|
private TagType _parentTagType = TagType.End;
|
||||||
|
private Tag _parentTag;
|
||||||
|
private string _key;
|
||||||
|
|
||||||
|
public byte GetType()
|
||||||
|
{
|
||||||
|
return (byte)GetTagType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract TagType GetTagType();
|
||||||
|
|
||||||
|
public bool HasParent => _parentTag != null;
|
||||||
|
|
||||||
|
public void UpdateParent(Tag tag)
|
||||||
|
{
|
||||||
|
if (tag == null)
|
||||||
|
{
|
||||||
|
_parentTag = null;
|
||||||
|
SetParentTagType(TagType.End);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_parentTag = tag;
|
||||||
|
SetParentTagType(tag.GetTagType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tag GetParent => _parentTag;
|
||||||
|
|
||||||
|
public TagType ParentTagType => _parentTagType;
|
||||||
|
|
||||||
|
public void SetParentTagType(TagType type)
|
||||||
|
{
|
||||||
|
_parentTagType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void WriteValue(ByteLayer data);
|
||||||
|
public abstract void ReadValue(ByteLayer data);
|
||||||
|
|
||||||
|
public string GetKey()
|
||||||
|
{
|
||||||
|
return _key ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetKey(string key)
|
||||||
|
{
|
||||||
|
_key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract dynamic GetValue();
|
||||||
|
public abstract void SetValue(dynamic val);
|
||||||
|
|
||||||
|
public static Tag ReadNamedTag(ByteLayer data)
|
||||||
|
{
|
||||||
|
var type = data.ReadByte();
|
||||||
|
if (type == 0)
|
||||||
|
{
|
||||||
|
return new EndTag();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Tag tag = MakeTagOfType(TagTypeExtensions.GetTagTypeFromByte(type));
|
||||||
|
tag._key = data.ReadString();
|
||||||
|
tag.ReadValue(data);
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteNamedTag(Tag tag, ByteLayer data)
|
||||||
|
{
|
||||||
|
data.WriteByte(tag.GetType());
|
||||||
|
if (tag.GetType() != 0)
|
||||||
|
{
|
||||||
|
data.WriteString(tag.GetKey());
|
||||||
|
tag.WriteValue(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteStringifiedNamedTag(Tag tag, StringBuilder builder, int indents)
|
||||||
|
{
|
||||||
|
if (tag.GetType() != 0)
|
||||||
|
{
|
||||||
|
if (builder.Length > 0)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(tag.GetKey()))
|
||||||
|
{
|
||||||
|
builder.Append(new string('\t', indents));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tag.ShouldQuoteName())
|
||||||
|
{
|
||||||
|
builder.Append(new string('\t', indents) + $"\"{tag.GetKey()}\": ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.Append(new string('\t', indents) + $"{tag.GetKey()}: ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag.WriteStringifiedValue(builder, indents + 1, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tag ReadStringifiedNamedTag(StringReader stringReader)
|
||||||
|
{
|
||||||
|
string name = stringReader.Peek() == '{' || stringReader.Peek() == '[' ? "" : stringReader.ReadString();
|
||||||
|
if (!string.IsNullOrEmpty(name)) stringReader.Expect(':');
|
||||||
|
|
||||||
|
TagType type = TagTypeExtensions.GetStringifiedTagType(stringReader);
|
||||||
|
Tag tag = MakeTagOfType(type);
|
||||||
|
tag._key = name;
|
||||||
|
tag.ReadStringifiedValue(stringReader);
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldQuoteName()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(GetKey()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
foreach (char c in GetKey())
|
||||||
|
{
|
||||||
|
if (!letters.Contains(c.ToString())) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldQuote(string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value)) return true;
|
||||||
|
|
||||||
|
string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
foreach (char c in value)
|
||||||
|
{
|
||||||
|
if (!letters.Contains(c.ToString())) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void WriteStringifiedValue(StringBuilder builder, int indent, bool isList);
|
||||||
|
public abstract void ReadStringifiedValue(StringReader reader);
|
||||||
|
|
||||||
|
public bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj == null || !(obj is Tag)) return false;
|
||||||
|
|
||||||
|
var tag = (Tag)obj;
|
||||||
|
if (tag.GetType() != GetType()) return false;
|
||||||
|
if (GetKey() != tag.GetKey()) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Tag MakeTagOfType(TagType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case TagType.Byte: return new ByteTag();
|
||||||
|
case TagType.ByteArray: return new ByteArrayTag();
|
||||||
|
case TagType.Compound: return new CompoundTag();
|
||||||
|
case TagType.Double: return new DoubleTag();
|
||||||
|
case TagType.End: return new EndTag();
|
||||||
|
case TagType.Short: return new ShortTag();
|
||||||
|
case TagType.Int: return new IntTag();
|
||||||
|
case TagType.Long: return new LongTag();
|
||||||
|
case TagType.Float: return new FloatTag();
|
||||||
|
case TagType.IntArray: return new IntArrayTag();
|
||||||
|
case TagType.LongArray: return new LongArrayTag();
|
||||||
|
case TagType.List: return new ListTag();
|
||||||
|
case TagType.String: return new StringTag();
|
||||||
|
default: throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int AsByte()
|
||||||
|
{
|
||||||
|
if (this is ByteTag byteTag) return byteTag.Value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<byte> AsByteArray()
|
||||||
|
{
|
||||||
|
if (this is ByteArrayTag byteArrayTag) return byteArrayTag.Value;
|
||||||
|
return new List<byte>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double AsDouble()
|
||||||
|
{
|
||||||
|
if (this is DoubleTag doubleTag) return doubleTag.Value;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double AsFloat()
|
||||||
|
{
|
||||||
|
if (this is FloatTag floatTag) return floatTag.value;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<int> AsIntArray()
|
||||||
|
{
|
||||||
|
if (this is IntArrayTag intArrayTag) return intArrayTag.Value;
|
||||||
|
return new List<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int AsInt()
|
||||||
|
{
|
||||||
|
if (this is IntTag intTag) return intTag.Value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<long> AsLongArray()
|
||||||
|
{
|
||||||
|
if (this is LongArrayTag longArrayTag) return longArrayTag.value;
|
||||||
|
return new List<long>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long AsLong()
|
||||||
|
{
|
||||||
|
if (this is LongTag longTag) return longTag.value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short AsShort()
|
||||||
|
{
|
||||||
|
if (this is ShortTag shortTag) return shortTag.value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string AsString()
|
||||||
|
{
|
||||||
|
if (this is StringTag stringTag) return stringTag.value;
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag AsCompoundTag()
|
||||||
|
{
|
||||||
|
return this is CompoundTag compoundTag ? compoundTag : new CompoundTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void PrettyPrint(int indent, bool recurse);
|
||||||
|
|
||||||
|
public static string GetCanonicalName(TagType type)
|
||||||
|
{
|
||||||
|
return type switch
|
||||||
|
{
|
||||||
|
TagType.String => "TAG_String",
|
||||||
|
TagType.List => "TAG_List",
|
||||||
|
TagType.LongArray => "TAG_LongArray",
|
||||||
|
TagType.Long => "TAG_Long",
|
||||||
|
TagType.IntArray => "TAG_IntArray",
|
||||||
|
TagType.Int => "TAG_Int",
|
||||||
|
TagType.Compound => "TAG_Compound",
|
||||||
|
TagType.ByteArray => "TAG_ByteArray",
|
||||||
|
TagType.Byte => "TAG_Byte",
|
||||||
|
TagType.Double => "TAG_Double",
|
||||||
|
TagType.Float => "TAG_Float",
|
||||||
|
TagType.Short => "TAG_Short",
|
||||||
|
TagType.End => "TAG_End",
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
18
NBT/API/TagType.cs
Normal file
18
NBT/API/TagType.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
namespace LibAC.NBT.API;
|
||||||
|
|
||||||
|
public enum TagType
|
||||||
|
{
|
||||||
|
End = 0,
|
||||||
|
Byte = 1,
|
||||||
|
Short = 2,
|
||||||
|
Int = 3,
|
||||||
|
Long = 4,
|
||||||
|
Float = 5,
|
||||||
|
Double = 6,
|
||||||
|
ByteArray = 7,
|
||||||
|
String = 8,
|
||||||
|
List = 9,
|
||||||
|
Compound = 10,
|
||||||
|
IntArray = 11,
|
||||||
|
LongArray = 12
|
||||||
|
}
|
145
NBT/API/TagTypeExtensions.cs
Normal file
145
NBT/API/TagTypeExtensions.cs
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
namespace LibAC.NBT.API;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
public static class TagTypeExtensions
|
||||||
|
{
|
||||||
|
private static readonly string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
public static TagType GetTagTypeFromByte(int byteValue)
|
||||||
|
{
|
||||||
|
return Enum.IsDefined(typeof(TagType), byteValue) ? (TagType)byteValue : TagType.End;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TagType GetStringifiedTagType(StringReader reader)
|
||||||
|
{
|
||||||
|
reader.StartSeek(); // Enter fake read mode
|
||||||
|
TagType ret = TagType.End;
|
||||||
|
bool isQuoted = false;
|
||||||
|
bool isNumeric = true; // Assume true until proven otherwise
|
||||||
|
bool isAlpha = true; // Assume true until proven otherwise
|
||||||
|
bool hasDecimalPoint = false;
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
|
||||||
|
while (reader.CanRead)
|
||||||
|
{
|
||||||
|
var val = reader.Peek(); // Peek at the next character without consuming it
|
||||||
|
|
||||||
|
if (val == ',' || val == '\n' || val == ']' || val == '}')
|
||||||
|
{
|
||||||
|
break; // Stop at comma or newline
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val == '"')
|
||||||
|
{
|
||||||
|
reader.Next(); // Consume the quote character
|
||||||
|
isQuoted = true; // Toggle quoted state
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val == '{')
|
||||||
|
{
|
||||||
|
ret = TagType.Compound; // Detected a CompoundTag
|
||||||
|
reader.Next(); // Consume '{'
|
||||||
|
reader.EndSeek(); // Restore the original stream position
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val == '[')
|
||||||
|
{
|
||||||
|
reader.Next(); // Consume '['
|
||||||
|
// Peek ahead to differentiate between List and Array
|
||||||
|
var prefix = reader.ReadUntil(';', 2).ToUpper();
|
||||||
|
|
||||||
|
switch (prefix)
|
||||||
|
{
|
||||||
|
case "B":
|
||||||
|
ret = TagType.ByteArray;
|
||||||
|
break;
|
||||||
|
case "I":
|
||||||
|
ret = TagType.IntArray;
|
||||||
|
break;
|
||||||
|
case "L":
|
||||||
|
ret = TagType.LongArray;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = TagType.List; // No type prefix, it's a List
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.EndSeek(); // Restore the original stream position
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjusting numeric and alphabetic checks
|
||||||
|
var current = reader.Next(); // Consume the character
|
||||||
|
|
||||||
|
buffer.Append(current.ToString());
|
||||||
|
|
||||||
|
// Updated check to allow digits, decimal points, and numeric suffixes
|
||||||
|
if (!Regex.IsMatch(current.ToString(), @"^[0-9]$"))
|
||||||
|
{
|
||||||
|
if (current == '.' && !hasDecimalPoint)
|
||||||
|
{
|
||||||
|
hasDecimalPoint = true; // Allow only one decimal point
|
||||||
|
}
|
||||||
|
else if (!Regex.IsMatch(current.ToString(), @"^[sSbBiIlLfFdD]$"))
|
||||||
|
{
|
||||||
|
isNumeric = false; // Not purely numeric or allowed decimal/suffix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if current character is purely alphabetical
|
||||||
|
if (!Regex.IsMatch(current.ToString(), @"^[A-Za-z]$"))
|
||||||
|
{
|
||||||
|
isAlpha = false; // Not purely alphabetical
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var input = buffer.ToString().Trim();
|
||||||
|
reader.EndSeek(); // Restore the original stream position
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(input))
|
||||||
|
{
|
||||||
|
return TagType.String; // No input detected
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isQuoted)
|
||||||
|
{
|
||||||
|
return TagType.String; // Quoted string
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNumeric)
|
||||||
|
{
|
||||||
|
// Check the last character for type indicator (only for numeric input)
|
||||||
|
var lastChar = input.Substring(input.Length - 1).ToUpper();
|
||||||
|
switch (lastChar)
|
||||||
|
{
|
||||||
|
case "S":
|
||||||
|
return TagType.Short;
|
||||||
|
case "B":
|
||||||
|
return TagType.Byte;
|
||||||
|
case "I":
|
||||||
|
return TagType.Int;
|
||||||
|
case "F":
|
||||||
|
return TagType.Float;
|
||||||
|
case "D":
|
||||||
|
return TagType.Double;
|
||||||
|
case "L":
|
||||||
|
return TagType.Long;
|
||||||
|
default:
|
||||||
|
return TagType.Int; // Default to Int if purely numeric with no specific suffix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isAlpha && !input.Contains(' '))
|
||||||
|
{
|
||||||
|
return TagType.String; // Unquoted purely alphabetical string
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return TagType.String; // Unquoted string with mixed content or spaces
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
NBT/ByteArrayTag.cs
Normal file
82
NBT/ByteArrayTag.cs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class ByteArrayTag : Tag
|
||||||
|
{
|
||||||
|
public List<byte> Value { get; private set; } = new List<byte>();
|
||||||
|
|
||||||
|
public ByteArrayTag() { }
|
||||||
|
|
||||||
|
private ByteArrayTag(List<byte> value)
|
||||||
|
{
|
||||||
|
Value.AddRange(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteArrayTag ValueOf(List<byte> value)
|
||||||
|
{
|
||||||
|
return new ByteArrayTag(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
int len = data.ReadInt();
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
Value.Add(data.ReadByte());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
data.WriteInt(Value.Count);
|
||||||
|
foreach (byte i in Value)
|
||||||
|
{
|
||||||
|
data.WriteByte(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.ByteArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override dynamic GetValue()
|
||||||
|
{
|
||||||
|
return null; // Implementation-specific value retrieval
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(dynamic val)
|
||||||
|
{
|
||||||
|
// Implementation-specific value setting
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
string array = string.Join(", ", Value);
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: [{array}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent) : "")}[B; {string.Join("B, ", Value)}B]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
reader.Expect('[');
|
||||||
|
reader.Expect('B');
|
||||||
|
reader.Expect(';');
|
||||||
|
while (reader.Peek() != ']')
|
||||||
|
{
|
||||||
|
Value.Add(byte.Parse(reader.ReadNumber()));
|
||||||
|
reader.Expect('b');
|
||||||
|
|
||||||
|
if (reader.Peek() == ',') reader.Next();
|
||||||
|
}
|
||||||
|
reader.Expect(']');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
NBT/ByteTag.cs
Normal file
67
NBT/ByteTag.cs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
using System;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class ByteTag : Tag
|
||||||
|
{
|
||||||
|
public byte Value { get; private set; } = 0;
|
||||||
|
|
||||||
|
public ByteTag() { }
|
||||||
|
|
||||||
|
private ByteTag(byte value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteTag ValueOf(byte value)
|
||||||
|
{
|
||||||
|
return new ByteTag(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
Value = data.ReadByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
data.WriteByte(Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.Byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override dynamic GetValue()
|
||||||
|
{
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(dynamic val)
|
||||||
|
{
|
||||||
|
if (val is byte)
|
||||||
|
{
|
||||||
|
Value = (byte)val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: {Value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
builder.Append($"{Value}b");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
string val = reader.ReadNumber();
|
||||||
|
Value = byte.Parse(val);
|
||||||
|
reader.Expect('b');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
283
NBT/CompoundTag.cs
Normal file
283
NBT/CompoundTag.cs
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class CompoundTag : Tag, IDictionary<string, Tag>
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, Tag> _value = new Dictionary<string, Tag>();
|
||||||
|
|
||||||
|
public CompoundTag() { }
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
_value.Clear();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Tag tag = Tag.ReadNamedTag(data);
|
||||||
|
if (tag.GetType() == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag.SetParentTagType(TagType.Compound);
|
||||||
|
this[tag.GetKey()] = tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
foreach (var tag in _value.Values)
|
||||||
|
{
|
||||||
|
Tag.WriteNamedTag(tag, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.WriteByte((byte)TagType.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Put(string name, Tag tag)
|
||||||
|
{
|
||||||
|
_value[name] = tag;
|
||||||
|
tag.SetKey(name);
|
||||||
|
tag.UpdateParent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tag? Get(string name)
|
||||||
|
{
|
||||||
|
return ContainsKey(name) ? _value[name] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.Compound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object GetValue()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(object val) { }
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: [{_value.Count} entries]");
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}");
|
||||||
|
if (recurse)
|
||||||
|
{
|
||||||
|
foreach (var tag in _value.Values)
|
||||||
|
{
|
||||||
|
tag.PrettyPrint(indent + 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndPrettyPrint(int indent)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent - 1) : "")}{{\n");
|
||||||
|
|
||||||
|
bool firstEntry = true;
|
||||||
|
foreach (var tag in _value.Values)
|
||||||
|
{
|
||||||
|
if (!firstEntry)
|
||||||
|
{
|
||||||
|
builder.Append(",\n");
|
||||||
|
}
|
||||||
|
firstEntry = false;
|
||||||
|
Tag.WriteStringifiedNamedTag(tag, builder, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append($"\n{new string('\t', indent - 1)}}}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(string key, out Tag value)
|
||||||
|
{
|
||||||
|
return _value.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tag? this[string key]
|
||||||
|
{
|
||||||
|
get => _value.ContainsKey(key) ? _value[key] : null;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
_value[key] = value;
|
||||||
|
value.UpdateParent(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(string key, Tag value)
|
||||||
|
{
|
||||||
|
_value.Add(key, value);
|
||||||
|
value.UpdateParent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(KeyValuePair<string, Tag> item)
|
||||||
|
{
|
||||||
|
_value.Add(item.Key, item.Value);
|
||||||
|
item.Value.UpdateParent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
UnsetParent();
|
||||||
|
_value.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(KeyValuePair<string, Tag> item)
|
||||||
|
{
|
||||||
|
return _value.ContainsKey(item.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(KeyValuePair<string, Tag>[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(KeyValuePair<string, Tag> item)
|
||||||
|
{
|
||||||
|
return _value.Remove(item.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsetParent()
|
||||||
|
{
|
||||||
|
foreach (var entry in _value)
|
||||||
|
{
|
||||||
|
entry.Value.SetParentTagType(TagType.End);
|
||||||
|
entry.Value.UpdateParent(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsKey(string key)
|
||||||
|
{
|
||||||
|
return _value.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsValue(Tag value)
|
||||||
|
{
|
||||||
|
return _value.ContainsValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForEach(Action<string, Tag> action)
|
||||||
|
{
|
||||||
|
foreach (var entry in _value)
|
||||||
|
{
|
||||||
|
action(entry.Key, entry.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count => _value.Count;
|
||||||
|
public bool IsReadOnly { get; }
|
||||||
|
|
||||||
|
public bool IsEmpty => _value.Count == 0;
|
||||||
|
|
||||||
|
public bool IsNotEmpty => _value.Count > 0;
|
||||||
|
|
||||||
|
public ICollection<string> Keys => _value.Keys;
|
||||||
|
|
||||||
|
public ICollection<Tag> Values => _value.Values;
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
reader.Expect('{');
|
||||||
|
|
||||||
|
while (reader.Peek() != '}')
|
||||||
|
{
|
||||||
|
Tag tag = Tag.ReadStringifiedNamedTag(reader);
|
||||||
|
Put(tag.GetKey(), tag);
|
||||||
|
|
||||||
|
if (reader.Peek() == ',') reader.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.Expect('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddAll(IDictionary<string, Tag> other)
|
||||||
|
{
|
||||||
|
foreach (var entry in other)
|
||||||
|
{
|
||||||
|
_value[entry.Key] = entry.Value;
|
||||||
|
entry.Value.UpdateParent(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(string key)
|
||||||
|
{
|
||||||
|
if (_value.ContainsKey(key))
|
||||||
|
{
|
||||||
|
_value[key].UpdateParent(null);
|
||||||
|
return _value.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveWhere(Predicate<KeyValuePair<string, Tag>> predicate)
|
||||||
|
{
|
||||||
|
var toRemove = new List<string>();
|
||||||
|
foreach (var entry in _value)
|
||||||
|
{
|
||||||
|
if (predicate(entry))
|
||||||
|
{
|
||||||
|
toRemove.Add(entry.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var key in toRemove)
|
||||||
|
{
|
||||||
|
_value[key].UpdateParent(null);
|
||||||
|
_value.Remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateAll(Action<string, Tag> update)
|
||||||
|
{
|
||||||
|
foreach (var entry in _value)
|
||||||
|
{
|
||||||
|
update(entry.Key, entry.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tag PutIfAbsent(string key, Func<Tag> ifAbsent)
|
||||||
|
{
|
||||||
|
if (!_value.ContainsKey(key))
|
||||||
|
{
|
||||||
|
var tag = ifAbsent();
|
||||||
|
tag.UpdateParent(this);
|
||||||
|
_value[key] = tag;
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _value[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddEntries(IEnumerable<KeyValuePair<string, Tag>> newEntries)
|
||||||
|
{
|
||||||
|
foreach (var entry in newEntries)
|
||||||
|
{
|
||||||
|
_value.Add(entry.Key, entry.Value);
|
||||||
|
entry.Value.UpdateParent(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<string, Tag>> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _value.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return _value.GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
NBT/DoubleTag.cs
Normal file
67
NBT/DoubleTag.cs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
using System;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class DoubleTag : Tag
|
||||||
|
{
|
||||||
|
public double Value { get; private set; } = 0.0;
|
||||||
|
|
||||||
|
public DoubleTag() { }
|
||||||
|
|
||||||
|
private DoubleTag(double value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DoubleTag ValueOf(double value)
|
||||||
|
{
|
||||||
|
return new DoubleTag(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
Value = data.ReadDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
data.WriteDouble(Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.Double;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override dynamic GetValue()
|
||||||
|
{
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(dynamic val)
|
||||||
|
{
|
||||||
|
if (val is double)
|
||||||
|
{
|
||||||
|
Value = (double)val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: {Value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent) : "")}{Value}d");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
double val = double.Parse(reader.ReadNumber());
|
||||||
|
Value = val;
|
||||||
|
reader.Expect('d');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
NBT/EndTag.cs
Normal file
42
NBT/EndTag.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
using System;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT;
|
||||||
|
|
||||||
|
public class EndTag : Tag
|
||||||
|
{
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.End;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override dynamic GetValue()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(dynamic val)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{"".PadLeft(indent, '\t')}{Tag.GetCanonicalName(GetTagType())}");
|
||||||
|
}
|
||||||
|
}
|
66
NBT/FloatTag.cs
Normal file
66
NBT/FloatTag.cs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
using System;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class FloatTag : Tag
|
||||||
|
{
|
||||||
|
public float value { get; private set; } = 0.0f;
|
||||||
|
|
||||||
|
public FloatTag() { }
|
||||||
|
|
||||||
|
private FloatTag(float value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FloatTag ValueOf(float value)
|
||||||
|
{
|
||||||
|
return new FloatTag(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
value = data.ReadFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
data.WriteFloat(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object GetValue()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(object val)
|
||||||
|
{
|
||||||
|
if (val is float)
|
||||||
|
{
|
||||||
|
value = (float)val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: {value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent) : "")}{value}f");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
value = float.Parse(reader.ReadNumber());
|
||||||
|
reader.Expect('f');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
76
NBT/IntArrayTag.cs
Normal file
76
NBT/IntArrayTag.cs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class IntArrayTag : Tag
|
||||||
|
{
|
||||||
|
public List<int> Value { get; private set; } = new List<int>();
|
||||||
|
|
||||||
|
public IntArrayTag() { }
|
||||||
|
|
||||||
|
private IntArrayTag(List<int> value)
|
||||||
|
{
|
||||||
|
this.Value.AddRange(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntArrayTag ValueOf(List<int> value)
|
||||||
|
{
|
||||||
|
return new IntArrayTag(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
int count = data.ReadInt();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
Value.Add(data.ReadInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
data.WriteInt(Value.Count);
|
||||||
|
foreach (int i in Value)
|
||||||
|
{
|
||||||
|
data.WriteInt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.IntArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(dynamic val) { }
|
||||||
|
|
||||||
|
public override dynamic GetValue() { return null; }
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
string array = string.Join(", ", Value);
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: [{array}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent) : "")}[I; {string.Join("I, ", Value)}I]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
reader.Expect('[');
|
||||||
|
reader.Expect('I');
|
||||||
|
reader.Expect(';');
|
||||||
|
while (reader.Peek() != ']')
|
||||||
|
{
|
||||||
|
Value.Add(int.Parse(reader.ReadNumber()));
|
||||||
|
|
||||||
|
if (reader.Peek() == ',')
|
||||||
|
reader.Next();
|
||||||
|
}
|
||||||
|
reader.Expect('I');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
NBT/IntTag.cs
Normal file
70
NBT/IntTag.cs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
using System;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class IntTag : Tag
|
||||||
|
{
|
||||||
|
public int Value { get; private set; } = 0;
|
||||||
|
|
||||||
|
public IntTag() { }
|
||||||
|
|
||||||
|
private IntTag(int value)
|
||||||
|
{
|
||||||
|
this.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntTag ValueOf(int value)
|
||||||
|
{
|
||||||
|
return new IntTag(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
Value = data.ReadInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
data.WriteInt(Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.Int;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(dynamic val)
|
||||||
|
{
|
||||||
|
if (val is int)
|
||||||
|
Value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override dynamic GetValue()
|
||||||
|
{
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: {Value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent) : "")}{Value}i");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
string val = reader.ReadNumber();
|
||||||
|
Value = int.Parse(val);
|
||||||
|
|
||||||
|
// Since a type indicator is optional for an int, check for a comma
|
||||||
|
if (reader.Peek() == ',')
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
reader.Expect('i');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
173
NBT/ListTag.cs
Normal file
173
NBT/ListTag.cs
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class ListTag : Tag
|
||||||
|
{
|
||||||
|
private List<Tag> value = new List<Tag>();
|
||||||
|
|
||||||
|
public List<Tag> GetList => new List<Tag>(value);
|
||||||
|
|
||||||
|
public ListTag() { }
|
||||||
|
|
||||||
|
public TagType ListTagType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return value.Count == 0 ? TagType.End : value[0].GetTagType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
TagType type = TagTypeExtensions.GetTagTypeFromByte(data.ReadByte());
|
||||||
|
int size = data.ReadInt();
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
Tag tag = Tag.MakeTagOfType(type);
|
||||||
|
tag.ReadValue(data);
|
||||||
|
Add(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
TagType type = TagType.End;
|
||||||
|
if (Size() > 0)
|
||||||
|
{
|
||||||
|
type = value[0].GetTagType();
|
||||||
|
}
|
||||||
|
|
||||||
|
data.WriteByte((byte)type);
|
||||||
|
data.WriteInt(Size());
|
||||||
|
for (int i = 0; i < Size(); i++)
|
||||||
|
{
|
||||||
|
value[i].WriteValue(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(Tag tag)
|
||||||
|
{
|
||||||
|
TagType type = TagType.End;
|
||||||
|
if (Size() > 0)
|
||||||
|
{
|
||||||
|
type = value[0].GetTagType();
|
||||||
|
}
|
||||||
|
if (type == TagType.End || type == tag.GetTagType())
|
||||||
|
{
|
||||||
|
value.Add(tag);
|
||||||
|
tag.UpdateParent(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tag Get(int index)
|
||||||
|
{
|
||||||
|
if (Size() > index)
|
||||||
|
{
|
||||||
|
return value[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new EndTag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(Tag tag)
|
||||||
|
{
|
||||||
|
value.Remove(tag);
|
||||||
|
tag.UpdateParent(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAt(int index)
|
||||||
|
{
|
||||||
|
value[index].UpdateParent(null);
|
||||||
|
value.RemoveAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IndexOf(Tag tag)
|
||||||
|
{
|
||||||
|
return value.IndexOf(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.List;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(dynamic val) { }
|
||||||
|
|
||||||
|
public override dynamic GetValue()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Size()
|
||||||
|
{
|
||||||
|
return value.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
// Clear the list
|
||||||
|
foreach (var entry in value)
|
||||||
|
{
|
||||||
|
entry.UpdateParent(null);
|
||||||
|
entry.SetParentTagType(TagType.End);
|
||||||
|
}
|
||||||
|
|
||||||
|
value.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: [{value.Count} entries]");
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}[");
|
||||||
|
foreach (Tag tag in value)
|
||||||
|
{
|
||||||
|
tag.PrettyPrint(indent + 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndPrettyPrint(int indent)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent - 1) : "")}[");
|
||||||
|
|
||||||
|
bool firstTag = true;
|
||||||
|
foreach (Tag tag in value)
|
||||||
|
{
|
||||||
|
if (!firstTag)
|
||||||
|
{
|
||||||
|
builder.Append(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
firstTag = false;
|
||||||
|
tag.WriteStringifiedValue(builder, indent + 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append($"{new string('\t', indent - 1)}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
reader.Expect('[');
|
||||||
|
while (reader.Peek() != ']')
|
||||||
|
{
|
||||||
|
TagType type = TagTypeExtensions.GetStringifiedTagType(reader);
|
||||||
|
Tag newTag = Tag.MakeTagOfType(type);
|
||||||
|
newTag.ReadStringifiedValue(reader);
|
||||||
|
Add(newTag);
|
||||||
|
|
||||||
|
if (reader.Peek() == ',') reader.Next();
|
||||||
|
}
|
||||||
|
reader.Expect(']');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
84
NBT/LongArrayTag.cs
Normal file
84
NBT/LongArrayTag.cs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class LongArrayTag : Tag
|
||||||
|
{
|
||||||
|
public List<long> value { get; private set; } = new List<long>();
|
||||||
|
|
||||||
|
public LongArrayTag() { }
|
||||||
|
|
||||||
|
public LongArrayTag(List<long> lst)
|
||||||
|
{
|
||||||
|
value.AddRange(lst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LongArrayTag ValueOf(List<long> value)
|
||||||
|
{
|
||||||
|
return new LongArrayTag(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
int count = data.ReadInt();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
value.Add(data.ReadLong());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
data.WriteInt(Size());
|
||||||
|
foreach (long val in value)
|
||||||
|
{
|
||||||
|
data.WriteLong(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Size()
|
||||||
|
{
|
||||||
|
return value.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.LongArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(dynamic val) { }
|
||||||
|
|
||||||
|
public override dynamic GetValue()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
string array = string.Join(", ", value);
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: [{array}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent) : "")}[L; {string.Join("L, ", value)}L]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
reader.Expect('[');
|
||||||
|
reader.Expect('L');
|
||||||
|
reader.Expect(';');
|
||||||
|
while (reader.Peek() != ']')
|
||||||
|
{
|
||||||
|
value.Add(long.Parse(reader.ReadNumber()));
|
||||||
|
reader.Expect('l');
|
||||||
|
|
||||||
|
if (reader.Peek() == ',') reader.Next();
|
||||||
|
}
|
||||||
|
reader.Expect(']');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
NBT/LongTag.cs
Normal file
65
NBT/LongTag.cs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
using System;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class LongTag : Tag
|
||||||
|
{
|
||||||
|
public long value { get; private set; } = 0;
|
||||||
|
|
||||||
|
public LongTag() { }
|
||||||
|
|
||||||
|
public LongTag(long value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LongTag ValueOf(long value)
|
||||||
|
{
|
||||||
|
return new LongTag(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
value = data.ReadLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
data.WriteLong(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.Long;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(dynamic val)
|
||||||
|
{
|
||||||
|
if (val is long) value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override dynamic GetValue()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: {value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent) : "")}{value}L");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
long val = long.Parse(reader.ReadNumber());
|
||||||
|
value = val;
|
||||||
|
|
||||||
|
reader.Expect('l');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
NBT/ShortTag.cs
Normal file
65
NBT/ShortTag.cs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
using System;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class ShortTag : Tag
|
||||||
|
{
|
||||||
|
public short value { get; private set; }
|
||||||
|
= 0;
|
||||||
|
public ShortTag() { }
|
||||||
|
|
||||||
|
public ShortTag(short value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShortTag ValueOf(short value)
|
||||||
|
{
|
||||||
|
return new ShortTag(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
value = data.ReadShort();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
data.WriteShort(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.Short;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(dynamic val)
|
||||||
|
{
|
||||||
|
if (val is short) value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override dynamic GetValue()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: {value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent) : "")}{value}S");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
short val = short.Parse(reader.ReadNumber());
|
||||||
|
value = val;
|
||||||
|
|
||||||
|
reader.Expect('s');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
NBT/StringTag.cs
Normal file
73
NBT/StringTag.cs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
using System;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
|
namespace LibAC.NBT
|
||||||
|
{
|
||||||
|
public class StringTag : Tag
|
||||||
|
{
|
||||||
|
public string value { get; private set; } = "";
|
||||||
|
|
||||||
|
public StringTag() { }
|
||||||
|
|
||||||
|
public StringTag(string str)
|
||||||
|
{
|
||||||
|
value = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringTag ValueOf(string str)
|
||||||
|
{
|
||||||
|
return new StringTag(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
value = data.ReadString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteValue(ByteLayer data)
|
||||||
|
{
|
||||||
|
data.WriteString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TagType GetTagType()
|
||||||
|
{
|
||||||
|
return TagType.String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(dynamic val)
|
||||||
|
{
|
||||||
|
if (val is string) value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override dynamic GetValue()
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrettyPrint(int indent, bool recurse)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: {value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList)
|
||||||
|
{
|
||||||
|
if (ShouldQuote(value))
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent) : "")}\"{value}\"");
|
||||||
|
else
|
||||||
|
builder.Append($"{(isList ? new string('\t', indent) : "")}{value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadStringifiedValue(StringReader reader)
|
||||||
|
{
|
||||||
|
string str = reader.ReadString();
|
||||||
|
value = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method will need to be implemented for checking if a string should be quoted
|
||||||
|
private bool ShouldQuote(string str)
|
||||||
|
{
|
||||||
|
// Implement logic for determining if the string needs to be quoted
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,236 +0,0 @@
|
||||||
// DISCLAIMER: Taken from fNBT to be altered to fit the needs of ZNI NBT
|
|
||||||
// All credit for the implementation of this file should go to the fNBT Authors, unless stated otherwise by comment!
|
|
||||||
|
|
||||||
|
|
||||||
using LibAC.Serialization.ACFile;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization
|
|
||||||
{
|
|
||||||
/// <summary> BinaryReader wrapper that takes care of reading primitives from an NBT stream,
|
|
||||||
/// while taking care of endianness, string encoding, and skipping. </summary>
|
|
||||||
public sealed class NBTReader : BinaryReader
|
|
||||||
{
|
|
||||||
readonly byte[] buffer = new byte[sizeof(double)];
|
|
||||||
|
|
||||||
byte[] seekBuffer;
|
|
||||||
const int SeekBufferSize = 8 * 1024;
|
|
||||||
readonly bool swapNeeded;
|
|
||||||
readonly byte[] stringConversionBuffer = new byte[64];
|
|
||||||
|
|
||||||
|
|
||||||
public NBTReader(Stream input, bool bigEndian)
|
|
||||||
: base(input)
|
|
||||||
{
|
|
||||||
swapNeeded = (BitConverter.IsLittleEndian == bigEndian);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public TagType ReadTagType()
|
|
||||||
{
|
|
||||||
int type = ReadByte();
|
|
||||||
if (type < 0)
|
|
||||||
{
|
|
||||||
throw new EndOfStreamException();
|
|
||||||
}
|
|
||||||
else if (type > (int)TagType.UUID) // ZNI: Other data types are supported
|
|
||||||
{
|
|
||||||
throw new Exception("NBT tag type out of range: " + type);
|
|
||||||
}
|
|
||||||
return (TagType)type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override short ReadInt16()
|
|
||||||
{
|
|
||||||
if (swapNeeded)
|
|
||||||
{
|
|
||||||
return Swap(base.ReadInt16());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return base.ReadInt16();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override int ReadInt32()
|
|
||||||
{
|
|
||||||
if (swapNeeded)
|
|
||||||
{
|
|
||||||
return Swap(base.ReadInt32());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return base.ReadInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override long ReadInt64()
|
|
||||||
{
|
|
||||||
if (swapNeeded)
|
|
||||||
{
|
|
||||||
return Swap(base.ReadInt64());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return base.ReadInt64();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override float ReadSingle()
|
|
||||||
{
|
|
||||||
if (swapNeeded)
|
|
||||||
{
|
|
||||||
FillBuffer(sizeof(float));
|
|
||||||
Array.Reverse(buffer, 0, sizeof(float));
|
|
||||||
return BitConverter.ToSingle(buffer, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return base.ReadSingle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override double ReadDouble()
|
|
||||||
{
|
|
||||||
if (swapNeeded)
|
|
||||||
{
|
|
||||||
FillBuffer(sizeof(double));
|
|
||||||
Array.Reverse(buffer);
|
|
||||||
return BitConverter.ToDouble(buffer, 0);
|
|
||||||
}
|
|
||||||
return base.ReadDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override string ReadString()
|
|
||||||
{
|
|
||||||
short length = ReadInt16();
|
|
||||||
if (length < 0)
|
|
||||||
{
|
|
||||||
throw new Exception("Negative string length given!");
|
|
||||||
}
|
|
||||||
if (length < stringConversionBuffer.Length)
|
|
||||||
{
|
|
||||||
int stringBytesRead = 0;
|
|
||||||
while (stringBytesRead < length)
|
|
||||||
{
|
|
||||||
int bytesToRead = length - stringBytesRead;
|
|
||||||
int bytesReadThisTime = BaseStream.Read(stringConversionBuffer, stringBytesRead, bytesToRead);
|
|
||||||
if (bytesReadThisTime == 0)
|
|
||||||
{
|
|
||||||
throw new EndOfStreamException();
|
|
||||||
}
|
|
||||||
stringBytesRead += bytesReadThisTime;
|
|
||||||
}
|
|
||||||
return Encoding.UTF8.GetString(stringConversionBuffer, 0, length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte[] stringData = ReadBytes(length);
|
|
||||||
if (stringData.Length < length)
|
|
||||||
{
|
|
||||||
throw new EndOfStreamException();
|
|
||||||
}
|
|
||||||
return Encoding.UTF8.GetString(stringData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Skip(int bytesToSkip)
|
|
||||||
{
|
|
||||||
if (bytesToSkip < 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException("bytesToSkip");
|
|
||||||
}
|
|
||||||
else if (BaseStream.CanSeek)
|
|
||||||
{
|
|
||||||
BaseStream.Position += bytesToSkip;
|
|
||||||
}
|
|
||||||
else if (bytesToSkip != 0)
|
|
||||||
{
|
|
||||||
if (seekBuffer == null) seekBuffer = new byte[SeekBufferSize];
|
|
||||||
int bytesSkipped = 0;
|
|
||||||
while (bytesSkipped < bytesToSkip)
|
|
||||||
{
|
|
||||||
int bytesToRead = Math.Min(SeekBufferSize, bytesToSkip - bytesSkipped);
|
|
||||||
int bytesReadThisTime = BaseStream.Read(seekBuffer, 0, bytesToRead);
|
|
||||||
if (bytesReadThisTime == 0)
|
|
||||||
{
|
|
||||||
throw new EndOfStreamException();
|
|
||||||
}
|
|
||||||
bytesSkipped += bytesReadThisTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
new void FillBuffer(int numBytes)
|
|
||||||
{
|
|
||||||
int offset = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
int num = BaseStream.Read(buffer, offset, numBytes - offset);
|
|
||||||
if (num == 0) throw new EndOfStreamException();
|
|
||||||
offset += num;
|
|
||||||
} while (offset < numBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void SkipString()
|
|
||||||
{
|
|
||||||
short length = ReadInt16();
|
|
||||||
if (length < 0)
|
|
||||||
{
|
|
||||||
throw new Exception("Negative string length given!");
|
|
||||||
}
|
|
||||||
Skip(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[DebuggerStepThrough]
|
|
||||||
static short Swap(short v)
|
|
||||||
{
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
return (short)((v >> 8) & 0x00FF |
|
|
||||||
(v << 8) & 0xFF00);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[DebuggerStepThrough]
|
|
||||||
static int Swap(int v)
|
|
||||||
{
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
var v2 = (uint)v;
|
|
||||||
return (int)((v2 >> 24) & 0x000000FF |
|
|
||||||
(v2 >> 8) & 0x0000FF00 |
|
|
||||||
(v2 << 8) & 0x00FF0000 |
|
|
||||||
(v2 << 24) & 0xFF000000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[DebuggerStepThrough]
|
|
||||||
static long Swap(long v)
|
|
||||||
{
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
return (Swap((int)v) & uint.MaxValue) << 32 |
|
|
||||||
Swap((int)(v >> 32)) & uint.MaxValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ZNI Removed selector. Not needed for the ZNI NBT implementation
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,263 +0,0 @@
|
||||||
// DISCLAIMER: Taken from fNBT to be altered to fit the needs of ZNI NBT
|
|
||||||
// All credit for the implementation of this file should go to the fNBT Authors, unless stated otherwise by comment!
|
|
||||||
|
|
||||||
using LibAC.Serialization.ACFile;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization
|
|
||||||
{
|
|
||||||
/// <summary> BinaryWriter wrapper that writes NBT primitives to a stream,
|
|
||||||
/// while taking care of endianness and string encoding, and counting bytes written. </summary>
|
|
||||||
public sealed unsafe class NBTWriter
|
|
||||||
{
|
|
||||||
// Write at most 4 MiB at a time.
|
|
||||||
public const int MaxWriteChunk = 4 * 1024 * 1024;
|
|
||||||
|
|
||||||
// Encoding can be shared among all instances of NbtBinaryWriter, because it is stateless.
|
|
||||||
static readonly UTF8Encoding Encoding = new UTF8Encoding(false, true);
|
|
||||||
|
|
||||||
// Each instance has to have its own encoder, because it does maintain state.
|
|
||||||
readonly Encoder encoder = Encoding.GetEncoder();
|
|
||||||
|
|
||||||
public Stream BaseStream
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
stream.Flush();
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly Stream stream;
|
|
||||||
|
|
||||||
// Buffer used for temporary conversion
|
|
||||||
const int BufferSize = 256;
|
|
||||||
|
|
||||||
// UTF8 characters use at most 4 bytes each.
|
|
||||||
const int MaxBufferedStringLength = BufferSize / 4;
|
|
||||||
|
|
||||||
// Each NbtBinaryWriter needs to have its own instance of the buffer.
|
|
||||||
readonly byte[] buffer = new byte[BufferSize];
|
|
||||||
|
|
||||||
// Swap is only needed if endianness of the runtime differs from desired NBT stream
|
|
||||||
readonly bool swapNeeded;
|
|
||||||
|
|
||||||
|
|
||||||
public NBTWriter( Stream input, bool bigEndian)
|
|
||||||
{
|
|
||||||
if (input == null) throw new ArgumentNullException("input");
|
|
||||||
if (!input.CanWrite) throw new ArgumentException("Given stream must be writable", "input");
|
|
||||||
stream = input;
|
|
||||||
swapNeeded = (BitConverter.IsLittleEndian == bigEndian);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Write(byte value)
|
|
||||||
{
|
|
||||||
stream.WriteByte(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Write(TagType value)
|
|
||||||
{
|
|
||||||
stream.WriteByte((byte)value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Write(short value)
|
|
||||||
{
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
if (swapNeeded)
|
|
||||||
{
|
|
||||||
buffer[0] = (byte)(value >> 8);
|
|
||||||
buffer[1] = (byte)value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer[0] = (byte)value;
|
|
||||||
buffer[1] = (byte)(value >> 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream.Write(buffer, 0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Write(int value)
|
|
||||||
{
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
if (swapNeeded)
|
|
||||||
{
|
|
||||||
buffer[0] = (byte)(value >> 24);
|
|
||||||
buffer[1] = (byte)(value >> 16);
|
|
||||||
buffer[2] = (byte)(value >> 8);
|
|
||||||
buffer[3] = (byte)value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer[0] = (byte)value;
|
|
||||||
buffer[1] = (byte)(value >> 8);
|
|
||||||
buffer[2] = (byte)(value >> 16);
|
|
||||||
buffer[3] = (byte)(value >> 24);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream.Write(buffer, 0, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Write(long value)
|
|
||||||
{
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
if (swapNeeded)
|
|
||||||
{
|
|
||||||
buffer[0] = (byte)(value >> 56);
|
|
||||||
buffer[1] = (byte)(value >> 48);
|
|
||||||
buffer[2] = (byte)(value >> 40);
|
|
||||||
buffer[3] = (byte)(value >> 32);
|
|
||||||
buffer[4] = (byte)(value >> 24);
|
|
||||||
buffer[5] = (byte)(value >> 16);
|
|
||||||
buffer[6] = (byte)(value >> 8);
|
|
||||||
buffer[7] = (byte)value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer[0] = (byte)value;
|
|
||||||
buffer[1] = (byte)(value >> 8);
|
|
||||||
buffer[2] = (byte)(value >> 16);
|
|
||||||
buffer[3] = (byte)(value >> 24);
|
|
||||||
buffer[4] = (byte)(value >> 32);
|
|
||||||
buffer[5] = (byte)(value >> 40);
|
|
||||||
buffer[6] = (byte)(value >> 48);
|
|
||||||
buffer[7] = (byte)(value >> 56);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream.Write(buffer, 0, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Write(float value)
|
|
||||||
{
|
|
||||||
ulong tmpValue = *(uint*)&value;
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
if (swapNeeded)
|
|
||||||
{
|
|
||||||
buffer[0] = (byte)(tmpValue >> 24);
|
|
||||||
buffer[1] = (byte)(tmpValue >> 16);
|
|
||||||
buffer[2] = (byte)(tmpValue >> 8);
|
|
||||||
buffer[3] = (byte)tmpValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer[0] = (byte)tmpValue;
|
|
||||||
buffer[1] = (byte)(tmpValue >> 8);
|
|
||||||
buffer[2] = (byte)(tmpValue >> 16);
|
|
||||||
buffer[3] = (byte)(tmpValue >> 24);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream.Write(buffer, 0, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Write(double value)
|
|
||||||
{
|
|
||||||
ulong tmpValue = *(ulong*)&value;
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
if (swapNeeded)
|
|
||||||
{
|
|
||||||
buffer[0] = (byte)(tmpValue >> 56);
|
|
||||||
buffer[1] = (byte)(tmpValue >> 48);
|
|
||||||
buffer[2] = (byte)(tmpValue >> 40);
|
|
||||||
buffer[3] = (byte)(tmpValue >> 32);
|
|
||||||
buffer[4] = (byte)(tmpValue >> 24);
|
|
||||||
buffer[5] = (byte)(tmpValue >> 16);
|
|
||||||
buffer[6] = (byte)(tmpValue >> 8);
|
|
||||||
buffer[7] = (byte)tmpValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer[0] = (byte)tmpValue;
|
|
||||||
buffer[1] = (byte)(tmpValue >> 8);
|
|
||||||
buffer[2] = (byte)(tmpValue >> 16);
|
|
||||||
buffer[3] = (byte)(tmpValue >> 24);
|
|
||||||
buffer[4] = (byte)(tmpValue >> 32);
|
|
||||||
buffer[5] = (byte)(tmpValue >> 40);
|
|
||||||
buffer[6] = (byte)(tmpValue >> 48);
|
|
||||||
buffer[7] = (byte)(tmpValue >> 56);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream.Write(buffer, 0, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Based on BinaryWriter.Write(String)
|
|
||||||
public void Write(string value)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("value");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write out string length (as number of bytes)
|
|
||||||
int numBytes = Encoding.GetByteCount(value);
|
|
||||||
Write((short)numBytes);
|
|
||||||
|
|
||||||
if (numBytes <= BufferSize)
|
|
||||||
{
|
|
||||||
// If the string fits entirely in the buffer, encode and write it as one
|
|
||||||
Encoding.GetBytes(value, 0, value.Length, buffer, 0);
|
|
||||||
stream.Write(buffer, 0, numBytes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Aggressively try to not allocate memory in this loop for runtime performance reasons.
|
|
||||||
// Use an Encoder to write out the string correctly (handling surrogates crossing buffer
|
|
||||||
// boundaries properly).
|
|
||||||
int charStart = 0;
|
|
||||||
int numLeft = value.Length;
|
|
||||||
while (numLeft > 0)
|
|
||||||
{
|
|
||||||
// Figure out how many chars to process this round.
|
|
||||||
int charCount = (numLeft > MaxBufferedStringLength) ? MaxBufferedStringLength : numLeft;
|
|
||||||
int byteLen;
|
|
||||||
fixed (char* pChars = value)
|
|
||||||
{
|
|
||||||
fixed (byte* pBytes = buffer)
|
|
||||||
{
|
|
||||||
byteLen = encoder.GetBytes(pChars + charStart, charCount, pBytes, BufferSize,
|
|
||||||
charCount == numLeft);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream.Write(buffer, 0, byteLen);
|
|
||||||
charStart += charCount;
|
|
||||||
numLeft -= charCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Write(byte[] data, int offset, int count)
|
|
||||||
{
|
|
||||||
int written = 0;
|
|
||||||
while (written < count)
|
|
||||||
{
|
|
||||||
int toWrite = Math.Min(MaxWriteChunk, count - written);
|
|
||||||
stream.Write(data, offset + written, toWrite);
|
|
||||||
written += toWrite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aria : Added a NBT compatible shortcut method for writing a byte array with the length prefix
|
|
||||||
public void Write(byte[] bytes)
|
|
||||||
{
|
|
||||||
this.Write(bytes.Length);
|
|
||||||
this.Write(bytes, 0, bytes.Length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
using LibAC.Serialization.ACFile;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization
|
|
||||||
{
|
|
||||||
public abstract class Serializable
|
|
||||||
{
|
|
||||||
public abstract void save(Folder f);
|
|
||||||
public abstract void load(Folder f);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,162 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization
|
|
||||||
{
|
|
||||||
public static class SerializingHelper
|
|
||||||
{
|
|
||||||
private static int SEGMENT_BITS = 0x7F;
|
|
||||||
private static int CONTINUE_BIT = 0x80;
|
|
||||||
/// <summary>
|
|
||||||
/// Adapted from code from wiki.vg
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bw"></param>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
public static void WriteVarInt(this BinaryWriter bw, int value)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if ((value & ~SEGMENT_BITS) == 0)
|
|
||||||
{
|
|
||||||
bw.Write((byte)value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte b = (byte)((value & SEGMENT_BITS) | CONTINUE_BIT);
|
|
||||||
bw.Write(b);
|
|
||||||
|
|
||||||
value >>>= 7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int ReadVarInt(this BinaryReader br)
|
|
||||||
{
|
|
||||||
int value = 0;
|
|
||||||
int position = 0;
|
|
||||||
byte curByte;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
curByte = br.ReadByte();
|
|
||||||
value |= (curByte & SEGMENT_BITS) << position;
|
|
||||||
if ((curByte & CONTINUE_BIT) == 0) break;
|
|
||||||
|
|
||||||
position += 7;
|
|
||||||
|
|
||||||
if (position >= 32) throw new VarIntSizeException("Too large");
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void WriteVarLong(this BinaryWriter bw, long value)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if ((value & ~((long)SEGMENT_BITS)) == 0)
|
|
||||||
{
|
|
||||||
byte bx = (byte)value;
|
|
||||||
bw.Write(bx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
byte b = (byte)((value & SEGMENT_BITS) | CONTINUE_BIT);
|
|
||||||
bw.Write(b);
|
|
||||||
value >>>= 7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long ReadVarLong(this BinaryReader br)
|
|
||||||
{
|
|
||||||
long value = 0;
|
|
||||||
int position = 0;
|
|
||||||
byte curByte;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
curByte = br.ReadByte();
|
|
||||||
value |= (long)(curByte & SEGMENT_BITS) << position;
|
|
||||||
|
|
||||||
if ((curByte & CONTINUE_BIT) == 0) break;
|
|
||||||
|
|
||||||
position += 7;
|
|
||||||
|
|
||||||
if (position >= 64) throw new VarLongSizeException("Too large");
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies ZigZag Encoding to the integer
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="i"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static int ZigZag(this int i)
|
|
||||||
{
|
|
||||||
return Math.Abs((i + i) + ((i < 0) ? 1 : 0));
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Undoes the zigzag encoding on a integer
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="i"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static int DeZigZag(this int i)
|
|
||||||
{
|
|
||||||
if ((i % 2) == 0)
|
|
||||||
{
|
|
||||||
// Even number. Divide by two
|
|
||||||
return (i / 2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int x = i - 1;
|
|
||||||
x = -i;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies ZigZag Encoding to the integer
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="i"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static long ZigZag(this long i)
|
|
||||||
{
|
|
||||||
return Math.Abs((i + i) + ((i < 0L) ? 1L : 0L));
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Undoes the zigzag encoding on a integer
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="i"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static long DeZigZag(this long i)
|
|
||||||
{
|
|
||||||
if ((i % 2) == 0)
|
|
||||||
{
|
|
||||||
// Even number. Divide by two
|
|
||||||
return (i / 2L);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
long x = i - 1L;
|
|
||||||
x = -i;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class VarIntSizeException : Exception
|
|
||||||
{
|
|
||||||
public VarIntSizeException(string Message) : base(Message) { }
|
|
||||||
}
|
|
||||||
public class VarLongSizeException : Exception
|
|
||||||
{
|
|
||||||
public VarLongSizeException(string Message) : base(Message) { }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
using LibAC.Serialization.ACFile;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This class contains helper functions for interacting with streams and files that are encoded using ZNIFile's structure
|
|
||||||
/// Additionally, this provides a overlay as it interacts with the final data set, and can compress and or encrypt.
|
|
||||||
/// </summary>
|
|
||||||
public static class TagIO
|
|
||||||
{
|
|
||||||
public static void WriteOnStream(Stream s, Tag x)
|
|
||||||
{
|
|
||||||
NBTWriter bw = new NBTWriter(s, true);
|
|
||||||
x.WriteTag(bw);
|
|
||||||
x.WriteData(bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Folder ReadFromStream(Stream s)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
Folder folder = new Folder();
|
|
||||||
NBTReader br = new NBTReader(s,true);
|
|
||||||
TagType type = (TagType)br.ReadByte();
|
|
||||||
if (type == TagType.FOLDER)
|
|
||||||
{
|
|
||||||
// Read the file!
|
|
||||||
folder.ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
return folder;
|
|
||||||
}catch(Exception e)
|
|
||||||
{
|
|
||||||
return new Folder();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SaveToFile(string FileName, Tag x, bool gz=false)
|
|
||||||
{
|
|
||||||
if(File.Exists(FileName))File.Delete(FileName);
|
|
||||||
Stream fs = new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
|
|
||||||
if (gz){
|
|
||||||
fs = new GZipStream(fs, CompressionLevel.SmallestSize);
|
|
||||||
}
|
|
||||||
WriteOnStream(fs, x);
|
|
||||||
fs.Close();
|
|
||||||
}
|
|
||||||
public static Folder ReadFromFile(string FileName, bool gz = false)
|
|
||||||
{
|
|
||||||
Stream fs = new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
|
|
||||||
if (gz)
|
|
||||||
{
|
|
||||||
fs = new GZipStream(fs, CompressionMode.Decompress);
|
|
||||||
}
|
|
||||||
Folder f = ReadFromStream(fs);
|
|
||||||
fs.Close();
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class BoolTag : Tag
|
|
||||||
{
|
|
||||||
private bool BoolVal;
|
|
||||||
public bool Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BoolVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BoolTag(string _Name, bool val)
|
|
||||||
{
|
|
||||||
Name = _Name;
|
|
||||||
BoolVal = val;
|
|
||||||
}
|
|
||||||
public BoolTag(bool boolVal) : this(null, boolVal)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public BoolTag() : this(null, false) { }
|
|
||||||
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.BOOL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new BoolTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
Folder vFolder = new Folder(Name);
|
|
||||||
vFolder.Add(new ByteTag("val", (byte)(Value ? 1 : 0)));
|
|
||||||
vFolder.Add(new ByteTag("_virtcast_", (byte)Type));
|
|
||||||
if(Parent != null)
|
|
||||||
{
|
|
||||||
if(Parent.Type == TagType.LIST)
|
|
||||||
{
|
|
||||||
vFolder.Add(new StringTag("name", Name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vFolder.WriteTag(bw);
|
|
||||||
vFolder.WriteData(bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new BoolTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
if (!F.HasNamedTag("name"))
|
|
||||||
Name = F.Name;
|
|
||||||
else Name = F["name"].StringValue;
|
|
||||||
|
|
||||||
int ret = F["val"].IntValue;
|
|
||||||
if (ret == 1) BoolVal = true;
|
|
||||||
else BoolVal = false;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class ByteArrayTag : Tag
|
|
||||||
{
|
|
||||||
private byte[] BArrVal;
|
|
||||||
public byte[] Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BArrVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteArrayTag(string _Name, byte[] val)
|
|
||||||
{
|
|
||||||
Name = _Name;
|
|
||||||
BArrVal = val;
|
|
||||||
}
|
|
||||||
public ByteArrayTag(byte[] boolVal) : this(null, boolVal)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public ByteArrayTag() : this(null, new byte[] {}) { }
|
|
||||||
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.BYTEARRAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
if(!(Parent!= null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
BArrVal = br.ReadBytes(br.ReadInt32());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new ByteArrayTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
bw.Write(Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new ByteArrayTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class ByteTag : Tag
|
|
||||||
{
|
|
||||||
private byte ByteVal;
|
|
||||||
public byte Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ByteVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteTag(string _Name, byte val)
|
|
||||||
{
|
|
||||||
Name = _Name;
|
|
||||||
ByteVal = val;
|
|
||||||
}
|
|
||||||
public ByteTag(byte _ByteVal) : this(null, _ByteVal)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public ByteTag() : this(null, 0) { }
|
|
||||||
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.BYTE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
ByteVal = br.ReadByte();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new ByteTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
bw.Write(Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new ByteTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class DoubleTag : Tag
|
|
||||||
{
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.DOUBLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private double DoubleVal;
|
|
||||||
public double Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return DoubleVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DoubleTag() : this(null, 0) { }
|
|
||||||
public DoubleTag(double Val) : this(null, Val) { }
|
|
||||||
public DoubleTag(string DName, double val)
|
|
||||||
{
|
|
||||||
Name = DName;
|
|
||||||
DoubleVal = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new DoubleTag(Name, Value);
|
|
||||||
}
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
DoubleVal = br.ReadDouble();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new DoubleTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
bw.Write(Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class FloatTag : Tag
|
|
||||||
{
|
|
||||||
private float FloatVal;
|
|
||||||
public float Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return FloatVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public FloatTag(string _Name, float val)
|
|
||||||
{
|
|
||||||
Name = _Name;
|
|
||||||
FloatVal = val;
|
|
||||||
}
|
|
||||||
public FloatTag(float _FloatVal) : this(null, _FloatVal)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public FloatTag() : this(null, 0f) { }
|
|
||||||
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.FLOAT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
FloatVal = br.ReadSingle();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new FloatTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
bw.Write(Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new FloatTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,293 +0,0 @@
|
||||||
using Microsoft.VisualBasic;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection.Metadata.Ecma335;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class Folder : Tag, ICollection<Tag>, ICollection
|
|
||||||
{
|
|
||||||
public Folder() { }
|
|
||||||
public Folder(string name)
|
|
||||||
{
|
|
||||||
this.Name = name;
|
|
||||||
}
|
|
||||||
public Collection<Tag> Tags { get; set; } = new Collection<Tag>();
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.FOLDER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Tags.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadOnly
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object SyncRoot
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (Tags as ICollection).SyncRoot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ICollection.IsSynchronized
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(Tag item)
|
|
||||||
{
|
|
||||||
if (item == null) throw new Exception("Bad item!");
|
|
||||||
|
|
||||||
Tags.Add(item);
|
|
||||||
item.Parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Tag this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Tags.ElementAt(index);
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
string TagName = Tags.ElementAt(index).Name;
|
|
||||||
this[TagName] = value;
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
Tags.Add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override Tag this[string index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Tags.Where(x => x.Name == index).FirstOrDefault();
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if(Tags.Select(x=>x.Name == index).Count() != 0)
|
|
||||||
{
|
|
||||||
Tags.RemoveAt(Tags.IndexOf(Tags.Where(x => x.Name == index).FirstOrDefault()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Tags.Add(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
foreach(Tag t in Tags)
|
|
||||||
{
|
|
||||||
t.Parent = null;
|
|
||||||
}
|
|
||||||
Tags = new Collection<Tag>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(Tag item)
|
|
||||||
{
|
|
||||||
return Tags.Contains(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(Tag[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
Tags.CopyTo(array, arrayIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(Array array, int index)
|
|
||||||
{
|
|
||||||
CopyTo((Tag[])array, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<Tag> GetEnumerator()
|
|
||||||
{
|
|
||||||
return Tags.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(Tag item)
|
|
||||||
{
|
|
||||||
return Tags.Remove(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
// Aria: Removed a return on parent not being null because that is how the ZNI Parsing system works.
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
TagType next = br.ReadTagType();
|
|
||||||
Tag _next = null;
|
|
||||||
switch (next)
|
|
||||||
{
|
|
||||||
case TagType.FOLDER:
|
|
||||||
_next = new Folder();
|
|
||||||
break;
|
|
||||||
case TagType.BYTE:
|
|
||||||
_next = new ByteTag();
|
|
||||||
break;
|
|
||||||
case TagType.DOUBLE:
|
|
||||||
_next = new DoubleTag();
|
|
||||||
break;
|
|
||||||
case TagType.FLOAT:
|
|
||||||
_next = new FloatTag();
|
|
||||||
break;
|
|
||||||
case TagType.INTEGER:
|
|
||||||
_next = new IntTag();
|
|
||||||
break;
|
|
||||||
case TagType.LIST:
|
|
||||||
_next = new ListTag();
|
|
||||||
break;
|
|
||||||
case TagType.LONG:
|
|
||||||
_next = new LongTag();
|
|
||||||
break;
|
|
||||||
case TagType.STRING:
|
|
||||||
_next = new StringTag();
|
|
||||||
break;
|
|
||||||
case TagType.BYTEARRAY:
|
|
||||||
_next = new ByteArrayTag();
|
|
||||||
break;
|
|
||||||
case TagType.INTARRAY:
|
|
||||||
_next = new IntArrayTag();
|
|
||||||
break;
|
|
||||||
case TagType.LONGARRAY:
|
|
||||||
_next = new LongArrayTag();
|
|
||||||
break;
|
|
||||||
case TagType.END:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case TagType.SHORT:
|
|
||||||
_next = new ShortTag();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_next.Parent = this;
|
|
||||||
|
|
||||||
if (_next.ReadTag(br))
|
|
||||||
{
|
|
||||||
if (_next.Type == TagType.FOLDER)
|
|
||||||
{
|
|
||||||
Folder NextTag = _next as Folder;
|
|
||||||
if (NextTag.HasNamedTag("_virtcast_"))
|
|
||||||
{
|
|
||||||
ByteTag bt = NextTag["_virtcast_"] as ByteTag;
|
|
||||||
next = (TagType)bt.Value;
|
|
||||||
Tag temp = null;
|
|
||||||
switch (next)
|
|
||||||
{
|
|
||||||
case TagType.BOOL:
|
|
||||||
temp = new BoolTag();
|
|
||||||
temp.CastFrom(NextTag);
|
|
||||||
break;
|
|
||||||
case TagType.ULONG:
|
|
||||||
temp = new uLongTag();
|
|
||||||
temp.CastFrom(NextTag);
|
|
||||||
break;
|
|
||||||
case TagType.UUID:
|
|
||||||
temp = new UUIDTag();
|
|
||||||
temp.CastFrom(NextTag);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_next = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Tags.Add(_next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasNamedTag(string Name)
|
|
||||||
{
|
|
||||||
foreach(Tag t in Tags)
|
|
||||||
{
|
|
||||||
if(t.Name == Name) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new Folder().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
foreach (Tag t in Tags)
|
|
||||||
{
|
|
||||||
t.WriteTag(bw);
|
|
||||||
t.WriteData(bw);
|
|
||||||
}
|
|
||||||
bw.Write(TagType.END);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type); // Write int (0), folder
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
// do nothing. The folder's collection will be automatically updated.
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new Folder(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Folder(Folder existing)
|
|
||||||
{
|
|
||||||
Name = existing.Name;
|
|
||||||
Tags = new Collection<Tag>(Tags.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class IntArrayTag : Tag
|
|
||||||
{
|
|
||||||
private int[] BArrVal;
|
|
||||||
public int[] Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BArrVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IntArrayTag(string _Name, int[] val)
|
|
||||||
{
|
|
||||||
Name = _Name;
|
|
||||||
BArrVal = val;
|
|
||||||
}
|
|
||||||
public IntArrayTag(int[] boolVal) : this(null, boolVal)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public IntArrayTag() : this(null, new int[] {}) { }
|
|
||||||
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.INTARRAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
|
|
||||||
int count = br.ReadInt32();
|
|
||||||
|
|
||||||
BArrVal = new int[count];
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
BArrVal[i] = br.ReadInt32();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new IntArrayTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
bw.Write(Value.Length);
|
|
||||||
|
|
||||||
foreach (int i in Value)
|
|
||||||
{
|
|
||||||
bw.Write(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new IntArrayTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class IntTag : Tag
|
|
||||||
{
|
|
||||||
|
|
||||||
public IntTag() : this(null, 0)
|
|
||||||
{ }
|
|
||||||
public IntTag(int Value) : this(null, Value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public IntTag(string _Name, int Val)
|
|
||||||
{
|
|
||||||
this.Name = _Name;
|
|
||||||
IntVal = Val;
|
|
||||||
}
|
|
||||||
private int IntVal;
|
|
||||||
public int Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return IntVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.INTEGER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
|
|
||||||
IntVal = br.ReadInt32();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new IntTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
bw.Write(Value);
|
|
||||||
}
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new IntTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,335 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class ListTag : Tag, IList<Tag>, IList
|
|
||||||
{
|
|
||||||
private TagType _subtype = TagType.INVALID;
|
|
||||||
private List<Tag> _tags;
|
|
||||||
public List<Tag> Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _tags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ListTag() : this(TagType.STRING, null, new List<Tag>())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public ListTag(TagType sub) : this(sub, null, new List<Tag>()) { }
|
|
||||||
public ListTag(TagType sub, string name) : this(sub,name, new List<Tag>()) { }
|
|
||||||
public ListTag(TagType sub, string name, List<Tag> tags)
|
|
||||||
{
|
|
||||||
_tags = tags;
|
|
||||||
Name = name;
|
|
||||||
setSubtype(sub);
|
|
||||||
}
|
|
||||||
public void setSubtype(TagType itemTypes)
|
|
||||||
{
|
|
||||||
_subtype = itemTypes;
|
|
||||||
}
|
|
||||||
public TagType getListType()
|
|
||||||
{
|
|
||||||
return _subtype;
|
|
||||||
}
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.LIST;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsFixedSize
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadOnly
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _tags.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSynchronized
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object SyncRoot
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ((IList)_tags).SyncRoot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object IList.this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _tags[index];
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_tags.Count >= index) _tags[index] = (Tag)value;
|
|
||||||
else _tags.Add((Tag)value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
//_subtype = (TagType)br.ReadInt32();
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
_subtype = br.ReadTagType();
|
|
||||||
int count = br.ReadInt32();
|
|
||||||
TagType next = _subtype;
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
Tag _next = null;
|
|
||||||
// read sub-tags
|
|
||||||
switch (next)
|
|
||||||
{
|
|
||||||
case TagType.FOLDER:
|
|
||||||
_next = new Folder();
|
|
||||||
break;
|
|
||||||
case TagType.BOOL:
|
|
||||||
_next = new BoolTag();
|
|
||||||
break;
|
|
||||||
case TagType.BYTE:
|
|
||||||
_next = new ByteTag();
|
|
||||||
break;
|
|
||||||
case TagType.DOUBLE:
|
|
||||||
_next = new DoubleTag();
|
|
||||||
break;
|
|
||||||
case TagType.FLOAT:
|
|
||||||
_next = new FloatTag();
|
|
||||||
break;
|
|
||||||
case TagType.INTEGER:
|
|
||||||
_next = new IntTag();
|
|
||||||
break;
|
|
||||||
case TagType.LIST:
|
|
||||||
_next = new ListTag();
|
|
||||||
break;
|
|
||||||
case TagType.LONG:
|
|
||||||
_next = new LongTag();
|
|
||||||
break;
|
|
||||||
case TagType.STRING:
|
|
||||||
_next = new StringTag();
|
|
||||||
break;
|
|
||||||
case TagType.BYTEARRAY:
|
|
||||||
_next = new ByteArrayTag();
|
|
||||||
break;
|
|
||||||
case TagType.INTARRAY:
|
|
||||||
_next = new IntArrayTag();
|
|
||||||
break;
|
|
||||||
case TagType.LONGARRAY:
|
|
||||||
_next = new LongArrayTag();
|
|
||||||
break;
|
|
||||||
case TagType.SHORT:
|
|
||||||
_next = new ShortTag();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_next.Parent = this;
|
|
||||||
if (_next.ReadTag(br))
|
|
||||||
{
|
|
||||||
if (_next.Type == TagType.FOLDER)
|
|
||||||
{
|
|
||||||
Folder nxt = _next as Folder;
|
|
||||||
if (nxt.HasNamedTag("_virtcast_"))
|
|
||||||
{
|
|
||||||
TagType tag = (TagType)nxt["_virtcast_"].ByteValue;
|
|
||||||
Tag temp = null;
|
|
||||||
switch (tag)
|
|
||||||
{
|
|
||||||
case TagType.BOOL:
|
|
||||||
temp = new BoolTag();
|
|
||||||
temp.CastFrom(nxt);
|
|
||||||
break;
|
|
||||||
case TagType.ULONG:
|
|
||||||
temp = new uLongTag();
|
|
||||||
temp.CastFrom(nxt);
|
|
||||||
break;
|
|
||||||
case TagType.UUID:
|
|
||||||
temp = new UUIDTag();
|
|
||||||
temp.CastFrom(nxt);
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
_next = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_tags.Add(_next);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new ListTag(_subtype).ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
bw.Write(_subtype);
|
|
||||||
bw.Write(_tags.Count);
|
|
||||||
|
|
||||||
foreach (Tag x in _tags)
|
|
||||||
{
|
|
||||||
x.WriteData(bw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type);
|
|
||||||
|
|
||||||
|
|
||||||
//bw.Write(((int)TagType.END));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Add(object value)
|
|
||||||
{
|
|
||||||
if (value is Tag)
|
|
||||||
{
|
|
||||||
Tag tx = (Tag)value;
|
|
||||||
Add(tx);
|
|
||||||
return _tags.IndexOf(tx);
|
|
||||||
}
|
|
||||||
else return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
foreach(Tag x in _tags)
|
|
||||||
{
|
|
||||||
x.Parent = null;
|
|
||||||
}
|
|
||||||
_tags.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(object value)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int IndexOf(object value)
|
|
||||||
{
|
|
||||||
if (!(value is Tag)) return -1;
|
|
||||||
return _tags.IndexOf((Tag)value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Insert(int index, object value)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Remove(object value)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveAt(int index)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(Array array, int index)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return _tags.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int IndexOf(Tag item)
|
|
||||||
{
|
|
||||||
return _tags.IndexOf(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Insert(int index, Tag item)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(Tag item)
|
|
||||||
{
|
|
||||||
item.Parent = this;
|
|
||||||
_tags.Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(Tag item)
|
|
||||||
{
|
|
||||||
return _tags.Contains(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(Tag[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(Tag item)
|
|
||||||
{
|
|
||||||
if (Contains(item))
|
|
||||||
{
|
|
||||||
item.Parent = null;
|
|
||||||
_tags.Remove(item);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator<Tag> IEnumerable<Tag>.GetEnumerator()
|
|
||||||
{
|
|
||||||
return _tags.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class LongArrayTag : Tag
|
|
||||||
{
|
|
||||||
private long[] BArrVal;
|
|
||||||
public long[] Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return BArrVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public LongArrayTag(string _Name, long[] val)
|
|
||||||
{
|
|
||||||
Name = _Name;
|
|
||||||
BArrVal = val;
|
|
||||||
}
|
|
||||||
public LongArrayTag(long[] boolVal) : this(null, boolVal)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public LongArrayTag() : this(null, new long[] {}) { }
|
|
||||||
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.LONGARRAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
int count = br.ReadVarInt();
|
|
||||||
BArrVal = new long[count];
|
|
||||||
for(int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
BArrVal[i] = br.ReadInt64();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new LongArrayTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
bw.Write(Value.Length);
|
|
||||||
|
|
||||||
foreach (long i in Value)
|
|
||||||
{
|
|
||||||
bw.Write(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new LongArrayTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class LongTag : Tag
|
|
||||||
{
|
|
||||||
private long LongVal;
|
|
||||||
public long Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return LongVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public LongTag(string _Name, long val)
|
|
||||||
{
|
|
||||||
Name = _Name;
|
|
||||||
LongVal = val;
|
|
||||||
}
|
|
||||||
public LongTag(long _LongVal) : this(null, _LongVal)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public LongTag() : this(null, 0) { }
|
|
||||||
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.LONG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
LongVal = br.ReadInt64();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new LongTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
|
|
||||||
bw.Write(Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new LongTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class ShortTag : Tag
|
|
||||||
{
|
|
||||||
private short FloatVal;
|
|
||||||
public short Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return FloatVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShortTag(string _Name, short val)
|
|
||||||
{
|
|
||||||
Name = _Name;
|
|
||||||
FloatVal = val;
|
|
||||||
}
|
|
||||||
public ShortTag(short _FloatVal) : this(null, _FloatVal)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public ShortTag() : this(null, 0) { }
|
|
||||||
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.SHORT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
FloatVal = br.ReadInt16();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new ShortTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
|
|
||||||
bw.Write(Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new ShortTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class StringTag : Tag
|
|
||||||
{
|
|
||||||
private string StrVal;
|
|
||||||
public string Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return StrVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.STRING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringTag() : this(null, "")
|
|
||||||
{ }
|
|
||||||
public StringTag(string Value) : this(null, Value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public StringTag(string _Name, string Val)
|
|
||||||
{
|
|
||||||
this.Name = _Name;
|
|
||||||
StrVal = Val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
Name = br.ReadString();
|
|
||||||
StrVal = br.ReadString();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new StringTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
if (!(Parent != null && Parent.Type == TagType.LIST))
|
|
||||||
bw.Write(Name);
|
|
||||||
|
|
||||||
bw.Write(StrVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
bw.Write(Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new StringTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,268 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public abstract class Tag : ICloneable, IComparable<Tag>
|
|
||||||
{
|
|
||||||
public Tag Parent { get; internal set; }
|
|
||||||
public abstract TagType Type { get; }
|
|
||||||
|
|
||||||
public bool HasValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch(Type)
|
|
||||||
{
|
|
||||||
case TagType.FOLDER:
|
|
||||||
case TagType.LIST:
|
|
||||||
case TagType.END:
|
|
||||||
case TagType.INVALID:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal string _Name="";
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _Name;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_Name == value) return;
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
value = "";
|
|
||||||
}
|
|
||||||
Folder f = Parent as Folder;
|
|
||||||
if(f != null)
|
|
||||||
{
|
|
||||||
f.Rename(_Name, value);
|
|
||||||
}
|
|
||||||
_Name = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract bool ReadTag(NBTReader br);
|
|
||||||
public abstract void SkipTag(NBTReader br);
|
|
||||||
public abstract void WriteTag(NBTWriter bw);
|
|
||||||
public abstract void WriteData(NBTWriter bw);
|
|
||||||
|
|
||||||
public abstract void CastFrom(Folder F);
|
|
||||||
|
|
||||||
private string Error = "Invalid tag type";
|
|
||||||
public virtual Tag this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(Error);
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Tag this[string index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(Error);
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetCanonicalName(TagType type)
|
|
||||||
{
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case TagType.FOLDER:
|
|
||||||
{
|
|
||||||
return "Folder";
|
|
||||||
}
|
|
||||||
case TagType.STRING:
|
|
||||||
{
|
|
||||||
return "String";
|
|
||||||
}
|
|
||||||
case TagType.INTEGER:
|
|
||||||
{
|
|
||||||
return "Integer";
|
|
||||||
}
|
|
||||||
case TagType.LIST:
|
|
||||||
{
|
|
||||||
return "List";
|
|
||||||
}
|
|
||||||
case TagType.BOOL:
|
|
||||||
{
|
|
||||||
return "Bool";
|
|
||||||
}
|
|
||||||
case TagType.DOUBLE:
|
|
||||||
{
|
|
||||||
return "Double";
|
|
||||||
}
|
|
||||||
case TagType.FLOAT:
|
|
||||||
{
|
|
||||||
return "Float";
|
|
||||||
}
|
|
||||||
case TagType.LONG:
|
|
||||||
{
|
|
||||||
return "Long";
|
|
||||||
}
|
|
||||||
case TagType.BYTE:
|
|
||||||
{
|
|
||||||
return "Invalid";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "Invalid";
|
|
||||||
}
|
|
||||||
|
|
||||||
public string StringValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch(Type)
|
|
||||||
{
|
|
||||||
case TagType.STRING:
|
|
||||||
{
|
|
||||||
return (this as StringTag).Value;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
throw new Exception("Invalid type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int IntValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case TagType.INTEGER:
|
|
||||||
return (this as IntTag).Value;
|
|
||||||
default:
|
|
||||||
throw new Exception("Invalid type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool BoolValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case TagType.BOOL:
|
|
||||||
return (this as BoolTag).Value;
|
|
||||||
default:
|
|
||||||
throw new Exception("Invalid type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public double DoubleValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case TagType.DOUBLE:
|
|
||||||
return (this as DoubleTag).Value;
|
|
||||||
default:
|
|
||||||
throw new Exception("Invalid type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public float FloatValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case TagType.FLOAT:
|
|
||||||
return (this as FloatTag).Value;
|
|
||||||
default:
|
|
||||||
throw new Exception("Invalid type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public long LongValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case TagType.LONG:
|
|
||||||
return (this as LongTag).Value;
|
|
||||||
default:
|
|
||||||
throw new Exception("Invalid type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public byte ByteValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case TagType.BYTE:
|
|
||||||
return (this as ByteTag).Value;
|
|
||||||
default:
|
|
||||||
throw new Exception("Invalid type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public ulong uLongValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case TagType.ULONG:
|
|
||||||
return (this as uLongTag).Value;
|
|
||||||
default:
|
|
||||||
throw new Exception("Invalid type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public Guid UUIDValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case TagType.UUID:
|
|
||||||
return (this as UUIDTag).Value;
|
|
||||||
default:
|
|
||||||
throw new Exception("Invalid type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void Rename(string old, string newName);
|
|
||||||
|
|
||||||
public abstract object Clone();
|
|
||||||
|
|
||||||
public int CompareTo(Tag other)
|
|
||||||
{
|
|
||||||
if (ID == other.ID) return 0;
|
|
||||||
else return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Guid ID { get; set; } = Guid.NewGuid();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
// Aria: Changed to a type of byte which keeps it to only one byte when writing out in serializing
|
|
||||||
public enum TagType : byte
|
|
||||||
{
|
|
||||||
END = 0x00, // Present at the end of a folder
|
|
||||||
BYTE = 0x01,
|
|
||||||
SHORT = 0x02,
|
|
||||||
INTEGER = 0x03,
|
|
||||||
LONG = 0x04,
|
|
||||||
FLOAT = 0x05,
|
|
||||||
DOUBLE = 0x06,
|
|
||||||
BYTEARRAY = 0x07,
|
|
||||||
STRING = 0x08,
|
|
||||||
LIST = 0x09, // List can be any valid Tag Type
|
|
||||||
FOLDER = 0x0A,
|
|
||||||
INTARRAY = 0x0B,
|
|
||||||
LONGARRAY = 0x0C,
|
|
||||||
BOOL = 0x0D,
|
|
||||||
ULONG=0x0E,
|
|
||||||
UUID=0x0F,
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
INVALID=0xFF
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,100 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class UUIDTag : Tag
|
|
||||||
{
|
|
||||||
private Guid LongVal;
|
|
||||||
public Guid Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return LongVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static UUIDTag Random(string sName)
|
|
||||||
{
|
|
||||||
UUIDTag rnd = new UUIDTag(sName, Guid.NewGuid());
|
|
||||||
|
|
||||||
return rnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UUIDTag Empty(string sName)
|
|
||||||
{
|
|
||||||
UUIDTag z = new UUIDTag(sName, Guid.Empty);
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUIDTag(string _Name, Guid val)
|
|
||||||
{
|
|
||||||
Name = _Name;
|
|
||||||
LongVal = val;
|
|
||||||
}
|
|
||||||
public UUIDTag(Guid _LongVal) : this(null, _LongVal)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public UUIDTag() : this(null, Guid.Empty) { }
|
|
||||||
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.UUID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
throw new Exception("Must be virtcasted!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new UUIDTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
Folder vCast = new Folder(Name);
|
|
||||||
vCast.Add(new ByteTag("_virtcast_", (byte)Type));
|
|
||||||
vCast.Add(new ByteArrayTag("val", Value.ToByteArray()));
|
|
||||||
if (Parent != null)
|
|
||||||
{
|
|
||||||
if (Parent.Type == TagType.LIST)
|
|
||||||
{
|
|
||||||
vCast.Add(new StringTag("name", Name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vCast.WriteTag(bw);
|
|
||||||
vCast.WriteData(bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new UUIDTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
if (!F.HasNamedTag("name"))
|
|
||||||
Name = F.Name;
|
|
||||||
else Name = F["name"].StringValue;
|
|
||||||
ByteArrayTag bat = F["val"] as ByteArrayTag;
|
|
||||||
LongVal = new Guid(bat.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace LibAC.Serialization.ACFile
|
|
||||||
{
|
|
||||||
public class uLongTag : Tag
|
|
||||||
{
|
|
||||||
private ulong LongVal;
|
|
||||||
public ulong Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return LongVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public uLongTag(string _Name, ulong val)
|
|
||||||
{
|
|
||||||
Name = _Name;
|
|
||||||
LongVal = val;
|
|
||||||
}
|
|
||||||
public uLongTag(ulong _LongVal) : this(null, _LongVal)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public uLongTag() : this(null, 0) { }
|
|
||||||
|
|
||||||
public override TagType Type
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return TagType.ULONG;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ReadTag(NBTReader br)
|
|
||||||
{
|
|
||||||
throw new Exception("Not allowed"); // This type must be virtual casted
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Rename(string old, string newName)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SkipTag(NBTReader br)
|
|
||||||
{
|
|
||||||
_ = new uLongTag().ReadTag(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteData(NBTWriter bw)
|
|
||||||
{
|
|
||||||
Folder vCast = new Folder(Name);
|
|
||||||
vCast.Add(new ByteTag("_virtcast_", (byte)Type));
|
|
||||||
vCast.Add(new StringTag("val", Value.ToString()));
|
|
||||||
if (Parent != null)
|
|
||||||
{
|
|
||||||
if (Parent.Type == TagType.LIST)
|
|
||||||
{
|
|
||||||
vCast.Add(new StringTag("name", Name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vCast.WriteTag(bw);
|
|
||||||
vCast.WriteData(bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteTag(NBTWriter bw)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object Clone()
|
|
||||||
{
|
|
||||||
return new uLongTag(Name, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void CastFrom(Folder F)
|
|
||||||
{
|
|
||||||
if (!F.HasNamedTag("name"))
|
|
||||||
Name = F.Name;
|
|
||||||
else Name = F["name"].StringValue;
|
|
||||||
LongVal = ulong.Parse(F["val"].StringValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
146
Utilities/UUID.cs
Normal file
146
Utilities/UUID.cs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace LibAC.Utilities
|
||||||
|
{
|
||||||
|
public class UUID
|
||||||
|
{
|
||||||
|
private readonly byte[] _bytes;
|
||||||
|
|
||||||
|
public static readonly UUID ZERO = UUID.Generate(0);
|
||||||
|
|
||||||
|
public UUID(byte[] bytes)
|
||||||
|
{
|
||||||
|
_bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Validate(string uuid)
|
||||||
|
{
|
||||||
|
return uuid.Length == (16 * 2) + 4; // Basic length check
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UUID Parse(string uuid)
|
||||||
|
{
|
||||||
|
if (Validate(uuid))
|
||||||
|
{
|
||||||
|
string[] segments = uuid.Split('-');
|
||||||
|
if (segments.Length != 5)
|
||||||
|
{
|
||||||
|
throw new FormatException("Invalid UUID format");
|
||||||
|
}
|
||||||
|
|
||||||
|
string msbString = string.Join("", segments.Take(3));
|
||||||
|
string lsbString = string.Join("", segments.Skip(3));
|
||||||
|
|
||||||
|
byte[] byteArray = new byte[16];
|
||||||
|
int i = 0;
|
||||||
|
for (i = 0; i < msbString.Length; i += 2)
|
||||||
|
{
|
||||||
|
byteArray[i / 2] = Convert.ToByte(msbString.Substring(i, 2), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < lsbString.Length; i += 2)
|
||||||
|
{
|
||||||
|
byteArray[msbString.Length / 2 + i / 2] = Convert.ToByte(lsbString.Substring(i, 2), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new UUID(byteArray);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringBuilder hexBuilder = new StringBuilder();
|
||||||
|
foreach (byte b in _bytes)
|
||||||
|
{
|
||||||
|
hexBuilder.Append(b.ToString("x2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{hexBuilder.ToString().Substring(0, 8)}-{hexBuilder.ToString().Substring(8, 4)}-{hexBuilder.ToString().Substring(12, 4)}-{hexBuilder.ToString().Substring(16, 4)}-{hexBuilder.ToString().Substring(20, 12)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UUID Generate(int version, params object[] parameters)
|
||||||
|
{
|
||||||
|
if (version != 4 && version != 0 && version != 3 && version != 5)
|
||||||
|
{
|
||||||
|
return Generate(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] bytes0 = new byte[16];
|
||||||
|
|
||||||
|
|
||||||
|
switch (version)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return new UUID(bytes0);
|
||||||
|
case 3:
|
||||||
|
if (parameters.Length != 2)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("UUID v3 requires two parameters: [namespace, name]");
|
||||||
|
}
|
||||||
|
|
||||||
|
string namespaceStr = parameters[0] as string;
|
||||||
|
string nameStr = parameters[1] as string;
|
||||||
|
|
||||||
|
using (MD5 md5 = MD5.Create())
|
||||||
|
{
|
||||||
|
byte[] namespaceBytes = Encoding.UTF8.GetBytes(namespaceStr);
|
||||||
|
byte[] nameBytes = Encoding.UTF8.GetBytes(nameStr);
|
||||||
|
byte[] combined = namespaceBytes.Concat(nameBytes).ToArray();
|
||||||
|
|
||||||
|
byte[] hash = md5.ComputeHash(combined);
|
||||||
|
|
||||||
|
Array.Copy(hash, 0, bytes0, 0, 16);
|
||||||
|
bytes0[6] = (byte)(bytes0[6] & 0x0F | 0x30); // Set version to 3
|
||||||
|
bytes0[8] = (byte)(bytes0[8] & 0x3F | 0x80); // Set variant to RFC4122
|
||||||
|
return new UUID(bytes0);
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
|
||||||
|
{
|
||||||
|
byte[] bytes4 = new byte[16];
|
||||||
|
rng.GetBytes(bytes4);
|
||||||
|
bytes4[6] = (byte)(bytes4[6] & 0x0F | 0x40); // Set version to 4
|
||||||
|
bytes4[8] = (byte)(bytes4[8] & 0x3F | 0x80); // Set variant to RFC4122
|
||||||
|
return new UUID(bytes4);
|
||||||
|
}
|
||||||
|
case 5:
|
||||||
|
if (parameters.Length != 2)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("UUID v5 requires two parameters: [namespace, name]");
|
||||||
|
}
|
||||||
|
|
||||||
|
string namespaceStr5 = parameters[0] as string;
|
||||||
|
string nameStr5 = parameters[1] as string;
|
||||||
|
|
||||||
|
using (SHA1 sha1 = SHA1.Create())
|
||||||
|
{
|
||||||
|
byte[] namespaceBytes5 = Encoding.UTF8.GetBytes(namespaceStr5);
|
||||||
|
byte[] nameBytes5 = Encoding.UTF8.GetBytes(nameStr5);
|
||||||
|
byte[] combined5 = namespaceBytes5.Concat(nameBytes5).ToArray();
|
||||||
|
|
||||||
|
byte[] hash = sha1.ComputeHash(combined5);
|
||||||
|
|
||||||
|
byte[] bytes5 = new byte[16];
|
||||||
|
Array.Copy(hash, 0, bytes5, 0, 16);
|
||||||
|
bytes5[6] = (byte)(bytes5[6] & 0x0F | 0x50); // Set version to 5
|
||||||
|
bytes5[8] = (byte)(bytes5[8] & 0x3F | 0x80); // Set variant to RFC4122
|
||||||
|
return new UUID(bytes5);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Unsupported UUID version: {version}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetBytes()
|
||||||
|
{
|
||||||
|
return _bytes.Take(16).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
90
Utilities/Vector2d.cs
Normal file
90
Utilities/Vector2d.cs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LibAC.Utilities
|
||||||
|
{
|
||||||
|
public class Vector2d
|
||||||
|
{
|
||||||
|
public static readonly Vector2d ZERO = new Vector2d(0, 0);
|
||||||
|
public double X { get; set; }
|
||||||
|
public double Z { get; set; }
|
||||||
|
|
||||||
|
public Vector2d(double X = 0.0, double Z = 0.0)
|
||||||
|
{
|
||||||
|
this.X = X;
|
||||||
|
this.Z = Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object other)
|
||||||
|
{
|
||||||
|
if (other is Vector2d)
|
||||||
|
{
|
||||||
|
Vector2d otherVector = (Vector2d)other;
|
||||||
|
return X == otherVector.X && Z == otherVector.Z;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2d operator +(Vector2d v1, Vector2d v2)
|
||||||
|
{
|
||||||
|
Vector2d result = v1.Clone();
|
||||||
|
result.X += v2.X;
|
||||||
|
result.Z += v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2d operator -(Vector2d v1, Vector2d v2)
|
||||||
|
{
|
||||||
|
Vector2d result = v1.Clone();
|
||||||
|
result.X -= v2.X;
|
||||||
|
result.Z -= v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2d operator *(Vector2d v1, Vector2d v2)
|
||||||
|
{
|
||||||
|
Vector2d result = v1.Clone();
|
||||||
|
result.X *= v2.X;
|
||||||
|
result.Z *= v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2d operator /(Vector2d v1, Vector2d v2)
|
||||||
|
{
|
||||||
|
Vector2d result = v1.Clone();
|
||||||
|
result.X /= v2.X;
|
||||||
|
result.Z /= v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator >(Vector2d v1, Vector2d v2)
|
||||||
|
{
|
||||||
|
return (v1.X > v2.X) || (v1.X > v2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator <(Vector2d v1, Vector2d v2)
|
||||||
|
{
|
||||||
|
return (v1.X < v2.X) || (v1.X < v2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2d Clone()
|
||||||
|
{
|
||||||
|
return new Vector2d(X, Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"<{X}, {Z}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Inside(Vector2d min, Vector2d max)
|
||||||
|
{
|
||||||
|
return (min.X <= X && max.X >= X) && (min.Z <= Z && max.Z >= Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override GetHashCode if you override Equals
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(X, Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
90
Utilities/Vector2i.cs
Normal file
90
Utilities/Vector2i.cs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LibAC.Utilities
|
||||||
|
{
|
||||||
|
public class Vector2i
|
||||||
|
{
|
||||||
|
public static readonly Vector2i ZERO = new Vector2i(0, 0);
|
||||||
|
public int X { get; set; }
|
||||||
|
public int Z { get; set; }
|
||||||
|
|
||||||
|
public Vector2i(int X = 0, int Z = 0)
|
||||||
|
{
|
||||||
|
this.X = X;
|
||||||
|
this.Z = Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object other)
|
||||||
|
{
|
||||||
|
if (other is Vector2i)
|
||||||
|
{
|
||||||
|
Vector2i otherVector = (Vector2i)other;
|
||||||
|
return X == otherVector.X && Z == otherVector.Z;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2i operator +(Vector2i v1, Vector2i v2)
|
||||||
|
{
|
||||||
|
Vector2i result = v1.Clone();
|
||||||
|
result.X += v2.X;
|
||||||
|
result.Z += v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2i operator -(Vector2i v1, Vector2i v2)
|
||||||
|
{
|
||||||
|
Vector2i result = v1.Clone();
|
||||||
|
result.X -= v2.X;
|
||||||
|
result.Z -= v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2i operator *(Vector2i v1, Vector2i v2)
|
||||||
|
{
|
||||||
|
Vector2i result = v1.Clone();
|
||||||
|
result.X *= v2.X;
|
||||||
|
result.Z *= v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2i operator /(Vector2i v1, Vector2i v2)
|
||||||
|
{
|
||||||
|
Vector2i result = v1.Clone();
|
||||||
|
result.X = (int)Math.Round((double)v1.X / v2.X);
|
||||||
|
result.Z = (int)Math.Round((double)v1.Z / v2.Z);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator >(Vector2i v1, Vector2i v2)
|
||||||
|
{
|
||||||
|
return (v1.X > v2.X) || (v1.X > v2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator <(Vector2i v1, Vector2i v2)
|
||||||
|
{
|
||||||
|
return (v1.X < v2.X) || (v1.X < v2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2i Clone()
|
||||||
|
{
|
||||||
|
return new Vector2i(X, Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"<{X}, {Z}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Inside(Vector2i min, Vector2i max)
|
||||||
|
{
|
||||||
|
return (min.X <= X && max.X >= X) && (min.Z <= Z && max.Z >= Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override GetHashCode if you override Equals
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(X, Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
96
Utilities/Vector3d.cs
Normal file
96
Utilities/Vector3d.cs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LibAC.Utilities
|
||||||
|
{
|
||||||
|
public class Vector3d
|
||||||
|
{
|
||||||
|
public static readonly Vector3d ZERO = new Vector3d(0, 0, 0);
|
||||||
|
public double X { get; set; }
|
||||||
|
public double Y { get; set; }
|
||||||
|
public double Z { get; set; }
|
||||||
|
|
||||||
|
public Vector3d(double X = 0.0, double Y = 0.0, double Z = 0.0)
|
||||||
|
{
|
||||||
|
this.X = X;
|
||||||
|
this.Y = Y;
|
||||||
|
this.Z = Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object other)
|
||||||
|
{
|
||||||
|
if (other is Vector3d)
|
||||||
|
{
|
||||||
|
Vector3d otherVector = (Vector3d)other;
|
||||||
|
return X == otherVector.X && Y == otherVector.Y && Z == otherVector.Z;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3d operator +(Vector3d v1, Vector3d v2)
|
||||||
|
{
|
||||||
|
Vector3d result = v1.Clone();
|
||||||
|
result.X += v2.X;
|
||||||
|
result.Y += v2.Y;
|
||||||
|
result.Z += v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3d operator -(Vector3d v1, Vector3d v2)
|
||||||
|
{
|
||||||
|
Vector3d result = v1.Clone();
|
||||||
|
result.X -= v2.X;
|
||||||
|
result.Y -= v2.Y;
|
||||||
|
result.Z -= v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3d operator *(Vector3d v1, Vector3d v2)
|
||||||
|
{
|
||||||
|
Vector3d result = v1.Clone();
|
||||||
|
result.X *= v2.X;
|
||||||
|
result.Y *= v2.Y;
|
||||||
|
result.Z *= v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3d operator /(Vector3d v1, Vector3d v2)
|
||||||
|
{
|
||||||
|
Vector3d result = v1.Clone();
|
||||||
|
result.X /= v2.X;
|
||||||
|
result.Y /= v2.Y;
|
||||||
|
result.Z /= v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator >(Vector3d v1, Vector3d v2)
|
||||||
|
{
|
||||||
|
return (v1.X > v2.X) || (v1.Y > v2.Y) || (v1.X > v2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator <(Vector3d v1, Vector3d v2)
|
||||||
|
{
|
||||||
|
return (v1.X < v2.X) || (v1.Y < v2.Y) || (v1.X < v2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3d Clone()
|
||||||
|
{
|
||||||
|
return new Vector3d(X, Y, Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"<{X}, {Y}, {Z}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Inside(Vector3d min, Vector3d max)
|
||||||
|
{
|
||||||
|
return (min.X <= X && max.X >= X) && (min.Y <= Y && max.Y >= Y) && (min.Z <= Z && max.Z >= Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override GetHashCode if you override Equals
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(X, Y, Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
96
Utilities/Vector3i.cs
Normal file
96
Utilities/Vector3i.cs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LibAC.Utilities
|
||||||
|
{
|
||||||
|
public class Vector3i
|
||||||
|
{
|
||||||
|
public static readonly Vector3i ZERO = new Vector3i(0, 0, 0);
|
||||||
|
public int X { get; set; }
|
||||||
|
public int Y { get; set; }
|
||||||
|
public int Z { get; set; }
|
||||||
|
|
||||||
|
public Vector3i(int X = 0, int Y = 0, int Z = 0)
|
||||||
|
{
|
||||||
|
this.X = X;
|
||||||
|
this.Y = Y;
|
||||||
|
this.Z = Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object other)
|
||||||
|
{
|
||||||
|
if (other is Vector3i)
|
||||||
|
{
|
||||||
|
Vector3i otherVector = (Vector3i)other;
|
||||||
|
return X == otherVector.X && Y == otherVector.Y && Z == otherVector.Z;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3i operator +(Vector3i v1, Vector3i v2)
|
||||||
|
{
|
||||||
|
Vector3i result = v1.Clone();
|
||||||
|
result.X += v2.X;
|
||||||
|
result.Y += v2.Y;
|
||||||
|
result.Z += v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3i operator -(Vector3i v1, Vector3i v2)
|
||||||
|
{
|
||||||
|
Vector3i result = v1.Clone();
|
||||||
|
result.X -= v2.X;
|
||||||
|
result.Y -= v2.Y;
|
||||||
|
result.Z -= v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3i operator *(Vector3i v1, Vector3i v2)
|
||||||
|
{
|
||||||
|
Vector3i result = v1.Clone();
|
||||||
|
result.X *= v2.X;
|
||||||
|
result.Y *= v2.Y;
|
||||||
|
result.Z *= v2.Z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3i operator /(Vector3i v1, Vector3i v2)
|
||||||
|
{
|
||||||
|
Vector3i result = v1.Clone();
|
||||||
|
result.X = (int)Math.Round((double)result.X / v2.X);
|
||||||
|
result.Y = (int)Math.Round((double)result.Y / v2.Y);
|
||||||
|
result.Z = (int)Math.Round((double)result.Z / v2.Z);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator >(Vector3i v1, Vector3i v2)
|
||||||
|
{
|
||||||
|
return (v1.X > v2.X) || (v1.Y > v2.Y) || (v1.X > v2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator <(Vector3i v1, Vector3i v2)
|
||||||
|
{
|
||||||
|
return (v1.X < v2.X) || (v1.Y < v2.Y) || (v1.X < v2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3i Clone()
|
||||||
|
{
|
||||||
|
return new Vector3i(X, Y, Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"<{X}, {Y}, {Z}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Inside(Vector3i min, Vector3i max)
|
||||||
|
{
|
||||||
|
return (min.X <= X && max.X >= X) && (min.Y <= Y && max.Y >= Y) && (min.Z <= Z && max.Z >= Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override GetHashCode if you override Equals
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(X, Y, Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
using LibAC.Serialization;
|
using System;
|
||||||
using LibAC.Serialization.ACFile;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime;
|
using System.Runtime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using LibAC.NBT;
|
||||||
|
using LibAC.NBT.API;
|
||||||
|
|
||||||
namespace LibAC
|
namespace LibAC
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@ namespace LibAC
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class Version : Serializable
|
public class Version
|
||||||
{
|
{
|
||||||
public List<int> ver { get; set; } = new List<int>();
|
public List<int> ver { get; set; } = new List<int>();
|
||||||
|
|
||||||
|
@ -104,26 +104,28 @@ namespace LibAC
|
||||||
|
|
||||||
return $"{ver[0]}.{ver[1]}.{ver[2]}.{ver[3]}.{CYCLE}.{ver[5]}";
|
return $"{ver[0]}.{ver[1]}.{ver[2]}.{ver[3]}.{CYCLE}.{ver[5]}";
|
||||||
}
|
}
|
||||||
public override void load(Folder f)
|
public void load(CompoundTag f)
|
||||||
{
|
{
|
||||||
ListTag lt = f["Version"] as ListTag;
|
ListTag lt = f["Version"] as ListTag;
|
||||||
ver = new List<int>();
|
ver = new List<int>();
|
||||||
foreach(Tag tag in lt)
|
foreach(Tag tag in lt.GetList)
|
||||||
{
|
{
|
||||||
IntTag it = tag as IntTag;
|
IntTag it = tag as IntTag;
|
||||||
ver.Add(it.IntValue);
|
ver.Add(it.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void save(Folder f)
|
public CompoundTag save()
|
||||||
{
|
{
|
||||||
ListTag lt = new ListTag(TagType.INTEGER, "Version");
|
CompoundTag ct = new CompoundTag();
|
||||||
|
ListTag lt = new ListTag();
|
||||||
foreach(int v in ver)
|
foreach(int v in ver)
|
||||||
{
|
{
|
||||||
IntTag i = new IntTag(v);
|
IntTag i = IntTag.ValueOf(v);
|
||||||
lt.Add(i);
|
lt.Add(i);
|
||||||
}
|
}
|
||||||
f.Add(lt);
|
ct.Put("Version", lt);
|
||||||
|
return ct;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue