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()
|
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)]
|
#[proc_macro_derive(PSOPacketData)]
|
||||||
pub fn pso_packet_data(input: TokenStream) -> TokenStream {
|
pub fn pso_packet_data(input: TokenStream) -> TokenStream {
|
||||||
let derive = parse_macro_input!(input as DeriveInput);
|
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(const_generics)]
|
||||||
|
#![feature(seek_convenience)]
|
||||||
|
|
||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
@ -117,7 +119,8 @@ pub trait PSOPacket: std::fmt::Debug {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use psopacket::{pso_packet, PSOPacketData};
|
use psopacket::{pso_packet, pso_message, PSOPacketData};
|
||||||
|
use crate::packet::messages::PSOMessage;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic_pso_packet() {
|
fn test_basic_pso_packet() {
|
||||||
@ -462,4 +465,63 @@ mod test {
|
|||||||
b: 456,
|
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 login;
|
||||||
pub mod patch;
|
pub mod patch;
|
||||||
pub mod ship;
|
pub mod ship;
|
||||||
|
pub mod messages;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user