private static CodeGenContext BuildPacketPacker(IEnumerable <ProtocolContent> protocolContents, string direction) { var protocolPath = CodeGenUtil.SHARED_PROTOCOL_DIR_PATH; var directoryNamespace = CodeGenUtil.GetNamespaceFromDirectory(protocolPath) ?? throw new DirectoryNotFoundException(); var packetPacker = $"{direction}PacketPacker"; var protocolEnumType = $"{direction}PacketProtocol"; var code = new CodeGenContext(directoryPath: protocolPath, fileName: $"{packetPacker}.g.cs"); code.Line($"using Shared.Network;"); code.Line($"using Shared.Util;"); code.Line($"using System;"); code.LineSpace(); using (code.Scope($"namespace {directoryNamespace}")) { using (code.Scope($"public static class {packetPacker}")) { using (code.Scope($"private static void WriteHeader(BinaryEncoder encoder, {protocolEnumType} protocol, int bodySize)")) { code.Line("encoder.Write(in protocol);"); code.Line("encoder.Write(in bodySize);"); } foreach (var p in protocolContents) { using (code.Scope($"public static ArraySegment<byte> Pack_{direction}_{p.ProtocolName}({p.Parameters.Concat()})")) { code.Line($"var protocol = {protocolEnumType}.{direction}_{p.ProtocolName};"); code.LineSpace(); code.Line($"int bodySize = 0;"); foreach (var param in p.Parameters) { code.Line($"bodySize += {param.ParameterName}.SizeForWrite();"); } code.LineSpace(); code.Line($"int packetSize = {direction}PacketHeader.HEADER_SIZE + bodySize;"); code.LineSpace(); code.Line($"var packetBuffer = new ArraySegment<byte>(new byte[packetSize]);"); using (code.Scope($"using(var encoder = new BinaryEncoder(packetBuffer))")) { code.Line($"WriteHeader(encoder, protocol, bodySize);"); foreach (var param in p.Parameters) { code.Line($"encoder.Write(in {param.ParameterName});"); } } code.Line($"return packetBuffer;"); } } } } return(code); }
static void Main(string[] args) { CodeGenUtil.Initialize(); try { var docs = SchemaLoader.LoadXmlSchema("Schema"); var protocolsContents = ProtocolContentParser.Parse(docs); var codeGenContexts = ProtocolCodeBuilder.GenerateCode(protocolsContents); CodeGenExporter.Export(codeGenContexts); } catch (Exception e) { Environment.Exit(-1); } Environment.Exit(0); }
private static CodeGenContext BuildPacketHandlerInterface(IEnumerable <ProtocolContent> protocolContents, string direction) { var protocolPath = CodeGenUtil.SHARED_PROTOCOL_DIR_PATH; var directoryNamespace = CodeGenUtil.GetNamespaceFromDirectory(protocolPath) ?? throw new DirectoryNotFoundException(); var packetHandlerInterface = $"I{direction}PacketHandler"; var code = new CodeGenContext(directoryPath: protocolPath, fileName: $"{packetHandlerInterface}.g.cs"); using (code.Scope($"namespace {directoryNamespace}")) { using (code.Scope($"public interface {packetHandlerInterface}")) { foreach (var p in protocolContents) { code.Line($"void HANDLE_{direction}_{p.ProtocolName}({p.Parameters.Concat()});"); } } } return(code); }
private static CodeGenContext BuildPacketSender(IEnumerable <ProtocolContent> protocolContents, string direction) { var protocolPath = CodeGenUtil.SHARED_PROTOCOL_DIR_PATH; var directoryNamespace = CodeGenUtil.GetNamespaceFromDirectory(protocolPath) ?? throw new DirectoryNotFoundException(); var packetSender = $"{direction}PacketSender"; var packetPacker = $"{direction}PacketPacker"; var code = new CodeGenContext(directoryPath: protocolPath, fileName: $"{packetSender}.g.cs"); code.Line("using Shared.Network;"); code.Line("using System;"); code.LineSpace(); using (code.Scope($"namespace {directoryNamespace}")) { using (code.Scope($"public sealed class {packetSender}")) { code.Line("private AsyncTcpConnection m_Connection;"); using (code.Scope($"public {packetSender}(AsyncTcpConnection connection)")) { code.Line("m_Connection = connection ?? throw new ArgumentNullException(nameof(connection));"); } code.LineSpace(); foreach (var p in protocolContents) { using (code.Scope($"public void SEND_{direction}_{p.ProtocolName}({p.Parameters.Concat()})")) { code.Line($"var packet = {packetPacker}.Pack_{direction}_{p.ProtocolName}({p.Parameters.ConcatName()});"); code.Line($"m_Connection.Send(packet);"); } code.LineSpace(); } } } return(code); }
private static CodeGenContext BuildPacketProtocolEnum(IEnumerable <ProtocolContent> protocolContents, string direction) { var protocolPath = CodeGenUtil.SHARED_PROTOCOL_DIR_PATH; var directoryNamespace = CodeGenUtil.GetNamespaceFromDirectory(protocolPath) ?? throw new DirectoryNotFoundException(); var packetProtocolEnum = $"{direction}PacketProtocol"; var code = new CodeGenContext(directoryPath: protocolPath, fileName: $"{packetProtocolEnum}.g.cs"); using (code.Scope($"namespace {directoryNamespace}")) { using (code.Scope($"public enum {packetProtocolEnum}: int")) { code.Line($"Invalid,"); code.LineSpace(); foreach (var p in protocolContents) { code.Line($"{direction}_{p.ProtocolName},"); } } } return(code); }
private static CodeGenContext BuildPacketProcessor(IEnumerable <ProtocolContent> protocolContents, string direction) { var protocolPath = CodeGenUtil.SHARED_PROTOCOL_DIR_PATH; var directoryNamespace = CodeGenUtil.GetNamespaceFromDirectory(protocolPath) ?? throw new DirectoryNotFoundException(); var packetProcessor = $"{direction}PacketProcessor"; var packetHandlerInterface = $"I{direction}PacketHandler"; var packetHeader = $"{direction}PacketHeader"; var packetProtocol = $"{direction}PacketProtocol"; var code = new CodeGenContext(directoryPath: protocolPath, fileName: $"{packetProcessor}.g.cs"); code.Line($"using Shared.Network;"); code.Line($"using System;"); code.Line($"using System.Diagnostics;"); code.LineSpace(); using (code.Scope($"namespace {directoryNamespace}")) { using (code.Scope($"public sealed class {packetProcessor} : PacketProcessorBase")) { code.Line($"private readonly {packetHandlerInterface} m_PacketHandler;"); code.LineSpace(); using (code.Scope($"public {packetProcessor}({packetHandlerInterface} handler)")) { code.Line("m_PacketHandler = handler ?? throw new ArgumentNullException(nameof(handler));"); } using (code.Scope($"public int ParseAndHandlePacket(ArraySegment<byte> dataStream)")) { using (code.Scope($"if(!HasPacketHeader(dataStream))")) { code.Line($"return 0;"); } code.LineSpace(); code.Line("var packetHeader = ParseHeader(dataStream);"); using (code.Scope($"if(!HasPacketBody(dataStream, packetHeader))")) { code.Line($"return 0;"); } code.LineSpace(); code.Line("var packetBody = PeekPacketBody(dataStream, packetHeader);"); code.Line("ParseAndHandleBody(packetHeader, packetBody);"); code.LineSpace(); code.Line($"return {packetHeader}.HEADER_SIZE + packetHeader.BodySize;"); } using (code.Scope($"private void ParseAndHandleBody({packetHeader} header, ArraySegment<byte> body)")) { using (code.Scope("switch (header.Protocol)")) { foreach (var p in protocolContents) { code.Line($"case {packetProtocol}.{direction}_{p.ProtocolName}: ParseAndHandle_{direction}_{p.ProtocolName}(body); break;"); } } } code.Line("#region Packet Paser Method"); code.LineSpace(); using (code.Scope($"private static {packetHeader} ParseHeader(ArraySegment<byte> dataStream)")) { code.Line("Debug.Assert(dataStream.Array != null);"); code.Line("Debug.Assert(HasPacketHeader(dataStream));"); code.LineSpace(); code.Line("int number = BitConverter.ToInt32(dataStream.Array, dataStream.Offset);"); code.Line($"var protocol = {packetProtocol}.Invalid;"); using (code.Scope($"try")) { code.Line($"protocol = ({packetProtocol})number;"); } using (code.Scope($"catch (InvalidCastException)")) { code.Line($"throw;"); } code.LineSpace(); code.Line($"int bodySize = BitConverter.ToInt32(dataStream.Array, dataStream.Offset + sizeof(int));"); using (code.Scope($"if (bodySize < 0)")) { code.Line($"throw new ArgumentOutOfRangeException($\"패킷 BodySize가 음수입니다. ProtocolNumber[{{number}}] BodySize[{{bodySize}}]\");"); } code.LineSpace(); code.Line($"return new {packetHeader}(protocol, bodySize);"); } using (code.Scope("private static bool HasPacketHeader(ArraySegment<byte> dataStream)")) { code.Line($"return (dataStream.Count >= {packetHeader}.HEADER_SIZE);"); } using (code.Scope($"private static bool HasPacketBody(ArraySegment<byte> dataStream, {packetHeader} packetHeader)")) { code.Line($"return (dataStream.Count >= ({packetHeader}.HEADER_SIZE + packetHeader.BodySize));"); } using (code.Scope($"private static ArraySegment<byte> PeekPacketBody(ArraySegment<byte> dataStream, {packetHeader} packetHeader)")) { code.Line($"return new ArraySegment<byte>(dataStream.Array, dataStream.Offset + {packetHeader}.HEADER_SIZE, packetHeader.BodySize);"); } code.LineSpace(); code.Line("#endregion"); code.LineSpace(); code.Line("#region Packet handler Method"); code.LineSpace(); foreach (var p in protocolContents) { using (code.Scope($"private void ParseAndHandle_{direction}_{p.ProtocolName}(ArraySegment<byte> body)")) { using (code.Scope($"using (var reader = new BinaryDecoder(body))")) { foreach (var param in p.Parameters) { code.Line($"reader.Read(out {param.TypeName} {param.ParameterName});"); } code.LineSpace(); using (code.Scope($"RunOrReserveHandler(handler: async () =>")) { code.Line($"m_PacketHandler.HANDLE_{direction}_{p.ProtocolName}({p.Parameters.ConcatName()});"); } code.Line(");"); } } } code.LineSpace(); code.Line("#endregion"); } } return(code); }