implement patch serving
This commit is contained in:
@@ -65,6 +65,7 @@ add_executable(newserv
|
||||
src/Map.cc
|
||||
src/Menu.cc
|
||||
src/NetworkAddresses.cc
|
||||
src/PatchFileIndex.cc
|
||||
src/Player.cc
|
||||
src/ProxyCommands.cc
|
||||
src/ProxyServer.cc
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "CommandFormats.hh"
|
||||
#include "FunctionCompiler.hh"
|
||||
#include "License.hh"
|
||||
#include "PatchFileIndex.hh"
|
||||
#include "Player.hh"
|
||||
#include "PSOEncryption.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
@@ -74,6 +75,9 @@ struct Client {
|
||||
uint32_t proxy_destination_address;
|
||||
uint16_t proxy_destination_port;
|
||||
|
||||
// Patch server
|
||||
std::vector<PatchFileChecksumRequest> patch_file_checksum_requests;
|
||||
|
||||
// Lobby/positioning
|
||||
float x;
|
||||
float z;
|
||||
|
||||
@@ -88,8 +88,8 @@ struct ClientConfigBB {
|
||||
|
||||
// Patch server commands
|
||||
|
||||
// The patch protocol is nearly identical between PSO PC and PSO BB (the only
|
||||
// versions on which it is used). Only the client's 04 command differs.
|
||||
// The patch protocol is identical between PSO PC and PSO BB (the only versions
|
||||
// on which it is used).
|
||||
|
||||
// A patch server session generally goes like this:
|
||||
// Server: 02 (unencrypted)
|
||||
@@ -157,12 +157,14 @@ struct S_ServerInit_Patch_02 {
|
||||
// Client will respond with an 04 command.
|
||||
|
||||
// 04 (C->S): Log in (patch)
|
||||
// The email field is always blank on BB. It may be blank on PC too, so this
|
||||
// cannot be used to determine the game version used by a patch client.
|
||||
|
||||
struct C_Login_Patch_04 {
|
||||
parray<le_uint32_t, 3> unused;
|
||||
ptext<char, 0x10> username;
|
||||
ptext<char, 0x10> password;
|
||||
ptext<char, 0x40> email; // Note: this field is blank on BB
|
||||
ptext<char, 0x40> email;
|
||||
};
|
||||
|
||||
// 05 (S->C): Unknown
|
||||
|
||||
@@ -16,6 +16,7 @@ PrefixedLogger function_compiler_log ("[FunctionCompiler] ", LogLevel::USE_DEFAU
|
||||
PrefixedLogger ip_stack_simulator_log("[IPStackSimulator] ", LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger license_log ("[LicenseManager] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger lobby_log ("" , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger patch_index_log ("[PatchFileIndex] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger player_data_log ("" , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger proxy_server_log ("[ProxyServer] " , LogLevel::USE_DEFAULT);
|
||||
PrefixedLogger replay_log ("[ReplaySession] " , LogLevel::USE_DEFAULT);
|
||||
@@ -51,6 +52,7 @@ void set_log_levels_from_json(shared_ptr<JSONObject> json) {
|
||||
set_log_level_from_json(ip_stack_simulator_log, json, "IPStackSimulator");
|
||||
set_log_level_from_json(license_log , json, "LicenseManager");
|
||||
set_log_level_from_json(lobby_log , json, "Lobbies");
|
||||
set_log_level_from_json(patch_index_log , json, "PatchFileIndex");
|
||||
set_log_level_from_json(player_data_log , json, "PlayerData");
|
||||
set_log_level_from_json(proxy_server_log , json, "ProxyServer");
|
||||
set_log_level_from_json(replay_log , json, "Replay");
|
||||
|
||||
@@ -15,6 +15,7 @@ extern PrefixedLogger function_compiler_log;
|
||||
extern PrefixedLogger ip_stack_simulator_log;
|
||||
extern PrefixedLogger license_log;
|
||||
extern PrefixedLogger lobby_log;
|
||||
extern PrefixedLogger patch_index_log;
|
||||
extern PrefixedLogger player_data_log;
|
||||
extern PrefixedLogger proxy_server_log;
|
||||
extern PrefixedLogger replay_log;
|
||||
|
||||
+13
@@ -496,6 +496,19 @@ int main(int argc, char** argv) {
|
||||
state->dol_file_index.reset(new DOLFileIndex());
|
||||
}
|
||||
|
||||
if (isdir("system/patch-pc")) {
|
||||
config_log.info("Indexing PSO PC patch files");
|
||||
state->pc_patch_file_index.reset(new PatchFileIndex("system/patch-pc"));
|
||||
} else {
|
||||
config_log.info("PSO PC patch files not present");
|
||||
}
|
||||
if (isdir("system/patch-bb")) {
|
||||
config_log.info("Indexing PSO BB patch files");
|
||||
state->bb_patch_file_index.reset(new PatchFileIndex("system/patch-bb"));
|
||||
} else {
|
||||
config_log.info("PSO BB patch files not present");
|
||||
}
|
||||
|
||||
config_log.info("Creating menus");
|
||||
state->create_menus(config_json);
|
||||
|
||||
|
||||
+107
-18
@@ -83,8 +83,10 @@ void process_connect(std::shared_ptr<ServerState> s, std::shared_ptr<Client> c)
|
||||
}
|
||||
break;
|
||||
|
||||
case ServerBehavior::PATCH_SERVER_BB:
|
||||
c->flags |= Client::Flag::BB_PATCH;
|
||||
case ServerBehavior::PATCH_SERVER_PC:
|
||||
case ServerBehavior::DATA_SERVER_BB:
|
||||
case ServerBehavior::PATCH_SERVER:
|
||||
case ServerBehavior::LOBBY_SERVER:
|
||||
send_server_init(s, c, false, false);
|
||||
break;
|
||||
@@ -2349,13 +2351,40 @@ void process_encryption_ok_patch(shared_ptr<ServerState>, shared_ptr<Client> c,
|
||||
send_command(c, 0x04, 0x00); // This requests the user's login information
|
||||
}
|
||||
|
||||
static void change_to_directory_patch(
|
||||
shared_ptr<Client> c,
|
||||
vector<string>& client_path_directories,
|
||||
const vector<string>& file_path_directories) {
|
||||
// First, exit all leaf directories that don't match the desired path
|
||||
while (!client_path_directories.empty() &&
|
||||
((client_path_directories.size() > file_path_directories.size()) ||
|
||||
(client_path_directories.back() != file_path_directories[client_path_directories.size() - 1]))) {
|
||||
send_command(c, 0x0A, 0x00);
|
||||
client_path_directories.pop_back();
|
||||
}
|
||||
|
||||
// At this point, client_path_directories should be a prefix of
|
||||
// file_path_directories (or should match exactly)
|
||||
if (client_path_directories.size() > file_path_directories.size()) {
|
||||
throw logic_error("did not exit all necessary directories");
|
||||
}
|
||||
for (size_t x = 0; x < client_path_directories.size(); x++) {
|
||||
if (client_path_directories[x] != file_path_directories[x]) {
|
||||
throw logic_error("intermediate path is not a prefix of final path");
|
||||
}
|
||||
}
|
||||
|
||||
// Second, enter all necessary leaf directories
|
||||
while (client_path_directories.size() < file_path_directories.size()) {
|
||||
const string& dir = file_path_directories[client_path_directories.size()];
|
||||
send_enter_directory_patch(c, dir);
|
||||
client_path_directories.emplace_back(dir);
|
||||
}
|
||||
}
|
||||
|
||||
void process_login_patch(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
uint16_t, uint32_t, const string& data) {
|
||||
const auto& cmd = check_size_t<C_Login_Patch_04>(data);
|
||||
|
||||
if (cmd.email.len() == 0) {
|
||||
c->flags |= Client::Flag::BB_PATCH;
|
||||
}
|
||||
check_size_v(data.size(), sizeof(C_Login_Patch_04));
|
||||
|
||||
// On BB we can use colors and newlines should be \n; on PC we can't use
|
||||
// colors, the text is auto-word-wrapped, and newlines should be \r\n.
|
||||
@@ -2365,16 +2394,72 @@ void process_login_patch(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
||||
send_message_box(c, message.c_str());
|
||||
}
|
||||
|
||||
// TODO: Implement patch serving for realz.
|
||||
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);
|
||||
auto index = (c->flags & Client::Flag::BB_PATCH) ?
|
||||
s->bb_patch_file_index : s->pc_patch_file_index;
|
||||
if (index.get()) {
|
||||
send_command(c, 0x0B, 0x00); // Start patch session; go to root directory
|
||||
|
||||
vector<string> path_directories;
|
||||
for (const auto& file : index->files) {
|
||||
change_to_directory_patch(c, path_directories, file->path_directories);
|
||||
|
||||
S_FileChecksumRequest_Patch_0C req = {
|
||||
c->patch_file_checksum_requests.size(), file->name};
|
||||
send_command_t(c, 0x0C, 0x00, req);
|
||||
c->patch_file_checksum_requests.emplace_back(file);
|
||||
}
|
||||
change_to_directory_patch(c, path_directories, {});
|
||||
|
||||
send_command(c, 0x0D, 0x00); // End of checksum requests
|
||||
|
||||
} else {
|
||||
// No patch index present: just do something that will satisfy the client
|
||||
// without actually checking or downloading any files
|
||||
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);
|
||||
send_command(c, 0x12, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
void process_file_checksum_result_patch(shared_ptr<ServerState>,
|
||||
shared_ptr<Client> c, uint16_t, uint32_t, const string& data) { // 0F
|
||||
auto& cmd = check_size_t<C_FileInformation_Patch_0F>(data);
|
||||
auto& req = c->patch_file_checksum_requests.at(cmd.request_id);
|
||||
req.crc32 = cmd.checksum;
|
||||
req.size = cmd.size;
|
||||
req.response_received = true;
|
||||
}
|
||||
|
||||
void process_file_checksum_results_done_patch(shared_ptr<ServerState>,
|
||||
shared_ptr<Client> c, uint16_t, uint32_t, const string&) { // 10
|
||||
|
||||
S_StartFileDownloads_Patch_11 start_cmd = {0, 0};
|
||||
for (const auto& req : c->patch_file_checksum_requests) {
|
||||
if (!req.response_received) {
|
||||
throw runtime_error("client did not respond to checksum request");
|
||||
}
|
||||
if (req.needs_update()) {
|
||||
start_cmd.total_bytes += req.file->size;
|
||||
start_cmd.num_files++;
|
||||
}
|
||||
}
|
||||
|
||||
if (start_cmd.num_files) {
|
||||
send_command_t(c, 0x11, 0x00, start_cmd);
|
||||
vector<string> path_directories;
|
||||
for (const auto& req : c->patch_file_checksum_requests) {
|
||||
if (req.needs_update()) {
|
||||
change_to_directory_patch(c, path_directories, req.file->path_directories);
|
||||
send_patch_file(c, req.file);
|
||||
}
|
||||
}
|
||||
change_to_directory_patch(c, path_directories, {});
|
||||
}
|
||||
|
||||
// This command terminates the patch connection successfully. PSOBB complains
|
||||
// if we don't check the above directories before sending this though
|
||||
send_command(c, 0x12, 0x00);
|
||||
}
|
||||
|
||||
@@ -2832,11 +2917,15 @@ static process_command_t patch_handlers[0x100] = {
|
||||
// 00
|
||||
nullptr, nullptr, process_encryption_ok_patch, nullptr,
|
||||
process_login_patch, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, process_file_checksum_result_patch,
|
||||
|
||||
// 10
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
process_file_checksum_results_done_patch, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
|
||||
// 20
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
|
||||
@@ -445,6 +445,28 @@ void send_enter_directory_patch(shared_ptr<Client> c, const string& dir) {
|
||||
send_command_t(c, 0x09, 0x00, cmd);
|
||||
}
|
||||
|
||||
void send_patch_file(shared_ptr<Client> c, shared_ptr<const PatchFileIndex::File> f) {
|
||||
S_OpenFile_Patch_06 open_cmd = {0, f->size, f->name};
|
||||
send_command_t(c, 0x06, 0x00, open_cmd);
|
||||
|
||||
for (size_t x = 0; x < f->chunks.size(); x++) {
|
||||
const auto& chunk = f->chunks[x];
|
||||
|
||||
// TODO: The use of StringWriter here is... unfortunate. Write a version of
|
||||
// Channel::send that takes iovecs or something to avoid these dumb massive
|
||||
// string copies.
|
||||
StringWriter w;
|
||||
S_WriteFileHeader_Patch_07 write_cmd_header = {
|
||||
x, chunk.crc32, chunk.data.size()};
|
||||
w.put(write_cmd_header);
|
||||
w.write(chunk.data);
|
||||
send_command(c, 0x07, 0x00, w.str());
|
||||
}
|
||||
|
||||
S_CloseCurrentFile_Patch_08 close_cmd = {0};
|
||||
send_command_t(c, 0x08, 0x00, close_cmd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -129,6 +129,7 @@ void send_approve_player_choice_bb(std::shared_ptr<Client> c);
|
||||
void send_complete_player_bb(std::shared_ptr<Client> c);
|
||||
|
||||
void send_enter_directory_patch(std::shared_ptr<Client> c, const std::string& dir);
|
||||
void send_patch_file(std::shared_ptr<Client> c, std::shared_ptr<const PatchFileIndex::File> f);
|
||||
|
||||
void send_message_box(std::shared_ptr<Client> c, const std::u16string& text);
|
||||
void send_lobby_name(std::shared_ptr<Client> c, const std::u16string& text);
|
||||
|
||||
@@ -51,6 +51,8 @@ struct ServerState {
|
||||
RunShellBehavior run_shell_behavior;
|
||||
std::vector<std::shared_ptr<const PSOBBEncryption::KeyFile>> bb_private_keys;
|
||||
std::shared_ptr<const FunctionCodeIndex> function_code_index;
|
||||
std::shared_ptr<const PatchFileIndex> pc_patch_file_index;
|
||||
std::shared_ptr<const PatchFileIndex> bb_patch_file_index;
|
||||
std::shared_ptr<const DOLFileIndex> dol_file_index;
|
||||
std::shared_ptr<const Ep3DataIndex> ep3_data_index;
|
||||
std::shared_ptr<const QuestIndex> quest_index;
|
||||
|
||||
+9
-5
@@ -113,8 +113,10 @@ const char* name_for_server_behavior(ServerBehavior behavior) {
|
||||
return "lobby_server";
|
||||
case ServerBehavior::DATA_SERVER_BB:
|
||||
return "data_server_bb";
|
||||
case ServerBehavior::PATCH_SERVER:
|
||||
return "patch_server";
|
||||
case ServerBehavior::PATCH_SERVER_PC:
|
||||
return "patch_server_pc";
|
||||
case ServerBehavior::PATCH_SERVER_BB:
|
||||
return "patch_server_bb";
|
||||
case ServerBehavior::PROXY_SERVER:
|
||||
return "proxy_server";
|
||||
default:
|
||||
@@ -131,11 +133,13 @@ ServerBehavior server_behavior_for_name(const char* name) {
|
||||
return ServerBehavior::LOBBY_SERVER;
|
||||
} else if (!strcasecmp(name, "data_server_bb") || !strcasecmp(name, "data_server") || !strcasecmp(name, "data")) {
|
||||
return ServerBehavior::DATA_SERVER_BB;
|
||||
} else if (!strcasecmp(name, "patch_server") || !strcasecmp(name, "patch")) {
|
||||
return ServerBehavior::PATCH_SERVER;
|
||||
} else if (!strcasecmp(name, "patch_server_pc") || !strcasecmp(name, "patch_pc")) {
|
||||
return ServerBehavior::PATCH_SERVER_PC;
|
||||
} else if (!strcasecmp(name, "patch_server_bb") || !strcasecmp(name, "patch_bb")) {
|
||||
return ServerBehavior::PATCH_SERVER_BB;
|
||||
} else if (!strcasecmp(name, "proxy_server") || !strcasecmp(name, "proxy")) {
|
||||
return ServerBehavior::PROXY_SERVER;
|
||||
} else {
|
||||
throw invalid_argument("incorrect server behavior name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -18,7 +18,8 @@ enum class ServerBehavior {
|
||||
LOGIN_SERVER,
|
||||
LOBBY_SERVER,
|
||||
DATA_SERVER_BB,
|
||||
PATCH_SERVER,
|
||||
PATCH_SERVER_PC,
|
||||
PATCH_SERVER_BB,
|
||||
PROXY_SERVER,
|
||||
};
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
"gc-eu11": [9201, "gc", "login_server"],
|
||||
"gc-eu3": [9203, "gc", "login_server"],
|
||||
"pc-login": [9300, "pc", "login_server"],
|
||||
"pc-patch": [10000, "patch", "patch_server"],
|
||||
"bb-patch": [11000, "patch", "patch_server"],
|
||||
"pc-patch": [10000, "patch", "patch_server_pc"],
|
||||
"bb-patch": [11000, "patch", "patch_server_bb"],
|
||||
"bb-init": [12000, "bb", "data_server_bb"],
|
||||
|
||||
// TODO: If Xbox support ever gets built, add this port to the above config.
|
||||
@@ -132,6 +132,9 @@
|
||||
// Lobby messages describe creation and deletion of lobbies and games, as
|
||||
// well as item tracking events within games.
|
||||
"Lobbies": "info",
|
||||
// Patch file index messages describe finding and preloading the patch files
|
||||
// available for download to BB and PC clients.
|
||||
"PatchFileIndex": "info",
|
||||
// Player data messages describe the loading and saving of player and
|
||||
// account data files.
|
||||
"PlayerData": "info",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
0x09 0x0009 # TAB
|
||||
0x0A 0x000A # NEWLINE
|
||||
0x0D 0x000D # CARRIAGE RETURN
|
||||
0x20 0x0020 # SPACE
|
||||
0x21 0x0021 # EXCLAMATION MARK
|
||||
0x22 0x0022 # QUOTATION MARK
|
||||
|
||||
+23
-23
@@ -18,29 +18,29 @@ I 80820 2022-07-07 23:33:27 - [Commands] Received from C-1 (version=Patch comman
|
||||
0000000000000050 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
|
||||
0000000000000060 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
|
||||
I 80820 2022-07-07 23:33:27 - [Commands] Sending to C-1 (version=Patch command=13 flag=00)
|
||||
0000000000000000 | 70 01 13 00 09 00 43 00 37 00 6E 00 65 00 77 00 | p C 7 n e w
|
||||
0000000000000010 | 73 00 65 00 72 00 76 00 20 00 70 00 61 00 74 00 | s e r v p a t
|
||||
0000000000000020 | 63 00 68 00 20 00 73 00 65 00 72 00 76 00 65 00 | c h s e r v e
|
||||
0000000000000030 | 72 00 0A 00 0A 00 54 00 68 00 69 00 73 00 20 00 | r T h i s
|
||||
0000000000000040 | 73 00 65 00 72 00 76 00 65 00 72 00 20 00 69 00 | s e r v e r i
|
||||
0000000000000050 | 73 00 20 00 6E 00 6F 00 74 00 20 00 61 00 66 00 | s n o t a f
|
||||
0000000000000060 | 66 00 69 00 6C 00 69 00 61 00 74 00 65 00 64 00 | f i l i a t e d
|
||||
0000000000000070 | 20 00 77 00 69 00 74 00 68 00 2C 00 20 00 73 00 | w i t h , s
|
||||
0000000000000080 | 70 00 6F 00 6E 00 73 00 6F 00 72 00 65 00 64 00 | p o n s o r e d
|
||||
0000000000000090 | 20 00 62 00 79 00 2C 00 20 00 6F 00 72 00 20 00 | b y , o r
|
||||
00000000000000A0 | 69 00 6E 00 20 00 61 00 6E 00 79 00 0A 00 6F 00 | i n a n y o
|
||||
00000000000000B0 | 74 00 68 00 65 00 72 00 20 00 77 00 61 00 79 00 | t h e r w a y
|
||||
00000000000000C0 | 20 00 63 00 6F 00 6E 00 6E 00 65 00 63 00 74 00 | c o n n e c t
|
||||
00000000000000D0 | 65 00 64 00 20 00 74 00 6F 00 20 00 53 00 45 00 | e d t o S E
|
||||
00000000000000E0 | 47 00 41 00 20 00 6F 00 72 00 20 00 53 00 6F 00 | G A o r S o
|
||||
00000000000000F0 | 6E 00 69 00 63 00 20 00 54 00 65 00 61 00 6D 00 | n i c T e a m
|
||||
0000000000000100 | 2C 00 20 00 61 00 6E 00 64 00 20 00 69 00 73 00 | , a n d i s
|
||||
0000000000000110 | 20 00 6F 00 77 00 6E 00 65 00 64 00 0A 00 61 00 | o w n e d a
|
||||
0000000000000120 | 6E 00 64 00 20 00 6F 00 70 00 65 00 72 00 61 00 | n d o p e r a
|
||||
0000000000000130 | 74 00 65 00 64 00 20 00 63 00 6F 00 6D 00 70 00 | t e d c o m p
|
||||
0000000000000140 | 6C 00 65 00 74 00 65 00 6C 00 79 00 20 00 69 00 | l e t e l y i
|
||||
0000000000000150 | 6E 00 64 00 65 00 70 00 65 00 6E 00 64 00 65 00 | n d e p e n d e
|
||||
0000000000000160 | 6E 00 74 00 6C 00 79 00 2E 00 00 00 00 00 00 00 | n t l y .
|
||||
0000000000000000 | 6C 01 13 00 6E 00 65 00 77 00 73 00 65 00 72 00 | l n e w s e r
|
||||
0000000000000010 | 76 00 20 00 70 00 61 00 74 00 63 00 68 00 20 00 | v p a t c h
|
||||
0000000000000020 | 73 00 65 00 72 00 76 00 65 00 72 00 0D 00 0A 00 | s e r v e r
|
||||
0000000000000030 | 0D 00 0A 00 54 00 68 00 69 00 73 00 20 00 73 00 | T h i s s
|
||||
0000000000000040 | 65 00 72 00 76 00 65 00 72 00 20 00 69 00 73 00 | e r v e r i s
|
||||
0000000000000050 | 20 00 6E 00 6F 00 74 00 20 00 61 00 66 00 66 00 | n o t a f f
|
||||
0000000000000060 | 69 00 6C 00 69 00 61 00 74 00 65 00 64 00 20 00 | i l i a t e d
|
||||
0000000000000070 | 77 00 69 00 74 00 68 00 2C 00 20 00 73 00 70 00 | w i t h , s p
|
||||
0000000000000080 | 6F 00 6E 00 73 00 6F 00 72 00 65 00 64 00 20 00 | o n s o r e d
|
||||
0000000000000090 | 62 00 79 00 2C 00 20 00 6F 00 72 00 20 00 69 00 | b y , o r i
|
||||
00000000000000A0 | 6E 00 20 00 61 00 6E 00 79 00 20 00 6F 00 74 00 | n a n y o t
|
||||
00000000000000B0 | 68 00 65 00 72 00 20 00 77 00 61 00 79 00 20 00 | h e r w a y
|
||||
00000000000000C0 | 63 00 6F 00 6E 00 6E 00 65 00 63 00 74 00 65 00 | c o n n e c t e
|
||||
00000000000000D0 | 64 00 20 00 74 00 6F 00 20 00 53 00 45 00 47 00 | d t o S E G
|
||||
00000000000000E0 | 41 00 20 00 6F 00 72 00 20 00 53 00 6F 00 6E 00 | A o r S o n
|
||||
00000000000000F0 | 69 00 63 00 20 00 54 00 65 00 61 00 6D 00 2C 00 | i c T e a m ,
|
||||
0000000000000100 | 20 00 61 00 6E 00 64 00 20 00 69 00 73 00 20 00 | a n d i s
|
||||
0000000000000110 | 6F 00 77 00 6E 00 65 00 64 00 20 00 61 00 6E 00 | o w n e d a n
|
||||
0000000000000120 | 64 00 20 00 6F 00 70 00 65 00 72 00 61 00 74 00 | d o p e r a t
|
||||
0000000000000130 | 65 00 64 00 20 00 63 00 6F 00 6D 00 70 00 6C 00 | e d c o m p l
|
||||
0000000000000140 | 65 00 74 00 65 00 6C 00 79 00 20 00 69 00 6E 00 | e t e l y i n
|
||||
0000000000000150 | 64 00 65 00 70 00 65 00 6E 00 64 00 65 00 6E 00 | d e p e n d e n
|
||||
0000000000000160 | 74 00 6C 00 79 00 2E 00 00 00 00 00 | t l y .
|
||||
I 80820 2022-07-07 23:33:27 - [Commands] Sending to C-1 (version=Patch command=09 flag=00)
|
||||
0000000000000000 | 44 00 09 00 2E 00 00 00 00 00 00 00 00 00 00 00 | D .
|
||||
0000000000000010 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
|
||||
|
||||
+3
-3
@@ -26,10 +26,10 @@
|
||||
"gc-eu11": [9201, "gc", "login_server"],
|
||||
"gc-eu3": [9203, "gc", "login_server"],
|
||||
"pc-login": [9300, "pc", "login_server"],
|
||||
"pc-patch": [10000, "patch", "patch_server"],
|
||||
"bb-patch": [11000, "patch", "patch_server"],
|
||||
"pc-patch": [10000, "patch", "patch_server_pc"],
|
||||
"bb-patch": [11000, "patch", "patch_server_bb"],
|
||||
"bb-init": [12000, "bb", "data_server_bb"],
|
||||
"bb-patch2": [10500, "patch", "patch_server"],
|
||||
"bb-patch2": [10500, "patch", "patch_server_bb"],
|
||||
"bb-init2": [13000, "bb", "data_server_bb"],
|
||||
"bb-proxy2": [9932, "bb", "proxy_server"],
|
||||
"bb-data1": [12004, "bb", "data_server_bb"],
|
||||
|
||||
Reference in New Issue
Block a user