luban/src/Luban.Job.Cfg/Source/DataExporters/ProtobufBinExportor.cs

329 lines
10 KiB
C#

using Google.Protobuf;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.DataSources;
using Luban.Job.Cfg.DataVisitors;
using Luban.Job.Cfg.Defs;
using Luban.Job.Common.Generate;
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Luban.Job.Cfg.DataExporters
{
class ProtobufBinExportor : IDataActionVisitor<CodedOutputStream>
{
public static ProtobufBinExportor Ins { get; } = new();
public void WriteList(DefTable table, List<Record> datas, MemoryStream x)
{
var cos = new CodedOutputStream(x);
foreach (var d in datas)
{
cos.WriteTag(1, WireFormat.WireType.LengthDelimited);
d.Data.Apply(this, cos);
}
cos.Flush();
}
public void Accept(DBool type, CodedOutputStream x)
{
x.WriteBool(type.Value);
}
public void Accept(DByte type, CodedOutputStream x)
{
x.WriteInt32(type.Value);
}
public void Accept(DShort type, CodedOutputStream x)
{
x.WriteInt32(type.Value);
}
public void Accept(DFshort type, CodedOutputStream x)
{
x.WriteInt32(type.Value);
}
public void Accept(DInt type, CodedOutputStream x)
{
x.WriteInt32(type.Value);
}
public void Accept(DFint type, CodedOutputStream x)
{
x.WriteSFixed32(type.Value);
}
public void Accept(DLong type, CodedOutputStream x)
{
x.WriteInt64(type.Value);
}
public void Accept(DFlong type, CodedOutputStream x)
{
x.WriteSFixed64(type.Value);
}
public void Accept(DFloat type, CodedOutputStream x)
{
x.WriteFloat(type.Value);
}
public void Accept(DDouble type, CodedOutputStream x)
{
x.WriteDouble(type.Value);
}
public void Accept(DEnum type, CodedOutputStream x)
{
x.WriteInt32(type.Value);
}
public void Accept(DDateTime type, CodedOutputStream x)
{
x.WriteInt64(type.UnixTimeOfCurrentAssembly);
}
public void Accept(DString type, CodedOutputStream x)
{
x.WriteString(type.Value);
}
public void Accept(DBytes type, CodedOutputStream x)
{
x.WriteBytes(ByteString.CopyFrom(type.Value));
}
public void Accept(DText type, CodedOutputStream x)
{
// 此处与 binary格式不同. binary格式还包含了key
// 意味pb格式是无法支持动态本土化的。
x.WriteString(type.TextOfCurrentAssembly);
}
private MemoryStream AllocMemoryStream()
{
// TODO 优化
return new MemoryStream();
}
private void FreeMemoryStream(MemoryStream cos)
{
cos.Seek(0, SeekOrigin.Begin);
}
public void Accept(DVector2 type, CodedOutputStream x)
{
var ms = AllocMemoryStream();
var temp = new CodedOutputStream(ms);
temp.WriteTag(1, WireFormat.WireType.Fixed32);
temp.WriteFloat(type.Value.X);
temp.WriteTag(2, WireFormat.WireType.Fixed32);
temp.WriteFloat(type.Value.Y);
temp.Flush();
ms.Seek(0, SeekOrigin.Begin);
x.WriteBytes(ByteString.FromStream(ms));
FreeMemoryStream(ms);
}
public void Accept(DVector3 type, CodedOutputStream x)
{
var ms = AllocMemoryStream();
var temp = new CodedOutputStream(ms);
temp.WriteTag(1, WireFormat.WireType.Fixed32);
temp.WriteFloat(type.Value.X);
temp.WriteTag(2, WireFormat.WireType.Fixed32);
temp.WriteFloat(type.Value.Y);
temp.WriteTag(3, WireFormat.WireType.Fixed32);
temp.WriteFloat(type.Value.Z);
temp.Flush();
ms.Seek(0, SeekOrigin.Begin);
x.WriteBytes(ByteString.FromStream(ms));
FreeMemoryStream(ms);
}
public void Accept(DVector4 type, CodedOutputStream x)
{
var ms = AllocMemoryStream();
var temp = new CodedOutputStream(ms);
temp.WriteTag(1, WireFormat.WireType.Fixed32);
temp.WriteFloat(type.Value.X);
temp.WriteTag(2, WireFormat.WireType.Fixed32);
temp.WriteFloat(type.Value.Y);
temp.WriteTag(3, WireFormat.WireType.Fixed32);
temp.WriteFloat(type.Value.Z);
temp.WriteTag(4, WireFormat.WireType.Fixed32);
temp.WriteFloat(type.Value.W);
temp.Flush();
ms.Seek(0, SeekOrigin.Begin);
x.WriteBytes(ByteString.FromStream(ms));
FreeMemoryStream(ms);
}
private void WriteRawMessageWithoutLength(DBean type, CodedOutputStream temp)
{
//var ms = AllocMemoryStream();
//var temp = new CodedOutputStream(ms);
//if (bean.IsAbstractType)
//{
// temp.WriteTag(type.ImplType.AutoId, WireFormat.WireType.LengthDelimited);
//}
var defFields = type.ImplType.HierarchyFields;
int index = 0;
foreach (var field in type.Fields)
{
var defField = (DefField)defFields[index++];
if (!defField.NeedExport)
{
continue;
}
var fieldType = defField.CType;
if (field == null)
{
continue;
}
switch (field)
{
case DArray arr:
{
WriteList(fieldType.ElementType, defField.AutoId, arr.Datas, temp);
break;
}
case DList list:
{
WriteList(fieldType.ElementType, defField.AutoId, list.Datas, temp);
break;
}
case DSet set:
{
WriteList(fieldType.ElementType, defField.AutoId, set.Datas, temp);
break;
}
case DMap map:
{
WriteMap(map, defField.AutoId, temp);
break;
}
default:
{
temp.WriteTag(defField.AutoId, defField.CType.Apply(ProtobufWireTypeVisitor.Ins));
field.Apply(this, temp);
break;
}
}
}
//temp.Flush();
//ms.Seek(0, SeekOrigin.Begin);
//var bs = ByteString.FromStream(ms);
//x.WriteBytes(bs);
//FreeMemoryStream(ms);
}
private void EnterScope(CodedOutputStream x, Action<CodedOutputStream> action)
{
var ms = AllocMemoryStream();
var temp = new CodedOutputStream(ms);
action(temp);
temp.Flush();
ms.Seek(0, SeekOrigin.Begin);
var bs = ByteString.FromStream(ms);
x.WriteBytes(bs);
FreeMemoryStream(ms);
}
public void Accept(DBean type, CodedOutputStream x)
{
EnterScope(x, cos =>
{
var bean = type.Type;
if (bean.IsAbstractType)
{
cos.WriteTag(type.ImplType.AutoId, WireFormat.WireType.LengthDelimited);
EnterScope(cos, cos2 => WriteRawMessageWithoutLength(type, cos2));
}
else
{
WriteRawMessageWithoutLength(type, cos);
}
});
}
private void WriteList(TType elementType, int fieldId, List<DType> datas, CodedOutputStream x)
{
if (elementType.Apply(IsProtobufPackedType.Ins))
{
x.WriteTag(fieldId, WireFormat.WireType.LengthDelimited);
var ms = AllocMemoryStream();
var temp = new CodedOutputStream(ms);
foreach (var data in datas)
{
data.Apply(this, temp);
}
temp.Flush();
ms.Seek(0, SeekOrigin.Begin);
x.WriteBytes(ByteString.FromStream(ms));
FreeMemoryStream(ms);
}
else
{
var eleWireType = elementType.Apply(ProtobufWireTypeVisitor.Ins);
foreach (var data in datas)
{
x.WriteTag(fieldId, eleWireType);
data.Apply(this, x);
}
}
}
public void Accept(DArray type, CodedOutputStream x)
{
throw new NotImplementedException();
}
public void Accept(DList type, CodedOutputStream x)
{
throw new NotImplementedException();
}
public void Accept(DSet type, CodedOutputStream x)
{
throw new NotImplementedException();
}
private void WriteMap(DMap type, int fieldId, CodedOutputStream x)
{
var keyType = type.Type.KeyType;
var valueType = type.Type.ValueType;
var ms = AllocMemoryStream();
foreach (var e in type.Datas)
{
x.WriteTag(fieldId, WireFormat.WireType.LengthDelimited);
ms.Seek(0, SeekOrigin.Begin);
var temp = new CodedOutputStream(ms);
temp.WriteTag(1, keyType.Apply(ProtobufWireTypeVisitor.Ins));
e.Key.Apply(this, temp);
temp.WriteTag(2, valueType.Apply(ProtobufWireTypeVisitor.Ins));
e.Value.Apply(this, temp);
temp.Flush();
ms.Seek(0, SeekOrigin.Begin);
x.WriteBytes(ByteString.FromStream(ms));
}
FreeMemoryStream(ms);
}
public void Accept(DMap type, CodedOutputStream x)
{
throw new NotSupportedException();
}
}
}