Compare commits
9 Commits
master
...
cleanupper
Author | SHA1 | Date | |
---|---|---|---|
0e2cac0f1b | |||
552f7d5774 | |||
05d505836c | |||
240ddc7e84 | |||
c309e51f02 | |||
d975874a64 | |||
c7ea9c03e9 | |||
30739b5d87 | |||
908b58f1b9 |
@ -5,6 +5,8 @@ authors = ["Jake Probst <jake.probst@gmail.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
psopacket = { path = "psopacket" }
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
chrono = "*"
|
chrono = "*"
|
||||||
psopacket = { path = "psopacket" }
|
serde = { version = "1.0", features = ["derive"]}
|
||||||
|
strum = { version = "0.25.0", features = ["derive"] }
|
||||||
|
@ -8,6 +8,6 @@ edition = "2018"
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
syn = {version = "1.0", features=["full", "extra-traits", "parsing"]}
|
syn = {version = "2.0.39", features=["full", "extra-traits", "parsing"]}
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = "1.0"
|
||||||
|
@ -6,8 +6,10 @@
|
|||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use syn::{parse_macro_input, ItemStruct, NestedMeta, DeriveInput, Field};
|
use syn::{parse_macro_input, ItemStruct, DeriveInput, Field};
|
||||||
use syn::punctuated::Iter;
|
use syn::punctuated::Iter;
|
||||||
|
use syn::punctuated::Punctuated;
|
||||||
|
use syn::parse::Parse;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -308,7 +310,7 @@ fn get_struct_fields(fields: Iter<Field>) -> Result<Vec<AttrType>, TokenStream>
|
|||||||
}
|
}
|
||||||
let mut attr_meta = AttrMeta::None;
|
let mut attr_meta = AttrMeta::None;
|
||||||
for attr in &field.attrs {
|
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,
|
"utf8" => AttrMeta::Utf8,
|
||||||
"utf16" => AttrMeta::Utf16,
|
"utf16" => AttrMeta::Utf16,
|
||||||
"nodebug" => AttrMeta::NoDebug,
|
"nodebug" => AttrMeta::NoDebug,
|
||||||
@ -345,35 +347,52 @@ fn get_struct_fields(fields: Iter<Field>) -> Result<Vec<AttrType>, TokenStream>
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[derive(Debug)]
|
||||||
pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream {
|
struct PSOPacketAttrs {
|
||||||
let args = parse_macro_input!(attr as syn::AttributeArgs);
|
cmd: u16,
|
||||||
let mut cmd = 0;
|
flag: bool,
|
||||||
let mut flag = true;
|
manual_flag: bool,
|
||||||
let mut manual_flag = false;
|
}
|
||||||
for a in args {
|
|
||||||
match &a {
|
impl Parse for PSOPacketAttrs {
|
||||||
NestedMeta::Lit(lit) => {
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||||
if let syn::Lit::Int(litint) = lit {
|
let vars = Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated(input)?;
|
||||||
cmd = litint.base10_parse().unwrap();
|
|
||||||
}
|
let (cmd, flag, manual_flag) = vars
|
||||||
},
|
.into_iter()
|
||||||
NestedMeta::Meta(k) => {
|
.fold((None, true, false), |mut acc, attr| {
|
||||||
if let syn::Meta::Path(syn::Path {segments, ..}) = k {
|
match attr {
|
||||||
match segments[0].ident.to_string().as_str() {
|
syn::Expr::Lit(lit) => {
|
||||||
"no_flag" => flag = false,
|
if let syn::Lit::Int(int) = lit.lit {
|
||||||
"manual_flag" => {
|
acc.0 = int.base10_parse().ok();
|
||||||
flag = false;
|
}
|
||||||
manual_flag = true;
|
},
|
||||||
},
|
syn::Expr::Path(path) => {
|
||||||
_ => {
|
if path.path.is_ident("no_flag") {
|
||||||
return syn::Error::new(segments[0].ident.span(), "unknown macro param").to_compile_error().into();
|
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 pkt_struct = parse_macro_input!(item as ItemStruct);
|
let pkt_struct = parse_macro_input!(item as ItemStruct);
|
||||||
let attrs = match get_struct_fields(pkt_struct.fields.iter()) {
|
let attrs = match get_struct_fields(pkt_struct.fields.iter()) {
|
||||||
@ -381,7 +400,7 @@ pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
Err(err) => return err
|
Err(err) => return err
|
||||||
};
|
};
|
||||||
|
|
||||||
if manual_flag {
|
if args.manual_flag {
|
||||||
match &attrs[0] {
|
match &attrs[0] {
|
||||||
AttrType::Array(_, ident, _, _) => {
|
AttrType::Array(_, ident, _, _) => {
|
||||||
if ident.to_string() != "flag" {
|
if ident.to_string() != "flag" {
|
||||||
@ -397,7 +416,7 @@ pub fn pso_packet(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let struct_def = generate_struct_def(pkt_struct.ident.clone(), &attrs);
|
let struct_def = generate_struct_def(pkt_struct.ident.clone(), &attrs);
|
||||||
let psopacket_impl = generate_psopacket_impl(cmd, pkt_struct.ident.clone(), &attrs, flag);
|
let psopacket_impl = generate_psopacket_impl(args.cmd, pkt_struct.ident.clone(), &attrs, args.flag);
|
||||||
let debug_impl = generate_debug_impl(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 partialeq_impl = generate_partialeq_impl(pkt_struct.ident.clone(), &attrs);
|
||||||
|
|
||||||
@ -588,18 +607,10 @@ fn generate_psomessage_impl(msg_cmd: u8, name: syn::Ident, attrs: &Vec<AttrType>
|
|||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
let args = parse_macro_input!(attr as syn::AttributeArgs);
|
let cmd = parse_macro_input!(attr as syn::LitInt).base10_parse().unwrap();
|
||||||
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 pkt_struct = parse_macro_input!(item as ItemStruct);
|
||||||
let mut attrs = match get_struct_fields(pkt_struct.fields.iter()) {
|
|
||||||
|
let mut fields = match get_struct_fields(pkt_struct.fields.iter()) {
|
||||||
Ok(a) => a,
|
Ok(a) => a,
|
||||||
Err(err) => return err
|
Err(err) => return err
|
||||||
};
|
};
|
||||||
@ -617,13 +628,13 @@ pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
segments: punctuated
|
segments: punctuated
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
attrs.insert(0, AttrType::Value(u8tpath.clone(), syn::Ident::new("target", proc_macro2::Span::call_site()), AttrMeta::None));
|
fields.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));
|
fields.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 struct_def = generate_struct_def(pkt_struct.ident.clone(), &fields);
|
||||||
let psopacket_impl = generate_psomessage_impl(cmd, pkt_struct.ident.clone(), &attrs);
|
let psopacket_impl = generate_psomessage_impl(cmd, pkt_struct.ident.clone(), &fields);
|
||||||
let debug_impl = generate_debug_impl(pkt_struct.ident.clone(), &attrs);
|
let debug_impl = generate_debug_impl(pkt_struct.ident.clone(), &fields);
|
||||||
let partialeq_impl = generate_partialeq_impl(pkt_struct.ident.clone(), &attrs);
|
let partialeq_impl = generate_partialeq_impl(pkt_struct.ident.clone(), &fields);
|
||||||
|
|
||||||
let q = quote!{
|
let q = quote!{
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -636,19 +647,7 @@ pub fn pso_message(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
q.into()
|
q.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(PSOPacketData)]
|
fn pso_packet_data_struct(name: syn::Ident, fields: syn::Fields) -> TokenStream {
|
||||||
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()) {
|
let attrs = match get_struct_fields(fields.iter()) {
|
||||||
Ok(a) => a,
|
Ok(a) => a,
|
||||||
Err(err) => return err
|
Err(err) => return err
|
||||||
@ -684,3 +683,75 @@ pub fn pso_packet_data(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
q.into()
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
// TODO: ch_class to CharacterClass enum
|
|
||||||
// TODO: section_id to SectionId enum
|
|
||||||
// TODO: techniques to enum
|
// TODO: techniques to enum
|
||||||
use psopacket::PSOPacketData;
|
use psopacket::PSOPacketData;
|
||||||
use crate::{PSOPacketData, PacketParseError};
|
use crate::{PSOPacketData, PacketParseError};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
#[repr(u32)]
|
|
||||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
#[repr(u8)]
|
||||||
pub enum Class {
|
#[derive(PSOPacketData, Default, Debug, Copy, Clone, Hash, PartialEq, Eq, strum::Display, strum::EnumString, Serialize, Deserialize)]
|
||||||
|
pub enum CharacterClass {
|
||||||
|
#[default]
|
||||||
HUmar,
|
HUmar,
|
||||||
HUnewearl,
|
HUnewearl,
|
||||||
HUcast,
|
HUcast,
|
||||||
@ -21,29 +22,78 @@ pub enum Class {
|
|||||||
FOnewearl,
|
FOnewearl,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<u8> for Class {
|
// TODO: TryFrom
|
||||||
fn from(f: u8) -> Class {
|
impl std::convert::From<u8> for CharacterClass {
|
||||||
|
fn from(f: u8) -> CharacterClass {
|
||||||
match f {
|
match f {
|
||||||
0 => Class::HUmar,
|
0 => CharacterClass::HUmar,
|
||||||
1 => Class::HUnewearl,
|
1 => CharacterClass::HUnewearl,
|
||||||
2 => Class::HUcast,
|
2 => CharacterClass::HUcast,
|
||||||
3 => Class::RAmar,
|
3 => CharacterClass::RAmar,
|
||||||
4 => Class::RAcast,
|
4 => CharacterClass::RAcast,
|
||||||
5 => Class::RAcaseal,
|
5 => CharacterClass::RAcaseal,
|
||||||
6 => Class::FOmarl,
|
6 => CharacterClass::FOmarl,
|
||||||
7 => Class::FOnewm,
|
7 => CharacterClass::FOnewm,
|
||||||
8 => Class::FOnewearl,
|
8 => CharacterClass::FOnewearl,
|
||||||
9 => Class::HUcaseal,
|
9 => CharacterClass::HUcaseal,
|
||||||
10 => Class::RAmarl,
|
10 => CharacterClass::RAmarl,
|
||||||
11 => Class::FOmar,
|
11 => CharacterClass::FOmar,
|
||||||
_ => panic!("unknown class")
|
_ => 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 {
|
pub enum SectionID {
|
||||||
|
#[default]
|
||||||
Viridia,
|
Viridia,
|
||||||
Greenill,
|
Greenill,
|
||||||
Skyly,
|
Skyly,
|
||||||
@ -56,6 +106,42 @@ pub enum SectionID {
|
|||||||
Whitill,
|
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)]
|
#[derive(PSOPacketData, Copy, Clone)]
|
||||||
@ -80,8 +166,8 @@ pub struct Character {
|
|||||||
pub _unused: [u8; 11],
|
pub _unused: [u8; 11],
|
||||||
pub play_time: u32,
|
pub play_time: u32,
|
||||||
pub name_color_checksum: u32,
|
pub name_color_checksum: u32,
|
||||||
pub section_id: u8,
|
pub section_id: SectionID,
|
||||||
pub ch_class: u8,
|
pub ch_class: CharacterClass,
|
||||||
pub v2flags: u8,
|
pub v2flags: u8,
|
||||||
pub version: u8,
|
pub version: u8,
|
||||||
pub v1flags: u32,
|
pub v1flags: u32,
|
||||||
@ -149,8 +235,8 @@ pub struct SelectScreenCharacter {
|
|||||||
pub model: u8,
|
pub model: u8,
|
||||||
pub _unused: [u8; 15],
|
pub _unused: [u8; 15],
|
||||||
pub name_color_checksum: u32,
|
pub name_color_checksum: u32,
|
||||||
pub section_id: u8,
|
pub section_id: SectionID,
|
||||||
pub ch_class: u8,
|
pub ch_class: CharacterClass,
|
||||||
pub v2flags: u8,
|
pub v2flags: u8,
|
||||||
pub version: u8,
|
pub version: u8,
|
||||||
pub v1flags: u32,
|
pub v1flags: u32,
|
||||||
@ -301,8 +387,8 @@ pub struct FullCharacter {
|
|||||||
pub guildcard_desc: [u16; 88],
|
pub guildcard_desc: [u16; 88],
|
||||||
pub _reserved1: u8,
|
pub _reserved1: u8,
|
||||||
pub _reserved2: u8,
|
pub _reserved2: u8,
|
||||||
pub section_id: u8,
|
pub section_id: SectionID,
|
||||||
pub char_class: u8,
|
pub char_class: CharacterClass,
|
||||||
pub _unknown2: u32,
|
pub _unknown2: u32,
|
||||||
pub symbol_chats: [u8; 0x4E0],
|
pub symbol_chats: [u8; 0x4E0],
|
||||||
pub shortcuts: [u8; 2624],
|
pub shortcuts: [u8; 2624],
|
||||||
|
@ -2,3 +2,5 @@
|
|||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod character;
|
pub mod character;
|
||||||
pub mod guildcard;
|
pub mod guildcard;
|
||||||
|
|
||||||
|
pub use character::{SectionID, CharacterClass};
|
||||||
|
@ -1,25 +1,37 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
pub mod weapon;
|
pub mod weapon;
|
||||||
pub mod tool;
|
//pub mod tool;
|
||||||
pub mod armor;
|
//pub mod armor;
|
||||||
pub mod shield;
|
//pub mod shield;
|
||||||
|
|
||||||
use std::io::{Read, Seek};
|
//use std::io::{Read, Seek};
|
||||||
use crate::{PacketParseError};
|
//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)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum Item {
|
pub enum Item {
|
||||||
Weapon(weapon::Weapon),
|
Weapon(weapon::Weapon),
|
||||||
Armor(armor::Armor),
|
//Armor(armor::Armor),
|
||||||
Shield(shield::Shield),
|
//Shield(shield::Shield),
|
||||||
//Unit(Unit),
|
//Unit(Unit),
|
||||||
//Mag(Mag),
|
//Mag(Mag),
|
||||||
Tool(tool::Tool),
|
//Tool(tool::Tool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
impl Item {
|
impl Item {
|
||||||
fn from_bytes<R: Read + Seek>(_cursor: &mut R) -> Result<Self, PacketParseError> {
|
fn from_bytes<R: Read + Seek>(_cursor: &mut R) -> Result<Self, PacketParseError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
@ -27,9 +39,9 @@ impl Item {
|
|||||||
pub fn as_bytes(&self) -> [u8; 16] {
|
pub fn as_bytes(&self) -> [u8; 16] {
|
||||||
match self {
|
match self {
|
||||||
Item::Weapon(wep) => wep.as_bytes(),
|
Item::Weapon(wep) => wep.as_bytes(),
|
||||||
Item::Armor(armor) => armor.as_bytes(),
|
//Item::Armor(armor) => armor.as_bytes(),
|
||||||
Item::Shield(shield) => shield.as_bytes(),
|
//Item::Shield(shield) => shield.as_bytes(),
|
||||||
Item::Tool(tool) => tool.as_bytes(),
|
//Item::Tool(tool) => tool.as_bytes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,3 +53,4 @@ impl Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
1613
src/item/weapon.rs
1613
src/item/weapon.rs
File diff suppressed because it is too large
Load Diff
31
src/lib.rs
31
src/lib.rs
@ -4,7 +4,7 @@ pub mod crypto;
|
|||||||
pub mod packet;
|
pub mod packet;
|
||||||
pub mod character;
|
pub mod character;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
//pub mod item;
|
pub mod item;
|
||||||
|
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -624,4 +624,33 @@ mod test {
|
|||||||
d: vec![9,9,9,8],
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,7 +489,7 @@ impl ShipList {
|
|||||||
pub fn new(ships: Vec<ShipListEntry>) -> ShipList {
|
pub fn new(ships: Vec<ShipListEntry>) -> ShipList {
|
||||||
ShipList {
|
ShipList {
|
||||||
baseship: ShipListEntry {
|
baseship: ShipListEntry {
|
||||||
menu: ships.get(0).map(|s| s.menu).unwrap_or(0),
|
menu: ships.first().map(|s| s.menu).unwrap_or(0),
|
||||||
item: 0,
|
item: 0,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
name: utf8_to_utf16_array("Ship"),
|
name: utf8_to_utf16_array("Ship"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user