- PDL.xml에 패킷 구조를 정의해두고 파싱할 예정 (Packet Definition List)
- 자동화 코드를 만들 때
1) 하드코딩
2) 재사용 할 수 있는 부분 찾기
3) 자동화하기
코드
PacketGenerator
PDL.xml
<?xml version="1.0" encoding="utf-8" ?>
<PDL>
<packet name="PlayerInfoReq">
<long name="playerId"/>
<string name="name"/>
<list name="skill">
<int name="id"/>
<short name="level"/>
<float name="duration"/>
</list>
</packet>
</PDL>
class PacketFormat
{
public static string packetFormat =
@"
class {0}
{{
{1}
public void Read(ArraySegment<byte> segment)
{{
ushort pos = 0;
ReadOnlySpan<byte> s = new ReadOnlySpan<byte>(segment.Array, segment.Offset, segment.Count);
pos += sizeof(ushort);
pos += sizeof(ushort);
{2}
}}
public ArraySegment<byte> Write()
{{
ArraySegment<byte> segment = SendBufferHelper.Open(4096); // SendBuffer의 _buffer
ushort size = 0;
bool success = true;
Span<byte> s = new Span<byte>(segment.Array, segment.Offset, segment.Count);
size += sizeof(ushort); // 2 : 패킷 size 사이즈
success &= BitConverter.TryWriteBytes(s.Slice(size, s.Length - size), (ushort)PacketID.{0}); // Slice가 Span<byte> 만들어서 반환하면 packetId를 그 범위에 바이트로 변환해서 씀
size += sizeof(ushort); // packetId 사이즈
{3}
success &= BitConverter.TryWriteBytes(s, size);
if (success == false)
return null; // 반환해서 밖에서 null체크
return SendBufferHelper.Close(size); // 최종 패킷 크기
}}
}}
";
public static string memberFormat =
@"public {0} {1}";
public static string readFormat =
@"this.{0} = BitConverter.{1}(s.Slice(pos, s.Length - pos));
pos += sizeof({2});";
public static string readStringFormat =
@"ushort {0}Len = BitConverter.ToUInt16(s.Slice(count, s.Length - count));
count += sizeof(ushort);
this.{0} = Encoding.Unicode.GetString(s.Slice(count, {0}Len));
count += {0}Len;";
public static string writeFormat =
@"success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), this.{0});
count += sizeof({1});";
public static string writeStringFormat =
@"ushort {0}Len = (ushort)Encoding.Unicode.GetBytes(this.{0}, 0, this.{0}.Length, segment.Array, segment.Offset + count + sizeof(ushort));
success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), {0}Len);
count += sizeof(ushort);
count += {0}Len;";
}
Program.cs
class Program
{
static void Main(string[] args)
{
XmlReaderSettings settings = new XmlReaderSettings()
{
IgnoreComments = true,
IgnoreWhitespace = true
};
using (XmlReader r = XmlReader.Create("PDL.xml", settings))
{
r.MoveToContent();
while(r.Read())
{
if (r.Depth == 1 && r.NodeType == XmlNodeType.Element)
ParsePacket(r);
}
}
}
public static void ParsePacket(XmlReader r)
{
if (r.NodeType == XmlNodeType.EndElement)
return;
if (r.Name.ToLower() != "packet")
{
Console.WriteLine("Packet 노드 invaild");
return;
}
string packetName = r["name"];
if(string.IsNullOrEmpty(packetName))
{
Console.WriteLine("Packet 이름 없음");
return;
}
ParseMembers(r);
}
public static void ParseMembers(XmlReader r)
{
string packetName = r["name"];
int depth = r.Depth + 1;
while(r.Read())
{
if (r.Depth != depth)
break;
string memberName = r["name"];
if(string.IsNullOrEmpty(memberName))
{
Console.WriteLine("member 이름 없음");
return;
}
string memberType = r.Name.ToLower();
switch(memberType)
{
case "bool":
case "byte":
case "short":
case "ushort":
case "int":
case "long":
case "float":
case "double":
case "string":
case "list":
break;
default:
break;
}
}
}
}