set up framework for DC patching
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
@@ -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&) {
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user