organize system/client-functions
This commit is contained in:
+94
-71
@@ -120,12 +120,14 @@ bool CompiledFunctionCode::is_big_endian() const {
|
||||
|
||||
shared_ptr<CompiledFunctionCode> compile_function_code(
|
||||
CompiledFunctionCode::Architecture arch,
|
||||
const string& directory,
|
||||
const string& function_directory,
|
||||
const string& system_directory,
|
||||
const string& name,
|
||||
const string& text) {
|
||||
#ifndef HAVE_RESOURCE_FILE
|
||||
(void)arch;
|
||||
(void)directory;
|
||||
(void)function_directory;
|
||||
(void)system_directory;
|
||||
(void)name;
|
||||
(void)text;
|
||||
throw runtime_error("function compiler is not available");
|
||||
@@ -154,7 +156,11 @@ shared_ptr<CompiledFunctionCode> compile_function_code(
|
||||
throw runtime_error("unknown architecture");
|
||||
}
|
||||
|
||||
string asm_filename = string_printf("%s/%s.%s.inc.s", directory.c_str(), name.c_str(), arch_name_token);
|
||||
// Look in the function directory first, then the system directory
|
||||
string asm_filename = string_printf("%s/%s.%s.inc.s", function_directory.c_str(), name.c_str(), arch_name_token);
|
||||
if (!isfile(asm_filename)) {
|
||||
asm_filename = string_printf("%s/%s.%s.inc.s", system_directory.c_str(), name.c_str(), arch_name_token);
|
||||
}
|
||||
if (isfile(asm_filename)) {
|
||||
if (!get_include_stack.emplace(name).second) {
|
||||
throw runtime_error("mutual recursion between includes: " + name);
|
||||
@@ -176,7 +182,12 @@ shared_ptr<CompiledFunctionCode> compile_function_code(
|
||||
get_include_stack.erase(name);
|
||||
return ret.code;
|
||||
}
|
||||
string bin_filename = directory + "/" + name + ".inc.bin";
|
||||
|
||||
string bin_filename = function_directory + "/" + name + ".inc.bin";
|
||||
if (isfile(bin_filename)) {
|
||||
return load_file(bin_filename);
|
||||
}
|
||||
bin_filename = system_directory + "/" + name + ".inc.bin";
|
||||
if (isfile(bin_filename)) {
|
||||
return load_file(bin_filename);
|
||||
}
|
||||
@@ -245,83 +256,95 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t next_menu_item_id = 0;
|
||||
for (const auto& filename : list_directory_sorted(directory)) {
|
||||
try {
|
||||
if (!ends_with(filename, ".s")) {
|
||||
continue;
|
||||
}
|
||||
string system_dir_path = ends_with(directory, "/") ? (directory + "System") : (directory + "/System");
|
||||
|
||||
string name = filename.substr(0, filename.size() - 2);
|
||||
if (ends_with(name, ".inc")) {
|
||||
continue;
|
||||
}
|
||||
uint32_t next_menu_item_id = 1;
|
||||
for (const auto& subdir_name : list_directory_sorted(directory)) {
|
||||
string subdir_path = ends_with(directory, "/") ? (directory + subdir_name) : (directory + "/" + subdir_name);
|
||||
if (!isdir(subdir_path)) {
|
||||
function_compiler_log.warning("Skipping %s (not a directory)", subdir_name.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_patch = ends_with(name, ".patch");
|
||||
if (is_patch) {
|
||||
name.resize(name.size() - 6);
|
||||
}
|
||||
for (const auto& filename : list_directory_sorted(subdir_path)) {
|
||||
try {
|
||||
if (!ends_with(filename, ".s")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Figure out the version or specific_version
|
||||
CompiledFunctionCode::Architecture arch = CompiledFunctionCode::Architecture::UNKNOWN;
|
||||
uint32_t specific_version = 0;
|
||||
string short_name = name;
|
||||
if (ends_with(name, ".ppc")) {
|
||||
arch = CompiledFunctionCode::Architecture::POWERPC;
|
||||
name.resize(name.size() - 4);
|
||||
short_name = name;
|
||||
} else if (ends_with(name, ".x86")) {
|
||||
arch = CompiledFunctionCode::Architecture::X86;
|
||||
name.resize(name.size() - 4);
|
||||
short_name = name;
|
||||
} else if (ends_with(name, ".sh4")) {
|
||||
arch = CompiledFunctionCode::Architecture::SH4;
|
||||
name.resize(name.size() - 4);
|
||||
short_name = name;
|
||||
} else if (is_patch && (name.size() >= 5) && (name[name.size() - 5] == '.')) {
|
||||
specific_version = (name[name.size() - 4] << 24) | (name[name.size() - 3] << 16) | (name[name.size() - 2] << 8) | name[name.size() - 1];
|
||||
if (specific_version_is_gc(specific_version)) {
|
||||
string name = filename.substr(0, filename.size() - 2);
|
||||
if (ends_with(name, ".inc")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_patch = ends_with(name, ".patch");
|
||||
if (is_patch) {
|
||||
name.resize(name.size() - 6);
|
||||
}
|
||||
|
||||
// Figure out the version or specific_version
|
||||
CompiledFunctionCode::Architecture arch = CompiledFunctionCode::Architecture::UNKNOWN;
|
||||
uint32_t specific_version = 0;
|
||||
string short_name = name;
|
||||
if (ends_with(name, ".ppc")) {
|
||||
arch = CompiledFunctionCode::Architecture::POWERPC;
|
||||
} else if (specific_version_is_xb(specific_version) || specific_version_is_bb(specific_version)) {
|
||||
name.resize(name.size() - 4);
|
||||
short_name = name;
|
||||
} else if (ends_with(name, ".x86")) {
|
||||
arch = CompiledFunctionCode::Architecture::X86;
|
||||
} else {
|
||||
throw runtime_error("unable to determine architecture from specific_version");
|
||||
name.resize(name.size() - 4);
|
||||
short_name = name;
|
||||
} else if (ends_with(name, ".sh4")) {
|
||||
arch = CompiledFunctionCode::Architecture::SH4;
|
||||
name.resize(name.size() - 4);
|
||||
short_name = name;
|
||||
} else if (is_patch && (name.size() >= 5) && (name[name.size() - 5] == '.')) {
|
||||
specific_version = (name[name.size() - 4] << 24) | (name[name.size() - 3] << 16) | (name[name.size() - 2] << 8) | name[name.size() - 1];
|
||||
if (specific_version_is_dc(specific_version)) {
|
||||
arch = CompiledFunctionCode::Architecture::SH4;
|
||||
} else if (specific_version_is_gc(specific_version)) {
|
||||
arch = CompiledFunctionCode::Architecture::POWERPC;
|
||||
} else if (specific_version_is_xb(specific_version) || specific_version_is_bb(specific_version)) {
|
||||
arch = CompiledFunctionCode::Architecture::X86;
|
||||
} else {
|
||||
throw runtime_error("unable to determine architecture from specific_version");
|
||||
}
|
||||
short_name = name.substr(0, name.size() - 5);
|
||||
}
|
||||
short_name = name.substr(0, name.size() - 5);
|
||||
}
|
||||
|
||||
if (arch == CompiledFunctionCode::Architecture::UNKNOWN) {
|
||||
throw runtime_error("unable to determine architecture");
|
||||
}
|
||||
|
||||
string path = directory + "/" + filename;
|
||||
string text = load_file(path);
|
||||
auto code = compile_function_code(arch, directory, name, text);
|
||||
if (code->index != 0) {
|
||||
if (!this->index_to_function.emplace(code->index, code).second) {
|
||||
throw runtime_error(string_printf(
|
||||
"duplicate function index: %08" PRIX32, code->index));
|
||||
if (arch == CompiledFunctionCode::Architecture::UNKNOWN) {
|
||||
throw runtime_error("unable to determine architecture");
|
||||
}
|
||||
}
|
||||
code->specific_version = specific_version;
|
||||
code->source_path = path;
|
||||
code->short_name = short_name;
|
||||
this->name_to_function.emplace(name, code);
|
||||
if (is_patch) {
|
||||
code->menu_item_id = next_menu_item_id++;
|
||||
this->menu_item_id_and_specific_version_to_patch_function.emplace(
|
||||
static_cast<uint64_t>(code->menu_item_id) << 32 | specific_version, code);
|
||||
this->name_and_specific_version_to_patch_function.emplace(
|
||||
string_printf("%s-%08" PRIX32, short_name.c_str(), specific_version), code);
|
||||
}
|
||||
|
||||
string index_prefix = code->index ? string_printf("%02X => ", code->index) : "";
|
||||
string patch_prefix = is_patch ? string_printf("[%08" PRIX32 "/%08" PRIX32 "] ", code->menu_item_id, code->specific_version) : "";
|
||||
function_compiler_log.info("Compiled function %s%s%s (%s)",
|
||||
index_prefix.c_str(), patch_prefix.c_str(), name.c_str(), name_for_architecture(code->arch));
|
||||
string path = subdir_path + "/" + filename;
|
||||
string text = load_file(path);
|
||||
auto code = compile_function_code(arch, subdir_path, system_dir_path, name, text);
|
||||
if (code->index != 0) {
|
||||
if (!this->index_to_function.emplace(code->index, code).second) {
|
||||
throw runtime_error(string_printf(
|
||||
"duplicate function index: %08" PRIX32, code->index));
|
||||
}
|
||||
}
|
||||
code->specific_version = specific_version;
|
||||
code->source_path = path;
|
||||
code->short_name = short_name;
|
||||
this->name_to_function.emplace(name, code);
|
||||
if (is_patch) {
|
||||
code->menu_item_id = next_menu_item_id++;
|
||||
this->menu_item_id_and_specific_version_to_patch_function.emplace(
|
||||
static_cast<uint64_t>(code->menu_item_id) << 32 | specific_version, code);
|
||||
this->name_and_specific_version_to_patch_function.emplace(
|
||||
string_printf("%s-%08" PRIX32, short_name.c_str(), specific_version), code);
|
||||
}
|
||||
|
||||
} catch (const exception& e) {
|
||||
function_compiler_log.warning("Failed to compile function %s: %s", filename.c_str(), e.what());
|
||||
string index_prefix = code->index ? string_printf("%02X => ", code->index) : "";
|
||||
string patch_prefix = is_patch ? string_printf("[%08" PRIX32 "/%08" PRIX32 "] ", code->menu_item_id, code->specific_version) : "";
|
||||
function_compiler_log.info("Compiled function %s%s%s (%s)",
|
||||
index_prefix.c_str(), patch_prefix.c_str(), name.c_str(), name_for_architecture(code->arch));
|
||||
|
||||
} catch (const exception& e) {
|
||||
function_compiler_log.warning("Failed to compile function %s: %s", filename.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1221,6 +1221,7 @@ static HandlerResult C_GXB_61(shared_ptr<ProxyServer::LinkedSession> ses, uint16
|
||||
if (is_ep3(ses->version()) && (ses->version() != Version::GC_EP3_NTE)) {
|
||||
ses->log.info("Version changed to GC_EP3_NTE");
|
||||
ses->set_version(Version::GC_EP3_NTE);
|
||||
ses->config.specific_version = SPECIFIC_VERSION_GC_EP3_NTE;
|
||||
}
|
||||
pd = &check_size_t<C_CharacterData_V3_61_98>(data, 0xFFFF);
|
||||
}
|
||||
|
||||
@@ -277,6 +277,7 @@ void ProxyServer::UnlinkedSession::on_input(Channel& ch, uint16_t command, uint3
|
||||
if (command == 0x8B) {
|
||||
ses->channel.version = Version::DC_NTE;
|
||||
ses->log.info("Version changed to DC_NTE");
|
||||
ses->config.specific_version = SPECIFIC_VERSION_DC_NTE;
|
||||
const auto& cmd = check_size_t<C_Login_DCNTE_8B>(data, sizeof(C_LoginExtended_DCNTE_8B));
|
||||
ses->login = s->account_index->from_dc_nte_credentials(cmd.serial_number.decode(), cmd.access_key.decode(), false);
|
||||
ses->sub_version = cmd.sub_version;
|
||||
@@ -286,6 +287,9 @@ void ProxyServer::UnlinkedSession::on_input(Channel& ch, uint16_t command, uint3
|
||||
} else if (command == 0x93) { // 11/2000 proto through DC V1
|
||||
ses->channel.version = Version::DC_V1;
|
||||
ses->log.info("Version changed to DC_V1");
|
||||
if (specific_version_is_indeterminate(ses->config.specific_version)) {
|
||||
ses->config.specific_version = SPECIFIC_VERSION_DC_V1_INDETERMINATE;
|
||||
}
|
||||
const auto& cmd = check_size_t<C_LoginV1_DC_93>(data);
|
||||
ses->login = s->account_index->from_dc_credentials(
|
||||
stoul(cmd.serial_number.decode(), nullptr, 16), cmd.access_key.decode(), cmd.name.decode(), false);
|
||||
@@ -298,11 +302,15 @@ void ProxyServer::UnlinkedSession::on_input(Channel& ch, uint16_t command, uint3
|
||||
if (cmd.sub_version >= 0x30) {
|
||||
ses->log.info("Version changed to GC_NTE");
|
||||
ses->channel.version = Version::GC_NTE;
|
||||
ses->config.specific_version = SPECIFIC_VERSION_GC_NTE;
|
||||
ses->login = s->account_index->from_gc_credentials(
|
||||
stoul(cmd.serial_number.decode(), nullptr, 16), cmd.access_key.decode(), nullptr, cmd.name.decode(), false);
|
||||
} else { // DC V2
|
||||
ses->log.info("Version changed to DC_V2");
|
||||
ses->channel.version = Version::DC_V2;
|
||||
if (specific_version_is_indeterminate(ses->config.specific_version)) {
|
||||
ses->config.specific_version = SPECIFIC_VERSION_DC_V2_INDETERMINATE;
|
||||
}
|
||||
ses->login = s->account_index->from_dc_credentials(
|
||||
stoul(cmd.serial_number.decode(), nullptr, 16), cmd.access_key.decode(), cmd.name.decode(), false);
|
||||
}
|
||||
@@ -345,6 +353,9 @@ void ProxyServer::UnlinkedSession::on_input(Channel& ch, uint16_t command, uint3
|
||||
if (cmd.sub_version >= 0x40) {
|
||||
ses->log.info("Version changed to GC_EP3");
|
||||
ses->channel.version = Version::GC_EP3;
|
||||
if (specific_version_is_indeterminate(ses->config.specific_version)) {
|
||||
ses->config.specific_version = SPECIFIC_VERSION_GC_EP3_INDETERMINATE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw runtime_error("command is not 9D or 9E");
|
||||
|
||||
+28
-7
@@ -341,9 +341,9 @@ static void send_main_menu(shared_ptr<Client> c) {
|
||||
if (!s->is_replay) {
|
||||
if (!s->function_code_index->patch_menu_empty(c->config.specific_version)) {
|
||||
main_menu->items.emplace_back(MainMenuItemID::PATCHES, "Patches",
|
||||
"Change game\nbehaviors", MenuItem::Flag::INVISIBLE_ON_DC | MenuItem::Flag::INVISIBLE_ON_PC | MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL);
|
||||
"Change game\nbehaviors", MenuItem::Flag::INVISIBLE_ON_PC | MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL);
|
||||
main_menu->items.emplace_back(MainMenuItemID::PATCH_SWITCHES, "Patch switches",
|
||||
"Automatically\napply patches every\ntime you connect", MenuItem::Flag::INVISIBLE_ON_DC | MenuItem::Flag::INVISIBLE_ON_PC | MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL);
|
||||
"Automatically\napply patches every\ntime you connect", MenuItem::Flag::INVISIBLE_ON_PC | MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL);
|
||||
}
|
||||
if (!s->dol_file_index->empty()) {
|
||||
main_menu->items.emplace_back(MainMenuItemID::PROGRAMS, "Programs",
|
||||
@@ -480,22 +480,32 @@ static void set_console_client_flags(shared_ptr<Client> c, uint32_t sub_version)
|
||||
if (sub_version <= 0x24) {
|
||||
c->channel.version = Version::DC_V1;
|
||||
c->log.info("Game version changed to DC_V1");
|
||||
if (specific_version_is_indeterminate(c->config.specific_version) || c->config.specific_version == SPECIFIC_VERSION_DC_11_2000_PROTOTYPE) {
|
||||
c->config.specific_version = SPECIFIC_VERSION_DC_V1_INDETERMINATE;
|
||||
}
|
||||
} else if (sub_version <= 0x28) {
|
||||
c->channel.version = Version::DC_V2;
|
||||
c->log.info("Game version changed to DC_V2");
|
||||
if (specific_version_is_indeterminate(c->config.specific_version)) {
|
||||
c->config.specific_version = SPECIFIC_VERSION_DC_V2_INDETERMINATE;
|
||||
}
|
||||
} else if (is_v3(c->version())) {
|
||||
c->channel.version = Version::GC_NTE;
|
||||
c->log.info("Game version changed to GC_NTE");
|
||||
c->config.specific_version = SPECIFIC_VERSION_GC_NTE;
|
||||
}
|
||||
} else {
|
||||
if (sub_version >= 0x40 && !is_ep3(c->version())) {
|
||||
c->channel.version = Version::GC_EP3;
|
||||
c->log.info("Game version changed to GC_EP3");
|
||||
if (specific_version_is_indeterminate(c->config.specific_version)) {
|
||||
c->config.specific_version = SPECIFIC_VERSION_GC_EP3_INDETERMINATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
c->config.set_flags_for_version(c->version(), sub_version);
|
||||
c->sub_version = sub_version;
|
||||
if (c->config.specific_version == default_specific_version_for_version(c->version(), -1)) {
|
||||
if (specific_version_is_indeterminate(c->config.specific_version)) {
|
||||
c->config.specific_version = default_specific_version_for_version(c->version(), sub_version);
|
||||
}
|
||||
}
|
||||
@@ -534,6 +544,7 @@ static void on_88_DCNTE(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
|
||||
auto s = c->require_server_state();
|
||||
|
||||
c->channel.version = Version::DC_NTE;
|
||||
c->config.specific_version = SPECIFIC_VERSION_DC_NTE;
|
||||
c->config.set_flags_for_version(c->version(), -1);
|
||||
c->log.info("Game version changed to DC_NTE");
|
||||
|
||||
@@ -560,6 +571,7 @@ static void on_8B_DCNTE(shared_ptr<Client> c, uint16_t, uint32_t, string& data)
|
||||
c->channel.version = Version::DC_NTE;
|
||||
c->channel.language = cmd.language;
|
||||
c->config.set_flags_for_version(c->version(), -1);
|
||||
c->config.specific_version = SPECIFIC_VERSION_DC_NTE;
|
||||
c->log.info("Game version changed to DC_NTE");
|
||||
|
||||
try {
|
||||
@@ -592,6 +604,9 @@ static void on_90_DC(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
|
||||
c->channel.version = Version::DC_V1;
|
||||
c->config.set_flags_for_version(c->version(), -1);
|
||||
if (specific_version_is_indeterminate(c->config.specific_version) || c->config.specific_version == SPECIFIC_VERSION_DC_11_2000_PROTOTYPE) {
|
||||
c->config.specific_version = SPECIFIC_VERSION_DC_V1_INDETERMINATE;
|
||||
}
|
||||
c->log.info("Game version changed to DC_V1");
|
||||
|
||||
string serial_number_str = cmd.serial_number.decode();
|
||||
@@ -624,6 +639,9 @@ static void on_92_DC(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
// client is actually DCv1 and not the prototype.
|
||||
c->config.set_flag(Client::Flag::CHECKED_FOR_DC_V1_PROTOTYPE);
|
||||
c->channel.version = Version::DC_V1;
|
||||
if (specific_version_is_indeterminate(c->config.specific_version) || c->config.specific_version == SPECIFIC_VERSION_DC_11_2000_PROTOTYPE) {
|
||||
c->config.specific_version = SPECIFIC_VERSION_DC_V1_INDETERMINATE;
|
||||
}
|
||||
c->log.info("Game version changed to DC_V1");
|
||||
send_command(c, 0x92, 0x01);
|
||||
}
|
||||
@@ -680,6 +698,9 @@ static void on_93_DC(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
send_command(c, 0x90, 0x01);
|
||||
c->config.set_flag(Client::Flag::CHECKED_FOR_DC_V1_PROTOTYPE);
|
||||
c->channel.version = Version::DC_V1_11_2000_PROTOTYPE;
|
||||
if (specific_version_is_indeterminate(c->config.specific_version)) {
|
||||
c->config.specific_version = SPECIFIC_VERSION_DC_11_2000_PROTOTYPE;
|
||||
}
|
||||
c->log.info("Game version changed to DC_V1_11_2000_PROTOTYPE (will be changed to V1 if 92 is received)");
|
||||
} else {
|
||||
on_login_complete(c);
|
||||
@@ -3006,16 +3027,16 @@ 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 == 0x00000000) {
|
||||
c->config.specific_version = 0x33534A30; // 3SJ0
|
||||
if (specific_version_is_indeterminate(c->config.specific_version)) {
|
||||
c->config.specific_version = SPECIFIC_VERSION_GC_EP3_JP; // 3SJ0
|
||||
}
|
||||
} else {
|
||||
if (is_ep3(c->version())) {
|
||||
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 == default_specific_version_for_version(Version::GC_EP3, -1)) {
|
||||
c->config.specific_version = 0x33534A54; // 3SJT
|
||||
if (specific_version_is_indeterminate(c->config.specific_version)) {
|
||||
c->config.specific_version = SPECIFIC_VERSION_GC_EP3_NTE;
|
||||
}
|
||||
c->convert_account_to_temporary_if_nte();
|
||||
}
|
||||
|
||||
+35
-18
@@ -207,56 +207,73 @@ uint32_t default_specific_version_for_version(Version version, int64_t sub_versi
|
||||
// VersionDetectDC, VersionDetectGC, or VersionDetectXB call.
|
||||
switch (version) {
|
||||
case Version::DC_NTE:
|
||||
return 0x314F4A31;
|
||||
return SPECIFIC_VERSION_DC_NTE;
|
||||
case Version::DC_V1_11_2000_PROTOTYPE:
|
||||
return 0x314F4A32;
|
||||
return SPECIFIC_VERSION_DC_11_2000_PROTOTYPE;
|
||||
case Version::DC_V1:
|
||||
return 0x00000000; // Need to send VersionDetectDC (but can't on V1; rip)
|
||||
return SPECIFIC_VERSION_DC_V1_INDETERMINATE; // Need to send VersionDetectDC (but can't on V1; rip)
|
||||
case Version::DC_V2:
|
||||
return SPECIFIC_VERSION_DC_V2_INDETERMINATE; // Need to send VersionDetectDC
|
||||
case Version::PC_V2:
|
||||
return SPECIFIC_VERSION_PC_V2;
|
||||
case Version::GC_NTE:
|
||||
return 0x334F4A54; // 3OJT
|
||||
return SPECIFIC_VERSION_GC_NTE; // 3OJT
|
||||
case Version::GC_V3:
|
||||
switch (sub_version) {
|
||||
case 0x32: // GC Ep1&2 EU 50Hz
|
||||
case 0x33: // GC Ep1&2 EU 60Hz
|
||||
return 0x334F5030; // 3OP0
|
||||
return SPECIFIC_VERSION_GC_V3_EU; // 3OP0
|
||||
case 0x36: // GC Ep1&2 US v1.2 (Plus)
|
||||
return 0x334F4532; // 3OE2
|
||||
case 0x39: // GC Ep1&2 JP v1.5 (Plus)
|
||||
return 0x334F4A35; // 3OJ5
|
||||
return SPECIFIC_VERSION_GC_V3_US_12; // 3OE2
|
||||
case 0x34: // GC Ep1&2 JP v1.3
|
||||
return 0x334F4A33; // 3OJ3
|
||||
return SPECIFIC_VERSION_GC_V3_JP_13; // 3OJ3
|
||||
case 0x35: // GC Ep1&2 JP v1.4 (Plus)
|
||||
return 0x334F4A34; // 3OJ4
|
||||
return SPECIFIC_VERSION_GC_V3_JP_14; // 3OJ4
|
||||
case 0x39: // GC Ep1&2 JP v1.5 (Plus)
|
||||
return SPECIFIC_VERSION_GC_V3_JP_15; // 3OJ5
|
||||
case -1: // Initial check (before sub_version recognition)
|
||||
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 0x00000000; // Need to send VersionDetectGC
|
||||
return SPECIFIC_VERSION_GC_V3_INDETERMINATE; // Need to send VersionDetectGC
|
||||
}
|
||||
throw logic_error("this should be impossible");
|
||||
case Version::GC_EP3_NTE:
|
||||
return 0x33534A54; // 3SJT
|
||||
return SPECIFIC_VERSION_GC_EP3_NTE; // 3SJT
|
||||
case Version::GC_EP3:
|
||||
switch (sub_version) {
|
||||
case 0x41: // GC Ep3 US
|
||||
return 0x33534530; // 3SE0
|
||||
return SPECIFIC_VERSION_GC_EP3_US; // 3SE0
|
||||
case 0x42: // GC Ep3 EU 50Hz
|
||||
case 0x43: // GC Ep3 EU 60Hz
|
||||
return 0x33535030; // 3SP0
|
||||
return SPECIFIC_VERSION_GC_EP3_EU; // 3SP0
|
||||
case -1: // Initial check (before sub_version recognition)
|
||||
case 0x40: // GC Ep3 trial and GC Ep3 JP
|
||||
default:
|
||||
return 0x00000000; // Need to send VersionDetectGC
|
||||
return SPECIFIC_VERSION_GC_EP3_INDETERMINATE; // Need to send VersionDetectGC
|
||||
}
|
||||
case Version::XB_V3:
|
||||
return 0x344F0000;
|
||||
return SPECIFIC_VERSION_XB_V3_INDETERMINATE;
|
||||
case Version::BB_V4:
|
||||
return 0x354F3030;
|
||||
return SPECIFIC_VERSION_BB_V4_INDETERMINATE;
|
||||
default:
|
||||
return 0x00000000;
|
||||
return SPECIFIC_VERSION_INDETERMINATE;
|
||||
}
|
||||
}
|
||||
|
||||
bool specific_version_is_indeterminate(uint32_t specific_version) {
|
||||
return ((specific_version & 0x000000FF) == 0);
|
||||
}
|
||||
|
||||
bool specific_version_is_dc(uint32_t specific_version) {
|
||||
// All v1 and v2 specific_versions are DC except 324F4A57 (2OJW), which is PC
|
||||
uint8_t major_version = specific_version >> 24;
|
||||
if (major_version < 0x31 || major_version > 0x32) {
|
||||
return false;
|
||||
}
|
||||
return (specific_version != 0x324F4A57);
|
||||
}
|
||||
|
||||
bool specific_version_is_gc(uint32_t specific_version) {
|
||||
// GC specific_versions are 3GRV, where G is [OE], R is [JEP], V is [0-9T]
|
||||
if ((specific_version & 0xFF000000) != 0x33000000) {
|
||||
|
||||
@@ -140,7 +140,30 @@ inline bool uses_utf16(Version version) {
|
||||
(version == Version::BB_V4);
|
||||
}
|
||||
|
||||
constexpr uint32_t SPECIFIC_VERSION_DC_NTE = 0x314F4A31; // 1OJ1
|
||||
constexpr uint32_t SPECIFIC_VERSION_DC_11_2000_PROTOTYPE = 0x314F4A32; // 1OJ2
|
||||
constexpr uint32_t SPECIFIC_VERSION_DC_V1_INDETERMINATE = 0x31000000; // 1___
|
||||
constexpr uint32_t SPECIFIC_VERSION_DC_V2_INDETERMINATE = 0x32000000; // 2___
|
||||
constexpr uint32_t SPECIFIC_VERSION_PC_V2 = 0x324F4A57; // 2OJW
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_NTE = 0x334F4A54; // 3OJT
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_V3_EU = 0x334F5030; // 3OP0
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_V3_US_12 = 0x334F4532; // 3OE2
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_V3_JP_13 = 0x334F4A33; // 3OJ3
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_V3_JP_14 = 0x334F4A34; // 3OJ4
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_V3_JP_15 = 0x334F4A35; // 3OJ5
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_V3_INDETERMINATE = 0x334F0000; // 3O__
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_EP3_INDETERMINATE = 0x33534A00; // 3SJ_
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_EP3_NTE = 0x33534A54; // 3SJT
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_EP3_JP = 0x33534A30; // 3SJ0
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_EP3_US = 0x33534530; // 3SE0
|
||||
constexpr uint32_t SPECIFIC_VERSION_GC_EP3_EU = 0x33535030; // 3SP0
|
||||
constexpr uint32_t SPECIFIC_VERSION_XB_V3_INDETERMINATE = 0x344F0000; // 4O__
|
||||
constexpr uint32_t SPECIFIC_VERSION_BB_V4_INDETERMINATE = 0x35000000; // 5___
|
||||
constexpr uint32_t SPECIFIC_VERSION_INDETERMINATE = 0x00000000; // ____
|
||||
|
||||
uint32_t default_specific_version_for_version(Version version, int64_t sub_version);
|
||||
bool specific_version_is_indeterminate(uint32_t specific_version);
|
||||
bool specific_version_is_dc(uint32_t specific_version);
|
||||
bool specific_version_is_gc(uint32_t specific_version);
|
||||
bool specific_version_is_xb(uint32_t specific_version);
|
||||
bool specific_version_is_bb(uint32_t specific_version);
|
||||
|
||||
Reference in New Issue
Block a user