Last active
January 24, 2019 23:38
-
-
Save wildbook/6e15db8f5f91e099668477e84ee587f7 to your computer and use it in GitHub Desktop.
Ports moonshadow565's SiphoningStrike structs from C# to Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
import os | |
import sys | |
# Version 1 | |
# USAGE: | |
# corrode.py | |
# MISSING: | |
# detect fucked floats - "(reader.ReadByte() - 128) / 100.0f;" | |
# bunch of types | |
# sized_string | |
# sized_string_null | |
# string_null | |
# Vec | |
# .. and guaranteed a lot more .. | |
template_base = ( | |
'#[packet_id({packet_id})]' '\n' | |
'#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default)]' '\n' | |
'pub struct {packet_name} {{' '\n' | |
'{fields}' | |
'}}' '\n' | |
) | |
template_bitfield_field = ( | |
' {field_name}: bool = bitfield & {field_index} != 0,' '\n' | |
) | |
template_bitfield_serialization_field = ( | |
' if self.{field_name} {{' '\n' | |
' byte |= {field_index};' '\n' | |
' }}' '\n' | |
) | |
template_bitfield = ( | |
'make_bitfield! {{' '\n' | |
' #[derive(Copy, Clone, Debug, Default)]' '\n' | |
' pub struct {name} = bitfield: u8 {{' '\n' | |
'{bitfield_fields}' | |
' }}' '\n' | |
'}}' '\n' | |
'' '\n' | |
'impl serde::Serialize for {name} {{' '\n' | |
' fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>' '\n' | |
' where' '\n' | |
' S: serde::Serializer,' '\n' | |
' {{' '\n' | |
' let mut byte = 0;' '\n' | |
'{serialize_fields}' | |
' s.serialize_u8(byte)' '\n' | |
' }}' '\n' | |
'}}' | |
) | |
template_field = ( | |
'{serde}' | |
' pub {field_name}: {field_type},' '\n' | |
) | |
builtins = { | |
# Convert | |
"short" : "i16", | |
"byte" : "u8", | |
"int" : "i32", | |
"float" : "f32", | |
"uint" : "u32", | |
"string": "String", | |
"uint" : "u32" | |
} | |
def fix_case(input): | |
output = re.sub(r'([A-Z]+)', lambda m: '_' + m.group(1).lower(), input) | |
output = re.sub(r'^_', lambda m: '', output) | |
return output | |
def get_serde_tag(type, name, csharp): | |
serde = '' | |
if type == 'String': | |
fixed = re.search('this\.{name} = reader\.ReadFixedString\(([0-9]*)\);'.format(name = name), csharp) | |
zero_terminated = re.search('this\.{name} = reader\.ReadZeroTerminatedString\(([0-9]*)\);'.format(name = name), csharp) | |
if fixed: | |
length = fixed.group(1) | |
serde = ' #[serde(with = "crate::string_{length}")]\n'.format(length = length) | |
elif zero_terminated: | |
serde = ' #[serde(with = "crate::string_null")]\n' | |
else: | |
0/0 # crash. | |
return serde | |
def get_bitfield_struct(packet_name, bitfields_r, csharp): | |
bitfield_out = '' | |
bitfields = re.finditer('this\.(.*?) = \(bitfield', csharp) | |
serialize_fields = '' | |
bitfield_fields = '' | |
for bitfield_field in bitfields_r: | |
serde = '' | |
bitfield_field_name = bitfield_field.group(1) | |
bitfield_field_index = bitfield_field.group(2) | |
serialize_fields += template_bitfield_serialization_field.format( | |
field_name = fix_case(bitfield_field_name), | |
field_index = bitfield_field_index | |
) | |
bitfield_fields += template_bitfield_field.format( | |
field_name = fix_case(bitfield_field_name), | |
field_index = bitfield_field_index | |
) | |
bitfield_out += template_bitfield.format( | |
name = packet_name + '_Bitfield', | |
serialize_fields = serialize_fields, | |
bitfield_fields = bitfield_fields | |
) | |
return '' if bitfield_out == '' else '\n' + bitfield_out | |
def port_packet_file(csharp): | |
packet_name = re.search(r'class (.*?) ', csharp).group(1) | |
packet_id = re.search(r' : GamePacket(?:, [\w]*)* *\/\/ 0x([A-Fa-f\d]{0,2})', csharp).group(1) | |
found_bitfield = False | |
fields_r = re.finditer(r'public (\w*?) (\w*?) \{', csharp) | |
bitfields_r = list(re.finditer(r'this\.([^ ]*?) = \(bitfield & ([0-9]*)\) != 0;', csharp)) | |
fields = ''; | |
for field in fields_r: | |
type = builtins[field.group(1)] if field.group(1) in builtins else field.group(1) | |
name = field.group(2) | |
serde = get_serde_tag(type, name, csharp) | |
if not (name in map(lambda x: x.group(1), bitfields_r)): | |
fields += template_field.format( | |
serde = serde, | |
field_name = fix_case(name), | |
field_type = type) | |
elif not found_bitfield: | |
fields += template_field.format( | |
serde = serde, | |
field_name = 'bitfield', | |
field_type = packet_name + '_Bitfield') | |
found_bitfield = True | |
out = template_base.format( | |
packet_id = packet_id, | |
packet_name = packet_name, | |
fields = fields | |
) | |
out += get_bitfield_struct(packet_name, bitfields_r, csharp) | |
return out | |
root = "SiphoningStrike-master/SiphoningStrike/Game" | |
for file in os.listdir(root): | |
if file.endswith(".cs"): | |
print(os.path.join(root, file)) | |
with open(filename, 'r') as cs_file: | |
with open(filename[:-2] + 'rs', 'w+') as rs_file: | |
csharp = cs_file.read() | |
rs_file.write(port_packet_file(os.path.join(root, file))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment