add item pickup patch

This commit is contained in:
Martin Michelsen
2024-12-07 17:29:10 -08:00
parent 3424d6481b
commit 4b3dcbb6f4
28 changed files with 656 additions and 20 deletions
+13 -6
View File
@@ -5,6 +5,7 @@
#include <phosg/Filesystem.hh>
#include <phosg/Strings.hh>
#include <resource_file/ExecutableFormats/DOLFile.hh>
#include <resource_file/ExecutableFormats/PEFile.hh>
#include <resource_file/ExecutableFormats/XBEFile.hh>
using namespace std;
@@ -112,9 +113,13 @@ public:
this->directory.pop_back();
}
for (const auto& filename : phosg::list_directory(this->directory)) {
if (filename.size() < 4) {
continue;
}
string name = filename.substr(0, filename.size() - 4);
string path = directory + "/" + filename;
if (phosg::ends_with(filename, ".dol")) {
string name = filename.substr(0, filename.size() - 4);
string path = directory + "/" + filename;
ResourceDASM::DOLFile dol(path.c_str());
auto mem = make_shared<ResourceDASM::MemoryContext>();
dol.load_into(mem);
@@ -122,16 +127,18 @@ public:
this->enable_ppc = true;
this->log.info("Loaded %s", name.c_str());
} else if (phosg::ends_with(filename, ".xbe")) {
string name = filename.substr(0, filename.size() - 4);
string path = directory + "/" + filename;
ResourceDASM::XBEFile xbe(path.c_str());
auto mem = make_shared<ResourceDASM::MemoryContext>();
xbe.load_into(mem);
this->mems.emplace(name, mem);
this->log.info("Loaded %s", name.c_str());
} else if (phosg::ends_with(filename, ".exe")) {
ResourceDASM::PEFile pe(path.c_str());
auto mem = make_shared<ResourceDASM::MemoryContext>();
pe.load_into(mem);
this->mems.emplace(name, mem);
this->log.info("Loaded %s", name.c_str());
} else if (phosg::ends_with(filename, ".bin")) {
string name = filename.substr(0, filename.size() - 4);
string path = directory + "/" + filename;
string data = phosg::load_file(path);
auto mem = make_shared<ResourceDASM::MemoryContext>();
mem->allocate_at(0x8C010000, data.size());
+94
View File
@@ -891,6 +891,98 @@ static void proxy_command_patch(shared_ptr<ProxyServer::LinkedSession> ses, cons
}
}
static bool console_address_in_range(Version version, uint32_t addr) {
if (is_dc(version)) {
return ((addr > 0x8C000000) && (addr <= 0x8CFFFFFC));
} else if (is_gc(version)) {
return ((addr > 0x80000000) && (addr <= 0x817FFFFC));
} else {
return true;
}
}
static void server_command_readmem(shared_ptr<Client> c, const std::string& args) {
check_debug_enabled(c);
uint32_t addr = stoul(args, nullptr, 16);
if (!console_address_in_range(c->version(), addr)) {
send_text_message(c, "$C4Address out of\nrange");
return;
}
prepare_client_for_patches(c, [wc = weak_ptr<Client>(c), addr]() {
auto c = wc.lock();
if (!c) {
return;
}
try {
auto s = c->require_server_state();
const char* function_name = is_dc(c->version())
? "ReadMemoryWordDC"
: is_gc(c->version())
? "ReadMemoryWordGC"
: "ReadMemoryWordX86";
auto fn = s->function_code_index->name_to_function.at(function_name);
send_function_call(c, fn, {{"address", addr}});
c->function_call_response_queue.emplace_back([wc = weak_ptr<Client>(c), addr](uint32_t ret, uint32_t) {
auto c = wc.lock();
if (c) {
string data_str;
if (is_big_endian(c->version())) {
be_uint32_t v = ret;
data_str = phosg::format_data_string(&v, sizeof(v));
} else {
le_uint32_t v = ret;
data_str = phosg::format_data_string(&v, sizeof(v));
}
send_text_message_printf(c, "Bytes at %08" PRIX32 ":\n$C6%s", addr, data_str.c_str());
}
});
} catch (const out_of_range&) {
send_text_message(c, "Invalid patch name");
}
});
}
static void server_command_writemem(shared_ptr<Client> c, const std::string& args) {
check_debug_enabled(c);
auto tokens = phosg::split(args, ' ');
if (tokens.size() < 2) {
send_text_message(c, "Incorrect arguments");
return;
}
uint32_t addr = stoul(tokens[0], nullptr, 16);
if (!console_address_in_range(c->version(), addr)) {
send_text_message(c, "$C4Address out of\nrange");
return;
}
tokens.erase(tokens.begin());
std::string data = phosg::parse_data_string(phosg::join(tokens, " "));
prepare_client_for_patches(c, [wc = weak_ptr<Client>(c), addr, data]() {
auto c = wc.lock();
if (!c) {
return;
}
try {
auto s = c->require_server_state();
const char* function_name = is_dc(c->version())
? "WriteMemoryDC"
: is_gc(c->version())
? "WriteMemoryGC"
: "WriteMemoryX86";
auto fn = s->function_code_index->name_to_function.at(function_name);
send_function_call(c, fn, {{"dest_addr", addr}, {"size", data.size()}}, data.data(), data.size());
c->function_call_response_queue.emplace_back(empty_function_call_response_handler);
} catch (const out_of_range&) {
send_text_message(c, "Invalid patch name");
}
});
}
static void server_command_persist(shared_ptr<Client> c, const std::string&) {
auto l = c->require_lobby();
if (l->check_flag(Lobby::Flag::DEFAULT)) {
@@ -2703,6 +2795,7 @@ static const unordered_map<string, ChatCommandDefinition> chat_commands({
{"$qsyncall", {server_command_qsyncall, proxy_command_qsyncall}},
{"$quest", {server_command_quest, nullptr}},
{"$rand", {server_command_rand, proxy_command_rand}},
{"$readmem", {server_command_readmem, nullptr}},
{"$save", {server_command_save, nullptr}},
{"$savechar", {server_command_savechar, nullptr}},
{"$saverec", {server_command_saverec, nullptr}},
@@ -2728,6 +2821,7 @@ static const unordered_map<string, ChatCommandDefinition> chat_commands({
{"$warpall", {server_command_warpall, proxy_command_warpall}},
{"$what", {server_command_what, nullptr}},
{"$where", {server_command_where, nullptr}},
{"$writemem", {server_command_writemem, nullptr}},
});
struct SplitCommand {
+1 -1
View File
@@ -67,7 +67,7 @@ string CompiledFunctionCode::generate_client_command_t(
if (offset > modified_code.size() - 4) {
throw runtime_error("label out of range");
}
*reinterpret_cast<be_uint32_t*>(modified_code.data() + offset) = it.second;
*reinterpret_cast<U32T<FooterT::IsBE>*>(modified_code.data() + offset) = it.second;
}
w.write(modified_code);
} else {
+4 -4
View File
@@ -2745,7 +2745,7 @@ static void on_10(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
// base address for loading the file.
send_function_call(
c,
s->function_code_index->name_to_function.at("ReadMemoryWord"),
s->function_code_index->name_to_function.at("ReadMemoryWordGC"),
{{"address", 0x80000034}}); // ArenaHigh from GC globals
}
break;
@@ -2927,7 +2927,7 @@ static void send_dol_file_chunk(shared_ptr<Client> c, uint32_t start_addr) {
string data_to_send = c->loading_dol_file->data.substr(offset, bytes_to_send);
auto s = c->require_server_state();
auto fn = s->function_code_index->name_to_function.at("WriteMemory");
auto fn = s->function_code_index->name_to_function.at("WriteMemoryGC");
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.data(), data_to_send.size());
@@ -2946,10 +2946,10 @@ static void on_B3(shared_ptr<Client> c, uint16_t, uint32_t flag, string& data) {
c->function_call_response_queue.pop_front();
} else if (c->loading_dol_file.get()) {
auto called_fn = s->function_code_index->index_to_function.at(flag);
if (called_fn->short_name == "ReadMemoryWord") {
if (called_fn->short_name == "ReadMemoryWordGC") {
c->dol_base_addr = (cmd.return_value - c->loading_dol_file->data.size()) & (~3);
send_dol_file_chunk(c, c->dol_base_addr);
} else if (called_fn->short_name == "WriteMemory") {
} else if (called_fn->short_name == "WriteMemoryGC") {
if (cmd.return_value >= c->dol_base_addr + c->loading_dol_file->data.size()) {
auto fn = s->function_code_index->name_to_function.at("RunDOL");
unordered_map<string, uint32_t> label_writes({{"dol_base_ptr", c->dol_base_addr}});
+5 -3
View File
@@ -135,9 +135,9 @@ WordSelectSet::WordSelectSet(const string& data, Version version, const vector<s
this->parse_non_windows_t<true, 0x63F, 0x693>(decrypt_and_decompress_pr2_data<true>(data), use_sjis);
break;
case Version::GC_EP3_NTE:
case Version::GC_V3:
this->parse_non_windows_t<true, 0x67C, 0x68C>(decrypt_and_decompress_pr2_data<true>(data), use_sjis);
break;
case Version::GC_V3:
case Version::GC_EP3:
this->parse_non_windows_t<true, 0x804, 0x68C>(decrypt_and_decompress_pr2_data<true>(data), use_sjis);
break;
@@ -159,11 +159,13 @@ const string& WordSelectSet::string_for_token(uint16_t token_id) const {
void WordSelectSet::print(FILE* stream) const {
fprintf(stream, "strings:\n");
for (size_t z = 0; z < this->strings.size(); z++) {
fprintf(stream, " [%04zX] \"%s\"\n", z, this->strings[z].c_str());
auto escaped = phosg::escape_controls_utf8(this->strings[z]);
fprintf(stream, " [%04zX] \"%s\"\n", z, escaped.c_str());
}
fprintf(stream, "token_id_to_string_id:\n");
for (size_t z = 0; z < this->token_id_to_string_id.size(); z++) {
fprintf(stream, " [%04zX] %04zX \"%s\"\n", z, this->token_id_to_string_id[z], this->string_for_token(z).c_str());
auto escaped = phosg::escape_controls_utf8(this->string_for_token(z));
fprintf(stream, " [%04zX] %04zX \"%s\"\n", z, this->token_id_to_string_id[z], escaped.c_str());
}
}