From abc5ddc5f8bf21c077f0e8a18609f46656cc4243 Mon Sep 17 00:00:00 2001 From: KimLS Date: Mon, 2 Mar 2015 00:44:28 -0800 Subject: [PATCH] Inventory Swap implemented and passes tests, though still want to verify it a bit more also does not yet save but that's next. Fixed a crash in memory buffer too. --- common/data_verification.h | 18 +++---- common/inventory.cpp | 73 ++++++++++++++++++++++++--- common/inventory.h | 4 ++ common/item.cpp | 2 +- common/item_instance.cpp | 62 +++++++++++++++-------- common/item_instance.h | 5 +- common/memory_buffer.cpp | 2 +- common/memory_buffer.h | 2 +- common/shareddb.cpp | 11 +--- tests/inventory_test.h | 46 +++++++++++++++-- zone/client_packet.cpp | 6 ++- zone/client_process.cpp | 100 ------------------------------------- zone/inventory.cpp | 6 ++- 13 files changed, 177 insertions(+), 160 deletions(-) diff --git a/common/data_verification.h b/common/data_verification.h index e0cb055c2..aa44df7bc 100644 --- a/common/data_verification.h +++ b/common/data_verification.h @@ -23,19 +23,19 @@ namespace EQEmu { -template -T Clamp(const T& value, const T& lower, const T& upper) { - return std::max(lower, std::min(value, upper)); +template +T Clamp(const T& value, const U& lower, const V& upper) { + return std::max(static_cast(lower), std::min(value, static_cast(upper))); } -template -T ClampLower(const T& value, const T& lower) { - return std::max(lower, value); +template +T ClampLower(const T& value, const U& lower) { + return std::max(static_cast(lower), value); } -template -T ClampUpper(const T& value, const T& upper) { - return std::min(value, upper); +template +T ClampUpper(const T& value, const U& upper) { + return std::min(value, static_cast(upper)); } template diff --git a/common/inventory.cpp b/common/inventory.cpp index f2b418ec7..c9124ced6 100644 --- a/common/inventory.cpp +++ b/common/inventory.cpp @@ -136,6 +136,18 @@ EQEmu::Inventory::~Inventory() { delete impl_; } +void EQEmu::Inventory::SetRace(int race) { + impl_->race_ = race; +} + +void EQEmu::Inventory::SetClass(int class_) { + impl_->class_ = class_; +} + +void EQEmu::Inventory::SetDeity(int deity) { + impl_->deity_ = deity; +} + std::shared_ptr EQEmu::Inventory::Get(const InventorySlot &slot) { auto iter = impl_->containers_.find(slot.Type()); if(iter != impl_->containers_.end()) { @@ -202,15 +214,12 @@ bool EQEmu::Inventory::Put(const InventorySlot &slot, std::shared_ptr %s (%i)\n", src.IsCursor() ? "Cursor" : src.ToString().c_str(), dest.IsCursor() ? "Cursor" : dest.ToString().c_str(), charges); - if(src == dest) { return true; } if(dest.IsDelete()) { - //return Delete(src); - return false; + return _destroy(src); } if(!src.IsValid() || !dest.IsValid()) { @@ -220,11 +229,11 @@ bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest, auto i_src = Get(src); auto i_dest = Get(dest); - if(dest.IsEquipment() && !CanEquip(i_dest, dest)) { + if(!i_src) { return false; } - if(!i_src) { + if(dest.IsEquipment() && !CanEquip(i_src, dest)) { return false; } @@ -234,8 +243,56 @@ bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest, } if(i_src->IsStackable()) { - //charges == 0 -> Move entire stack from src to dest - //charges > 0 -> Move charges number of charges from src to dest (may require creating a new item + //move # charges from src to dest + + //0 means *all* the charges + if(charges == 0) { + charges = i_src->GetCharges(); + } + + //src needs to have that many charges + if(i_src->GetCharges() < charges) { + return false; + } + + //if dest exists it needs to not only be the same item id but also be able to hold enough charges + if(i_dest) { + uint32 src_id = i_src->GetBaseItem()->ID; + uint32 dest_id = i_dest->GetBaseItem()->ID; + if(src_id != dest_id) { + return false; + } + + int charges_avail = i_dest->GetBaseItem()->StackSize - i_dest->GetCharges(); + if(charges_avail < charges) { + return false; + } + + if(i_src->GetCharges() == charges) { + if(!_destroy(src)) { + return false; + } + } else { + i_src->SetCharges(i_src->GetCharges() - charges); + } + + i_dest->SetCharges(i_dest->GetCharges() + charges); + return true; + } else { + //if dest does not exist and src charges > # charges then we need to create a new item with # charges in dest + //if dest does not exist and src charges == # charges then we need to swap src to dest + if(i_src->GetCharges() > charges) { + auto split = i_src->Split(charges); + if(!split) { + return false; + } + + Put(dest, split); + return true; + } else { + return _swap(src, dest); + } + } } else { return _swap(src, dest); } diff --git a/common/inventory.h b/common/inventory.h index fb55b1765..24c5e7881 100644 --- a/common/inventory.h +++ b/common/inventory.h @@ -126,6 +126,10 @@ namespace EQEmu Inventory(int race, int class_, int deity); ~Inventory(); + void SetRace(int race); + void SetClass(int class_); + void SetDeity(int deity); + std::shared_ptr Get(const InventorySlot &slot); bool Put(const InventorySlot &slot, std::shared_ptr inst); bool Swap(const InventorySlot &src, const InventorySlot &dest, int charges); diff --git a/common/item.cpp b/common/item.cpp index 0a9bb2dc4..67664ccc5 100644 --- a/common/item.cpp +++ b/common/item.cpp @@ -993,7 +993,7 @@ int InventoryOld::GetSlotByItemInst(ItemInst *inst) { return INVALID_INDEX; } -uint8 Inventory::FindBrightestLightType() +uint8 InventoryOld::FindBrightestLightType() { uint8 brightest_light_type = 0; diff --git a/common/item_instance.cpp b/common/item_instance.cpp index d4880d199..f3c24aad5 100644 --- a/common/item_instance.cpp +++ b/common/item_instance.cpp @@ -20,6 +20,12 @@ #include "data_verification.h" #include "item_container.h" +uint32 ItemInstanceSerial = 1; +uint32 EQEmu::GetNextItemInstanceSerial() { + ItemInstanceSerial++; + return ItemInstanceSerial; +} + struct EQEmu::ItemInstance::impl { const ItemData *base_item_; ItemData *modified_item_; @@ -39,24 +45,6 @@ struct EQEmu::ItemInstance::impl { ItemContainer contents_; }; -EQEmu::ItemInstance::ItemInstance() { - impl_ = new impl; - impl_->base_item_ = nullptr; - impl_->modified_item_ = nullptr; - impl_->charges_ = -1; - impl_->color_ = 0; - impl_->attuned_ = false; - impl_->ornament_idfile_ = 0; - impl_->ornament_icon_ = 0; - impl_->ornament_hero_model_ = 0; - impl_->serial_id_ = 0; - impl_->recast_timestamp_ = 0; - impl_->merchant_slot_ = 0; - impl_->merchant_count_ = 0; - impl_->price_ = 0; - memset(impl_->tracking_id_, 0, 17); -} - EQEmu::ItemInstance::ItemInstance(const ItemData* idata) { impl_ = new impl; impl_->base_item_ = idata; @@ -97,6 +85,39 @@ EQEmu::ItemInstance::~ItemInstance() { delete impl_; } + +std::shared_ptr EQEmu::ItemInstance::Split(int charges) { + if(!IsStackable()) { + //Can't split non stackable items! + return std::shared_ptr(nullptr); + } + + if(charges >= GetCharges()) { + return std::shared_ptr(nullptr); + } + + if(impl_->contents_.Size() > 0) { + return std::shared_ptr(nullptr); + } + + std::shared_ptr split = std::shared_ptr(new EQEmu::ItemInstance(impl_->base_item_, charges)); + split->SetSerialNumber(EQEmu::GetNextItemInstanceSerial()); + //Set Tracking here + split->impl_->attuned_ = impl_->attuned_; + split->impl_->custom_data_ = impl_->custom_data_; + split->impl_->recast_timestamp_ = impl_->recast_timestamp_; + split->impl_->price_ = impl_->price_; + split->impl_->color_ = impl_->color_; + split->impl_->merchant_count_ = impl_->merchant_count_; + split->impl_->merchant_slot_ = impl_->merchant_slot_; + split->impl_->ornament_hero_model_ = impl_->ornament_hero_model_; + split->impl_->ornament_icon_ = impl_->ornament_icon_; + split->impl_->ornament_idfile_ = impl_->ornament_idfile_; + + SetCharges(GetCharges() - charges); + return split; +} + const ItemData *EQEmu::ItemInstance::GetItem() { return impl_->modified_item_ ? impl_->modified_item_ : impl_->base_item_; } @@ -118,10 +139,6 @@ std::shared_ptr EQEmu::ItemInstance::Get(const int index) { } bool EQEmu::ItemInstance::Put(const int index, std::shared_ptr inst) { - if(!inst || !inst->GetItem()) { - return false; - } - if(!impl_->base_item_) { return false; } @@ -342,3 +359,4 @@ bool EQEmu::ItemInstance::IsNoDrop() const { EQEmu::ItemContainer *EQEmu::ItemInstance::GetContainer() { return &(impl_->contents_); } + diff --git a/common/item_instance.h b/common/item_instance.h index 29f2394a2..18901bff6 100644 --- a/common/item_instance.h +++ b/common/item_instance.h @@ -24,11 +24,12 @@ namespace EQEmu { + uint32 GetNextItemInstanceSerial(); + class ItemContainer; class ItemInstance { public: - ItemInstance(); ItemInstance(const ItemData* idata); ItemInstance(const ItemData* idata, const int16 charges); ~ItemInstance(); @@ -37,6 +38,8 @@ namespace EQEmu const ItemData *GetBaseItem(); const ItemData *GetBaseItem() const; + std::shared_ptr Split(int charges); + //Container std::shared_ptr Get(const int index); bool Put(const int index, std::shared_ptr inst); diff --git a/common/memory_buffer.cpp b/common/memory_buffer.cpp index 4f47867d8..c762a1118 100644 --- a/common/memory_buffer.cpp +++ b/common/memory_buffer.cpp @@ -162,7 +162,7 @@ void EQEmu::MemoryBuffer::Resize(size_t sz) { if(sz > capacity_) { size_t new_size = sz + 32; uchar *temp = new uchar[new_size]; - memcpy(temp, buffer_, new_size); + memcpy(temp, buffer_, capacity_); delete[] buffer_; buffer_ = temp; diff --git a/common/memory_buffer.h b/common/memory_buffer.h index 26a5897df..689ed81bd 100644 --- a/common/memory_buffer.h +++ b/common/memory_buffer.h @@ -121,4 +121,4 @@ namespace EQEmu } // EQEmu -#endif \ No newline at end of file +#endif diff --git a/common/shareddb.cpp b/common/shareddb.cpp index f7f18aeb8..cf18cac55 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -15,14 +15,6 @@ #include "shareddb.h" #include "string_util.h" -uint32 ItemInstanceSerial = 1; -static inline uint32 GetNextItemInstanceSerial() { - ItemInstanceSerial++; - return ItemInstanceSerial; -} - - - SharedDatabase::SharedDatabase() : Database(), skill_caps_mmf(nullptr), items_mmf(nullptr), items_hash(nullptr), faction_mmf(nullptr), faction_hash(nullptr), loot_table_mmf(nullptr), loot_table_hash(nullptr), loot_drop_mmf(nullptr), loot_drop_hash(nullptr), base_data_mmf(nullptr) @@ -1273,7 +1265,8 @@ std::shared_ptr SharedDatabase::CreateItem(uint32 item_id, } std::shared_ptr inst = std::shared_ptr(new EQEmu::ItemInstance(item, charges)); - inst->SetSerialNumber(GetNextItemInstanceSerial()); + inst->SetSerialNumber(EQEmu::GetNextItemInstanceSerial()); + //Set Tracking here return inst; } diff --git a/tests/inventory_test.h b/tests/inventory_test.h index f373e9cf0..11ff2acd0 100644 --- a/tests/inventory_test.h +++ b/tests/inventory_test.h @@ -38,6 +38,8 @@ public: TEST_ADD(InventoryTest::InventorySwapCursorToGeneral2); TEST_ADD(InventoryTest::InventorySplitStackToCursor); TEST_ADD(InventoryTest::InventoryStackCombine); + TEST_ADD(InventoryTest::InventorySplitStackToCursor2); + TEST_ADD(InventoryTest::InventoryStackCombine2); } ~InventoryTest() { @@ -135,7 +137,7 @@ private: stackable.SkillModType = -1; stackable.Click.Effect = -1; stackable.Weight = 5; - stackable.StackSize = 100; + stackable.StackSize = 105; stackable.Stackable = 1; stackable.Size = 1; stackable.Proc.Effect = -1; @@ -261,13 +263,13 @@ private: } void InventorySplitStackToCursor() { - auto swap_result = inv.Swap(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral1, 7), + auto swap_result = inv.Swap(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral2, 7), EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor), 10); TEST_ASSERT(swap_result == true); auto m_stackable_cursor = inv.Get(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor)); - auto m_stackable = inv.Get(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral1, 7)); + auto m_stackable = inv.Get(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral2, 7)); TEST_ASSERT(m_stackable_cursor); TEST_ASSERT(m_stackable); @@ -278,12 +280,12 @@ private: void InventoryStackCombine() { auto swap_result = inv.Swap(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor), - EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral1, 7), 0); + EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral2, 7), 0); TEST_ASSERT(swap_result == true); auto m_cursor = inv.Get(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor)); - auto m_stackable = inv.Get(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral1, 7)); + auto m_stackable = inv.Get(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral2, 7)); TEST_ASSERT(!m_cursor); TEST_ASSERT(m_stackable); @@ -291,6 +293,40 @@ private: TEST_ASSERT(m_stackable->GetCharges() == 100); } + void InventorySplitStackToCursor2() { + std::shared_ptr m_stackable_i(new EQEmu::ItemInstance(&stackable, 10)); + inv.Put(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral2, 8), m_stackable_i); + + auto swap_result = inv.Swap(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral2, 8), + EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor), 0); + + TEST_ASSERT(swap_result == true); + + auto m_stackable_cursor = inv.Get(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor)); + auto m_stackable = inv.Get(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral2, 8)); + + TEST_ASSERT(m_stackable_cursor); + TEST_ASSERT(!m_stackable); + + TEST_ASSERT(m_stackable_cursor->GetCharges() == 10); + } + + void InventoryStackCombine2() { + auto swap_result = inv.Swap(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor), + EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral2, 7), 5); + + TEST_ASSERT(swap_result == true); + + auto m_cursor = inv.Get(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor)); + auto m_stackable = inv.Get(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotGeneral2, 7)); + + TEST_ASSERT(m_cursor); + TEST_ASSERT(m_stackable); + + TEST_ASSERT(m_stackable->GetCharges() == 105); + TEST_ASSERT(m_cursor->GetCharges() == 5); + } + EQEmu::Inventory inv; ItemData container; ItemData armor; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index e9343ba0b..84c102817 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1271,7 +1271,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) m_pp.platinum_shared = database.GetSharedPlatinum(this->AccountID()); database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */ - loaditems = database.GetInventory(cid, &m_inventory); /* Load Character Inventory */ database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */ database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */ database.LoadCharacterMaterialColor(cid, &m_pp); /* Load Character Material */ @@ -1287,6 +1286,11 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) database.LoadCharacterLeadershipAA(cid, &m_pp); /* Load Character Leadership AA's */ database.LoadCharacterTribute(cid, &m_pp); /* Load CharacterTribute */ + m_inventory.SetRace(GetBaseRace()); + m_inventory.SetClass(GetBaseClass()); + m_inventory.SetDeity(GetDeity()); + loaditems = database.GetInventory(cid, &m_inventory); /* Load Character Inventory */ + /* Load AdventureStats */ AdventureStats_Struct as; if(database.GetAdventureStats(cid, &as)) diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 7d9066930..662264d95 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -824,106 +824,6 @@ void Client::BulkSendInventoryItems() { EQApplicationPacket outapp(OP_CharInventory, items.Size()); memcpy(outapp.pBuffer, items, items.Size()); QueuePacket(&outapp); - - - //int16 slot_id = 0; - // - //// LINKDEAD TRADE ITEMS - //// Move trade slot items back into normal inventory..need them there now for the proceeding validity checks -U - //for(slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_END; slot_id++) { - // ItemInst* inst = m_inv.PopItem(slot_id); - // if(inst) { - // bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false; - // int16 free_slot_id = m_inv.FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size, is_arrow); - // Log.Out(Logs::Detail, Logs::Inventory, "Incomplete Trade Transaction: Moving %s from slot %i to %i", inst->GetItem()->Name, slot_id, free_slot_id); - // PutItemInInventory(free_slot_id, *inst, false); - // database.SaveInventory(character_id, nullptr, slot_id); - // safe_delete(inst); - // } - //} - // - //bool deletenorent = database.NoRentExpired(GetName()); - //if(deletenorent){ RemoveNoRent(false); } //client was offline for more than 30 minutes, delete no rent items - // - //RemoveDuplicateLore(false); - //MoveSlotNotAllowed(false); - // - //// The previous three method calls took care of moving/removing expired/illegal item placements -U - // - ////TODO: this function is just retarded... it re-allocates the buffer for every - ////new item. It should be changed to loop through once, gather the - ////lengths, and item packet pointers into an array (fixed length), and - ////then loop again to build the packet. - ////EQApplicationPacket *packets[50]; - ////unsigned long buflen = 0; - ////unsigned long pos = 0; - ////memset(packets, 0, sizeof(packets)); - ////foreach item in the invendor sections - //// packets[pos++] = ReturnItemPacket(...) - //// buflen += temp->size - ////... - ////allocat the buffer - ////for r from 0 to pos - //// put pos[r]->pBuffer into the buffer - ////for r from 0 to pos - //// safe_delete(pos[r]); - // - //uint32 size = 0; - //uint16 i = 0; - //std::map ser_items; - //std::map::iterator itr; - // - ////Inventory items - //for(slot_id = MAIN_BEGIN; slot_id < EmuConstants::MAP_POSSESSIONS_SIZE; slot_id++) { - // const ItemInst* inst = m_inv[slot_id]; - // if(inst) { - // std::string packet = inst->Serialize(slot_id); - // ser_items[i++] = packet; - // size += packet.length(); - // } - //} - // - //// Power Source - //if(GetClientVersion() >= ClientVersion::SoF) { - // const ItemInst* inst = m_inv[MainPowerSource]; - // if(inst) { - // std::string packet = inst->Serialize(MainPowerSource); - // ser_items[i++] = packet; - // size += packet.length(); - // } - //} - // - //// Bank items - //for(slot_id = EmuConstants::BANK_BEGIN; slot_id <= EmuConstants::BANK_END; slot_id++) { - // const ItemInst* inst = m_inv[slot_id]; - // if(inst) { - // std::string packet = inst->Serialize(slot_id); - // ser_items[i++] = packet; - // size += packet.length(); - // } - //} - // - //// Shared Bank items - //for(slot_id = EmuConstants::SHARED_BANK_BEGIN; slot_id <= EmuConstants::SHARED_BANK_END; slot_id++) { - // const ItemInst* inst = m_inv[slot_id]; - // if(inst) { - // std::string packet = inst->Serialize(slot_id); - // ser_items[i++] = packet; - // size += packet.length(); - // } - //} - // - //EQApplicationPacket* outapp = new EQApplicationPacket(OP_CharInventory, size); - //uchar* ptr = outapp->pBuffer; - //for(itr = ser_items.begin(); itr != ser_items.end(); ++itr){ - // int length = itr->second.length(); - // if(length > 5) { - // memcpy(ptr, itr->second.c_str(), length); - // ptr += length; - // } - //} - //QueuePacket(outapp); - //safe_delete(outapp); } void Client::BulkSendMerchantInventory(int merchant_id, int npcid) { diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 143b3d18f..72ba9984e 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -3133,12 +3133,14 @@ bool Client::SwapItem(const EQEmu::InventorySlot &src, const EQEmu::InventorySlo } } + Message(0, "%s -> %s (%i)\n", src.IsCursor() ? "Cursor" : src.ToString().c_str(), dest.IsCursor() ? "Cursor" : dest.ToString().c_str(), number_in_stack); + bool res = m_inventory.Swap(src, dest, number_in_stack); if(res) { - printf("Swap success\n"); + Message(0, "Swap success\n"); } else { - printf("Swap failure!\n"); + Message(0, "Swap failure!\n"); } if(auto_attack && res && recalc_weapon_speed) {