From e0f887abc921267b5e4dccf857fa64464d375627 Mon Sep 17 00:00:00 2001 From: sruon Date: Tue, 7 Apr 2026 19:05:56 -0600 Subject: [PATCH] Limit delivery box to 128 items in flight --- settings/default/map.lua | 3 +++ src/map/utils/dboxutils.cpp | 40 +++++++++++++++++++++++++++++++------ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/settings/default/map.lua b/settings/default/map.lua index 01d2b9ca0ec..46114b9b3d6 100644 --- a/settings/default/map.lua +++ b/settings/default/map.lua @@ -291,6 +291,9 @@ xi.settings.map = AUDIT_PLAYER_DBOX = false, AUDIT_PLAYER_VENDOR = false, + -- Maximum number of in-flight items (slots) allowed in a player's delivery box for PC-to-PC transfers. + DELIVERY_BOX_MAX_INFLIGHT = 128, + -- Seconds between healing ticks. Default is 10 HEALING_TICK_DELAY = 10, diff --git a/src/map/utils/dboxutils.cpp b/src/map/utils/dboxutils.cpp index 54de422e786..63925706d70 100644 --- a/src/map/utils/dboxutils.cpp +++ b/src/map/utils/dboxutils.cpp @@ -38,6 +38,17 @@ #include "packets/s2c/0x04b_pbx_result.h" #include "universal_container.h" +namespace +{ +auto isDeliveryBoxInflightAtCapacity(uint32 charid) -> bool +{ + static const uint32 maxInflight = settings::get("map.DELIVERY_BOX_MAX_INFLIGHT"); + + const auto rset = db::preparedStmt("SELECT COUNT(*) AS cnt FROM delivery_box WHERE charid = ? AND box = 1 AND slot >= 8", charid); + return rset && rset->next() && rset->get("cnt") >= maxInflight; +} +} // anonymous namespace + void dboxutils::SendOldItems(CCharEntity* PChar, GP_CLI_COMMAND_PBX_BOXNO BoxNo) { DebugDeliveryBoxFmt("DBOX: SendOldItems: player: {} ({}), BoxNo: {}", PChar->name, PChar->id, static_cast(BoxNo)); @@ -214,11 +225,22 @@ void dboxutils::SendConfirmation(CCharEntity* PChar, GP_CLI_COMMAND_PBX_BOXNO Bo if (PItem && !PItem->isSent()) { + uint32 charid = charutils::getCharIdFromName(PItem->getReceiver()); + if (!charid) + { + return; + } + + if (isDeliveryBoxInflightAtCapacity(charid)) + { + PChar->pushPacket(GP_CLI_COMMAND_PBX_COMMAND::Send, BoxNo, PItem, PostWorkNo, send_items, 0x02); + PChar->pushPacket(GP_CLI_COMMAND_PBX_COMMAND::Send, BoxNo, PItem, PostWorkNo, send_items, 0xFE); + return; + } + // clang-format off const auto success = db::transaction([&]() { - uint32 charid = charutils::getCharIdFromName(PItem->getReceiver()); - const auto rset = db::preparedStmt("UPDATE delivery_box SET sent = 1 WHERE charid = ? AND senderid = ? AND slot = ? AND box = ?", PChar->id, charid, PostWorkNo, 2); if (rset && rset->rowsAffected()) @@ -547,9 +569,7 @@ void dboxutils::ReturnToSender(CCharEntity* PChar, GP_CLI_COMMAND_PBX_BOXNO BoxN PChar->id, PostWorkNo); FOR_DB_SINGLE_RESULT(rset) { - const auto senderID = rset->get("senderid"); - const auto senderName = rset->get("sender"); - return std::make_pair(senderID, senderName); + return std::make_pair(rset->get("senderid"), rset->get("sender")); } return std::make_pair(0, std::string()); @@ -557,6 +577,13 @@ void dboxutils::ReturnToSender(CCharEntity* PChar, GP_CLI_COMMAND_PBX_BOXNO BoxN if (senderID) { + if (isDeliveryBoxInflightAtCapacity(senderID)) + { + PChar->pushPacket(GP_CLI_COMMAND_PBX_COMMAND::Reject, BoxNo, PItem, PostWorkNo, PChar->UContainer->GetItemsCount(), 0x02); + PChar->pushPacket(GP_CLI_COMMAND_PBX_COMMAND::Reject, BoxNo, PItem, PostWorkNo, PChar->UContainer->GetItemsCount(), 0xFE); + return; + } + // NOTE: This will trigger SQL trigger: delivery_box_insert const auto rset = db::preparedStmt("INSERT INTO delivery_box (charid, charname, box, itemid, itemsubid, quantity, extra, senderid, sender) " "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)", @@ -568,7 +595,8 @@ void dboxutils::ReturnToSender(CCharEntity* PChar, GP_CLI_COMMAND_PBX_BOXNO BoxN if (rset2 && rset2->rowsAffected()) { PChar->UContainer->SetItem(PostWorkNo, nullptr); - PChar->pushPacket(GP_CLI_COMMAND_PBX_COMMAND::Reject, BoxNo, PItem, PostWorkNo, PChar->UContainer->GetItemsCount(), 1); + PChar->pushPacket(GP_CLI_COMMAND_PBX_COMMAND::Reject, BoxNo, PItem, PostWorkNo, PChar->UContainer->GetItemsCount(), 0x02); + PChar->pushPacket(GP_CLI_COMMAND_PBX_COMMAND::Reject, BoxNo, PItem, PostWorkNo, PChar->UContainer->GetItemsCount(), 0x01); DebugDeliveryBoxFmt("DBOX: ReturnToSender: player: {} ({}) returned item: {} ({}) to sender: {} ({})", PChar->getName(), PChar->id, PItem->getName(), itemId, senderName, senderID);