Files
psopeeps-newserv/diffs/dc_v2_exp_dispatcher.patch
T

100 lines
3.6 KiB
Diff

Subject: [PATCH] DC V2 EXP: server-side per-difficulty dispatcher hooked into set-events
Adds a `dispatch_dc_v2_exp_patch` helper that:
- no-ops unless the client is DC V2, supports send_function_call, has
`PsoPeepsV2EXP_enabled` in `auto_patches_enabled`, and is in an actual game
- reads the lobby's current difficulty
- looks up `PsoPeepsV2EXP_internal_{10|5}x_{normal|hard|vh|ult}` (10x preferred
if both deployed; falls back to 5x)
- sends it via the existing send_function_call coroutine
Hooks the dispatcher at the end of `on_trigger_set_event`, which fires on every
6x67 the client emits (i.e. every area transition that triggers map events).
This survives all difficulty/area cycling because the patch is re-applied on
every trigger.
The menu-visible shim `PsoPeepsV2EXP_enabled` uses a fixed key across both 5x
week and 10x weekend deploys, so a player's selection survives the systemd
file swap.
---
src/ReceiveSubcommands.cc | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc
--- a/src/ReceiveSubcommands.cc
+++ b/src/ReceiveSubcommands.cc
@@ -- (around line 3637 — directly before the existing `on_trigger_set_event`) --
+// Dispatch the right per-difficulty DC V2 EXP table when the player has the
+// universal EXP shim enabled. The shim's body covers Normal; this corrects to
+// the actual loaded difficulty on every set-events trigger. No-op for non-DC-V2
+// clients, clients without the shim toggled on, or when the right internal
+// patch isn't currently deployed.
+static asio::awaitable<void> dispatch_dc_v2_exp_patch(std::shared_ptr<Client> c) {
+ if (c->version() != Version::DC_V2) {
+ co_return;
+ }
+ if (!c->check_flag(Client::Flag::HAS_SEND_FUNCTION_CALL)) {
+ co_return;
+ }
+ if (!c->login || !c->login->account) {
+ co_return;
+ }
+ if (!c->login->account->auto_patches_enabled.contains("PsoPeepsV2EXP_enabled")) {
+ co_return;
+ }
+
+ auto l = c->require_lobby();
+ if (!l->is_game()) {
+ co_return;
+ }
+
+ const char* diff_str;
+ switch (l->difficulty) {
+ case Difficulty::NORMAL: diff_str = "normal"; break;
+ case Difficulty::HARD: diff_str = "hard"; break;
+ case Difficulty::VERY_HARD: diff_str = "vh"; break;
+ case Difficulty::ULTIMATE: diff_str = "ult"; break;
+ default: co_return;
+ }
+
+ auto s = c->require_server_state();
+ // Try 10x first; fall back to 5x. The active multiplier is whichever set is
+ // deployed by the current week's systemd timer state.
+ for (int mult : {10, 5}) {
+ std::string key = std::format("PsoPeepsV2EXP_internal_{}x_{}", mult, diff_str);
+ std::shared_ptr<Function> fn;
+ try {
+ fn = s->client_functions->get(key, c->specific_version);
+ } catch (...) {
+ continue;
+ }
+ if (fn) {
+ co_await send_function_call(c, fn);
+ co_return;
+ }
+ }
+}
+
static asio::awaitable<void> on_trigger_set_event(shared_ptr<Client> c, SubcommandMessage& msg) {
auto l = c->require_lobby();
if (!l->is_game()) {
co_return;
}
const auto& cmd = msg.check_size_t<G_TriggerSetEvent_6x67>();
auto event_sts = l->map_state->event_states_for_id(c->version(), cmd.floor, cmd.event_id);
l->log.info_f("Client triggered set events with floor {:02X} and ID {:X} ({} events)",
cmd.floor, cmd.event_id, event_sts.size());
for (auto ev_st : event_sts) {
ev_st->flags |= 0x04;
if (c->check_flag(Client::Flag::DEBUG_ENABLED)) {
send_text_message_fmt(c, "$C5W-{:03X} START", ev_st->w_id);
}
}
forward_subcommand(c, msg);
+
+ co_await dispatch_dc_v2_exp_patch(c);
}