mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 10:46:17 +00:00
简单提交
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using JNGame.Runtime.Util;
|
||||
using JNGame.Util;
|
||||
|
||||
namespace JNGame.Serialization
|
||||
{
|
||||
[Serializable]
|
||||
public partial class BaseFormater : ISerializable, ISerializablePacket
|
||||
{
|
||||
public virtual void Serialize(Serializer writer) { }
|
||||
|
||||
public virtual void Deserialize(Deserializer reader) { }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return JsonUtil.ToJson(this);
|
||||
}
|
||||
|
||||
public byte[] ToBytes()
|
||||
{
|
||||
var writer = new Serializer();
|
||||
Serialize(writer);
|
||||
var bytes = writer.CopyData(); // Compressor.Compress(writer.CopyData());
|
||||
return bytes;
|
||||
}
|
||||
public void FromBytes(byte[] data)
|
||||
{
|
||||
var bytes = data; //Compressor.Decompress(data);
|
||||
var reader = new Deserializer(bytes);
|
||||
Deserialize(reader);
|
||||
}
|
||||
public void FromBytes(byte[] data, int offset, int size)
|
||||
{
|
||||
var bytes = data; //Compressor.Decompress(data);
|
||||
var reader = new Deserializer(bytes, offset, size);
|
||||
Deserialize(reader);
|
||||
}
|
||||
|
||||
public static T FromBytes<T>(byte[] data) where T : BaseFormater, new()
|
||||
{
|
||||
var ret = new T();
|
||||
ret.FromBytes(data, 0, data.Length);
|
||||
return ret;
|
||||
}
|
||||
public static T FromBytes<T>(byte[] data, int offset, int size) where T : BaseFormater, new()
|
||||
{
|
||||
var ret = new T();
|
||||
ret.FromBytes(data, offset, size);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 601c581990ac843e7a62fa8a4cffb197
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
|
||||
namespace JNGame.Serialization
|
||||
{
|
||||
public class ByteHelper
|
||||
{
|
||||
public static void CopyBytes(short value, byte[] buffer, int index)
|
||||
{
|
||||
CopyBytesImpl(value, 2, buffer, index);
|
||||
}
|
||||
|
||||
/// Copies the specified 32-bit signed integer value into the specified byte array,
|
||||
/// beginning at the specified index.
|
||||
public static void CopyBytes(int value, byte[] buffer, int index)
|
||||
{
|
||||
CopyBytesImpl(value, 4, buffer, index);
|
||||
}
|
||||
|
||||
protected static void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
|
||||
{
|
||||
for (var i = 0; i < bytes; i++)
|
||||
{
|
||||
buffer[i + index] = unchecked((byte)(value & 0xff));
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.
|
||||
public static short ToInt16(byte[] value, int startIndex)
|
||||
{
|
||||
return unchecked((short)CheckedFromBytes(value, startIndex, 2));
|
||||
}
|
||||
|
||||
/// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.
|
||||
public static int ToInt32(byte[] value, int startIndex)
|
||||
{
|
||||
return unchecked((int)CheckedFromBytes(value, startIndex, 4));
|
||||
}
|
||||
|
||||
private static long CheckedFromBytes(byte[] buffer, int startIndex, int bytesToConvert)
|
||||
{
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException("buffer");
|
||||
if ((startIndex < 0) || (startIndex > buffer.Length - bytesToConvert))
|
||||
throw new ArgumentOutOfRangeException("startIndex");
|
||||
long ret = 0;
|
||||
for (var i = 0; i < bytesToConvert; i++)
|
||||
ret = unchecked((ret << 8) | buffer[startIndex + bytesToConvert - 1 - i]);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 844fb1126baf449dd93750b0e4ffad15
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,49 @@
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace JNGame.Serialization
|
||||
{
|
||||
public static class Compressor
|
||||
{
|
||||
|
||||
public static byte[] Compress(byte[] data)
|
||||
{
|
||||
using (var output = new MemoryStream())
|
||||
{
|
||||
using (var dstream = new DeflateStream(output, CompressionLevel.Optimal))
|
||||
{
|
||||
dstream.Write(data, 0, data.Length);
|
||||
}
|
||||
return output.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Compress(Serializer serializer)
|
||||
{
|
||||
using (var output = new MemoryStream())
|
||||
{
|
||||
using (var dstream = new DeflateStream(output, CompressionLevel.Optimal))
|
||||
{
|
||||
dstream.Write(serializer.Data, 0, serializer.Length);
|
||||
}
|
||||
return output.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Decompress(byte[] data)
|
||||
{
|
||||
using (var input = new MemoryStream(data))
|
||||
{
|
||||
using (var output = new MemoryStream())
|
||||
{
|
||||
using (var dstream = new DeflateStream(input, CompressionMode.Decompress))
|
||||
{
|
||||
dstream.CopyTo(output);
|
||||
}
|
||||
return output.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41476905d95bf4bddbe138f884a4db5d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,832 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace JNGame.Serialization
|
||||
{
|
||||
public delegate uint FuncReadSlot(uint vTblOffset, int idx);
|
||||
|
||||
public class Deserializer
|
||||
{
|
||||
protected byte[] _data;
|
||||
protected int _position;
|
||||
protected int _dataSize;
|
||||
private int _offset;
|
||||
|
||||
public byte[] RawData
|
||||
{
|
||||
get { return _data; }
|
||||
}
|
||||
|
||||
public int RawDataSize
|
||||
{
|
||||
get { return _dataSize; }
|
||||
}
|
||||
|
||||
public int UserDataOffset
|
||||
{
|
||||
get { return _offset; }
|
||||
}
|
||||
|
||||
public int UserDataSize
|
||||
{
|
||||
get { return _dataSize - _offset; }
|
||||
}
|
||||
|
||||
public bool IsNull
|
||||
{
|
||||
get { return _data == null; }
|
||||
}
|
||||
|
||||
public int Position
|
||||
{
|
||||
get { return _position; }
|
||||
}
|
||||
|
||||
public void SetPosition(int pos)
|
||||
{
|
||||
_position = pos;
|
||||
}
|
||||
|
||||
public bool SkipLen(long len)
|
||||
{
|
||||
var dst = _position + len;
|
||||
if (dst > _dataSize)
|
||||
{
|
||||
throw new Exception(
|
||||
$"Skip len is out of range _dataSize:{_dataSize} _position:{_position} skipLen:{len}");
|
||||
}
|
||||
|
||||
_position += (int)len;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool EndOfData
|
||||
{
|
||||
get { return _position == _dataSize; }
|
||||
}
|
||||
|
||||
public int AvailableBytes
|
||||
{
|
||||
get { return _dataSize - _position; }
|
||||
}
|
||||
|
||||
public bool IsEnd
|
||||
{
|
||||
get { return _dataSize == _position; }
|
||||
}
|
||||
|
||||
public void SetSource(Serializer dataWriter)
|
||||
{
|
||||
_data = dataWriter.Data;
|
||||
_position = 0;
|
||||
_offset = 0;
|
||||
_dataSize = dataWriter.Length;
|
||||
}
|
||||
|
||||
public void SetSource(byte[] source)
|
||||
{
|
||||
_data = source;
|
||||
_position = 0;
|
||||
_offset = 0;
|
||||
_dataSize = source.Length;
|
||||
}
|
||||
|
||||
public void SetSource(byte[] source, int offset)
|
||||
{
|
||||
_data = source;
|
||||
_position = offset;
|
||||
_offset = offset;
|
||||
_dataSize = source.Length;
|
||||
}
|
||||
|
||||
public void SetSource(byte[] source, int offset, int maxSize)
|
||||
{
|
||||
_data = source;
|
||||
_position = offset;
|
||||
_offset = offset;
|
||||
_dataSize = maxSize;
|
||||
}
|
||||
|
||||
public Deserializer() { }
|
||||
|
||||
public Deserializer(byte[] source)
|
||||
{
|
||||
SetSource(source);
|
||||
}
|
||||
|
||||
public Deserializer(byte[] source, int offset)
|
||||
{
|
||||
SetSource(source, offset);
|
||||
}
|
||||
|
||||
public Deserializer(byte[] source, int offset, int maxSize)
|
||||
{
|
||||
SetSource(source, offset, maxSize);
|
||||
}
|
||||
|
||||
#region GetMethods
|
||||
|
||||
public bool SetSlotOffset(int vTblOffset, int slotSize, int idx)
|
||||
{
|
||||
int offset = (int)(vTblOffset + idx * slotSize);
|
||||
int dataOffset = _data[offset];
|
||||
if (slotSize == 4)
|
||||
{
|
||||
dataOffset = (int)FastBitConverter.ToUInt32(_data, offset);
|
||||
}
|
||||
else if (slotSize == 2)
|
||||
{
|
||||
dataOffset = FastBitConverter.ToUInt16(_data, offset);
|
||||
}
|
||||
_position = dataOffset;
|
||||
return dataOffset != 0;
|
||||
}
|
||||
|
||||
public uint ReadSlotInt16(uint offset, int idx)
|
||||
{
|
||||
return FastBitConverter.ToUInt16(_data, (int)(offset + idx * 2));
|
||||
}
|
||||
|
||||
public uint ReadSlotInt32(uint offset, int idx)
|
||||
{
|
||||
return FastBitConverter.ToUInt32(_data, (int)(offset + idx * 2));
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
byte res = _data[_position];
|
||||
_position += 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
public sbyte ReadSByte()
|
||||
{
|
||||
var b = (sbyte)_data[_position];
|
||||
_position++;
|
||||
return b;
|
||||
}
|
||||
|
||||
public bool ReadBoolean()
|
||||
{
|
||||
bool res = _data[_position] > 0;
|
||||
_position += 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
public char ReadChar()
|
||||
{
|
||||
char result = (char)FastBitConverter.ToInt16(_data, _position);
|
||||
_position += 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
public ushort ReadUInt16()
|
||||
{
|
||||
ushort result = FastBitConverter.ToUInt16(_data, _position);
|
||||
_position += 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
public short ReadInt16()
|
||||
{
|
||||
short result = FastBitConverter.ToInt16(_data, _position);
|
||||
_position += 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
public long ReadInt64()
|
||||
{
|
||||
long result = FastBitConverter.ToInt64(_data, _position);
|
||||
_position += 8;
|
||||
return result;
|
||||
}
|
||||
|
||||
public ulong ReadUInt64()
|
||||
{
|
||||
ulong result = FastBitConverter.ToUInt64(_data, _position);
|
||||
_position += 8;
|
||||
return result;
|
||||
}
|
||||
|
||||
public int ReadInt32()
|
||||
{
|
||||
int result = FastBitConverter.ToInt32(_data, _position);
|
||||
_position += 4;
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint ReadUInt32()
|
||||
{
|
||||
uint result = FastBitConverter.ToUInt32(_data, _position);
|
||||
_position += 4;
|
||||
return result;
|
||||
}
|
||||
|
||||
public float ReadSingle()
|
||||
{
|
||||
float result = FastBitConverter.ToSingle(_data, _position);
|
||||
_position += 4;
|
||||
return result;
|
||||
}
|
||||
|
||||
public double ReadDouble()
|
||||
{
|
||||
double result = FastBitConverter.ToDouble(_data, _position);
|
||||
_position += 8;
|
||||
return result;
|
||||
}
|
||||
|
||||
public LFloat ReadLFloat()
|
||||
{
|
||||
var x = ReadInt64();
|
||||
return new LFloat(true, x);
|
||||
}
|
||||
|
||||
public LVector2 ReadLVector2()
|
||||
{
|
||||
var x = ReadInt64();
|
||||
var y = ReadInt64();
|
||||
return new LVector2(true, x, y);
|
||||
}
|
||||
|
||||
public LVector3 ReadLVector3()
|
||||
{
|
||||
var x = ReadInt64();
|
||||
var y = ReadInt64();
|
||||
var z = ReadInt64();
|
||||
return new LVector3(true, x, y, z);
|
||||
}
|
||||
|
||||
public T ReadRef<T>(ref T _) where T : BaseFormater, new()
|
||||
{
|
||||
if (ReadBoolean())
|
||||
return null;
|
||||
var val = new T();
|
||||
val.Deserialize(this);
|
||||
return val;
|
||||
}
|
||||
|
||||
public string ReadString(int maxLength)
|
||||
{
|
||||
int bytesCount = ReadInt32();
|
||||
if (bytesCount <= 0 || bytesCount > maxLength * 2)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
int charCount = Encoding.UTF8.GetCharCount(_data, _position, bytesCount);
|
||||
if (charCount > maxLength)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string result = Encoding.UTF8.GetString(_data, _position, bytesCount);
|
||||
_position += bytesCount;
|
||||
return result;
|
||||
}
|
||||
|
||||
public string ReadString()
|
||||
{
|
||||
int bytesCount = ReadInt32();
|
||||
if (bytesCount <= 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string result = Encoding.UTF8.GetString(_data, _position, bytesCount);
|
||||
_position += bytesCount;
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte[] ReadToEnd()
|
||||
{
|
||||
int size = _data.Length - _position;
|
||||
var outgoingData = new byte[size];
|
||||
Buffer.BlockCopy(_data, _position, outgoingData, 0, size);
|
||||
_position += size;
|
||||
return outgoingData;
|
||||
}
|
||||
|
||||
public byte[] ReadArray(byte[] _)
|
||||
{
|
||||
return ReadBytes();
|
||||
}
|
||||
|
||||
public short[] ReadArray(short[] _)
|
||||
{
|
||||
return _ReadArray(ReadInt16);
|
||||
}
|
||||
public List<short> ReadList(IList<short> _)
|
||||
{
|
||||
return _ReadList(ReadInt16);
|
||||
}
|
||||
|
||||
public ushort[] ReadArray(ushort[] _)
|
||||
{
|
||||
return _ReadArray(ReadUInt16);
|
||||
}
|
||||
public List<ushort> ReadList(IList<ushort> _)
|
||||
{
|
||||
return _ReadList(ReadUInt16);
|
||||
}
|
||||
|
||||
public int[] ReadArray(int[] _)
|
||||
{
|
||||
return _ReadArray(ReadInt32);
|
||||
}
|
||||
public List<int> ReadList(IList<int> _)
|
||||
{
|
||||
return _ReadList(ReadInt32);
|
||||
}
|
||||
|
||||
public uint[] ReadArray(uint[] _)
|
||||
{
|
||||
return _ReadArray(ReadUInt32);
|
||||
}
|
||||
public List<uint> ReadList(IList<uint> _)
|
||||
{
|
||||
return _ReadList(ReadUInt32);
|
||||
}
|
||||
|
||||
public long[] ReadArray(long[] _)
|
||||
{
|
||||
return _ReadArray(ReadInt64);
|
||||
}
|
||||
public List<long> ReadList(IList<long> _)
|
||||
{
|
||||
return _ReadList(ReadInt64);
|
||||
}
|
||||
|
||||
public ulong[] ReadArray(ulong[] _)
|
||||
{
|
||||
return _ReadArray(ReadUInt64);
|
||||
}
|
||||
public List<ulong> ReadList(IList<ulong> _)
|
||||
{
|
||||
return _ReadList(ReadUInt64);
|
||||
}
|
||||
|
||||
public float[] ReadArray(float[] _)
|
||||
{
|
||||
return _ReadArray(ReadSingle);
|
||||
}
|
||||
public List<float> ReadList(IList<float> _)
|
||||
{
|
||||
return _ReadList(ReadSingle);
|
||||
}
|
||||
|
||||
public double[] ReadArray(double[] _)
|
||||
{
|
||||
return _ReadArray(ReadDouble);
|
||||
}
|
||||
public List<double> ReadList(IList<double> _)
|
||||
{
|
||||
return _ReadList(ReadDouble);
|
||||
}
|
||||
|
||||
public bool[] ReadArray(bool[] _)
|
||||
{
|
||||
return _ReadArray(ReadBoolean);
|
||||
}
|
||||
public List<bool> ReadList(IList<bool> _)
|
||||
{
|
||||
return _ReadList(ReadBoolean);
|
||||
}
|
||||
|
||||
public string[] ReadArray(string[] _)
|
||||
{
|
||||
return _ReadArray(ReadString);
|
||||
}
|
||||
public List<string> ReadList(IList<string> _)
|
||||
{
|
||||
return _ReadList(ReadString);
|
||||
}
|
||||
|
||||
public LFloat[] ReadArray(LFloat[] _)
|
||||
{
|
||||
return _ReadArray(ReadLFloat);
|
||||
}
|
||||
public List<LFloat> ReadList(IList<LFloat> _)
|
||||
{
|
||||
return _ReadList(ReadLFloat);
|
||||
}
|
||||
|
||||
public LVector2[] ReadArray(LVector2[] _)
|
||||
{
|
||||
return _ReadArray(ReadLVector2);
|
||||
}
|
||||
public List<LVector2> ReadList(IList<LVector2> _)
|
||||
{
|
||||
return _ReadList(ReadLVector2);
|
||||
}
|
||||
|
||||
public LVector3[] ReadArray(LVector3[] _)
|
||||
{
|
||||
return _ReadArray(ReadLVector3);
|
||||
}
|
||||
public List<LVector3> ReadList(IList<LVector3> _)
|
||||
{
|
||||
return _ReadList(ReadLVector3);
|
||||
}
|
||||
|
||||
private T[] _ReadArray<T>(Func<T> _func)
|
||||
{
|
||||
ushort size = FastBitConverter.ToUInt16(_data, _position);
|
||||
_position += 2;
|
||||
var arr = new T[size];
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
arr[i] = _func();
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
private List<T> _ReadList<T>(Func<T> _func)
|
||||
{
|
||||
ushort size = FastBitConverter.ToUInt16(_data, _position);
|
||||
_position += 2;
|
||||
var arr = new List<T>(size);
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
arr.Add(_func());
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public T[] ReadArray<T>(T[] _) where T : BaseFormater, new()
|
||||
{
|
||||
ushort len = ReadUInt16();
|
||||
if (len == 0)
|
||||
return null;
|
||||
var formatters = new T[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (ReadBoolean())
|
||||
formatters[i] = null;
|
||||
else
|
||||
{
|
||||
var val = new T();
|
||||
val.Deserialize(this);
|
||||
formatters[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
return formatters;
|
||||
}
|
||||
|
||||
public List<T> ReadList<T>(List<T> _) where T : BaseFormater, new()
|
||||
{
|
||||
ushort len = ReadUInt16();
|
||||
if (len == 0)
|
||||
return null;
|
||||
var formatters = new List<T>(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (ReadBoolean())
|
||||
formatters[i] = null;
|
||||
else
|
||||
{
|
||||
var val = new T();
|
||||
val.Deserialize(this);
|
||||
formatters.Add(val);
|
||||
}
|
||||
}
|
||||
|
||||
return formatters;
|
||||
}
|
||||
|
||||
public byte[] GetRemainingBytes()
|
||||
{
|
||||
byte[] outgoingData = new byte[AvailableBytes];
|
||||
Buffer.BlockCopy(_data, _position, outgoingData, 0, AvailableBytes);
|
||||
_position = _data.Length;
|
||||
return outgoingData;
|
||||
}
|
||||
|
||||
public void GetBytes(byte[] destination, int start, int count)
|
||||
{
|
||||
Buffer.BlockCopy(_data, _position, destination, start, count);
|
||||
_position += count;
|
||||
}
|
||||
|
||||
public void GetBytes(byte[] destination, int count)
|
||||
{
|
||||
Buffer.BlockCopy(_data, _position, destination, 0, count);
|
||||
_position += count;
|
||||
}
|
||||
|
||||
public byte[] ReadBytes()
|
||||
{
|
||||
ushort size = ReadUInt16();
|
||||
if (size == 0) return null;
|
||||
var outgoingData = new byte[size];
|
||||
Buffer.BlockCopy(_data, _position, outgoingData, 0, size);
|
||||
_position += size;
|
||||
return outgoingData;
|
||||
}
|
||||
|
||||
public byte[] ReadBytes_255()
|
||||
{
|
||||
ushort size = ReadByte();
|
||||
if (size == 0) return null;
|
||||
var outgoingData = new byte[size];
|
||||
Buffer.BlockCopy(_data, _position, outgoingData, 0, size);
|
||||
_position += size;
|
||||
return outgoingData;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PeekMethods
|
||||
|
||||
public byte PeekByte()
|
||||
{
|
||||
return _data[_position];
|
||||
}
|
||||
|
||||
public sbyte PeekSByte()
|
||||
{
|
||||
return (sbyte)_data[_position];
|
||||
}
|
||||
|
||||
public bool PeekBool()
|
||||
{
|
||||
return _data[_position] > 0;
|
||||
}
|
||||
|
||||
public char PeekChar()
|
||||
{
|
||||
return (char)FastBitConverter.ToInt16(_data, _position);
|
||||
}
|
||||
|
||||
public ushort PeekUShort()
|
||||
{
|
||||
return FastBitConverter.ToUInt16(_data, _position);
|
||||
}
|
||||
|
||||
public short PeekShort()
|
||||
{
|
||||
return FastBitConverter.ToInt16(_data, _position);
|
||||
}
|
||||
|
||||
public long PeekLong()
|
||||
{
|
||||
return FastBitConverter.ToInt64(_data, _position);
|
||||
}
|
||||
|
||||
public ulong PeekULong()
|
||||
{
|
||||
return FastBitConverter.ToUInt64(_data, _position);
|
||||
}
|
||||
|
||||
public int PeekInt()
|
||||
{
|
||||
return FastBitConverter.ToInt32(_data, _position);
|
||||
}
|
||||
|
||||
public uint PeekUInt()
|
||||
{
|
||||
return FastBitConverter.ToUInt32(_data, _position);
|
||||
}
|
||||
|
||||
public float PeekFloat()
|
||||
{
|
||||
return FastBitConverter.ToSingle(_data, _position);
|
||||
}
|
||||
|
||||
public double PeekDouble()
|
||||
{
|
||||
return FastBitConverter.ToDouble(_data, _position);
|
||||
}
|
||||
|
||||
public string PeekString(int maxLength)
|
||||
{
|
||||
int bytesCount = BitConverter.ToInt32(_data, _position);
|
||||
if (bytesCount <= 0 || bytesCount > maxLength * 2)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
int charCount = Encoding.UTF8.GetCharCount(_data, _position + 4, bytesCount);
|
||||
if (charCount > maxLength)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string result = Encoding.UTF8.GetString(_data, _position + 4, bytesCount);
|
||||
return result;
|
||||
}
|
||||
|
||||
public string PeekString()
|
||||
{
|
||||
int bytesCount = BitConverter.ToInt32(_data, _position);
|
||||
if (bytesCount <= 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string result = Encoding.UTF8.GetString(_data, _position + 4, bytesCount);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TryReadMethods
|
||||
|
||||
public bool TryReadByte(out byte result)
|
||||
{
|
||||
if (AvailableBytes >= 1)
|
||||
{
|
||||
result = ReadByte();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadSByte(out sbyte result)
|
||||
{
|
||||
if (AvailableBytes >= 1)
|
||||
{
|
||||
result = ReadSByte();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadBool(out bool result)
|
||||
{
|
||||
if (AvailableBytes >= 1)
|
||||
{
|
||||
result = ReadBoolean();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadChar(out char result)
|
||||
{
|
||||
if (AvailableBytes >= 2)
|
||||
{
|
||||
result = ReadChar();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadShort(out short result)
|
||||
{
|
||||
if (AvailableBytes >= 2)
|
||||
{
|
||||
result = ReadInt16();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadUShort(out ushort result)
|
||||
{
|
||||
if (AvailableBytes >= 2)
|
||||
{
|
||||
result = ReadUInt16();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadInt(out int result)
|
||||
{
|
||||
if (AvailableBytes >= 4)
|
||||
{
|
||||
result = ReadInt32();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadUInt(out uint result)
|
||||
{
|
||||
if (AvailableBytes >= 4)
|
||||
{
|
||||
result = ReadUInt32();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadLong(out long result)
|
||||
{
|
||||
if (AvailableBytes >= 8)
|
||||
{
|
||||
result = ReadInt64();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadULong(out ulong result)
|
||||
{
|
||||
if (AvailableBytes >= 8)
|
||||
{
|
||||
result = ReadUInt64();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadFloat(out float result)
|
||||
{
|
||||
if (AvailableBytes >= 4)
|
||||
{
|
||||
result = ReadSingle();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadDouble(out double result)
|
||||
{
|
||||
if (AvailableBytes >= 8)
|
||||
{
|
||||
result = ReadDouble();
|
||||
return true;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadString(out string result)
|
||||
{
|
||||
if (AvailableBytes >= 4)
|
||||
{
|
||||
var bytesCount = PeekInt();
|
||||
if (AvailableBytes >= bytesCount + 4)
|
||||
{
|
||||
result = ReadString();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryReadStringArray(out string[] result)
|
||||
{
|
||||
ushort size;
|
||||
if (!TryReadUShort(out size))
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = new string[size];
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (!TryReadString(out result[i]))
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_position = 0;
|
||||
_dataSize = 0;
|
||||
_data = null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7362bef928b714323be0211b60e419f2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,189 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace JNGame.Serialization
|
||||
{
|
||||
public static class FastBitConverter
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct ConverterHelperDouble
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public ulong Along;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public double Adouble;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct ConverterHelperFloat
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int Aint;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public float Afloat;
|
||||
}
|
||||
|
||||
private static void WriteLittleEndian(byte[] buffer, int offset, ulong data)
|
||||
{
|
||||
#if BIGENDIAN
|
||||
buffer[offset + 7] = (byte)(data);
|
||||
buffer[offset + 6] = (byte)(data >> 8);
|
||||
buffer[offset + 5] = (byte)(data >> 16);
|
||||
buffer[offset + 4] = (byte)(data >> 24);
|
||||
buffer[offset + 3] = (byte)(data >> 32);
|
||||
buffer[offset + 2] = (byte)(data >> 40);
|
||||
buffer[offset + 1] = (byte)(data >> 48);
|
||||
buffer[offset ] = (byte)(data >> 56);
|
||||
#else
|
||||
buffer[offset] = (byte)(data);
|
||||
buffer[offset + 1] = (byte)(data >> 8);
|
||||
buffer[offset + 2] = (byte)(data >> 16);
|
||||
buffer[offset + 3] = (byte)(data >> 24);
|
||||
buffer[offset + 4] = (byte)(data >> 32);
|
||||
buffer[offset + 5] = (byte)(data >> 40);
|
||||
buffer[offset + 6] = (byte)(data >> 48);
|
||||
buffer[offset + 7] = (byte)(data >> 56);
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void WriteLittleEndian(byte[] buffer, int offset, int data)
|
||||
{
|
||||
#if BIGENDIAN
|
||||
buffer[offset + 3] = (byte)(data);
|
||||
buffer[offset + 2] = (byte)(data >> 8);
|
||||
buffer[offset + 1] = (byte)(data >> 16);
|
||||
buffer[offset ] = (byte)(data >> 24);
|
||||
#else
|
||||
buffer[offset] = (byte)(data);
|
||||
buffer[offset + 1] = (byte)(data >> 8);
|
||||
buffer[offset + 2] = (byte)(data >> 16);
|
||||
buffer[offset + 3] = (byte)(data >> 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void WriteLittleEndian(byte[] buffer, int offset, short data)
|
||||
{
|
||||
#if BIGENDIAN
|
||||
buffer[offset + 1] = (byte)(data);
|
||||
buffer[offset ] = (byte)(data >> 8);
|
||||
#else
|
||||
buffer[offset] = (byte)(data);
|
||||
buffer[offset + 1] = (byte)(data >> 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void GetBytes(byte[] bytes, int startIndex, double value)
|
||||
{
|
||||
ConverterHelperDouble ch = new ConverterHelperDouble { Adouble = value };
|
||||
WriteLittleEndian(bytes, startIndex, ch.Along);
|
||||
}
|
||||
|
||||
public static void GetBytes(byte[] bytes, int startIndex, float value)
|
||||
{
|
||||
ConverterHelperFloat ch = new ConverterHelperFloat { Afloat = value };
|
||||
WriteLittleEndian(bytes, startIndex, ch.Aint);
|
||||
}
|
||||
|
||||
public static void GetBytes(byte[] bytes, int startIndex, bool value)
|
||||
{
|
||||
bytes[startIndex] = (byte)(value ? 1 : 0);
|
||||
}
|
||||
public static void GetBytes(byte[] bytes, int startIndex, short value)
|
||||
{
|
||||
WriteLittleEndian(bytes, startIndex, value);
|
||||
}
|
||||
public static void GetBytes(byte[] bytes, int startIndex, ushort value)
|
||||
{
|
||||
WriteLittleEndian(bytes, startIndex, (short)value);
|
||||
}
|
||||
|
||||
public static void GetBytes(byte[] bytes, int startIndex, int value)
|
||||
{
|
||||
WriteLittleEndian(bytes, startIndex, value);
|
||||
}
|
||||
|
||||
public static void GetBytes(byte[] bytes, int startIndex, uint value)
|
||||
{
|
||||
WriteLittleEndian(bytes, startIndex, (int)value);
|
||||
}
|
||||
|
||||
public static void GetBytes(byte[] bytes, int startIndex, long value)
|
||||
{
|
||||
WriteLittleEndian(bytes, startIndex, (ulong)value);
|
||||
}
|
||||
|
||||
public static void GetBytes(byte[] bytes, int startIndex, ulong value)
|
||||
{
|
||||
WriteLittleEndian(bytes, startIndex, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static ulong ReadLittleEndian(byte[] buffer, int offset, int count)
|
||||
{
|
||||
ulong r = 0;
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
r |= (ulong)buffer[offset + i] << i * 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
r |= (ulong)buffer[offset + count - 1 - i] << i * 8;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public static short ToInt16(byte[] buffer, int index)
|
||||
{
|
||||
return (short)ReadLittleEndian(buffer, index, sizeof(short));
|
||||
}
|
||||
|
||||
public static ushort ToUInt16(byte[] buffer, int index)
|
||||
{
|
||||
return (ushort)ReadLittleEndian(buffer, index, sizeof(ushort));
|
||||
}
|
||||
|
||||
public static int ToInt32(byte[] buffer, int index)
|
||||
{
|
||||
return (int)ReadLittleEndian(buffer, index, sizeof(int));
|
||||
}
|
||||
|
||||
public static uint ToUInt32(byte[] buffer, int index)
|
||||
{
|
||||
return (uint)ReadLittleEndian(buffer, index, sizeof(uint));
|
||||
}
|
||||
|
||||
public static long ToInt64(byte[] buffer, int index)
|
||||
{
|
||||
return (long)ReadLittleEndian(buffer, index, sizeof(long));
|
||||
}
|
||||
|
||||
public static ulong ToUInt64(byte[] buffer, int index)
|
||||
{
|
||||
return ReadLittleEndian(buffer, index, sizeof(ulong));
|
||||
}
|
||||
|
||||
public static float ToSingle(byte[] buffer, int index)
|
||||
{
|
||||
int i = (int)ReadLittleEndian(buffer, index, sizeof(float));
|
||||
ConverterHelperFloat ch = new ConverterHelperFloat { Aint = i };
|
||||
return ch.Afloat;
|
||||
}
|
||||
|
||||
public static double ToDouble(byte[] buffer, int index)
|
||||
{
|
||||
ulong i = ReadLittleEndian(buffer, index, sizeof(double));
|
||||
ConverterHelperDouble ch = new ConverterHelperDouble { Along = i };
|
||||
return ch.Adouble;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b957561d8211f485ebb45999c9b5524a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,107 @@
|
||||
|
||||
using System;
|
||||
using JNGame.Serialization;
|
||||
|
||||
namespace JNGame.Serialization
|
||||
{
|
||||
public class NoToBytesAttribute : Attribute { }
|
||||
|
||||
public class ToBytesAttribute : Attribute { }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class IndexAttribute : Attribute
|
||||
{
|
||||
public int idx;
|
||||
|
||||
public IndexAttribute(int idx)
|
||||
{
|
||||
this.idx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class TypeIdAttribute : Attribute
|
||||
{
|
||||
public int idx;
|
||||
|
||||
public TypeIdAttribute(int idx)
|
||||
{
|
||||
this.idx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||
public class ExtFormatAttribute : Attribute { }
|
||||
|
||||
public static class NetMsgExtension
|
||||
{
|
||||
|
||||
public static T Parse<T>(this Deserializer reader) where T : ISerializable, new()
|
||||
{
|
||||
var val = new T();
|
||||
val.Deserialize(reader);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ArrayExtention
|
||||
{
|
||||
public static bool EqualsEx(this byte[] arra, byte[] arrb)
|
||||
{
|
||||
if ((arra == null) != (arrb == null)) return false;
|
||||
if (arra == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
var count = arra.Length;
|
||||
if (count != arrb.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (arra[i] != arrb[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool EqualsEx<T>(this T[] arra, T[] arrb) where T : class
|
||||
{
|
||||
if ((arra == null) != (arrb == null)) return false;
|
||||
if (arra == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var count = arra.Length;
|
||||
if (count != arrb.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var a = arra[i];
|
||||
var b = arrb[i];
|
||||
if ((a == null) != (b == null)) return false;
|
||||
if (a == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!a.Equals(b))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2728e145802d34e8e9c37150ab3ee2fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,534 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace JNGame.Serialization
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class Limited : Attribute
|
||||
{
|
||||
public bool le255;
|
||||
public bool le65535;
|
||||
|
||||
public Limited()
|
||||
{
|
||||
le255 = false;
|
||||
le65535 = true;
|
||||
}
|
||||
|
||||
public Limited(bool isLess255)
|
||||
{
|
||||
le255 = isLess255;
|
||||
le65535 = !isLess255;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ISerializablePacket
|
||||
{
|
||||
byte[] ToBytes();
|
||||
void FromBytes(byte[] bytes);
|
||||
}
|
||||
|
||||
public interface ISerializable
|
||||
{
|
||||
void Serialize(Serializer writer);
|
||||
|
||||
void Deserialize(Deserializer reader);
|
||||
}
|
||||
|
||||
public partial class Serializer
|
||||
{
|
||||
//for ext
|
||||
protected int[] offsets;
|
||||
|
||||
public void SetPosition(int pos)
|
||||
{
|
||||
_position = pos;
|
||||
}
|
||||
|
||||
public int[] GetOffsetTable(int len)
|
||||
{
|
||||
if (offsets == null)
|
||||
{
|
||||
offsets = new int[len];
|
||||
return offsets;
|
||||
}
|
||||
else
|
||||
{
|
||||
var rawLen = offsets.Length;
|
||||
if (rawLen >= len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
offsets[i] = 0;
|
||||
}
|
||||
return offsets;
|
||||
}
|
||||
|
||||
while (rawLen < len)
|
||||
{
|
||||
rawLen *= 2;
|
||||
}
|
||||
offsets = new int[rawLen];
|
||||
return offsets;
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] _data;
|
||||
protected int _position;
|
||||
private const int InitialSize = 64;
|
||||
private int _capacity;
|
||||
|
||||
public int Position => _position;
|
||||
public int Capacity
|
||||
{
|
||||
get { return _capacity; }
|
||||
}
|
||||
|
||||
public Serializer() : this(true, InitialSize) { }
|
||||
|
||||
public Serializer(int initialSize) : this(true, initialSize) { }
|
||||
|
||||
private Serializer(bool autoResize, int initialSize)
|
||||
{
|
||||
_data = new byte[initialSize];
|
||||
_capacity = initialSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates NetDataWriter from existing ByteArray
|
||||
/// </summary>
|
||||
/// <param name="bytes">Source byte array</param>
|
||||
/// <param name="copy">Copy array to new location or use existing</param>
|
||||
public static Serializer FromBytes(byte[] bytes, bool copy)
|
||||
{
|
||||
if (copy)
|
||||
{
|
||||
var netDataWriter = new Serializer(true, bytes.Length);
|
||||
netDataWriter._Put(bytes);
|
||||
return netDataWriter;
|
||||
}
|
||||
|
||||
return new Serializer(true, 0) { _data = bytes, _capacity = bytes.Length };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates NetDataWriter from existing ByteArray (always copied data)
|
||||
/// </summary>
|
||||
/// <param name="bytes">Source byte array</param>
|
||||
/// <param name="offset">Offset of array</param>
|
||||
/// <param name="length">Length of array</param>
|
||||
public static Serializer FromBytes(byte[] bytes, int offset, int length)
|
||||
{
|
||||
var netDataWriter = new Serializer(true, bytes.Length);
|
||||
netDataWriter._Put(bytes, offset, length);
|
||||
return netDataWriter;
|
||||
}
|
||||
|
||||
public static Serializer FromString(string value)
|
||||
{
|
||||
var netDataWriter = new Serializer();
|
||||
netDataWriter.Write(value);
|
||||
return netDataWriter;
|
||||
}
|
||||
|
||||
public void ResizeIfNeed(int newSize)
|
||||
{
|
||||
int len = _data.Length;
|
||||
if (len < newSize)
|
||||
{
|
||||
while (len < newSize)
|
||||
len *= 2;
|
||||
Array.Resize(ref _data, len);
|
||||
_capacity = _data.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset(int size)
|
||||
{
|
||||
ResizeIfNeed(size);
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
public byte[] CopyData()
|
||||
{
|
||||
byte[] resultData = new byte[_position];
|
||||
Buffer.BlockCopy(_data, 0, resultData, 0, _position);
|
||||
return resultData;
|
||||
}
|
||||
|
||||
public byte[] Data
|
||||
{
|
||||
get { return _data; }
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get { return _position; }
|
||||
}
|
||||
|
||||
public void Write(float value)
|
||||
{
|
||||
ResizeIfNeed(_position + 4);
|
||||
FastBitConverter.GetBytes(_data, _position, value);
|
||||
_position += 4;
|
||||
}
|
||||
|
||||
public void Write(double value)
|
||||
{
|
||||
ResizeIfNeed(_position + 8);
|
||||
FastBitConverter.GetBytes(_data, _position, value);
|
||||
_position += 8;
|
||||
}
|
||||
|
||||
public void Write(long value)
|
||||
{
|
||||
ResizeIfNeed(_position + 8);
|
||||
FastBitConverter.GetBytes(_data, _position, value);
|
||||
_position += 8;
|
||||
}
|
||||
|
||||
public void Write(ulong value)
|
||||
{
|
||||
ResizeIfNeed(_position + 8);
|
||||
FastBitConverter.GetBytes(_data, _position, value);
|
||||
_position += 8;
|
||||
}
|
||||
|
||||
public void Write(int value)
|
||||
{
|
||||
ResizeIfNeed(_position + 4);
|
||||
FastBitConverter.GetBytes(_data, _position, value);
|
||||
_position += 4;
|
||||
}
|
||||
|
||||
public void Write(uint value)
|
||||
{
|
||||
ResizeIfNeed(_position + 4);
|
||||
FastBitConverter.GetBytes(_data, _position, value);
|
||||
_position += 4;
|
||||
}
|
||||
|
||||
|
||||
public void Write(ushort value)
|
||||
{
|
||||
ResizeIfNeed(_position + 2);
|
||||
FastBitConverter.GetBytes(_data, _position, value);
|
||||
_position += 2;
|
||||
}
|
||||
|
||||
public void Write(short value)
|
||||
{
|
||||
ResizeIfNeed(_position + 2);
|
||||
FastBitConverter.GetBytes(_data, _position, value);
|
||||
_position += 2;
|
||||
}
|
||||
|
||||
public void Write(sbyte value)
|
||||
{
|
||||
ResizeIfNeed(_position + 1);
|
||||
_data[_position] = (byte)value;
|
||||
_position++;
|
||||
}
|
||||
|
||||
public void Write(byte value)
|
||||
{
|
||||
ResizeIfNeed(_position + 1);
|
||||
_data[_position] = value;
|
||||
_position++;
|
||||
}
|
||||
|
||||
public void Write(bool value)
|
||||
{
|
||||
ResizeIfNeed(_position + 1);
|
||||
_data[_position] = (byte)(value ? 1 : 0);
|
||||
_position++;
|
||||
}
|
||||
|
||||
public void Write(char value)
|
||||
{
|
||||
ResizeIfNeed(_position + 2);
|
||||
FastBitConverter.GetBytes(_data, _position, value);
|
||||
_position += 2;
|
||||
}
|
||||
|
||||
public void Write(IPEndPoint endPoint)
|
||||
{
|
||||
Write(endPoint.Address.ToString());
|
||||
Write(endPoint.Port);
|
||||
}
|
||||
|
||||
public void Write(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
Write(0);
|
||||
return;
|
||||
}
|
||||
|
||||
//put bytes count
|
||||
int bytesCount = Encoding.UTF8.GetByteCount(value);
|
||||
ResizeIfNeed(_position + bytesCount + 4);
|
||||
Write(bytesCount);
|
||||
|
||||
//put string
|
||||
Encoding.UTF8.GetBytes(value, 0, value.Length, _data, _position);
|
||||
_position += bytesCount;
|
||||
}
|
||||
|
||||
|
||||
public void Write(BaseFormater value)
|
||||
{
|
||||
Write(value == null);
|
||||
value?.Serialize(this);
|
||||
}
|
||||
|
||||
|
||||
public void Write(string[] value)
|
||||
{
|
||||
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
|
||||
Write(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
Write(value[i]);
|
||||
}
|
||||
|
||||
public void Append(byte[] value)
|
||||
{
|
||||
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
|
||||
if (len > 0)
|
||||
{
|
||||
_Put(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// len should less then ushort.MaxValue
|
||||
public void Write(byte[] value)
|
||||
{
|
||||
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
|
||||
Write(len);
|
||||
if (len > 0)
|
||||
{
|
||||
_Put(value);
|
||||
}
|
||||
}
|
||||
public void WriteBytes_255(byte[] value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Write((byte)0);
|
||||
return;
|
||||
}
|
||||
if (value.Length > byte.MaxValue)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException($"Input Cmd len should less then {byte.MaxValue}");
|
||||
}
|
||||
Write((byte)value.Length);
|
||||
_Put(value);
|
||||
}
|
||||
|
||||
public void Write(float[] value) { _PutArray(value, sizeof(float), FastBitConverter.GetBytes); }
|
||||
public void Write(IList<float> value) { _PutArray(value, sizeof(float), FastBitConverter.GetBytes); }
|
||||
|
||||
public void Write(double[] value) { _PutArray(value, sizeof(double), FastBitConverter.GetBytes); }
|
||||
public void Write(IList<double> value) { _PutArray(value, sizeof(double), FastBitConverter.GetBytes); }
|
||||
|
||||
public void Write(long[] value) { _PutArray(value, sizeof(long), FastBitConverter.GetBytes); }
|
||||
public void Write(IList<long> value) { _PutArray(value, sizeof(long), FastBitConverter.GetBytes); }
|
||||
|
||||
public void Write(ulong[] value) { _PutArray(value, sizeof(ulong), FastBitConverter.GetBytes); }
|
||||
public void Write(IList<ulong> value) { _PutArray(value, sizeof(ulong), FastBitConverter.GetBytes); }
|
||||
|
||||
public void Write(int[] value) { _PutArray(value, sizeof(int), FastBitConverter.GetBytes); }
|
||||
public void Write(IList<int> value) { _PutArray(value, sizeof(int), FastBitConverter.GetBytes); }
|
||||
|
||||
public void Write(uint[] value) { _PutArray(value, sizeof(uint), FastBitConverter.GetBytes); }
|
||||
public void Write(IList<uint> value) { _PutArray(value, sizeof(uint), FastBitConverter.GetBytes); }
|
||||
|
||||
public void Write(ushort[] value) { _PutArray(value, sizeof(ushort), FastBitConverter.GetBytes); }
|
||||
public void Write(IList<ushort> value) { _PutArray(value, sizeof(ushort), FastBitConverter.GetBytes); }
|
||||
|
||||
public void Write(short[] value) { _PutArray(value, sizeof(short), FastBitConverter.GetBytes); }
|
||||
public void Write(IList<short> value) { _PutArray(value, sizeof(short), FastBitConverter.GetBytes); }
|
||||
|
||||
public void Write(bool[] value) { _PutArray(value, sizeof(bool), FastBitConverter.GetBytes); }
|
||||
public void Write(IList<bool> value) { _PutArray(value, sizeof(bool), FastBitConverter.GetBytes); }
|
||||
|
||||
public void Write(LFloat val) { Write(val.rawValue); }
|
||||
public void Write(LFloat[] value)
|
||||
{
|
||||
ushort len = (ushort)(value?.Length ?? 0);
|
||||
Write(len);
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
Write(value[i]);
|
||||
}
|
||||
}
|
||||
public void Write(IList<LFloat> value)
|
||||
{
|
||||
ushort len = (ushort)(value?.Count ?? 0);
|
||||
Write(len);
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
Write(value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(LVector2 val) { Write(val.RawX); Write(val.RawY); }
|
||||
public void Write(LVector2[] value)
|
||||
{
|
||||
ushort len = (ushort)(value?.Length ?? 0);
|
||||
Write(len);
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
Write(value[i]);
|
||||
}
|
||||
}
|
||||
public void Write(IList<LVector2> value)
|
||||
{
|
||||
ushort len = (ushort)(value?.Count ?? 0);
|
||||
Write(len);
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
Write(value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(LVector3 val) { Write(val.RawX); Write(val.RawY); Write(val.RawZ); }
|
||||
public void Write(LVector3[] value)
|
||||
{
|
||||
ushort len = (ushort)(value?.Length ?? 0);
|
||||
Write(len);
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
Write(value[i]);
|
||||
}
|
||||
}
|
||||
public void Write(IList<LVector3> value)
|
||||
{
|
||||
ushort len = (ushort)(value?.Count ?? 0);
|
||||
Write(len);
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
Write(value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Write<T>(T[] value) where T : BaseFormater
|
||||
{
|
||||
ushort len = (ushort)(value?.Length ?? 0);
|
||||
Write(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
var val = value[i];
|
||||
Write(val == null);
|
||||
val?.Serialize(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void Write<T>(List<T> value) where T : BaseFormater
|
||||
{
|
||||
ushort len = (ushort)(value?.Count ?? 0);
|
||||
Write(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
var val = value[i];
|
||||
Write(val == null);
|
||||
val?.Serialize(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void _Put(byte[] data, int offset, int length)
|
||||
{
|
||||
ResizeIfNeed(_position + length);
|
||||
Buffer.BlockCopy(data, offset, _data, _position, length);
|
||||
_position += length;
|
||||
}
|
||||
|
||||
private void _Put(byte[] data)
|
||||
{
|
||||
ResizeIfNeed(_position + data.Length);
|
||||
Buffer.BlockCopy(data, 0, _data, _position, data.Length);
|
||||
_position += data.Length;
|
||||
}
|
||||
|
||||
|
||||
private void _PutArray<T>(T[] value, int typeSize, Action<byte[], int, T> _func) where T : struct
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
__PutArrayFastLE(value, typeSize);
|
||||
return;
|
||||
}
|
||||
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
|
||||
ResizeIfNeed(_position + 2 + typeSize * len);
|
||||
Write(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
_func(_data, _position, value[i]);
|
||||
_position += typeSize;
|
||||
}
|
||||
}
|
||||
|
||||
private void _PutArray<T>(IList<T> value, int typeSize, Action<byte[], int, T> _func) where T : struct
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
__PutArrayFastLE(value, typeSize);
|
||||
return;
|
||||
}
|
||||
ushort len = value == null ? (ushort)0 : (ushort)value.Count;
|
||||
ResizeIfNeed(_position + 2 + typeSize * len);
|
||||
Write(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
_func(_data, _position, value[i]);
|
||||
_position += typeSize;
|
||||
}
|
||||
}
|
||||
|
||||
private void __PutArrayFastLE<T>(T[] x, int elemSize) where T : struct
|
||||
{
|
||||
ushort len = x == null ? (ushort)0 : (ushort)x.Length;
|
||||
int bytesCount = elemSize * len;
|
||||
ResizeIfNeed(_position + 2 + bytesCount);
|
||||
FastBitConverter.GetBytes(_data, _position, len);
|
||||
_position += 2;
|
||||
if (len == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if we are LE, just do a block copy
|
||||
Buffer.BlockCopy(x, 0, _data, _position, bytesCount);
|
||||
_position += bytesCount;
|
||||
}
|
||||
|
||||
private void __PutArrayFastLE<T>(IList<T> x, int elemSize) where T : struct
|
||||
{
|
||||
ushort len = x == null ? (ushort)0 : (ushort)x.Count;
|
||||
int bytesCount = elemSize * len;
|
||||
ResizeIfNeed(_position + 2 + bytesCount);
|
||||
FastBitConverter.GetBytes(_data, _position, len);
|
||||
_position += 2;
|
||||
if (len == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if we are LE, just do a block copy
|
||||
Buffer.BlockCopy(x.ToArray(), 0, _data, _position, bytesCount);
|
||||
_position += bytesCount;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71031343319b34c629838e63c427d499
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,258 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JNGame.Math;
|
||||
|
||||
namespace JNGame.Serialization.Test
|
||||
{
|
||||
public enum ETypeId
|
||||
{
|
||||
TestClassBase = 1001,
|
||||
TestClass = 1002,
|
||||
TestClass2 = 1003,
|
||||
}
|
||||
|
||||
[TypeId(idx: (int)ETypeId.TestClassBase)]
|
||||
public partial class TestClassBase
|
||||
{
|
||||
[Index(0)] public int val0;
|
||||
public int val1;
|
||||
[Index(2)] public LFloat val2 = 100;
|
||||
[Index(3)] public bool val3;
|
||||
[Index(4)] public int[] val4;
|
||||
}
|
||||
|
||||
[TypeId(idx: (int)ETypeId.TestClass)]
|
||||
public partial class TestClass : TestClassBase
|
||||
{
|
||||
[Index(5)] public TestClassBase[] val5;
|
||||
}
|
||||
|
||||
[TypeId(idx: (int)ETypeId.TestClass2)]
|
||||
public partial class TestClass2 : TestClassBase
|
||||
{
|
||||
[Index(5)] public LVector3 val5;
|
||||
}
|
||||
|
||||
public partial class NormalClass : ICompatible
|
||||
{
|
||||
public float val2 = 100;
|
||||
public bool val3;
|
||||
public int[] val4;
|
||||
}
|
||||
|
||||
public partial class CompositeClass
|
||||
{
|
||||
public NormalClass val2;
|
||||
public TestClass2 val3;
|
||||
public TestClassBase[] val4;
|
||||
public NormalClass val5;
|
||||
}
|
||||
}
|
||||
|
||||
namespace JNGame.Serialization.Test
|
||||
{
|
||||
public partial class TestClassBase : ICompatibleExt
|
||||
{
|
||||
public virtual void SerializeExt(Serializer writer)
|
||||
{
|
||||
writer.BeforeWriteData((ushort)ETypeId.TestClassBase);
|
||||
int initPos = writer.Position;
|
||||
int tableLen = 4 + 1;
|
||||
var offsetTable = writer.GetOffsetTable(tableLen);
|
||||
offsetTable[0] = writer.Position; if (val0 != 0) writer.Write(val0); else { offsetTable[0] = 0; }
|
||||
offsetTable[2] = writer.Position; if (val2 != 0) writer.Write(val2); else { offsetTable[2] = 0; }
|
||||
offsetTable[3] = writer.Position; if (val3 != false) writer.Write(val3); else { offsetTable[3] = 0; }
|
||||
offsetTable[4] = writer.Position; if (val4 != null) writer.Write(val4); else { offsetTable[4] = 0; }
|
||||
writer.AfterWriteData(tableLen, offsetTable, initPos);
|
||||
}
|
||||
|
||||
public virtual void DeserializeExt(Deserializer reader, int dataOffset,
|
||||
int vTblOffset, int vTableLen, byte slotSize)
|
||||
{
|
||||
if (reader.SetSlotOffset((int)vTblOffset, slotSize, 0)) val0 = reader.ReadInt32();
|
||||
if (reader.SetSlotOffset((int)vTblOffset, slotSize, 2)) val2 = reader.ReadLFloat();
|
||||
if (reader.SetSlotOffset((int)vTblOffset, slotSize, 3)) val3 = reader.ReadBoolean();
|
||||
if (reader.SetSlotOffset((int)vTblOffset, slotSize, 4)) val4 = reader.ReadArray(val4);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class TestClass : ICompatibleExt
|
||||
{
|
||||
public override void SerializeExt(Serializer writer)
|
||||
{
|
||||
base.SerializeExt(writer);
|
||||
writer.BeforeWriteData((ushort)ETypeId.TestClassBase);
|
||||
int initPos = writer.Position;
|
||||
int tableLen = 4 + 1;
|
||||
var offsetTable = writer.GetOffsetTable(tableLen);
|
||||
offsetTable[0] = writer.Position; if (val0 != 0) writer.Write(val0); else { offsetTable[0] = 0; }
|
||||
offsetTable[2] = writer.Position; if (val2 != 0) writer.Write(val2); else { offsetTable[2] = 0; }
|
||||
offsetTable[3] = writer.Position; if (val3 != false) writer.Write(val3); else { offsetTable[3] = 0; }
|
||||
offsetTable[4] = writer.Position; if (val4 != null) writer.Write(val4); else { offsetTable[4] = 0; }
|
||||
//offsetTable[4] = writer.Position;if (val5 != null) writer.Write(val5);else{offsetTable[4] = 0;}
|
||||
writer.AfterWriteData(tableLen, offsetTable, initPos);
|
||||
}
|
||||
|
||||
public override void DeserializeExt(Deserializer reader, int dataOffset,
|
||||
int vTblOffset, int vTableLen, byte slotSize)
|
||||
{
|
||||
if (reader.SetSlotOffset((int)vTblOffset, slotSize, 0)) val0 = reader.ReadInt32();
|
||||
if (reader.SetSlotOffset((int)vTblOffset, slotSize, 2)) val2 = reader.ReadLFloat();
|
||||
if (reader.SetSlotOffset((int)vTblOffset, slotSize, 3)) val3 = reader.ReadBoolean();
|
||||
if (reader.SetSlotOffset((int)vTblOffset, slotSize, 4)) val4 = reader.ReadArray(val4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace JNGame.Serialization
|
||||
{
|
||||
public interface ICompatible { }
|
||||
|
||||
public interface ICompatibleExt : ICompatible
|
||||
{
|
||||
void SerializeExt(Serializer writer);
|
||||
void DeserializeExt(Deserializer reader, int dataOffset, int vTblOffset, int vTableLen, byte slotSize);
|
||||
}
|
||||
|
||||
public static class SerExt
|
||||
{
|
||||
|
||||
//public static void WriteExt<T>(this Serializer writer, ref T[] value) where T : ICompatibleExt{
|
||||
// writer.Write(value == null);
|
||||
// if (value == null) { }
|
||||
//
|
||||
// value.SerializeExt(writer);
|
||||
//}
|
||||
public static void WriteExt<T>(this Serializer writer, ref T value) where T : ICompatibleExt
|
||||
{
|
||||
writer.Write(value == null);
|
||||
if (value == null) { }
|
||||
|
||||
value.SerializeExt(writer);
|
||||
}
|
||||
|
||||
public static T ReadExt<T>(this Deserializer reader, ref T _) where T : ICompatibleExt, new()
|
||||
{
|
||||
var isDefault = reader.ReadBoolean();
|
||||
if (isDefault) return default(T);
|
||||
var typeId = reader.ReadUInt16();
|
||||
var slotSize = reader.ReadByte();
|
||||
int vTableLen = 0;
|
||||
int dataLen = 0;
|
||||
dataLen = reader.ReadInt32();
|
||||
vTableLen = reader.ReadInt32();
|
||||
|
||||
var hasType = SerializationExtHelper.HasType(typeId);
|
||||
long allDataLen = vTableLen + dataLen;
|
||||
if (allDataLen > int.MaxValue)
|
||||
{
|
||||
throw new Exception($"ReadExt failed! typeId{typeId} allDataLen{allDataLen}");
|
||||
}
|
||||
|
||||
var dataOffset = reader.Position;
|
||||
if (hasType)
|
||||
{
|
||||
reader.SetPosition((int)(dataOffset + allDataLen));
|
||||
return default(T);
|
||||
}
|
||||
else
|
||||
{
|
||||
var obj = SerializationExtHelper.CreateType<T>(typeId);
|
||||
obj.DeserializeExt(reader, dataOffset, dataOffset + dataLen, vTableLen, slotSize);
|
||||
reader.SkipLen(allDataLen);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static void BeforeWriteData(this Serializer writer, ushort id)
|
||||
{
|
||||
writer.Write(id);
|
||||
writer.Write(4);
|
||||
writer.Write(0); //dataLen
|
||||
writer.Write(0); //vTableLen
|
||||
}
|
||||
public static void AfterWriteData(this Serializer writer, int tableLen, int[] offsetTbl, int initPos)
|
||||
{
|
||||
var endPos = writer.Position;
|
||||
int maxIdx = tableLen - 1;
|
||||
for (; maxIdx >= 0 && offsetTbl[maxIdx] == 0; maxIdx--) { }
|
||||
byte slotSize = 4;
|
||||
int dataLen = endPos - initPos;
|
||||
if (dataLen < ushort.MaxValue)
|
||||
{
|
||||
slotSize = 2;
|
||||
}
|
||||
if (dataLen < ushort.MaxValue)
|
||||
{
|
||||
slotSize = 1;
|
||||
}
|
||||
|
||||
if (slotSize == 1) for (int i = 0; i <= maxIdx; i++) { writer.Write((byte)offsetTbl[i]); }
|
||||
else if (slotSize == 2) for (int i = 0; i <= maxIdx; i++) { writer.Write((ushort)offsetTbl[i]); }
|
||||
else for (int i = 0; i <= maxIdx; i++) { writer.Write((uint)offsetTbl[i]); }
|
||||
|
||||
int vTableLen = (maxIdx + 1) * slotSize;
|
||||
writer.SetPosition(initPos - 8 - 1);
|
||||
writer.Write(slotSize);
|
||||
writer.Write(dataLen);
|
||||
writer.Write(vTableLen);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SerializationExtHelper
|
||||
{
|
||||
private static HashSet<ushort> _typeidHashset = new HashSet<ushort>();
|
||||
private static HashSet<ushort> _isStruct = new HashSet<ushort>();
|
||||
|
||||
private static Dictionary<ushort, FuncCreateObject> _typeid2FuncCreate =
|
||||
new Dictionary<ushort, FuncCreateObject>();
|
||||
|
||||
public delegate object FuncCreateObject();
|
||||
|
||||
public static T CreateType<T>(ushort id) where T : ICompatibleExt
|
||||
{
|
||||
if (!IsStruct(id))
|
||||
{
|
||||
var val = _typeid2FuncCreate[id]();
|
||||
return (T)val;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public static bool IsStruct(ushort id)
|
||||
{
|
||||
return _isStruct.Contains(id);
|
||||
}
|
||||
|
||||
public static bool HasType(ushort id)
|
||||
{
|
||||
return _typeidHashset.Contains(id);
|
||||
}
|
||||
|
||||
public static bool RegisterType<T>(ushort id, FuncCreateObject func)
|
||||
{
|
||||
if (func != null)
|
||||
{
|
||||
_typeid2FuncCreate[id] = func;
|
||||
}
|
||||
|
||||
var isClass = typeof(T).IsClass;
|
||||
if (!isClass)
|
||||
{
|
||||
_isStruct.Add(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (func == null)
|
||||
{
|
||||
throw new Exception("Class must have a Factory Function" + id);
|
||||
}
|
||||
}
|
||||
|
||||
return _typeidHashset.Add(id);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbc203722f2c495484f2c4335e6412bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user