implement extended $loadchar on GC
This commit is contained in:
+46
-5
@@ -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&) {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
@@ -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");
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user