From 28cb1c52b5d06a87ac62a3a4f229527577b8ea7e Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sat, 24 Feb 2024 22:49:37 -0800 Subject: [PATCH] support full DC NTE credentials --- src/EventUtils.cc | 23 +++++++++++ src/EventUtils.hh | 3 ++ src/License.cc | 42 ++++++++++++++++++-- src/License.hh | 6 ++- src/ReceiveCommands.cc | 16 ++++---- src/ServerShell.cc | 12 +++++- src/ServerState.hh | 4 ++ tests/DCNTE-GameSmokeTest.test.txt | 62 +++++++++++++++--------------- 8 files changed, 123 insertions(+), 45 deletions(-) diff --git a/src/EventUtils.cc b/src/EventUtils.cc index 629cc423..c6e8444f 100644 --- a/src/EventUtils.cc +++ b/src/EventUtils.cc @@ -18,3 +18,26 @@ void forward_to_event_thread(std::shared_ptr base, std::funct std::function* new_fn = new std::function(std::move(fn)); event_base_once(base.get(), -1, EV_TIMEOUT, dispatch_forward_to_event_thread, new_fn, &tv); } + +template <> +void call_on_event_thread(std::shared_ptr base, std::function&& compute) { + bool succeeded = false; + std::string exc_what; + std::mutex ret_lock; + std::condition_variable ret_cv; + std::unique_lock g(ret_lock); + forward_to_event_thread(base, [&]() -> void { + std::lock_guard g(ret_lock); + try { + compute(); + succeeded = true; + } catch (const std::exception& e) { + exc_what = e.what(); + } + ret_cv.notify_one(); + }); + ret_cv.wait(g); + if (!succeeded) { + throw std::runtime_error(exc_what); + } +} diff --git a/src/EventUtils.hh b/src/EventUtils.hh index 6cef85d5..c2803ee1 100644 --- a/src/EventUtils.hh +++ b/src/EventUtils.hh @@ -33,3 +33,6 @@ T call_on_event_thread(std::shared_ptr base, std::function +void call_on_event_thread(std::shared_ptr base, std::function&& compute); diff --git a/src/License.cc b/src/License.cc index 94bd20a0..01bf0f77 100644 --- a/src/License.cc +++ b/src/License.cc @@ -19,6 +19,8 @@ License::License(const JSON& json) bb_team_id(0) { this->serial_number = json.get_int("SerialNumber"); this->access_key = json.get_string("AccessKey", ""); + this->dc_nte_serial_number = json.get_string("DCNTESerialNumber", ""); + this->dc_nte_access_key = json.get_string("DCNTEAccessKey", ""); this->gc_password = json.get_string("GCPassword", ""); this->xb_gamertag = json.get_string("XBGamerTag", ""); this->xb_user_id = json.get_int("XBUserID", 0); @@ -38,6 +40,8 @@ JSON License::json() const { return JSON::dict({ {"SerialNumber", this->serial_number}, {"AccessKey", this->access_key}, + {"DCNTESerialNumber", this->dc_nte_serial_number}, + {"DCNTEAccessKey", this->dc_nte_access_key}, {"GCPassword", this->gc_password}, {"XBGamerTag", this->xb_gamertag}, {"XBUserID", this->xb_user_id}, @@ -63,6 +67,12 @@ string License::str() const { if (!this->access_key.empty()) { tokens.emplace_back("access_key=" + this->access_key); } + if (!this->dc_nte_serial_number.empty()) { + tokens.emplace_back("dc_nte_serial_number=" + this->dc_nte_serial_number); + } + if (!this->dc_nte_access_key.empty()) { + tokens.emplace_back("dc_nte_access_key=" + this->dc_nte_access_key); + } if (!this->gc_password.empty()) { tokens.emplace_back("gc_password=" + this->gc_password); } @@ -147,23 +157,47 @@ vector> LicenseIndex::all() const { void LicenseIndex::add(shared_ptr l) { this->serial_number_to_license[l->serial_number] = l; - if (!l->bb_username.empty()) { - this->bb_username_to_license[l->bb_username] = l; + if (!l->dc_nte_serial_number.empty()) { + this->dc_nte_serial_number_to_license[l->dc_nte_serial_number] = l; } if (!l->xb_gamertag.empty()) { this->xb_gamertag_to_license[l->xb_gamertag] = l; } + if (!l->bb_username.empty()) { + this->bb_username_to_license[l->bb_username] = l; + } } void LicenseIndex::remove(uint32_t serial_number) { auto l = this->serial_number_to_license.at(serial_number); this->serial_number_to_license.erase(l->serial_number); - if (!l->bb_username.empty()) { - this->bb_username_to_license.erase(l->bb_username); + if (!l->dc_nte_serial_number.empty()) { + this->dc_nte_serial_number_to_license.erase(l->dc_nte_serial_number); } if (!l->xb_gamertag.empty()) { this->xb_gamertag_to_license.erase(l->xb_gamertag); } + if (!l->bb_username.empty()) { + this->bb_username_to_license.erase(l->bb_username); + } +} + +shared_ptr LicenseIndex::verify_dc_nte(const string& serial_number, const string& access_key) const { + if (serial_number.empty()) { + throw no_username(); + } + try { + auto& license = this->dc_nte_serial_number_to_license.at(serial_number); + if (license->ban_end_time && (license->ban_end_time >= now())) { + throw invalid_argument("user is banned"); + } + if (license->dc_nte_access_key != access_key) { + throw incorrect_access_key(); + } + return license; + } catch (const out_of_range&) { + throw missing_license(); + } } shared_ptr LicenseIndex::verify_v1_v2( diff --git a/src/License.hh b/src/License.hh index 58b2d963..9b8cf9e4 100644 --- a/src/License.hh +++ b/src/License.hh @@ -35,6 +35,8 @@ public: }; uint32_t serial_number = 0; + std::string dc_nte_serial_number; + std::string dc_nte_access_key; std::string access_key; std::string gc_password; std::string xb_gamertag; @@ -123,6 +125,7 @@ public: void add(std::shared_ptr l); void remove(uint32_t serial_number); + std::shared_ptr verify_dc_nte(const std::string& serial_number, const std::string& access_key) const; std::shared_ptr verify_v1_v2( uint32_t serial_number, const std::string& access_key, @@ -140,8 +143,9 @@ public: std::shared_ptr verify_bb(const std::string& username, const std::string& password) const; protected: - std::unordered_map> bb_username_to_license; + std::unordered_map> dc_nte_serial_number_to_license; std::unordered_map> xb_gamertag_to_license; + std::unordered_map> bb_username_to_license; std::unordered_map> serial_number_to_license; std::shared_ptr create_temporary_license_for_shared_license( diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index f205c624..f16b32e0 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -465,9 +465,8 @@ static void on_88_DCNTE(shared_ptr c, uint16_t, uint32_t, string& data) c->config.set_flags_for_version(c->version(), -1); c->log.info("Game version changed to DC_NTE"); - uint32_t serial_number = stoul(cmd.serial_number.decode(), nullptr, 16); try { - shared_ptr l = s->license_index->verify_v1_v2(serial_number, cmd.access_key.decode(), ""); + shared_ptr l = s->license_index->verify_dc_nte(cmd.serial_number.decode(), cmd.access_key.decode()); c->set_license(l); send_command(c, 0x88, 0x00); @@ -487,8 +486,9 @@ static void on_88_DCNTE(shared_ptr c, uint16_t, uint32_t, string& data) } else { c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED); auto l = s->license_index->create_license(); - l->serial_number = serial_number; - l->access_key = cmd.access_key.decode(); + l->dc_nte_serial_number = cmd.serial_number.decode(); + l->dc_nte_access_key = cmd.access_key.decode(); + l->serial_number = fnv1a32(l->dc_nte_serial_number) & 0x7FFFFFFF; s->license_index->add(l); if (!s->is_replay) { l->save(); @@ -510,9 +510,8 @@ static void on_8B_DCNTE(shared_ptr c, uint16_t, uint32_t, string& data) c->config.set_flags_for_version(c->version(), -1); c->log.info("Game version changed to DC_NTE"); - uint32_t serial_number = stoul(cmd.serial_number.decode(), nullptr, 16); try { - shared_ptr l = s->license_index->verify_v1_v2(serial_number, cmd.access_key.decode(), cmd.name.decode()); + shared_ptr l = s->license_index->verify_dc_nte(cmd.serial_number.decode(), cmd.access_key.decode()); c->set_license(l); } catch (const LicenseIndex::no_username& e) { @@ -531,8 +530,9 @@ static void on_8B_DCNTE(shared_ptr c, uint16_t, uint32_t, string& data) } else { c->config.set_flag(Client::Flag::LICENSE_WAS_CREATED); auto l = s->license_index->create_license(); - l->serial_number = serial_number; - l->access_key = cmd.access_key.decode(); + l->dc_nte_serial_number = cmd.serial_number.decode(); + l->dc_nte_access_key = cmd.access_key.decode(); + l->serial_number = fnv1a32(l->dc_nte_serial_number) & 0x7FFFFFFF; s->license_index->add(l); if (!s->is_replay) { l->save(); diff --git a/src/ServerShell.cc b/src/ServerShell.cc index c4f5c542..fa528ea4 100644 --- a/src/ServerShell.cc +++ b/src/ServerShell.cc @@ -52,7 +52,7 @@ struct CommandDefinition { if (!def) { fprintf(stderr, "FAILED: no such command; try 'help'\n"); } else if (def->run_on_event_thread) { - args.s->forward_to_event_thread([def, args]() { + args.s->call_on_event_thread([def, args]() { CommandArgs local_args = args; try { def->run(local_args); @@ -282,6 +282,8 @@ CommandDefinition c_add_license( xb-user-id= (Xbox user ID)\n\ xb-account-id= (Xbox account ID)\n\ gc-password= (GC password)\n\ + dc-nte-serial-number= (DC NTE serial number)\n\ + dc-nte-access-key= (DC NTE access key)\n\ access-key= (DC/GC/PC access key)\n\ serial= (decimal serial number; required for all licenses)\n\ flags= (see below)\n\ @@ -318,6 +320,10 @@ CommandDefinition c_add_license( l->xb_account_id = stoull(token.substr(14), nullptr, 16); } else if (starts_with(token, "gc-password=")) { l->gc_password = token.substr(12); + } else if (starts_with(token, "dc-nte-serial-number=")) { + l->dc_nte_serial_number = token.substr(21); + } else if (starts_with(token, "dc-nte-access-key=")) { + l->dc_nte_access_key = token.substr(18); } else if (starts_with(token, "access-key=")) { l->access_key = token.substr(11); } else if (starts_with(token, "serial=")) { @@ -383,6 +389,10 @@ CommandDefinition c_update_license( l->xb_account_id = stoull(token.substr(14), nullptr, 16); } else if (starts_with(token, "gc-password=")) { l->gc_password = token.substr(12); + } else if (starts_with(token, "dc-nte-serial-number=")) { + l->dc_nte_serial_number = token.substr(21); + } else if (starts_with(token, "dc-nte-access-key=")) { + l->dc_nte_access_key = token.substr(18); } else if (starts_with(token, "access-key=")) { l->access_key = token.substr(11); } else if (starts_with(token, "serial=")) { diff --git a/src/ServerState.hh b/src/ServerState.hh index 5c75cacf..118497be 100644 --- a/src/ServerState.hh +++ b/src/ServerState.hh @@ -309,6 +309,10 @@ struct ServerState : public std::enable_shared_from_this { std::pair parse_port_spec(const JSON& json) const; std::vector parse_port_configuration(const JSON& json) const; + template + inline void call_on_event_thread(std::function&& fn) { + return ::call_on_event_thread(this->base, std::move(fn)); + } inline void forward_to_event_thread(std::function&& fn) { ::forward_to_event_thread(this->base, std::move(fn)); } diff --git a/tests/DCNTE-GameSmokeTest.test.txt b/tests/DCNTE-GameSmokeTest.test.txt index cfe5aa6e..35a6e6dc 100644 --- a/tests/DCNTE-GameSmokeTest.test.txt +++ b/tests/DCNTE-GameSmokeTest.test.txt @@ -18,9 +18,9 @@ I 91446 2023-12-31 21:04:43 - [Commands] Sending to C-1 (version=DC_NTE command= 00E0 | 65 20 77 69 74 68 20 70 72 6F 67 72 61 6D 73 20 | e with programs 00F0 | 74 68 61 74 20 65 78 70 65 63 74 20 69 74 2E 00 | that expect it. I 91446 2023-12-31 21:04:43 - [Commands] Received from C-1 (version=DC_NTE command=88 flag=00) -0000 | 88 00 26 00 35 35 35 35 35 35 35 35 00 00 00 00 | & 55555555 -0010 | 00 00 00 00 00 38 38 38 38 38 38 38 38 00 00 00 | 88888888 -0020 | 00 00 00 00 00 00 | +0000 | 88 00 26 00 35 35 35 35 35 35 35 35 35 35 35 35 | & 555555555555 +0010 | 35 35 35 35 00 38 38 38 38 38 38 38 38 38 38 38 | 5555 88888888888 +0020 | 38 38 38 38 38 00 | 88888 I 91446 2023-12-31 21:04:43 - [C-1] Game version changed to DC_NTE I 91446 2023-12-31 21:04:43 - [C-1] Created license [License: serial_number=1431655765/55555555, access_key=88888888, flags=00000000] I 91446 2023-12-31 21:04:43 - [Commands] Sending to C-1 (version=DC_NTE command=88 flag=00) @@ -43,8 +43,8 @@ I 91446 2023-12-31 21:04:44 - [Commands] Sending to C-1 (version=DC_V1 command=8 I 91446 2023-12-31 21:04:44 - [Commands] Received from C-1 (version=DC_V1 command=8B flag=00) 0000 | 8B 00 14 01 00 00 FF FF FF FF 00 00 00 00 13 2B | + 0010 | 64 B2 2C B2 20 00 00 00 00 00 00 00 35 35 35 35 | d , 5555 -0020 | 35 35 35 35 00 00 00 00 00 00 00 00 00 38 38 38 | 5555 888 -0030 | 38 38 38 38 38 00 00 00 00 00 00 00 00 00 66 6C | 88888 fl +0020 | 35 35 35 35 35 35 35 35 35 35 35 35 00 38 38 38 | 555555555555 888 +0030 | 38 38 38 38 38 38 38 38 38 38 38 38 38 00 66 6C | 8888888888888 fl 0040 | 79 63 61 73 74 31 00 00 00 00 00 00 00 00 00 00 | ycast1 0050 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0060 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 61 | pa @@ -61,7 +61,7 @@ I 91446 2023-12-31 21:04:44 - [Commands] Received from C-1 (version=DC_V1 comman 0110 | 00 00 00 00 | I 91446 2023-12-31 21:04:44 - [C-1] Game version changed to DC_NTE I 91446 2023-12-31 21:04:44 - [Commands] Sending to C-1 (version=DC_NTE command=04 flag=00) -0000 | 04 00 0C 00 00 00 01 00 55 55 55 55 | UUUU +0000 | 04 00 0C 00 00 00 01 00 F5 5D C2 1A | UUUU I 91446 2023-12-31 21:04:44 - [C-1] Client is a prototype version and the license was created during this session; converting permanent license to temporary license I 91446 2023-12-31 21:04:44 - [Commands] Sending to C-1 (version=DC_NTE command=07 flag=02) 0000 | 07 02 58 00 11 00 00 11 FF FF FF FF 04 00 41 6C | X Al @@ -96,10 +96,10 @@ I 91446 2023-12-31 21:04:56 - [Commands] Sending to C-2 (version=DC_NTE command= 00E0 | 65 20 77 69 74 68 20 70 72 6F 67 72 61 6D 73 20 | e with programs 00F0 | 74 68 61 74 20 65 78 70 65 63 74 20 69 74 2E 00 | that expect it. I 91446 2023-12-31 21:04:56 - [Commands] Received from C-2 (version=DC_NTE command=8B flag=00) -0000 | 8B 00 B0 00 00 00 01 00 55 55 55 55 00 00 13 2B | UUUU + +0000 | 8B 00 B0 00 00 00 01 00 F5 5D C2 1A 00 00 13 2B | UUUU + 0010 | 64 B2 2C B2 20 00 00 00 00 00 00 00 35 35 35 35 | d , 5555 -0020 | 35 35 35 35 00 00 00 00 00 00 00 00 00 38 38 38 | 5555 888 -0030 | 38 38 38 38 38 00 00 00 00 00 00 00 00 00 66 6C | 88888 fl +0020 | 35 35 35 35 35 35 35 35 35 35 35 35 00 38 38 38 | 555555555555 888 +0030 | 38 38 38 38 38 38 38 38 38 38 38 38 38 00 66 6C | 8888888888888 fl 0040 | 79 63 61 73 74 31 00 00 00 00 00 00 00 00 00 00 | ycast1 0050 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0060 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 61 | pa @@ -110,7 +110,7 @@ I 91446 2023-12-31 21:04:56 - [Commands] Received from C-2 (version=DC_NTE comma I 91446 2023-12-31 21:04:56 - [C-2] Game version changed to DC_NTE I 91446 2023-12-31 21:04:56 - [C-2] Created license [License: serial_number=1431655765/55555555, access_key=88888888, flags=00000000] I 91446 2023-12-31 21:04:56 - [Commands] Sending to C-2 (version=DC_NTE command=04 flag=00) -0000 | 04 00 0C 00 00 00 01 00 55 55 55 55 | UUUU +0000 | 04 00 0C 00 00 00 01 00 F5 5D C2 1A | UUUU I 91446 2023-12-31 21:04:56 - [C-2] Client is a prototype version and the license was created during this session; converting permanent license to temporary license I 91446 2023-12-31 21:04:56 - [Commands] Sending to C-2 (version=DC_NTE command=83 flag=0A) 0000 | 83 0A 7C 00 33 00 00 33 01 00 00 00 00 00 00 00 | | 3 3 @@ -205,7 +205,7 @@ I 91446 2023-12-31 21:04:57 - [C-2] Assigned inventory item IDs [PlayerInventory] 9: [+00000010] 03020000 03010000 00000000 (10010009) 00000000 (Disk:Barta Lv.1) I 91446 2023-12-31 21:04:57 - [C-2] Bank is empty I 91446 2023-12-31 21:04:57 - [Commands] Sending to C-2 (ABCDEFGHIJKL) (version=DC_NTE command=67 flag=01) -0000 | 67 01 44 04 00 00 01 00 00 00 01 00 55 55 55 55 | g D UUUU +0000 | 67 01 44 04 00 00 01 00 00 00 01 00 F5 5D C2 1A | g D UUUU 0010 | 7F 00 00 01 00 00 00 00 41 42 43 44 45 46 47 48 | ABCDEFGH 0020 | 49 4A 4B 4C 00 00 00 00 0A 00 00 00 01 00 00 00 | IJKL 0030 | 04 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 | @@ -317,7 +317,7 @@ I 91446 2023-12-31 21:05:17 - [Commands] Received from C-2 (ABCDEFGHIJKL) (versi 0000 | 06 00 14 00 00 00 00 00 00 00 00 00 6F 6D 67 20 | omg 0010 | 68 34 78 00 | h4x I 91446 2023-12-31 21:05:17 - [Commands] Sending to C-2 (ABCDEFGHIJKL) (version=DC_NTE command=06 flag=00) -0000 | 06 00 24 00 00 00 00 00 55 55 55 55 41 42 43 44 | $ UUUUABCD +0000 | 06 00 24 00 00 00 00 00 F5 5D C2 1A 41 42 43 44 | $ UUUUABCD 0010 | 45 46 47 48 49 4A 4B 4C 3E 30 6F 6D 67 20 68 34 | EFGHIJKL>0omg h4 0020 | 78 00 00 00 | x I 91446 2023-12-31 21:05:17 - [Commands] Received from C-2 (ABCDEFGHIJKL) (version=DC_NTE command=60 flag=00) @@ -456,9 +456,9 @@ I 91446 2023-12-31 21:05:43 - [Commands] Sending to C-3 (version=DC_NTE command= 00E0 | 65 20 77 69 74 68 20 70 72 6F 67 72 61 6D 73 20 | e with programs 00F0 | 74 68 61 74 20 65 78 70 65 63 74 20 69 74 2E 00 | that expect it. I 91446 2023-12-31 21:05:43 - [Commands] Received from C-3 (version=DC_NTE command=88 flag=00) -0000 | 88 00 26 00 39 39 39 39 39 39 39 39 00 00 00 00 | & 99999999 -0010 | 00 00 00 00 00 39 39 39 39 39 39 39 39 00 00 00 | 99999999 -0020 | 00 00 00 00 00 00 | +0000 | 88 00 26 00 39 39 39 39 39 39 39 39 39 39 39 39 | & 999999999999 +0010 | 39 39 39 39 00 39 39 39 39 39 39 39 39 39 39 39 | 9999 99999999999 +0020 | 39 39 39 39 39 00 | 99999 I 91446 2023-12-31 21:05:43 - [C-3] Game version changed to DC_NTE I 91446 2023-12-31 21:05:43 - [C-3] Created license [License: serial_number=2576980377/99999999, access_key=99999999, flags=00000000] I 91446 2023-12-31 21:05:43 - [Commands] Sending to C-3 (version=DC_NTE command=88 flag=00) @@ -495,7 +495,7 @@ I 91446 2023-12-31 21:05:43 - [C-2] Assigned inventory item IDs [PlayerInventory] 9: [+00000010] 03020000 03010000 00000000 (10010009) 00000000 (Disk:Barta Lv.1) I 91446 2023-12-31 21:05:43 - [C-2] Bank is empty I 91446 2023-12-31 21:05:43 - [Commands] Sending to C-2 (ABCDEFGHIJKL) (version=DC_NTE command=67 flag=01) -0000 | 67 01 44 04 00 00 01 00 00 00 01 00 55 55 55 55 | g D UUUU +0000 | 67 01 44 04 00 00 01 00 00 00 01 00 F5 5D C2 1A | g D UUUU 0010 | 7F 00 00 01 00 00 00 00 41 42 43 44 45 46 47 48 | ABCDEFGH 0020 | 49 4A 4B 4C 00 00 00 00 0A 00 00 00 01 00 00 00 | IJKL 0030 | 04 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 | @@ -567,8 +567,8 @@ I 91446 2023-12-31 21:05:43 - [Commands] Sending to C-2 (ABCDEFGHIJKL) (version= I 91446 2023-12-31 21:05:43 - [Commands] Received from C-3 (version=DC_V1 command=8B flag=00) 0000 | 8B 00 14 01 00 00 FF FF FF FF 00 00 00 00 B7 57 | W 0010 | 02 41 B9 22 20 00 00 00 00 00 00 00 39 39 39 39 | A " 9999 -0020 | 39 39 39 39 00 00 00 00 00 00 00 00 00 39 39 39 | 9999 999 -0030 | 39 39 39 39 39 00 00 00 00 00 00 00 00 00 66 6C | 99999 fl +0020 | 39 39 39 39 39 39 39 39 39 39 39 39 00 39 39 39 | 999999999999 999 +0030 | 39 39 39 39 39 39 39 39 39 39 39 39 39 00 66 6C | 9999999999999 fl 0040 | 79 63 61 73 74 31 00 00 00 00 00 00 00 00 00 00 | ycast1 0050 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0060 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 61 | pa @@ -585,7 +585,7 @@ I 91446 2023-12-31 21:05:43 - [Commands] Received from C-3 (version=DC_V1 comman 0110 | 00 00 00 00 | I 91446 2023-12-31 21:05:43 - [C-3] Game version changed to DC_NTE I 91446 2023-12-31 21:05:43 - [Commands] Sending to C-3 (version=DC_NTE command=04 flag=00) -0000 | 04 00 0C 00 00 00 01 00 99 99 99 99 | +0000 | 04 00 0C 00 00 00 01 00 F5 79 DE 25 | I 91446 2023-12-31 21:05:43 - [C-3] Client is a prototype version and the license was created during this session; converting permanent license to temporary license I 91446 2023-12-31 21:05:43 - [Commands] Sending to C-3 (version=DC_NTE command=07 flag=02) 0000 | 07 02 58 00 11 00 00 11 FF FF FF FF 04 00 41 6C | X Al @@ -629,10 +629,10 @@ I 91446 2023-12-31 21:05:45 - [Commands] Sending to C-4 (version=DC_NTE command= 00E0 | 65 20 77 69 74 68 20 70 72 6F 67 72 61 6D 73 20 | e with programs 00F0 | 74 68 61 74 20 65 78 70 65 63 74 20 69 74 2E 00 | that expect it. I 91446 2023-12-31 21:05:45 - [Commands] Received from C-4 (version=DC_NTE command=8B flag=00) -0000 | 8B 00 B0 00 00 00 01 00 99 99 99 99 00 00 B7 57 | W +0000 | 8B 00 B0 00 00 00 01 00 F5 79 DE 25 00 00 B7 57 | W 0010 | 02 41 B9 22 20 00 00 00 00 00 00 00 39 39 39 39 | A " 9999 -0020 | 39 39 39 39 00 00 00 00 00 00 00 00 00 39 39 39 | 9999 999 -0030 | 39 39 39 39 39 00 00 00 00 00 00 00 00 00 66 6C | 99999 fl +0020 | 39 39 39 39 39 39 39 39 39 39 39 39 00 39 39 39 | 999999999999 999 +0030 | 39 39 39 39 39 39 39 39 39 39 39 39 39 00 66 6C | 9999999999999 fl 0040 | 79 63 61 73 74 31 00 00 00 00 00 00 00 00 00 00 | ycast1 0050 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0060 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 61 | pa @@ -643,7 +643,7 @@ I 91446 2023-12-31 21:05:45 - [Commands] Received from C-4 (version=DC_NTE comma I 91446 2023-12-31 21:05:45 - [C-4] Game version changed to DC_NTE I 91446 2023-12-31 21:05:45 - [C-4] Created license [License: serial_number=2576980377/99999999, access_key=99999999, flags=00000000] I 91446 2023-12-31 21:05:45 - [Commands] Sending to C-4 (version=DC_NTE command=04 flag=00) -0000 | 04 00 0C 00 00 00 01 00 99 99 99 99 | +0000 | 04 00 0C 00 00 00 01 00 F5 79 DE 25 | I 91446 2023-12-31 21:05:45 - [C-4] Client is a prototype version and the license was created during this session; converting permanent license to temporary license I 91446 2023-12-31 21:05:45 - [Commands] Sending to C-4 (version=DC_NTE command=83 flag=0A) 0000 | 83 0A 7C 00 33 00 00 33 01 00 00 00 00 00 00 00 | | 3 3 @@ -732,7 +732,7 @@ I 91446 2023-12-31 21:05:45 - [C-4] Assigned inventory item IDs [PlayerInventory] 3: [+00000004] 01020100 00000000 00000000 (10010003) 00000000 (Shield) I 91446 2023-12-31 21:05:45 - [C-4] Bank is empty I 91446 2023-12-31 21:05:45 - [Commands] Sending to C-4 (BBBBBBBBBBBB) (version=DC_NTE command=67 flag=01) -0000 | 67 01 44 04 00 00 01 00 00 00 01 00 99 99 99 99 | g D +0000 | 67 01 44 04 00 00 01 00 00 00 01 00 F5 79 DE 25 | g D 0010 | 7F 00 00 01 00 00 00 00 42 42 42 42 42 42 42 42 | BBBBBBBB 0020 | 42 42 42 42 00 00 00 00 04 00 00 00 01 00 00 00 | BBBB 0030 | 10 00 00 00 03 00 00 00 00 02 00 00 00 00 00 00 | @@ -872,7 +872,7 @@ I 91446 2023-12-31 21:05:56 - [C-2] Assigned inventory item IDs [PlayerInventory] 9: [+00000010] 03020000 03010000 00000000 (10210009) 00000000 (Disk:Barta Lv.1) I 91446 2023-12-31 21:05:56 - [C-2] Bank is empty I 91446 2023-12-31 21:05:56 - [Commands] Sending to C-4 (BBBBBBBBBBBB) (version=DC_NTE command=68 flag=01) -0000 | 68 01 44 04 00 00 01 00 00 00 01 00 55 55 55 55 | h D UUUU +0000 | 68 01 44 04 00 00 01 00 00 00 01 00 F5 5D C2 1A | h D UUUU 0010 | 7F 00 00 01 01 00 00 00 41 42 43 44 45 46 47 48 | ABCDEFGH 0020 | 49 4A 4B 4C 00 00 00 00 0A 00 00 00 01 00 00 00 | IJKL 0030 | 04 00 00 00 00 06 00 00 00 00 00 00 00 00 00 00 | @@ -942,7 +942,7 @@ I 91446 2023-12-31 21:05:56 - [Commands] Sending to C-4 (BBBBBBBBBBBB) (version= 0430 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | 0440 | FF FF FF 00 | I 91446 2023-12-31 21:05:56 - [Commands] Sending to C-2 (ABCDEFGHIJKL) (version=DC_NTE command=67 flag=02) -0000 | 67 02 80 08 01 00 01 00 00 00 01 00 99 99 99 99 | g +0000 | 67 02 80 08 01 00 01 00 00 00 01 00 F5 79 DE 25 | g 0010 | 7F 00 00 01 00 00 00 00 42 42 42 42 42 42 42 42 | BBBBBBBB 0020 | 42 42 42 42 00 00 00 00 04 00 00 00 01 00 00 00 | BBBB 0030 | 10 00 00 00 03 00 00 00 00 02 00 00 00 00 00 00 | @@ -1010,7 +1010,7 @@ I 91446 2023-12-31 21:05:56 - [Commands] Sending to C-2 (ABCDEFGHIJKL) (version= 0410 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0420 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0430 | FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | -0440 | FF FF FF 00 00 00 01 00 55 55 55 55 7F 00 00 01 | UUUU +0440 | FF FF FF 00 00 00 01 00 F5 5D C2 1A 7F 00 00 01 | UUUU 0450 | 01 00 00 00 41 42 43 44 45 46 47 48 49 4A 4B 4C | ABCDEFGHIJKL 0460 | 00 00 00 00 0A 00 00 00 01 00 00 00 04 00 00 00 | 0470 | 00 06 00 00 00 00 00 00 00 00 00 00 00 00 21 10 | ! @@ -1205,7 +1205,7 @@ I 91446 2023-12-31 21:06:24 - [Commands] Sending to C-2 (ABCDEFGHIJKL) (version= 0050 | 00 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 | 0060 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0070 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | -0080 | 00 00 00 00 00 00 00 00 00 00 01 00 55 55 55 55 | UUUU +0080 | 00 00 00 00 00 00 00 00 00 00 01 00 F5 5D C2 1A | UUUU 0090 | 7F 00 00 01 00 00 00 00 41 42 43 44 45 46 47 48 | ABCDEFGH 00A0 | 49 4A 4B 4C 00 00 00 00 00 00 00 00 00 00 00 00 | IJKL 00B0 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | @@ -1296,7 +1296,7 @@ I 91446 2023-12-31 21:06:44 - [C-4] Assigned inventory item IDs but did not mark [PlayerInventory] 3: [+00000004] 01020100 00000000 00000000 (00210003) 00000000 (Shield) I 91446 2023-12-31 21:06:44 - [C-4] Bank is empty I 91446 2023-12-31 21:06:44 - [Commands] Sending to C-2 (ABCDEFGHIJKL) (version=DC_NTE command=65 flag=01) -0000 | 65 01 44 04 00 00 01 00 00 00 01 00 99 99 99 99 | e D +0000 | 65 01 44 04 00 00 01 00 00 00 01 00 F5 79 DE 25 | e D 0010 | 7F 00 00 01 01 00 00 00 42 42 42 42 42 42 42 42 | BBBBBBBB 0020 | 42 42 42 42 00 00 00 00 04 00 00 00 01 00 00 00 | BBBB 0030 | 10 00 00 00 03 00 00 00 00 02 00 00 00 00 00 00 | @@ -1374,9 +1374,9 @@ I 91446 2023-12-31 21:06:44 - [Commands] Sending to C-4 (BBBBBBBBBBBB) (version= 0050 | 00 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 | 0060 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0070 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | -0080 | 00 00 00 00 00 00 00 00 00 00 01 00 55 55 55 55 | UUUU +0080 | 00 00 00 00 00 00 00 00 00 00 01 00 F5 5D C2 1A | UUUU 0090 | 7F 00 00 01 00 00 00 00 41 42 43 44 45 46 47 48 | ABCDEFGH -00A0 | 49 4A 4B 4C 00 00 00 00 00 00 01 00 99 99 99 99 | IJKL +00A0 | 49 4A 4B 4C 00 00 00 00 00 00 01 00 F5 79 DE 25 | IJKL 00B0 | 7F 00 00 01 01 00 00 00 42 42 42 42 42 42 42 42 | BBBBBBBB 00C0 | 42 42 42 42 00 00 00 00 00 00 00 00 00 00 00 00 | BBBB 00D0 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |