corrade-vassal – Rev 1
?pathlinks?
using System;
using System.Collections.Generic;
using System.IO;
namespace mapgenerator
{
class mapgenerator
{
static void WriteFieldMember(TextWriter writer, MapField field)
{
string type = String.Empty;
switch (field.Type)
{
case FieldType.BOOL:
type = "bool";
break;
case FieldType.F32:
type = "float";
break;
case FieldType.F64:
type = "double";
break;
case FieldType.IPPORT:
case FieldType.U16:
type = "ushort";
break;
case FieldType.IPADDR:
case FieldType.U32:
type = "uint";
break;
case FieldType.LLQuaternion:
type = "Quaternion";
break;
case FieldType.LLUUID:
type = "UUID";
break;
case FieldType.LLVector3:
type = "Vector3";
break;
case FieldType.LLVector3d:
type = "Vector3d";
break;
case FieldType.LLVector4:
type = "Vector4";
break;
case FieldType.S16:
type = "short";
break;
case FieldType.S32:
type = "int";
break;
case FieldType.S8:
type = "sbyte";
break;
case FieldType.U64:
type = "ulong";
break;
case FieldType.U8:
type = "byte";
break;
case FieldType.Fixed:
type = "byte[]";
break;
}
if (field.Type != FieldType.Variable)
{
//writer.WriteLine(" /// <summary>" + field.Name + " field</summary>");
writer.WriteLine(" public " + type + " " + field.Name + ";");
}
else
{
writer.WriteLine(" public byte[] " + field.Name + ";");
//writer.WriteLine(" private byte[] _" + field.Name.ToLower() + ";");
////writer.WriteLine(" /// <summary>" + field.Name + " field</summary>");
//writer.WriteLine(" public byte[] " + field.Name + Environment.NewLine + " {");
//writer.WriteLine(" get { return _" + field.Name.ToLower() + "; }");
//writer.WriteLine(" set" + Environment.NewLine + " {");
//writer.WriteLine(" if (value == null) { _" +
// field.Name.ToLower() + " = null; return; }");
//writer.WriteLine(" if (value.Length > " +
// ((field.Count == 1) ? "255" : "1100") + ") { throw new OverflowException(" +
// "\"Value exceeds " + ((field.Count == 1) ? "255" : "1100") + " characters\"); }");
//writer.WriteLine(" else { _" + field.Name.ToLower() +
// " = new byte[value.Length]; Buffer.BlockCopy(value, 0, _" +
// field.Name.ToLower() + ", 0, value.Length); }");
//writer.WriteLine(" }" + Environment.NewLine + " }");
}
}
static void WriteFieldFromBytes(TextWriter writer, MapField field)
{
switch (field.Type)
{
case FieldType.BOOL:
writer.WriteLine(" " +
field.Name + " = (bytes[i++] != 0) ? (bool)true : (bool)false;");
break;
case FieldType.F32:
writer.WriteLine(" " +
field.Name + " = Utils.BytesToFloat(bytes, i); i += 4;");
break;
case FieldType.F64:
writer.WriteLine(" " +
field.Name + " = Utils.BytesToDouble(bytes, i); i += 8;");
break;
case FieldType.Fixed:
writer.WriteLine(" " + field.Name + " = new byte[" + field.Count + "];");
writer.WriteLine(" Buffer.BlockCopy(bytes, i, " + field.Name +
", 0, " + field.Count + "); i += " + field.Count + ";");
break;
case FieldType.IPADDR:
case FieldType.U32:
writer.WriteLine(" " + field.Name +
" = (uint)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24));");
break;
case FieldType.IPPORT:
// IPPORT is big endian while U16/S16 are little endian. Go figure
writer.WriteLine(" " + field.Name +
" = (ushort)((bytes[i++] << 8) + bytes[i++]);");
break;
case FieldType.U16:
writer.WriteLine(" " + field.Name +
" = (ushort)(bytes[i++] + (bytes[i++] << 8));");
break;
case FieldType.LLQuaternion:
writer.WriteLine(" " + field.Name + ".FromBytes(bytes, i, true); i += 12;");
break;
case FieldType.LLUUID:
writer.WriteLine(" " + field.Name + ".FromBytes(bytes, i); i += 16;");
break;
case FieldType.LLVector3:
writer.WriteLine(" " + field.Name + ".FromBytes(bytes, i); i += 12;");
break;
case FieldType.LLVector3d:
writer.WriteLine(" " + field.Name + ".FromBytes(bytes, i); i += 24;");
break;
case FieldType.LLVector4:
writer.WriteLine(" " + field.Name + ".FromBytes(bytes, i); i += 16;");
break;
case FieldType.S16:
writer.WriteLine(" " + field.Name +
" = (short)(bytes[i++] + (bytes[i++] << 8));");
break;
case FieldType.S32:
writer.WriteLine(" " + field.Name +
" = (int)(bytes[i++] + (bytes[i++] << 8) + (bytes[i++] << 16) + (bytes[i++] << 24));");
break;
case FieldType.S8:
writer.WriteLine(" " + field.Name +
" = (sbyte)bytes[i++];");
break;
case FieldType.U64:
writer.WriteLine(" " + field.Name +
" = (ulong)((ulong)bytes[i++] + ((ulong)bytes[i++] << 8) + " +
"((ulong)bytes[i++] << 16) + ((ulong)bytes[i++] << 24) + " +
"((ulong)bytes[i++] << 32) + ((ulong)bytes[i++] << 40) + " +
"((ulong)bytes[i++] << 48) + ((ulong)bytes[i++] << 56));");
break;
case FieldType.U8:
writer.WriteLine(" " + field.Name +
" = (byte)bytes[i++];");
break;
case FieldType.Variable:
if (field.Count == 1)
{
writer.WriteLine(" length = bytes[i++];");
}
else
{
writer.WriteLine(" length = (bytes[i++] + (bytes[i++] << 8));");
}
writer.WriteLine(" " + field.Name + " = new byte[length];");
writer.WriteLine(" Buffer.BlockCopy(bytes, i, " + field.Name + ", 0, length); i += length;");
break;
default:
writer.WriteLine("!!! ERROR: Unhandled FieldType: " + field.Type.ToString() + " !!!");
break;
}
}
static void WriteFieldToBytes(TextWriter writer, MapField field)
{
writer.Write(" ");
switch (field.Type)
{
case FieldType.BOOL:
writer.WriteLine("bytes[i++] = (byte)((" + field.Name + ") ? 1 : 0);");
break;
case FieldType.F32:
writer.WriteLine("Utils.FloatToBytes(" + field.Name + ", bytes, i); i += 4;");
break;
case FieldType.F64:
writer.WriteLine("Utils.DoubleToBytes(" + field.Name + ", bytes, i); i += 8;");
break;
case FieldType.Fixed:
writer.WriteLine("Buffer.BlockCopy(" + field.Name + ", 0, bytes, i, " + field.Count + ");" +
"i += " + field.Count + ";");
break;
case FieldType.IPPORT:
// IPPORT is big endian while U16/S16 is little endian. Go figure
writer.WriteLine("bytes[i++] = (byte)((" + field.Name + " >> 8) % 256);");
writer.WriteLine(" bytes[i++] = (byte)(" + field.Name + " % 256);");
break;
case FieldType.U16:
case FieldType.S16:
writer.WriteLine("bytes[i++] = (byte)(" + field.Name + " % 256);");
writer.WriteLine(" bytes[i++] = (byte)((" + field.Name + " >> 8) % 256);");
break;
case FieldType.LLQuaternion:
case FieldType.LLVector3:
writer.WriteLine(field.Name + ".ToBytes(bytes, i); i += 12;");
break;
case FieldType.LLUUID:
case FieldType.LLVector4:
writer.WriteLine(field.Name + ".ToBytes(bytes, i); i += 16;");
break;
case FieldType.LLVector3d:
writer.WriteLine(field.Name + ".ToBytes(bytes, i); i += 24;");
break;
case FieldType.U8:
writer.WriteLine("bytes[i++] = " + field.Name + ";");
break;
case FieldType.S8:
writer.WriteLine("bytes[i++] = (byte)" + field.Name + ";");
break;
case FieldType.IPADDR:
case FieldType.U32:
writer.WriteLine("Utils.UIntToBytes(" + field.Name + ", bytes, i); i += 4;");
break;
case FieldType.S32:
writer.WriteLine("Utils.IntToBytes(" + field.Name + ", bytes, i); i += 4;");
break;
case FieldType.U64:
writer.WriteLine("Utils.UInt64ToBytes(" + field.Name + ", bytes, i); i += 8;");
break;
case FieldType.Variable:
//writer.WriteLine("if(" + field.Name + " == null) { Console.WriteLine(\"Warning: " + field.Name + " is null, in \" + this.GetType()); }");
//writer.Write(" ");
if (field.Count == 1)
{
writer.WriteLine("bytes[i++] = (byte)" + field.Name + ".Length;");
}
else
{
writer.WriteLine("bytes[i++] = (byte)(" + field.Name + ".Length % 256);");
writer.WriteLine(" bytes[i++] = (byte)((" +
field.Name + ".Length >> 8) % 256);");
}
writer.WriteLine(" Buffer.BlockCopy(" + field.Name + ", 0, bytes, i, " +
field.Name + ".Length); " + "i += " + field.Name + ".Length;");
break;
default:
writer.WriteLine("!!! ERROR: Unhandled FieldType: " + field.Type.ToString() + " !!!");
break;
}
}
static int GetFieldLength(TextWriter writer, MapField field)
{
switch (field.Type)
{
case FieldType.BOOL:
case FieldType.U8:
case FieldType.S8:
return 1;
case FieldType.U16:
case FieldType.S16:
case FieldType.IPPORT:
return 2;
case FieldType.U32:
case FieldType.S32:
case FieldType.F32:
case FieldType.IPADDR:
return 4;
case FieldType.U64:
case FieldType.F64:
return 8;
case FieldType.LLVector3:
case FieldType.LLQuaternion:
return 12;
case FieldType.LLUUID:
case FieldType.LLVector4:
return 16;
case FieldType.LLVector3d:
return 24;
case FieldType.Fixed:
return field.Count;
case FieldType.Variable:
return 0;
default:
writer.WriteLine("!!! ERROR: Unhandled FieldType " + field.Type.ToString() + " !!!");
return 0;
}
}
static void WriteBlockClass(TextWriter writer, MapBlock block, MapPacket packet)
{
int variableFieldCountBytes = 0;
//writer.WriteLine(" /// <summary>" + block.Name + " block</summary>");
writer.WriteLine(" /// <exclude/>");
writer.WriteLine(" public sealed class " + block.Name + "Block : PacketBlock" + Environment.NewLine + " {");
foreach (MapField field in block.Fields)
{
WriteFieldMember(writer, field);
if (field.Type == FieldType.Variable) { variableFieldCountBytes += field.Count; }
}
// Length property
writer.WriteLine("");
//writer.WriteLine(" /// <summary>Length of this block serialized in bytes</summary>");
writer.WriteLine(" public override int Length" + Environment.NewLine +
" {" + Environment.NewLine +
" get" + Environment.NewLine +
" {");
int length = variableFieldCountBytes;
// Figure out the length of this block
foreach (MapField field in block.Fields)
{
length += GetFieldLength(writer, field);
}
if (variableFieldCountBytes == 0)
{
writer.WriteLine(" return " + length + ";");
}
else
{
writer.WriteLine(" int length = " + length + ";");
foreach (MapField field in block.Fields)
{
if (field.Type == FieldType.Variable)
{
writer.WriteLine(" if (" + field.Name +
" != null) { length += " + field.Name + ".Length; }");
}
}
writer.WriteLine(" return length;");
}
writer.WriteLine(" }" + Environment.NewLine + " }" + Environment.NewLine);
// Default constructor
//writer.WriteLine(" /// <summary>Default constructor</summary>");
writer.WriteLine(" public " + block.Name + "Block() { }");
// Constructor for building the class from bytes
//writer.WriteLine(" /// <summary>Constructor for building the block from a byte array</summary>");
writer.WriteLine(" public " + block.Name + "Block(byte[] bytes, ref int i)" + Environment.NewLine +
" {" + Environment.NewLine +
" FromBytes(bytes, ref i);" + Environment.NewLine +
" }" + Environment.NewLine);
// Initiates instance variables from a byte message
writer.WriteLine(" public override void FromBytes(byte[] bytes, ref int i)" + Environment.NewLine +
" {");
// Declare a length variable if we need it for variable fields in this constructor
if (variableFieldCountBytes > 0) { writer.WriteLine(" int length;"); }
// Start of the try catch block
writer.WriteLine(" try" + Environment.NewLine + " {");
foreach (MapField field in block.Fields)
{
WriteFieldFromBytes(writer, field);
}
writer.WriteLine(" }" + Environment.NewLine +
" catch (Exception)" + Environment.NewLine +
" {" + Environment.NewLine +
" throw new MalformedDataException();" + Environment.NewLine +
" }" + Environment.NewLine + " }" + Environment.NewLine);
// ToBytes() function
//writer.WriteLine(" /// <summary>Serialize this block to a byte array</summary>");
writer.WriteLine(" public override void ToBytes(byte[] bytes, ref int i)" + Environment.NewLine +
" {");
foreach (MapField field in block.Fields)
{
WriteFieldToBytes(writer, field);
}
writer.WriteLine(" }" + Environment.NewLine);
writer.WriteLine(" }" + Environment.NewLine);
}
static void WritePacketClass(TextWriter writer, MapPacket packet)
{
bool hasVariableBlocks = false;
string sanitizedName;
//writer.WriteLine(" /// <summary>" + packet.Name + " packet</summary>");
writer.WriteLine(" /// <exclude/>");
writer.WriteLine(" public sealed class " + packet.Name + "Packet : Packet" + Environment.NewLine + " {");
// Write out each block class
foreach (MapBlock block in packet.Blocks)
{
WriteBlockClass(writer, block, packet);
}
// Length member
writer.WriteLine(" public override int Length" + Environment.NewLine +
" {" + Environment.NewLine + " get" + Environment.NewLine +
" {");
int length = 0;
if (packet.Frequency == PacketFrequency.Low) { length = 10; }
else if (packet.Frequency == PacketFrequency.Medium) { length = 8; }
else { length = 7; }
foreach (MapBlock block in packet.Blocks)
{
if (block.Count == -1)
{
hasVariableBlocks = true;
++length;
}
}
writer.WriteLine(" int length = " + length + ";");
foreach (MapBlock block in packet.Blocks)
{
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == -1)
{
// Variable count block
writer.WriteLine(" for (int j = 0; j < " + sanitizedName + ".Length; j++)");
writer.WriteLine(" length += " + sanitizedName + "[j].Length;");
}
else if (block.Count == 1)
{
writer.WriteLine(" length += " + sanitizedName + ".Length;");
}
else
{
// Multiple count block
writer.WriteLine(" for (int j = 0; j < " + block.Count + "; j++)");
writer.WriteLine(" length += " + sanitizedName + "[j].Length;");
}
}
writer.WriteLine(" return length;");
writer.WriteLine(" }" + Environment.NewLine + " }");
// Block members
foreach (MapBlock block in packet.Blocks)
{
// TODO: More thorough name blacklisting
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
//writer.WriteLine(" /// <summary>" + block.Name + " block</summary>");
writer.WriteLine(" public " + block.Name + "Block" +
((block.Count != 1) ? "[]" : "") + " " + sanitizedName + ";");
}
writer.WriteLine("");
// Default constructor
//writer.WriteLine(" /// <summary>Default constructor</summary>");
writer.WriteLine(" public " + packet.Name + "Packet()" + Environment.NewLine + " {");
writer.WriteLine(" HasVariableBlocks = " + hasVariableBlocks.ToString().ToLowerInvariant() + ";");
writer.WriteLine(" Type = PacketType." + packet.Name + ";");
writer.WriteLine(" Header = new Header();");
writer.WriteLine(" Header.Frequency = PacketFrequency." + packet.Frequency + ";");
writer.WriteLine(" Header.ID = " + packet.ID + ";");
writer.WriteLine(" Header.Reliable = true;"); // Turn the reliable flag on by default
if (packet.Encoded) { writer.WriteLine(" Header.Zerocoded = true;"); }
foreach (MapBlock block in packet.Blocks)
{
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == 1)
{
// Single count block
writer.WriteLine(" " + sanitizedName + " = new " + block.Name + "Block();");
}
else if (block.Count == -1)
{
// Variable count block
writer.WriteLine(" " + sanitizedName + " = null;");
}
else
{
// Multiple count block
writer.WriteLine(" " + sanitizedName + " = new " + block.Name + "Block[" + block.Count + "];");
}
}
writer.WriteLine(" }" + Environment.NewLine);
// Constructor that takes a byte array and beginning position only (no prebuilt header)
bool seenVariable = false;
//writer.WriteLine(" /// <summary>Constructor that takes a byte array and beginning position (no prebuilt header)</summary>");
writer.WriteLine(" public " + packet.Name + "Packet(byte[] bytes, ref int i) : this()" + Environment.NewLine +
" {" + Environment.NewLine +
" int packetEnd = bytes.Length - 1;" + Environment.NewLine +
" FromBytes(bytes, ref i, ref packetEnd, null);" + Environment.NewLine +
" }" + Environment.NewLine);
writer.WriteLine(" override public void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer)" + Environment.NewLine + " {");
writer.WriteLine(" Header.FromBytes(bytes, ref i, ref packetEnd);");
writer.WriteLine(" if (Header.Zerocoded && zeroBuffer != null)");
writer.WriteLine(" {");
writer.WriteLine(" packetEnd = Helpers.ZeroDecode(bytes, packetEnd + 1, zeroBuffer) - 1;");
writer.WriteLine(" bytes = zeroBuffer;");
writer.WriteLine(" }");
foreach (MapBlock block in packet.Blocks)
{
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == 1)
{
// Single count block
writer.WriteLine(" " + sanitizedName + ".FromBytes(bytes, ref i);");
}
else if (block.Count == -1)
{
// Variable count block
if (!seenVariable)
{
writer.WriteLine(" int count = (int)bytes[i++];");
seenVariable = true;
}
else
{
writer.WriteLine(" count = (int)bytes[i++];");
}
writer.WriteLine(" if(" + sanitizedName + " == null || " + sanitizedName + ".Length != " + block.Count + ") {");
writer.WriteLine(" " + sanitizedName + " = new " + block.Name + "Block[count];");
writer.WriteLine(" for(int j = 0; j < count; j++)");
writer.WriteLine(" { " + sanitizedName + "[j] = new " + block.Name + "Block(); }");
writer.WriteLine(" }");
writer.WriteLine(" for (int j = 0; j < count; j++)");
writer.WriteLine(" { " + sanitizedName + "[j].FromBytes(bytes, ref i); }");
}
else
{
// Multiple count block
writer.WriteLine(" if(" + sanitizedName + " == null || " + sanitizedName + ".Length != " + block.Count + ") {");
writer.WriteLine(" " + sanitizedName + " = new " + block.Name + "Block[" + block.Count + "];");
writer.WriteLine(" for(int j = 0; j < " + block.Count + "; j++)");
writer.WriteLine(" { " + sanitizedName + "[j] = new " + block.Name + "Block(); }");
writer.WriteLine(" }");
writer.WriteLine(" for (int j = 0; j < " + block.Count + "; j++)");
writer.WriteLine(" { " + sanitizedName + "[j].FromBytes(bytes, ref i); }");
}
}
writer.WriteLine(" }" + Environment.NewLine);
seenVariable = false;
// Constructor that takes a byte array and a prebuilt header
//writer.WriteLine(" /// <summary>Constructor that takes a byte array and a prebuilt header</summary>");
writer.WriteLine(" public " + packet.Name + "Packet(Header head, byte[] bytes, ref int i): this()" + Environment.NewLine +
" {" + Environment.NewLine +
" int packetEnd = bytes.Length - 1;" + Environment.NewLine +
" FromBytes(head, bytes, ref i, ref packetEnd);" + Environment.NewLine +
" }" + Environment.NewLine);
writer.WriteLine(" override public void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd)" + Environment.NewLine +
" {");
writer.WriteLine(" Header = header;");
foreach (MapBlock block in packet.Blocks)
{
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == 1)
{
// Single count block
writer.WriteLine(" " + sanitizedName + ".FromBytes(bytes, ref i);");
}
else if (block.Count == -1)
{
// Variable count block
if (!seenVariable)
{
writer.WriteLine(" int count = (int)bytes[i++];");
seenVariable = true;
}
else
{
writer.WriteLine(" count = (int)bytes[i++];");
}
writer.WriteLine(" if(" + sanitizedName + " == null || " + sanitizedName + ".Length != count) {");
writer.WriteLine(" " + sanitizedName + " = new " + block.Name + "Block[count];");
writer.WriteLine(" for(int j = 0; j < count; j++)");
writer.WriteLine(" { " + sanitizedName + "[j] = new " + block.Name + "Block(); }");
writer.WriteLine(" }");
writer.WriteLine(" for (int j = 0; j < count; j++)");
writer.WriteLine(" { " + sanitizedName + "[j].FromBytes(bytes, ref i); }");
}
else
{
// Multiple count block
writer.WriteLine(" if(" + sanitizedName + " == null || " + sanitizedName + ".Length != " + block.Count + ") {");
writer.WriteLine(" " + sanitizedName + " = new " + block.Name + "Block[" + block.Count + "];");
writer.WriteLine(" for(int j = 0; j < " + block.Count + "; j++)");
writer.WriteLine(" { " + sanitizedName + "[j] = new " + block.Name + "Block(); }");
writer.WriteLine(" }");
writer.WriteLine(" for (int j = 0; j < " + block.Count + "; j++)");
writer.WriteLine(" { " + sanitizedName + "[j].FromBytes(bytes, ref i); }");
}
}
writer.WriteLine(" }" + Environment.NewLine);
#region ToBytes() Function
//writer.WriteLine(" /// <summary>Serialize this packet to a byte array</summary><returns>A byte array containing the serialized packet</returns>");
writer.WriteLine(" public override byte[] ToBytes()" + Environment.NewLine + " {");
writer.Write(" int length = ");
if (packet.Frequency == PacketFrequency.Low) { writer.WriteLine("10;"); }
else if (packet.Frequency == PacketFrequency.Medium) { writer.WriteLine("8;"); }
else { writer.WriteLine("7;"); }
foreach (MapBlock block in packet.Blocks)
{
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == 1)
{
// Single count block
writer.WriteLine(" length += " + sanitizedName + ".Length;");
}
}
foreach (MapBlock block in packet.Blocks)
{
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == -1)
{
writer.WriteLine(" length++;");
writer.WriteLine(" for (int j = 0; j < " + sanitizedName +
".Length; j++) { length += " + sanitizedName + "[j].Length; }");
}
else if (block.Count > 1)
{
writer.WriteLine(" for (int j = 0; j < " + block.Count +
"; j++) { length += " + sanitizedName + "[j].Length; }");
}
}
writer.WriteLine(" if (Header.AckList != null && Header.AckList.Length > 0) { length += Header.AckList.Length * 4 + 1; }");
writer.WriteLine(" byte[] bytes = new byte[length];");
writer.WriteLine(" int i = 0;");
writer.WriteLine(" Header.ToBytes(bytes, ref i);");
foreach (MapBlock block in packet.Blocks)
{
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == -1)
{
// Variable count block
writer.WriteLine(" bytes[i++] = (byte)" + sanitizedName + ".Length;");
writer.WriteLine(" for (int j = 0; j < " + sanitizedName +
".Length; j++) { " + sanitizedName + "[j].ToBytes(bytes, ref i); }");
}
else if (block.Count == 1)
{
writer.WriteLine(" " + sanitizedName + ".ToBytes(bytes, ref i);");
}
else
{
// Multiple count block
writer.WriteLine(" for (int j = 0; j < " + block.Count +
"; j++) { " + sanitizedName + "[j].ToBytes(bytes, ref i); }");
}
}
writer.WriteLine(" if (Header.AckList != null && Header.AckList.Length > 0) { Header.AcksToBytes(bytes, ref i); }");
writer.WriteLine(" return bytes;" + Environment.NewLine + " }" + Environment.NewLine);
#endregion ToBytes() Function
WriteToBytesMultiple(writer, packet);
writer.WriteLine(" }" + Environment.NewLine);
}
static void WriteToBytesMultiple(TextWriter writer, MapPacket packet)
{
writer.WriteLine(
" public override byte[][] ToBytesMultiple()" + Environment.NewLine +
" {");
// Check if there are any variable blocks
bool hasVariable = false;
bool cannotSplit = false;
foreach (MapBlock block in packet.Blocks)
{
if (block.Count == -1)
{
hasVariable = true;
}
else if (hasVariable)
{
// A fixed or single block showed up after a variable count block.
// Our automatic splitting algorithm won't work for this packet
cannotSplit = true;
break;
}
}
if (hasVariable && !cannotSplit)
{
writer.WriteLine(
" System.Collections.Generic.List<byte[]> packets = new System.Collections.Generic.List<byte[]>();");
writer.WriteLine(
" int i = 0;");
writer.Write(
" int fixedLength = ");
if (packet.Frequency == PacketFrequency.Low) { writer.WriteLine("10;"); }
else if (packet.Frequency == PacketFrequency.Medium) { writer.WriteLine("8;"); }
else { writer.WriteLine("7;"); }
writer.WriteLine();
// ACK serialization
writer.WriteLine(" byte[] ackBytes = null;");
writer.WriteLine(" int acksLength = 0;");
writer.WriteLine(" if (Header.AckList != null && Header.AckList.Length > 0) {");
writer.WriteLine(" Header.AppendedAcks = true;");
writer.WriteLine(" ackBytes = new byte[Header.AckList.Length * 4 + 1];");
writer.WriteLine(" Header.AcksToBytes(ackBytes, ref acksLength);");
writer.WriteLine(" }");
writer.WriteLine();
// Count fixed blocks
foreach (MapBlock block in packet.Blocks)
{
string sanitizedName;
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == 1)
{
// Single count block
writer.WriteLine(" fixedLength += " + sanitizedName + ".Length;");
}
else if (block.Count > 0)
{
// Fixed count block
writer.WriteLine(" for (int j = 0; j < " + block.Count + "; j++) { fixedLength += " + sanitizedName + "[j].Length; }");
}
}
// Serialize fixed blocks
writer.WriteLine(
" byte[] fixedBytes = new byte[fixedLength];");
writer.WriteLine(
" Header.ToBytes(fixedBytes, ref i);");
foreach (MapBlock block in packet.Blocks)
{
string sanitizedName;
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == 1)
{
// Single count block
writer.WriteLine(" " + sanitizedName + ".ToBytes(fixedBytes, ref i);");
}
else if (block.Count > 0)
{
// Fixed count block
writer.WriteLine(" for (int j = 0; j < " + block.Count + "; j++) { " + sanitizedName + "[j].ToBytes(fixedBytes, ref i); }");
}
}
int variableCountBlock = 0;
foreach (MapBlock block in packet.Blocks)
{
string sanitizedName;
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == -1)
{
// Variable count block
++variableCountBlock;
}
}
writer.WriteLine(" fixedLength += " + variableCountBlock + ";");
writer.WriteLine();
foreach (MapBlock block in packet.Blocks)
{
string sanitizedName;
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == -1)
{
// Variable count block
writer.WriteLine(" int " + sanitizedName + "Start = 0;");
}
}
writer.WriteLine(" do");
writer.WriteLine(" {");
// Count how many variable blocks can go in this packet
writer.WriteLine(" int variableLength = 0;");
foreach (MapBlock block in packet.Blocks)
{
string sanitizedName;
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == -1)
{
// Variable count block
writer.WriteLine(" int " + sanitizedName + "Count = 0;");
}
}
writer.WriteLine();
foreach (MapBlock block in packet.Blocks)
{
string sanitizedName;
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == -1)
{
// Variable count block
writer.WriteLine(" i = " + sanitizedName + "Start;");
writer.WriteLine(" while (fixedLength + variableLength + acksLength < Packet.MTU && i < " + sanitizedName + ".Length) {");
writer.WriteLine(" int blockLength = " + sanitizedName + "[i].Length;");
writer.WriteLine(" if (fixedLength + variableLength + blockLength + acksLength <= MTU) {");
writer.WriteLine(" variableLength += blockLength;");
writer.WriteLine(" ++" + sanitizedName + "Count;");
writer.WriteLine(" }");
writer.WriteLine(" else { break; }");
writer.WriteLine(" ++i;");
writer.WriteLine(" }");
writer.WriteLine();
}
}
// Create the packet
writer.WriteLine(" byte[] packet = new byte[fixedLength + variableLength + acksLength];");
writer.WriteLine(" int length = fixedBytes.Length;");
writer.WriteLine(" Buffer.BlockCopy(fixedBytes, 0, packet, 0, length);");
// Remove the appended ACKs flag from subsequent packets
writer.WriteLine(" if (packets.Count > 0) { packet[0] = (byte)(packet[0] & ~0x10); }");
writer.WriteLine();
foreach (MapBlock block in packet.Blocks)
{
string sanitizedName;
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == -1)
{
writer.WriteLine(" packet[length++] = (byte)" + sanitizedName + "Count;");
writer.WriteLine(" for (i = " + sanitizedName + "Start; i < " + sanitizedName + "Start + "
+ sanitizedName + "Count; i++) { " + sanitizedName + "[i].ToBytes(packet, ref length); }");
writer.WriteLine(" " + sanitizedName + "Start += " + sanitizedName + "Count;");
writer.WriteLine();
}
}
// ACK appending
writer.WriteLine(" if (acksLength > 0) {");
writer.WriteLine(" Buffer.BlockCopy(ackBytes, 0, packet, length, acksLength);");
writer.WriteLine(" acksLength = 0;");
writer.WriteLine(" }");
writer.WriteLine();
writer.WriteLine(" packets.Add(packet);");
writer.WriteLine(" } while (");
bool first = true;
foreach (MapBlock block in packet.Blocks)
{
string sanitizedName;
if (block.Name == "Header") { sanitizedName = "_" + block.Name; }
else { sanitizedName = block.Name; }
if (block.Count == -1)
{
if (first) first = false;
else writer.WriteLine(" ||");
// Variable count block
writer.Write(" " + sanitizedName + "Start < " + sanitizedName + ".Length");
}
}
writer.WriteLine(");");
writer.WriteLine();
writer.WriteLine(" return packets.ToArray();");
writer.WriteLine(" }");
}
else
{
writer.WriteLine(" return new byte[][] { ToBytes() };");
writer.WriteLine(" }");
}
}
static int Main(string[] args)
{
ProtocolManager protocol;
List<string> unused = new List<string>();
TextWriter writer;
try
{
if (args.Length != 4)
{
Console.WriteLine("Usage: [message_template.msg] [template.cs] [unusedpackets.txt] [_Packets_.cs]");
return -1;
}
writer = new StreamWriter(args[3]);
protocol = new ProtocolManager(args[0]);
// Build a list of unused packets
using (StreamReader unusedReader = new StreamReader(args[2]))
{
while (unusedReader.Peek() >= 0)
{
unused.Add(unusedReader.ReadLine().Trim());
}
}
// Read in the template.cs file and write it to our output
TextReader reader = new StreamReader(args[1]);
writer.WriteLine(reader.ReadToEnd());
reader.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return -2;
}
// Prune all of the unused packets out of the protocol
int i = 0;
foreach (MapPacket packet in protocol.LowMaps)
{
if (packet != null && unused.Contains(packet.Name))
protocol.LowMaps[i] = null;
i++;
}
i = 0;
foreach (MapPacket packet in protocol.MediumMaps)
{
if (packet != null && unused.Contains(packet.Name))
protocol.MediumMaps[i] = null;
i++;
}
i = 0;
foreach (MapPacket packet in protocol.HighMaps)
{
if (packet != null && unused.Contains(packet.Name))
protocol.HighMaps[i] = null;
i++;
}
// Write the PacketType enum
writer.WriteLine(" public enum PacketType" + Environment.NewLine + " {" + Environment.NewLine +
" /// <summary>A generic value, not an actual packet type</summary>" + Environment.NewLine +
" Default,");
foreach (MapPacket packet in protocol.LowMaps)
if (packet != null)
writer.WriteLine(" " + packet.Name + " = " + (0x10000 | packet.ID) + ",");
foreach (MapPacket packet in protocol.MediumMaps)
if (packet != null)
writer.WriteLine(" " + packet.Name + " = " + (0x20000 | packet.ID) + ",");
foreach (MapPacket packet in protocol.HighMaps)
if (packet != null)
writer.WriteLine(" " + packet.Name + " = " + (0x30000 | packet.ID) + ",");
writer.WriteLine(" }" + Environment.NewLine);
// Write the base Packet class
writer.WriteLine(
" public abstract partial class Packet" + Environment.NewLine + " {" + Environment.NewLine +
" public const int MTU = 1200;" + Environment.NewLine +
Environment.NewLine +
" public Header Header;" + Environment.NewLine +
" public bool HasVariableBlocks;" + Environment.NewLine +
" public PacketType Type;" + Environment.NewLine +
" public abstract int Length { get; }" + Environment.NewLine +
" public abstract void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer);" + Environment.NewLine +
" public abstract void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd);" + Environment.NewLine +
" public abstract byte[] ToBytes();" + Environment.NewLine +
" public abstract byte[][] ToBytesMultiple();"
);
writer.WriteLine();
// Write the Packet.GetType() function
writer.WriteLine(
" public static PacketType GetType(ushort id, PacketFrequency frequency)" + Environment.NewLine +
" {" + Environment.NewLine +
" switch (frequency)" + Environment.NewLine +
" {" + Environment.NewLine +
" case PacketFrequency.Low:" + Environment.NewLine +
" switch (id)" + Environment.NewLine +
" {");
foreach (MapPacket packet in protocol.LowMaps)
if (packet != null)
writer.WriteLine(" case " + packet.ID + ": return PacketType." + packet.Name + ";");
writer.WriteLine(" }" + Environment.NewLine +
" break;" + Environment.NewLine +
" case PacketFrequency.Medium:" + Environment.NewLine +
" switch (id)" + Environment.NewLine + " {");
foreach (MapPacket packet in protocol.MediumMaps)
if (packet != null)
writer.WriteLine(" case " + packet.ID + ": return PacketType." + packet.Name + ";");
writer.WriteLine(" }" + Environment.NewLine +
" break;" + Environment.NewLine +
" case PacketFrequency.High:" + Environment.NewLine +
" switch (id)" + Environment.NewLine + " {");
foreach (MapPacket packet in protocol.HighMaps)
if (packet != null)
writer.WriteLine(" case " + packet.ID + ": return PacketType." + packet.Name + ";");
writer.WriteLine(" }" + Environment.NewLine +
" break;" + Environment.NewLine + " }" + Environment.NewLine + Environment.NewLine +
" return PacketType.Default;" + Environment.NewLine + " }" + Environment.NewLine);
// Write the Packet.BuildPacket(PacketType) function
writer.WriteLine(" public static Packet BuildPacket(PacketType type)");
writer.WriteLine(" {");
foreach (MapPacket packet in protocol.HighMaps)
if (packet != null)
writer.WriteLine(" if(type == PacketType." + packet.Name + ") return new " + packet.Name + "Packet();");
foreach (MapPacket packet in protocol.MediumMaps)
if (packet != null)
writer.WriteLine(" if(type == PacketType." + packet.Name + ") return new " + packet.Name + "Packet();");
foreach (MapPacket packet in protocol.LowMaps)
if (packet != null)
writer.WriteLine(" if(type == PacketType." + packet.Name + ") return new " + packet.Name + "Packet();");
writer.WriteLine(" return null;" + Environment.NewLine);
writer.WriteLine(" }");
// Write the Packet.BuildPacket() function
writer.WriteLine(@"
public static Packet BuildPacket(byte[] packetBuffer, ref int packetEnd, byte[] zeroBuffer)
{
byte[] bytes;
int i = 0;
Header header = Header.BuildHeader(packetBuffer, ref i, ref packetEnd);
if (header.Zerocoded)
{
packetEnd = Helpers.ZeroDecode(packetBuffer, packetEnd + 1, zeroBuffer) - 1;
bytes = zeroBuffer;
}
else
{
bytes = packetBuffer;
}
Array.Clear(bytes, packetEnd + 1, bytes.Length - packetEnd - 1);
switch (header.Frequency)
{
case PacketFrequency.Low:
switch (header.ID)
{");
foreach (MapPacket packet in protocol.LowMaps)
if (packet != null)
writer.WriteLine(" case " + packet.ID + ": return new " + packet.Name + "Packet(header, bytes, ref i);");
writer.WriteLine(@"
}
break;
case PacketFrequency.Medium:
switch (header.ID)
{");
foreach (MapPacket packet in protocol.MediumMaps)
if (packet != null)
writer.WriteLine(" case " + packet.ID + ": return new " + packet.Name + "Packet(header, bytes, ref i);");
writer.WriteLine(@"
}
break;
case PacketFrequency.High:
switch (header.ID)
{");
foreach (MapPacket packet in protocol.HighMaps)
if (packet != null)
writer.WriteLine(" case " + packet.ID + ": return new " + packet.Name + "Packet(header, bytes, ref i);");
writer.WriteLine(@"
}
break;
}
throw new MalformedDataException(""Unknown packet ID "" + header.Frequency + "" "" + header.ID);
}
}");
// Write the packet classes
foreach (MapPacket packet in protocol.LowMaps)
if (packet != null) { WritePacketClass(writer, packet); }
foreach (MapPacket packet in protocol.MediumMaps)
if (packet != null) { WritePacketClass(writer, packet); }
foreach (MapPacket packet in protocol.HighMaps)
if (packet != null) { WritePacketClass(writer, packet); }
// Finish up
writer.WriteLine("}");
writer.Close();
return 0;
}
}
}