new drone, convert some macros to functions #32

Merged
jake merged 4 commits from somecleaning into master 1 year ago
  1. 31
      .drone.yml
  2. 2
      Cargo.toml
  3. 2
      psopacket/Cargo.toml
  4. 10
      psopacket/src/lib.rs
  5. 1
      src/character/mod.rs
  6. 15
      src/crypto/bb.rs
  7. 12
      src/crypto/mod.rs
  8. 14
      src/crypto/pc.rs
  9. 4
      src/lib.rs
  10. 72
      src/packet/login.rs
  11. 16
      src/packet/messages.rs
  12. 45
      src/packet/patch.rs
  13. 46
      src/packet/ship.rs
  14. 44
      src/util.rs

31
.drone.yml

@ -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

2
Cargo.toml

@ -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"

2
psopacket/Cargo.toml

@ -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"

10
psopacket/src/lib.rs

@ -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 };
@ -542,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];

1
src/character/mod.rs

@ -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;

15
src/crypto/bb.rs

@ -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;
l = r;
r = tmp;
std::mem::swap(&mut l, &mut r);
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;
r = tmp;
std::mem::swap(&mut l, &mut r);
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());

12
src/crypto/mod.rs

@ -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 decrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError>;
fn encrypt(&mut self, data: &[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> {
Ok(data.clone())
fn encrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> {
Ok(data.to_vec())
} }
fn decrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> {
Ok(data.clone())
fn decrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> {
Ok(data.to_vec())
} }
fn header_size(&self) -> usize { fn header_size(&self) -> usize {

14
src/crypto/pc.rs

@ -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;
edi = edi + W(0x15);
ebx -= esi;
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)
} }

4
src/lib.rs

@ -4,7 +4,7 @@ pub mod crypto;
pub mod packet; pub mod packet;
pub mod character; pub mod character;
pub mod util; pub mod util;
pub mod item;
//pub mod item;
use std::io::{Read, Seek}; use std::io::{Read, Seek};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -119,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> {

72
src/packet/login.rs

@ -1,7 +1,8 @@
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;
@ -23,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,
server_key: server_key,
client_key: client_key,
copyright,
server_key,
client_key,
} }
} }
} }
@ -75,8 +76,8 @@ pub struct Session {
pub character_slot: u8, // 1..=4 pub character_slot: u8, // 1..=4
} }
impl Session {
pub fn new() -> Session {
impl Default for Session {
fn default() -> Session {
Session { Session {
version: [0; 30], version: [0; 30],
session_id: 0, session_id: 0,
@ -179,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,
} }
} }
@ -193,9 +194,9 @@ impl LoginResponse {
status: AccountStatus::Ok, status: AccountStatus::Ok,
tag: 0x00010000, tag: 0x00010000,
//tag: 0x00000100, //tag: 0x00000100,
guildcard: guildcard,
team_id: team_id,
session: session,
guildcard,
team_id,
session,
caps: 0x00000102, caps: 0x00000102,
} }
} }
@ -228,10 +229,10 @@ impl SendKeyAndTeamSettings {
pub fn new(keyboard_config: [u8; 0x16C], gamepad_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],
keyboard_config: keyboard_config,
gamepad_config: gamepad_config,
guildcard: guildcard,
team_id: team_id,
keyboard_config,
gamepad_config,
guildcard,
team_id,
//team_info: [0; 2], //team_info: [0; 2],
team_info: [0; 8], team_info: [0; 8],
team_priv: 0, team_priv: 0,
@ -254,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,
port: port,
ip,
port,
padding: 0, padding: 0,
} }
} }
@ -275,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,
} }
} }
} }
@ -314,7 +315,7 @@ impl GuildcardDataHeader {
GuildcardDataHeader { GuildcardDataHeader {
one: 1, one: 1,
len: len as u32, len: len as u32,
checksum: checksum
checksum,
} }
} }
} }
@ -330,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,
} }
@ -338,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,
buffer: buffer,
len: len,
chunk,
buffer,
len,
} }
} }
} }
@ -371,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();
write!(f, " flag: {:?}\n", 0).unwrap();
write!(f, " _unknown: {:#X?}\n", self._unknown).unwrap();
write!(f, " chunk: {:#X?}\n", self.chunk).unwrap();
write!(f, " buffer: [0..{:#X}]\n", self.len).unwrap();
write!(f, "}}")
writeln!(f, "packet GuildcardDataChunk {{").unwrap();
writeln!(f, " flag: {:?}", 0).unwrap();
writeln!(f, " _unknown: {:#X?}", self._unknown).unwrap();
writeln!(f, " chunk: {:#X?}", self.chunk).unwrap();
writeln!(f, " buffer: [0..{:#X}]", self.len).unwrap();
writeln!(f, "}}")
} }
} }
@ -428,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();
write!(f, " files: [..]\n").unwrap();
write!(f, "}}")
writeln!(f, "packet ParamDataHeader{{").unwrap();
writeln!(f, " files: [..]").unwrap();
writeln!(f, "}}")
} }
} }
@ -492,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,
} }
} }
} }
@ -517,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,
}; };
@ -560,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);
} }
} }

16
src/packet/messages.rs

@ -764,21 +764,21 @@ impl PSOPacketData for TradeRequestCommand {
0, 0, 0, 0,
0, 0, 0, 0] 0, 0, 0, 0]
.into_iter() .into_iter()
.chain(meseta.to_le_bytes().to_vec().into_iter())
.chain(meseta.to_le_bytes().iter().copied())
.collect() .collect()
}, },
TradeRequestCommand::AddItem(item_id, amount) => { TradeRequestCommand::AddItem(item_id, amount) => {
vec![1u8, 0, 0, 0] vec![1u8, 0, 0, 0]
.into_iter() .into_iter()
.chain(item_id.to_le_bytes().to_vec().into_iter())
.chain(amount.to_le_bytes().to_vec().into_iter())
.chain(item_id.to_le_bytes().iter().copied())
.chain(amount.to_le_bytes().iter().copied())
.collect() .collect()
}, },
TradeRequestCommand::RemoveItem(item_id, amount) => { TradeRequestCommand::RemoveItem(item_id, amount) => {
vec![2u8, 0, 0, 0] vec![2u8, 0, 0, 0]
.into_iter() .into_iter()
.chain(item_id.to_le_bytes().to_vec().into_iter())
.chain(amount.to_le_bytes().to_vec().into_iter())
.chain(item_id.to_le_bytes().iter().copied())
.chain(amount.to_le_bytes().iter().copied())
.collect() .collect()
}, },
TradeRequestCommand::Confirm => { TradeRequestCommand::Confirm => {
@ -1178,7 +1178,7 @@ pub enum GameMessage {
PlayerTelepipe(PlayerTelepipe), PlayerTelepipe(PlayerTelepipe),
NpcSpawn(NpcSpawn), NpcSpawn(NpcSpawn),
ActivateBossWarp(ActivateBossWarp), ActivateBossWarp(ActivateBossWarp),
PlayerJoiningGame(PlayerJoiningGame),
PlayerJoiningGame(Box<PlayerJoiningGame>),
PlayerJoiningGame2(PlayerJoiningGame2), PlayerJoiningGame2(PlayerJoiningGame2),
BurstDone(BurstDone), BurstDone(BurstDone),
WordSelect(WordSelect), WordSelect(WordSelect),
@ -1346,7 +1346,7 @@ impl PSOPacketData for GameMessage {
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)?)),
ActivateBossWarp::CMD => Ok(GameMessage::ActivateBossWarp(ActivateBossWarp::from_bytes(&mut cur)?)), ActivateBossWarp::CMD => Ok(GameMessage::ActivateBossWarp(ActivateBossWarp::from_bytes(&mut cur)?)),
PlayerJoiningGame::CMD => Ok(GameMessage::PlayerJoiningGame(PlayerJoiningGame::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)?)),
@ -1427,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()
} }
)), )),

45
src/packet/patch.rs

@ -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,
client_key: client_key,
server_key,
client_key,
} }
} }
} }
@ -58,8 +58,8 @@ impl StartFileSend {
*dst = *src *dst = *src
} }
StartFileSend { StartFileSend {
id: id,
size: size,
id,
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();
write!(f, " chunk_num: {:?}\n", self.chunk_num).unwrap();
write!(f, " checksum: {:X?}\n", self.checksum).unwrap();
write!(f, " chunk_size: {:X?}\n", self.chunk_size).unwrap();
write!(f, " buffer: [...a large array ...]\n").unwrap();
write!(f, "}}")
writeln!(f, "packet FileSend {{").unwrap();
writeln!(f, " chunk_num: {:?}", self.chunk_num).unwrap();
writeln!(f, " checksum: {:X?}", self.checksum).unwrap();
writeln!(f, " chunk_size: {:X?}", self.chunk_size).unwrap();
writeln!(f, " buffer: [...a large array ...]").unwrap();
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,
file_count: file_count,
data_size,
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,
port: port,
ip,
port,
padding: 0, padding: 0,
} }
} }

46
src/packet/ship.rs

@ -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,
server_key: server_key,
client_key: client_key,
copyright,
server_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()
} }
} }
@ -149,8 +149,8 @@ pub struct BurstDone72 {
target: u8, target: u8,
} }
impl BurstDone72 {
pub fn new() -> BurstDone72 {
impl Default for 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,
} }
} }
} }
@ -280,7 +280,7 @@ impl SmallDialog {
} }
SmallDialog { SmallDialog {
padding: [0; 0x02], padding: [0; 0x02],
msg: msg,
msg,
} }
} }
} }
@ -299,7 +299,7 @@ impl RightText {
} }
RightText { RightText {
padding: [0; 0x02], padding: [0; 0x02],
msg: msg,
msg,
} }
} }
} }
@ -317,7 +317,7 @@ impl SmallLeftDialog {
} }
SmallLeftDialog { SmallLeftDialog {
padding: [0x00004500, 0x45004500], padding: [0x00004500, 0x45004500],
msg: msg,
msg,
} }
} }
} }
@ -335,7 +335,7 @@ impl LargeDialog {
} }
LargeDialog { LargeDialog {
padding: [0, 0x45000000], padding: [0, 0x45000000],
msg: msg,
msg,
} }
} }
} }
@ -383,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,
leader: leader,
client,
leader,
_padding: 0, _padding: 0,
} }
} }
@ -400,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,
leader: leader,
client,
leader,
_padding: 0, _padding: 0,
} }
} }
@ -418,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,
message: message,
guildcard,
message,
} }
} }
} }
@ -501,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,
} }
@ -514,8 +514,8 @@ pub struct LobbyList {
entries: [LobbyEntry; 16], entries: [LobbyEntry; 16],
} }
impl LobbyList {
pub fn new() -> LobbyList {
impl Default for 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;

44
src/util.rs

@ -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,36 +12,24 @@ 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()
} }
} }
// TODO: const fn version of this! (helpful with tests)
#[macro_export]
macro_rules! utf8_to_array {
($s: expr, $size: expr) => {
{
let mut array = [0u8; $size];
let bytes = $s.as_bytes();
array[..bytes.len()].clone_from_slice(&bytes);
pub fn utf8_to_array<const N: usize>(s: impl Into<String>) -> [u8; N] {
let mut array = [0u8; N];
let s = s.into();
let bytes = s.as_bytes();
array[..bytes.len()].clone_from_slice(bytes);
array array
} }
}
}
#[macro_export]
macro_rules! utf8_to_utf16_array {
($s: expr, $size: expr) => {
{
let mut array = [0u16; $size];
//let bytes = $s.as_bytes();
let bytes = $s.encode_utf16().collect::<Vec<_>>();
pub fn utf8_to_utf16_array<const N: usize>(s: impl Into<String>) -> [u16; N] {
let mut array = [0u16; N];
let bytes = s.into().encode_utf16().collect::<Vec<_>>();
array[..bytes.len()].clone_from_slice(&bytes); array[..bytes.len()].clone_from_slice(&bytes);
array 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] {
let mut result: [T; N] = [T::default(); N]; let mut result: [T; N] = [T::default(); 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() {
let utf16 = utf8_to_utf16_array!("asdf", 16);
fn test_utf8_to_utf16_array() {
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() {
let utf16 = utf8_to_utf16_array!("あいうえお", 16);
fn test_utf8_to_utf16_array_unicode() {
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])
} }
} }
Loading…
Cancel
Save