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.

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