|
@ -1,9 +1,12 @@ |
|
|
use psopacket::pso_packet;
|
|
|
use psopacket::pso_packet;
|
|
|
use crate::{PSOPacket, PacketParseError};
|
|
|
use crate::{PSOPacket, PacketParseError};
|
|
|
|
|
|
|
|
|
|
|
|
use crate::character::character::SelectScreenCharacter;
|
|
|
|
|
|
|
|
|
use std::io::{Read, Seek, SeekFrom};
|
|
|
use std::io::{Read, Seek, SeekFrom};
|
|
|
|
|
|
|
|
|
pub const PATCH_FILE_CHUNK_SIZE: u16 = 0x8000; // 32kb
|
|
|
pub const PATCH_FILE_CHUNK_SIZE: u16 = 0x8000; // 32kb
|
|
|
|
|
|
pub const GUILD_CARD_CHUNK_SIZE: usize = 0x6800;
|
|
|
|
|
|
|
|
|
#[allow(non_camel_case_types)]
|
|
|
#[allow(non_camel_case_types)]
|
|
|
type u8_str = u8;
|
|
|
type u8_str = u8;
|
|
@ -228,6 +231,103 @@ pub struct CharAck { |
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[pso_packet(0xE5)]
|
|
|
|
|
|
pub struct CharacterPreview {
|
|
|
|
|
|
pub flag: u32,
|
|
|
|
|
|
pub slot: u32,
|
|
|
|
|
|
pub character: SelectScreenCharacter,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[pso_packet(0x3E8)]
|
|
|
|
|
|
pub struct GuildcardDataRequest {
|
|
|
|
|
|
flag: u32,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[pso_packet(0x1DC)]
|
|
|
|
|
|
pub struct GuildcardDataHeader {
|
|
|
|
|
|
flag: u32,
|
|
|
|
|
|
one: u32,
|
|
|
|
|
|
len: u32,
|
|
|
|
|
|
checksum: u32,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl GuildcardDataHeader {
|
|
|
|
|
|
pub fn new(len: usize, checksum: u32) -> GuildcardDataHeader {
|
|
|
|
|
|
GuildcardDataHeader {
|
|
|
|
|
|
flag: 0,
|
|
|
|
|
|
one: 1,
|
|
|
|
|
|
len: len as u32,
|
|
|
|
|
|
checksum: checksum
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[pso_packet(0x3DC)]
|
|
|
|
|
|
pub struct GuildcardDataChunkRequest {
|
|
|
|
|
|
flag: u32,
|
|
|
|
|
|
_unknown: u32,
|
|
|
|
|
|
pub chunk: u32,
|
|
|
|
|
|
pub again: u32,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub struct GuildcardDataChunk {
|
|
|
|
|
|
flag: u32,
|
|
|
|
|
|
_unknown: u32,
|
|
|
|
|
|
chunk: u32,
|
|
|
|
|
|
pub buffer: [u8; GUILD_CARD_CHUNK_SIZE],
|
|
|
|
|
|
|
|
|
|
|
|
len: usize,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl GuildcardDataChunk {
|
|
|
|
|
|
pub fn new(chunk: u32, buffer: [u8; GUILD_CARD_CHUNK_SIZE], len: usize) -> GuildcardDataChunk {
|
|
|
|
|
|
GuildcardDataChunk {
|
|
|
|
|
|
flag: 0,
|
|
|
|
|
|
_unknown: 0,
|
|
|
|
|
|
chunk: chunk as u32,
|
|
|
|
|
|
buffer: buffer,
|
|
|
|
|
|
len: len,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl PSOPacket for GuildcardDataChunk {
|
|
|
|
|
|
fn from_bytes(_data: &[u8]) -> Result<GuildcardDataChunk, PacketParseError> {
|
|
|
|
|
|
unimplemented!();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn as_bytes(&self) -> Vec<u8> {
|
|
|
|
|
|
let mut buf: Vec<u8> = Vec::new();
|
|
|
|
|
|
buf.extend_from_slice(&u32::to_le_bytes(self.flag));
|
|
|
|
|
|
buf.extend_from_slice(&u32::to_le_bytes(self._unknown));
|
|
|
|
|
|
buf.extend_from_slice(&u32::to_le_bytes(self.chunk));
|
|
|
|
|
|
buf.extend_from_slice(&self.buffer[0..self.len]);
|
|
|
|
|
|
while buf.len() % 4 != 0 {
|
|
|
|
|
|
buf.push(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let pkt_len = (buf.len() + 4) as u16;
|
|
|
|
|
|
let mut prebuf: Vec<u8> = Vec::new();
|
|
|
|
|
|
prebuf.extend_from_slice(&u16::to_le_bytes(pkt_len));
|
|
|
|
|
|
prebuf.extend_from_slice(&u16::to_le_bytes(0x2DC));
|
|
|
|
|
|
prebuf.append(&mut buf);
|
|
|
|
|
|
prebuf
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl std::fmt::Debug for GuildcardDataChunk {
|
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
|
|
write!(f, "packet GuildcardDataChunk {{\n").unwrap();
|
|
|
|
|
|
write!(f, " flag: {:?}\n", self.flag).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, "}}")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
#[cfg(test)]
|
|
|
mod tests {
|
|
|
mod tests {
|
|
|
#[test]
|
|
|
#[test]
|
|
|