/** * Unity-Compatible C# Generator for DeukPack * Unity DLL 호환성을 위한 C# 코드 생성기 */ using System; using System.Collections.Generic; using System.Text; using System.IO; namespace DeukPack.Unity { /// /// Unity 호환 Thrift 프로토콜 라이브러리 /// Unity 2020.3+ 지원 /// public enum TType : byte { Stop = 0, Void = 1, Bool = 2, Byte = 3, Double = 4, I16 = 6, I32 = 8, I64 = 10, String = 11, Binary = 11, Struct = 12, Map = 13, Set = 14, List = 15 } /// /// Unity 호환 Thrift 메시지 타입 /// public enum TMessageType : byte { Call = 1, Reply = 2, Exception = 3, Oneway = 4 } /// /// Unity 호환 Thrift 구조체 정보 /// [System.Serializable] public struct TStruct { public string Name; public TStruct(string name) { Name = name; } } /// /// Unity 호환 Thrift 필드 정보 /// [System.Serializable] public struct TField { public string Name; public TType Type; public short ID; public TField(string name, TType type, short id) { Name = name; Type = type; ID = id; } } /// /// Unity 호환 Thrift 리스트 정보 /// [System.Serializable] public struct TList { public TType ElementType; public int Count; public TList(TType elementType, int count) { ElementType = elementType; Count = count; } } /// /// Unity 호환 Thrift 셋 정보 /// [System.Serializable] public struct TSet { public TType ElementType; public int Count; public TSet(TType elementType, int count) { ElementType = elementType; Count = count; } } /// /// Unity 호환 Thrift 맵 정보 /// [System.Serializable] public struct TMap { public TType KeyType; public TType ValueType; public int Count; public TMap(TType keyType, TType valueType, int count) { KeyType = keyType; ValueType = valueType; Count = count; } } /// /// Unity 호환 Thrift 프로토콜 인터페이스 /// public interface TProtocol { void WriteStructBegin(TStruct structBegin); void WriteStructEnd(); void WriteFieldBegin(TField field); void WriteFieldEnd(); void WriteFieldStop(); void WriteBool(bool b); void WriteByte(byte b); void WriteI16(short i16); void WriteI32(int i32); void WriteI64(long i64); void WriteDouble(double d); void WriteString(string s); void WriteBinary(byte[] b); void WriteListBegin(TList list); void WriteListEnd(); void WriteSetBegin(TSet set); void WriteSetEnd(); void WriteMapBegin(TMap map); void WriteMapEnd(); TStruct ReadStructBegin(); void ReadStructEnd(); TField ReadFieldBegin(); void ReadFieldEnd(); bool ReadBool(); byte ReadByte(); short ReadI16(); int ReadI32(); long ReadI64(); double ReadDouble(); string ReadString(); byte[] ReadBinary(); TList ReadListBegin(); void ReadListEnd(); TSet ReadSetBegin(); void ReadSetEnd(); TMap ReadMapBegin(); void ReadMapEnd(); } /// /// Unity 호환 바이너리 프로토콜 /// Unity의 메모리 관리에 최적화 /// public class TBinaryProtocol : TProtocol { private byte[] _buffer; private int _offset; private bool _strictRead; private bool _strictWrite; public TBinaryProtocol(byte[] buffer, bool strictRead = true, bool strictWrite = true) { _buffer = buffer; _offset = 0; _strictRead = strictRead; _strictWrite = strictWrite; } public void WriteStructBegin(TStruct structBegin) { // Binary protocol doesn't write struct names } public void WriteStructEnd() { // Binary protocol doesn't write struct end markers } public void WriteFieldBegin(TField field) { WriteByte((byte)field.Type); WriteI16(field.ID); } public void WriteFieldEnd() { // Binary protocol doesn't write field end markers } public void WriteFieldStop() { WriteByte((byte)TType.Stop); } public void WriteBool(bool b) { WriteByte(b ? (byte)1 : (byte)0); } public void WriteByte(byte b) { if (_offset >= _buffer.Length) { Array.Resize(ref _buffer, _buffer.Length * 2); } _buffer[_offset++] = b; } public void WriteI16(short i16) { byte[] bytes = BitConverter.GetBytes(i16); if (!BitConverter.IsLittleEndian) { Array.Reverse(bytes); } WriteBytes(bytes); } public void WriteI32(int i32) { byte[] bytes = BitConverter.GetBytes(i32); if (!BitConverter.IsLittleEndian) { Array.Reverse(bytes); } WriteBytes(bytes); } public void WriteI64(long i64) { byte[] bytes = BitConverter.GetBytes(i64); if (!BitConverter.IsLittleEndian) { Array.Reverse(bytes); } WriteBytes(bytes); } public void WriteDouble(double d) { byte[] bytes = BitConverter.GetBytes(d); if (!BitConverter.IsLittleEndian) { Array.Reverse(bytes); } WriteBytes(bytes); } public void WriteString(string s) { byte[] bytes = Encoding.UTF8.GetBytes(s); WriteI32(bytes.Length); WriteBytes(bytes); } public void WriteBinary(byte[] b) { WriteI32(b.Length); WriteBytes(b); } public void WriteListBegin(TList list) { WriteByte((byte)list.ElementType); WriteI32(list.Count); } public void WriteListEnd() { // Binary protocol doesn't write list end markers } public void WriteSetBegin(TSet set) { WriteByte((byte)set.ElementType); WriteI32(set.Count); } public void WriteSetEnd() { // Binary protocol doesn't write set end markers } public void WriteMapBegin(TMap map) { WriteByte((byte)map.KeyType); WriteByte((byte)map.ValueType); WriteI32(map.Count); } public void WriteMapEnd() { // Binary protocol doesn't write map end markers } public TStruct ReadStructBegin() { return new TStruct(); } public void ReadStructEnd() { // Binary protocol doesn't read struct end markers } public TField ReadFieldBegin() { byte type = ReadByte(); if (type == (byte)TType.Stop) { return new TField("", TType.Stop, 0); } short id = ReadI16(); return new TField("", (TType)type, id); } public void ReadFieldEnd() { // Binary protocol doesn't read field end markers } public bool ReadBool() { return ReadByte() != 0; } public byte ReadByte() { if (_offset >= _buffer.Length) { throw new EndOfStreamException(); } return _buffer[_offset++]; } public short ReadI16() { byte[] bytes = ReadBytes(2); if (!BitConverter.IsLittleEndian) { Array.Reverse(bytes); } return BitConverter.ToInt16(bytes, 0); } public int ReadI32() { byte[] bytes = ReadBytes(4); if (!BitConverter.IsLittleEndian) { Array.Reverse(bytes); } return BitConverter.ToInt32(bytes, 0); } public long ReadI64() { byte[] bytes = ReadBytes(8); if (!BitConverter.IsLittleEndian) { Array.Reverse(bytes); } return BitConverter.ToInt64(bytes, 0); } public double ReadDouble() { byte[] bytes = ReadBytes(8); if (!BitConverter.IsLittleEndian) { Array.Reverse(bytes); } return BitConverter.ToDouble(bytes, 0); } public string ReadString() { int length = ReadI32(); byte[] bytes = ReadBytes(length); return Encoding.UTF8.GetString(bytes); } public byte[] ReadBinary() { int length = ReadI32(); return ReadBytes(length); } public TList ReadListBegin() { byte elementType = ReadByte(); int count = ReadI32(); return new TList((TType)elementType, count); } public void ReadListEnd() { // Binary protocol doesn't read list end markers } public TSet ReadSetBegin() { byte elementType = ReadByte(); int count = ReadI32(); return new TSet((TType)elementType, count); } public void ReadSetEnd() { // Binary protocol doesn't read set end markers } public TMap ReadMapBegin() { byte keyType = ReadByte(); byte valueType = ReadByte(); int count = ReadI32(); return new TMap((TType)keyType, (TType)valueType, count); } public void ReadMapEnd() { // Binary protocol doesn't read map end markers } private void WriteBytes(byte[] bytes) { if (_offset + bytes.Length > _buffer.Length) { Array.Resize(ref _buffer, Math.Max(_buffer.Length * 2, _offset + bytes.Length)); } Array.Copy(bytes, 0, _buffer, _offset, bytes.Length); _offset += bytes.Length; } private byte[] ReadBytes(int count) { if (_offset + count > _buffer.Length) { throw new EndOfStreamException(); } byte[] result = new byte[count]; Array.Copy(_buffer, _offset, result, 0, count); _offset += count; return result; } // Unity 호환성 메서드 public byte[] GetBuffer() { byte[] result = new byte[_offset]; Array.Copy(_buffer, 0, result, 0, _offset); return result; } public int GetOffset() { return _offset; } public void SetOffset(int offset) { _offset = offset; } } /// /// Unity 호환 Thrift 프로토콜 유틸리티 /// public static class TProtocolUtil { public static void Skip(TProtocol prot, TType type) { switch (type) { case TType.Bool: prot.ReadBool(); break; case TType.Byte: prot.ReadByte(); break; case TType.I16: prot.ReadI16(); break; case TType.I32: prot.ReadI32(); break; case TType.I64: prot.ReadI64(); break; case TType.Double: prot.ReadDouble(); break; case TType.String: prot.ReadBinary(); break; case TType.List: var list = prot.ReadListBegin(); for (int i = 0; i < list.Count; i++) { Skip(prot, list.ElementType); } prot.ReadListEnd(); break; case TType.Set: var set = prot.ReadSetBegin(); for (int i = 0; i < set.Count; i++) { Skip(prot, set.ElementType); } prot.ReadSetEnd(); break; case TType.Map: var map = prot.ReadMapBegin(); for (int i = 0; i < map.Count; i++) { Skip(prot, map.KeyType); Skip(prot, map.ValueType); } prot.ReadMapEnd(); break; case TType.Struct: prot.ReadStructBegin(); while (true) { var field = prot.ReadFieldBegin(); if (field.Type == TType.Stop) { break; } Skip(prot, field.Type); prot.ReadFieldEnd(); } prot.ReadStructEnd(); break; } } } /// /// Unity 호환 Thrift 직렬화 헬퍼 /// Unity의 메모리 관리에 최적화 /// public static class ThriftSerializer { private static readonly byte[] _tempBuffer = new byte[1024 * 1024]; // 1MB temp buffer public static byte[] Serialize(T obj) where T : IThriftSerializable { var protocol = new TBinaryProtocol(_tempBuffer, true, true); obj.Write(protocol); return protocol.GetBuffer(); } public static T Deserialize(byte[] data) where T : IThriftSerializable, new() { var protocol = new TBinaryProtocol(data, true, true); var obj = new T(); obj.Read(protocol); return obj; } } /// /// Unity 호환 Thrift 직렬화 인터페이스 /// public interface IThriftSerializable { void Write(TProtocol oprot); void Read(TProtocol iprot); } }