implement extended $loadchar on GC
This commit is contained in:
@@ -507,8 +507,8 @@ Some commands only work on the game server and not on the proxy server. The chat
|
||||
* `$patch <name>`: Run a patch on your client. `<name>` must exactly match the name of a patch on the server.
|
||||
|
||||
* Character data commands (game server only)
|
||||
* `$savechar <slot>`: Saves your current character data on the server in the specified slot (each serial number has 4 slots, numbered 1-4). These slots are separate from BB character slots; using this command does not affect BB characters.
|
||||
* `$loadchar <slot>` (v1 and v2 only): Loads your character data from the specified slot. The changes will be undone if you join a game - to save your changes, disconnect from the lobby.
|
||||
* `$savechar <slot>`: Saves your current character data on the server in the specified slot (each serial number has 4 slots, numbered 1-4). These slots are separate from BB character slots; using this command does not affect BB characters. On non-Plus GC versions, this command also saves your bank contents and chat shortcuts.
|
||||
* `$loadchar <slot>` (v1, v2, and GC non-Plus only): Loads your character data from the specified slot. The changes will be undone if you join a game - to save your changes, disconnect from the lobby.
|
||||
* `$bbchar <username> <password> <slot>`: Use this command when playing on a non-BB version of PSO. If the username and password are correct, this command converts your current character to BB format and saves it on the server in the given slot (1-4). Any character already in that slot is overwritten. (This command is similar to `$savechar`, except it overwrites a BB character slot, and can transfer characters across accounts.) Note that the character's chat data, quick menu config, and bank contents are not copied, since there is no way for the server to request those types of data.
|
||||
* `$edit <stat> <value>`: Modifies your character data. If you are on V3 (GameCube/Xbox), this command does nothing. If you are on V1 or V2 (DC or PC, not BB), your changes will be undone if you join a game - to save your changes, disconnect from the lobby. If cheats are allowed on the server, `<stat>` can be any of `atp`, `mst`, `evp`, `hp`, `dfp`, `ata`, `lck`, `meseta`, `exp`, `level`, `namecolor`, `secid`, `name`, `language`, `npc`, or `tech`. If cheats are not allowed, only `namecolor`, `name`, `language`, and `npc` can be used. Changing your character's language is only useful on BB; to do so, use a single-character language code (e.g. to switch your character to English, use `$edit language E`; for Japanese, use `$edit language J`).
|
||||
|
||||
|
||||
+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);
|
||||
|
||||
+3
-6
@@ -6,14 +6,11 @@ entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
mflr r12
|
||||
bl get_data_addr
|
||||
.include GetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x803DB0E0 # malloc9
|
||||
.data 0x802021D0 # get_character_file
|
||||
.data 0x802021AC # get_selected_character_file_index
|
||||
.data 0x805C5760 # char_file_part1
|
||||
.data 0x805C5764 # char_file_part2
|
||||
.data 0x805C4D80 # root_protocol (anchor: send_05)
|
||||
.data 0x803DB138 # free9
|
||||
.data 0x800787B0 # TProtocol_wait_send_drain
|
||||
get_data_addr:
|
||||
.include GetExtendedPlayerInfoGC
|
||||
+3
-6
@@ -6,14 +6,11 @@ entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
mflr r12
|
||||
bl get_data_addr
|
||||
.include GetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x803DB138 # malloc9
|
||||
.data 0x802021D0 # get_character_file
|
||||
.data 0x802021AC # get_selected_character_file_index
|
||||
.data 0x805CC740 # char_file_part1
|
||||
.data 0x805CC744 # char_file_part2
|
||||
.data 0x805CBD60 # root_protocol (anchor: send_05)
|
||||
.data 0x803DB190 # free9
|
||||
.data 0x800787B0 # TProtocol_wait_send_drain
|
||||
get_data_addr:
|
||||
.include GetExtendedPlayerInfoGC
|
||||
+3
-6
@@ -6,14 +6,11 @@ entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
mflr r12
|
||||
bl get_data_addr
|
||||
.include GetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x803DE838 # malloc9
|
||||
.data 0x80202BA0 # get_character_file
|
||||
.data 0x80202B7C # get_selected_character_file_index
|
||||
.data 0x805D5F60 # char_file_part1
|
||||
.data 0x805D5F64 # char_file_part2
|
||||
.data 0x805D5580 # root_protocol (anchor: send_05)
|
||||
.data 0x803DE890 # free9
|
||||
.data 0x8007889C # TProtocol_wait_send_drain
|
||||
get_data_addr:
|
||||
.include GetExtendedPlayerInfoGC
|
||||
+3
-6
@@ -6,14 +6,11 @@ entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
mflr r12
|
||||
bl get_data_addr
|
||||
.include GetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x803D9E38 # malloc9
|
||||
.data 0x802019D4 # get_character_file
|
||||
.data 0x802019B0 # get_selected_character_file_index
|
||||
.data 0x805C4E68 # char_file_part1
|
||||
.data 0x805C4E6C # char_file_part2
|
||||
.data 0x805C4488 # root_protocol (anchor: send_05)
|
||||
.data 0x803D9E90 # free9
|
||||
.data 0x8007848C # TProtocol_wait_send_drain
|
||||
get_data_addr:
|
||||
.include GetExtendedPlayerInfoGC
|
||||
+3
-6
@@ -6,14 +6,11 @@ entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
mflr r12
|
||||
bl get_data_addr
|
||||
.include GetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x803DC818 # malloc9
|
||||
.data 0x80202248 # get_character_file
|
||||
.data 0x80202224 # get_selected_character_file_index
|
||||
.data 0x805CF430 # char_file_part1
|
||||
.data 0x805CF434 # char_file_part2
|
||||
.data 0x805CEA50 # root_protocol (anchor: send_05)
|
||||
.data 0x803DC870 # free9
|
||||
.data 0x800785F0 # TProtocol_wait_send_drain
|
||||
get_data_addr:
|
||||
.include GetExtendedPlayerInfoGC
|
||||
+3
-6
@@ -6,14 +6,11 @@ entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
mflr r12
|
||||
bl get_data_addr
|
||||
.include GetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x803DE6B8 # malloc9
|
||||
.data 0x801FD950 # get_character_file
|
||||
.data 0x80222C0C # get_selected_character_file_index
|
||||
.data 0x805D68B0 # char_file_part1
|
||||
.data 0x805D68B4 # char_file_part2
|
||||
.data 0x805D5ED0 # root_protocol (anchor: send_05)
|
||||
.data 0x803DE710 # free9
|
||||
.data 0x80078748 # TProtocol_wait_send_drain
|
||||
get_data_addr:
|
||||
.include GetExtendedPlayerInfoGC
|
||||
+3
-6
@@ -6,14 +6,11 @@ entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
mflr r12
|
||||
bl get_data_addr
|
||||
.include GetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x803DE468 # malloc9
|
||||
.data 0x8020286C # get_character_file
|
||||
.data 0x80202848 # get_selected_character_file_index
|
||||
.data 0x805D6650 # char_file_part1
|
||||
.data 0x805D6654 # char_file_part2
|
||||
.data 0x805D5C70 # root_protocol (anchor: send_05)
|
||||
.data 0x803DE4C0 # free9
|
||||
.data 0x800786A0 # TProtocol_wait_send_drain
|
||||
get_data_addr:
|
||||
.include GetExtendedPlayerInfoGC
|
||||
+3
-6
@@ -6,14 +6,11 @@ entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
mflr r12
|
||||
bl get_data_addr
|
||||
.include GetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x803DD328 # malloc9
|
||||
.data 0x80202AB4 # get_character_file
|
||||
.data 0x80202A90 # get_selected_character_file_index
|
||||
.data 0x805D21A0 # char_file_part1
|
||||
.data 0x805D21A4 # char_file_part2
|
||||
.data 0x805D17C0 # root_protocol (anchor: send_05)
|
||||
.data 0x803DD380 # free9
|
||||
.data 0x80078820 # TProtocol_wait_send_drain
|
||||
get_data_addr:
|
||||
.include GetExtendedPlayerInfoGC
|
||||
+23
-14
@@ -1,9 +1,13 @@
|
||||
stwu [r1 - 0x20], r1
|
||||
stw [r1 + 0x24], r12
|
||||
mflr r0
|
||||
stw [r1 + 0x24], r0
|
||||
stw [r1 + 0x08], r31
|
||||
stw [r1 + 0x0C], r30
|
||||
stw [r1 + 0x10], r29
|
||||
stw [r1 + 0x14], r28
|
||||
|
||||
b get_data_ptr
|
||||
get_data_ptr_ret:
|
||||
mflr r30
|
||||
|
||||
li r3, 0x279C
|
||||
@@ -17,21 +21,23 @@
|
||||
ori r0, r0, 0x9C27
|
||||
stw [r31], r0 # header = 30 00 9C 27
|
||||
|
||||
lwz r0, [r30 + 0x04]
|
||||
mtctr r0
|
||||
bctrl # get_character_file
|
||||
mr r28, r3
|
||||
|
||||
lwz r0, [r30 + 0x08]
|
||||
mtctr r0
|
||||
bctrl # get_selected_character_file_index
|
||||
mulli r3, r3, 0x2798
|
||||
addi r3, r3, 4
|
||||
add r4, r3, r28 # r4 = &character_file->characters[selected_char_file_index]
|
||||
addi r3, r31, 4
|
||||
li r5, 0x2798
|
||||
lwz r4, [r30 + 0x04]
|
||||
lwz r4, [r4] # r4 = char_file_part1
|
||||
addi r3, r31, 0x0004
|
||||
li r5, 0x041C # sizeof(part1)
|
||||
bl memcpy
|
||||
|
||||
lwz r4, [r30 + 0x08]
|
||||
lwz r4, [r4] # r4 = char_file_part2
|
||||
addi r3, r31, 0x0420
|
||||
li r5, 0x2370 # sizeof(part2)
|
||||
bl memcpy
|
||||
|
||||
li r0, 0
|
||||
stw [r31 + 0x2790], r0
|
||||
stw [r31 + 0x2794], r0
|
||||
stw [r31 + 0x2798], r0
|
||||
|
||||
mr r28, r31
|
||||
li r29, 0x279C
|
||||
send_again:
|
||||
@@ -79,3 +85,6 @@ malloc9_failed:
|
||||
memcpy:
|
||||
.include CopyDataWords
|
||||
blr
|
||||
|
||||
get_data_ptr:
|
||||
bl get_data_ptr_ret
|
||||
@@ -0,0 +1,12 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="SetExtendedPlayerInfo"
|
||||
.meta description=""
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include SetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x805C5758 # character_file
|
||||
# Server adds a PSOGCCharacterFile::Character here
|
||||
@@ -0,0 +1,12 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="SetExtendedPlayerInfo"
|
||||
.meta description=""
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include SetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x805CC738 # character_file
|
||||
# Server adds a PSOGCCharacterFile::Character here
|
||||
@@ -0,0 +1,12 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="SetExtendedPlayerInfo"
|
||||
.meta description=""
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include SetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x805D5F58 # character_file
|
||||
# Server adds a PSOGCCharacterFile::Character here
|
||||
@@ -0,0 +1,12 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="SetExtendedPlayerInfo"
|
||||
.meta description=""
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include SetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x805C4E60 # character_file
|
||||
# Server adds a PSOGCCharacterFile::Character here
|
||||
@@ -0,0 +1,12 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="SetExtendedPlayerInfo"
|
||||
.meta description=""
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include SetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x805CF428 # character_file
|
||||
# Server adds a PSOGCCharacterFile::Character here
|
||||
@@ -0,0 +1,12 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="SetExtendedPlayerInfo"
|
||||
.meta description=""
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include SetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x805D68A8 # character_file
|
||||
# Server adds a PSOGCCharacterFile::Character here
|
||||
@@ -0,0 +1,12 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="SetExtendedPlayerInfo"
|
||||
.meta description=""
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include SetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x805D6648 # character_file
|
||||
# Server adds a PSOGCCharacterFile::Character here
|
||||
@@ -0,0 +1,12 @@
|
||||
.meta hide_from_patches_menu
|
||||
.meta name="SetExtendedPlayerInfo"
|
||||
.meta description=""
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
start:
|
||||
.include SetExtendedPlayerInfoGC
|
||||
data:
|
||||
.data 0x805D2198 # character_file
|
||||
# Server adds a PSOGCCharacterFile::Character here
|
||||
@@ -0,0 +1,37 @@
|
||||
mflr r12
|
||||
bl get_data_ptr
|
||||
get_data_ptr_ret:
|
||||
mflr r11
|
||||
|
||||
lwz r10, [r11]
|
||||
|
||||
# Copy part1 data into place
|
||||
lwz r3, [r10 + 0x08]
|
||||
addi r4, r11, 0x0004
|
||||
li r5, 0x41C
|
||||
bl memcpy
|
||||
|
||||
# Copy part2 data into place, but retain the values of a few metadata fields
|
||||
# so the game won't think the file is corrupt
|
||||
lwz r3, [r10 + 0x0C]
|
||||
lwz r7, [r3 + 0x04] # creation_timestamp
|
||||
lwz r8, [r3 + 0x08] # signature
|
||||
lwz r9, [r3 + 0x14] # save_count
|
||||
addi r4, r11, 0x0420
|
||||
li r5, 0x2370
|
||||
bl memcpy
|
||||
lwz r3, [r10 + 0x0C]
|
||||
stw [r3 + 0x04], r7 # creation_timestamp
|
||||
stw [r3 + 0x08], r8 # signature
|
||||
stw [r3 + 0x14], r9 # save_count
|
||||
|
||||
li r3, 1
|
||||
mtlr r12
|
||||
blr
|
||||
|
||||
memcpy:
|
||||
.include CopyDataWords
|
||||
blr
|
||||
|
||||
get_data_ptr:
|
||||
bl get_data_ptr_ret
|
||||
@@ -1,7 +1,7 @@
|
||||
# r3 = dest ptr
|
||||
# r4 = src ptr
|
||||
# r5 = size
|
||||
# Clobbers r3, r4, r5
|
||||
# Clobbers r3, r4, r5, ctr
|
||||
addi r5, r5, 3
|
||||
rlwinm r5, r5, 30, 2, 31 # r5 = number of words to copy
|
||||
mtctr r5
|
||||
|
||||
Reference in New Issue
Block a user