간단하게 패킷 자동화를 어떻게 할 수 있을지에 대한 개념이해를 위해 큰 틀을 짜놓는 작업을 하였다.
xml파일에 담긴 데이터를 읽어와 각 타입에 맞게 변화시키는 작업이 귀찮지만 굉장히 유용해서 추후 다른 프로젝트에서도 종종 사용할 수 있을 것 같다.
using (XmlReader x = XmlReader.Create("PDL.xml", settings))
{
x.MoveToContent();
while (x.Read())
{
if (x.Depth == 1 && x.NodeType == XmlNodeType.Element)
ParsePacket(x);
}
File.WriteAllText("GenPackets.cs", genPackets);
}
기존에 using문을 통해 랩핑해준 영역에서 while문이 종료되는 시점에 File.WriteAllText(저장경로, 내용)
를 통해 GenPackets.cs 파일을 만들어준다.
ParsePacket()에서 ParseMembers() 호출 이후의 데이터를 genPackets에 지난 시간에 선언해준 PacketFormat.packetFormat형식으로 담아준다.
genPackets += string.Format(PacketFormat.packetFormat,
packetName, , ,);
packetFormat은 총 4개의 값들({0}~{3}) 까지를 채워 넣어주어야 하기에 해당 값들은 아래에서 가져와 담아준다.
기존 void 타입이었던 함수를 Tuple<string, string, string>
로 선언하여 3개의 값을 리턴하도록 한다. *packetname의 경우는 이미 존재하기에
Tuple
메서드로부터 복수 개의 값들을 리턴받을 수 있는 기능
Switch문을 통해 memberType에 따라 동작 코드를 구분해 놓은 곳에 각 타입에 맞게 값을 담아준다.
PacketFormat - memberFormat에 필요한 두 가지일 경우 아래와 같이 미리 선언해둔 memberType, memberName을 넘겨 주고,
memberCode +=
string.Format(PacketFormat.memberFormat,
memberType, memberName);
readCode, writeCode 모두 같은 형식으로 담아준다. 여기서 readCode에 memberType의 경우는 ToInt16
같은 변환 타입이 필요한 위치이기에 함수를 만들어 값을 구해준다.
간단하게 각 타입별로 지정된 변환타입으로 return 값을 날려주면 된다.
string도 물론 비슷하지만, 아래와 같이 제작 시에 사용한 형태가 다르기에 Format 타입을 변경하여 그에 맞는 값을 넣어준다.
list 형식은 앞서 Tuple 리턴값을 가진 ParseListPacket()을 만들고, 값을 받아와 Tuple.Item숫자
이렇게 뽑아서 사용하면 된다.
리스트 형식 처리를 위한 함수를 제작한다. 우선 예외 처리를 위해 검사를 먼저 해주고,
public static Tuple<string, string, string> ParseListPacket(XmlReader x)
{
string listName = x["name"];
if (string.IsNullOrEmpty(listName))
{
Console.WriteLine("List without name");
return null;
}
Tuple 타입으로 memberCode에 넣기위한 값을 가져와 담아주고 나머지 값들은 이름의 대소문자 이기에 이를 가져오기 위한 함수를 따로 제작한다.
크게 복잡한 거는 없고, 첫 문자 값만 대문자 or 소문자로 바꿔주는 기능을 한다.
public static string FirstCharToUpper(string input)
{
if (string.IsNullOrEmpty(input))
return "";
return input[0].ToString().ToUpper() + input.Substring(1); // substring은 인자 부터 값 시작
}
public static string FirstCharToLower(string input)
{
if (string.IsNullOrEmpty(input))
return "";
return input[0].ToString().ToLower() + input.Substring(1);
}
}
그 뒤에 저장해두었던 Format에 맞추어 값을 잘 넣어주면 된다.
그렇게 적용한 함수 및 값들을 해당 Format에 맞게 담아주기만 하면 작업은 끝난다.
public static Tuple<string, string, string> ParseMembers(XmlReader x)
{
... 지난 시간 작성한 내용
switch (memberType)
{
case "bool":
case "byte":
case "short":
case "ushort":
case "int":
case "long":
case "float":
case "double":
memberCode += string.Format(PacketFormat.memberFormat, memberType, memberName);
readCode += string.Format(PacketFormat.readFormat, memberName, ToMemberType(memberType), memberType);
writeCode += string.Format(PacketFormat.writeFormat, memberName, memberType);
break;
case "string":
memberCode += string.Format(PacketFormat.memberFormat, memberType, memberName);
readCode += string.Format(PacketFormat.readStringFormat, memberName);
writeCode += string.Format(PacketFormat.writeStringFormat, memberName);
break;
case "list":
Tuple<string, string, string> t = ParseListPacket(x);
memberCode += t.Item1;
readCode += t.Item2;
writeCode += t.Item3;
break;
default:
break;
}
}
이제 작동을 시켜보면 GenPackets라는 파일이 생성되고 내용이 담겨있는 것을 확인할 수 있다.
다만 아마 파일 내용의 배치가 뛰어쓰기가 안되어있어 어색할텐데 이렇게 Replace
를 사용하여 공백인 경우 Enter
한 것과 같이 보이도록 작업을 해줄 수 있다
memberCode += memberCode.Replace("\n", "\n\t");
readCode += readCode.Replace("\n", "\n\t\t");
writeCode += writeCode.Replace("\n", "\n\t\t");
정리가 되면 새로 생성된 코드를 기존 ClientSession, ServerSession에 담아서 테스트 돌려보면 다시 정상적으로 동작하는 것을 확인할 수 있다.
PacketFormat 제작 시에 Count에 값 더하는 게 하나가 들어가지 않아서 계속 실행이 안되어 한참 원인을 찾았다.
Packet 영역을 구성할 때는 진짜 하나하나 신경을 잘 써야겠다.. 아니라면 바로 이렇게 동작하지 않아버리니 ㅠㅠ