set up framework for DC patching

This commit is contained in:
Martin Michelsen
2024-04-14 21:00:32 -07:00
parent 8ecbe6798d
commit d6edf1b24d
12 changed files with 132 additions and 34 deletions
+3
View File
@@ -44,6 +44,9 @@ void Client::Config::set_flags_for_version(Version version, int64_t sub_version)
case Version::DC_NTE:
case Version::DC_V1_11_2000_PROTOTYPE:
case Version::DC_V1:
this->set_flag(Flag::NO_D6);
this->set_flag(Flag::NO_SEND_FUNCTION_CALL);
break;
case Version::DC_V2:
this->set_flag(Flag::NO_D6);
this->set_flag(Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH);
+9 -1
View File
@@ -10,6 +10,7 @@
#ifdef HAVE_RESOURCE_FILE
#include <resource_file/Emulators/PPC32Emulator.hh>
#include <resource_file/Emulators/SH4Emulator.hh>
#include <resource_file/Emulators/X86Emulator.hh>
#endif
@@ -39,6 +40,8 @@ const char* name_for_architecture(CompiledFunctionCode::Architecture arch) {
return "PowerPC";
case CompiledFunctionCode::Architecture::X86:
return "x86";
case CompiledFunctionCode::Architecture::SH4:
return "SH-4";
default:
throw logic_error("invalid architecture");
}
@@ -165,7 +168,8 @@ shared_ptr<CompiledFunctionCode> compile_function_code(
ret = X86Emulator::assemble(load_file(asm_filename), get_include);
break;
case CompiledFunctionCode::Architecture::SH4:
throw runtime_error("cannot compuile SH-4 assembly");
ret = SH4Emulator::assemble(load_file(asm_filename), get_include);
break;
default:
throw runtime_error("unknown architecture");
}
@@ -184,6 +188,10 @@ shared_ptr<CompiledFunctionCode> compile_function_code(
assembled = PPC32Emulator::assemble(text, get_include);
} else if (arch == CompiledFunctionCode::Architecture::X86) {
assembled = X86Emulator::assemble(text, get_include);
} else if (arch == CompiledFunctionCode::Architecture::SH4) {
assembled = SH4Emulator::assemble(text, get_include);
} else {
throw runtime_error("invalid architecture");
}
ret->code = std::move(assembled.code);
ret->label_offsets = std::move(assembled.label_offsets);
+11 -9
View File
@@ -1196,10 +1196,8 @@ Action a_assemble_all_patches(
two compiled .bin files for each patch (one unencrypted, for most PSO\n\
versions, and one encrypted, for PSO GC JP v1.4, JP Ep3, and Ep3 Trial\n\
Edition). The output files are saved in system/client-functions.\n",
+[](Arguments& args) {
string config_filename = args.get<string>("config");
auto s = make_shared<ServerState>(config_filename);
s->compile_functions(false);
+[](Arguments&) {
auto fci = make_shared<FunctionCodeIndex>("system/client-functions");
auto process_code = +[](shared_ptr<const CompiledFunctionCode> code,
uint32_t checksum_addr,
@@ -1216,23 +1214,27 @@ Action a_assemble_all_patches(
}
};
for (const auto& it : s->function_code_index->name_and_specific_version_to_patch_function) {
for (const auto& it : fci->name_and_specific_version_to_patch_function) {
process_code(it.second, 0, 0, 0);
}
try {
process_code(s->function_code_index->name_to_function.at("VersionDetectGC"), 0, 0, 0);
process_code(fci->name_to_function.at("VersionDetectDC"), 0, 0, 0);
} catch (const out_of_range&) {
}
try {
process_code(s->function_code_index->name_to_function.at("VersionDetectXB"), 0, 0, 0);
process_code(fci->name_to_function.at("VersionDetectGC"), 0, 0, 0);
} catch (const out_of_range&) {
}
try {
process_code(s->function_code_index->name_to_function.at("CacheClearFix-Phase1"), 0x80000000, 8, 0x7F2734EC);
process_code(fci->name_to_function.at("VersionDetectXB"), 0, 0, 0);
} catch (const out_of_range&) {
}
try {
process_code(s->function_code_index->name_to_function.at("CacheClearFix-Phase2"), 0, 0, 0);
process_code(fci->name_to_function.at("CacheClearFix-Phase1"), 0x80000000, 8, 0x7F2734EC);
} catch (const out_of_range&) {
}
try {
process_code(fci->name_to_function.at("CacheClearFix-Phase2"), 0, 0, 0);
} catch (const out_of_range&) {
}
});
+9 -1
View File
@@ -24,6 +24,7 @@
#include <phosg/Time.hh>
#ifdef HAVE_RESOURCE_FILE
#include <resource_file/Emulators/PPC32Emulator.hh>
#include <resource_file/Emulators/SH4Emulator.hh>
#include <resource_file/Emulators/X86Emulator.hh>
#endif
@@ -728,7 +729,8 @@ static HandlerResult S_B2(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
// TODO: Support SH-4 disassembly too
bool is_ppc = ::is_ppc(ses->version());
bool is_x86 = ::is_x86(ses->version());
if (is_ppc || is_x86) {
bool is_sh4 = ::is_sh4(ses->version());
if (is_ppc || is_x86 || is_sh4) {
try {
if (code.size() < sizeof(FooterT)) {
throw runtime_error("code section is too small");
@@ -763,6 +765,12 @@ static HandlerResult S_B2(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t,
code.size(),
0,
&labels);
} else if (is_sh4) {
disassembly = SH4Emulator::disassemble(
&r.pget<uint8_t>(0, code.size()),
code.size(),
0,
&labels);
} else {
// We shouldn't have entered the outer if statement if this happens
throw logic_error("unsupported architecture");
+6 -2
View File
@@ -122,6 +122,10 @@ void send_first_pre_lobby_commands(shared_ptr<Client> c, std::function<void()> o
// TODO: This function is bad. Ideally we would use coroutines and clean up
// all these terrible callbacks.
if (c->login->account->auto_patches_enabled.empty()) {
c->config.set_flag(Client::Flag::HAS_AUTO_PATCHES);
}
if (function_compiler_available() &&
!c->config.check_flag(Client::Flag::HAS_AUTO_PATCHES) &&
!c->config.check_flag(Client::Flag::NO_SEND_FUNCTION_CALL)) {
@@ -3002,7 +3006,7 @@ static void on_61_98(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
const auto* cmd3 = &check_size_t<C_CharacterData_Ep3_61_98>(data);
c->ep3_config = make_shared<Episode3::PlayerConfig>(cmd3->ep3_config);
cmd = reinterpret_cast<const C_CharacterData_V3_61_98*>(cmd3);
if (c->config.specific_version == 0x33000000) {
if (c->config.specific_version == 0x00000000) {
c->config.specific_version = 0x33534A30; // 3SJ0
}
} else {
@@ -3010,7 +3014,7 @@ static void on_61_98(shared_ptr<Client> c, uint16_t command, uint32_t flag, stri
c->channel.version = Version::GC_EP3_NTE;
c->log.info("Game version changed to GC_EP3_NTE");
c->config.clear_flag(Client::Flag::ENCRYPTED_SEND_FUNCTION_CALL);
if (c->config.specific_version == 0x33000000) {
if (c->config.specific_version == default_specific_version_for_version(Version::GC_EP3, -1)) {
c->config.specific_version = 0x33534A54; // 3SJT
}
c->convert_account_to_temporary_if_nte();
+10 -4
View File
@@ -338,11 +338,17 @@ void prepare_client_for_patches(shared_ptr<Client> c, function<void()> on_comple
if (!c) {
return;
}
bool is_gc = ::is_gc(c->version());
bool is_xb = (c->version() == Version::XB_V3);
if ((is_gc || is_xb) &&
const char* version_detect_name = nullptr;
if (c->version() == Version::DC_V2) {
version_detect_name = "VersionDetectDC";
} else if (is_gc(c->version())) {
version_detect_name = "VersionDetectGC";
} else if (c->version() == Version::XB_V3) {
version_detect_name = "VersionDetectXB";
}
if (version_detect_name &&
c->config.specific_version == default_specific_version_for_version(c->version(), -1)) {
send_function_call(c, s->function_code_index->name_to_function.at(is_xb ? "VersionDetectXB" : "VersionDetectGC"));
send_function_call(c, s->function_code_index->name_to_function.at(version_detect_name));
c->function_call_response_queue.emplace_back([wc = weak_ptr<Client>(c), on_complete](uint32_t specific_version, uint32_t) -> void {
auto c = wc.lock();
if (!c) {
+9 -3
View File
@@ -204,8 +204,14 @@ uint32_t default_specific_version_for_version(Version version, int64_t sub_versi
// to set the specific_version based on sub_version. Fortunately, all
// versions that share sub_version values also support send_function_call,
// so for those versions we get the specific_version later by sending the
// VersionDetectGC or VersionDetectXB call.
// VersionDetectDC, VersionDetectGC, or VersionDetectXB call.
switch (version) {
case Version::DC_NTE:
return 0x314F4A31;
case Version::DC_V1_11_2000_PROTOTYPE:
return 0x314F4A32;
case Version::DC_V1:
return 0x00000000; // Need to send VersionDetectDC (but can't on V1; rip)
case Version::GC_NTE:
return 0x334F4A54; // 3OJT
case Version::GC_V3:
@@ -225,7 +231,7 @@ uint32_t default_specific_version_for_version(Version version, int64_t sub_versi
case 0x30: // GC Ep1&2 GameJam demo, GC Ep1&2 Trial Edition, GC Ep1&2 JP v1.2, at least one version of PSO XB
case 0x31: // GC Ep1&2 US v1.0, GC US v1.1, XB US
default:
return 0x33000000;
return 0x00000000; // Need to send VersionDetectGC
}
throw logic_error("this should be impossible");
case Version::GC_EP3_NTE:
@@ -240,7 +246,7 @@ uint32_t default_specific_version_for_version(Version version, int64_t sub_versi
case -1: // Initial check (before sub_version recognition)
case 0x40: // GC Ep3 trial and GC Ep3 JP
default:
return 0x33000000;
return 0x00000000; // Need to send VersionDetectGC
}
case Version::XB_V3:
return 0x344F0000;
@@ -0,0 +1,61 @@
# This function returns the game version, with values more specific than can be
# detected by the sub_version field in the various login commands (e.g. 93/9D).
# The returned value has the format SSPPRRVV, where:
# S = version (31 = PSOv1, 32 = PSOv2)
# G = game (4F = PSO)
# R = region (45 = E, 4A = J, 50 = P)
# V = minor version (31 = NTE, 32 = 11/2000, 33 = 12/2000, 24 = 01/2001,
# 35 = 08/2001, 46 = not a prototype)
# This results in a 4-character ASCII-printable version code which encodes all
# of the above information. This value is called specific_version in the places
# where it's used by the server.
entry_ptr:
reloc0:
.offsetof start
start:
mova r0, [data_start]
mov r1, r0
mov.l r2, [r1]+ # target value
again:
mov.l r0, [r1]+ # candidate address
cmpeq r0, 0
bt done # return 0 if no version matched
mov.l r0, [r0] # value from candidate address
cmpeq r0, r2
mov.l r0, [r1]+ # specific_version from this match
bf again
nop
done:
rets
nop
.align 4
data_start:
.data 0x61657244
.data 0x8C239D78 # v1 NTE
.data 0x314F4A31 # 1OJ1
.data 0x8C24CA24 # v1 11/2000
.data 0x314F4A32 # 1OJ2
.data 0x8C2873AC # v1 12/2000
.data 0x314F4A33 # 1OJ3
.data 0x8C28B04C # v1 01/2001
.data 0x314F4A34 # 1OJ4
.data 0x8C291E34 # v1 JP
.data 0x314F4A46 # 1OJF
.data 0x8C28B924 # v1 USA
.data 0x314F4546 # 1OEF
.data 0x8C28B3F4 # v1 EU
.data 0x314F5046 # 1OPF
.data 0x8C2F3748 # v2 08/2001
.data 0x324F4A35 # 2OJ5
.data 0x8C2F11D0 # v2 JP
.data 0x324F4A46 # 2OJF
.data 0x8C2F3738 # v2 USA
.data 0x324F4546 # 2OEF
.data 0x8C2E7CE0 # v2 EU
.data 0x324F5046 # 2OPF
.data 0x00000000 # end sentinel
+5 -5
View File
@@ -467,7 +467,7 @@ I 94381 2023-12-29 15:36:19 - [Commands] Received from C-4 (version=GC_V3 comman
0140 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
I 94381 2023-12-29 15:36:19 - [Commands] Sending to C-4 (version=GC_V3 command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 1E B1 05 17 32 AC 99 83 | , 2
0010 | 00 00 00 33 00 00 00 40 20 00 00 00 00 00 00 00 | 3 B
0010 | 00 00 00 00 00 00 00 40 20 00 00 00 00 00 00 00 | 3 B
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 94381 2023-12-29 15:36:19 - [Commands] Sending to C-4 (version=GC_V3 command=D5 flag=00)
0000 | D5 00 2C 00 59 6F 75 20 61 72 65 20 63 6F 6E 6E | , You are conn
@@ -477,7 +477,7 @@ I 94381 2023-12-29 15:36:19 - [Commands] Received from C-4 (version=GC_V3 comman
0000 | 96 00 0C 00 7B 9E 17 2C 1D 00 00 00 | { ,
I 94381 2023-12-29 15:36:19 - [Commands] Sending to C-4 (version=GC_V3 command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 1E B1 05 17 32 AC 99 83 | , 2
0010 | 00 00 00 33 00 00 00 40 20 00 04 00 00 00 00 00 | 3 B
0010 | 00 00 00 00 00 00 00 40 20 00 04 00 00 00 00 00 | 3 B
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 94381 2023-12-29 15:36:19 - [Commands] Sending to C-4 (version=GC_V3 command=B1 flag=00)
0000 | B1 00 20 00 32 30 32 33 3A 31 32 3A 32 39 3A 20 | 2023:12:29:
@@ -506,7 +506,7 @@ I 94381 2023-12-29 15:36:19 - [Commands] Sending to C-4 (version=GC_V3 command=9
0000 | 97 01 04 00 |
I 94381 2023-12-29 15:36:19 - [Commands] Sending to C-4 (version=GC_V3 command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 1E B1 05 17 32 AC 99 83 | , 2
0010 | 00 00 00 33 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
0010 | 00 00 00 00 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 94381 2023-12-29 15:36:19 - [Commands] Received from C-4 (version=GC_V3 command=B1 flag=00)
0000 | B1 00 04 00 |
@@ -555,11 +555,11 @@ I 94381 2023-12-29 15:36:20 - [Commands] Received from C-5 (version=GC_V3 comman
00A0 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
00B0 | 00 00 00 00 00 00 00 00 00 00 00 00 4A 6F 6E 61 | Jona
00C0 | 68 00 00 00 00 00 00 00 00 00 00 00 32 AC 99 83 | h 2
00D0 | 00 00 00 33 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
00D0 | 00 00 00 00 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
00E0 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 94381 2023-12-29 15:36:20 - [Commands] Sending to C-5 (version=GC_V3 command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 1E B1 05 17 32 AC 99 83 | , 2
0010 | 00 00 00 33 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
0010 | 00 00 00 00 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 94381 2023-12-29 15:36:20 - [Commands] Sending to C-5 (version=GC_V3 command=83 flag=0F)
0000 | 83 0F B8 00 33 00 00 33 01 00 00 00 00 00 00 00 | 3 3
@@ -5867,7 +5867,7 @@ I 17097 2023-09-19 21:53:53 - [Commands] Received from C-3 (version=GC command=9
0140 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
I 17097 2023-09-19 21:53:53 - [Commands] Sending to C-3 (version=GC command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 22 22 22 22 32 AC 99 83 | , """"2
0010 | 00 00 00 33 00 A1 00 40 20 00 00 00 00 00 00 00 | 3@ `
0010 | 00 00 00 00 00 A1 00 40 20 00 00 00 00 00 00 00 | 3@ `
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 17097 2023-09-19 21:53:53 - [Commands] Sending to C-3 (version=GC command=B7 flag=00)
0000 | B7 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 |
@@ -5882,7 +5882,7 @@ I 17097 2023-09-19 21:53:53 - [Commands] Received from C-3 (version=GC command=9
0000 | 96 00 0C 00 30 AA 74 2C 27 00 00 00 | 0 t,'
I 17097 2023-09-19 21:53:53 - [Commands] Sending to C-3 (version=GC command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 22 22 22 22 32 AC 99 83 | , """"2
0010 | 00 00 00 33 00 A1 00 40 20 00 04 00 00 00 00 00 | 3@ `
0010 | 00 00 00 00 00 A1 00 40 20 00 04 00 00 00 00 00 | 3@ `
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 17097 2023-09-19 21:53:53 - [Commands] Sending to C-3 (version=GC command=B1 flag=00)
0000 | B1 00 20 00 32 30 32 33 3A 30 39 3A 32 30 3A 20 | 2023:09:20:
@@ -62,7 +62,7 @@ I 25793 2023-11-24 23:03:38 - [Commands] Received from C-4 (version=GC_EP3 comma
0140 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
I 25793 2023-11-24 23:03:38 - [Commands] Sending to C-4 (version=GC_EP3 command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 11 11 11 11 32 AC 99 83 | , 2
0010 | 00 00 00 33 00 A1 00 40 20 00 00 00 00 00 00 00 | 3 B`
0010 | 00 00 00 00 00 A1 00 40 20 00 00 00 00 00 00 00 | 3 B`
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 25793 2023-11-24 23:03:38 - [Commands] Sending to C-4 (version=GC_EP3 command=B7 flag=00)
0000 | B7 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 |
@@ -77,7 +77,7 @@ I 25793 2023-11-24 23:03:38 - [Commands] Received from C-4 (version=GC_EP3 comma
0000 | 96 00 0C 00 5C E6 6B 2C 3B 00 00 00 | \ k,;
I 25793 2023-11-24 23:03:38 - [Commands] Sending to C-4 (version=GC_EP3 command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 11 11 11 11 32 AC 99 83 | , 2
0010 | 00 00 00 33 00 A1 00 40 20 00 04 00 00 00 00 00 | 3 B`
0010 | 00 00 00 00 00 A1 00 40 20 00 04 00 00 00 00 00 | 3 B`
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 25793 2023-11-24 23:03:38 - [Commands] Sending to C-4 (version=GC_EP3 command=B1 flag=00)
0000 | B1 00 20 00 32 30 32 33 3A 31 31 3A 32 35 3A 20 | 2023:11:25:
+5 -5
View File
@@ -23206,7 +23206,7 @@ I 56327 2024-03-03 23:56:37 - [Commands] Received from C-4 (version=GC_V3 comman
0140 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
I 56327 2024-03-03 23:56:37 - [Commands] Sending to C-4 (version=GC_V3 command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 1E B1 05 17 32 AC 99 83 | , 2
0010 | 00 00 00 33 00 00 00 40 20 00 00 00 00 00 00 00 | 3 @
0010 | 00 00 00 00 00 00 00 40 20 00 00 00 00 00 00 00 | 3 @
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 56327 2024-03-03 23:56:37 - [Commands] Sending to C-4 (version=GC_V3 command=D5 flag=00)
0000 | D5 00 2C 00 59 6F 75 20 61 72 65 20 63 6F 6E 6E | , You are conn
@@ -23216,7 +23216,7 @@ I 56327 2024-03-03 23:56:37 - [Commands] Received from C-4 (version=GC_V3 comman
0000 | 96 00 0C 00 28 59 6C 2B 08 01 00 00 | (Yl+
I 56327 2024-03-03 23:56:37 - [Commands] Sending to C-4 (version=GC_V3 command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 1E B1 05 17 32 AC 99 83 | , 2
0010 | 00 00 00 33 00 00 00 40 20 00 04 00 00 00 00 00 | 3 @
0010 | 00 00 00 00 00 00 00 40 20 00 04 00 00 00 00 00 | 3 @
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 56327 2024-03-03 23:56:37 - [Commands] Sending to C-4 (version=GC_V3 command=B1 flag=00)
0000 | B1 00 20 00 32 30 32 34 3A 30 33 3A 30 34 3A 20 | 2024:03:04:
@@ -23245,7 +23245,7 @@ I 56327 2024-03-03 23:56:38 - [Commands] Sending to C-4 (version=GC_V3 command=9
0000 | 97 01 04 00 |
I 56327 2024-03-03 23:56:38 - [Commands] Sending to C-4 (version=GC_V3 command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 1E B1 05 17 32 AC 99 83 | , 2
0010 | 00 00 00 33 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
0010 | 00 00 00 00 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 56327 2024-03-03 23:56:38 - [Commands] Received from C-4 (version=GC_V3 command=B1 flag=00)
0000 | B1 00 04 00 |
@@ -23294,11 +23294,11 @@ I 56327 2024-03-03 23:56:38 - [Commands] Received from C-5 (version=GC_V3 comman
00A0 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
00B0 | 00 00 00 00 00 00 00 00 00 00 00 00 4E 4F 20 44 | NO D
00C0 | 41 54 41 20 00 00 00 00 00 00 00 00 32 AC 99 83 | ATA 2
00D0 | 00 00 00 33 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
00D0 | 00 00 00 00 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
00E0 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 56327 2024-03-03 23:56:38 - [Commands] Sending to C-5 (version=GC_V3 command=04 flag=00)
0000 | 04 00 2C 00 00 00 01 00 1E B1 05 17 32 AC 99 83 | , 2
0010 | 00 00 00 33 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
0010 | 00 00 00 00 00 00 00 44 20 00 00 00 00 00 00 00 | 3 D
0020 | 00 00 00 00 00 00 FF FF 80 FF FF FF |
I 56327 2024-03-03 23:56:38 - [Commands] Sending to C-5 (version=GC_V3 command=83 flag=0F)
0000 | 83 0F B8 00 33 00 00 33 01 00 00 00 00 00 00 00 | 3 3