You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

578 lines
14 KiB

5 years ago
5 years ago
5 years ago
2 years ago
5 years ago
5 years ago
5 years ago
  1. use chrono::{DateTime, Utc};
  2. use psopacket::{pso_packet, PSOPacketData};
  3. use crate::{PSOPacket, PacketParseError, PSOPacketData, utf8_to_utf16_array};
  4. use crate::character::character::SelectScreenCharacter;
  5. use std::io::Read;
  6. pub const GUILD_CARD_CHUNK_SIZE: usize = 0x6800;
  7. pub const PARAM_DATA_CHUNK_SIZE: usize = 0x6800;
  8. #[pso_packet(0x03)]
  9. pub struct LoginWelcome {
  10. #[utf8]
  11. copyright: [u8; 0x60],
  12. server_key: [u8; 48],
  13. client_key: [u8; 48],
  14. }
  15. impl LoginWelcome {
  16. pub fn new(server_key: [u8; 48], client_key: [u8; 48]) -> LoginWelcome {
  17. let mut copyright = [0u8; 0x60];
  18. copyright[..0x4B].clone_from_slice(b"Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM.");
  19. LoginWelcome {
  20. copyright: copyright,
  21. server_key: server_key,
  22. client_key: client_key,
  23. }
  24. }
  25. }
  26. #[derive(Clone, Copy, Debug, PartialEq)]
  27. pub enum SessionAction {
  28. None,
  29. SelectCharacter,
  30. NewCharacter,
  31. DressingRoom,
  32. }
  33. impl PSOPacketData for SessionAction {
  34. fn from_bytes<R: Read>(cursor: &mut R) -> Result<Self, PacketParseError> {
  35. let mut bytes = [0u8; 1];
  36. let len = cursor.read(&mut bytes).map_err(|_| PacketParseError::ReadError)?;
  37. if len != 1 {
  38. return Err(PacketParseError::NotEnoughBytes)
  39. }
  40. match bytes[0] {
  41. 0 => Ok(SessionAction::None),
  42. 1 => Ok(SessionAction::SelectCharacter),
  43. 2 => Ok(SessionAction::NewCharacter),
  44. 3 => Ok(SessionAction::DressingRoom),
  45. _ => Err(PacketParseError::InvalidValue)
  46. }
  47. }
  48. fn as_bytes(&self) -> Vec<u8> {
  49. vec![match self {
  50. SessionAction::None => 0,
  51. SessionAction::SelectCharacter => 1,
  52. SessionAction::NewCharacter => 2,
  53. SessionAction::DressingRoom => 3,
  54. }]
  55. }
  56. }
  57. #[derive(PSOPacketData, Clone, Copy)]
  58. pub struct Session {
  59. pub version: [u8; 30],
  60. pub session_id: u32,
  61. pub interserver_checksum: u32,
  62. pub action: SessionAction,
  63. pub character_slot: u8, // 1..=4
  64. }
  65. impl Session {
  66. pub fn new() -> Session {
  67. Session {
  68. version: [0; 30],
  69. session_id: 0,
  70. interserver_checksum: 0,
  71. action: SessionAction::None,
  72. character_slot: 0,
  73. }
  74. }
  75. }
  76. #[pso_packet(0x93)]
  77. pub struct Login {
  78. pub tag: u32,
  79. pub guildcard: u32,
  80. pub version: u16,
  81. pub unknown1: [u8; 6],
  82. pub team: u32,
  83. #[utf8]
  84. pub username: [u8; 16],
  85. pub unknown2: [u8; 32],
  86. #[utf8]
  87. pub password: [u8; 16],
  88. pub unknown3: [u8; 40],
  89. pub hwinfo: [u8; 8],
  90. pub session: Session
  91. //pub security_data: [u8; 40],
  92. }
  93. #[derive(Debug, Clone, PartialEq)]
  94. pub enum AccountStatus {
  95. Ok,
  96. Error,
  97. InvalidPassword,
  98. InvalidPassword2,
  99. Maintenance,
  100. AlreadyOnline,
  101. Banned,
  102. Banned2,
  103. InvalidUser,
  104. PayUp,
  105. Locked,
  106. BadVersion,
  107. }
  108. impl PSOPacketData for AccountStatus {
  109. fn from_bytes<R: Read>(cursor: &mut R) -> Result<Self, PacketParseError> {
  110. let mut bytes = [0u8; 4];
  111. let len = cursor.read(&mut bytes).map_err(|_| PacketParseError::ReadError)?;
  112. if len != 4 {
  113. return Err(PacketParseError::NotEnoughBytes)
  114. }
  115. match bytes[0] {
  116. 0 => Ok(AccountStatus::Ok),
  117. 1 => Ok(AccountStatus::Error),
  118. 2 => Ok(AccountStatus::InvalidPassword),
  119. 3 => Ok(AccountStatus::InvalidPassword2),
  120. 4 => Ok(AccountStatus::Maintenance),
  121. 5 => Ok(AccountStatus::AlreadyOnline),
  122. 6 => Ok(AccountStatus::Banned),
  123. 7 => Ok(AccountStatus::Banned2),
  124. 8 => Ok(AccountStatus::InvalidUser),
  125. 9 => Ok(AccountStatus::PayUp),
  126. 10 => Ok(AccountStatus::Locked),
  127. 11 => Ok(AccountStatus::BadVersion),
  128. _ => Err(PacketParseError::InvalidValue),
  129. }
  130. }
  131. fn as_bytes(&self) -> Vec<u8> {
  132. vec![match self {
  133. AccountStatus::Ok => 0,
  134. AccountStatus::Error => 1,
  135. AccountStatus::InvalidPassword => 2,
  136. AccountStatus::InvalidPassword2 => 3,
  137. AccountStatus::Maintenance => 4,
  138. AccountStatus::AlreadyOnline => 5,
  139. AccountStatus::Banned => 6,
  140. AccountStatus::Banned2 => 7,
  141. AccountStatus::InvalidUser => 8,
  142. AccountStatus::PayUp => 9,
  143. AccountStatus::Locked => 10,
  144. AccountStatus::BadVersion => 11,
  145. },0,0,0]
  146. }
  147. }
  148. #[pso_packet(0xE6)]
  149. pub struct LoginResponse {
  150. pub status: AccountStatus,
  151. pub tag: u32,
  152. pub guildcard: u32,
  153. pub team_id: u32,
  154. //pub security_data: [u8; 40],
  155. pub session: Session,
  156. pub caps: u32,
  157. }
  158. impl LoginResponse {
  159. pub fn by_status(status: AccountStatus, session: Session) -> LoginResponse {
  160. LoginResponse {
  161. status: status,
  162. tag: 0x00010000,
  163. //tag: 0x00000100,
  164. guildcard: 0,
  165. team_id: 0,
  166. session: session,
  167. caps: 0x00000102,
  168. }
  169. }
  170. pub fn by_char_select(guildcard: u32, team_id: u32, session: Session) -> LoginResponse {
  171. LoginResponse {
  172. status: AccountStatus::Ok,
  173. tag: 0x00010000,
  174. //tag: 0x00000100,
  175. guildcard: guildcard,
  176. team_id: team_id,
  177. session: session,
  178. caps: 0x00000102,
  179. }
  180. }
  181. }
  182. #[pso_packet(0xE0)]
  183. pub struct RequestSettings {
  184. }
  185. #[pso_packet(0xE2)]
  186. pub struct SendKeyAndTeamSettings {
  187. unknown: [u8; 0x114],
  188. keyboard_config: [u8; 0x16C],
  189. gamepad_config: [u8; 0x38],
  190. guildcard: u32,
  191. team_id: u32,
  192. //team_info: [u32; 2],
  193. team_info: [u8; 8],
  194. team_priv: u16,
  195. unknown2: u16,
  196. //team_name: [u16; 16],
  197. team_name: [u8; 32],
  198. #[nodebug]
  199. team_flag: [u8; 2048],
  200. team_rewards: [u8; 8],
  201. }
  202. impl SendKeyAndTeamSettings {
  203. pub fn new(keyboard_config: [u8; 0x16C], gamepad_config: [u8; 0x38], guildcard: u32, team_id: u32) -> SendKeyAndTeamSettings {
  204. SendKeyAndTeamSettings {
  205. unknown: [0; 0x114],
  206. keyboard_config: keyboard_config,
  207. gamepad_config: gamepad_config,
  208. guildcard: guildcard,
  209. team_id: team_id,
  210. //team_info: [0; 2],
  211. team_info: [0; 8],
  212. team_priv: 0,
  213. unknown2: 0,
  214. //team_name: [0; 16],
  215. team_name: [0; 32],
  216. team_flag: [0; 2048],
  217. team_rewards: [0; 8]
  218. }
  219. }
  220. }
  221. #[pso_packet(0x19)]
  222. pub struct RedirectClient {
  223. pub ip: u32,
  224. pub port: u16,
  225. pub padding: u16,
  226. }
  227. impl RedirectClient {
  228. pub fn new(ip: u32, port: u16) -> RedirectClient {
  229. RedirectClient {
  230. ip: ip,
  231. port: port,
  232. padding: 0,
  233. }
  234. }
  235. }
  236. #[pso_packet(0x1E8)]
  237. pub struct Checksum {
  238. pub checksum: u32,
  239. pub padding: u32,
  240. }
  241. #[pso_packet(0x2E8)]
  242. pub struct ChecksumAck {
  243. pub ack: u32,
  244. }
  245. impl ChecksumAck {
  246. pub fn new(ack: u32) -> ChecksumAck {
  247. ChecksumAck {
  248. ack: ack,
  249. }
  250. }
  251. }
  252. #[pso_packet(0xE3)]
  253. pub struct CharSelect {
  254. pub slot: u32,
  255. pub reason: u32, // TODO: enum?
  256. }
  257. #[pso_packet(0xE4)]
  258. pub struct CharAck {
  259. pub slot: u32,
  260. pub code: u32, // TODO: enum?
  261. }
  262. impl PSOPacketData for SelectScreenCharacter {
  263. fn from_bytes<R: Read>(cursor: &mut R) -> Result<Self, PacketParseError> {
  264. let mut buf = [0u8; SelectScreenCharacter::SIZE];
  265. cursor.read(&mut buf).map_err(|_| PacketParseError::ReadError)?;
  266. SelectScreenCharacter::from_le_bytes(buf)
  267. }
  268. fn as_bytes(&self) -> Vec<u8> {
  269. self.to_le_bytes().to_vec()
  270. }
  271. }
  272. #[pso_packet(0xE5)]
  273. pub struct CharacterPreview {
  274. pub slot: u32,
  275. pub character: SelectScreenCharacter,
  276. }
  277. #[pso_packet(0x3E8)]
  278. pub struct GuildcardDataRequest {
  279. }
  280. #[pso_packet(0x1DC)]
  281. pub struct GuildcardDataHeader {
  282. one: u32,
  283. len: u32,
  284. checksum: u32,
  285. }
  286. impl GuildcardDataHeader {
  287. pub fn new(len: usize, checksum: u32) -> GuildcardDataHeader {
  288. GuildcardDataHeader {
  289. one: 1,
  290. len: len as u32,
  291. checksum: checksum
  292. }
  293. }
  294. }
  295. #[pso_packet(0x3DC)]
  296. pub struct GuildcardDataChunkRequest {
  297. _unknown: u32,
  298. pub chunk: u32,
  299. pub again: u32,
  300. }
  301. pub struct GuildcardDataChunk {
  302. _unknown: u32,
  303. chunk: u32,
  304. pub buffer: [u8; GUILD_CARD_CHUNK_SIZE],
  305. len: usize,
  306. }
  307. impl GuildcardDataChunk {
  308. pub fn new(chunk: u32, buffer: [u8; GUILD_CARD_CHUNK_SIZE], len: usize) -> GuildcardDataChunk {
  309. GuildcardDataChunk {
  310. _unknown: 0,
  311. chunk: chunk as u32,
  312. buffer: buffer,
  313. len: len,
  314. }
  315. }
  316. }
  317. impl PSOPacket for GuildcardDataChunk {
  318. fn from_bytes(_data: &[u8]) -> Result<GuildcardDataChunk, PacketParseError> {
  319. unimplemented!();
  320. }
  321. fn as_bytes(&self) -> Vec<u8> {
  322. let mut buf: Vec<u8> = Vec::new();
  323. buf.extend_from_slice(&u32::to_le_bytes(0));
  324. buf.extend_from_slice(&u32::to_le_bytes(self._unknown));
  325. buf.extend_from_slice(&u32::to_le_bytes(self.chunk));
  326. buf.extend_from_slice(&self.buffer[0..self.len]);
  327. while buf.len() % 4 != 0 {
  328. buf.push(0);
  329. }
  330. let pkt_len = (buf.len() + 4) as u16;
  331. let mut prebuf: Vec<u8> = Vec::new();
  332. prebuf.extend_from_slice(&u16::to_le_bytes(pkt_len));
  333. prebuf.extend_from_slice(&u16::to_le_bytes(0x2DC));
  334. prebuf.append(&mut buf);
  335. prebuf
  336. }
  337. }
  338. impl std::fmt::Debug for GuildcardDataChunk {
  339. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  340. write!(f, "packet GuildcardDataChunk {{\n").unwrap();
  341. write!(f, " flag: {:?}\n", 0).unwrap();
  342. write!(f, " _unknown: {:#X?}\n", self._unknown).unwrap();
  343. write!(f, " chunk: {:#X?}\n", self.chunk).unwrap();
  344. write!(f, " buffer: [0..{:#X}]\n", self.len).unwrap();
  345. write!(f, "}}")
  346. }
  347. }
  348. #[pso_packet(0x4EB)]
  349. pub struct ParamDataRequest {
  350. }
  351. #[derive(Clone)]
  352. pub struct ParamFile {
  353. pub size: u32,
  354. pub checksum: u32,
  355. pub offset: u32,
  356. pub filename: [u8; 0x40],
  357. }
  358. #[derive(Clone)]
  359. pub struct ParamDataHeader {
  360. pub files: Vec<ParamFile>
  361. }
  362. impl PSOPacket for ParamDataHeader {
  363. fn from_bytes(_data: &[u8]) -> Result<ParamDataHeader, PacketParseError> {
  364. unimplemented!();
  365. }
  366. fn as_bytes(&self) -> Vec<u8> {
  367. let mut buf: Vec<u8> = Vec::new();
  368. buf.extend_from_slice(&u32::to_le_bytes(self.files.len() as u32));
  369. for f in &self.files {
  370. buf.extend_from_slice(&u32::to_le_bytes(f.size));
  371. buf.extend_from_slice(&u32::to_le_bytes(f.checksum));
  372. buf.extend_from_slice(&u32::to_le_bytes(f.offset));
  373. buf.extend_from_slice(&f.filename[..]);
  374. }
  375. while buf.len() % 4 != 0 {
  376. buf.push(0);
  377. }
  378. let pkt_len = (buf.len() + 4) as u16;
  379. let mut prebuf: Vec<u8> = Vec::new();
  380. prebuf.extend_from_slice(&u16::to_le_bytes(pkt_len));
  381. prebuf.extend_from_slice(&u16::to_le_bytes(0x1EB));
  382. prebuf.append(&mut buf);
  383. prebuf
  384. }
  385. }
  386. impl std::fmt::Debug for ParamDataHeader {
  387. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  388. write!(f, "packet ParamDataHeader{{\n").unwrap();
  389. write!(f, " files: [..]\n").unwrap();
  390. write!(f, "}}")
  391. }
  392. }
  393. #[pso_packet(0x3EB)]
  394. pub struct ParamDataChunkRequest {
  395. }
  396. #[pso_packet(0x2EB)]
  397. pub struct ParamDataChunk {
  398. pub chunk: u32,
  399. #[nodebug]
  400. pub data: [u8; 0x6800], // TODO: why wont the const work here? (blame macros?)
  401. }
  402. #[pso_packet(0xEC)]
  403. pub struct SetFlag {
  404. pub flags: u32,
  405. }
  406. #[pso_packet(0xB1)]
  407. pub struct Timestamp {
  408. #[utf8]
  409. timestamp: [u8; 28],
  410. }
  411. impl Timestamp {
  412. pub fn new(time: DateTime<Utc>) -> Timestamp {
  413. let timestr = time.format("%Y:%m:%d: %H:%M:%S").to_string();
  414. let timebytes = timestr.as_bytes();
  415. let mut timebuf = [0u8; 28];
  416. timebuf[..timebytes.len()].clone_from_slice(timebytes);
  417. Timestamp {
  418. timestamp: timebuf
  419. }
  420. }
  421. }
  422. #[derive(PSOPacketData, Copy, Clone)]
  423. pub struct ShipListEntry {
  424. pub menu: u32,
  425. pub item: u32,
  426. pub flags: u16,
  427. pub name: [u16; 0x11],
  428. }
  429. #[pso_packet(0xA0)]
  430. pub struct ShipList {
  431. baseship: ShipListEntry,
  432. pub ships: Vec<ShipListEntry>,
  433. }
  434. impl ShipList {
  435. pub fn new(ships: Vec<ShipListEntry>) -> ShipList {
  436. ShipList {
  437. baseship: ShipListEntry {
  438. menu: ships.get(0).map(|s| s.menu).unwrap_or(0),
  439. item: 0,
  440. flags: 0,
  441. name: utf8_to_utf16_array!("Ship", 0x11),
  442. },
  443. ships: ships,
  444. }
  445. }
  446. }
  447. #[pso_packet(0x10)]
  448. pub struct MenuSelect {
  449. pub menu: u32,
  450. pub item: u32,
  451. }
  452. #[cfg(test)]
  453. mod tests {
  454. #[test]
  455. fn test_account_status_enum() {
  456. use super::PSOPacket;
  457. use super::Session;
  458. let pkt = super::LoginResponse {
  459. status: super::AccountStatus::InvalidPassword,
  460. tag: 0,
  461. guildcard: 0,
  462. team_id: 0,
  463. session: Session::new(),
  464. caps: 0,
  465. };
  466. let mut bytes = pkt.as_bytes();
  467. assert!(bytes[8] == 2);
  468. bytes[8] = 8;
  469. let pkt = super::LoginResponse::from_bytes(&bytes).unwrap();
  470. assert!(pkt.status == super::AccountStatus::InvalidUser);
  471. }
  472. #[test]
  473. fn test_key_settings_reply() {
  474. use super::PSOPacket;
  475. use rand::{Rng};
  476. let mut rng = rand::thread_rng();
  477. let mut keyboard_config = [0u8; 0x16C];
  478. let mut gamepad_config = [0u8; 0x38];
  479. rng.fill(&mut keyboard_config[..]);
  480. rng.fill(&mut gamepad_config[..]);
  481. let pkt = super::SendKeyAndTeamSettings::new(keyboard_config, gamepad_config, 123, 456);
  482. let bytes = pkt.as_bytes();
  483. assert!(bytes[2] == 0xe2);
  484. assert!(bytes[8 + 0x114] == keyboard_config[0]);
  485. assert!(bytes[8 + 0x114 + 0x16C] == gamepad_config[0]);
  486. }
  487. #[test]
  488. fn test_login_checksum_ack() {
  489. use super::PSOPacket;
  490. let pkt = super::ChecksumAck::new(1);
  491. assert!(pkt.as_bytes() == [0xC, 0, 0xE8, 0x02, 0,0,0,0, 1,0,0,0]);
  492. }
  493. #[test]
  494. fn test_session_size() {
  495. use super::PSOPacketData;
  496. let session = super::Session::new();
  497. assert!(session.as_bytes().len() == 40);
  498. }
  499. }