implement extended $loadchar on GC

This commit is contained in:
Martin Michelsen
2024-04-28 23:48:02 -07:00
parent ee21885f13
commit 31616954cc
27 changed files with 264 additions and 90 deletions
+46 -5
View File
@@ -1458,8 +1458,8 @@ static void server_command_savechar(shared_ptr<Client> c, const std::string& arg
}
static void server_command_loadchar(shared_ptr<Client> c, const std::string& args) {
if (!is_v1_or_v2(c->version())) {
send_text_message(c, "$C7This command can only\nbe used on v1 or v2");
if (!is_v1_or_v2(c->version()) && c->version() != Version::GC_V3) {
send_text_message(c, "$C7This command can only\nbe used on v1, v2,\nand GC");
return;
}
if (c->login->account->check_flag(Account::Flag::IS_SHARED_ACCOUNT)) {
@@ -1476,9 +1476,50 @@ static void server_command_loadchar(shared_ptr<Client> c, const std::string& arg
}
c->load_backup_character(c->login->account->account_id, index);
auto s = c->require_server_state();
send_player_leave_notification(l, c->lobby_client_id);
s->send_lobby_join_notifications(l, c);
if (c->version() == Version::GC_V3) {
// TODO: Support extended player info on other versions
auto s = c->require_server_state();
if (c->config.check_flag(Client::Flag::NO_SEND_FUNCTION_CALL) ||
c->config.check_flag(Client::Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY)) {
send_text_message_printf(c, "Can\'t load character\ndata on PSO Plus");
return;
}
auto gc_char = make_shared<PSOGCCharacterFile::Character>(c->character()->to_gc());
prepare_client_for_patches(c, [wc = weak_ptr<Client>(c), gc_char]() {
auto c = wc.lock();
if (!c) {
return;
}
try {
auto s = c->require_server_state();
auto fn = s->function_code_index->get_patch("SetExtendedPlayerInfo", c->config.specific_version);
send_function_call(c, fn, {}, gc_char.get(), sizeof(PSOGCCharacterFile::Character));
c->function_call_response_queue.emplace_back([wc = weak_ptr<Client>(c)](uint32_t, uint32_t) -> void {
auto c = wc.lock();
if (!c) {
return;
}
auto l = c->lobby.lock();
if (l) {
auto s = c->require_server_state();
send_player_leave_notification(l, c->lobby_client_id);
s->send_lobby_join_notifications(l, c);
}
});
} catch (const exception& e) {
c->log.warning("Failed to set extended player info: %s", e.what());
send_text_message_printf(c, "Failed to set\nplayer info:\n%s", e.what());
}
});
} else {
// On v1 and v2, the client will assign its character data from the lobby
// join command, so it suffices to just resend the join notification.
auto s = c->require_server_state();
send_player_leave_notification(l, c->lobby_client_id);
s->send_lobby_join_notifications(l, c);
}
}
static void server_command_save(shared_ptr<Client> c, const std::string&) {
+9 -5
View File
@@ -50,7 +50,8 @@ const char* name_for_architecture(CompiledFunctionCode::Architecture arch) {
template <typename FooterT>
string CompiledFunctionCode::generate_client_command_t(
const unordered_map<string, uint32_t>& label_writes,
const string& suffix,
const void* suffix_data,
size_t suffix_size,
uint32_t override_relocations_offset) const {
FooterT footer;
footer.num_relocations = this->relocation_deltas.size();
@@ -72,7 +73,9 @@ string CompiledFunctionCode::generate_client_command_t(
} else {
w.write(this->code);
}
w.write(suffix);
if (suffix_size) {
w.write(suffix_data, suffix_size);
}
while (w.size() & 3) {
w.put_u8(0);
}
@@ -101,14 +104,15 @@ string CompiledFunctionCode::generate_client_command_t(
string CompiledFunctionCode::generate_client_command(
const unordered_map<string, uint32_t>& label_writes,
const string& suffix,
const void* suffix_data,
size_t suffix_size,
uint32_t override_relocations_offset) const {
if (this->arch == Architecture::POWERPC) {
return this->generate_client_command_t<S_ExecuteCode_Footer_GC_B2>(
label_writes, suffix, override_relocations_offset);
label_writes, suffix_data, suffix_size, override_relocations_offset);
} else if ((this->arch == Architecture::X86) || (this->arch == Architecture::SH4)) {
return this->generate_client_command_t<S_ExecuteCode_Footer_DC_PC_XB_BB_B2>(
label_writes, suffix, override_relocations_offset);
label_writes, suffix_data, suffix_size, override_relocations_offset);
} else {
throw logic_error("invalid architecture");
}
+4 -2
View File
@@ -43,11 +43,13 @@ struct CompiledFunctionCode {
template <typename FooterT>
std::string generate_client_command_t(
const std::unordered_map<std::string, uint32_t>& label_writes,
const std::string& suffix,
const void* suffix_data = nullptr,
size_t suffix_size = 0,
uint32_t override_relocations_offset = 0) const;
std::string generate_client_command(
const std::unordered_map<std::string, uint32_t>& label_writes = {},
const std::string& suffix = "",
const void* suffix_data = nullptr,
size_t suffix_size = 0,
uint32_t override_relocations_offset = 0) const;
};
+2 -1
View File
@@ -1261,7 +1261,8 @@ Action a_assemble_all_patches(
uint32_t override_start_addr) -> void {
for (uint8_t encrypted = 0; encrypted < 2; encrypted++) {
StringWriter w;
string data = prepare_send_function_call_data(code, {}, "", checksum_addr, checksum_size, override_start_addr, encrypted);
string data = prepare_send_function_call_data(
code, {}, nullptr, 0, checksum_addr, checksum_size, override_start_addr, encrypted);
w.put(PSOCommandHeaderDCV3{.command = 0xB2, .flag = code->index, .size = data.size() + 4});
w.write(data);
string out_path = code->source_path + (encrypted ? ".enc.bin" : ".std.bin");
+1 -1
View File
@@ -2778,7 +2778,7 @@ static void send_dol_file_chunk(shared_ptr<Client> c, uint32_t start_addr) {
auto fn = s->function_code_index->name_to_function.at("WriteMemory");
unordered_map<string, uint32_t> label_writes(
{{"dest_addr", start_addr}, {"size", bytes_to_send}});
send_function_call(c, fn, label_writes, data_to_send);
send_function_call(c, fn, label_writes, data_to_send.data(), data_to_send.size());
size_t progress_percent = ((offset + bytes_to_send) * 100) / c->loading_dol_file->data.size();
send_ship_info(c, string_printf("%zu%%%%", progress_percent));
+13 -8
View File
@@ -365,7 +365,8 @@ void prepare_client_for_patches(shared_ptr<Client> c, function<void()> on_comple
};
if (!c->config.check_flag(Client::Flag::SEND_FUNCTION_CALL_NO_CACHE_PATCH)) {
send_function_call(c, s->function_code_index->name_to_function.at("CacheClearFix-Phase1"), {}, "", 0x80000000, 8, 0x7F2734EC);
auto fn = s->function_code_index->name_to_function.at("CacheClearFix-Phase1");
send_function_call(c, fn, {}, nullptr, 0, 0x80000000, 8, 0x7F2734EC);
c->function_call_response_queue.emplace_back([s, wc = weak_ptr<Client>(c), send_version_detect](uint32_t, uint32_t header_checksum) -> void {
auto c = wc.lock();
if (!c) {
@@ -397,14 +398,15 @@ void prepare_client_for_patches(shared_ptr<Client> c, function<void()> on_comple
string prepare_send_function_call_data(
shared_ptr<const CompiledFunctionCode> code,
const unordered_map<string, uint32_t>& label_writes,
const string& suffix,
const void* suffix_data,
size_t suffix_size,
uint32_t checksum_addr,
uint32_t checksum_size,
uint32_t override_relocations_offset,
bool use_encrypted_format) {
string data;
if (code.get()) {
data = code->generate_client_command(label_writes, suffix, override_relocations_offset);
data = code->generate_client_command(label_writes, suffix_data, suffix_size, override_relocations_offset);
if (use_encrypted_format) {
uint32_t key = random_object<uint32_t>();
@@ -446,7 +448,8 @@ void send_function_call(
shared_ptr<Client> c,
shared_ptr<const CompiledFunctionCode> code,
const unordered_map<string, uint32_t>& label_writes,
const string& suffix,
const void* suffix_data,
size_t suffix_size,
uint32_t checksum_addr,
uint32_t checksum_size,
uint32_t override_relocations_offset) {
@@ -455,7 +458,8 @@ void send_function_call(
c->config,
code,
label_writes,
suffix,
suffix_data,
suffix_size,
checksum_addr,
checksum_size,
override_relocations_offset);
@@ -466,7 +470,8 @@ void send_function_call(
const Client::Config& client_config,
shared_ptr<const CompiledFunctionCode> code,
const unordered_map<string, uint32_t>& label_writes,
const string& suffix,
const void* suffix_data,
size_t suffix_size,
uint32_t checksum_addr,
uint32_t checksum_size,
uint32_t override_relocations_offset) {
@@ -478,7 +483,7 @@ void send_function_call(
}
string data = prepare_send_function_call_data(
code, label_writes, suffix, checksum_addr, checksum_size, override_relocations_offset,
code, label_writes, suffix_data, suffix_size, checksum_addr, checksum_size, override_relocations_offset,
client_config.check_flag(Client::Flag::ENCRYPTED_SEND_FUNCTION_CALL));
ch.send(0xB2, code ? code->index : 0x00, data);
@@ -520,7 +525,7 @@ bool send_protected_command(std::shared_ptr<Client> c, const void* data, size_t
auto s = c->require_server_state();
auto fn = s->function_code_index->get_patch("CallProtectedHandler", c->config.specific_version);
uint32_t size_label_value = is_big_endian(c->version()) ? data.size() : bswap32(data.size());
send_function_call(c, fn, {{"size", size_label_value}}, data);
send_function_call(c, fn, {{"size", size_label_value}}, data.data(), data.size());
c->function_call_response_queue.emplace_back(empty_function_call_response_handler);
if (echo_to_lobby) {
auto l = c->lobby.lock();
+6 -3
View File
@@ -152,7 +152,8 @@ void prepare_client_for_patches(std::shared_ptr<Client> c, std::function<void()>
std::string prepare_send_function_call_data(
std::shared_ptr<const CompiledFunctionCode> code,
const std::unordered_map<std::string, uint32_t>& label_writes,
const std::string& suffix,
const void* suffix_data,
size_t suffix_size,
uint32_t checksum_addr,
uint32_t checksum_size,
uint32_t override_relocations_offset,
@@ -162,7 +163,8 @@ void send_function_call(
const Client::Config& client_config,
std::shared_ptr<const CompiledFunctionCode> code,
const std::unordered_map<std::string, uint32_t>& label_writes = {},
const std::string& suffix = "",
const void* suffix_data = nullptr,
size_t suffix_size = 0,
uint32_t checksum_addr = 0,
uint32_t checksum_size = 0,
uint32_t override_relocations_offset = 0);
@@ -170,7 +172,8 @@ void send_function_call(
std::shared_ptr<Client> c,
std::shared_ptr<const CompiledFunctionCode> code,
const std::unordered_map<std::string, uint32_t>& label_writes = {},
const std::string& suffix = "",
const void* suffix_data = nullptr,
size_t suffix_size = 0,
uint32_t checksum_addr = 0,
uint32_t checksum_size = 0,
uint32_t override_relocations_offset = 0);