ScrapHacks/tools/remaster/scrap_net/src/parser.rs

152 lines
6.2 KiB
Rust

use std::collections::HashMap;
use std::error::Error;
use crate::hex_ii::hex_ii_dump;
use crate::ServerFlags;
use binrw::BinReaderExt;
use binrw::{binread, BinRead, NullString};
/*
00000000: 7f 4c 00 00 06 ba ce 01 01 06 63 61 63 6f 74 61 | .L........cacota
00000010: 10 5b 42 4a 5a 5d 20 45 61 72 74 68 6e 75 6b 65 | .[BJZ].Earthnuke
00000020: 72 06 53 50 6f 6c 69 31 37 00 08 50 5f 50 6f 6c | r.SPoli17..P_Pol
00000030: 69 63 65 06 4d 50 4f 4c 49 31 00 00 00 0d 30 2c | ice.MPOLI1....0,
00000040: 30 2c 30 2c 31 2c 30 2c 30 2c 31 00 00 00 00 | 0,0,1,0,0,1....
00000000: 7f 49 00 00 06 ba ce 01 01 06 63 61 63 6f 74 61 | .I........cacota
00000010: 0e 55 6e 6e 61 6d 65 64 20 50 6c 61 79 65 72 07 | .Unnamed.Player.
00000020: 53 42 65 74 74 79 31 50 00 07 50 5f 42 65 74 74 | SBetty1P..P_Bett
00000030: 79 07 4d 42 65 74 74 79 31 00 00 00 0b 31 2c 31 | y.MBetty1....1,1
00000040: 2c 30 2c 31 2c 33 2c 30 00 00 00 00 | ,0,1,3,0....
*/
#[derive(Debug, Clone, BinRead)]
#[br(big)]
#[br(magic = b"\xba\xce")]
struct ServerInfoJoin {
#[br(map = |v: (u8,u8)| format!("{}.{}",v.0,v.1))]
version: String,
}
struct Data {
player_id: u32,
num_vals: u32,
pos: [f32; 3],
player_index: u32,
rtt: u32,
}
#[binread]
#[br(big)]
#[derive(Debug, Clone)]
enum PacketData {
#[br(magic = b"\x7f")]
PlayerJoin {
data_len: u8,
_1: u8,
cur_players: u8,
max_players: u8,
info: ServerInfoJoin,
#[br(temp)]
pw_len: u8,
#[br(count = pw_len, map = |bytes: Vec<u8>| String::from_utf8_lossy(&bytes).into_owned())]
password: String,
#[br(temp)]
player_name_len: u8,
#[br(count = player_name_len, map = |bytes: Vec<u8>| String::from_utf8_lossy(&bytes).into_owned())]
player_name: String,
#[br(temp)]
ship_model_len: u8,
#[br(count = ship_model_len, map = |bytes: Vec<u8>| String::from_utf8_lossy(&bytes).into_owned())]
ship_model: String,
#[br(little)]
max_health: u16,
#[br(temp)]
pilot_model_len: u8,
#[br(count = pilot_model_len, map = |bytes: Vec<u8>| String::from_utf8_lossy(&bytes).into_owned())]
pilot_model: String,
#[br(temp)]
engine_model_r_len: u8,
#[br(count = engine_model_r_len, map = |bytes: Vec<u8>| String::from_utf8_lossy(&bytes).into_owned())]
engine_model_r: String,
#[br(temp)]
engine_model_l_len: u8,
#[br(count = engine_model_r_len, map = |bytes: Vec<u8>| String::from_utf8_lossy(&bytes).into_owned())]
engine_model_l: String,
_2: u16,
#[br(temp)]
loadout_len: u8,
#[br(count = loadout_len, map = |bytes: Vec<u8>| String::from_utf8_lossy(&bytes).into_owned())]
loadout: String,
team_number: u16,
padding: [u8; 2],
},
#[br(magic = b"\x80\x15")]
MapInfo {
#[br(temp)]
map_len: u32,
#[br(count = map_len, map = |bytes: Vec<u8>| String::from_utf8_lossy(&bytes).into_owned())]
map: String,
#[br(temp)]
mode_len: u8,
#[br(count = mode_len, map = |bytes: Vec<u8>| String::from_utf8_lossy(&bytes).into_owned())]
mode: String,
_2: u16,
item_count: u8,
// _3: u32,
// #[br(count = item_count)]
// items: Vec<[u8;0x11]>
},
#[br(magic = b"\xba\xce")]
ServerInfo {
#[br(map = |v: (u8,u8)| format!("{}.{}",v.1,v.0))]
version: String,
port: u16,
max_players: u16,
cur_players: u16,
#[br(map = u8::into)]
flags: ServerFlags,
#[br(pad_size_to(0x20), map=|s: NullString| s.to_string())]
name: String,
#[br(pad_size_to(0x10), map=|s: NullString| s.to_string())]
mode: String,
#[br(pad_size_to(0x20), map=|s: NullString| s.to_string())]
map: String,
_pad: u8,
},
}
fn parse(data: &[u8]) -> Result<(PacketData, Vec<u8>), Box<dyn Error>> {
use std::io::Cursor;
let mut rdr = Cursor::new(data);
let pkt: PacketData = rdr.read_le()?;
let rest = data[rdr.position() as usize..].to_vec();
println!("{}", rhexdump::hexdump(data));
Ok((pkt, rest))
}
#[test]
fn test_parser() {
let log = include_str!("../test_.log").lines();
let mut hm = HashMap::new();
for line in log {
let data = line.split_ascii_whitespace().nth(1).unwrap();
let data = hex::decode(data).unwrap();
*hm.entry(data[0..1].to_vec()).or_insert(0usize) += 1;
match parse(&data) {
Ok((pkt, rest)) => {
println!("{:#x?}", pkt);
}
Err(e) => (),
}
}
let mut hm: Vec<(_, _)> = hm.iter().collect();
hm.sort_by_key(|(_, v)| *v);
for (k, v) in hm {
let k = k.iter().map(|v| format!("{:02x}", v)).collect::<String>();
println!("{} {}", k, v);
}
// println!("{:#x?}",parse("8015000000094c6576656c732f465a08466c616748756e7400000100000000000000000000000000000000000004105feb0006003e1125f3bc1300000019007e9dfa0404d5f9003f00000000000000000000"));
// println!("{:#x?}",parse("8015000000094c6576656c732f465a08466c616748756e7400002000000000000000000000000000000000000004105feb0006003e1125f3bc1300000019007e9dfa0404d5f9003f000000000000000000001f020b0376a8e2475b6e5b467c1e99461e020903982d14c5ec79cb45b2ee96471d020e03b29dbc46caa433464a28a0c71c020603aa80514658b8ab458db025c71b020803ce492f4658b8ab4514d320c71a02070344532f4658b8ab4587cf16c7190205031b3a0d4658b8ab459eaf25c7180206030ac34c4669e1fd469891ca47170208032e8c2a4669e1fd465500cd4716020703a4952a4669e1fd461b02d247150205037b7c084669e1fd460f92ca4714020603da6b7ec714aa3746b77c5a4713020803c87c83c714aa3746305a5f47120207039a7b83c714aa3746bd5d694711020503bfbe87c714aa3746a67d5a4710020803c5c719474ad5d445a7b3d2c60f0206037c5522474ad5d4459a6edcc60e02070323ca19474ad5d4458dacbec60d020503d84311474ad5d445bb6cdcc60c020603a9b16b47d52d974602dd15470b020803f2236347d52d97467bba1a470a02070350266347d52d974608be24470902050305a05a47d52d9746f1dd1547080206031f4066c6384b9c46955bd345070208037e3b84c6384b9c466147fa4506020703c33684c6384b9c46e431254605020503574395c6384b9c461063d34504020603ba349bc77a60294640f387c103020803957b9fc77a602946658f994402020703677a9fc77a60294680006d45010205038cbda3c77a602946807880c1"));
}