diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 75d67bc4..91f5f962 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -216,6 +216,20 @@ static void server_command_patch(shared_ptr s, shared_ptr, } } +static void proxy_command_patch(shared_ptr s, + ProxyServer::LinkedSession& session, const std::u16string& args) { + std::shared_ptr fn; + try { + fn = s->function_code_index->name_to_function.at(encode_sjis(args)); + send_function_call( + session.client_channel, session.newserv_client_config.cfg.flags, fn); + // Don't forward the patch response to the server + session.should_forward_function_call_return_queue.emplace_back(false); + } catch (const out_of_range&) { + send_text_message(session.client_channel, u"Invalid patch name"); + } +} + static void server_command_persist(shared_ptr, shared_ptr l, shared_ptr c, const std::u16string&) { check_privileges(c, Privilege::DEBUG); @@ -980,7 +994,7 @@ static const unordered_map chat_commands({ {u"$minlevel", {server_command_min_level, nullptr, u"Usage:\nmin_level "}}, {u"$next", {server_command_next, proxy_command_next, u"Usage:\nnext"}}, {u"$password", {server_command_password, nullptr, u"Usage:\nlock [password]\nomit password to\nunlock game"}}, - {u"$patch", {server_command_patch, nullptr, u"Usage:\npatch "}}, + {u"$patch", {server_command_patch, proxy_command_patch, u"Usage:\npatch "}}, {u"$persist", {server_command_persist, nullptr, u"Usage:\npersist"}}, {u"$rand", {server_command_rand, proxy_command_rand, u"Usage:\nrand [hex seed]\nomit seed to revert\nto default"}}, {u"$secid", {server_command_secid, proxy_command_secid, u"Usage:\nsecid [section ID]\nomit section ID to\nrevert to normal"}}, diff --git a/src/ProxyCommands.cc b/src/ProxyCommands.cc index 046cb72a..efa294e2 100644 --- a/src/ProxyCommands.cc +++ b/src/ProxyCommands.cc @@ -687,10 +687,22 @@ static HandlerResult S_B2(shared_ptr, session.server_channel.send(0xB3, flag, &cmd, sizeof(cmd)); return HandlerResult::Type::SUPPRESS; } else { + session.should_forward_function_call_return_queue.emplace_back(true); return HandlerResult::Type::FORWARD; } } +static HandlerResult C_B3(shared_ptr, + ProxyServer::LinkedSession& session, uint16_t, uint32_t, string&) { + if (session.should_forward_function_call_return_queue.empty()) { + session.log.warning("Received function call result with empty result queue"); + return HandlerResult::Type::FORWARD; + } + bool should_forward = session.should_forward_function_call_return_queue.front(); + session.should_forward_function_call_return_queue.pop_front(); + return should_forward ? HandlerResult::Type::FORWARD : HandlerResult::Type::SUPPRESS; +} + static HandlerResult S_B_E7(shared_ptr, ProxyServer::LinkedSession& session, uint16_t, uint32_t, string& data) { if (session.save_files) { @@ -1554,7 +1566,7 @@ static on_command_t handlers[0x100][6][2] = { /* B0 */ {{S_invalid, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}, /* B1 */ {{S_invalid, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}, /* B2 */ {{S_invalid, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, {S_B2, nullptr}, {S_B2, nullptr}, {S_B2, nullptr}}, -/* B3 */ {{S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}}, +/* B3 */ {{S_invalid, C_B3}, {S_invalid, C_B3}, {S_invalid, C_B3}, {S_invalid, C_B3}, {S_invalid, C_B3}, {S_invalid, C_B3}}, /* B4 */ {{S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}}, /* B5 */ {{S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}}, /* B6 */ {{S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}, {S_invalid, nullptr}}, diff --git a/src/ProxyServer.hh b/src/ProxyServer.hh index 95526c86..fd929eff 100644 --- a/src/ProxyServer.hh +++ b/src/ProxyServer.hh @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -67,6 +68,7 @@ public: bool infinite_tp; bool save_files; bool suppress_remote_login; + std::deque should_forward_function_call_return_queue; int64_t function_call_return_value; // -1 = don't block function calls G_SwitchStateChanged_6x05 last_switch_enabled_command; PlayerInventoryItem next_drop_item; diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 0b04dcb4..d6ee7853 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -318,10 +318,28 @@ void send_function_call( const std::string& suffix, uint32_t checksum_addr, uint32_t checksum_size) { - if (c->flags & Client::Flag::NO_SEND_FUNCTION_CALL) { + return send_function_call( + c->channel, + c->flags, + code, + label_writes, + suffix, + checksum_addr, + checksum_size); +} + +void send_function_call( + Channel& ch, + uint64_t client_flags, + shared_ptr code, + const std::unordered_map& label_writes, + const std::string& suffix, + uint32_t checksum_addr, + uint32_t checksum_size) { + if (client_flags & Client::Flag::NO_SEND_FUNCTION_CALL) { throw logic_error("client does not support function calls"); } - if (code.get() && (c->flags & Client::Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY)) { + if (code.get() && (client_flags & Client::Flag::SEND_FUNCTION_CALL_CHECKSUM_ONLY)) { throw logic_error("client only supports checksums in send_function_call"); } @@ -331,7 +349,7 @@ void send_function_call( data = code->generate_client_command(label_writes, suffix); index = code->index; - if (c->flags & Client::Flag::ENCRYPTED_SEND_FUNCTION_CALL) { + if (client_flags & Client::Flag::ENCRYPTED_SEND_FUNCTION_CALL) { uint32_t key = random_object(); // This format was probably never used on any little-endian system, but we @@ -364,7 +382,7 @@ void send_function_call( w.put(header); w.write(data); - send_command(c, 0xB2, index, w.str()); + ch.send(0xB2, index, w.str()); } diff --git a/src/SendCommands.hh b/src/SendCommands.hh index 307acf70..132c2e1a 100644 --- a/src/SendCommands.hh +++ b/src/SendCommands.hh @@ -124,6 +124,14 @@ void send_update_client_config(std::shared_ptr c); void send_quest_buffer_overflow( std::shared_ptr s, std::shared_ptr c); +void send_function_call( + Channel& ch, + uint64_t client_flags, + std::shared_ptr code, + const std::unordered_map& label_writes = {}, + const std::string& suffix = "", + uint32_t checksum_addr = 0, + uint32_t checksum_size = 0); void send_function_call( std::shared_ptr c, std::shared_ptr code,