Make GC V3 EXP boost config-driven
This commit is contained in:
@@ -3688,6 +3688,79 @@ static asio::awaitable<void> dispatch_dc_v2_exp_patch(shared_ptr<Client> c) {
|
||||
}
|
||||
}
|
||||
|
||||
// Dispatch the correct GC V3 EXP table for the current episode when the
|
||||
// universal GC EXP enable shim is active. This avoids EP1/EP2 patches
|
||||
// overwriting each other or leaving stale episode tables in memory.
|
||||
static asio::awaitable<void> dispatch_gc_v3_exp_patch(shared_ptr<Client> c) {
|
||||
if (c->version() != Version::GC_V3) {
|
||||
co_return;
|
||||
}
|
||||
if (not c->check_flag(Client::Flag::HAS_SEND_FUNCTION_CALL)) {
|
||||
co_return;
|
||||
}
|
||||
if (not c->login || not c->login->account) {
|
||||
co_return;
|
||||
}
|
||||
if (not c->login->account->auto_patches_enabled.count("PsoPeepsGCV3EXP_enabled")) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
auto l = c->require_lobby();
|
||||
if (not l->is_game()) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
const char* key = nullptr;
|
||||
size_t num_exp_labels = 0;
|
||||
switch (l->episode) {
|
||||
case Episode::EP1:
|
||||
key = "PsoPeepsEP1EXP_internal";
|
||||
num_exp_labels = 204;
|
||||
break;
|
||||
case Episode::EP2:
|
||||
key = "PsoPeepsEP2EXP_internal";
|
||||
num_exp_labels = 239;
|
||||
break;
|
||||
default:
|
||||
co_return;
|
||||
}
|
||||
|
||||
try {
|
||||
auto server_state = c->require_server_state();
|
||||
auto base_fn = server_state->client_functions->get(key, c->specific_version);
|
||||
auto fn = make_shared<ClientFunctionIndex::Function>(*base_fn);
|
||||
|
||||
for (size_t z = 0; z < num_exp_labels; z++) {
|
||||
string label = std::format("exp_{:03}", z);
|
||||
size_t offset = fn->label_offsets.at(label);
|
||||
if (offset > fn->code.size() - 4) {
|
||||
throw runtime_error("GC V3 EXP label out of range");
|
||||
}
|
||||
|
||||
uint32_t base_exp =
|
||||
(static_cast<uint32_t>(static_cast<uint8_t>(fn->code[offset])) << 24) |
|
||||
(static_cast<uint32_t>(static_cast<uint8_t>(fn->code[offset + 1])) << 16) |
|
||||
(static_cast<uint32_t>(static_cast<uint8_t>(fn->code[offset + 2])) << 8) |
|
||||
static_cast<uint32_t>(static_cast<uint8_t>(fn->code[offset + 3]));
|
||||
|
||||
uint64_t scaled_exp = static_cast<uint64_t>(base_exp) *
|
||||
static_cast<uint64_t>(server_state->gc_v3_exp_multiplier);
|
||||
if (scaled_exp > 0xFFFFFFFFULL) {
|
||||
scaled_exp = 0xFFFFFFFFULL;
|
||||
}
|
||||
|
||||
fn->code[offset] = static_cast<char>((scaled_exp >> 24) & 0xFF);
|
||||
fn->code[offset + 1] = static_cast<char>((scaled_exp >> 16) & 0xFF);
|
||||
fn->code[offset + 2] = static_cast<char>((scaled_exp >> 8) & 0xFF);
|
||||
fn->code[offset + 3] = static_cast<char>(scaled_exp & 0xFF);
|
||||
}
|
||||
|
||||
co_await send_function_call(c, fn);
|
||||
} catch (const out_of_range&) {
|
||||
c->log.warning_f("GC V3 EXP dispatcher could not find client function {}", key);
|
||||
}
|
||||
}
|
||||
|
||||
static asio::awaitable<void> on_trigger_set_event(shared_ptr<Client> c, SubcommandMessage& msg) {
|
||||
auto l = c->require_lobby();
|
||||
if (!l->is_game()) {
|
||||
@@ -3695,6 +3768,7 @@ static asio::awaitable<void> on_trigger_set_event(shared_ptr<Client> c, Subcomma
|
||||
}
|
||||
|
||||
co_await dispatch_dc_v2_exp_patch(c);
|
||||
co_await dispatch_gc_v3_exp_patch(c);
|
||||
|
||||
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);
|
||||
|
||||
@@ -1139,6 +1139,7 @@ void ServerState::load_config_early() {
|
||||
|
||||
this->bb_global_exp_multiplier = this->config_json->get_float("BBGlobalEXPMultiplier", 1.0f);
|
||||
this->dc_v2_exp_multiplier = std::max<int64_t>(1, this->config_json->get_int("DCV2EXPMultiplier", 1));
|
||||
this->gc_v3_exp_multiplier = std::max<int64_t>(1, this->config_json->get_int("GCV3EXPMultiplier", 1));
|
||||
this->exp_share_multiplier = this->config_json->get_float("BBEXPShareMultiplier", 0.5f);
|
||||
this->server_global_drop_rate_multiplier = this->config_json->get_float("ServerGlobalDropRateMultiplier", 1.0f);
|
||||
|
||||
|
||||
@@ -270,6 +270,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
QuestF960Result quest_F960_failure_results;
|
||||
float bb_global_exp_multiplier = 1.0f;
|
||||
int64_t dc_v2_exp_multiplier = 1;
|
||||
int64_t gc_v3_exp_multiplier = 1;
|
||||
float exp_share_multiplier = 0.5f;
|
||||
float server_global_drop_rate_multiplier = 1.0f;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
.meta visibility="menu"
|
||||
.meta key="PsoPeepsGCV3EXP_enabled"
|
||||
.meta name="GC XP"
|
||||
.meta client_flag="0x0000200000000000"
|
||||
.meta description="Enables server-scaled GC V3 EXP boost. Server applies the correct Episode 1 or Episode 2 table."
|
||||
|
||||
.versions 3OE2 3OJ5
|
||||
|
||||
entry_ptr:
|
||||
reloc0:
|
||||
.offsetof start
|
||||
|
||||
start:
|
||||
blr
|
||||
Reference in New Issue
Block a user