Compare commits

..

No commits in common. "cleanuppery" and "master" have entirely different histories.

9 changed files with 139 additions and 1879 deletions

View File

@ -5,8 +5,6 @@ authors = ["Jake Probst <jake.probst@gmail.com>"]
edition = "2018"
[dependencies]
psopacket = { path = "psopacket" }
rand = "0.6.5"
chrono = "*"
serde = { version = "1.0", features = ["derive"]}
strum = { version = "0.25.0", features = ["derive"] }
psopacket = { path = "psopacket" }

View File

@ -8,6 +8,6 @@ edition = "2018"
proc-macro = true
[dependencies]
syn = {version = "2.0.39", features=["full", "extra-traits", "parsing"]}
syn = {version = "1.0", features=["full", "extra-traits", "parsing"]}
quote = "1.0"
proc-macro2 = "1.0"

View File

@ -6,10 +6,8 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use syn::{parse_macro_input, ItemStruct, DeriveInput, Field};
use syn::{parse_macro_input, ItemStruct, NestedMeta, DeriveInput, Field};
use syn::punctuated::Iter;
use syn::punctuated::Punctuated;
use syn::parse::Parse;
use quote::quote;
#[derive(Debug, PartialEq)]
@ -310,7 +308,7 @@ fn get_struct_fields(fields: Iter<Field>) -> Result<Vec<AttrType>, TokenStream>
}
let mut attr_meta = AttrMeta::None;
for attr in &field.attrs {
attr_meta = match attr.path().segments[0].ident.to_string().as_str() {
attr_meta = match attr.path.segments[0].ident.to_string().as_str() {
"utf8" => AttrMeta::Utf8,
"utf16" => AttrMeta::Utf16,
"nodebug" => AttrMeta::NoDebug,
@ -347,52 +345,35 @@ fn get_struct_fields(fields: Iter<Field>) -> Result<Vec<AttrType>, TokenStream>
}
#[derive(Debug)]
struct PSOPacketAttrs {
cmd: u16,
flag: bool,
manual_flag: bool,
}
impl Parse for PSOPacketAttrs {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let vars = Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated(input)?;
let (cmd, flag, manual_flag) = vars
.into_iter()
.fold((None, true, false), |mut acc, attr| {
match attr {
syn::Expr::Lit(lit) => {
if let syn::Lit::Int(int) = lit.lit {
acc.0 = int.base10_parse().ok();
}
},
syn::Expr::Path(path) => {
if path.path.is_ident("no_flag") {
acc.1 = false;
}
if path.path.is_ident("manual_flag") {
acc.1 = false;
acc.2 = true;
}
}
_ => {},
}
acc
});
Ok(PSOPacketAttrs {
cmd: cmd.unwrap(),
flag,
manual_flag
})
}
}
#[proc_macro_attribute]
pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream {
let args = parse_macro_input!(attr as PSOPacketAttrs);
let args = parse_macro_input!(attr as syn::AttributeArgs);
let mut cmd = 0;
let mut flag = true;
let mut manual_flag = false;
for a in args {
match &a {
NestedMeta::Lit(lit) => {
if let syn::Lit::Int(litint) = lit {
cmd = litint.base10_parse().unwrap();
}
},
NestedMeta::Meta(k) => {
if let syn::Meta::Path(syn::Path {segments, ..}) = k {
match segments[0].ident.to_string().as_str() {
"no_flag" => flag = false,
"manual_flag" => {
flag = false;
manual_flag = true;
},
_ => {
return syn::Error::new(segments[0].ident.span(), "unknown macro param").to_compile_error().into();
}
}
}
},
}
}
let pkt_struct = parse_macro_input!(item as ItemStruct);
let attrs = match get_struct_fields(pkt_struct.fields.iter()) {
@ -400,7 +381,7 @@ pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream {
Err(err) => return err
};
if args.manual_flag {
if manual_flag {
match &attrs[0] {
AttrType::Array(_, ident, _, _) => {
if ident.to_string() != "flag" {
@ -416,7 +397,7 @@ pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream {
}
let struct_def = generate_struct_def(pkt_struct.ident.clone(), &attrs);
let psopacket_impl = generate_psopacket_impl(args.cmd, pkt_struct.ident.clone(), &attrs, args.flag);
let psopacket_impl = generate_psopacket_impl(cmd, pkt_struct.ident.clone(), &attrs, flag);
let debug_impl = generate_debug_impl(pkt_struct.ident.clone(), &attrs);
let partialeq_impl = generate_partialeq_impl(pkt_struct.ident.clone(), &attrs);
@ -607,10 +588,18 @@ fn generate_psomessage_impl(msg_cmd: u8, name: syn::Ident, attrs: &Vec<AttrType>
#[proc_macro_attribute]
pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream {
let cmd = parse_macro_input!(attr as syn::LitInt).base10_parse().unwrap();
let pkt_struct = parse_macro_input!(item as ItemStruct);
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 mut fields = match get_struct_fields(pkt_struct.fields.iter()) {
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
};
@ -628,13 +617,13 @@ pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream {
segments: punctuated
}
};
fields.insert(0, AttrType::Value(u8tpath.clone(), syn::Ident::new("target", proc_macro2::Span::call_site()), AttrMeta::None));
fields.insert(0, AttrType::Value(u8tpath, syn::Ident::new("client", proc_macro2::Span::call_site()), AttrMeta::None));
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(), &fields);
let psopacket_impl = generate_psomessage_impl(cmd, pkt_struct.ident.clone(), &fields);
let debug_impl = generate_debug_impl(pkt_struct.ident.clone(), &fields);
let partialeq_impl = generate_partialeq_impl(pkt_struct.ident.clone(), &fields);
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)]
@ -647,7 +636,19 @@ pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream {
q.into()
}
fn pso_packet_data_struct(name: syn::Ident, fields: syn::Fields) -> TokenStream {
#[proc_macro_derive(PSOPacketData)]
pub fn pso_packet_data(input: TokenStream) -> TokenStream {
let derive = parse_macro_input!(input as DeriveInput);
let name = derive.ident;
let fields = if let syn::Data::Struct(strct) = derive.data {
strct.fields
}
else {
return syn::Error::new(name.span(), "PSOPacketData only works on structs").to_compile_error().into();
};
let attrs = match get_struct_fields(fields.iter()) {
Ok(a) => a,
Err(err) => return err
@ -683,75 +684,3 @@ fn pso_packet_data_struct(name: syn::Ident, fields: syn::Fields) -> TokenStream
q.into()
}
fn pso_packet_data_enum<'a>(name: syn::Ident, repr_type: syn::Ident, variants: impl Iterator<Item = &'a syn::Variant> + Clone) -> TokenStream {
let value_to_variant = variants
.clone()
.enumerate()
.map(|(i, variant)| {
let variant = &variant.ident;
quote! {
#i => #name::#variant,
}
})
.collect::<Vec<_>>();
let variant_to_value = variants
.enumerate()
.map(|(i, variant)| {
let variant = &variant.ident;
quote! {
#name::#variant => #repr_type::to_le_bytes(#i as #repr_type).to_vec(),
}
})
.collect::<Vec<_>>();
let impl_pso_data_packet = quote! {
impl PSOPacketData for #name {
fn from_bytes<R: std::io::Read + std::io::Seek>(mut cur: &mut R) -> Result<Self, PacketParseError> {
let mut buf = #repr_type::default().to_le_bytes();
cur.read_exact(&mut buf).unwrap();
let value = #repr_type::from_le_bytes(buf);
Ok(match value as usize {
#(#value_to_variant)*
_ => return Err(PacketParseError::InvalidValue)
})
}
fn as_bytes(&self) -> Vec<#repr_type> {
match self {
#(#variant_to_value)*
}
}
}
};
impl_pso_data_packet.into()
}
#[proc_macro_derive(PSOPacketData)]
pub fn pso_packet_data(input: TokenStream) -> TokenStream {
let derive = parse_macro_input!(input as DeriveInput);
let name = derive.ident;
if let syn::Data::Struct(strct) = derive.data {
pso_packet_data_struct(name, strct.fields)
}
else if let syn::Data::Enum(enm) = derive.data {
let repr_type = derive.attrs.iter().fold(None, |mut repr_type, attr| {
if attr.path().is_ident("repr") {
attr.parse_nested_meta(|meta| {
repr_type = Some(meta.path.get_ident().cloned().unwrap());
Ok(())
}).unwrap();
}
repr_type
});
pso_packet_data_enum(name, repr_type.unwrap(), enm.variants.iter())
}
else {
syn::Error::new(name.span(), "PSOPacketData only works on structs and enums").to_compile_error().into()
}
}

View File

@ -1,13 +1,12 @@
// TODO: ch_class to CharacterClass enum
// TODO: section_id to SectionId enum
// TODO: techniques to enum
use psopacket::PSOPacketData;
use crate::{PSOPacketData, PacketParseError};
use serde::{Serialize, Deserialize};
#[repr(u8)]
#[derive(PSOPacketData, Default, Debug, Copy, Clone, Hash, PartialEq, Eq, strum::Display, strum::EnumString, Serialize, Deserialize)]
pub enum CharacterClass {
#[default]
#[repr(u32)]
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub enum Class {
HUmar,
HUnewearl,
HUcast,
@ -22,78 +21,29 @@ pub enum CharacterClass {
FOnewearl,
}
// TODO: TryFrom
impl std::convert::From<u8> for CharacterClass {
fn from(f: u8) -> CharacterClass {
impl std::convert::From<u8> for Class {
fn from(f: u8) -> Class {
match f {
0 => CharacterClass::HUmar,
1 => CharacterClass::HUnewearl,
2 => CharacterClass::HUcast,
3 => CharacterClass::RAmar,
4 => CharacterClass::RAcast,
5 => CharacterClass::RAcaseal,
6 => CharacterClass::FOmarl,
7 => CharacterClass::FOnewm,
8 => CharacterClass::FOnewearl,
9 => CharacterClass::HUcaseal,
10 => CharacterClass::RAmarl,
11 => CharacterClass::FOmar,
0 => Class::HUmar,
1 => Class::HUnewearl,
2 => Class::HUcast,
3 => Class::RAmar,
4 => Class::RAcast,
5 => Class::RAcaseal,
6 => Class::FOmarl,
7 => Class::FOnewm,
8 => Class::FOnewearl,
9 => Class::HUcaseal,
10 => Class::RAmarl,
11 => Class::FOmar,
_ => panic!("unknown class")
}
}
}
impl From<CharacterClass> for u8 {
fn from(other: CharacterClass) -> u8 {
match other {
CharacterClass::HUmar => 0,
CharacterClass::HUnewearl => 1,
CharacterClass::HUcast => 2,
CharacterClass::RAmar => 3,
CharacterClass::RAcast => 4,
CharacterClass::RAcaseal => 5,
CharacterClass::FOmarl => 6,
CharacterClass::FOnewm => 7,
CharacterClass::FOnewearl => 8,
CharacterClass::HUcaseal => 9,
CharacterClass::FOmar => 10,
CharacterClass::RAmarl => 11,
}
}
}
impl CharacterClass {
pub fn is_human(&self) -> bool {
matches!(self,
CharacterClass::HUmar |
CharacterClass::RAmar |
CharacterClass::RAmarl |
CharacterClass::FOmar |
CharacterClass::FOmarl)
}
pub fn is_newman(&self) -> bool {
matches!(self,
CharacterClass::HUnewearl |
CharacterClass::FOnewm |
CharacterClass::FOnewearl)
}
pub fn is_android(&self) -> bool {
matches!(self,
CharacterClass::HUcast |
CharacterClass::HUcaseal |
CharacterClass::RAcast |
CharacterClass::RAcaseal)
}
}
#[repr(u8)]
#[derive(PSOPacketData, Default, Debug, Copy, Clone, Hash, PartialEq, Eq, strum::Display, strum::EnumString, Serialize, Deserialize)]
pub enum SectionID {
#[default]
Viridia,
Greenill,
Skyly,
@ -106,42 +56,6 @@ pub enum SectionID {
Whitill,
}
// TODO: TryFrom
impl From<u8> for SectionID {
fn from(id: u8) -> SectionID {
match id {
0 => SectionID::Viridia,
1 => SectionID::Greenill,
2 => SectionID::Skyly,
3 => SectionID::Bluefull,
4 => SectionID::Purplenum,
5 => SectionID::Pinkal,
6 => SectionID::Redria,
7 => SectionID::Oran,
8 => SectionID::Yellowboze,
9 => SectionID::Whitill,
_ => panic!(),
}
}
}
impl From<SectionID> for u8 {
fn from(other: SectionID) -> u8 {
match other {
SectionID::Viridia => 0,
SectionID::Greenill => 1,
SectionID::Skyly => 2,
SectionID::Bluefull => 3,
SectionID::Purplenum => 4,
SectionID::Pinkal => 5,
SectionID::Redria => 6,
SectionID::Oran => 7,
SectionID::Yellowboze => 8,
SectionID::Whitill => 9,
}
}
}
#[derive(PSOPacketData, Copy, Clone)]
@ -166,8 +80,8 @@ pub struct Character {
pub _unused: [u8; 11],
pub play_time: u32,
pub name_color_checksum: u32,
pub section_id: SectionID,
pub ch_class: CharacterClass,
pub section_id: u8,
pub ch_class: u8,
pub v2flags: u8,
pub version: u8,
pub v1flags: u32,
@ -235,8 +149,8 @@ pub struct SelectScreenCharacter {
pub model: u8,
pub _unused: [u8; 15],
pub name_color_checksum: u32,
pub section_id: SectionID,
pub ch_class: CharacterClass,
pub section_id: u8,
pub ch_class: u8,
pub v2flags: u8,
pub version: u8,
pub v1flags: u32,
@ -387,8 +301,8 @@ pub struct FullCharacter {
pub guildcard_desc: [u16; 88],
pub _reserved1: u8,
pub _reserved2: u8,
pub section_id: SectionID,
pub char_class: CharacterClass,
pub section_id: u8,
pub char_class: u8,
pub _unknown2: u32,
pub symbol_chats: [u8; 0x4E0],
pub shortcuts: [u8; 2624],

View File

@ -2,5 +2,3 @@
pub mod settings;
pub mod character;
pub mod guildcard;
pub use character::{SectionID, CharacterClass};

View File

@ -1,37 +1,25 @@
#![allow(dead_code)]
pub mod weapon;
//pub mod tool;
//pub mod armor;
//pub mod shield;
pub mod tool;
pub mod armor;
pub mod shield;
//use std::io::{Read, Seek};
//use crate::{PacketParseError};
use std::io::{Read, Seek};
use crate::{PacketParseError};
pub trait ItemBytes {
fn as_bytes(&self) -> [u8; 16] {
// this is one of those things that should be easier than it is
let mut result = [0; 16];
let (left, right) = result.split_at_mut(12);
left.copy_from_slice(&self.as_bytes_upper());
right.copy_from_slice(&self.as_bytes_lower());
result
}
fn as_bytes_upper(&self) -> [u8; 12];
fn as_bytes_lower(&self) -> [u8; 4];
}
#[derive(Debug, Copy, Clone)]
pub enum Item {
Weapon(weapon::Weapon),
//Armor(armor::Armor),
//Shield(shield::Shield),
Armor(armor::Armor),
Shield(shield::Shield),
//Unit(Unit),
//Mag(Mag),
//Tool(tool::Tool),
Tool(tool::Tool),
}
/*
impl Item {
fn from_bytes<R: Read + Seek>(_cursor: &mut R) -> Result<Self, PacketParseError> {
unimplemented!()
@ -39,9 +27,9 @@ impl Item {
pub fn as_bytes(&self) -> [u8; 16] {
match self {
Item::Weapon(wep) => wep.as_bytes(),
//Item::Armor(armor) => armor.as_bytes(),
//Item::Shield(shield) => shield.as_bytes(),
//Item::Tool(tool) => tool.as_bytes(),
Item::Armor(armor) => armor.as_bytes(),
Item::Shield(shield) => shield.as_bytes(),
Item::Tool(tool) => tool.as_bytes(),
}
}
@ -53,4 +41,3 @@ impl Item {
}
}
*/

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@ pub mod crypto;
pub mod packet;
pub mod character;
pub mod util;
pub mod item;
//pub mod item;
use std::io::{Read, Seek};
#[derive(Debug, PartialEq)]
@ -624,33 +624,4 @@ mod test {
d: vec![9,9,9,8],
});
}
#[test]
fn test_derive_pso_packet_data_on_simple_enum() {
#[repr(u8)]
#[derive(PSOPacketData, Eq, PartialEq)]
enum Q {
A,
B,
C,
}
let q = Q::A.as_bytes();
assert!(q == vec![0]);
let q = Q::B.as_bytes();
assert!(q == vec![1]);
let q = Q::C.as_bytes();
assert!(q == vec![2]);
let q = Q::from_bytes(&mut std::io::Cursor::new(vec![0])).unwrap();
assert!(q == Q::A);
let q = Q::from_bytes(&mut std::io::Cursor::new(vec![1])).unwrap();
assert!(q == Q::B);
let q = Q::from_bytes(&mut std::io::Cursor::new(vec![2])).unwrap();
assert!(q == Q::C);
}
}

View File

@ -489,7 +489,7 @@ impl ShipList {
pub fn new(ships: Vec<ShipListEntry>) -> ShipList {
ShipList {
baseship: ShipListEntry {
menu: ships.first().map(|s| s.menu).unwrap_or(0),
menu: ships.get(0).map(|s| s.menu).unwrap_or(0),
item: 0,
flags: 0,
name: utf8_to_utf16_array("Ship"),