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.

566 lines
14 KiB

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. #[pso_packet(0xE5)]
  263. pub struct CharacterPreview {
  264. pub slot: u32,
  265. pub character: SelectScreenCharacter,
  266. }
  267. #[pso_packet(0x3E8)]
  268. pub struct GuildcardDataRequest {
  269. }
  270. #[pso_packet(0x1DC)]
  271. pub struct GuildcardDataHeader {
  272. one: u32,
  273. len: u32,
  274. checksum: u32,
  275. }
  276. impl GuildcardDataHeader {
  277. pub fn new(len: usize, checksum: u32) -> GuildcardDataHeader {
  278. GuildcardDataHeader {
  279. one: 1,
  280. len: len as u32,
  281. checksum: checksum
  282. }
  283. }
  284. }
  285. #[pso_packet(0x3DC)]
  286. pub struct GuildcardDataChunkRequest {
  287. _unknown: u32,
  288. pub chunk: u32,
  289. pub again: u32,
  290. }
  291. pub struct GuildcardDataChunk {
  292. _unknown: u32,
  293. chunk: u32,
  294. pub buffer: [u8; GUILD_CARD_CHUNK_SIZE],
  295. len: usize,
  296. }
  297. impl GuildcardDataChunk {
  298. pub fn new(chunk: u32, buffer: [u8; GUILD_CARD_CHUNK_SIZE], len: usize) -> GuildcardDataChunk {
  299. GuildcardDataChunk {
  300. _unknown: 0,
  301. chunk: chunk as u32,
  302. buffer: buffer,
  303. len: len,
  304. }
  305. }
  306. }
  307. impl PSOPacket for GuildcardDataChunk {
  308. fn from_bytes(_data: &[u8]) -> Result<GuildcardDataChunk, PacketParseError> {
  309. unimplemented!();
  310. }
  311. fn as_bytes(&self) -> Vec<u8> {
  312. let mut buf: Vec<u8> = Vec::new();
  313. buf.extend_from_slice(&u32::to_le_bytes(0));
  314. buf.extend_from_slice(&u32::to_le_bytes(self._unknown));
  315. buf.extend_from_slice(&u32::to_le_bytes(self.chunk));
  316. buf.extend_from_slice(&self.buffer[0..self.len]);
  317. while buf.len() % 4 != 0 {
  318. buf.push(0);
  319. }
  320. let pkt_len = (buf.len() + 4) as u16;
  321. let mut prebuf: Vec<u8> = Vec::new();
  322. prebuf.extend_from_slice(&u16::to_le_bytes(pkt_len));
  323. prebuf.extend_from_slice(&u16::to_le_bytes(0x2DC));
  324. prebuf.append(&mut buf);
  325. prebuf
  326. }
  327. }
  328. impl std::fmt::Debug for GuildcardDataChunk {
  329. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  330. write!(f, "packet GuildcardDataChunk {{\n").unwrap();
  331. write!(f, " flag: {:?}\n", 0).unwrap();
  332. write!(f, " _unknown: {:#X?}\n", self._unknown).unwrap();
  333. write!(f, " chunk: {:#X?}\n", self.chunk).unwrap();
  334. write!(f, " buffer: [0..{:#X}]\n", self.len).unwrap();
  335. write!(f, "}}")
  336. }
  337. }
  338. #[pso_packet(0x4EB)]
  339. pub struct ParamDataRequest {
  340. }
  341. #[derive(Clone)]
  342. pub struct ParamFile {
  343. pub size: u32,
  344. pub checksum: u32,
  345. pub offset: u32,
  346. pub filename: [u8; 0x40],
  347. }
  348. #[derive(Clone)]
  349. pub struct ParamDataHeader {
  350. pub files: Vec<ParamFile>
  351. }
  352. impl PSOPacket for ParamDataHeader {
  353. fn from_bytes(_data: &[u8]) -> Result<ParamDataHeader, PacketParseError> {
  354. unimplemented!();
  355. }
  356. fn as_bytes(&self) -> Vec<u8> {
  357. let mut buf: Vec<u8> = Vec::new();
  358. buf.extend_from_slice(&u32::to_le_bytes(self.files.len() as u32));
  359. for f in &self.files {
  360. buf.extend_from_slice(&u32::to_le_bytes(f.size));
  361. buf.extend_from_slice(&u32::to_le_bytes(f.checksum));
  362. buf.extend_from_slice(&u32::to_le_bytes(f.offset));
  363. buf.extend_from_slice(&f.filename[..]);
  364. }
  365. while buf.len() % 4 != 0 {
  366. buf.push(0);
  367. }
  368. let pkt_len = (buf.len() + 4) as u16;
  369. let mut prebuf: Vec<u8> = Vec::new();
  370. prebuf.extend_from_slice(&u16::to_le_bytes(pkt_len));
  371. prebuf.extend_from_slice(&u16::to_le_bytes(0x1EB));
  372. prebuf.append(&mut buf);
  373. prebuf
  374. }
  375. }
  376. impl std::fmt::Debug for ParamDataHeader {
  377. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  378. write!(f, "packet ParamDataHeader{{\n").unwrap();
  379. write!(f, " files: [..]\n").unwrap();
  380. write!(f, "}}")
  381. }
  382. }
  383. #[pso_packet(0x3EB)]
  384. pub struct ParamDataChunkRequest {
  385. }
  386. #[pso_packet(0x2EB)]
  387. pub struct ParamDataChunk {
  388. pub chunk: u32,
  389. #[nodebug]
  390. pub data: [u8; 0x6800], // TODO: why wont the const work here? (blame macros?)
  391. }
  392. #[pso_packet(0xEC)]
  393. pub struct SetFlag {
  394. pub flags: u32,
  395. }
  396. #[pso_packet(0xB1)]
  397. pub struct Timestamp {
  398. #[utf8]
  399. timestamp: [u8; 28],
  400. }
  401. impl Timestamp {
  402. pub fn new(time: DateTime<Utc>) -> Timestamp {
  403. let timestr = time.format("%Y:%m:%d: %H:%M:%S").to_string();
  404. let timebytes = timestr.as_bytes();
  405. let mut timebuf = [0u8; 28];
  406. timebuf[..timebytes.len()].clone_from_slice(timebytes);
  407. Timestamp {
  408. timestamp: timebuf
  409. }
  410. }
  411. }
  412. #[derive(PSOPacketData, Copy, Clone)]
  413. pub struct ShipListEntry {
  414. pub menu: u32,
  415. pub item: u32,
  416. pub flags: u16,
  417. pub name: [u16; 0x11],
  418. }
  419. #[pso_packet(0xA0)]
  420. pub struct ShipList {
  421. baseship: ShipListEntry,
  422. pub ships: Vec<ShipListEntry>,
  423. }
  424. impl ShipList {
  425. pub fn new(ships: Vec<ShipListEntry>) -> ShipList {
  426. ShipList {
  427. baseship: ShipListEntry {
  428. menu: ships.get(0).map(|s| s.menu).unwrap_or(0),
  429. item: 0,
  430. flags: 0,
  431. name: utf8_to_utf16_array!("Ship", 0x11),
  432. },
  433. ships: ships,
  434. }
  435. }
  436. }
  437. #[pso_packet(0x10)]
  438. pub struct MenuSelect {
  439. pub menu: u32,
  440. pub item: u32,
  441. }
  442. #[cfg(test)]
  443. mod tests {
  444. #[test]
  445. fn test_account_status_enum() {
  446. use super::PSOPacket;
  447. use super::Session;
  448. let pkt = super::LoginResponse {
  449. status: super::AccountStatus::InvalidPassword,
  450. tag: 0,
  451. guildcard: 0,
  452. team_id: 0,
  453. session: Session::new(),
  454. caps: 0,
  455. };
  456. let mut bytes = pkt.as_bytes();
  457. assert!(bytes[8] == 2);
  458. bytes[8] = 8;
  459. let pkt = super::LoginResponse::from_bytes(&bytes).unwrap();
  460. assert!(pkt.status == super::AccountStatus::InvalidUser);
  461. }
  462. #[test]
  463. fn test_key_settings_reply() {
  464. use super::PSOPacket;
  465. use rand::{Rng};
  466. let mut rng = rand::thread_rng();
  467. let mut keyboard_config = [0u8; 0x16C];
  468. let mut gamepad_config = [0u8; 0x38];
  469. rng.fill(&mut keyboard_config[..]);
  470. rng.fill(&mut gamepad_config[..]);
  471. let pkt = super::SendKeyAndTeamSettings::new(keyboard_config, gamepad_config, 123, 456);
  472. let bytes = pkt.as_bytes();
  473. assert!(bytes[2] == 0xe2);
  474. assert!(bytes[8 + 0x114] == keyboard_config[0]);
  475. assert!(bytes[8 + 0x114 + 0x16C] == gamepad_config[0]);
  476. }
  477. #[test]
  478. fn test_login_checksum_ack() {
  479. use super::PSOPacket;
  480. let pkt = super::ChecksumAck::new(1);
  481. assert!(pkt.as_bytes() == [0xC, 0, 0xE8, 0x02, 0,0,0,0, 1,0,0,0]);
  482. }
  483. #[test]
  484. fn test_session_size() {
  485. use super::PSOPacketData;
  486. let session = super::Session::new();
  487. assert!(session.as_bytes().len() == 40);
  488. }
  489. }