pso_message macro
This commit is contained in:
parent
b692b8b417
commit
d2df4f6490
@ -404,6 +404,108 @@ pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
q.into()
|
||||
}
|
||||
|
||||
fn generate_psomessage_impl(msg_cmd: u8, name: syn::Ident, attrs: &Vec<AttrType>) -> proc_macro2::TokenStream {
|
||||
let from_bytes = generate_from_bytes(&attrs);
|
||||
let as_bytes = generate_as_bytes(&attrs);
|
||||
|
||||
quote! {
|
||||
impl PSOMessage for #name {
|
||||
const CMD: u8 = #msg_cmd;
|
||||
fn from_bytes<R: std::io::Read + std::io::Seek >(mut cur: &mut R) -> Result<#name, PacketParseError> {
|
||||
let mut buf1 = [0u8; 1];
|
||||
cur.read(&mut buf1).unwrap();
|
||||
let cmd = buf1[0];
|
||||
cur.read(&mut buf1).unwrap();
|
||||
let size = buf1[0];
|
||||
|
||||
let mut subbuf = vec![0u8; size as usize * 4 - 2];
|
||||
let len = cur.read(&mut subbuf).unwrap();
|
||||
|
||||
if cmd != #msg_cmd {
|
||||
return Err(PacketParseError::WrongPacketCommand);
|
||||
}
|
||||
|
||||
if len != size as usize * 4 - 2 {
|
||||
return Err(PacketParseError::WrongPacketSize(size as u16 * 4, len));
|
||||
}
|
||||
|
||||
let mut cur = std::io::Cursor::new(subbuf);
|
||||
let result = Ok(#name {
|
||||
#(#from_bytes)*
|
||||
});
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn as_bytes(&self) -> Vec<u8> {
|
||||
let mut buf = Vec::new();
|
||||
#(#as_bytes)*
|
||||
|
||||
while buf.len() % 4 != 2 {
|
||||
buf.push(0);
|
||||
}
|
||||
|
||||
let mut fullbuf = Vec::new();
|
||||
fullbuf.push(#msg_cmd);
|
||||
fullbuf.push((buf.len() as u8 + 2) / 4);
|
||||
fullbuf.extend_from_slice(&mut buf);
|
||||
|
||||
fullbuf
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let args = parse_macro_input!(attr as syn::AttributeArgs);
|
||||
let mut cmd = 0;
|
||||
for a in args {
|
||||
if let NestedMeta::Lit(lit) = a {
|
||||
if let syn::Lit::Int(litint) = lit {
|
||||
cmd = litint.base10_parse().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let pkt_struct = parse_macro_input!(item as ItemStruct);
|
||||
let mut attrs = match get_struct_fields(pkt_struct.fields.iter()) {
|
||||
Ok(a) => a,
|
||||
Err(err) => return err
|
||||
};
|
||||
|
||||
// this is a lot of work to make a `u8` token, surely this can be easier?
|
||||
let mut punctuated: syn::punctuated::Punctuated<syn::PathSegment, syn::Token![::]> = syn::punctuated::Punctuated::new();
|
||||
punctuated.push_value(syn::PathSegment {
|
||||
ident: syn::Ident::new("u8", proc_macro2::Span::call_site()),
|
||||
arguments: syn::PathArguments::None,
|
||||
});
|
||||
let u8tpath = syn::TypePath {
|
||||
qself: None,
|
||||
path: syn::Path {
|
||||
leading_colon: None,
|
||||
segments: punctuated
|
||||
}
|
||||
};
|
||||
attrs.insert(0, AttrType::Value(u8tpath.clone(), syn::Ident::new("target", proc_macro2::Span::call_site()), AttrMeta::None));
|
||||
attrs.insert(0, AttrType::Value(u8tpath, syn::Ident::new("client", proc_macro2::Span::call_site()), AttrMeta::None));
|
||||
|
||||
let struct_def = generate_struct_def(pkt_struct.ident.clone(), &attrs);
|
||||
let psopacket_impl = generate_psomessage_impl(cmd, pkt_struct.ident.clone(), &attrs);
|
||||
let debug_impl = generate_debug_impl(pkt_struct.ident.clone(), &attrs);
|
||||
let partialeq_impl = generate_partialeq_impl(pkt_struct.ident.clone(), &attrs);
|
||||
|
||||
let q = quote!{
|
||||
#[derive(Clone)]
|
||||
#struct_def
|
||||
#psopacket_impl
|
||||
#debug_impl
|
||||
#partialeq_impl
|
||||
};
|
||||
|
||||
q.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(PSOPacketData)]
|
||||
pub fn pso_packet_data(input: TokenStream) -> TokenStream {
|
||||
let derive = parse_macro_input!(input as DeriveInput);
|
||||
|
64
src/lib.rs
64
src/lib.rs
@ -1,4 +1,6 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(const_generics)]
|
||||
#![feature(seek_convenience)]
|
||||
|
||||
pub mod crypto;
|
||||
pub mod packet;
|
||||
@ -117,7 +119,8 @@ pub trait PSOPacket: std::fmt::Debug {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use psopacket::{pso_packet, PSOPacketData};
|
||||
use psopacket::{pso_packet, pso_message, PSOPacketData};
|
||||
use crate::packet::messages::PSOMessage;
|
||||
|
||||
#[test]
|
||||
fn test_basic_pso_packet() {
|
||||
@ -462,4 +465,63 @@ mod test {
|
||||
b: 456,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pso_message() {
|
||||
#[pso_message(0x23)]
|
||||
struct Test {
|
||||
a: u32,
|
||||
b: f32,
|
||||
}
|
||||
|
||||
let test = Test {
|
||||
client: 1,
|
||||
target: 2,
|
||||
a: 123,
|
||||
b: 4.56,
|
||||
};
|
||||
|
||||
let mut bytes = test.as_bytes();
|
||||
assert!(bytes == vec![35, 3, 1, 2, 123, 0, 0, 0, 133, 235, 145, 64]);
|
||||
|
||||
bytes[6] = 2;
|
||||
let test2 = Test::from_bytes(&mut std::io::Cursor::new(bytes)).unwrap();
|
||||
assert!(test2 == Test {
|
||||
client: 1,
|
||||
target: 2,
|
||||
a: 131195,
|
||||
b: 4.56,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pso_message_non_4_byte_size() {
|
||||
#[pso_message(0x23)]
|
||||
struct Test {
|
||||
a: u32,
|
||||
b: f32,
|
||||
c: u8,
|
||||
}
|
||||
|
||||
let test = Test {
|
||||
client: 1,
|
||||
target: 2,
|
||||
a: 123,
|
||||
b: 4.56,
|
||||
c: 5,
|
||||
};
|
||||
|
||||
let mut bytes = test.as_bytes();
|
||||
assert!(bytes == vec![35, 4, 1, 2, 123, 0, 0, 0, 133, 235, 145, 64, 5, 0, 0, 0]);
|
||||
|
||||
bytes[6] = 2;
|
||||
let test2 = Test::from_bytes(&mut std::io::Cursor::new(bytes)).unwrap();
|
||||
assert!(test2 == Test {
|
||||
client: 1,
|
||||
target: 2,
|
||||
a: 131195,
|
||||
b: 4.56,
|
||||
c: 5,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
45
src/packet/messages.rs
Normal file
45
src/packet/messages.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use std::io::{Seek, SeekFrom};
|
||||
|
||||
use psopacket::pso_message;
|
||||
use crate::{PSOPacketData, PacketParseError};
|
||||
|
||||
|
||||
pub trait PSOMessage {
|
||||
const CMD: u8;
|
||||
fn from_bytes<R: std::io::Read + std::io::Seek>(cur: &mut R) -> Result<Self, PacketParseError> where Self: Sized;
|
||||
fn as_bytes(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
|
||||
#[pso_message(0x40)]
|
||||
pub struct PlayerWalking {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub enum Message {
|
||||
PlayerWalking(PlayerWalking),
|
||||
}
|
||||
|
||||
impl PSOPacketData for Message {
|
||||
fn from_bytes<R: std::io::Read + std::io::Seek>(mut cur: &mut R) -> Result<Self, PacketParseError> {
|
||||
let mut byte = [0u8; 1];
|
||||
cur.read(&mut byte);
|
||||
cur.seek(SeekFrom::Current(-1)); // Cursor doesn't implement Peek?
|
||||
match byte[0] {
|
||||
PlayerWalking::CMD => Ok(Message::PlayerWalking(PlayerWalking::from_bytes(&mut cur)?)),
|
||||
_ => Err(PacketParseError::WrongPacketCommand),
|
||||
}
|
||||
}
|
||||
fn as_bytes(&self) -> Vec<u8> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod login;
|
||||
pub mod patch;
|
||||
pub mod ship;
|
||||
pub mod messages;
|
||||
|
Loading…
x
Reference in New Issue
Block a user