From 1e3dd6a274c38ef6f78e93dc590c4b2c57ed2228 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sun, 8 May 2022 00:04:39 -0700 Subject: [PATCH] document patch server commands --- src/CommandFormats.hh | 171 ++++++++++++++++++++++++++++++++++------- src/ReceiveCommands.cc | 6 +- src/SendCommands.cc | 8 +- src/SendCommands.hh | 2 +- 4 files changed, 153 insertions(+), 34 deletions(-) diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index 48acf202..b6f1234e 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -77,6 +77,150 @@ struct ClientConfigBB { +// Patch server commands + +// A patch server session generally goes like this: +// Server: 02 +// Client: 02 +// Server: 04 +// Client: 04 +// Server: 13 (if desired) +// Server: 0B +// Server: 09 (with directory name ".") +// For each directory to be checked: +// Server: 09 +// Server: (commands to check subdirectories - more 09/0A/0C) +// For each file in the directory: +// Server: 0C +// Server: 0A +// Server: 0D +// For each 0C sent by the server earlier: +// Client: 0F +// Client: 10 +// If there are any files to be updated: +// Server: 11 +// For each directory containing files to be updated: +// Server: 09 +// Server: (commands to update subdirectories) +// For each file to be updated in this directory: +// Server: 06 +// Server: 07 (possibly multiple 07s if the file is large) +// Server: 08 +// Server: 0A +// Server: 12 + +// 02 (S->C): Start encryption + +struct S_ServerInit_Patch_02 { + ptext copyright; + le_uint32_t server_key; + le_uint32_t client_key; + // BB rejects the command if it's larger than this size, so we can't add the + // after_message like we do in the other server init commands +}; + +// 04 (S->C): Request login information (no arguments); max. size 4 +// 04 (C->S): Log in (patch) + +struct C_Login_Patch_04 { + parray unused; + ptext username; + ptext password; + ptext email; // Note: this field is blank on BB +}; + +// 05 (S->C): Unknown +// No arguments + +// 06 (S->C): Open file for writing + +struct S_OpenFile_Patch_06 { + le_uint32_t unknown; // Seems to always be zero + le_uint32_t size; + ptext filename; +}; + +// 07 (S->C): Write file +// The client's handler table says this command's maximum size is 0x6010 +// including the header, but the only servers I've seen use this command limit +// chunks to 0x4010 (including the header). + +struct S_WriteFileHeader_Patch_07 { + le_uint32_t chunk_index; + le_uint32_t chunk_checksum; // crc32 + le_uint32_t chunk_size; + // The chunk data immediately follows here +}; + +// 08 (S->C): Close current file +// Maximum size 8 (including header) + +struct S_CloseCurrentFile_Patch_08 { + le_uint32_t unknown; // Seems to always be zero +}; + +// 09 (S->C): Enter directory + +struct S_EnterDirectory_Patch_09 { + ptext name; +}; + +// 0A (S->C): Exit directory +// No arguments + +// 0B (S->C): Unknown; possibly start patch session +// No arguments + +// 0C (S->C): File checksum request + +struct S_FileChecksumRequest_Patch_0C { + le_uint32_t request_id; + ptext filename; +}; + +// 0D (S->C): End of file check requests +// No arguments + +// 0F (C->S): File information + +struct C_FileInformation_Patch_0F { + le_uint32_t request_id; + le_uint32_t checksum; + le_uint32_t size; +}; + +// 10 (C->S): End of file information command list +// No arguments + +// 11 (S->C): Start file downloads + +struct S_Unknown_Patch_11 { + le_uint32_t total_bytes; + le_uint32_t num_files; +}; + +// 12 (S->C): End patch session successfully +// No arguments + +// 13 (S->C): Message box +// Same as 1A/D5 on the game server. On PSOBB, the message appears in the upper +// message box and functions like a normal PSO message box. On PSOPC, the +// message appears in a Windows edit field, so line breaks must be \r\n (as +// opposed to just \n on PSOBB) and standard PSO color escapes don't work. +// THe maximum size of this command is 0x2004 bytes, including the header. + +// 14 (S->C): Reconnect +// Same as 19 on the game server. + +// 15 (S->C): Unknown +// No arguments + +// No commands beyond 15 are valid on the patch server. + + + +// Game server commands + // 00: Invalid command // 01 (S->C): Lobby message box @@ -100,14 +244,6 @@ struct S_ServerInit_DC_PC_GC_02_17 { ptext after_message; }; -struct S_ServerInit_Patch_02 { - ptext copyright; - le_uint32_t server_key; - le_uint32_t client_key; - // BB rejects the command if it's not exactly this size, so we can't add the - // after_message like we do in the other server init commands -}; - // 03 (S->C): Start encryption (BB) // Client will respond with a 93 command. @@ -140,16 +276,6 @@ struct S_UpdateClientConfig_DC_PC_GC_04 { ClientConfig cfg; }; -// 04 (S->C): Request login information (patch server) (no arguments) -// 04 (C->S): Log in (patch server) - -struct C_Login_Patch_04 { - parray unused; - ptext username; - ptext password; - ptext email; // Note: this field is blank on BB -}; - // 05: Disconnect // No arguments @@ -203,12 +329,6 @@ struct S_GameMenuEntry { struct S_GameMenuEntry_PC_BB_08 : S_GameMenuEntry { }; struct S_GameMenuEntry_GC_08 : S_GameMenuEntry { }; -// 09 (S->C): Check directory (patch server) - -struct S_CheckDirectory_Patch_09 { - ptext name; -}; - // 09 (C->S): Menu item info request // Server will respond with an 11 command, or an A3 if it's the quest menu. @@ -217,9 +337,6 @@ struct C_MenuItemInfoRequest_09 { le_uint32_t item_id; }; -// 0A: Done checking directory (patch server) -// No arguemnts - // 0B: Invalid command // 0C: Create game (DCv1) diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 9f871a07..535a3401 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -1744,9 +1744,9 @@ independently.\r\n\ } send_message_box(c, message.c_str()); - send_check_directory_patch(c, "."); - send_check_directory_patch(c, "data"); - send_check_directory_patch(c, "scene"); + send_enter_directory_patch(c, "."); + send_enter_directory_patch(c, "data"); + send_enter_directory_patch(c, "scene"); send_command(c, 0x0A, 0x00); send_command(c, 0x0A, 0x00); send_command(c, 0x0A, 0x00); diff --git a/src/SendCommands.cc b/src/SendCommands.cc index a340fbe1..4fa4ad47 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -267,7 +267,9 @@ void send_update_client_config(shared_ptr c) { void send_reconnect(shared_ptr c, uint32_t address, uint16_t port) { S_Reconnect_19 cmd = {address, port, 0}; - send_command_t(c, 0x19, 0x00, cmd); + // On the patch server, 14 is the reconnect command, but it works exactly the + // same way as 19 on the game server. + send_command_t(c, (c->version == GameVersion::PATCH) ? 0x14 : 0x19, 0x00, cmd); } // Sends the command (first used by Schthack) that separates PC and GC users @@ -426,8 +428,8 @@ void send_complete_player_bb(shared_ptr c) { //////////////////////////////////////////////////////////////////////////////// // patch functions -void send_check_directory_patch(shared_ptr c, const string& dir) { - S_CheckDirectory_Patch_09 cmd = {dir}; +void send_enter_directory_patch(shared_ptr c, const string& dir) { + S_EnterDirectory_Patch_09 cmd = {dir}; send_command_t(c, 0x09, 0x00, cmd); } diff --git a/src/SendCommands.hh b/src/SendCommands.hh index 85862fa3..27300902 100644 --- a/src/SendCommands.hh +++ b/src/SendCommands.hh @@ -114,7 +114,7 @@ void send_stream_file_chunk_bb(std::shared_ptr c, uint32_t chunk_index); void send_approve_player_choice_bb(std::shared_ptr c); void send_complete_player_bb(std::shared_ptr c); -void send_check_directory_patch(std::shared_ptr c, const std::string& dir); +void send_enter_directory_patch(std::shared_ptr c, const std::string& dir); void send_message_box(std::shared_ptr c, const std::u16string& text); void send_lobby_name(std::shared_ptr c, const std::u16string& text);