Compare commits

..

79 Commits

Author SHA1 Message Date
90246b6a80 Merge pull request 'new drone, convert some macros to functions' (#32) from somecleaning into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #32
2023-11-15 00:05:40 -05:00
edb6319189 how has libpso avoided the baleful eye of clippy
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-11-14 22:05:13 -07:00
9ff866c489 convert macros into functions
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-11-14 21:37:22 -07:00
22278e04e6 use latest drone config 2023-11-14 21:37:02 -07:00
ed278cb8f6 set some versions 2023-02-17 11:49:15 -07:00
e1a8ad7fc5 Merge pull request 'andy/floor-limit' (#29) from andy/floor-limit into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #29
2023-02-15 19:59:43 -05:00
433800da6b Merge pull request 'right-side screen text' (#31) from andy/right-text into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #31
Reviewed-by: jake <jake@sharnoth.com>
2023-02-15 19:20:09 -05:00
fe5919199e right-side screen text
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-16 00:04:17 +00:00
55f46d867c Merge pull request 'boss warp msg' (#30) from bosswarp into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #30
2023-02-14 01:52:16 -05:00
9b04da5ab3 boss warp msg
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-02-13 23:38:17 -07:00
2dd1161ae7 rename to match the rest of the code
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-08 23:36:00 +00:00
eff9fba20a very important packet data
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-08 01:50:09 +00:00
58b8fa132c floor limit packet 2023-02-08 01:49:49 +00:00
05222bbf9f Merge pull request 'large dialog' (#28) from large_dialog into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #28
2023-02-05 14:45:48 -05:00
59b564c44b large dialog
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-05 12:44:28 -07:00
16a37ec828 update tech menu
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-02 22:01:28 -07:00
e71b435ea3 Merge pull request 'update tech menu' (#27) from tech_menu_config into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #27
2023-02-03 00:01:27 -05:00
dcdaef82c5 Merge pull request 'more quiet' (#26) from quieter2 into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #26
2023-02-03 00:01:19 -05:00
0a9e10bee9 more quiet
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-01-31 10:15:15 -07:00
8c88303009 Merge pull request 'be quieter' (#25) from quiter into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #25
2023-01-29 19:39:30 -05:00
32203551c0 be quieter
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-01-29 17:33:33 -07:00
5051514fb1 Merge pull request 'lobby event packet' (#24) from lobby_event into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #24
2022-10-19 21:13:54 -04:00
321780088b lobby event packet
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-10-19 19:13:16 -06:00
7198aade75 Merge pull request 'use Formatter::debug_struct for packet debug impl' (#23) from improve_packet_debug into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #23
2022-08-03 00:23:45 -04:00
a1424332e7 why wasn't this derived originally
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-08-02 21:46:04 -06:00
2996b176a7 use Formatter::debug_struct for packet debug impl
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-08-02 21:31:29 -06:00
73fca2e983 Merge pull request 'veryimportantnull probably' (#22) from roominfo into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #22
2022-07-20 14:13:52 -04:00
530bb7875c veryimportantnull probably
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-07-06 22:39:06 +00:00
3cf9cf5392 Merge pull request 'exp steal packet' (#21) from expsteal into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #21
2022-05-17 17:32:39 -04:00
d1c5e30ce0 exp steal packet
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-05-15 17:49:11 +00:00
b3beb87874 Merge pull request 'change patch chunk size to 24kb for the client and remove duplicate' (#20) from unitxt into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #20
2022-05-12 19:54:59 -04:00
cf3a84c60d Merge branch 'master' into unitxt
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-05-12 18:56:28 -04:00
4fba0529ae Merge pull request 'sendgc' (#19) from sendgc into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #19
2022-05-01 13:14:39 -04:00
0b80a107bd GuildcardRecv struct
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-05-01 11:12:37 -06:00
c9aaa38465 0x for hexes 2022-05-01 11:11:54 -06:00
fcccba9554 guildcard structs and repr(c) cus the compiler hates me 2022-05-01 11:11:54 -06:00
35c6e068e1 Merge pull request 'movement config packets!' (#17) from keyboardconfig into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #17
2022-05-01 13:11:23 -04:00
0a6f8ac95e key_config -> keyboard_config
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-05-01 11:08:35 -06:00
8a9c4ceca4 controller -> gamepad for consistency with in-game 2022-05-01 11:08:35 -06:00
a417b08e4e joystick_config -> controller_config for consistency 2022-05-01 11:08:35 -06:00
f8f5e8bdb5 move defaults from character.rs to settings.rs. rename key_config -> keyboard_config. rename joystick_config -> controller_config. fix packet sizes 2022-05-01 11:08:35 -06:00
4ee5f38d7e add controller config blob 2022-05-01 11:08:35 -06:00
9d92d65046 keyboard config blob 2022-05-01 11:08:35 -06:00
1b4590c13b change patch chunk size to 24kb for the client and remove duplicate
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-15 02:12:08 +00:00
892d2ed220 Merge pull request 'add manual flag to RequestQuestList to know which quest npc we're talking to' (#18) from questlist into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #18
2022-02-11 19:02:22 -05:00
178354c24c add manual flag to RequestQuestList to know which quest npc we're talking to
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-07 03:05:01 +00:00
0bd4396bd1 Merge pull request 'trade request cancel' (#16) from trade_cancel into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #16
2021-12-27 02:45:24 -05:00
1713c30bc4 trade request cancel
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-12-27 00:46:15 -07:00
7276b875c4 Merge pull request 'don't feed bytes to the void' (#15) from mobattack_flag into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #15
2021-12-19 18:19:42 -05:00
bbd3c78329 don't feed bytes to the void
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-12-17 05:17:47 +00:00
fdd4aa916d Merge pull request 'remove unknown trade state' (#14) from trade_unknown into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #14
2021-12-09 02:43:28 -05:00
519344e9c4 remove unknown trade state
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-12-09 00:41:13 -07:00
564a1ce165 Merge pull request 'properly define TradeRequest' (#13) from traderequest into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #13
2021-12-02 03:42:54 -05:00
e8ebbb8a4e properly define TradeRequest
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-12-02 01:43:35 -07:00
315cfded37 Merge pull request 'fix tradesuccess flag thing' (#12) from tradesuccessful into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #12
2021-11-23 03:07:27 -05:00
2bf0ec5257 fix tradesuccess flag thing
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-11-23 01:08:26 -07:00
9d11968ce6 Merge pull request 'tradesuccessful' (#11) from tradesuccessful into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #11
2021-11-23 02:58:44 -05:00
32088d4762 tradesuccessful
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-11-23 00:58:39 -07:00
4da1e2f336 Merge pull request 'these features are stabilized now' (#10) from stabilized_features into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #10
2021-10-13 22:38:16 -04:00
3212017511 these features are stabilized now 2021-10-13 20:37:37 -06:00
8e87a8df3b Merge pull request 'append null to avoid message artifacts' (#9) from small_dialog into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #9
Reviewed-by: jake <jake@sharnoth.com>
2021-06-22 22:14:25 -04:00
faab6e8fd6 append null to avoid message artifacts
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-06-22 23:22:41 +00:00
90c990e632 Merge pull request 'Vec-ing is hard' (#6) from combo_targets into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #6
2021-06-21 18:36:07 -04:00
a2822b17ae Vec-ing is hard
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-06-20 21:04:07 +00:00
ad1dc584ab Merge pull request 'traps' (#5) from traps into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #5
Reviewed-by: jake <jake@sharnoth.com>
2021-06-20 11:35:16 -04:00
cd2af79091 why do i need to pull man
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-06-20 04:29:06 +00:00
43b37e985c rebase - trap trigger packet 2021-06-20 04:22:01 +00:00
69ddebdc45 Merge pull request 'pbs' (#2) from pbs into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #2
2021-06-20 00:16:24 -04:00
505ec2188d add to enum oops
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-06-20 04:12:34 +00:00
6e6c7c494f shop_sell (#4)
All checks were successful
continuous-integration/drone/push Build is passing
oops sold my 95h calibur

Reviewed-on: #4
Co-authored-by: andy <andynewjack@protonmail.com>
Co-committed-by: andy <andynewjack@protonmail.com>
2021-06-19 23:52:43 -04:00
3f0f4886cb shiny_mobs (#3)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #3
Co-authored-by: andy <andynewjack@protonmail.com>
Co-committed-by: andy <andynewjack@protonmail.com>
2021-06-19 23:51:54 -04:00
e2c54986f7 rebasing still difficult in 2021
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-06-20 02:24:01 +00:00
2debc015b7 rebased
Some checks failed
continuous-integration/drone/push Build is failing
2021-06-20 01:00:38 +00:00
e959fc3094 pb structs 2021-06-20 00:57:46 +00:00
e698ad993c Merge pull request 'techs' (#1) from techs into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #1
2021-06-19 00:25:04 -04:00
65532db884 sloppy spacing
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-06-17 21:07:49 +00:00
dbfb396643 trap trigger packet
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-30 05:41:53 +00:00
799a9e6880 pb structs
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-24 20:48:25 +00:00
a2ecb14d82 trade packets
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-12 19:55:53 -07:00
17 changed files with 838 additions and 462 deletions

View File

@ -3,8 +3,23 @@ kind: pipeline
type: docker type: docker
name: test libpso name: test libpso
concurrency:
limit: 1
environment:
CARGO_INCREMENTAL: false
steps: steps:
- name: cargo build - name: clean cache
image: rustlang/rust:nightly
volumes:
- name: cache
path: /usr/local/cargo
- name: target-cache
path: /drone/src/target
commands:
- cargo prune
- name: build
image: rustlang/rust:nightly image: rustlang/rust:nightly
volumes: volumes:
- name: cache - name: cache
@ -13,7 +28,7 @@ steps:
path: /drone/src/target path: /drone/src/target
commands: commands:
- cargo build - cargo build
- name: cargo test - name: clippy!
image: rustlang/rust:nightly image: rustlang/rust:nightly
volumes: volumes:
- name: cache - name: cache
@ -21,7 +36,16 @@ steps:
- name: target-cache - name: target-cache
path: /drone/src/target path: /drone/src/target
commands: commands:
- cargo test - cargo clippy -- --deny warnings
- name: test
image: rustlang/rust:nightly
volumes:
- name: cache
path: /usr/local/cargo
- name: target-cache
path: /drone/src/target
commands:
- cargo test --jobs 1
volumes: volumes:
- name: cache - name: cache
@ -30,4 +54,3 @@ volumes:
- name: target-cache - name: target-cache
host: host:
path: /home/drone/cargo-cache path: /home/drone/cargo-cache

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libpso" name = "libpso"
version = "0.1.0" version = "0.0.1"
authors = ["Jake Probst <jake.probst@gmail.com>"] authors = ["Jake Probst <jake.probst@gmail.com>"]
edition = "2018" edition = "2018"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "psopacket" name = "psopacket"
version = "1.0.0" version = "0.0.1"
authors = ["Jake Probst <jake.probst@gmail.com>"] authors = ["Jake Probst <jake.probst@gmail.com>"]
edition = "2018" edition = "2018"

View File

@ -149,14 +149,14 @@ fn generate_psopacket_impl(pkt_cmd: u16, name: syn::Ident, attrs: &Vec<AttrType>
fn from_bytes(data: &[u8]) -> Result<#name, PacketParseError> { fn from_bytes(data: &[u8]) -> Result<#name, PacketParseError> {
let mut cur = std::io::Cursor::new(data); let mut cur = std::io::Cursor::new(data);
let mut b: [u8; 2] = [0; 2]; let mut b: [u8; 2] = [0; 2];
cur.read(&mut b).unwrap(); cur.read_exact(&mut b).unwrap();
let len = u16::from_le_bytes(b); let len = u16::from_le_bytes(b);
cur.read(&mut b).unwrap(); cur.read_exact(&mut b).unwrap();
let cmd = u16::from_le_bytes(b); let cmd = u16::from_le_bytes(b);
let mut f: [u8; 4] = [0; 4]; let mut f: [u8; 4] = [0; 4];
let flag = if #include_flag { let flag = if #include_flag {
cur.read(&mut f).unwrap(); cur.read_exact(&mut f).unwrap();
u32::from_le_bytes(f) u32::from_le_bytes(f)
} }
else { 0 }; else { 0 };
@ -205,55 +205,59 @@ fn generate_psopacket_impl(pkt_cmd: u16, name: syn::Ident, attrs: &Vec<AttrType>
} }
fn generate_debug_impl(name: syn::Ident, attrs: &Vec<AttrType>) -> proc_macro2::TokenStream { fn generate_debug_impl(name: syn::Ident, attrs: &Vec<AttrType>) -> proc_macro2::TokenStream {
let mut dbg_write = Vec::new(); let dbg_write = attrs
for attr in attrs { .iter()
let element = match attr { .map(|attr| {
AttrType::Value(ty, name, meta) => { match attr {
let ident_str = name.to_string(); AttrType::Value(ty, name, meta) => {
let type_str = ty.path.segments[0].ident.to_string(); let ident_str = name.to_string();
match meta { let type_str = ty.path.segments[0].ident.to_string();
AttrMeta::NoDebug => quote! { match meta {
write!(f, " {} {}: [...]\n", #ident_str, #type_str)?; AttrMeta::NoDebug => quote! {
}, .field(&format!("{} [{}]", #ident_str, #type_str), &format_args!("[...]"))
_ => quote! { },
write!(f, " {} {}: {:?}\n", #ident_str, #type_str, self.#name)?; _ => quote! {
.field(&format!("{} [{}]", #ident_str, #type_str), &self.#name)
}
}
},
AttrType::Array(ty, name, len, meta) => {
let ident_str = name.to_string();
let type_str = ty.path.segments[0].ident.to_string();
match meta {
AttrMeta::Utf8 => quote! {
.field(&format!("{} [utf8; {}]", #ident_str, #len),
match std::str::from_utf8(&self.#name) {
Ok(ref s) => s,
Err(_) => &self.#name
})
},
AttrMeta::Utf16 => quote! {
.field(&format!("{} [utf16; {}]", #ident_str, #len),
match std::str::from_utf16(&self.#name) {
Ok(ref s) => s,
Err(_) => &self.#name
})
},
AttrMeta::NoDebug => quote! {
.field(&format!("{} [{}; {}]", #ident_str, #type_str, #len), &format_args!("[...]"))
},
_ => quote! {
.field(&format!("{} [{}; {}]", #ident_str, #type_str, #len), &format_args!("{:?}", &self.#name))
}
} }
} }
},
AttrType::Array(ty, name, len, meta) => {
let ident_str = name.to_string();
let type_str = ty.path.segments[0].ident.to_string();
match meta {
AttrMeta::Utf8 => quote! {
match std::str::from_utf8(&self.#name) {
Ok(v) => write!(f, " {} [utf8; {}]: {:?}\n", #ident_str, #len, v)?,
Err(_) => write!(f, " {} [{}; {}]: {:?}\n", #ident_str, #type_str, #len, self.#name.to_vec())?,
};
},
AttrMeta::Utf16 => quote! {
match String::from_utf16(&self.#name) {
Ok(v) => write!(f, " {} [utf16; {}]: {:?}\n", #ident_str, #len, v)?,
Err(_) => write!(f, " {} [{}; {}]: {:?}\n", #ident_str, #type_str, #len, self.#name.to_vec())?,
};
},
AttrMeta::NoDebug => quote! {
write!(f, " {} [{}; {}]: [...]\n", #ident_str, #type_str, #len)?;
},
_ => quote! {
write!(f, " {} [{}; {}]: {:?}\n", #ident_str, #type_str, #len, self.#name.to_vec())?;
},
}
} }
}; })
dbg_write.push(element); .collect::<Vec<_>>();
}
let name_str = name.to_string(); let name_str = name.to_string();
quote! { quote! {
impl std::fmt::Debug for #name { impl std::fmt::Debug for #name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{} {{\n", #name_str)?; f.debug_struct(#name_str)
#(#dbg_write)* #(#dbg_write)*
write!(f, "}}") .finish()
} }
} }
} }
@ -538,9 +542,9 @@ fn generate_psomessage_impl(msg_cmd: u8, name: syn::Ident, attrs: &Vec<AttrType>
const CMD: u8 = #msg_cmd; const CMD: u8 = #msg_cmd;
fn from_bytes<R: std::io::Read + std::io::Seek >(mut cur: &mut R) -> Result<#name, PacketParseError> { fn from_bytes<R: std::io::Read + std::io::Seek >(mut cur: &mut R) -> Result<#name, PacketParseError> {
let mut buf1 = [0u8; 1]; let mut buf1 = [0u8; 1];
cur.read(&mut buf1).unwrap(); cur.read_exact(&mut buf1).unwrap();
let cmd = buf1[0]; let cmd = buf1[0];
cur.read(&mut buf1).unwrap(); cur.read_exact(&mut buf1).unwrap();
let size = buf1[0]; let size = buf1[0];
let mut subbuf = vec![0u8; size as usize * 4 - 2]; let mut subbuf = vec![0u8; size as usize * 4 - 2];

View File

@ -3,91 +3,6 @@
// TODO: techniques to enum // TODO: techniques to enum
use psopacket::PSOPacketData; use psopacket::PSOPacketData;
use crate::{PSOPacketData, PacketParseError}; use crate::{PSOPacketData, PacketParseError};
//use crate::PSOPacketData;
pub const DEFAULT_PALETTE_CONFIG: [u8; 0xE8] = [
0, 0, 0, 0,
1, 0, 0, 0,
2, 0, 1, 0,
2, 1, 1, 0,
4, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
1, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
];
pub const DEFAULT_TECH_MENU: [u8; 40] = [
0x00, 0x00,
0x06, 0x00,
0x03, 0x00,
0x01, 0x00,
0x07, 0x00,
0x04, 0x00,
0x02, 0x00,
0x08, 0x00,
0x05, 0x00,
0x09, 0x00,
0x12, 0x00,
0x0f, 0x00,
0x10, 0x00,
0x11, 0x00,
0x0d, 0x00,
0x0a, 0x00,
0x0b, 0x00,
0x0c, 0x00,
0x0e, 0x00,
0x00, 0x00,
];
#[repr(u32)] #[repr(u32)]
#[derive(Copy, Clone, Hash, PartialEq, Eq)] #[derive(Copy, Clone, Hash, PartialEq, Eq)]
@ -223,7 +138,7 @@ impl std::default::Default for Character {
} }
} }
#[derive(Copy, Clone, Debug, PartialEq, Default)] #[derive(Copy, Clone, PSOPacketData, Default)]
#[repr(C)] #[repr(C)]
pub struct SelectScreenCharacter { pub struct SelectScreenCharacter {
pub exp: u32, pub exp: u32,
@ -254,20 +169,6 @@ pub struct SelectScreenCharacter {
} }
impl SelectScreenCharacter { impl SelectScreenCharacter {
pub const SIZE: usize = 0x7C;
pub fn from_le_bytes(bytes: [u8; 0x7C]) -> Result<SelectScreenCharacter, crate::PacketParseError> {
unsafe {
Ok(std::mem::transmute(bytes))
}
}
pub fn to_le_bytes(&self) -> [u8; 0x7C] {
unsafe {
std::mem::transmute(*self)
}
}
pub fn as_character(&self) -> Character { pub fn as_character(&self) -> Character {
Character { Character {
exp: self.exp, exp: self.exp,
@ -357,8 +258,8 @@ impl std::default::Default for Bank {
#[derive(PSOPacketData, Copy, Clone)] #[derive(PSOPacketData, Copy, Clone)]
pub struct KeyTeamConfig { pub struct KeyTeamConfig {
pub _unknown: [u8; 0x114], pub _unknown: [u8; 0x114],
pub key_config: [u8; 0x16C], pub keyboard_config: [u8; 0x16C],
pub joystick_config: [u8; 0x38], pub gamepad_config: [u8; 0x38],
pub guildcard: u32, pub guildcard: u32,
pub team_id: u32, pub team_id: u32,
pub team_info: [u32; 2], pub team_info: [u32; 2],
@ -438,8 +339,8 @@ pub struct DBChar {
#[derive(PSOPacketData, Copy, Clone)] #[derive(PSOPacketData, Copy, Clone)]
pub struct DBOpts { pub struct DBOpts {
pub blocked: [u32; 30], pub blocked: [u32; 30],
pub key_config: [u8; 0x16C], pub keyboard_config: [u8; 0x16C],
pub joystick_config: [u8; 0x38], pub gamepad_config: [u8; 0x38],
pub option_flags: u32, pub option_flags: u32,
pub shortcuts: [u8; 0xA40], pub shortcuts: [u8; 0xA40],
pub symbol_chats: [u8; 0x4E0], pub symbol_chats: [u8; 0x4E0],

View File

@ -1,53 +1,22 @@
use crate::packet::ship::{GuildcardAccept};
#[derive(Copy, Clone, Debug)]
/* #[repr(C)]
typedef struct bb_guildcard_data { pub struct BlockedGuildCard { // 264
uint8_t unk1[0x0114]; pub id: u32, // 4
struct { pub name: [u16; 0x18], // 48
uint32_t guildcard; pub team: [u16; 0x10], // 32
uint16_t name[0x18]; pub desc: [u16; 0x58], // 176
uint16_t team[0x10]; pub reserved1: u8, // 1
uint16_t desc[0x58]; pub language: u8, // 1
uint8_t reserved1; pub section_id: u8, // 1
uint8_t language; pub class: u8, // 1
uint8_t section;
uint8_t ch_class;
} blocked[29];
uint8_t unk2[0x78];
struct {
uint32_t guildcard;
uint16_t name[0x18];
uint16_t team[0x10];
uint16_t desc[0x58];
uint8_t reserved1;
uint8_t language;
uint8_t section;
uint8_t ch_class;
uint32_t padding;
uint16_t comment[0x58];
} entries[104];
uint8_t unk3[0x01BC];
} bb_gc_data_t;
*/
#[derive(Copy, Clone)]
pub struct BlockedGuildCard {
pub guildcard: u32,
pub name: [u16; 0x18],
pub team: [u16; 0x10],
pub desc: [u16; 0x58],
pub reserved1: u8,
pub language: u8,
pub section_id: u8,
pub class: u8,
} }
impl Default for BlockedGuildCard { impl Default for BlockedGuildCard {
fn default() -> BlockedGuildCard { fn default() -> BlockedGuildCard {
BlockedGuildCard { BlockedGuildCard {
guildcard: 0, id: 0,
name: [0; 0x18], name: [0; 0x18],
team: [0; 0x10], team: [0; 0x10],
desc: [0; 0x58], desc: [0; 0x58],
@ -59,25 +28,41 @@ impl Default for BlockedGuildCard {
} }
} }
#[derive(Copy, Clone)] impl From<GuildCard> for BlockedGuildCard {
pub struct GuildCard { fn from(g: GuildCard) -> BlockedGuildCard {
pub guildcard: u32, BlockedGuildCard {
pub name: [u16; 0x18], id: g.id,
pub team: [u16; 0x10], name: g.name,
pub desc: [u16; 0x58], team: g.team,
pub reserved1: u8, desc: g.desc,
pub language: u8, reserved1: g.reserved1,
pub section_id: u8, language: g.language,
pub class: u8, section_id: g.section_id,
pub padding: u32, class: g.class,
pub comment: [u16; 0x58], }
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct GuildCard { // 444
pub id: u32, // 4
pub name: [u16; 0x18], // 48
pub team: [u16; 0x10], // 32
pub desc: [u16; 0x58], // 176
pub reserved1: u8, // 1
pub language: u8, // 1
pub section_id: u8, // 1
pub class: u8, // 1
pub padding: u32, // 4
pub comment: [u16; 0x58], // 176
} }
impl Default for GuildCard { impl Default for GuildCard {
fn default() -> GuildCard { fn default() -> GuildCard {
GuildCard { GuildCard {
guildcard: 0, id: 0,
name: [0; 0x18], name: [0; 0x18],
team: [0; 0x10], team: [0; 0x10],
desc: [0; 0x58], desc: [0; 0x58],
@ -91,13 +76,30 @@ impl Default for GuildCard {
} }
} }
#[derive(Copy, Clone)] impl From<&GuildcardAccept> for GuildCard {
pub struct GuildCardData { fn from(g: &GuildcardAccept) -> GuildCard {
pub _unknown1: [u8; 0x114], GuildCard {
pub blocked: [BlockedGuildCard; 29], id: g.id,
pub _unknown2: [u8; 0x78], name: g.name,
pub friends: [GuildCard; 104], team: g.team,
pub _unknown3: [u8; 0x1BC], desc: g.desc,
reserved1: g.one,
language: g.language,
section_id: g.section_id,
class: g.class,
padding: 0,
comment: [0; 0x58],
}
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct GuildCardData { // 54672 0xd590
pub _unknown1: [u8; 0x114], // 276
pub blocked: [BlockedGuildCard; 29], // 264 * 29 = 7656
pub _unknown2: [u8; 0x78], // 120
pub friends: [GuildCard; 105], // 444 * 105 = 46620
} }
impl Default for GuildCardData { impl Default for GuildCardData {
@ -106,8 +108,7 @@ impl Default for GuildCardData {
_unknown1: [0; 0x114], _unknown1: [0; 0x114],
blocked: [BlockedGuildCard::default(); 29], blocked: [BlockedGuildCard::default(); 29],
_unknown2: [0; 0x78], _unknown2: [0; 0x78],
friends: [GuildCard::default(); 104], friends: [GuildCard::default(); 105],
_unknown3: [0; 0x1BC],
} }
} }
} }

View File

@ -1,3 +1,4 @@
#![allow(clippy::module_inception)]
pub mod settings; pub mod settings;
pub mod character; pub mod character;
pub mod guildcard; pub mod guildcard;

View File

@ -1,6 +1,6 @@
// TODO: deblobify all of this // TODO: deblobify all of this
const DEFAULT_KEY_CONFIG: [u8; 0x16C] = [ pub const DEFAULT_KEYBOARD_CONFIG1: [u8; 0x16C] = [
0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00,
@ -39,7 +39,128 @@ const DEFAULT_KEY_CONFIG: [u8; 0x16C] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00 0x01, 0x00, 0x00, 0x00
]; ];
const DEFAULT_JOYSTICK_CONFIG: [u8; 0x38] = [
pub const DEFAULT_KEYBOARD_CONFIG2: [u8; 364] = [
0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00
];
pub const DEFAULT_KEYBOARD_CONFIG3: [u8; 364] = [
0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00
];
pub const DEFAULT_KEYBOARD_CONFIG4: [u8; 364] = [
0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00
];
pub const DEFAULT_GAMEPAD_CONFIG: [u8; 0x38] = [
0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00,
@ -176,12 +297,96 @@ const DEFAULT_SYMBOLCHATS: [u8; 0x4E0] = [
0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00
]; ];
pub const DEFAULT_PALETTE_CONFIG: [u8; 0xE8] = [
0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x01, 0x00,
0x02, 0x01, 0x01, 0x00,
0x04, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00,
0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
];
pub const DEFAULT_TECH_MENU: [u8; 40] = [
0x00, 0x00,
0x06, 0x00,
0x03, 0x00,
0x01, 0x00,
0x07, 0x00,
0x04, 0x00,
0x02, 0x00,
0x08, 0x00,
0x05, 0x00,
0x09, 0x00,
0x12, 0x00,
0x0f, 0x00,
0x10, 0x00,
0x11, 0x00,
0x0d, 0x00,
0x0a, 0x00,
0x0b, 0x00,
0x0c, 0x00,
0x0e, 0x00,
0x00, 0x00,
];
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
#[repr(C)] #[repr(C)]
pub struct UserSettings { pub struct UserSettings {
pub blocked_users: [u32; 0x1E], pub blocked_users: [u32; 0x1E],
pub key_config: [u8; 0x16C], pub keyboard_config: [u8; 0x16C],
pub joystick_config: [u8; 0x38], pub gamepad_config: [u8; 0x38],
pub option_flags: u32, pub option_flags: u32,
pub shortcuts: [u8; 0xA40], pub shortcuts: [u8; 0xA40],
pub symbol_chats: [u8; 0x4E0], pub symbol_chats: [u8; 0x4E0],
@ -193,8 +398,8 @@ impl Default for UserSettings {
fn default() -> UserSettings { fn default() -> UserSettings {
UserSettings { UserSettings {
blocked_users: [0; 0x1E], blocked_users: [0; 0x1E],
key_config: DEFAULT_KEY_CONFIG, keyboard_config: DEFAULT_KEYBOARD_CONFIG1,
joystick_config: DEFAULT_JOYSTICK_CONFIG, gamepad_config: DEFAULT_GAMEPAD_CONFIG,
option_flags: 0, option_flags: 0,
shortcuts: [0; 0xA40], shortcuts: [0; 0xA40],
symbol_chats: DEFAULT_SYMBOLCHATS, symbol_chats: DEFAULT_SYMBOLCHATS,

View File

@ -48,7 +48,7 @@ impl PSOBBCipher {
for k in cipher.p_array.iter_mut() { for k in cipher.p_array.iter_mut() {
let mut pt = *k as u16; let mut pt = *k as u16;
pt = ((pt & 0x00FF) << 8) + ((pt & 0xFF00) >> 8); pt = ((pt & 0x00FF) << 8) + ((pt & 0xFF00) >> 8);
*k = ((((*k >> 16) ^ pt as u32) << 16)) + pt as u32; *k = (((*k >> 16) ^ pt as u32) << 16) + pt as u32;
} }
for i in 0..18 { for i in 0..18 {
@ -85,7 +85,7 @@ impl PSOBBCipher {
} }
impl PSOCipher for PSOBBCipher { impl PSOCipher for PSOBBCipher {
fn encrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { fn encrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> {
let mut real_data = data.chunks(4).map(|k| { let mut real_data = data.chunks(4).map(|k| {
u32::from_le_bytes([k[0], k[1], k[2], k[3]]) u32::from_le_bytes([k[0], k[1], k[2], k[3]])
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
@ -106,9 +106,7 @@ impl PSOCipher for PSOBBCipher {
l ^= self.p_array[4]; l ^= self.p_array[4];
r ^= self.p_array[5]; r ^= self.p_array[5];
let tmp = l; std::mem::swap(&mut l, &mut r);
l = r;
r = tmp;
result.extend_from_slice(&l.to_le_bytes()); result.extend_from_slice(&l.to_le_bytes());
result.extend_from_slice(&r.to_le_bytes()); result.extend_from_slice(&r.to_le_bytes());
@ -117,7 +115,7 @@ impl PSOCipher for PSOBBCipher {
Ok(result) Ok(result)
} }
fn decrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { fn decrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> {
if data.len() % 8 != 0 { if data.len() % 8 != 0 {
return Err(CipherError::InvalidSize); return Err(CipherError::InvalidSize);
} }
@ -139,9 +137,8 @@ impl PSOCipher for PSOBBCipher {
l ^= self.p_array[1]; l ^= self.p_array[1];
r ^= self.p_array[0]; r ^= self.p_array[0];
let tmp = l;
l = r; std::mem::swap(&mut l, &mut r);
r = tmp;
result.extend_from_slice(&l.to_le_bytes()); result.extend_from_slice(&l.to_le_bytes());
result.extend_from_slice(&r.to_le_bytes()); result.extend_from_slice(&r.to_le_bytes());

View File

@ -10,8 +10,8 @@ pub enum CipherError {
pub trait PSOCipher { pub trait PSOCipher {
fn encrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError>; fn encrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError>;
fn decrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError>; fn decrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError>;
fn header_size(&self) -> usize; fn header_size(&self) -> usize;
fn block_size(&self) -> usize { fn block_size(&self) -> usize {
self.header_size() self.header_size()
@ -24,12 +24,12 @@ pub struct NullCipher {
} }
impl PSOCipher for NullCipher { impl PSOCipher for NullCipher {
fn encrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { fn encrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> {
Ok(data.clone()) Ok(data.to_vec())
} }
fn decrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { fn decrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> {
Ok(data.clone()) Ok(data.to_vec())
} }
fn header_size(&self) -> usize { fn header_size(&self) -> usize {

View File

@ -31,15 +31,15 @@ impl PSOPCCipher {
eax = edi; eax = edi;
var1 = eax / W(55); var1 = eax / W(55);
edx = eax - (var1 * W(55)); edx = eax - (var1 * W(55));
ebx = ebx - esi; ebx -= esi;
edi = edi + W(0x15); edi += W(0x15);
stream[edx.0 as usize] = esi.0; stream[edx.0 as usize] = esi.0;
esi = ebx; esi = ebx;
ebx = W(stream[edx.0 as usize]); ebx = W(stream[edx.0 as usize]);
} }
let mut cipher = PSOPCCipher { let mut cipher = PSOPCCipher {
stream: stream, stream,
offset: 1, offset: 1,
}; };
@ -63,7 +63,7 @@ impl PSOPCCipher {
while edx > W(0) { while edx > W(0) {
esi = W(self.stream[eax.0 as usize + 0x1F]); esi = W(self.stream[eax.0 as usize + 0x1F]);
ebp = W(self.stream[eax.0 as usize]); ebp = W(self.stream[eax.0 as usize]);
ebp = ebp - esi; ebp -= esi;
self.stream[eax.0 as usize] = ebp.0; self.stream[eax.0 as usize] = ebp.0;
eax += W(1); eax += W(1);
edx -= W(1); edx -= W(1);
@ -74,7 +74,7 @@ impl PSOPCCipher {
while edx > W(0) { while edx > W(0) {
esi = W(self.stream[eax.0 as usize - 0x18]); esi = W(self.stream[eax.0 as usize - 0x18]);
ebp = W(self.stream[eax.0 as usize]); ebp = W(self.stream[eax.0 as usize]);
ebp = ebp - esi; ebp -= esi;
self.stream[eax.0 as usize] = ebp.0; self.stream[eax.0 as usize] = ebp.0;
eax += W(1); eax += W(1);
edx -= W(1); edx -= W(1);
@ -94,7 +94,7 @@ impl PSOPCCipher {
} }
impl PSOCipher for PSOPCCipher { impl PSOCipher for PSOPCCipher {
fn encrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { fn encrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> {
let mut result = Vec::new(); let mut result = Vec::new();
if data.len() % 4 != 0 { if data.len() % 4 != 0 {
return Err(CipherError::InvalidSize) return Err(CipherError::InvalidSize)
@ -108,7 +108,7 @@ impl PSOCipher for PSOPCCipher {
Ok(result) Ok(result)
} }
fn decrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { fn decrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> {
self.encrypt(data) self.encrypt(data)
} }

View File

@ -1,12 +1,10 @@
#![allow(incomplete_features)] #![allow(incomplete_features)]
#![feature(const_generics)]
#![feature(seek_convenience)]
pub mod crypto; 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)]
@ -111,7 +109,7 @@ impl PSOPacketData for String {
} }
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct ConsumingBlob { pub struct ConsumingBlob {
pub blob: Vec<u8>, pub blob: Vec<u8>,
} }
@ -121,7 +119,7 @@ impl PSOPacketData for ConsumingBlob {
let mut blob: Vec<u8> = Vec::new(); let mut blob: Vec<u8> = Vec::new();
cursor.read_to_end(&mut blob).map_err(|_| PacketParseError::ReadError)?; cursor.read_to_end(&mut blob).map_err(|_| PacketParseError::ReadError)?;
Ok(ConsumingBlob { Ok(ConsumingBlob {
blob: blob, blob,
}) })
} }
fn as_bytes(&self) -> Vec<u8> { fn as_bytes(&self) -> Vec<u8> {
@ -129,6 +127,14 @@ impl PSOPacketData for ConsumingBlob {
} }
} }
impl std::fmt::Debug for ConsumingBlob {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ConsumingBlob")
.field("blob", &"[...]")
.finish()
}
}
pub trait PSOPacket: std::fmt::Debug { pub trait PSOPacket: std::fmt::Debug {
// const CMD: u16; // const CMD: u16;
fn from_bytes(data: &[u8]) -> Result<Self, PacketParseError> where Self: Sized; fn from_bytes(data: &[u8]) -> Result<Self, PacketParseError> where Self: Sized;

View File

@ -1,13 +1,13 @@
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use psopacket::{pso_packet, PSOPacketData}; use psopacket::{pso_packet, PSOPacketData};
use crate::{PSOPacket, PacketParseError, PSOPacketData, utf8_to_utf16_array}; use crate::{PSOPacket, PacketParseError, PSOPacketData};
use crate::util::utf8_to_utf16_array;
use crate::character::character::SelectScreenCharacter; use crate::character::character::SelectScreenCharacter;
use std::io::Read; use std::io::Read;
pub const PATCH_FILE_CHUNK_SIZE: u16 = 0x8000; // 32kb
pub const GUILD_CARD_CHUNK_SIZE: usize = 0x6800; pub const GUILD_CARD_CHUNK_SIZE: usize = 0x6800;
pub const PARAM_DATA_CHUNK_SIZE: usize = 0x6800; pub const PARAM_DATA_CHUNK_SIZE: usize = 0x6800;
@ -24,9 +24,9 @@ impl LoginWelcome {
let mut copyright = [0u8; 0x60]; let mut copyright = [0u8; 0x60];
copyright[..0x4B].clone_from_slice(b"Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM."); copyright[..0x4B].clone_from_slice(b"Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM.");
LoginWelcome { LoginWelcome {
copyright: copyright, copyright,
server_key: server_key, server_key,
client_key: client_key, client_key,
} }
} }
} }
@ -76,8 +76,8 @@ pub struct Session {
pub character_slot: u8, // 1..=4 pub character_slot: u8, // 1..=4
} }
impl Session { impl Default for Session {
pub fn new() -> Session { fn default() -> Session {
Session { Session {
version: [0; 30], version: [0; 30],
session_id: 0, session_id: 0,
@ -180,12 +180,12 @@ pub struct LoginResponse {
impl LoginResponse { impl LoginResponse {
pub fn by_status(status: AccountStatus, session: Session) -> LoginResponse { pub fn by_status(status: AccountStatus, session: Session) -> LoginResponse {
LoginResponse { LoginResponse {
status: status, status,
tag: 0x00010000, tag: 0x00010000,
//tag: 0x00000100, //tag: 0x00000100,
guildcard: 0, guildcard: 0,
team_id: 0, team_id: 0,
session: session, session,
caps: 0x00000102, caps: 0x00000102,
} }
} }
@ -194,9 +194,9 @@ impl LoginResponse {
status: AccountStatus::Ok, status: AccountStatus::Ok,
tag: 0x00010000, tag: 0x00010000,
//tag: 0x00000100, //tag: 0x00000100,
guildcard: guildcard, guildcard,
team_id: team_id, team_id,
session: session, session,
caps: 0x00000102, caps: 0x00000102,
} }
} }
@ -210,8 +210,8 @@ pub struct RequestSettings {
#[pso_packet(0xE2)] #[pso_packet(0xE2)]
pub struct SendKeyAndTeamSettings { pub struct SendKeyAndTeamSettings {
unknown: [u8; 0x114], unknown: [u8; 0x114],
key_config: [u8; 0x16C], keyboard_config: [u8; 0x16C],
joystick_config: [u8; 0x38], gamepad_config: [u8; 0x38],
guildcard: u32, guildcard: u32,
team_id: u32, team_id: u32,
//team_info: [u32; 2], //team_info: [u32; 2],
@ -226,13 +226,13 @@ pub struct SendKeyAndTeamSettings {
} }
impl SendKeyAndTeamSettings { impl SendKeyAndTeamSettings {
pub fn new(key_config: [u8; 0x16C], joystick_config: [u8; 0x38], guildcard: u32, team_id: u32) -> SendKeyAndTeamSettings { pub fn new(keyboard_config: [u8; 0x16C], gamepad_config: [u8; 0x38], guildcard: u32, team_id: u32) -> SendKeyAndTeamSettings {
SendKeyAndTeamSettings { SendKeyAndTeamSettings {
unknown: [0; 0x114], unknown: [0; 0x114],
key_config: key_config, keyboard_config,
joystick_config: joystick_config, gamepad_config,
guildcard: guildcard, guildcard,
team_id: team_id, team_id,
//team_info: [0; 2], //team_info: [0; 2],
team_info: [0; 8], team_info: [0; 8],
team_priv: 0, team_priv: 0,
@ -255,8 +255,8 @@ pub struct RedirectClient {
impl RedirectClient { impl RedirectClient {
pub fn new(ip: u32, port: u16) -> RedirectClient { pub fn new(ip: u32, port: u16) -> RedirectClient {
RedirectClient { RedirectClient {
ip: ip, ip,
port: port, port,
padding: 0, padding: 0,
} }
} }
@ -276,7 +276,7 @@ pub struct ChecksumAck {
impl ChecksumAck { impl ChecksumAck {
pub fn new(ack: u32) -> ChecksumAck { pub fn new(ack: u32) -> ChecksumAck {
ChecksumAck { ChecksumAck {
ack: ack, ack,
} }
} }
} }
@ -293,18 +293,6 @@ pub struct CharAck {
pub code: u32, // TODO: enum? pub code: u32, // TODO: enum?
} }
impl PSOPacketData for SelectScreenCharacter {
fn from_bytes<R: Read>(cursor: &mut R) -> Result<Self, PacketParseError> {
let mut buf = [0u8; SelectScreenCharacter::SIZE];
cursor.read(&mut buf).map_err(|_| PacketParseError::ReadError)?;
SelectScreenCharacter::from_le_bytes(buf)
}
fn as_bytes(&self) -> Vec<u8> {
self.to_le_bytes().to_vec()
}
}
#[pso_packet(0xE5)] #[pso_packet(0xE5)]
pub struct CharacterPreview { pub struct CharacterPreview {
pub slot: u32, pub slot: u32,
@ -327,7 +315,7 @@ impl GuildcardDataHeader {
GuildcardDataHeader { GuildcardDataHeader {
one: 1, one: 1,
len: len as u32, len: len as u32,
checksum: checksum checksum,
} }
} }
} }
@ -343,7 +331,6 @@ pub struct GuildcardDataChunk {
_unknown: u32, _unknown: u32,
chunk: u32, chunk: u32,
pub buffer: [u8; GUILD_CARD_CHUNK_SIZE], pub buffer: [u8; GUILD_CARD_CHUNK_SIZE],
len: usize, len: usize,
} }
@ -351,9 +338,9 @@ impl GuildcardDataChunk {
pub fn new(chunk: u32, buffer: [u8; GUILD_CARD_CHUNK_SIZE], len: usize) -> GuildcardDataChunk { pub fn new(chunk: u32, buffer: [u8; GUILD_CARD_CHUNK_SIZE], len: usize) -> GuildcardDataChunk {
GuildcardDataChunk { GuildcardDataChunk {
_unknown: 0, _unknown: 0,
chunk: chunk as u32, chunk,
buffer: buffer, buffer,
len: len, len,
} }
} }
} }
@ -384,12 +371,12 @@ impl PSOPacket for GuildcardDataChunk {
impl std::fmt::Debug for GuildcardDataChunk { impl std::fmt::Debug for GuildcardDataChunk {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "packet GuildcardDataChunk {{\n").unwrap(); writeln!(f, "packet GuildcardDataChunk {{").unwrap();
write!(f, " flag: {:?}\n", 0).unwrap(); writeln!(f, " flag: {:?}", 0).unwrap();
write!(f, " _unknown: {:X?}\n", self._unknown).unwrap(); writeln!(f, " _unknown: {:#X?}", self._unknown).unwrap();
write!(f, " chunk: {:X?}\n", self.chunk).unwrap(); writeln!(f, " chunk: {:#X?}", self.chunk).unwrap();
write!(f, " buffer: [0..{:X}]\n", self.len).unwrap(); writeln!(f, " buffer: [0..{:#X}]", self.len).unwrap();
write!(f, "}}") writeln!(f, "}}")
} }
} }
@ -441,9 +428,9 @@ impl PSOPacket for ParamDataHeader {
impl std::fmt::Debug for ParamDataHeader { impl std::fmt::Debug for ParamDataHeader {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "packet ParamDataHeader{{\n").unwrap(); writeln!(f, "packet ParamDataHeader{{").unwrap();
write!(f, " files: [..]\n").unwrap(); writeln!(f, " files: [..]").unwrap();
write!(f, "}}") writeln!(f, "}}")
} }
} }
@ -505,9 +492,9 @@ impl ShipList {
menu: ships.get(0).map(|s| s.menu).unwrap_or(0), menu: ships.get(0).map(|s| s.menu).unwrap_or(0),
item: 0, item: 0,
flags: 0, flags: 0,
name: utf8_to_utf16_array!("Ship", 0x11), name: utf8_to_utf16_array("Ship"),
}, },
ships: ships, ships,
} }
} }
} }
@ -530,7 +517,7 @@ mod tests {
tag: 0, tag: 0,
guildcard: 0, guildcard: 0,
team_id: 0, team_id: 0,
session: Session::new(), session: Session::default(),
caps: 0, caps: 0,
}; };
@ -550,17 +537,17 @@ mod tests {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let mut key_config = [0u8; 0x16C]; let mut keyboard_config = [0u8; 0x16C];
let mut joystick_config = [0u8; 0x38]; let mut gamepad_config = [0u8; 0x38];
rng.fill(&mut key_config[..]); rng.fill(&mut keyboard_config[..]);
rng.fill(&mut joystick_config[..]); rng.fill(&mut gamepad_config[..]);
let pkt = super::SendKeyAndTeamSettings::new(key_config, joystick_config, 123, 456); let pkt = super::SendKeyAndTeamSettings::new(keyboard_config, gamepad_config, 123, 456);
let bytes = pkt.as_bytes(); let bytes = pkt.as_bytes();
assert!(bytes[2] == 0xe2); assert!(bytes[2] == 0xe2);
assert!(bytes[8 + 0x114] == key_config[0]); assert!(bytes[8 + 0x114] == keyboard_config[0]);
assert!(bytes[8 + 0x114 + 0x16C] == joystick_config[0]); assert!(bytes[8 + 0x114 + 0x16C] == gamepad_config[0]);
} }
#[test] #[test]
@ -573,7 +560,7 @@ mod tests {
#[test] #[test]
fn test_session_size() { fn test_session_size() {
use super::PSOPacketData; use super::PSOPacketData;
let session = super::Session::new(); let session = super::Session::default();
assert!(session.as_bytes().len() == 40); assert!(session.as_bytes().len() == 40);
} }
} }

View File

@ -1,5 +1,6 @@
#![allow(unused_must_use)] #![allow(unused_must_use)]
use std::io::{SeekFrom}; use std::io::{SeekFrom};
use std::convert::TryInto;
use psopacket::{pso_message, PSOPacketData}; use psopacket::{pso_message, PSOPacketData};
use crate::{PSOPacketData, PacketParseError}; use crate::{PSOPacketData, PacketParseError};
@ -43,7 +44,7 @@ pub struct SymbolChat {
pub struct MobAttack { pub struct MobAttack {
enemy_id: u16, enemy_id: u16,
damage: u16, damage: u16,
flags: u16, flags: [u8; 4],
} }
#[pso_message(0x0B)] #[pso_message(0x0B)]
@ -256,15 +257,19 @@ pub struct PlayerUsedMoonAtomizer {
} }
#[pso_message(0x36)] #[pso_message(0x37)]
pub struct PlayerPBDonation { pub struct PlayerPBUsed {
energy: u32,
} }
#[pso_message(0x37)] #[pso_message(0x38)]
pub struct PlayerInitiatedPB { pub struct PlayerDonatedPB {
pb_amount: u8, recipient: u32,
unknown1: [u8; 4], }
#[pso_message(0x39)]
pub struct PlayerPBReady {
player: u16,
} }
#[pso_message(0x3A)] #[pso_message(0x3A)]
@ -322,7 +327,6 @@ pub struct ComboStep1 {
pub struct ComboStep2 { pub struct ComboStep2 {
rotation: u16, rotation: u16,
attack: u16, attack: u16,
} }
#[pso_message(0x45)] #[pso_message(0x45)]
@ -333,10 +337,10 @@ pub struct ComboStep3 {
#[pso_message(0x46)] #[pso_message(0x46)]
pub struct TargetsHit { pub struct TargetsHit {
num_of_targets: [u8; 4], // thats a lot of targets? #[length_of(targets)]
client2: u8, // TODO: what even is this? num_of_targets: u32, // thats a lot of targets?
target2: u8, // TODO: what even is this? #[length_is(num_of_targets)]
unknown2: [u8; 2], targets: Vec<u32>,
} }
#[pso_message(0x47)] #[pso_message(0x47)]
@ -359,11 +363,9 @@ pub struct PlayerTechDone { // this packet gets sent once the tech is actually c
} }
#[pso_message(0x49)] #[pso_message(0x49)]
pub struct PlayerPBUsed { pub struct PlayerInitiatedPB {
pb: u8, pb: u32,
unknown1: u32, energy: u32,
amount: u8,
unknown2: u32,
} }
#[pso_message(0x4A)] #[pso_message(0x4A)]
@ -499,12 +501,11 @@ pub struct MagAnimation {
unknown1: u16, unknown1: u16,
} }
//#[pso_message(0x63)] #[pso_message(0x63)]
//pub struct FloorItemLimitItemDeletion { pub struct FloorItemLimitItemDeletion {
// client_id: u16, item_id: u32,
// item_id: u8, map_area: u16,
// amount: u8, }
//}
#[pso_message(0x66)] #[pso_message(0x66)]
pub struct PlayerUsedStarAtomizer { pub struct PlayerUsedStarAtomizer {
@ -534,6 +535,12 @@ pub struct NpcSpawn {
data: [u8; 8], data: [u8; 8],
} }
#[pso_message(0x6A)]
pub struct ActivateBossWarp {
unknown: u32,
}
#[pso_message(0x6F)] #[pso_message(0x6F)]
pub struct PlayerJoiningGame { pub struct PlayerJoiningGame {
data: [u32; 0x81], data: [u32; 0x81],
@ -583,10 +590,10 @@ pub struct KillMonster {
//} //}
//#[pso_message(0x80)] #[pso_message(0x80)]
//pub struct PlayerTrapActivate { pub struct PlayerTrapActivate {
data: [u8; 4],
//} }
#[pso_message(0x83)] #[pso_message(0x83)]
pub struct PlayerTrapSet { pub struct PlayerTrapSet {
@ -683,10 +690,123 @@ pub struct BoxDropRequest {
//} //}
//#[pso_message(0xA6)]
//pub struct TradeRequest {
//} #[derive(Clone, Debug, PartialEq)]
pub enum TradeRequestInitializeCommand {
Initialize,
Respond,
}
#[derive(Clone, Debug, PartialEq)]
pub enum TradeRequestCommand {
Initialize(TradeRequestInitializeCommand, u32),
AddItem(u32, u32),
RemoveItem(u32, u32),
Confirm,
FinalConfirm,
Cancel,
}
impl PSOPacketData for TradeRequestCommand {
fn from_bytes<R: std::io::Read + std::io::Seek>(cursor: &mut R) -> Result<Self, PacketParseError> {
let mut bytes = [0u8; 12];
let len = cursor.read(&mut bytes).map_err(|_| PacketParseError::ReadError)?;
if len != 12 {
return Err(PacketParseError::NotEnoughBytes);
}
match bytes[0] {
0 => {
let meseta = u32::from_le_bytes(bytes[8..12].try_into().map_err(|_| PacketParseError::InvalidValue)?);
match bytes[1] {
0 => Ok(TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Initialize, meseta)),
2 => Ok(TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Respond, meseta)),
_ => Err(PacketParseError::InvalidValue)
}
},
1 => {
Ok(TradeRequestCommand::AddItem(
u32::from_le_bytes(bytes[4..8].try_into().map_err(|_| PacketParseError::InvalidValue)?),
u32::from_le_bytes(bytes[8..12].try_into().map_err(|_| PacketParseError::InvalidValue)?),
))
},
2 => {
Ok(TradeRequestCommand::RemoveItem(
u32::from_le_bytes(bytes[4..8].try_into().map_err(|_| PacketParseError::InvalidValue)?),
u32::from_le_bytes(bytes[8..12].try_into().map_err(|_| PacketParseError::InvalidValue)?),
))
},
3 => {
Ok(TradeRequestCommand::Confirm)
},
4 => {
Ok(TradeRequestCommand::FinalConfirm)
},
5 => {
Ok(TradeRequestCommand::Cancel)
},
_ => {
Err(PacketParseError::InvalidValue)
},
}
}
fn as_bytes(&self) -> Vec<u8> {
match self {
TradeRequestCommand::Initialize(cmd, meseta) => {
vec![0u8,
match cmd {
TradeRequestInitializeCommand::Initialize => 0,
TradeRequestInitializeCommand::Respond => 2,
},
0, 0,
0, 0, 0, 0]
.into_iter()
.chain(meseta.to_le_bytes().iter().copied())
.collect()
},
TradeRequestCommand::AddItem(item_id, amount) => {
vec![1u8, 0, 0, 0]
.into_iter()
.chain(item_id.to_le_bytes().iter().copied())
.chain(amount.to_le_bytes().iter().copied())
.collect()
},
TradeRequestCommand::RemoveItem(item_id, amount) => {
vec![2u8, 0, 0, 0]
.into_iter()
.chain(item_id.to_le_bytes().iter().copied())
.chain(amount.to_le_bytes().iter().copied())
.collect()
},
TradeRequestCommand::Confirm => {
vec![3u8]
.into_iter()
.chain(std::iter::repeat(0).take(11))
.collect()
},
TradeRequestCommand::FinalConfirm => {
vec![4u8]
.into_iter()
.chain(std::iter::repeat(0).take(11))
.collect()
},
TradeRequestCommand::Cancel=> {
vec![5u8]
.into_iter()
.chain(std::iter::repeat(0).take(11))
.collect()
},
}
}
}
#[pso_message(0xA6)]
pub struct TradeRequest {
pub trade: TradeRequestCommand,
}
//#[pso_message(0xA8)] //#[pso_message(0xA8)]
//pub struct BossInteractionGolDragon { //pub struct BossInteractionGolDragon {
@ -809,12 +929,12 @@ pub struct GiveCharacterExp {
exp: u32, exp: u32,
} }
//#[pso_message(0xC0)] #[pso_message(0xC0)]
//pub struct PlayerSoldItem { pub struct PlayerSoldItem {
// client_id: u16, item_id: u32,
// item_id: u8, amount: u8,
// amount: u8, // TODO: other data?
//} }
//#[pso_message(0xC1)] //#[pso_message(0xC1)]
//pub struct TeamInvite { //pub struct TeamInvite {
@ -833,6 +953,7 @@ pub struct DropCoordinates {
x: f32, x: f32,
z: f32, z: f32,
item_id: u32, item_id: u32,
amount: u32,
} }
#[pso_message(0xC4)] #[pso_message(0xC4)]
@ -845,10 +966,12 @@ pub struct PlayerUsedMedicalCenter {
} }
//#[pso_message(0xC6)] #[pso_message(0xC6)]
//pub struct ExperienceSteal { pub struct ExperienceSteal {
client2: u8,
//} target2: u8,
enemy_id: u16,
}
#[pso_message(0xC7)] #[pso_message(0xC7)]
pub struct ChargeAttack { pub struct ChargeAttack {
@ -1014,7 +1137,7 @@ pub enum GameMessage {
PlayerResurrected(PlayerResurrected), PlayerResurrected(PlayerResurrected),
PlayerResurrectedMedicalCenter(PlayerResurrectedMedicalCenter), PlayerResurrectedMedicalCenter(PlayerResurrectedMedicalCenter),
PlayerUsedMoonAtomizer(PlayerUsedMoonAtomizer), PlayerUsedMoonAtomizer(PlayerUsedMoonAtomizer),
PlayerPBDonation(PlayerPBDonation), // PlayerPBDonation(PlayerPBDonation),
PlayerInitiatedPB(PlayerInitiatedPB), PlayerInitiatedPB(PlayerInitiatedPB),
PlayerLeftArea(PlayerLeftArea), PlayerLeftArea(PlayerLeftArea),
PlayerSpawnedIntoArea(PlayerSpawnedIntoArea), PlayerSpawnedIntoArea(PlayerSpawnedIntoArea),
@ -1029,6 +1152,8 @@ pub enum GameMessage {
PlayerTechCast(PlayerTechCast), PlayerTechCast(PlayerTechCast),
PlayerTechDone(PlayerTechDone), PlayerTechDone(PlayerTechDone),
PlayerPBUsed(PlayerPBUsed), PlayerPBUsed(PlayerPBUsed),
PlayerDonatedPB(PlayerDonatedPB),
PlayerPBReady(PlayerPBReady),
PlayerBlockedDamage(PlayerBlockedDamage), PlayerBlockedDamage(PlayerBlockedDamage),
PlayerReceivedDamage(PlayerReceivedDamage), PlayerReceivedDamage(PlayerReceivedDamage),
PlayerReceivedDamage2(PlayerReceivedDamage2), PlayerReceivedDamage2(PlayerReceivedDamage2),
@ -1047,12 +1172,13 @@ pub enum GameMessage {
ItemDrop(ItemDrop), ItemDrop(ItemDrop),
RequestItem(RequestItem), RequestItem(RequestItem),
MagAnimation(MagAnimation), MagAnimation(MagAnimation),
//FloorItemLimitItemDeletion(FloorItemLimitItemDeletion), FloorItemLimitItemDeletion(FloorItemLimitItemDeletion),
PlayerUsedStarAtomizer(PlayerUsedStarAtomizer), PlayerUsedStarAtomizer(PlayerUsedStarAtomizer),
SpawningMonsters(SpawningMonsters), SpawningMonsters(SpawningMonsters),
PlayerTelepipe(PlayerTelepipe), PlayerTelepipe(PlayerTelepipe),
NpcSpawn(NpcSpawn), NpcSpawn(NpcSpawn),
PlayerJoiningGame(PlayerJoiningGame), ActivateBossWarp(ActivateBossWarp),
PlayerJoiningGame(Box<PlayerJoiningGame>),
PlayerJoiningGame2(PlayerJoiningGame2), PlayerJoiningGame2(PlayerJoiningGame2),
BurstDone(BurstDone), BurstDone(BurstDone),
WordSelect(WordSelect), WordSelect(WordSelect),
@ -1064,7 +1190,7 @@ pub enum GameMessage {
//BmodeData(BmodeData), //BmodeData(BmodeData),
PlayerTrapSet(PlayerTrapSet), PlayerTrapSet(PlayerTrapSet),
//Unknown84(Unknown84), //Unknown84(Unknown84),
//PlayerTrapActivate(PlayerTrapActivate), PlayerTrapActivate(PlayerTrapActivate),
//PlayerShrink(PlayerShrink), //PlayerShrink(PlayerShrink),
//PlayerUnshrink(PlayerUnshrink), //PlayerUnshrink(PlayerUnshrink),
PlayerKilledByMonster(PlayerKilledByMonster), PlayerKilledByMonster(PlayerKilledByMonster),
@ -1080,7 +1206,7 @@ pub enum GameMessage {
//BossInteractionOlgaFlow(BossInteractionOlgaFlow), //BossInteractionOlgaFlow(BossInteractionOlgaFlow),
//BossInteractionOlgaFlow2(BossInteractionOlgaFlow2), //BossInteractionOlgaFlow2(BossInteractionOlgaFlow2),
//BossInteractionOlgaFlow3(BossInteractionOlgaFlow3), //BossInteractionOlgaFlow3(BossInteractionOlgaFlow3),
//TradeRequest(TradeRequest), TradeRequest(TradeRequest),
//BossInteractionGolDragon(BossInteractionGolDragon), //BossInteractionGolDragon(BossInteractionGolDragon),
//BossInteractionBarbaRay(BossInteractionBarbaRay), //BossInteractionBarbaRay(BossInteractionBarbaRay),
//BossInteractionBarbaRay2(BossInteractionBarbaRay2), //BossInteractionBarbaRay2(BossInteractionBarbaRay2),
@ -1097,7 +1223,7 @@ pub enum GameMessage {
TekAccept(TekAccept), TekAccept(TekAccept),
BankRequest(BankRequest), BankRequest(BankRequest),
BankInteraction(BankInteraction), BankInteraction(BankInteraction),
//PlayerSoldItem(PlayerSoldItem), PlayerSoldItem(PlayerSoldItem),
//TeamInvite(TeamInvite), //TeamInvite(TeamInvite),
//AcceptTeamInvite(AcceptTeamInvite), //AcceptTeamInvite(AcceptTeamInvite),
CreateItem(CreateItem), CreateItem(CreateItem),
@ -1105,7 +1231,7 @@ pub enum GameMessage {
DropCoordinates(DropCoordinates), DropCoordinates(DropCoordinates),
SortItems(SortItems), SortItems(SortItems),
PlayerUsedMedicalCenter(PlayerUsedMedicalCenter), PlayerUsedMedicalCenter(PlayerUsedMedicalCenter),
//ExperienceSteal(ExperienceSteal), ExperienceSteal(ExperienceSteal),
ChargeAttack(ChargeAttack), ChargeAttack(ChargeAttack),
RequestExp(RequestExp), RequestExp(RequestExp),
//QuestRewardMeseta(QuestRewardMeseta), //QuestRewardMeseta(QuestRewardMeseta),
@ -1179,7 +1305,7 @@ impl PSOPacketData for GameMessage {
PlayerResurrected::CMD => Ok(GameMessage::PlayerResurrected(PlayerResurrected::from_bytes(&mut cur)?)), PlayerResurrected::CMD => Ok(GameMessage::PlayerResurrected(PlayerResurrected::from_bytes(&mut cur)?)),
PlayerResurrectedMedicalCenter::CMD => Ok(GameMessage::PlayerResurrectedMedicalCenter(PlayerResurrectedMedicalCenter::from_bytes(&mut cur)?)), PlayerResurrectedMedicalCenter::CMD => Ok(GameMessage::PlayerResurrectedMedicalCenter(PlayerResurrectedMedicalCenter::from_bytes(&mut cur)?)),
PlayerUsedMoonAtomizer::CMD => Ok(GameMessage::PlayerUsedMoonAtomizer(PlayerUsedMoonAtomizer::from_bytes(&mut cur)?)), PlayerUsedMoonAtomizer::CMD => Ok(GameMessage::PlayerUsedMoonAtomizer(PlayerUsedMoonAtomizer::from_bytes(&mut cur)?)),
PlayerPBDonation::CMD => Ok(GameMessage::PlayerPBDonation(PlayerPBDonation::from_bytes(&mut cur)?)), // PlayerPBDonation::CMD => Ok(GameMessage::PlayerPBDonation(PlayerPBDonation::from_bytes(&mut cur)?)),
PlayerInitiatedPB::CMD => Ok(GameMessage::PlayerInitiatedPB(PlayerInitiatedPB::from_bytes(&mut cur)?)), PlayerInitiatedPB::CMD => Ok(GameMessage::PlayerInitiatedPB(PlayerInitiatedPB::from_bytes(&mut cur)?)),
PlayerLeftArea::CMD => Ok(GameMessage::PlayerLeftArea(PlayerLeftArea::from_bytes(&mut cur)?)), PlayerLeftArea::CMD => Ok(GameMessage::PlayerLeftArea(PlayerLeftArea::from_bytes(&mut cur)?)),
PlayerSpawnedIntoArea::CMD => Ok(GameMessage::PlayerSpawnedIntoArea(PlayerSpawnedIntoArea::from_bytes(&mut cur)?)), PlayerSpawnedIntoArea::CMD => Ok(GameMessage::PlayerSpawnedIntoArea(PlayerSpawnedIntoArea::from_bytes(&mut cur)?)),
@ -1194,6 +1320,8 @@ impl PSOPacketData for GameMessage {
PlayerTechCast::CMD => Ok(GameMessage::PlayerTechCast(PlayerTechCast::from_bytes(&mut cur)?)), PlayerTechCast::CMD => Ok(GameMessage::PlayerTechCast(PlayerTechCast::from_bytes(&mut cur)?)),
PlayerTechDone::CMD => Ok(GameMessage::PlayerTechDone(PlayerTechDone::from_bytes(&mut cur)?)), PlayerTechDone::CMD => Ok(GameMessage::PlayerTechDone(PlayerTechDone::from_bytes(&mut cur)?)),
PlayerPBUsed::CMD => Ok(GameMessage::PlayerPBUsed(PlayerPBUsed::from_bytes(&mut cur)?)), PlayerPBUsed::CMD => Ok(GameMessage::PlayerPBUsed(PlayerPBUsed::from_bytes(&mut cur)?)),
PlayerDonatedPB::CMD => Ok(GameMessage::PlayerDonatedPB(PlayerDonatedPB::from_bytes(&mut cur)?)),
PlayerPBReady::CMD => Ok(GameMessage::PlayerPBReady(PlayerPBReady::from_bytes(&mut cur)?)),
PlayerBlockedDamage::CMD => Ok(GameMessage::PlayerBlockedDamage(PlayerBlockedDamage::from_bytes(&mut cur)?)), PlayerBlockedDamage::CMD => Ok(GameMessage::PlayerBlockedDamage(PlayerBlockedDamage::from_bytes(&mut cur)?)),
PlayerReceivedDamage::CMD => Ok(GameMessage::PlayerReceivedDamage(PlayerReceivedDamage::from_bytes(&mut cur)?)), PlayerReceivedDamage::CMD => Ok(GameMessage::PlayerReceivedDamage(PlayerReceivedDamage::from_bytes(&mut cur)?)),
PlayerReceivedDamage2::CMD => Ok(GameMessage::PlayerReceivedDamage2(PlayerReceivedDamage2::from_bytes(&mut cur)?)), PlayerReceivedDamage2::CMD => Ok(GameMessage::PlayerReceivedDamage2(PlayerReceivedDamage2::from_bytes(&mut cur)?)),
@ -1212,12 +1340,13 @@ impl PSOPacketData for GameMessage {
ItemDrop::CMD => Ok(GameMessage::ItemDrop(ItemDrop::from_bytes(&mut cur)?)), ItemDrop::CMD => Ok(GameMessage::ItemDrop(ItemDrop::from_bytes(&mut cur)?)),
RequestItem::CMD => Ok(GameMessage::RequestItem(RequestItem::from_bytes(&mut cur)?)), RequestItem::CMD => Ok(GameMessage::RequestItem(RequestItem::from_bytes(&mut cur)?)),
MagAnimation::CMD => Ok(GameMessage::MagAnimation(MagAnimation::from_bytes(&mut cur)?)), MagAnimation::CMD => Ok(GameMessage::MagAnimation(MagAnimation::from_bytes(&mut cur)?)),
//FloorItemLimitItemDeletion::CMD => Ok(GameMessage::FloorItemLimitItemDeletion(FloorItemLimitItemDeletion::from_bytes(&mut cur)?)), FloorItemLimitItemDeletion::CMD => Ok(GameMessage::FloorItemLimitItemDeletion(FloorItemLimitItemDeletion::from_bytes(&mut cur)?)),
PlayerUsedStarAtomizer::CMD => Ok(GameMessage::PlayerUsedStarAtomizer(PlayerUsedStarAtomizer::from_bytes(&mut cur)?)), PlayerUsedStarAtomizer::CMD => Ok(GameMessage::PlayerUsedStarAtomizer(PlayerUsedStarAtomizer::from_bytes(&mut cur)?)),
SpawningMonsters::CMD => Ok(GameMessage::SpawningMonsters(SpawningMonsters::from_bytes(&mut cur)?)), SpawningMonsters::CMD => Ok(GameMessage::SpawningMonsters(SpawningMonsters::from_bytes(&mut cur)?)),
PlayerTelepipe::CMD => Ok(GameMessage::PlayerTelepipe(PlayerTelepipe::from_bytes(&mut cur)?)), PlayerTelepipe::CMD => Ok(GameMessage::PlayerTelepipe(PlayerTelepipe::from_bytes(&mut cur)?)),
NpcSpawn::CMD => Ok(GameMessage::NpcSpawn(NpcSpawn::from_bytes(&mut cur)?)), NpcSpawn::CMD => Ok(GameMessage::NpcSpawn(NpcSpawn::from_bytes(&mut cur)?)),
PlayerJoiningGame::CMD => Ok(GameMessage::PlayerJoiningGame(PlayerJoiningGame::from_bytes(&mut cur)?)), ActivateBossWarp::CMD => Ok(GameMessage::ActivateBossWarp(ActivateBossWarp::from_bytes(&mut cur)?)),
PlayerJoiningGame::CMD => Ok(GameMessage::PlayerJoiningGame(Box::new(PlayerJoiningGame::from_bytes(&mut cur)?))),
PlayerJoiningGame2::CMD => Ok(GameMessage::PlayerJoiningGame2(PlayerJoiningGame2::from_bytes(&mut cur)?)), PlayerJoiningGame2::CMD => Ok(GameMessage::PlayerJoiningGame2(PlayerJoiningGame2::from_bytes(&mut cur)?)),
BurstDone::CMD => Ok(GameMessage::BurstDone(BurstDone::from_bytes(&mut cur)?)), BurstDone::CMD => Ok(GameMessage::BurstDone(BurstDone::from_bytes(&mut cur)?)),
WordSelect::CMD => Ok(GameMessage::WordSelect(WordSelect::from_bytes(&mut cur)?)), WordSelect::CMD => Ok(GameMessage::WordSelect(WordSelect::from_bytes(&mut cur)?)),
@ -1229,7 +1358,7 @@ impl PSOPacketData for GameMessage {
//BmodeData::CMD => Ok(GameMessage::BmodeData(BmodeData::from_bytes(&mut cur)?)), //BmodeData::CMD => Ok(GameMessage::BmodeData(BmodeData::from_bytes(&mut cur)?)),
PlayerTrapSet::CMD => Ok(GameMessage::PlayerTrapSet(PlayerTrapSet::from_bytes(&mut cur)?)), PlayerTrapSet::CMD => Ok(GameMessage::PlayerTrapSet(PlayerTrapSet::from_bytes(&mut cur)?)),
//Unknown84::CMD => Ok(GameMessage::Unknown84(Unknown84::from_bytes(&mut cur)?)), //Unknown84::CMD => Ok(GameMessage::Unknown84(Unknown84::from_bytes(&mut cur)?)),
//PlayerTrapActivate::CMD => Ok(GameMessage::PlayerTrapActivate(PlayerTrapActivate::from_bytes(&mut cur)?)), PlayerTrapActivate::CMD => Ok(GameMessage::PlayerTrapActivate(PlayerTrapActivate::from_bytes(&mut cur)?)),
//PlayerShrink::CMD => Ok(GameMessage::PlayerShrink(PlayerShrink::from_bytes(&mut cur)?)), //PlayerShrink::CMD => Ok(GameMessage::PlayerShrink(PlayerShrink::from_bytes(&mut cur)?)),
//PlayerUnshrink::CMD => Ok(GameMessage::PlayerUnshrink(PlayerUnshrink::from_bytes(&mut cur)?)), //PlayerUnshrink::CMD => Ok(GameMessage::PlayerUnshrink(PlayerUnshrink::from_bytes(&mut cur)?)),
PlayerKilledByMonster::CMD => Ok(GameMessage::PlayerKilledByMonster(PlayerKilledByMonster::from_bytes(&mut cur)?)), PlayerKilledByMonster::CMD => Ok(GameMessage::PlayerKilledByMonster(PlayerKilledByMonster::from_bytes(&mut cur)?)),
@ -1245,7 +1374,7 @@ impl PSOPacketData for GameMessage {
//BossInteractionOlgaFlow::CMD => Ok(GameMessage::BossInteractionOlgaFlow(BossInteractionOlgaFlow::from_bytes(&mut cur)?)), //BossInteractionOlgaFlow::CMD => Ok(GameMessage::BossInteractionOlgaFlow(BossInteractionOlgaFlow::from_bytes(&mut cur)?)),
//BossInteractionOlgaFlow2::CMD => Ok(GameMessage::BossInteractionOlgaFlow2(BossInteractionOlgaFlow2::from_bytes(&mut cur)?)), //BossInteractionOlgaFlow2::CMD => Ok(GameMessage::BossInteractionOlgaFlow2(BossInteractionOlgaFlow2::from_bytes(&mut cur)?)),
//BossInteractionOlgaFlow3::CMD => Ok(GameMessage::BossInteractionOlgaFlow3(BossInteractionOlgaFlow3::from_bytes(&mut cur)?)), //BossInteractionOlgaFlow3::CMD => Ok(GameMessage::BossInteractionOlgaFlow3(BossInteractionOlgaFlow3::from_bytes(&mut cur)?)),
//TradeRequest::CMD => Ok(GameMessage::TradeRequest(TradeRequest::from_bytes(&mut cur)?)), TradeRequest::CMD => Ok(GameMessage::TradeRequest(TradeRequest::from_bytes(&mut cur)?)),
//BossInteractionGolDragon::CMD => Ok(GameMessage::BossInteractionGolDragon(BossInteractionGolDragon::from_bytes(&mut cur)?)), //BossInteractionGolDragon::CMD => Ok(GameMessage::BossInteractionGolDragon(BossInteractionGolDragon::from_bytes(&mut cur)?)),
//BossInteractionBarbaRay::CMD => Ok(GameMessage::BossInteractionBarbaRay(BossInteractionBarbaRay::from_bytes(&mut cur)?)), //BossInteractionBarbaRay::CMD => Ok(GameMessage::BossInteractionBarbaRay(BossInteractionBarbaRay::from_bytes(&mut cur)?)),
//BossInteractionBarbaRay2::CMD => Ok(GameMessage::BossInteractionBarbaRay2(BossInteractionBarbaRay2::from_bytes(&mut cur)?)), //BossInteractionBarbaRay2::CMD => Ok(GameMessage::BossInteractionBarbaRay2(BossInteractionBarbaRay2::from_bytes(&mut cur)?)),
@ -1262,7 +1391,7 @@ impl PSOPacketData for GameMessage {
TekAccept::CMD => Ok(GameMessage::TekAccept(TekAccept::from_bytes(&mut cur)?)), TekAccept::CMD => Ok(GameMessage::TekAccept(TekAccept::from_bytes(&mut cur)?)),
BankRequest::CMD => Ok(GameMessage::BankRequest(BankRequest::from_bytes(&mut cur)?)), BankRequest::CMD => Ok(GameMessage::BankRequest(BankRequest::from_bytes(&mut cur)?)),
BankInteraction::CMD => Ok(GameMessage::BankInteraction(BankInteraction::from_bytes(&mut cur)?)), BankInteraction::CMD => Ok(GameMessage::BankInteraction(BankInteraction::from_bytes(&mut cur)?)),
//PlayerSoldItem::CMD => Ok(GameMessage::PlayerSoldItem(PlayerSoldItem::from_bytes(&mut cur)?)), PlayerSoldItem::CMD => Ok(GameMessage::PlayerSoldItem(PlayerSoldItem::from_bytes(&mut cur)?)),
//TeamInvite::CMD => Ok(GameMessage::TeamInvite(TeamInvite::from_bytes(&mut cur)?)), //TeamInvite::CMD => Ok(GameMessage::TeamInvite(TeamInvite::from_bytes(&mut cur)?)),
//AcceptTeamInvite::CMD => Ok(GameMessage::AcceptTeamInvite(AcceptTeamInvite::from_bytes(&mut cur)?)), //AcceptTeamInvite::CMD => Ok(GameMessage::AcceptTeamInvite(AcceptTeamInvite::from_bytes(&mut cur)?)),
CreateItem::CMD => Ok(GameMessage::CreateItem(CreateItem::from_bytes(&mut cur)?)), CreateItem::CMD => Ok(GameMessage::CreateItem(CreateItem::from_bytes(&mut cur)?)),
@ -1270,7 +1399,7 @@ impl PSOPacketData for GameMessage {
DropCoordinates::CMD => Ok(GameMessage::DropCoordinates(DropCoordinates::from_bytes(&mut cur)?)), DropCoordinates::CMD => Ok(GameMessage::DropCoordinates(DropCoordinates::from_bytes(&mut cur)?)),
SortItems::CMD => Ok(GameMessage::SortItems(SortItems::from_bytes(&mut cur)?)), SortItems::CMD => Ok(GameMessage::SortItems(SortItems::from_bytes(&mut cur)?)),
PlayerUsedMedicalCenter::CMD => Ok(GameMessage::PlayerUsedMedicalCenter(PlayerUsedMedicalCenter::from_bytes(&mut cur)?)), PlayerUsedMedicalCenter::CMD => Ok(GameMessage::PlayerUsedMedicalCenter(PlayerUsedMedicalCenter::from_bytes(&mut cur)?)),
//ExperienceSteal::CMD => Ok(GameMessage::ExperienceSteal(ExperienceSteal::from_bytes(&mut cur)?)), ExperienceSteal::CMD => Ok(GameMessage::ExperienceSteal(ExperienceSteal::from_bytes(&mut cur)?)),
ChargeAttack::CMD => Ok(GameMessage::ChargeAttack(ChargeAttack::from_bytes(&mut cur)?)), ChargeAttack::CMD => Ok(GameMessage::ChargeAttack(ChargeAttack::from_bytes(&mut cur)?)),
RequestExp::CMD => Ok(GameMessage::RequestExp(RequestExp::from_bytes(&mut cur)?)), RequestExp::CMD => Ok(GameMessage::RequestExp(RequestExp::from_bytes(&mut cur)?)),
//QuestRewardMeseta::CMD => Ok(GameMessage::QuestRewardMeseta(QuestRewardMeseta::from_bytes(&mut cur)?)), //QuestRewardMeseta::CMD => Ok(GameMessage::QuestRewardMeseta(QuestRewardMeseta::from_bytes(&mut cur)?)),
@ -1298,7 +1427,7 @@ impl PSOPacketData for GameMessage {
_ => Err(PacketParseError::UnknownMessage(byte[0], _ => Err(PacketParseError::UnknownMessage(byte[0],
{ {
let mut b = vec![0; len[0] as usize * 4]; let mut b = vec![0; len[0] as usize * 4];
cur.read(&mut b).unwrap(); cur.read_exact(&mut b).unwrap();
b.to_vec() b.to_vec()
} }
)), )),
@ -1346,7 +1475,7 @@ impl PSOPacketData for GameMessage {
GameMessage::PlayerResurrected(data) => data.as_bytes(), GameMessage::PlayerResurrected(data) => data.as_bytes(),
GameMessage::PlayerResurrectedMedicalCenter(data) => data.as_bytes(), GameMessage::PlayerResurrectedMedicalCenter(data) => data.as_bytes(),
GameMessage::PlayerUsedMoonAtomizer(data) => data.as_bytes(), GameMessage::PlayerUsedMoonAtomizer(data) => data.as_bytes(),
GameMessage::PlayerPBDonation(data) => data.as_bytes(), // GameMessage::PlayerPBDonation(data) => data.as_bytes(),
GameMessage::PlayerInitiatedPB(data) => data.as_bytes(), GameMessage::PlayerInitiatedPB(data) => data.as_bytes(),
GameMessage::PlayerLeftArea(data) => data.as_bytes(), GameMessage::PlayerLeftArea(data) => data.as_bytes(),
GameMessage::PlayerSpawnedIntoArea(data) => data.as_bytes(), GameMessage::PlayerSpawnedIntoArea(data) => data.as_bytes(),
@ -1361,6 +1490,8 @@ impl PSOPacketData for GameMessage {
GameMessage::PlayerTechCast(data) => data.as_bytes(), GameMessage::PlayerTechCast(data) => data.as_bytes(),
GameMessage::PlayerTechDone(data) => data.as_bytes(), GameMessage::PlayerTechDone(data) => data.as_bytes(),
GameMessage::PlayerPBUsed(data) => data.as_bytes(), GameMessage::PlayerPBUsed(data) => data.as_bytes(),
GameMessage::PlayerDonatedPB(data) => data.as_bytes(),
GameMessage::PlayerPBReady(data) => data.as_bytes(),
GameMessage::PlayerBlockedDamage(data) => data.as_bytes(), GameMessage::PlayerBlockedDamage(data) => data.as_bytes(),
GameMessage::PlayerReceivedDamage(data) => data.as_bytes(), GameMessage::PlayerReceivedDamage(data) => data.as_bytes(),
GameMessage::PlayerReceivedDamage2(data) => data.as_bytes(), GameMessage::PlayerReceivedDamage2(data) => data.as_bytes(),
@ -1379,11 +1510,12 @@ impl PSOPacketData for GameMessage {
GameMessage::ItemDrop(data) => data.as_bytes(), GameMessage::ItemDrop(data) => data.as_bytes(),
GameMessage::RequestItem(data) => data.as_bytes(), GameMessage::RequestItem(data) => data.as_bytes(),
GameMessage::MagAnimation(data) => data.as_bytes(), GameMessage::MagAnimation(data) => data.as_bytes(),
//GameMessage::FloorItemLimitItemDeletion(data) => data.as_bytes(), GameMessage::FloorItemLimitItemDeletion(data) => data.as_bytes(),
GameMessage::PlayerUsedStarAtomizer(data) => data.as_bytes(), GameMessage::PlayerUsedStarAtomizer(data) => data.as_bytes(),
GameMessage::SpawningMonsters(data) => data.as_bytes(), GameMessage::SpawningMonsters(data) => data.as_bytes(),
GameMessage::PlayerTelepipe(data) => data.as_bytes(), GameMessage::PlayerTelepipe(data) => data.as_bytes(),
GameMessage::NpcSpawn(data) => data.as_bytes(), GameMessage::NpcSpawn(data) => data.as_bytes(),
GameMessage::ActivateBossWarp(data) => data.as_bytes(),
GameMessage::PlayerJoiningGame(data) => data.as_bytes(), GameMessage::PlayerJoiningGame(data) => data.as_bytes(),
GameMessage::PlayerJoiningGame2(data) => data.as_bytes(), GameMessage::PlayerJoiningGame2(data) => data.as_bytes(),
GameMessage::BurstDone(data) => data.as_bytes(), GameMessage::BurstDone(data) => data.as_bytes(),
@ -1396,7 +1528,7 @@ impl PSOPacketData for GameMessage {
//GameMessage::BmodeData(data) => data.as_bytes(), //GameMessage::BmodeData(data) => data.as_bytes(),
GameMessage::PlayerTrapSet(data) => data.as_bytes(), GameMessage::PlayerTrapSet(data) => data.as_bytes(),
//GameMessage::Unknown84(data) => data.as_bytes(), //GameMessage::Unknown84(data) => data.as_bytes(),
//GameMessage::PlayerTrapActivate(data) => data.as_bytes(), GameMessage::PlayerTrapActivate(data) => data.as_bytes(),
//GameMessage::PlayerShrink(data) => data.as_bytes(), //GameMessage::PlayerShrink(data) => data.as_bytes(),
//GameMessage::PlayerUnshrink(data) => data.as_bytes(), //GameMessage::PlayerUnshrink(data) => data.as_bytes(),
GameMessage::PlayerKilledByMonster(data) => data.as_bytes(), GameMessage::PlayerKilledByMonster(data) => data.as_bytes(),
@ -1412,7 +1544,7 @@ impl PSOPacketData for GameMessage {
//GameMessage::BossInteractionOlgaFlow(data) => data.as_bytes(), //GameMessage::BossInteractionOlgaFlow(data) => data.as_bytes(),
//GameMessage::BossInteractionOlgaFlow2(data) => data.as_bytes(), //GameMessage::BossInteractionOlgaFlow2(data) => data.as_bytes(),
//GameMessage::BossInteractionOlgaFlow3(data) => data.as_bytes(), //GameMessage::BossInteractionOlgaFlow3(data) => data.as_bytes(),
//GameMessage::TradeRequest(data) => data.as_bytes(), GameMessage::TradeRequest(data) => data.as_bytes(),
//GameMessage::BossInteractionGolDragon(data) => data.as_bytes(), //GameMessage::BossInteractionGolDragon(data) => data.as_bytes(),
//GameMessage::BossInteractionBarbaRay(data) => data.as_bytes(), //GameMessage::BossInteractionBarbaRay(data) => data.as_bytes(),
//GameMessage::BossInteractionBarbaRay2(data) => data.as_bytes(), //GameMessage::BossInteractionBarbaRay2(data) => data.as_bytes(),
@ -1429,7 +1561,7 @@ impl PSOPacketData for GameMessage {
GameMessage::TekAccept(data) => data.as_bytes(), GameMessage::TekAccept(data) => data.as_bytes(),
GameMessage::BankRequest(data) => data.as_bytes(), GameMessage::BankRequest(data) => data.as_bytes(),
GameMessage::BankInteraction(data) => data.as_bytes(), GameMessage::BankInteraction(data) => data.as_bytes(),
//GameMessage::PlayerSoldItem(data) => data.as_bytes(), GameMessage::PlayerSoldItem(data) => data.as_bytes(),
//GameMessage::TeamInvite(data) => data.as_bytes(), //GameMessage::TeamInvite(data) => data.as_bytes(),
//GameMessage::AcceptTeamInvite(data) => data.as_bytes(), //GameMessage::AcceptTeamInvite(data) => data.as_bytes(),
GameMessage::CreateItem(data) => data.as_bytes(), GameMessage::CreateItem(data) => data.as_bytes(),
@ -1437,7 +1569,7 @@ impl PSOPacketData for GameMessage {
GameMessage::DropCoordinates(data) => data.as_bytes(), GameMessage::DropCoordinates(data) => data.as_bytes(),
GameMessage::SortItems(data) => data.as_bytes(), GameMessage::SortItems(data) => data.as_bytes(),
GameMessage::PlayerUsedMedicalCenter(data) => data.as_bytes(), GameMessage::PlayerUsedMedicalCenter(data) => data.as_bytes(),
//GameMessage::ExperienceSteal(data) => data.as_bytes(), GameMessage::ExperienceSteal(data) => data.as_bytes(),
GameMessage::ChargeAttack(data) => data.as_bytes(), GameMessage::ChargeAttack(data) => data.as_bytes(),
GameMessage::RequestExp(data) => data.as_bytes(), GameMessage::RequestExp(data) => data.as_bytes(),
//GameMessage::QuestRewardMeseta(data) => data.as_bytes(), //GameMessage::QuestRewardMeseta(data) => data.as_bytes(),
@ -1465,3 +1597,15 @@ impl PSOPacketData for GameMessage {
} }
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_trade_request_cancel() {
let data = vec![166, 4, 0, 0, 5, 4, 0, 0, 157, 58, 113, 0, 1, 0, 0, 0];
let _pkt = GameMessage::from_bytes(&mut std::io::Cursor::new(data)).unwrap();
}
}

View File

@ -3,7 +3,7 @@ use crate::{PSOPacket, PacketParseError, PSOPacketData};
use std::io::Read; use std::io::Read;
pub const PATCH_FILE_CHUNK_SIZE: u16 = 0x8000; // 32kb pub const PATCH_FILE_CHUNK_SIZE: u16 = 0x6000; // 24kb
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
type u8_str = u8; type u8_str = u8;
@ -19,10 +19,10 @@ pub struct PatchWelcome {
impl PatchWelcome { impl PatchWelcome {
pub fn new(server_key: u32, client_key: u32) -> PatchWelcome { pub fn new(server_key: u32, client_key: u32) -> PatchWelcome {
PatchWelcome { PatchWelcome {
copyright: b"Patch Server. Copyright SonicTeam, LTD. 2001".clone(), copyright: *b"Patch Server. Copyright SonicTeam, LTD. 2001",
padding: [0; 20], padding: [0; 20],
server_key: server_key, server_key,
client_key: client_key, client_key,
} }
} }
} }
@ -58,8 +58,8 @@ impl StartFileSend {
*dst = *src *dst = *src
} }
StartFileSend { StartFileSend {
id: id, id,
size: size, size,
filename: f, filename: f,
} }
} }
@ -106,31 +106,22 @@ impl PSOPacket for FileSend {
impl std::fmt::Debug for FileSend { impl std::fmt::Debug for FileSend {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "packet FileSend {{\n").unwrap(); writeln!(f, "packet FileSend {{").unwrap();
write!(f, " chunk_num: {:?}\n", self.chunk_num).unwrap(); writeln!(f, " chunk_num: {:?}", self.chunk_num).unwrap();
write!(f, " checksum: {:X?}\n", self.checksum).unwrap(); writeln!(f, " checksum: {:X?}", self.checksum).unwrap();
write!(f, " chunk_size: {:X?}\n", self.chunk_size).unwrap(); writeln!(f, " chunk_size: {:X?}", self.chunk_size).unwrap();
write!(f, " buffer: [...a large array ...]\n").unwrap(); writeln!(f, " buffer: [...a large array ...]").unwrap();
write!(f, "}}") writeln!(f, "}}")
} }
} }
#[derive(Default)]
#[pso_packet(0x08, no_flag)] #[pso_packet(0x08, no_flag)]
pub struct EndFileSend { pub struct EndFileSend {
padding: u32, padding: u32,
} }
impl EndFileSend {
pub fn new() -> EndFileSend {
EndFileSend {
padding: 0,
}
}
}
#[pso_packet(0x0B, no_flag)] #[pso_packet(0x0B, no_flag)]
pub struct PatchStartList { pub struct PatchStartList {
} }
@ -169,7 +160,7 @@ impl FileInfo {
*dst = *src *dst = *src
}; };
FileInfo { FileInfo {
id: id, id,
filename: f, filename: f,
} }
} }
@ -200,8 +191,8 @@ pub struct FilesToPatchMetadata {
impl FilesToPatchMetadata { impl FilesToPatchMetadata {
pub fn new(data_size: u32, file_count: u32) -> FilesToPatchMetadata { pub fn new(data_size: u32, file_count: u32) -> FilesToPatchMetadata {
FilesToPatchMetadata { FilesToPatchMetadata {
data_size: data_size, data_size,
file_count: file_count, file_count,
} }
} }
} }
@ -221,7 +212,7 @@ impl Message {
pub fn new(mut msg: String) -> Message { pub fn new(mut msg: String) -> Message {
msg.push('\0'); msg.push('\0');
Message { Message {
msg: msg, msg,
} }
} }
} }
@ -237,8 +228,8 @@ pub struct RedirectClient {
impl RedirectClient { impl RedirectClient {
pub fn new(ip: u32, port: u16) -> RedirectClient { pub fn new(ip: u32, port: u16) -> RedirectClient {
RedirectClient { RedirectClient {
ip: ip, ip,
port: port, port,
padding: 0, padding: 0,
} }
} }

View File

@ -1,6 +1,6 @@
use psopacket::{pso_packet, PSOPacketData}; use psopacket::{pso_packet, PSOPacketData};
use crate::{PSOPacket, PacketParseError, PSOPacketData}; use crate::{PSOPacket, PacketParseError, PSOPacketData};
use crate::utf8_to_utf16_array; use crate::util::utf8_to_utf16_array;
use crate::packet::messages::GameMessage; use crate::packet::messages::GameMessage;
//use character::character::FullCharacter; //use character::character::FullCharacter;
use crate::character::character as character; use crate::character::character as character;
@ -26,9 +26,9 @@ impl ShipWelcome {
let mut copyright = [0u8; 0x60]; let mut copyright = [0u8; 0x60];
copyright[..0x4B].clone_from_slice(b"Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM."); copyright[..0x4B].clone_from_slice(b"Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM.");
ShipWelcome { ShipWelcome {
copyright: copyright, copyright,
server_key: server_key, server_key,
client_key: client_key, client_key,
} }
} }
} }
@ -82,13 +82,13 @@ impl ShipBlockList {
menu: BLOCK_MENU_ID, menu: BLOCK_MENU_ID,
item: 0, item: 0,
flags: 0, flags: 0,
name: utf8_to_utf16_array!(shipname, 0x11) name: utf8_to_utf16_array(shipname)
}, },
blocks: (0..num_blocks).map(|i| BlockEntry { blocks: (0..num_blocks).map(|i| BlockEntry {
menu: BLOCK_MENU_ID, menu: BLOCK_MENU_ID,
item: i as u32 + 1, item: i as u32 + 1,
flags: 0, flags: 0,
name: utf8_to_utf16_array!(format!("Block {}", i+1), 0x11) name: utf8_to_utf16_array(format!("Block {}", i+1))
}).collect() }).collect()
} }
} }
@ -124,7 +124,7 @@ pub struct LobbySelect {
#[pso_packet(0xE7)] #[pso_packet(0xE7)]
pub struct FullCharacter { pub struct FullCharacter {
#[no_debug] #[nodebug]
character: character::FullCharacter, character: character::FullCharacter,
} }
@ -149,8 +149,8 @@ pub struct BurstDone72 {
target: u8, target: u8,
} }
impl BurstDone72 { impl Default for BurstDone72 {
pub fn new() -> BurstDone72 { fn default() -> BurstDone72 {
BurstDone72 { BurstDone72 {
msg: 0x72, msg: 0x72,
len: 3, len: 3,
@ -169,7 +169,7 @@ pub struct Message {
impl Message { impl Message {
pub fn new(msg: GameMessage) -> Message { pub fn new(msg: GameMessage) -> Message {
Message { Message {
msg: msg, msg,
} }
} }
} }
@ -184,7 +184,7 @@ impl DirectMessage {
pub fn new(target: u32, msg: GameMessage) -> DirectMessage { pub fn new(target: u32, msg: GameMessage) -> DirectMessage {
DirectMessage { DirectMessage {
flag: target, flag: target,
msg: msg, msg,
} }
} }
} }
@ -274,10 +274,32 @@ pub struct SmallDialog {
} }
impl SmallDialog { impl SmallDialog {
pub fn new(msg: String) -> SmallDialog { pub fn new(mut msg: String) -> SmallDialog {
if !msg.ends_with('\0') {
msg.push('\0');
}
SmallDialog { SmallDialog {
padding: [0; 0x02], padding: [0; 0x02],
msg: msg, msg,
}
}
}
// this is literally the same struct as 0x01.
#[pso_packet(0xB0)]
pub struct RightText {
padding: [u32; 0x02],
msg: String,
}
impl RightText {
pub fn new(mut msg: String) -> RightText {
if !msg.ends_with('\0') {
msg.push('\0');
}
RightText {
padding: [0; 0x02],
msg,
} }
} }
} }
@ -289,10 +311,31 @@ pub struct SmallLeftDialog {
} }
impl SmallLeftDialog { impl SmallLeftDialog {
pub fn new(msg: String) -> SmallLeftDialog { pub fn new(mut msg: String) -> SmallLeftDialog {
if !msg.ends_with('\0') {
msg.push('\0');
}
SmallLeftDialog { SmallLeftDialog {
padding: [0x00004500, 0x45004500], padding: [0x00004500, 0x45004500],
msg: msg, msg,
}
}
}
#[pso_packet(0x1A)]
pub struct LargeDialog {
padding: [u32; 0x02],
msg: String,
}
impl LargeDialog {
pub fn new(mut msg: String) -> LargeDialog {
if !msg.ends_with('\0') {
msg.push('\0');
}
LargeDialog {
padding: [0, 0x45000000],
msg,
} }
} }
} }
@ -340,8 +383,8 @@ pub struct LeaveLobby {
impl LeaveLobby { impl LeaveLobby {
pub fn new(client: u8, leader: u8) -> LeaveLobby { pub fn new(client: u8, leader: u8) -> LeaveLobby {
LeaveLobby { LeaveLobby {
client: client, client,
leader: leader, leader,
_padding: 0, _padding: 0,
} }
} }
@ -357,8 +400,8 @@ pub struct LeaveRoom {
impl LeaveRoom { impl LeaveRoom {
pub fn new(client: u8, leader: u8) -> LeaveRoom { pub fn new(client: u8, leader: u8) -> LeaveRoom {
LeaveRoom { LeaveRoom {
client: client, client,
leader: leader, leader,
_padding: 0, _padding: 0,
} }
} }
@ -375,8 +418,8 @@ impl PlayerChat {
pub fn new(guildcard: u32, message: String) -> PlayerChat { pub fn new(guildcard: u32, message: String) -> PlayerChat {
PlayerChat { PlayerChat {
unknown: 0x00010000, unknown: 0x00010000,
guildcard: guildcard, guildcard,
message: message, message,
} }
} }
} }
@ -391,6 +434,11 @@ pub struct RoomNameResponse {
pub name: String, pub name: String,
} }
#[pso_packet(0x6ED)]
pub struct UpdateTechMenu {
pub config: [u8; 0x28],
}
#[pso_packet(0x7ED)] #[pso_packet(0x7ED)]
pub struct UpdateConfig{ pub struct UpdateConfig{
pub config: [u8; 0xE8], pub config: [u8; 0xE8],
@ -400,6 +448,11 @@ pub struct UpdateConfig{
pub struct ViewInfoboardRequest { pub struct ViewInfoboardRequest {
} }
#[pso_packet(0xDE)]
pub struct RareMonsterList{
pub ids: [u16; 16],
}
#[derive(PSOPacketData, Clone)] #[derive(PSOPacketData, Clone)]
pub struct InfoboardResponse { pub struct InfoboardResponse {
pub name: [u16; 16], pub name: [u16; 16],
@ -448,7 +501,7 @@ pub struct LobbyEntry {
impl LobbyEntry { impl LobbyEntry {
pub fn new(menu_id: u32, lobby_id: u32) -> LobbyEntry { pub fn new(menu_id: u32, lobby_id: u32) -> LobbyEntry {
LobbyEntry { LobbyEntry {
menu_id: menu_id, menu_id,
item_id: lobby_id, item_id: lobby_id,
padding: 0, padding: 0,
} }
@ -461,8 +514,8 @@ pub struct LobbyList {
entries: [LobbyEntry; 16], entries: [LobbyEntry; 16],
} }
impl LobbyList { impl Default for LobbyList {
pub fn new() -> LobbyList { fn default() -> LobbyList {
let lobbies = (0..16).fold([LobbyEntry::default(); 16], let lobbies = (0..16).fold([LobbyEntry::default(); 16],
|mut acc, index| { |mut acc, index| {
acc[index].menu_id = LOBBY_MENU_ID; acc[index].menu_id = LOBBY_MENU_ID;
@ -489,8 +542,9 @@ pub struct ClientCharacterData {
pub data: [u8; 2088], pub data: [u8; 2088],
} }
#[pso_packet(0xA2)] #[pso_packet(0xA2, manual_flag)]
pub struct RequestQuestList { pub struct RequestQuestList {
pub flag: u32,
} }
#[derive(PSOPacketData, Clone, Copy)] #[derive(PSOPacketData, Clone, Copy)]
@ -558,6 +612,7 @@ pub struct QuestFileRequest {
pub struct QuestChunk { pub struct QuestChunk {
pub chunk_num: u32, pub chunk_num: u32,
pub filename: [u8; 16], pub filename: [u8; 16],
#[nodebug]
pub blob: [u8; 0x400], pub blob: [u8; 0x400],
pub blob_length: u32, pub blob_length: u32,
pub unknown: u32, pub unknown: u32,
@ -583,3 +638,74 @@ pub struct FullCharacterData {
pub struct SaveOptions { pub struct SaveOptions {
pub options: u32, pub options: u32,
} }
#[derive(PSOPacketData, Clone, Copy, Default)]
pub struct TradeItem {
pub item_data: [u8; 12],
pub item_id: u32,
pub item_data2: [u8; 4],
}
#[pso_packet(0xD0)]
pub struct ItemsToTrade {
pub trade_target: u8,
pub unknown2: u8,
pub count: u16,
pub items: [TradeItem; 32],
}
#[pso_packet(0xD1)]
pub struct AcknowledgeTrade {
}
#[pso_packet(0xD2)]
pub struct TradeConfirmed {
}
#[pso_packet(0xD4)]
pub struct CancelTrade {
}
#[pso_packet(0xD4, manual_flag)]
pub struct TradeSuccessful {
flag: u32,
}
impl std::default::Default for TradeSuccessful {
fn default() -> TradeSuccessful {
TradeSuccessful {
flag: 1,
}
}
}
#[pso_packet(0xDA, no_flag)]
pub struct LobbyEvent {
pub event: u32,
}
#[pso_packet(0x4ED)]
pub struct KeyboardConfig {
pub keyboard_config: [u8; 364],
}
#[pso_packet(0x5ED)]
pub struct GamepadConfig {
pub gamepad_config: [u8; 56],
}
// same struct as libpso::packet::messages::GuildcardRecv
#[pso_packet(0x4E8)]
pub struct GuildcardAccept {
id: u32,
name: [u16; 0x18],
team: [u16; 0x10],
desc: [u16; 0x58],
one: u8,
language: u8,
section_id: u8,
class: u8,
}

View File

@ -2,7 +2,7 @@
pub fn array_to_utf8<const X: usize>(array: [u8; X]) -> Result<String, std::string::FromUtf8Error> { pub fn array_to_utf8<const X: usize>(array: [u8; X]) -> Result<String, std::string::FromUtf8Error> {
String::from_utf8(array.to_vec()) String::from_utf8(array.to_vec())
.map(|mut s| { .map(|mut s| {
if let Some(index) = s.find("\u{0}") { if let Some(index) = s.find('\u{0}') {
s.truncate(index); s.truncate(index);
} }
s s
@ -12,35 +12,23 @@ pub fn array_to_utf8<const X: usize>(array: [u8; X]) -> Result<String, std::stri
pub fn array_to_utf16(array: &[u8]) -> String { pub fn array_to_utf16(array: &[u8]) -> String {
unsafe { unsafe {
let (_, data, _) = array.align_to(); let (_, data, _) = array.align_to();
String::from_utf16_lossy(&data).trim_matches(char::from(0)).into() String::from_utf16_lossy(data).trim_matches(char::from(0)).into()
} }
} }
pub fn utf8_to_array<const N: usize>(s: impl Into<String>) -> [u8; N] {
// TODO: const fn version of this! (helpful with tests) let mut array = [0u8; N];
#[macro_export] let s = s.into();
macro_rules! utf8_to_array { let bytes = s.as_bytes();
($s: expr, $size: expr) => { array[..bytes.len()].clone_from_slice(bytes);
{ array
let mut array = [0u8; $size];
let bytes = $s.as_bytes();
array[..bytes.len()].clone_from_slice(&bytes);
array
}
}
} }
#[macro_export] pub fn utf8_to_utf16_array<const N: usize>(s: impl Into<String>) -> [u16; N] {
macro_rules! utf8_to_utf16_array { let mut array = [0u16; N];
($s: expr, $size: expr) => { let bytes = s.into().encode_utf16().collect::<Vec<_>>();
{ array[..bytes.len()].clone_from_slice(&bytes);
let mut array = [0u16; $size]; array
//let bytes = $s.as_bytes();
let bytes = $s.encode_utf16().collect::<Vec<_>>();
array[..bytes.len()].clone_from_slice(&bytes);
array
}
}
} }
pub fn vec_to_array<T: Default + Copy, const N: usize>(vec: Vec<T>) -> [T; N] { pub fn vec_to_array<T: Default + Copy, const N: usize>(vec: Vec<T>) -> [T; N] {
@ -53,10 +41,12 @@ pub fn vec_to_array<T: Default + Copy, const N: usize>(vec: Vec<T>) -> [T; N] {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*;
#[test] #[test]
fn test_utf8_to_array() { fn test_utf8_to_array() {
let s = "asdf".to_owned(); let s = "asdf".to_owned();
let a = utf8_to_array!(s, 8); let a = utf8_to_array(s);
let mut e = [0u8; 8]; let mut e = [0u8; 8];
e[..4].clone_from_slice(b"asdf"); e[..4].clone_from_slice(b"asdf");
@ -64,14 +54,14 @@ mod test {
} }
#[test] #[test]
fn utf8_to_utf16_array() { fn test_utf8_to_utf16_array() {
let utf16 = utf8_to_utf16_array!("asdf", 16); let utf16 = utf8_to_utf16_array("asdf");
assert!(utf16 == [97, 115, 100, 102, 0,0,0,0,0,0,0,0,0,0,0,0]) assert!(utf16 == [97, 115, 100, 102, 0,0,0,0,0,0,0,0,0,0,0,0])
} }
#[test] #[test]
fn utf8_to_utf16_array_unicode() { fn test_utf8_to_utf16_array_unicode() {
let utf16 = utf8_to_utf16_array!("あいうえお", 16); let utf16 = utf8_to_utf16_array("あいうえお");
assert!(utf16 == [0x3042 , 0x3044, 0x3046, 0x3048, 0x304A, 0,0,0,0,0,0,0,0,0,0,0]) assert!(utf16 == [0x3042 , 0x3044, 0x3046, 0x3048, 0x304A, 0,0,0,0,0,0,0,0,0,0,0])
} }
} }