656 lines
20 KiB
C#
656 lines
20 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using System;
|
||
using System.Text;
|
||
using ProtoBuf;
|
||
using Thousandto.Core.Base;
|
||
namespace Thousandto.Plugins.Common
|
||
{
|
||
/// <summary>
|
||
/// ProtoBuf工具
|
||
/// </summary>
|
||
public class ProtoBufUtils
|
||
{
|
||
//多线程使用
|
||
public static object WriteLocker = new object();
|
||
public static object ReadLocker = new object();
|
||
//计数器(作为单个消息子结构体临时id)
|
||
private static int _counter = 0;
|
||
//long 最大值
|
||
private const long Int64Max = 9223372036854775807;
|
||
//int 最大值
|
||
private const int Int32Max = 2147483647;
|
||
//缓存
|
||
private static byte[] _bytesCache = new byte[256 * 1024];
|
||
//当前写入位置
|
||
private static int _writePos = 0;
|
||
//UTF8编码
|
||
private static readonly UTF8Encoding Encoding = new UTF8Encoding();
|
||
//子结构体字典
|
||
private static Dictionary<int, SubItemInfo> SubItemInfoDic = new Dictionary<int, SubItemInfo>(23);
|
||
//当前反序列化后的byte数组
|
||
private static byte[] _readbytes = null;
|
||
|
||
//==================================================[Write]===================================================
|
||
|
||
//初始化重置
|
||
public static void InitWriteData()
|
||
{
|
||
_writePos = 0;
|
||
_counter = 0;
|
||
}
|
||
|
||
//获取子结构体临时id
|
||
public static int GetSubItemInfoId()
|
||
{
|
||
return ++_counter;
|
||
}
|
||
|
||
//1.设置一个位置空长度(这里默认都设置1个byte)
|
||
public static void SetEmptyLength(int SubItemInfoId)//, int Count = 1)
|
||
{
|
||
if (!SubItemInfoDic.ContainsKey(SubItemInfoId))
|
||
{
|
||
SubItemInfo msgInfo = new SubItemInfo
|
||
{
|
||
LBeginIndex = _writePos,
|
||
LCount = 1
|
||
};
|
||
SubItemInfoDic.Add(SubItemInfoId, msgInfo);
|
||
}
|
||
else
|
||
{
|
||
var subItemInfo = SubItemInfoDic[SubItemInfoId];
|
||
subItemInfo.LBeginIndex = _writePos;
|
||
subItemInfo.LCount = 1;
|
||
}
|
||
//for (int i = 0; i < Count; i++)
|
||
//{
|
||
_bytesCache[_writePos++] = 0;
|
||
//}
|
||
}
|
||
|
||
//设置子结构体的开始索引
|
||
public static void SetVBeginIndex(int SubItemInfoId)
|
||
{
|
||
if (!SubItemInfoDic.ContainsKey(SubItemInfoId))
|
||
{
|
||
Debug.LogError("Error SetBeginIndex");
|
||
return;
|
||
}
|
||
SubItemInfoDic[SubItemInfoId].VBeginIndex = _writePos;
|
||
}
|
||
|
||
//设置子结构体的结束索引
|
||
public static void SetVEndIndex(int SubItemInfoId)
|
||
{
|
||
if (!SubItemInfoDic.ContainsKey(SubItemInfoId))
|
||
{
|
||
Debug.LogError("Error SetEndIndex");
|
||
return;
|
||
}
|
||
SubItemInfoDic[SubItemInfoId].VEndIndex = _writePos;
|
||
}
|
||
|
||
//检查真实长度是否大于一个byte的存储,如果大于就需要整体偏移,最后设置真实的长度
|
||
public static int CheckAndSetLength(int SubItemInfoId)
|
||
{
|
||
if (!SubItemInfoDic.ContainsKey(SubItemInfoId))
|
||
{
|
||
Debug.LogError("Error CheckAndSetLength");
|
||
return 0;
|
||
}
|
||
int length = 1;
|
||
SubItemInfo subItemInfo = SubItemInfoDic[SubItemInfoId];
|
||
int realLength = subItemInfo.VEndIndex - subItemInfo.VBeginIndex;
|
||
int lengthIndex = subItemInfo.LBeginIndex;
|
||
if (realLength > 127)
|
||
{
|
||
if (realLength > 16383)
|
||
{
|
||
//偏移2个位置
|
||
Move(lengthIndex + 1, lengthIndex + 3, realLength);
|
||
length = 3;
|
||
}
|
||
else
|
||
{
|
||
//偏移1个位置
|
||
Move(lengthIndex + 1, lengthIndex + 2, realLength);
|
||
length = 2;
|
||
}
|
||
}
|
||
//设置真实的长度
|
||
do
|
||
{
|
||
_bytesCache[lengthIndex++] = (byte)(realLength & 0x7F | 0x80);
|
||
}
|
||
while ((realLength >>= 7) != 0);
|
||
_bytesCache[lengthIndex - 1] &= 0x7F;
|
||
return length;
|
||
}
|
||
|
||
//byte数组中的内容整体移动
|
||
private static void Move(int srcOffset, int desOffset, int count)
|
||
{
|
||
Buffer.BlockCopy(_bytesCache, srcOffset, _bytesCache, desOffset, count);
|
||
_writePos += desOffset - srcOffset;
|
||
}
|
||
|
||
//获取数据
|
||
public static byte[] GetData()
|
||
{
|
||
var bytes = GetByteArrFormPool(_writePos);
|
||
Buffer.BlockCopy(_bytesCache, 0, bytes, 0, _writePos);
|
||
return bytes;
|
||
}
|
||
|
||
//从缓存池获取bytes
|
||
private static byte[] GetByteArrFormPool(int length)
|
||
{
|
||
return BytesPool.GetBytes(length);
|
||
}
|
||
|
||
//回收bytes
|
||
public static void Free(byte[] bytes)
|
||
{
|
||
BytesPool.Free(bytes);
|
||
}
|
||
|
||
//写内容头
|
||
public static void WriteHeader(int fieldNumber, WireType wireType)
|
||
{
|
||
uint header = (((uint)fieldNumber) << 3) | (((uint)wireType) & 7);
|
||
WriteUInt32Variant(header);
|
||
}
|
||
|
||
//=========[T-V]========
|
||
|
||
//可变长度Variant 32位
|
||
private static uint Zig(int value)
|
||
{
|
||
return (uint)((value << 1) ^ (value >> 31));
|
||
}
|
||
|
||
//可变长度Variant 64位
|
||
private static ulong Zig(long value)
|
||
{
|
||
return (ulong)((value << 1) ^ (value >> 63));
|
||
}
|
||
|
||
//可变长度write type = 0
|
||
private static void WriteUInt32Variant(uint value)
|
||
{
|
||
do
|
||
{
|
||
_bytesCache[_writePos++] = (byte)(value & 0x7F | 0x80);
|
||
}
|
||
while ((value >>= 7) != 0);
|
||
_bytesCache[_writePos - 1] &= 0x7F;
|
||
}
|
||
|
||
//可变长度write type = 0
|
||
private static void WriteUInt64Variant(ulong value)
|
||
{
|
||
do
|
||
{
|
||
_bytesCache[_writePos++] = (byte)(value & 0x7F | 0x80);
|
||
}
|
||
while ((value >>= 7) != 0);
|
||
_bytesCache[_writePos - 1] &= 0x7F;
|
||
}
|
||
|
||
//bool
|
||
public static void WriteBoolean(int fieldNumber, bool value)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.Variant);
|
||
WriteUInt32Variant(value ? (uint)1 : (uint)0);
|
||
}
|
||
|
||
//int32
|
||
public static void WriteInt32(int fieldNumber, int value)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.Variant);
|
||
if (value >= 0)
|
||
WriteUInt32Variant((uint)value);
|
||
else
|
||
{
|
||
_bytesCache[_writePos++] = (byte)(value & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 7 & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 14 & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 21 & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 28 & 0xF);
|
||
}
|
||
}
|
||
|
||
//int64
|
||
public static void WriteInt64(int fieldNumber, long value)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.Variant);
|
||
if (value >= 0)
|
||
WriteUInt64Variant((ulong)value);
|
||
else
|
||
{
|
||
_bytesCache[_writePos++] = (byte)(value & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 7 & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 14 & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 21 & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 28 & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 35 & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 42 & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 49 & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)(value >> 56 & 0x7F | 0x80);
|
||
_bytesCache[_writePos++] = (byte)1;
|
||
}
|
||
}
|
||
|
||
//uint32
|
||
public static void WriteUint32(int fieldNumber, uint value)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.Variant);
|
||
WriteUInt32Variant(value);
|
||
}
|
||
|
||
//uint64
|
||
public static void WriteUint64(int fieldNumber, ulong value)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.Variant);
|
||
WriteUInt64Variant(value);
|
||
}
|
||
|
||
//sint32
|
||
public static void WriteSint32(int fieldNumber, int value)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.Variant);
|
||
WriteUInt32Variant(Zig(value));
|
||
}
|
||
|
||
//sint64
|
||
public static void WriteSint64(int fieldNumber, long value)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.Variant);
|
||
WriteUInt64Variant(Zig(value));
|
||
}
|
||
|
||
//=========[固定32位]========
|
||
|
||
//32位写入byte数组
|
||
private static void WriteInt32ToBuffer(uint value)
|
||
{
|
||
_bytesCache[_writePos++] = (byte)value;
|
||
_bytesCache[_writePos++] = (byte)(value >> 8);
|
||
_bytesCache[_writePos++] = (byte)(value >> 16);
|
||
_bytesCache[_writePos++] = (byte)(value >> 24);
|
||
}
|
||
|
||
//Fixed32
|
||
public static void WriteFixed32(int fieldNumber, uint value)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.Fixed32);
|
||
WriteInt32ToBuffer(value);
|
||
}
|
||
|
||
//float
|
||
public static void WriteFloat(int fieldNumber, float value)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.Fixed32);
|
||
WriteInt32ToBuffer(MathLib.Float2Uint(value));
|
||
}
|
||
|
||
//=========[固定64位]========
|
||
|
||
//64位写入byte数组
|
||
private static void WriteInt64ToBuffer(ulong value)
|
||
{
|
||
_bytesCache[_writePos++] = (byte)value;
|
||
_bytesCache[_writePos++] = (byte)(value >> 8);
|
||
_bytesCache[_writePos++] = (byte)(value >> 16);
|
||
_bytesCache[_writePos++] = (byte)(value >> 24);
|
||
_bytesCache[_writePos++] = (byte)(value >> 32);
|
||
_bytesCache[_writePos++] = (byte)(value >> 40);
|
||
_bytesCache[_writePos++] = (byte)(value >> 48);
|
||
_bytesCache[_writePos++] = (byte)(value >> 56);
|
||
}
|
||
|
||
//Fixed64
|
||
public static void WriteFixed64(int fieldNumber, ulong value)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.Fixed64);
|
||
WriteInt64ToBuffer(value);
|
||
}
|
||
|
||
//double
|
||
public static void WriteDouble(int fieldNumber, double value)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.Fixed64);
|
||
WriteInt64ToBuffer(MathLib.Double2Ulong(value));
|
||
}
|
||
|
||
//==========[T-L-V]=======
|
||
|
||
//string
|
||
public static void WriteString(int fieldNumber, string value)
|
||
{
|
||
if (value == null)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.String);
|
||
WriteUInt32Variant(0);
|
||
return;
|
||
}
|
||
int len = value.Length;
|
||
if (len == 0)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.String);
|
||
WriteUInt32Variant(0);
|
||
return;
|
||
}
|
||
WriteHeader(fieldNumber, WireType.String);
|
||
int predicted = Encoding.GetByteCount(value);
|
||
WriteUInt32Variant((uint)predicted);
|
||
Encoding.GetBytes(value, 0, value.Length, _bytesCache, _writePos);
|
||
_writePos += predicted;
|
||
}
|
||
|
||
//byte[]
|
||
public static void WriteBytes(int fieldNumber, byte[] value)
|
||
{
|
||
if (value == null)
|
||
{
|
||
return;
|
||
}
|
||
int len = value.Length;
|
||
if (len == 0)
|
||
{
|
||
WriteHeader(fieldNumber, WireType.String);
|
||
WriteUInt32Variant(0);
|
||
return;
|
||
}
|
||
Buffer.BlockCopy(value, 0, _bytesCache, _writePos, len);
|
||
_writePos += len;
|
||
}
|
||
|
||
//==================================================[Read]===================================================
|
||
|
||
//可变长度Variant 32位
|
||
private static int Zag(uint ziggedValue)
|
||
{
|
||
int value = (int)ziggedValue;
|
||
return ((value >> 1) & Int32Max) ^ (-(value & 0x01));
|
||
}
|
||
|
||
//可变长度Variant 64位
|
||
private static long Zag(ulong ziggedValue)
|
||
{
|
||
long value = (long)ziggedValue;
|
||
return ((value >> 1) & ~Int64Max) ^ (-(value & 0x01L));
|
||
}
|
||
|
||
//初始化重置
|
||
public static void InitReadData(byte[] bytes, ref int readPos)
|
||
{
|
||
_readbytes = bytes;
|
||
readPos = 0;
|
||
}
|
||
|
||
//field_number 不能为负数
|
||
public static int ReadFieldNumber(ref int readPos)
|
||
{
|
||
int fieldNumber = 0;
|
||
int count = 1;
|
||
fieldNumber = (_readbytes[readPos] >> 3) & 0x4F;
|
||
while (_readbytes[readPos] >> 7 == 1)
|
||
{
|
||
fieldNumber |= (_readbytes[++readPos] & 0x7F) << (count++ * 7 - 3);
|
||
};
|
||
++readPos;
|
||
return fieldNumber;
|
||
}
|
||
|
||
//bool
|
||
public static bool ReadBoolean(ref int readPos)
|
||
{
|
||
return _readbytes[readPos++] == 1;
|
||
}
|
||
|
||
//Int32
|
||
public static int ReadInt32(ref int readPos)
|
||
{
|
||
//容错处理
|
||
return (int)ReadInt64(ref readPos);
|
||
//int result = 0;
|
||
//int count = 1;
|
||
//result = _readbytes[readPos] & 0x7F;
|
||
//while (_readbytes[readPos] >> 7 == 1)
|
||
//{
|
||
// result |= (_readbytes[++readPos] & 0x7F) << (count++ * 7);
|
||
//};
|
||
//++readPos;
|
||
//if(result < 0)
|
||
//{
|
||
// Debug.LogError(result +","+readPos);
|
||
// DebugBytes(_readbytes);
|
||
//}
|
||
//return result;
|
||
}
|
||
|
||
//Int64
|
||
public static long ReadInt64(ref int readPos)
|
||
{
|
||
long result = 0;
|
||
int count = 1;
|
||
result = _readbytes[readPos] & 0x7F;
|
||
while (_readbytes[readPos] >> 7 == 1)
|
||
{
|
||
result |= (long)(_readbytes[++readPos] & 0x7F) << (count++ * 7);
|
||
};
|
||
++readPos;
|
||
return result;
|
||
}
|
||
|
||
//Uint32
|
||
public static uint ReadUint32(ref int readPos)
|
||
{
|
||
uint result = 0;
|
||
int count = 1;
|
||
result = (uint)(_readbytes[readPos] & 0x7F);
|
||
while (_readbytes[readPos] >> 7 == 1)
|
||
{
|
||
result |= (uint)(_readbytes[++readPos] & 0x7F) << (count++ * 7);
|
||
};
|
||
++readPos;
|
||
return result;
|
||
}
|
||
|
||
//Uint64
|
||
public static ulong ReadUint64(ref int readPos)
|
||
{
|
||
ulong result = 0;
|
||
int count = 1;
|
||
result = (ulong)(_readbytes[readPos] & 0x7F);
|
||
while (_readbytes[readPos] >> 7 == 1)
|
||
{
|
||
result |= (ulong)(_readbytes[++readPos] & 0x7F) << (count++ * 7);
|
||
};
|
||
++readPos;
|
||
return result;
|
||
}
|
||
|
||
//sint32
|
||
public static int ReadSint32(ref int readPos)
|
||
{
|
||
return Zag(ReadUint32(ref readPos));
|
||
}
|
||
|
||
//sint64
|
||
public static long ReadSint64(ref int readPos)
|
||
{
|
||
return Zag(ReadUint64(ref readPos));
|
||
}
|
||
|
||
//Fixed32
|
||
public static uint ReadFixed32(ref int readPos)
|
||
{
|
||
return (uint)_readbytes[readPos++]
|
||
| (uint)_readbytes[readPos++] << 8
|
||
| (uint)_readbytes[readPos++] << 16
|
||
| (uint)_readbytes[readPos++] << 24;
|
||
}
|
||
|
||
//float
|
||
public static float ReadFloat(ref int readPos)
|
||
{
|
||
uint value = ReadFixed32(ref readPos);
|
||
return MathLib.Uint2Float(value);
|
||
}
|
||
|
||
//Fixed64
|
||
public static ulong ReadFixed64(ref int readPos)
|
||
{
|
||
return _readbytes[readPos++]
|
||
| (ulong)_readbytes[readPos++] << 8
|
||
| (ulong)_readbytes[readPos++] << 16
|
||
| (ulong)_readbytes[readPos++] << 24
|
||
| (ulong)_readbytes[readPos++] << 32
|
||
| (ulong)_readbytes[readPos++] << 40
|
||
| (ulong)_readbytes[readPos++] << 48
|
||
| (ulong)_readbytes[readPos++] << 56;
|
||
}
|
||
|
||
//double
|
||
public static double ReadDouble(ref int readPos)
|
||
{
|
||
ulong value = ReadFixed64(ref readPos);
|
||
return MathLib.Ulong2Double(value);
|
||
}
|
||
|
||
//=================T-L-V
|
||
|
||
//string
|
||
public static string ReadString(ref int readPos)
|
||
{
|
||
int len = ReadInt32(ref readPos);
|
||
if (len == 0)
|
||
{
|
||
return "";
|
||
}
|
||
string s = Encoding.GetString(_readbytes, readPos, len);
|
||
readPos += len;
|
||
return s;
|
||
}
|
||
|
||
//bytes
|
||
public static byte[] ReadBytes(ref int readPos)
|
||
{
|
||
int len = ReadInt32(ref readPos);
|
||
if (len == 0)
|
||
{
|
||
return null;
|
||
}
|
||
byte[] bytes = new byte[len];
|
||
Buffer.BlockCopy(_readbytes, readPos, bytes, 0, len);
|
||
readPos += len;
|
||
return bytes;
|
||
}
|
||
|
||
public static void DebugBytes()
|
||
{
|
||
DebugBytes(GetData());
|
||
}
|
||
|
||
public static void DebugBytes(byte[] bytes)
|
||
{
|
||
if (bytes != null && bytes.Length > 0)
|
||
{
|
||
StringBuilder sb = new StringBuilder();
|
||
for (int i = 0; i < bytes.Length; i++)
|
||
{
|
||
sb.Append(bytes[i]);
|
||
sb.Append(" ");
|
||
}
|
||
Debug.Log(sb.ToString());
|
||
return;
|
||
}
|
||
Debug.Log(string.Empty);
|
||
}
|
||
|
||
public static byte[] Serialize(IMessageInfo msg)
|
||
{
|
||
lock (WriteLocker)
|
||
{
|
||
InitWriteData();
|
||
int headLength = msg.WriteMessage(1) + 1;
|
||
var bytes = GetByteArrFormPool(_writePos - headLength);
|
||
Buffer.BlockCopy(_bytesCache, headLength, bytes, 0, _writePos - headLength);
|
||
return bytes;
|
||
}
|
||
}
|
||
|
||
public static void Deserialize(IMessageInfo msg, byte[] bytes)
|
||
{
|
||
lock (ReadLocker)
|
||
{
|
||
int readPos = 0;
|
||
InitReadData(bytes, ref readPos);
|
||
msg.ReadMessage(ref readPos, bytes.Length);
|
||
}
|
||
}
|
||
|
||
//子结构体信息
|
||
private class SubItemInfo
|
||
{
|
||
//L: 开始索引
|
||
public int LBeginIndex = 0;
|
||
//L: 预留长度
|
||
public int LCount = 0;
|
||
//V: 开始索引
|
||
public int VBeginIndex = 0;
|
||
//V: 结束索引
|
||
public int VEndIndex = 0;
|
||
}
|
||
|
||
//byte数组对象池
|
||
private class BytesPool
|
||
{
|
||
//bytes缓存
|
||
public static Dictionary<int, byte[]> _cacheByteDic = new Dictionary<int, byte[]>();
|
||
private static int _size = 0;
|
||
public static byte[] GetBytes(int length)
|
||
{
|
||
byte[] bytes = null;
|
||
if (!_cacheByteDic.TryGetValue(length, out bytes))
|
||
{
|
||
return new byte[length];
|
||
}
|
||
_cacheByteDic.Remove(length);
|
||
return bytes;
|
||
}
|
||
|
||
public static void Free(byte[] bytes)
|
||
{
|
||
if (bytes != null)
|
||
{
|
||
int length = bytes.Length;
|
||
if (_size + length > 1048576)
|
||
{
|
||
var iter = _cacheByteDic.GetEnumerator();
|
||
int maxLength = 0;
|
||
while (iter.MoveNext())
|
||
{
|
||
int itemLength = iter.Current.Value.Length;
|
||
if (itemLength > maxLength)
|
||
{
|
||
maxLength = itemLength;
|
||
}
|
||
}
|
||
_cacheByteDic.Remove(maxLength);
|
||
}
|
||
if (!_cacheByteDic.ContainsKey(length))
|
||
{
|
||
_cacheByteDic.Add(length, bytes);
|
||
_size += length;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} |