[Feature] Implement Big Bags (#4606)

* [Feature] Implement "Big Bags"

* Update worlddb.cpp

* Update shareddb.cpp

* Cleanup

* Cleanup

* Add slot ID conversions

* Update shareddb.cpp

* Update database_update_manifest.cpp

* Update database_update_manifest.cpp

* Update database_update_manifest.cpp

* Update database_update_manifest.cpp

* Update ruletypes.h

* Update database_update_manifest.cpp

* Inventory load fix

* Wrap Handle_OP_MoveItem in a transaction, taking 200+ queries from 200ms+ to 5-20ms

* Speed up lazy loading

* [Performance] Significantly Improve Client Network Resends

* Improve resend algorithm to be exact about when to resend

* Manifest merge

* Update database_update_manifest.cpp

* Post merge

* Add forced interactive update

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
Alex King
2025-02-03 17:14:41 -05:00
committed by GitHub
parent e3ab90695f
commit d1d6db3a09
25 changed files with 2069 additions and 1655 deletions
+4 -4
View File
@@ -9210,7 +9210,7 @@ void Client::SetPrimaryWeaponOrnamentation(uint32 model_id)
auto l = InventoryRepository::GetWhere(
database,
fmt::format(
"`charid` = {} AND `slotid` = {}",
"`character_id` = {} AND `slot_id` = {}",
character_id,
EQ::invslot::slotPrimary
)
@@ -9222,7 +9222,7 @@ void Client::SetPrimaryWeaponOrnamentation(uint32 model_id)
auto e = l.front();
e.ornamentidfile = model_id;
e.ornament_idfile = model_id;
const int updated = InventoryRepository::UpdateOne(database, e);
@@ -9243,7 +9243,7 @@ void Client::SetSecondaryWeaponOrnamentation(uint32 model_id)
auto l = InventoryRepository::GetWhere(
database,
fmt::format(
"`charid` = {} AND `slotid` = {}",
"`character_id` = {} AND `slot_id` = {}",
character_id,
EQ::invslot::slotSecondary
)
@@ -9255,7 +9255,7 @@ void Client::SetSecondaryWeaponOrnamentation(uint32 model_id)
auto e = l.front();
e.ornamentidfile = model_id;
e.ornament_idfile = model_id;
const int updated = InventoryRepository::UpdateOne(database, e);
+21 -42
View File
@@ -1666,11 +1666,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
m_pp.abilitySlotRefresh = 0;
}
#ifdef _EQDEBUG
printf("Dumping inventory on load:\n");
m_inv.dumpEntireInventory();
#endif
/* Reset to max so they dont drown on zone in if its underwater */
m_pp.air_remaining = 60;
/* Check for PVP Zone status*/
@@ -10762,8 +10757,7 @@ void Client::Handle_OP_MoveCoin(const EQApplicationPacket *app)
void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
{
if (!CharacterID())
{
if (!CharacterID()) {
return;
}
@@ -10772,57 +10766,38 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
return;
}
MoveItem_Struct* mi = (MoveItem_Struct*)app->pBuffer;
if (spellend_timer.Enabled() && casting_spell_id && !IsBardSong(casting_spell_id))
{
if (mi->from_slot != mi->to_slot && (mi->from_slot <= EQ::invslot::GENERAL_END || mi->from_slot > 39) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot))
{
const EQ::ItemInstance *itm_from = GetInv().GetItem(mi->from_slot);
const EQ::ItemInstance *itm_to = GetInv().GetItem(mi->to_slot);
auto message = fmt::format("Player issued a move item from {}(item id {}) to {}(item id {}) while casting {}.",
BenchTimer bench;
MoveItem_Struct* mi = (MoveItem_Struct*) app->pBuffer;
if (spellend_timer.Enabled() && casting_spell_id && !IsBardSong(casting_spell_id)) {
if (mi->from_slot != mi->to_slot && (mi->from_slot <= EQ::invslot::GENERAL_END || mi->from_slot > 39) &&
IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) {
const EQ::ItemInstance* itm_from = GetInv().GetItem(mi->from_slot);
const EQ::ItemInstance* itm_to = GetInv().GetItem(mi->to_slot);
auto message = fmt::format(
"Player issued a move item from {}(item id {}) to {}(item id {}) while casting {}.",
mi->from_slot,
itm_from ? itm_from->GetID() : 0,
mi->to_slot,
itm_to ? itm_to->GetID() : 0,
casting_spell_id);
RecordPlayerEventLog(PlayerEvent::POSSIBLE_HACK, PlayerEvent::PossibleHackEvent{.message = message});
casting_spell_id
);
RecordPlayerEventLog(PlayerEvent::POSSIBLE_HACK, PlayerEvent::PossibleHackEvent{ .message = message });
Kick("Inventory desync"); // Kick client to prevent client and server from getting out-of-sync inventory slots
return;
}
}
// Illegal bagslot usage checks. Currently, user only receives a message if this check is triggered.
bool mi_hack = false;
if (mi->from_slot >= EQ::invbag::GENERAL_BAGS_BEGIN && mi->from_slot <= EQ::invbag::CURSOR_BAG_END) {
if (mi->from_slot >= EQ::invbag::CURSOR_BAG_BEGIN) { mi_hack = true; }
else {
int16 from_parent = m_inv.CalcSlotId(mi->from_slot);
if (!m_inv[from_parent]) { mi_hack = true; }
else if (!m_inv[from_parent]->IsClassBag()) { mi_hack = true; }
else if (m_inv.CalcBagIdx(mi->from_slot) >= m_inv[from_parent]->GetItem()->BagSlots) { mi_hack = true; }
}
}
if (mi->to_slot >= EQ::invbag::GENERAL_BAGS_BEGIN && mi->to_slot <= EQ::invbag::CURSOR_BAG_END) {
if (mi->to_slot >= EQ::invbag::CURSOR_BAG_BEGIN) { mi_hack = true; }
else {
int16 to_parent = m_inv.CalcSlotId(mi->to_slot);
if (!m_inv[to_parent]) { mi_hack = true; }
else if (!m_inv[to_parent]->IsClassBag()) { mi_hack = true; }
else if (m_inv.CalcBagIdx(mi->to_slot) >= m_inv[to_parent]->GetItem()->BagSlots) { mi_hack = true; }
}
}
if (mi_hack) { Message(Chat::Yellow, "Caution: Illegal use of inaccessible bag slots!"); }
database.TransactionBegin();
if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) {
SwapItemResync(mi);
bool error = false;
InterrogateInventory(this, false, true, false, error, false);
if (error)
if (error) {
InterrogateInventory(this, true, false, true, error);
}
}
for (int slot : {mi->to_slot, mi->from_slot}) {
@@ -10831,6 +10806,10 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
CharacterEvolvingItemsRepository::UpdateOne(database, item->GetEvolvingDetails());
}
}
database.TransactionCommit();
LogInventory("OP_MoveItem took [{}] ms", bench.elapsedMilliseconds());
}
void Client::Handle_OP_MoveMultipleItems(const EQApplicationPacket *app)
+79 -53
View File
@@ -300,24 +300,30 @@ bool Client::Process() {
}
}
if (m_lazy_load_bank && m_lazy_load_sent_bank_slots <= EQ::invslot::SHARED_BANK_END) {
const EQ::ItemInstance *inst = nullptr;
int lazy_load_bank_slots = 0;
for (int i = 0; i < 5000; i++) {
if (m_lazy_load_bank && m_lazy_load_sent_bank_slots <= EQ::invslot::SHARED_BANK_END) {
const EQ::ItemInstance *inst = nullptr;
// Jump the gaps
if (m_lazy_load_sent_bank_slots < EQ::invslot::BANK_BEGIN) {
m_lazy_load_sent_bank_slots = EQ::invslot::BANK_BEGIN;
}
else if (m_lazy_load_sent_bank_slots > EQ::invslot::BANK_END &&
m_lazy_load_sent_bank_slots < EQ::invslot::SHARED_BANK_BEGIN) {
m_lazy_load_sent_bank_slots = EQ::invslot::SHARED_BANK_BEGIN;
}
else {
m_lazy_load_sent_bank_slots++;
}
// Jump the gaps
if (m_lazy_load_sent_bank_slots < EQ::invslot::BANK_BEGIN) {
m_lazy_load_sent_bank_slots = EQ::invslot::BANK_BEGIN;
}
else if (m_lazy_load_sent_bank_slots > EQ::invslot::BANK_END &&
m_lazy_load_sent_bank_slots < EQ::invslot::SHARED_BANK_BEGIN) {
m_lazy_load_sent_bank_slots = EQ::invslot::SHARED_BANK_BEGIN;
}
else {
m_lazy_load_sent_bank_slots++;
}
inst = m_inv[m_lazy_load_sent_bank_slots];
if (inst) {
SendItemPacket(m_lazy_load_sent_bank_slots, inst, ItemPacketType::ItemPacketTrade);
inst = m_inv[m_lazy_load_sent_bank_slots];
if (inst) {
SendItemPacket(m_lazy_load_sent_bank_slots, inst, ItemPacketType::ItemPacketTrade);
lazy_load_bank_slots++;
}
} else {
break;
}
}
}
@@ -776,65 +782,83 @@ void Client::BulkSendInventoryItems()
EQ::OutBuffer ob;
EQ::OutBuffer::pos_type last_pos = ob.tellp();
// Possessions items
for (int16 slot_id = EQ::invslot::POSSESSIONS_BEGIN; slot_id <= EQ::invslot::POSSESSIONS_END; slot_id++) {
// Equipment items
for (int16 slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; slot_id++) {
const EQ::ItemInstance* inst = m_inv[slot_id];
if (!inst)
if (!inst) {
continue;
}
inst->Serialize(ob, slot_id);
if (ob.tellp() == last_pos)
if (ob.tellp() == last_pos) {
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
}
last_pos = ob.tellp();
}
if (!RuleB(Inventory, LazyLoadBank)) {
// Bank items
for (int16 slot_id = EQ::invslot::BANK_BEGIN; slot_id <= EQ::invslot::BANK_END; slot_id++) {
const EQ::ItemInstance* inst = m_inv[slot_id];
if (!inst)
continue;
// General items
for (int16 slot_id = EQ::invslot::GENERAL_BEGIN; slot_id <= EQ::invslot::GENERAL_END; slot_id++) {
const EQ::ItemInstance* inst = m_inv[slot_id];
if (!inst) {
continue;
}
inst->Serialize(ob, slot_id);
inst->Serialize(ob, slot_id);
if (ob.tellp() == last_pos)
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
if (ob.tellp() == last_pos) {
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
}
last_pos = ob.tellp();
}
last_pos = ob.tellp();
}
// SharedBank items
for (int16 slot_id = EQ::invslot::SHARED_BANK_BEGIN; slot_id <= EQ::invslot::SHARED_BANK_END; slot_id++) {
const EQ::ItemInstance* inst = m_inv[slot_id];
if (!inst)
continue;
if (!RuleB(Inventory, LazyLoadBank)) {
// Bank items
for (int16 slot_id = EQ::invslot::BANK_BEGIN; slot_id <= EQ::invslot::BANK_END; slot_id++) {
const EQ::ItemInstance* inst = m_inv[slot_id];
if (!inst) {
continue;
}
inst->Serialize(ob, slot_id);
inst->Serialize(ob, slot_id);
if (ob.tellp() == last_pos)
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
if (ob.tellp() == last_pos) {
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
}
last_pos = ob.tellp();
}
}
last_pos = ob.tellp();
}
auto outapp = new EQApplicationPacket(OP_CharInventory);
outapp->size = ob.size();
outapp->pBuffer = ob.detach();
QueuePacket(outapp);
safe_delete(outapp);
// SharedBank items
for (int16 slot_id = EQ::invslot::SHARED_BANK_BEGIN; slot_id <= EQ::invslot::SHARED_BANK_END; slot_id++) {
const EQ::ItemInstance* inst = m_inv[slot_id];
if (!inst) {
continue;
}
inst->Serialize(ob, slot_id);
if (ob.tellp() == last_pos) {
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
}
last_pos = ob.tellp();
}
}
auto outapp = new EQApplicationPacket(OP_CharInventory);
outapp->size = ob.size();
outapp->pBuffer = ob.detach();
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
const EQ::ItemData* handy_item = nullptr;
uint32 merchant_slots = 80; //The max number of items passed in the transaction.
if (m_ClientVersionBit & EQ::versions::maskRoFAndLater) { // RoF+ can send 200 items
merchant_slots = 200;
}
const EQ::ItemData *item = nullptr;
auto merchant_list = zone->merchanttable[merchant_id];
auto npc = entity_list.GetMobByNpcTypeID(npcid);
@@ -846,6 +870,8 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
}
}
const int16 merchant_slots = (m_ClientVersionBit & EQ::versions::maskRoFAndLater) ? EQ::invtype::MERCHANT_SIZE : 80;
auto temporary_merchant_list = zone->tmpmerchanttable[npcid];
uint32 slot_id = 1;
uint8 handy_chance = 0;
+2 -2
View File
@@ -845,7 +845,7 @@ LootItem *Corpse::GetItem(uint16 lootslot, LootItem **bag_item_data)
// convert above code to for loop
for (const auto &item: m_item_list) {
if (item->equip_slot >= bagstart && item->equip_slot < bagstart + 10) {
if (item->equip_slot >= bagstart && item->equip_slot < bagstart + EQ::invbag::SLOT_COUNT) {
bag_item_data[item->equip_slot - bagstart] = item;
}
}
@@ -1472,7 +1472,7 @@ void Corpse::LootCorpseItem(Client *c, const EQApplicationPacket *app)
const EQ::ItemData *item = nullptr;
EQ::ItemInstance *inst = nullptr;
LootItem *item_data = nullptr, *bag_item_data[10] = {};
LootItem *item_data = nullptr, *bag_item_data[EQ::invbag::SLOT_COUNT] = {};
memset(bag_item_data, 0, sizeof(bag_item_data));
if (GetPlayerKillItem() > 1) {
+19 -19
View File
@@ -278,25 +278,25 @@ int Perl__getinventoryslotid(std::string identifier)
else if (identifier == "generalbags.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN;
else if (identifier == "generalbags.end") result = EQ::invbag::GENERAL_BAGS_END;
else if (identifier == "general1bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN;
else if (identifier == "general1bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + 9;
else if (identifier == "general2bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + 10;
else if (identifier == "general2bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + 19;
else if (identifier == "general3bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + 20;
else if (identifier == "general3bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + 29;
else if (identifier == "general4bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + 30;
else if (identifier == "general4bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + 39;
else if (identifier == "general5bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + 40;
else if (identifier == "general5bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + 49;
else if (identifier == "general6bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + 50;
else if (identifier == "general6bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + 59;
else if (identifier == "general7bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + 60;
else if (identifier == "general7bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + 69;
else if (identifier == "general8bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + 70;
else if (identifier == "general8bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + 79;
else if (identifier == "general9bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + 80;
else if (identifier == "general9bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + 89;
else if (identifier == "general10bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + 90;
else if (identifier == "general10bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + 99;
else if (identifier == "general1bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + (EQ::invbag::SLOT_COUNT - 1);
else if (identifier == "general2bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + EQ::invbag::SLOT_COUNT;
else if (identifier == "general2bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + ((EQ::invbag::SLOT_COUNT * 2) - 1);
else if (identifier == "general3bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + (EQ::invbag::SLOT_COUNT * 2);
else if (identifier == "general3bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + ((EQ::invbag::SLOT_COUNT * 3) - 1);
else if (identifier == "general4bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + (EQ::invbag::SLOT_COUNT * 3);
else if (identifier == "general4bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + ((EQ::invbag::SLOT_COUNT * 4) - 1);
else if (identifier == "general5bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + (EQ::invbag::SLOT_COUNT * 4);
else if (identifier == "general5bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + ((EQ::invbag::SLOT_COUNT * 5) - 1);
else if (identifier == "general6bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + (EQ::invbag::SLOT_COUNT * 5);
else if (identifier == "general6bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + ((EQ::invbag::SLOT_COUNT * 6) - 1);
else if (identifier == "general7bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + (EQ::invbag::SLOT_COUNT * 6);
else if (identifier == "general7bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + ((EQ::invbag::SLOT_COUNT * 7) - 1);
else if (identifier == "general8bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + (EQ::invbag::SLOT_COUNT * 7);
else if (identifier == "general8bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + ((EQ::invbag::SLOT_COUNT * 8) - 1);
else if (identifier == "general9bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + (EQ::invbag::SLOT_COUNT * 8);
else if (identifier == "general9bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + ((EQ::invbag::SLOT_COUNT * 9) - 1);
else if (identifier == "general10bag.begin") result = EQ::invbag::GENERAL_BAGS_BEGIN + (EQ::invbag::SLOT_COUNT * 9);
else if (identifier == "general10bag.end") result = EQ::invbag::GENERAL_BAGS_BEGIN + ((EQ::invbag::SLOT_COUNT * 10) - 1);
else if (identifier == "cursorbag.begin") result = EQ::invbag::CURSOR_BAG_BEGIN;
else if (identifier == "cursorbag.end") result = EQ::invbag::CURSOR_BAG_END;
else if (identifier == "bank.begin") result = EQ::invslot::BANK_BEGIN;
+4 -4
View File
@@ -310,7 +310,7 @@ void ShowInventory(Client *c, const Seperator *sep)
Chat::White,
fmt::format(
"Slot {} | {} ({}){}",
(8000 + limboIndex),
(14000 + limboIndex),
item_data->ID,
linker.GenerateLink(),
(
@@ -339,7 +339,7 @@ void ShowInventory(Client *c, const Seperator *sep)
Chat::White,
fmt::format(
"Slot {} (Augment Slot {}) | {} ({}){}",
(8000 + limboIndex),
(14000 + limboIndex),
augment_index,
linker.GenerateLink(),
item_data->ID,
@@ -375,7 +375,7 @@ void ShowInventory(Client *c, const Seperator *sep)
Chat::White,
fmt::format(
"Slot {} Bag Slot {} | {} ({}){}",
(8000 + limboIndex),
(14000 + limboIndex),
sub_index,
linker.GenerateLink(),
item_data->ID,
@@ -407,7 +407,7 @@ void ShowInventory(Client *c, const Seperator *sep)
Chat::White,
fmt::format(
"Slot {} Bag Slot {} (Augment Slot {}) | {} ({}){}",
(8000 + limboIndex),
(14000 + limboIndex),
sub_index,
augment_index,
linker.GenerateLink(),
+40 -14
View File
@@ -1919,13 +1919,20 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
return false;
}
//verify shared bank transactions in the database
if (src_inst && src_slot_id >= EQ::invslot::SHARED_BANK_BEGIN && src_slot_id <= EQ::invbag::SHARED_BANK_BAGS_END) {
if (
src_inst &&
(
EQ::ValueWithin(src_slot_id, EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END) ||
EQ::ValueWithin(src_slot_id, EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END)
)
) {
if(!database.VerifyInventory(account_id, src_slot_id, src_inst)) {
LogError("Player [{}] on account [{}] was found exploiting the shared bank.\n", GetName(), account_name);
DeleteItemInInventory(dst_slot_id,0,true);
return(false);
}
if (src_slot_id >= EQ::invslot::SHARED_BANK_BEGIN && src_slot_id <= EQ::invslot::SHARED_BANK_END && src_inst->IsClassBag()){
if (EQ::ValueWithin(src_slot_id, EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END) && src_inst->IsClassBag()){
for (uint8 idx = EQ::invbag::SLOT_BEGIN; idx <= EQ::invbag::SLOT_END; idx++) {
const EQ::ItemInstance* baginst = src_inst->GetItem(idx);
if (baginst && !database.VerifyInventory(account_id, EQ::InventoryProfile::CalcSlotId(src_slot_id, idx), baginst)){
@@ -1934,13 +1941,21 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
}
}
}
if (dst_inst && dst_slot_id >= EQ::invslot::SHARED_BANK_BEGIN && dst_slot_id <= EQ::invbag::SHARED_BANK_BAGS_END) {
if (
dst_inst &&
(
EQ::ValueWithin(dst_slot_id, EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END) ||
EQ::ValueWithin(dst_slot_id, EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END)
)
) {
if(!database.VerifyInventory(account_id, dst_slot_id, dst_inst)) {
LogError("Player [{}] on account [{}] was found exploting the shared bank.\n", GetName(), account_name);
DeleteItemInInventory(src_slot_id,0,true);
return(false);
}
if (dst_slot_id >= EQ::invslot::SHARED_BANK_BEGIN && dst_slot_id <= EQ::invslot::SHARED_BANK_END && dst_inst->IsClassBag()){
if (EQ::ValueWithin(dst_slot_id, EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END) && dst_inst->IsClassBag()){
for (uint8 idx = EQ::invbag::SLOT_BEGIN; idx <= EQ::invbag::SLOT_END; idx++) {
const EQ::ItemInstance* baginst = dst_inst->GetItem(idx);
if (baginst && !database.VerifyInventory(account_id, EQ::InventoryProfile::CalcSlotId(dst_slot_id, idx), baginst)){
@@ -1953,10 +1968,20 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
// Check for No Drop Hacks
Mob* with = trade->With();
if (((with && with->IsClient() && !with->CastToClient()->IsBecomeNPC() && dst_slot_id >= EQ::invslot::TRADE_BEGIN && dst_slot_id <= EQ::invslot::TRADE_END) ||
(dst_slot_id >= EQ::invslot::SHARED_BANK_BEGIN && dst_slot_id <= EQ::invbag::SHARED_BANK_BAGS_END))
&& GetInv().CheckNoDrop(src_slot_id)
&& !CanTradeFVNoDropItem()) {
if (
(
(
with &&
with->IsClient() &&
!with->CastToClient()->IsBecomeNPC() &&
EQ::ValueWithin(dst_slot_id, EQ::invslot::TRADE_BEGIN, EQ::invslot::TRADE_END)
) ||
EQ::ValueWithin(dst_slot_id, EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END) ||
EQ::ValueWithin(dst_slot_id, EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END)
) &&
GetInv().CheckNoDrop(src_slot_id) &&
!CanTradeFVNoDropItem()
) {
auto ndh_inst = m_inv[src_slot_id];
std::string ndh_item_data;
if (ndh_inst == nullptr) {
@@ -3626,7 +3651,7 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool
if (cursor_itr == m_inv.cursor_cbegin())
continue;
instmap[8000 + limbo] = *cursor_itr;
instmap[EQ::invbag::CURSOR_BAG_BEGIN + limbo] = *cursor_itr;
}
// call InterrogateInventory_ for error check
@@ -3729,11 +3754,12 @@ bool Client::InterrogateInventory_error(int16 head, int16 index, const EQ::ItemI
// very basic error checking - can be elaborated upon if more in-depth testing is needed...
if (
(head >= EQ::invslot::EQUIPMENT_BEGIN && head <= EQ::invslot::EQUIPMENT_END) ||
(head >= EQ::invslot::TRIBUTE_BEGIN && head <= EQ::invslot::TRIBUTE_END) ||
(head >= EQ::invslot::GUILD_TRIBUTE_BEGIN && head <= EQ::invslot::GUILD_TRIBUTE_END) ||
(head >= EQ::invslot::WORLD_BEGIN && head <= EQ::invslot::WORLD_END) ||
(head >= 8000 && head <= 8101)) {
EQ::ValueWithin(head, EQ::invslot::EQUIPMENT_BEGIN, EQ::invslot::EQUIPMENT_END) ||
EQ::ValueWithin(head, EQ::invslot::TRIBUTE_BEGIN, EQ::invslot::TRIBUTE_END) ||
EQ::ValueWithin(head, EQ::invslot::GUILD_TRIBUTE_BEGIN, EQ::invslot::GUILD_TRIBUTE_END) ||
EQ::ValueWithin(head, EQ::invslot::WORLD_BEGIN, EQ::invslot::WORLD_END) ||
EQ::ValueWithin(head, EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END)
) {
switch (depth)
{
case 0: // requirement: inst is extant
+4 -4
View File
@@ -208,10 +208,10 @@ struct ZoneSpellsBlocked {
};
struct TraderCharges_Struct {
uint32 ItemID[80];
int32 SerialNumber[80];
uint32 ItemCost[80];
int32 Charges[80];
uint32 ItemID[EQ::invtype::BAZAAR_SIZE];
int32 SerialNumber[EQ::invtype::BAZAAR_SIZE];
uint32 ItemCost[EQ::invtype::BAZAAR_SIZE];
int32 Charges[EQ::invtype::BAZAAR_SIZE];
};
const int MaxMercStanceID = 9;