update client functions for eventual pc v2 semantics
This commit is contained in:
+3
-3
@@ -1373,7 +1373,7 @@ ChatCommandDefinition cc_loadchar(
|
||||
// TODO: Support extended player info on other versions
|
||||
auto s = a.c->require_server_state();
|
||||
if (!a.c->config.check_flag(Client::Flag::HAS_SEND_FUNCTION_CALL) ||
|
||||
a.c->config.check_flag(Client::Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY)) {
|
||||
!a.c->config.check_flag(Client::Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE)) {
|
||||
throw precondition_failed_printf("Can\'t load character\ndata on this game\nversion");
|
||||
}
|
||||
|
||||
@@ -1588,7 +1588,7 @@ ChatCommandDefinition cc_patch(
|
||||
send_function_call(c, fn, pca.label_writes);
|
||||
c->function_call_response_queue.emplace_back(empty_function_call_response_handler);
|
||||
} catch (const out_of_range&) {
|
||||
throw precondition_failed("Invalid patch name");
|
||||
send_text_message(c, "$C6Invalid patch name");
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -1607,7 +1607,7 @@ ChatCommandDefinition cc_patch(
|
||||
// Don't forward the patch response to the server
|
||||
ses->function_call_return_handler_queue.emplace_back(empty_function_call_response_handler);
|
||||
} catch (const out_of_range&) {
|
||||
throw precondition_failed("Invalid patch name");
|
||||
send_text_message(ses->client_channel, "$C6Invalid patch name");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+12
-2
@@ -51,20 +51,23 @@ void Client::Config::set_flags_for_version(Version version, int64_t sub_version)
|
||||
case Version::DC_V2:
|
||||
this->set_flag(Flag::NO_D6);
|
||||
this->set_flag(Flag::HAS_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH);
|
||||
break;
|
||||
case Version::PC_NTE:
|
||||
case Version::PC_V2:
|
||||
this->set_flag(Flag::NO_D6);
|
||||
this->set_flag(Flag::HAS_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY);
|
||||
// SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE not set here
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH);
|
||||
break;
|
||||
case Version::GC_NTE:
|
||||
this->set_flag(Flag::HAS_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE);
|
||||
break;
|
||||
case Version::GC_EP3_NTE:
|
||||
this->set_flag(Flag::HAS_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE);
|
||||
this->set_flag(Flag::ENCRYPTED_SEND_FUNCTION_CALL);
|
||||
break;
|
||||
case Version::GC_V3:
|
||||
@@ -76,6 +79,7 @@ void Client::Config::set_flags_for_version(Version version, int64_t sub_version)
|
||||
// TODO: Do all versions of XB need this flag? US does, at least.
|
||||
this->set_flag(Flag::NO_D6_AFTER_LOBBY);
|
||||
this->set_flag(Flag::HAS_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH);
|
||||
break;
|
||||
default:
|
||||
@@ -95,27 +99,32 @@ void Client::Config::set_flags_for_version(Version version, int64_t sub_version)
|
||||
case 0x28: // DCv2 EU 60Hz (presumably)
|
||||
this->set_flag(Flag::NO_D6);
|
||||
this->set_flag(Flag::HAS_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH);
|
||||
break;
|
||||
case 0x29: // PC
|
||||
this->set_flag(Flag::NO_D6);
|
||||
this->set_flag(Flag::HAS_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY);
|
||||
// SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE not set here
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH);
|
||||
this->set_flag(Flag::CAN_RECEIVE_ENABLE_B2_QUEST);
|
||||
break;
|
||||
case 0x30: // GC Ep1&2 GameJam demo, GC Ep1&2 Trial Edition, GC Ep1&2 JP v1.2, XB JP
|
||||
case 0x31: // GC Ep1&2 US v1.0, GC US v1.1, XB US
|
||||
this->set_flag(Flag::HAS_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE);
|
||||
break;
|
||||
case 0x32: // GC Ep1&2 EU 50Hz
|
||||
case 0x33: // GC Ep1&2 EU 60Hz
|
||||
case 0x34: // GC Ep1&2 JP v1.3
|
||||
this->set_flag(Flag::NO_D6_AFTER_LOBBY);
|
||||
this->set_flag(Flag::HAS_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE);
|
||||
break;
|
||||
case 0x35: // GC Ep1&2 JP v1.4 (Plus)
|
||||
this->set_flag(Flag::NO_D6_AFTER_LOBBY);
|
||||
this->set_flag(Flag::HAS_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE);
|
||||
this->set_flag(Flag::ENCRYPTED_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH);
|
||||
break;
|
||||
@@ -130,6 +139,7 @@ void Client::Config::set_flags_for_version(Version version, int64_t sub_version)
|
||||
case 0x40: // GC Ep3 JP and Trial Edition (and BB)
|
||||
this->set_flag(Flag::NO_D6_AFTER_LOBBY);
|
||||
this->set_flag(Flag::HAS_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE);
|
||||
this->set_flag(Flag::ENCRYPTED_SEND_FUNCTION_CALL);
|
||||
this->set_flag(Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH);
|
||||
// sub_version can't be used to tell JP final and Trial Edition apart; we
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public:
|
||||
// Flags describing the behavior for send_function_call
|
||||
HAS_SEND_FUNCTION_CALL = 0x0000000000001000,
|
||||
ENCRYPTED_SEND_FUNCTION_CALL = 0x0000000000002000,
|
||||
SEND_FUNCTION_CALL_CHECKSUM_ONLY = 0x0000000000004000,
|
||||
SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE = 0x0000000000004000,
|
||||
SEND_FUNCTION_CALL_NO_CACHE_PATCH = 0x0000000000008000,
|
||||
CAN_RECEIVE_ENABLE_B2_QUEST = 0x0000000000020000,
|
||||
AWAITING_ENABLE_B2_QUEST = 0x0000000000040000, // Server-side only
|
||||
|
||||
@@ -311,7 +311,9 @@ FunctionCodeIndex::FunctionCodeIndex(const string& directory) {
|
||||
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)) {
|
||||
} else if (specific_version_is_pc_v2(specific_version) ||
|
||||
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");
|
||||
@@ -370,7 +372,7 @@ shared_ptr<const Menu> FunctionCodeIndex::patch_menu(uint32_t specific_version)
|
||||
fn->menu_item_id,
|
||||
fn->long_name.empty() ? fn->short_name : fn->long_name,
|
||||
fn->description,
|
||||
MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL);
|
||||
MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -389,7 +391,7 @@ shared_ptr<const Menu> FunctionCodeIndex::patch_switches_menu(
|
||||
string name;
|
||||
name.push_back(auto_patches_enabled.count(fn->short_name) ? '*' : '-');
|
||||
name += fn->long_name.empty() ? fn->short_name : fn->long_name;
|
||||
ret->items.emplace_back(fn->menu_item_id, name, fn->description, MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL);
|
||||
ret->items.emplace_back(fn->menu_item_id, name, fn->description, MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -479,7 +481,7 @@ DOLFileIndex::DOLFileIndex(const string& directory) {
|
||||
this->name_to_file.emplace(dol->name, dol);
|
||||
this->item_id_to_file.emplace_back(dol);
|
||||
|
||||
menu->items.emplace_back(dol->menu_item_id, dol->name, description, MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL);
|
||||
menu->items.emplace_back(dol->menu_item_id, dol->name, description, MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE);
|
||||
|
||||
} catch (const exception& e) {
|
||||
function_compiler_log.warning("Failed to load DOL file %s: %s", filename.c_str(), e.what());
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ struct MenuItem {
|
||||
XB_ONLY = INVISIBLE_ON_DC | INVISIBLE_ON_PC | INVISIBLE_ON_GC | INVISIBLE_ON_BB,
|
||||
BB_ONLY = INVISIBLE_ON_DC | INVISIBLE_ON_PC | INVISIBLE_ON_GC | INVISIBLE_ON_XB,
|
||||
REQUIRES_MESSAGE_BOXES = 0x100,
|
||||
REQUIRES_SEND_FUNCTION_CALL = 0x200,
|
||||
REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE = 0x200,
|
||||
REQUIRES_SAVE_DISABLED = 0x400,
|
||||
INVISIBLE_IN_INFO_MENU = 0x800,
|
||||
};
|
||||
|
||||
+101
-17
@@ -374,13 +374,13 @@ 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_PC | MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL);
|
||||
"Change game\nbehaviors", MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE);
|
||||
main_menu->items.emplace_back(MainMenuItemID::PATCH_SWITCHES, "Patch switches",
|
||||
"Automatically\napply patches every\ntime you connect", MenuItem::Flag::INVISIBLE_ON_PC | MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL);
|
||||
"Automatically\napply patches every\ntime you connect", MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE);
|
||||
}
|
||||
if (!s->dol_file_index->empty()) {
|
||||
main_menu->items.emplace_back(MainMenuItemID::PROGRAMS, "Programs",
|
||||
"Run GameCube\nprograms", MenuItem::Flag::GC_ONLY | MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL | MenuItem::Flag::REQUIRES_SAVE_DISABLED);
|
||||
"Run GameCube\nprograms", MenuItem::Flag::GC_ONLY | MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE | MenuItem::Flag::REQUIRES_SAVE_DISABLED);
|
||||
}
|
||||
}
|
||||
main_menu->items.emplace_back(MainMenuItemID::DISCONNECT, "Disconnect",
|
||||
@@ -427,30 +427,44 @@ void on_login_complete(shared_ptr<Client> c) {
|
||||
auto s = c->require_server_state();
|
||||
|
||||
if (c->config.check_flag(Client::Flag::CAN_RECEIVE_ENABLE_B2_QUEST) &&
|
||||
!c->config.check_flag(Client::Flag::HAS_SEND_FUNCTION_CALL)) {
|
||||
(!c->config.check_flag(Client::Flag::HAS_SEND_FUNCTION_CALL) ||
|
||||
!c->config.check_flag(Client::Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE))) {
|
||||
shared_ptr<const Quest> q;
|
||||
try {
|
||||
int64_t quest_num = s->enable_send_function_call_quest_numbers.at(c->config.specific_version);
|
||||
q = s->default_quest_index->get(quest_num);
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
if (q) {
|
||||
if (!q) {
|
||||
c->log.info("There is no quest to enable server function calls for specific version %08" PRIX32, c->config.specific_version);
|
||||
} else if (q) {
|
||||
auto vq = q->version(is_ep3(c->version()) ? Version::GC_V3 : c->version(), 1);
|
||||
if (vq) {
|
||||
c->config.set_flag(Client::Flag::HAS_SEND_FUNCTION_CALL);
|
||||
c->config.set_flag(Client::Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE);
|
||||
c->config.set_flag(Client::Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH);
|
||||
c->config.set_flag(Client::Flag::AWAITING_ENABLE_B2_QUEST);
|
||||
send_update_client_config(c, false);
|
||||
|
||||
c->log.info("Sending %c version of quest \"%s\"", char_for_language_code(vq->language), vq->name.c_str());
|
||||
string bin_filename = vq->bin_filename();
|
||||
string dat_filename = vq->dat_filename();
|
||||
string xb_filename = vq->xb_filename();
|
||||
send_open_quest_file(c, bin_filename, bin_filename, xb_filename, vq->quest_number, QuestFileType::ONLINE, vq->bin_contents);
|
||||
send_open_quest_file(c, dat_filename, dat_filename, xb_filename, vq->quest_number, QuestFileType::ONLINE, vq->dat_contents);
|
||||
// PCv2 will crash if it receives an online quest file while it's
|
||||
// not in a game, so we have to put it into a fake game first
|
||||
if (c->version() == Version::PC_V2) {
|
||||
S_JoinGame_PC_64 cmd;
|
||||
auto& lobby_data = cmd.lobby_data[0];
|
||||
lobby_data.player_tag = 0x00010000;
|
||||
lobby_data.guild_card_number = c->login->account->account_id;
|
||||
send_command_t(c, 0x64, 0x01, cmd);
|
||||
} else {
|
||||
c->log.info("Sending %c version of quest \"%s\"", char_for_language_code(vq->language), vq->name.c_str());
|
||||
string bin_filename = vq->bin_filename();
|
||||
string dat_filename = vq->dat_filename();
|
||||
string xb_filename = vq->xb_filename();
|
||||
send_open_quest_file(c, bin_filename, bin_filename, xb_filename, vq->quest_number, QuestFileType::ONLINE, vq->bin_contents);
|
||||
send_open_quest_file(c, dat_filename, dat_filename, xb_filename, vq->quest_number, QuestFileType::ONLINE, vq->dat_contents);
|
||||
|
||||
if (!is_v1_or_v2(c->version())) {
|
||||
send_command(c, 0xAC, 0x00);
|
||||
if (!is_v1_or_v2(c->version())) {
|
||||
send_command(c, 0xAC, 0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1066,7 +1080,43 @@ static void on_9D_9E(shared_ptr<Client> c, uint16_t command, uint32_t, string& d
|
||||
c->should_disconnect = true;
|
||||
} else {
|
||||
send_update_client_config(c, true);
|
||||
on_login_complete(c);
|
||||
// On PCv2, we send a B2 command to get the client's specific_version and
|
||||
// check whether it has patch support or not; we'll call on_login_complete
|
||||
// once we receive the B3 response
|
||||
if (c->version() == Version::PC_V2) {
|
||||
try {
|
||||
auto code = s->function_code_index->name_to_function.at("ReturnTokenX86");
|
||||
send_function_call(c, code, {{"token", c->login->account->account_id}}, nullptr, 0, 0x00400000, 0x0000E000, 0, true);
|
||||
c->function_call_response_queue.emplace_back([wc = weak_ptr<Client>(c)](uint32_t return_value, uint32_t checksum) -> void {
|
||||
auto c = wc.lock();
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
if (!c->login) {
|
||||
throw logic_error("received PC_V2 version detect response with no login");
|
||||
}
|
||||
if (return_value == c->login->account->account_id) {
|
||||
// Client already has the patch that enables patches
|
||||
c->config.set_flag(Client::Flag::HAS_SEND_FUNCTION_CALL);
|
||||
c->config.set_flag(Client::Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE);
|
||||
c->config.set_flag(Client::Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH);
|
||||
}
|
||||
if (checksum == 0x3677024C) {
|
||||
c->config.specific_version = SPECIFIC_VERSION_PC_V2_DEFAULT;
|
||||
c->log.info("Version detected as %08" PRIX32 " from PE header checksum %08" PRIX32,
|
||||
c->config.specific_version, checksum);
|
||||
} else {
|
||||
c->config.specific_version = SPECIFIC_VERSION_PC_V2_INDETERMINATE;
|
||||
c->log.info("Version cannot be determined from PE header checksum %08" PRIX32, checksum);
|
||||
}
|
||||
on_login_complete(c);
|
||||
});
|
||||
} catch (const out_of_range&) {
|
||||
on_login_complete(c);
|
||||
}
|
||||
} else {
|
||||
on_login_complete(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4714,15 +4764,49 @@ static void on_8A(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
|
||||
} else {
|
||||
check_size_v(data.size(), 0);
|
||||
auto l = c->require_lobby();
|
||||
send_lobby_name(c, l->name.c_str());
|
||||
auto l = c->lobby.lock();
|
||||
if (!l) {
|
||||
if (c->config.check_flag(Client::Flag::AWAITING_ENABLE_B2_QUEST)) {
|
||||
send_lobby_name(c, "");
|
||||
} else {
|
||||
throw std::runtime_error("received 8A command from client not in any lobby");
|
||||
}
|
||||
} else {
|
||||
send_lobby_name(c, l->name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void on_6F(shared_ptr<Client> c, uint16_t command, uint32_t, string& data) {
|
||||
check_size_v(data.size(), 0);
|
||||
|
||||
auto l = c->require_lobby();
|
||||
auto l = c->lobby.lock();
|
||||
if (!l) {
|
||||
if (!c->config.check_flag(Client::Flag::AWAITING_ENABLE_B2_QUEST)) {
|
||||
throw runtime_error("client is not in any lobby and is not awaiting a patch enabler quest");
|
||||
}
|
||||
auto s = c->require_server_state();
|
||||
shared_ptr<const Quest> q;
|
||||
try {
|
||||
int64_t quest_num = s->enable_send_function_call_quest_numbers.at(c->config.specific_version);
|
||||
q = s->default_quest_index->get(quest_num);
|
||||
} catch (const out_of_range&) {
|
||||
throw std::logic_error("cannot find patch enable quest after it was previously found during login");
|
||||
}
|
||||
auto vq = q->version(is_ep3(c->version()) ? Version::GC_V3 : c->version(), 1);
|
||||
if (!vq) {
|
||||
throw std::logic_error("cannot find patch enable quest version after it was previously found during login");
|
||||
}
|
||||
c->log.info("Sending %c version of quest \"%s\"", char_for_language_code(vq->language), vq->name.c_str());
|
||||
string bin_filename = vq->bin_filename();
|
||||
string dat_filename = vq->dat_filename();
|
||||
string xb_filename = vq->xb_filename();
|
||||
send_open_quest_file(c, bin_filename, bin_filename, xb_filename, vq->quest_number, QuestFileType::ONLINE, vq->bin_contents);
|
||||
send_open_quest_file(c, dat_filename, dat_filename, xb_filename, vq->quest_number, QuestFileType::ONLINE, vq->dat_contents);
|
||||
return;
|
||||
}
|
||||
// Now l is not null
|
||||
|
||||
if (!l->is_game()) {
|
||||
throw runtime_error("client sent ready command outside of game");
|
||||
}
|
||||
|
||||
+14
-8
@@ -335,6 +335,7 @@ void prepare_client_for_patches(shared_ptr<Client> c, function<void()> on_comple
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* version_detect_name = nullptr;
|
||||
if (c->version() == Version::DC_V2) {
|
||||
version_detect_name = "VersionDetectDC";
|
||||
@@ -447,7 +448,8 @@ void send_function_call(
|
||||
size_t suffix_size,
|
||||
uint32_t checksum_addr,
|
||||
uint32_t checksum_size,
|
||||
uint32_t override_relocations_offset) {
|
||||
uint32_t override_relocations_offset,
|
||||
bool ignore_actually_runs_code_flag) {
|
||||
return send_function_call(
|
||||
c->channel,
|
||||
c->config,
|
||||
@@ -457,7 +459,8 @@ void send_function_call(
|
||||
suffix_size,
|
||||
checksum_addr,
|
||||
checksum_size,
|
||||
override_relocations_offset);
|
||||
override_relocations_offset,
|
||||
ignore_actually_runs_code_flag);
|
||||
}
|
||||
|
||||
void send_function_call(
|
||||
@@ -469,11 +472,14 @@ void send_function_call(
|
||||
size_t suffix_size,
|
||||
uint32_t checksum_addr,
|
||||
uint32_t checksum_size,
|
||||
uint32_t override_relocations_offset) {
|
||||
uint32_t override_relocations_offset,
|
||||
bool ignore_actually_runs_code_flag) {
|
||||
if (!client_config.check_flag(Client::Flag::HAS_SEND_FUNCTION_CALL)) {
|
||||
throw logic_error("client does not support function calls");
|
||||
}
|
||||
if (code.get() && client_config.check_flag(Client::Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY)) {
|
||||
if (!ignore_actually_runs_code_flag &&
|
||||
code.get() &&
|
||||
!client_config.check_flag(Client::Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE)) {
|
||||
throw logic_error("client only supports checksums in send_function_call");
|
||||
}
|
||||
|
||||
@@ -508,7 +514,7 @@ bool send_protected_command(std::shared_ptr<Client> c, const void* data, size_t
|
||||
auto s = c->require_server_state();
|
||||
if (!s->enable_v3_v4_protected_subcommands ||
|
||||
!c->config.check_flag(Client::Flag::HAS_SEND_FUNCTION_CALL) ||
|
||||
c->config.check_flag(Client::Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY)) {
|
||||
!c->config.check_flag(Client::Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1426,8 +1432,8 @@ void send_menu_t(shared_ptr<Client> c, shared_ptr<const Menu> menu, bool is_info
|
||||
if (item.flags & MenuItem::Flag::REQUIRES_MESSAGE_BOXES) {
|
||||
is_visible &= !c->config.check_flag(Client::Flag::NO_D6);
|
||||
}
|
||||
if (item.flags & MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL) {
|
||||
is_visible &= c->config.check_flag(Client::Flag::HAS_SEND_FUNCTION_CALL);
|
||||
if (item.flags & MenuItem::Flag::REQUIRES_SEND_FUNCTION_CALL_RUNS_CODE) {
|
||||
is_visible &= (c->config.check_flag(Client::Flag::HAS_SEND_FUNCTION_CALL) && c->config.check_flag(Client::Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE));
|
||||
}
|
||||
if (item.flags & MenuItem::Flag::REQUIRES_SAVE_DISABLED) {
|
||||
is_visible &= !c->config.check_flag(Client::Flag::SAVE_ENABLED);
|
||||
@@ -2402,7 +2408,7 @@ void send_get_player_info(shared_ptr<Client> c, bool request_extended) {
|
||||
|
||||
if (request_extended &&
|
||||
c->config.check_flag(Client::Flag::HAS_SEND_FUNCTION_CALL) &&
|
||||
!c->config.check_flag(Client::Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY)) {
|
||||
c->config.check_flag(Client::Flag::SEND_FUNCTION_CALL_ACTUALLY_RUNS_CODE)) {
|
||||
auto s = c->require_server_state();
|
||||
prepare_client_for_patches(c, [wc = weak_ptr<Client>(c)]() {
|
||||
auto c = wc.lock();
|
||||
|
||||
+4
-2
@@ -169,7 +169,8 @@ void send_function_call(
|
||||
size_t suffix_size = 0,
|
||||
uint32_t checksum_addr = 0,
|
||||
uint32_t checksum_size = 0,
|
||||
uint32_t override_relocations_offset = 0);
|
||||
uint32_t override_relocations_offset = 0,
|
||||
bool ignore_actually_runs_code_flag = false);
|
||||
void send_function_call(
|
||||
std::shared_ptr<Client> c,
|
||||
std::shared_ptr<const CompiledFunctionCode> code,
|
||||
@@ -178,7 +179,8 @@ void send_function_call(
|
||||
size_t suffix_size = 0,
|
||||
uint32_t checksum_addr = 0,
|
||||
uint32_t checksum_size = 0,
|
||||
uint32_t override_relocations_offset = 0);
|
||||
uint32_t override_relocations_offset = 0,
|
||||
bool ignore_actually_runs_code_flag = false);
|
||||
bool send_protected_command(std::shared_ptr<Client> c, const void* data, size_t size, bool echo_to_lobby);
|
||||
|
||||
void send_reconnect(std::shared_ptr<Client> c, uint32_t address, uint16_t port);
|
||||
|
||||
+6
-2
@@ -253,7 +253,7 @@ uint32_t default_specific_version_for_version(Version version, int64_t sub_versi
|
||||
case Version::DC_V2:
|
||||
return SPECIFIC_VERSION_DC_V2_INDETERMINATE; // 2___; need to send VersionDetectDC
|
||||
case Version::PC_V2:
|
||||
return SPECIFIC_VERSION_PC_V2; // 2OJW
|
||||
return SPECIFIC_VERSION_PC_V2_INDETERMINATE; // 2OJ_; need to send checksum command
|
||||
case Version::GC_NTE:
|
||||
return SPECIFIC_VERSION_GC_NTE; // 3OJT
|
||||
case Version::GC_V3:
|
||||
@@ -310,7 +310,11 @@ bool specific_version_is_dc(uint32_t specific_version) {
|
||||
if (major_version < 0x31 || major_version > 0x32) {
|
||||
return false;
|
||||
}
|
||||
return (specific_version != 0x324F4A57);
|
||||
return (specific_version != SPECIFIC_VERSION_PC_V2_DEFAULT);
|
||||
}
|
||||
|
||||
bool specific_version_is_pc_v2(uint32_t specific_version) {
|
||||
return (specific_version == SPECIFIC_VERSION_PC_V2_DEFAULT);
|
||||
}
|
||||
|
||||
bool specific_version_is_gc(uint32_t specific_version) {
|
||||
|
||||
+3
-1
@@ -191,7 +191,8 @@ constexpr uint32_t SPECIFIC_VERSION_DC_V1_US = 0x314F4546; // 1OEF
|
||||
constexpr uint32_t SPECIFIC_VERSION_DC_V1_EU_INDETERMINATE = 0x314F5000; // 1OP_
|
||||
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_PC_V2_INDETERMINATE = 0x324F4A00; // 2OJW
|
||||
constexpr uint32_t SPECIFIC_VERSION_PC_V2_DEFAULT = 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
|
||||
@@ -212,6 +213,7 @@ uint32_t default_sub_version_for_version(Version version);
|
||||
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_pc_v2(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