简单提交

This commit is contained in:
PC-20230316NUNE\Administrator
2024-10-22 16:10:12 +08:00
parent 930911e7df
commit 0e94e376fb
562 changed files with 26182 additions and 29365 deletions

View File

@@ -1,3 +1,4 @@
using System;
using Newtonsoft.Json;
namespace JNGame.Runtime.Util {
@@ -9,5 +10,8 @@ namespace JNGame.Runtime.Util {
public static T ToObject<T>(string txt){
return JsonConvert.DeserializeObject<T>(txt);
}
public static object ToObject(string txt,Type type){
return JsonConvert.DeserializeObject(txt,type);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fb0bec139f16466896156d9ff4322641
timeCreated: 1729562648

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 601c581990ac843e7a62fa8a4cffb197
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 844fb1126baf449dd93750b0e4ffad15
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 41476905d95bf4bddbe138f884a4db5d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7362bef928b714323be0211b60e419f2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b957561d8211f485ebb45999c9b5524a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2728e145802d34e8e9c37150ab3ee2fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 71031343319b34c629838e63c427d499
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cbc203722f2c495484f2c4335e6412bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: