I thrown together the script I used in about 30 minutes when I needed it. It was just meant to save me time creating headers and code files for identical code structures for every packet. (In C++).
You'll need to modify most of the script to make it work with C#
Code:
use strict;
my $base_message_name;
my $namespace_name;
sub message_environment
{
my $namespace = shift;
my $base_message = shift;
$namespace_name = $namespace;
$base_message_name = $base_message;
};
sub enum {
my $udt = shift;
my $tcast = shift;
return { 'udt' => "$udt", 'tcast' => $tcast, 'size_type' => 0 };
}
sub int8 {
return { 'cpptype' => "int8_t", 'cstype' => "sbyte", 'size_type' => 1 };
}
sub int16 {
return { 'cpptype' => "int16_t", 'cstype' => "short", 'size_type' => 2 };
}
sub int32 {
return { 'cpptype' => "int32_t", 'cstype' => "long", 'size_type' => 4 };
}
sub uint8 {
return { 'cpptype' => "uint8_t", 'cstype' => "byte", 'size_type' => 1 };
}
sub uint16 {
return { 'cpptype' => "uint16_t", 'cstype' => "ushort", 'size_type' => 2 };
}
sub uint32 {
return { 'cpptype' => "uint32_t", 'cstype' => "ulong", 'size_type' => 4 };
}
sub string {
return { 'cpptype' => "std::string", 'cstype' => "string", 'size_type' => 4 };
}
sub string_list {
return { 'cpptype' => "std::vector<std::string> ", 'cstype' => "list<string>", 'size_type' => 3 };
}
sub fixed_string {
my $string_length = shift;
return { 'cpptype' => "std::string", 'cstype' => "string", 'str_len' => "$string_length", 'size_type' => 0 };
}
sub define_message
{
my $message_name = shift;
my $message_properties = shift;
my $message_id = shift;
my $message_default_length = shift;
my $ptype;
my $cpptype;
my $str_len;
my $fld;
my $size_type;
my $current_pos=0;
my $tcast;
my $casttype;
my $name_upper = "msg_$message_name";
$name_upper =~ tr/a-z/A-Z/;
open HEADER, ">packets/msg_$message_name.hpp" or die "unable to open header file\n";
open SOURCE, ">packets/msg_$message_name.cpp" or die "unable to open source file\n";
print HEADER "#ifndef msg_$message_name\_hpp\n";
print HEADER "#define msg_$message_name\_hpp\n";
print HEADER "\n";
print HEADER "#include \"$base_message_name.hpp\"\n";
print HEADER "\n";
print HEADER "namespace $namespace_name\n";
print HEADER "{\n";
print HEADER " class msg_$message_name : public $base_message_name\n";
print HEADER " {\n";
print HEADER " public:\n";
print HEADER " msg_$message_name();\n";
print HEADER " virtual ~msg_$message_name();\n";
print SOURCE "#include \"msg_$message_name.hpp\"\n";
print SOURCE "\n";
print SOURCE "namespace $namespace_name\n";
print SOURCE "{\n";
print SOURCE " msg_$message_name\::msg_$message_name()\n";
print SOURCE " : $base_message_name(id_msg_$message_name, msg_$message_name\_default_size)\n";
print SOURCE " {\n";
print SOURCE "\n";
print SOURCE " }\n";
print SOURCE "\n";
print SOURCE " msg_$message_name\::~msg_$message_name() {}\n";
print SOURCE "\n";
$current_pos = 4;
my @copy = @$message_properties;
while ($fld = shift @copy) {
$ptype = shift @copy;
$cpptype = $ptype->{'cpptype'};
$size_type = $ptype->{'size_type'};
$tcast="";
$str_len = 0;
if (exists $ptype->{'str_len'}) {
$str_len = $ptype->{'str_len'};
}
if (exists $ptype->{'tcast'}) {
$tcast = $ptype->{'tcast'};
$casttype = $tcast->{'cpptype'};
$size_type = $tcast->{'size_type'};
$cpptype = $ptype->{'udt'};
}
print HEADER "\n";
print HEADER " $cpptype $fld(void);\n";
print HEADER " void $fld($cpptype);\n";
print SOURCE "\n";
print SOURCE " $cpptype msg_$message_name\::$fld(void)\n";
print SOURCE " {\n";
if ($str_len==0) {
if ($tcast) {
print SOURCE " return ($cpptype)read<$casttype>($current_pos);\n";
}else {
print SOURCE " return read<$cpptype>($current_pos);\n";
}
} else {
print SOURCE " return read<$cpptype>($current_pos, $str_len);\n";
}
print SOURCE " }\n";
print SOURCE "\n";
print SOURCE " void msg_$message_name\::$fld($cpptype value)\n";
print SOURCE " {\n";
if ($str_len==0) {
if ($tcast) {
print SOURCE " write<$casttype>($current_pos, ($casttype)value);\n";
}else {
print SOURCE " write<$cpptype>($current_pos, value);\n";
}
} else {
print SOURCE " write<$cpptype>($current_pos, value, $str_len);\n";
}
print SOURCE " }\n";
$current_pos = $current_pos + $size_type + $str_len;
}
print HEADER " };\n";
print HEADER "\n";
print HEADER " const int id_msg_$message_name = $message_id;\n";
print HEADER "\n";
print HEADER " const int msg_$message_name\_default_size = $current_pos;\n";
print HEADER "}\n";
print HEADER "\n";
print HEADER "#endif // msg_$message_name\_hpp";
print HEADER "\n";
print SOURCE "}\n";
close HEADER;
close SOURCE;
}
Given the example you're using. You wrap the definition as an argument to the define_message function, and it generates a header and code file containing this.
Code:
#example
#note: blacknull is my namespace
# base_message is the base class which contains the read<> and write<> templates.
#message_environment only needs calling once each time the script is run, but you can define multiple messages in the same run.
message_environment ( "blacknull", "base_message" );
define_message (
item_vend => [
item_id => uint32(),
shop_id => uint32(),
price => uint32(),
item_type_id => uint32(),
max_dura => uint16(),
remaining_dura => uint16(),
item_info_mode => enum("ITEM_INFO_MODE", uint16()),
equipment_slot => enum("EQUIPMENT_SLOT", uint16()),
socket_1 => uint8(),
socket_2 => uint8(),
reborn_effect => uint16(),
composition => uint8(),
enchant => uint8(),
bless => uint8(),
padding1 => uint16(),
padding2 => uint32(),
], 0x454
);
Code:
/* msg_item_vend.hpp */
#ifndef msg_item_vend_hpp
#define msg_item_vend_hpp
#include "base_message.hpp"
namespace blacknull
{
class msg_item_vend : public base_message
{
public:
msg_item_vend();
virtual ~msg_item_vend();
uint32_t item_id(void);
void item_id(uint32_t);
uint32_t shop_id(void);
void shop_id(uint32_t);
uint32_t price(void);
void price(uint32_t);
uint32_t item_type_id(void);
void item_type_id(uint32_t);
uint16_t max_dura(void);
void max_dura(uint16_t);
uint16_t remaining_dura(void);
void remaining_dura(uint16_t);
ITEM_INFO_MODE item_info_mode(void);
void item_info_mode(ITEM_INFO_MODE);
EQUIPMENT_SLOT equipment_slot(void);
void equipment_slot(EQUIPMENT_SLOT);
uint8_t socket_1(void);
void socket_1(uint8_t);
uint8_t socket_2(void);
void socket_2(uint8_t);
uint16_t reborn_effect(void);
void reborn_effect(uint16_t);
uint8_t composition(void);
void composition(uint8_t);
uint8_t enchant(void);
void enchant(uint8_t);
uint8_t bless(void);
void bless(uint8_t);
uint16_t padding1(void);
void padding1(uint16_t);
uint32_t padding2(void);
void padding2(uint32_t);
};
const int id_msg_item_vend = 1108;
const int msg_item_vend_default_size = 41;
}
#endif // msg_item_vend_hpp
Code:
/* msg_item_vend.cpp */
#include "msg_item_vend.hpp"
namespace blacknull
{
msg_item_vend::msg_item_vend()
: base_message(id_msg_item_vend, msg_item_vend_default_size)
{
}
msg_item_vend::~msg_item_vend() {}
uint32_t msg_item_vend::item_id(void)
{
return read<uint32_t>(4);
}
void msg_item_vend::item_id(uint32_t value)
{
write<uint32_t>(4, value);
}
uint32_t msg_item_vend::shop_id(void)
{
return read<uint32_t>(8);
}
void msg_item_vend::shop_id(uint32_t value)
{
write<uint32_t>(8, value);
}
uint32_t msg_item_vend::price(void)
{
return read<uint32_t>(12);
}
void msg_item_vend::price(uint32_t value)
{
write<uint32_t>(12, value);
}
uint32_t msg_item_vend::item_type_id(void)
{
return read<uint32_t>(16);
}
void msg_item_vend::item_type_id(uint32_t value)
{
write<uint32_t>(16, value);
}
uint16_t msg_item_vend::max_dura(void)
{
return read<uint16_t>(20);
}
void msg_item_vend::max_dura(uint16_t value)
{
write<uint16_t>(20, value);
}
uint16_t msg_item_vend::remaining_dura(void)
{
return read<uint16_t>(22);
}
void msg_item_vend::remaining_dura(uint16_t value)
{
write<uint16_t>(22, value);
}
ITEM_INFO_MODE msg_item_vend::item_info_mode(void)
{
return (ITEM_INFO_MODE)read<uint16_t>(24);
}
void msg_item_vend::item_info_mode(ITEM_INFO_MODE value)
{
write<uint16_t>(24, (uint16_t)value);
}
EQUIPMENT_SLOT msg_item_vend::equipment_slot(void)
{
return (EQUIPMENT_SLOT)read<uint16_t>(26);
}
void msg_item_vend::equipment_slot(EQUIPMENT_SLOT value)
{
write<uint16_t>(26, (uint16_t)value);
}
uint8_t msg_item_vend::socket_1(void)
{
return read<uint8_t>(28);
}
void msg_item_vend::socket_1(uint8_t value)
{
write<uint8_t>(28, value);
}
uint8_t msg_item_vend::socket_2(void)
{
return read<uint8_t>(29);
}
void msg_item_vend::socket_2(uint8_t value)
{
write<uint8_t>(29, value);
}
uint16_t msg_item_vend::reborn_effect(void)
{
return read<uint16_t>(30);
}
void msg_item_vend::reborn_effect(uint16_t value)
{
write<uint16_t>(30, value);
}
uint8_t msg_item_vend::composition(void)
{
return read<uint8_t>(32);
}
void msg_item_vend::composition(uint8_t value)
{
write<uint8_t>(32, value);
}
uint8_t msg_item_vend::enchant(void)
{
return read<uint8_t>(33);
}
void msg_item_vend::enchant(uint8_t value)
{
write<uint8_t>(33, value);
}
uint8_t msg_item_vend::bless(void)
{
return read<uint8_t>(34);
}
void msg_item_vend::bless(uint8_t value)
{
write<uint8_t>(34, value);
}
uint16_t msg_item_vend::padding1(void)
{
return read<uint16_t>(35);
}
void msg_item_vend::padding1(uint16_t value)
{
write<uint16_t>(35, value);
}
uint32_t msg_item_vend::padding2(void)
{
return read<uint32_t>(37);
}
void msg_item_vend::padding2(uint32_t value)
{
write<uint32_t>(37, value);
}
}
The code here just points each part of the code to a place in the packet. The base class handles all the reading and writing.