|
@ -1,6 +1,6 @@ |
|
|
use chrono::{DateTime, Utc};
|
|
|
use chrono::{DateTime, Utc};
|
|
|
|
|
|
|
|
|
use psopacket::pso_packet;
|
|
|
|
|
|
|
|
|
use psopacket::{pso_packet, PSOPacketData};
|
|
|
use crate::{PSOPacket, PacketParseError, PSOPacketData};
|
|
|
use crate::{PSOPacket, PacketParseError, PSOPacketData};
|
|
|
|
|
|
|
|
|
use crate::character::character::SelectScreenCharacter;
|
|
|
use crate::character::character::SelectScreenCharacter;
|
|
@ -31,6 +31,64 @@ impl LoginWelcome { |
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
|
pub enum SessionAction {
|
|
|
|
|
|
None,
|
|
|
|
|
|
SelectCharacter,
|
|
|
|
|
|
NewCharacter,
|
|
|
|
|
|
DressingRoom,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl PSOPacketData for SessionAction {
|
|
|
|
|
|
fn from_bytes<R: Read>(cursor: &mut R) -> Result<Self, PacketParseError> {
|
|
|
|
|
|
let mut bytes = [0u8; 1];
|
|
|
|
|
|
let len = cursor.read(&mut bytes).map_err(|_| PacketParseError::ReadError)?;
|
|
|
|
|
|
if len != 1 {
|
|
|
|
|
|
return Err(PacketParseError::NotEnoughBytes)
|
|
|
|
|
|
}
|
|
|
|
|
|
match bytes[0] {
|
|
|
|
|
|
0 => Ok(SessionAction::None),
|
|
|
|
|
|
1 => Ok(SessionAction::SelectCharacter),
|
|
|
|
|
|
2 => Ok(SessionAction::NewCharacter),
|
|
|
|
|
|
3 => Ok(SessionAction::DressingRoom),
|
|
|
|
|
|
_ => Err(PacketParseError::InvalidValue)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn as_bytes(&self) -> Vec<u8> {
|
|
|
|
|
|
vec![match self {
|
|
|
|
|
|
SessionAction::None => 0,
|
|
|
|
|
|
SessionAction::SelectCharacter => 1,
|
|
|
|
|
|
SessionAction::NewCharacter => 2,
|
|
|
|
|
|
SessionAction::DressingRoom => 3,
|
|
|
|
|
|
}]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(PSOPacketData, Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
|
pub struct Session {
|
|
|
|
|
|
pub version: [u8; 30],
|
|
|
|
|
|
pub session_id: u32,
|
|
|
|
|
|
pub interserver_checksum: u32,
|
|
|
|
|
|
pub action: SessionAction,
|
|
|
|
|
|
pub character_slot: u8, // 1..=4
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Session {
|
|
|
|
|
|
pub fn new() -> Session {
|
|
|
|
|
|
Session {
|
|
|
|
|
|
version: [0; 30],
|
|
|
|
|
|
session_id: 0,
|
|
|
|
|
|
interserver_checksum: 0,
|
|
|
|
|
|
action: SessionAction::None,
|
|
|
|
|
|
character_slot: 0,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[pso_packet(0x93)]
|
|
|
#[pso_packet(0x93)]
|
|
|
pub struct Login {
|
|
|
pub struct Login {
|
|
|
pub tag: u32,
|
|
|
pub tag: u32,
|
|
@ -45,7 +103,8 @@ pub struct Login { |
|
|
pub password: [u8; 16],
|
|
|
pub password: [u8; 16],
|
|
|
pub unknown3: [u8; 40],
|
|
|
pub unknown3: [u8; 40],
|
|
|
pub hwinfo: [u8; 8],
|
|
|
pub hwinfo: [u8; 8],
|
|
|
pub security_data: [u8; 40],
|
|
|
|
|
|
|
|
|
pub session: Session
|
|
|
|
|
|
//pub security_data: [u8; 40],
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
@ -67,7 +126,10 @@ pub enum AccountStatus { |
|
|
impl PSOPacketData for AccountStatus {
|
|
|
impl PSOPacketData for AccountStatus {
|
|
|
fn from_bytes<R: Read>(cursor: &mut R) -> Result<Self, PacketParseError> {
|
|
|
fn from_bytes<R: Read>(cursor: &mut R) -> Result<Self, PacketParseError> {
|
|
|
let mut bytes = [0u8; 4];
|
|
|
let mut bytes = [0u8; 4];
|
|
|
cursor.read(&mut bytes).map_err(|_| PacketParseError::ReadError)?;
|
|
|
|
|
|
|
|
|
let len = cursor.read(&mut bytes).map_err(|_| PacketParseError::ReadError)?;
|
|
|
|
|
|
if len != 4 {
|
|
|
|
|
|
return Err(PacketParseError::NotEnoughBytes)
|
|
|
|
|
|
}
|
|
|
match bytes[0] {
|
|
|
match bytes[0] {
|
|
|
0 => Ok(AccountStatus::Ok),
|
|
|
0 => Ok(AccountStatus::Ok),
|
|
|
1 => Ok(AccountStatus::Error),
|
|
|
1 => Ok(AccountStatus::Error),
|
|
@ -110,30 +172,31 @@ pub struct LoginResponse { |
|
|
pub tag: u32,
|
|
|
pub tag: u32,
|
|
|
pub guildcard: u32,
|
|
|
pub guildcard: u32,
|
|
|
pub team_id: u32,
|
|
|
pub team_id: u32,
|
|
|
pub security_data: [u8; 40],
|
|
|
|
|
|
|
|
|
//pub security_data: [u8; 40],
|
|
|
|
|
|
pub session: Session,
|
|
|
pub caps: u32,
|
|
|
pub caps: u32,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
impl LoginResponse {
|
|
|
impl LoginResponse {
|
|
|
pub fn by_status(status: AccountStatus, security_data: [u8; 40]) -> LoginResponse {
|
|
|
|
|
|
|
|
|
pub fn by_status(status: AccountStatus, session: Session) -> LoginResponse {
|
|
|
LoginResponse {
|
|
|
LoginResponse {
|
|
|
status: status,
|
|
|
status: status,
|
|
|
tag: 0x00010000,
|
|
|
tag: 0x00010000,
|
|
|
//tag: 0x00000100,
|
|
|
//tag: 0x00000100,
|
|
|
guildcard: 0,
|
|
|
guildcard: 0,
|
|
|
team_id: 0,
|
|
|
team_id: 0,
|
|
|
security_data: security_data,
|
|
|
|
|
|
|
|
|
session: session,
|
|
|
caps: 0x00000102,
|
|
|
caps: 0x00000102,
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
pub fn by_char_select(guildcard: u32, team_id: u32, security_data: [u8; 40]) -> LoginResponse {
|
|
|
|
|
|
|
|
|
pub fn by_char_select(guildcard: u32, team_id: u32, session: Session) -> LoginResponse {
|
|
|
LoginResponse {
|
|
|
LoginResponse {
|
|
|
status: AccountStatus::Ok,
|
|
|
status: AccountStatus::Ok,
|
|
|
tag: 0x00010000,
|
|
|
tag: 0x00010000,
|
|
|
//tag: 0x00000100,
|
|
|
//tag: 0x00000100,
|
|
|
guildcard: guildcard,
|
|
|
guildcard: guildcard,
|
|
|
team_id: team_id,
|
|
|
team_id: team_id,
|
|
|
security_data: security_data,
|
|
|
|
|
|
|
|
|
session: session,
|
|
|
caps: 0x00000102,
|
|
|
caps: 0x00000102,
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@ -458,7 +521,6 @@ impl PSOPacketData for ShipListEntry { |
|
|
bytes.extend_from_slice(&u16::to_le_bytes(self.flags));
|
|
|
bytes.extend_from_slice(&u16::to_le_bytes(self.flags));
|
|
|
bytes.extend_from_slice(&unsafe { std::mem::transmute::<[u16; 0x11], [u8; 0x11*2]>(self.name) });
|
|
|
bytes.extend_from_slice(&unsafe { std::mem::transmute::<[u16; 0x11], [u8; 0x11*2]>(self.name) });
|
|
|
bytes
|
|
|
bytes
|
|
|
//self.to_le_bytes().to_vec()
|
|
|
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
@ -527,12 +589,13 @@ mod tests { |
|
|
#[test]
|
|
|
#[test]
|
|
|
fn test_account_status_enum() {
|
|
|
fn test_account_status_enum() {
|
|
|
use super::PSOPacket;
|
|
|
use super::PSOPacket;
|
|
|
|
|
|
use super::Session;
|
|
|
let pkt = super::LoginResponse {
|
|
|
let pkt = super::LoginResponse {
|
|
|
status: super::AccountStatus::InvalidPassword,
|
|
|
status: super::AccountStatus::InvalidPassword,
|
|
|
tag: 0,
|
|
|
tag: 0,
|
|
|
guildcard: 0,
|
|
|
guildcard: 0,
|
|
|
team_id: 0,
|
|
|
team_id: 0,
|
|
|
security_data: [0; 40],
|
|
|
|
|
|
|
|
|
session: Session::new(),
|
|
|
caps: 0,
|
|
|
caps: 0,
|
|
|
};
|
|
|
};
|
|
|
|
|
|
|
|
@ -571,4 +634,11 @@ mod tests { |
|
|
let pkt = super::ChecksumAck::new(1);
|
|
|
let pkt = super::ChecksumAck::new(1);
|
|
|
assert!(pkt.as_bytes() == [0xC, 0, 0xE8, 0x02, 0,0,0,0, 1,0,0,0]);
|
|
|
assert!(pkt.as_bytes() == [0xC, 0, 0xE8, 0x02, 0,0,0,0, 1,0,0,0]);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_session_size() {
|
|
|
|
|
|
use super::PSOPacketData;
|
|
|
|
|
|
let session = super::Session::new();
|
|
|
|
|
|
assert!(session.as_bytes().len() == 40);
|
|
|
|
|
|
}
|
|
|
}
|
|
|
}
|