You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
6.9 KiB
221 lines
6.9 KiB
/*
|
|
Sog 游戏基础库
|
|
2016 by zouwei
|
|
*/
|
|
|
|
|
|
using System;
|
|
using System.Net;
|
|
using System.Text;
|
|
using System.Collections.Generic;
|
|
|
|
using Google.Protobuf.WellKnownTypes;
|
|
using Google.Protobuf;
|
|
|
|
namespace Sog
|
|
{
|
|
|
|
public class ProtoBufPacker : IProtoPacker
|
|
{
|
|
// todo 效率不高,换成数组
|
|
private Dictionary<int, MessageParser> m_typeMessageParser = new Dictionary<int, MessageParser>();
|
|
|
|
public ProtoBufPacker()
|
|
{
|
|
|
|
}
|
|
|
|
//最小8
|
|
public int GetHeaderLength()
|
|
{
|
|
return 8;
|
|
}
|
|
|
|
public int GetFullHeaderLength()
|
|
{
|
|
return 16;
|
|
}
|
|
|
|
//打包头
|
|
public int PackHeader(MessageHeader header, byte[] headerBytes)
|
|
{
|
|
//小字节序
|
|
if(header.ObjectID == 0)
|
|
{
|
|
headerBytes[0] = (byte)(header.Length % 256);
|
|
headerBytes[1] = (byte)(header.Length / 256);
|
|
|
|
headerBytes[2] = (byte)(header.Type % 256);
|
|
headerBytes[3] = (byte)(header.Type / 256);
|
|
|
|
Span<byte> pbServerID = new Span<byte>(headerBytes, 4, 4);
|
|
BitConverter.TryWriteBytes(pbServerID, header.ServerID);
|
|
|
|
return 8;
|
|
}
|
|
else
|
|
{
|
|
headerBytes[0] = (byte)(header.Length % 256);
|
|
headerBytes[1] = (byte)(header.Length / 256);
|
|
|
|
//最高位置1
|
|
int newType = header.Type | 0x8000;
|
|
|
|
headerBytes[2] = (byte)(newType % 256);
|
|
headerBytes[3] = (byte)(newType / 256);
|
|
|
|
Span<byte> pbServerID = new Span<byte>(headerBytes, 4, 4);
|
|
BitConverter.TryWriteBytes(pbServerID, header.ServerID);
|
|
|
|
Span<byte> pbObjectID = new Span<byte>(headerBytes, 8, 8);
|
|
BitConverter.TryWriteBytes(pbObjectID, header.ObjectID);
|
|
|
|
return 16;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//解包头
|
|
public int UnPackHeader(byte[] data, int offset, int length, ref MessageHeader header)
|
|
{
|
|
int byte0 = data[offset + 0];
|
|
int byte1 = data[offset + 1];
|
|
int byte2 = data[offset + 2];
|
|
int byte3 = data[offset + 3];
|
|
|
|
header.Length = byte1 * 256 + byte0;
|
|
header.Type = byte3 * 256 + byte2;
|
|
|
|
header.ServerID = BitConverter.ToUInt32(data, offset + 4);
|
|
|
|
bool haveObjectID = (header.Type & 0x00008000) > 0;
|
|
if (!haveObjectID)
|
|
{
|
|
return 8;
|
|
}
|
|
|
|
//头有16字节
|
|
if (length < 16)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//去掉最高位
|
|
header.Type &= 0x00007fff;
|
|
header.ObjectID = BitConverter.ToInt64(data, offset + 8);
|
|
|
|
|
|
return 16;
|
|
}
|
|
|
|
public virtual bool UnpackMessage(MessageData message, out RequestPacket packet)
|
|
{
|
|
try
|
|
{
|
|
MessageParser parser;
|
|
m_typeMessageParser.TryGetValue(message.Header.Type,out parser);
|
|
IMessage pbmessage = null;
|
|
|
|
packet = new RequestPacket(message.Header.Type, message.Header.ObjectID, message.Header.ServerID);
|
|
|
|
//现在工具用的还是class不是struct,之后看看要不要移动
|
|
//主要是message.Buffer.Data现在有缓存了,必须把message.Buffer.Length的正确长度传入
|
|
if (parser != null)
|
|
{
|
|
pbmessage = parser.ParseFrom(message.Buffer.Data, message.Buffer.Length);
|
|
}
|
|
else
|
|
{
|
|
TraceLog.Error("protobuf decode package type {0} error, can not find MessageParser,please register it first!"
|
|
, message.Header.Type);
|
|
|
|
return false;
|
|
}
|
|
|
|
packet.Message = pbmessage;
|
|
//packet.MsgID = message.Header.Type;
|
|
return true;
|
|
}
|
|
catch(Exception error)
|
|
{
|
|
TraceLog.Error("protobuf decode package type {0} error, {1}", message.Header.Type, error.Message);
|
|
packet = null;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public virtual bool PackMessage(RequestPacket packet, ref MessageData message)
|
|
{
|
|
try
|
|
{
|
|
//这个基本不用了,这里不cache了
|
|
message.Buffer.Data = MessageExtensions.ToByteArray((IMessage)packet.Message);
|
|
message.Buffer.Length = message.Buffer.Data.Length;
|
|
message.Header.Length = message.Buffer.Data.Length;
|
|
message.Header.Type = packet.MsgID;
|
|
|
|
|
|
//校验一下消息id,需要注册,不注册返回失败
|
|
//校验类型是否匹配
|
|
//影响效率
|
|
if (TraceLog.GetLogLevel() <= Log.LogLevel.Trace)
|
|
{
|
|
if (OSUtils.IsWindows())
|
|
{
|
|
MessageParser parser;
|
|
m_typeMessageParser.TryGetValue(packet.MsgID, out parser);
|
|
if (parser == null)
|
|
{
|
|
TraceLog.Error("protobuf encode package type {0} error, can not find MessageParser,please register it first!"
|
|
, packet.MsgID);
|
|
return false;
|
|
}
|
|
|
|
//windows下校验一下message是否会出问题
|
|
|
|
IMessage pbCheckMessage = parser.ParseFrom(message.Buffer.Data);
|
|
if (pbCheckMessage.GetType() != packet.Message.GetType())
|
|
{
|
|
TraceLog.Error("protobuf encode package type {0} error, Message type {1} != registed Message type {2}"
|
|
, packet.MsgID, packet.Message.GetType().Name, pbCheckMessage.GetType().Name);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
catch (Exception error)
|
|
{
|
|
TraceLog.Error("protobuf encode package type {0} error, {1}", message.Header.Type, error.Message);
|
|
packet = null;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//需要注册,提高效率
|
|
public void RegisterProtoType(int iMsgID, object obj)
|
|
{
|
|
MessageParser parser = (MessageParser)obj;
|
|
if(m_typeMessageParser.ContainsKey(iMsgID))
|
|
{
|
|
MessageParser oldparser = m_typeMessageParser[iMsgID];
|
|
|
|
TraceLog.Error("protobuf RegisterProtoType msgId {0} duplicate,registed name {1} new name {2}"
|
|
, iMsgID, oldparser.GetType().Name, parser.GetType().Name);
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
m_typeMessageParser.Add(iMsgID, parser);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|