From 9fcdf5367e77f1c1a7c0169bcb5ebd0c35e9a378 Mon Sep 17 00:00:00 2001 From: KimLS Date: Wed, 4 Mar 2015 19:33:01 -0800 Subject: [PATCH] Swap saving now works correctly except for cursor items which wont be reloaded correctly as we don't send cursor on login yet. Also added check for bag into another bag src bag needs to have nothing in it first. --- common/CMakeLists.txt | 2 + common/inventory.cpp | 8 +- common/inventory.h | 2 +- common/inventory_data_model.h | 6 +- common/inventory_db_data_model.cpp | 197 +++++++++++++++++++++++++++++ common/inventory_db_data_model.h | 45 +++++++ common/inventory_null_data_model.h | 6 +- common/item_instance.cpp | 24 ++++ common/item_instance.h | 6 + zone/client_packet.cpp | 2 + 10 files changed, 290 insertions(+), 8 deletions(-) create mode 100644 common/inventory_db_data_model.cpp create mode 100644 common/inventory_db_data_model.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index c66ff5776..292d1032b 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -31,6 +31,7 @@ SET(common_sources guild_base.cpp guilds.cpp inventory.cpp + inventory_db_data_model.cpp ipc_mutex.cpp item.cpp item_container.cpp @@ -143,6 +144,7 @@ SET(common_headers guilds.h inventory.h inventory_data_model.h + inventory_db_data_model.h inventory_null_data_model.h ipc_mutex.h item.h diff --git a/common/inventory.cpp b/common/inventory.cpp index 5d5a2c9ed..e90322b93 100644 --- a/common/inventory.cpp +++ b/common/inventory.cpp @@ -151,7 +151,7 @@ void EQEmu::Inventory::SetDeity(int deity) { impl_->deity_ = deity; } -void EQEmu::Inventory::SetDataMode(InventoryDataModel *dm) { +void EQEmu::Inventory::SetDataModel(InventoryDataModel *dm) { impl_->data_model_ = std::unique_ptr(dm); } @@ -236,6 +236,12 @@ bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest, return false; } + if(i_src->GetBaseItem()->ItemClass == ItemClassContainer && dest.BagIndex() > -1) { + if(i_src->GetContainer()->Size() > 0) { + return false; + } + } + if(dest.IsEquipment() && !CanEquip(i_src, dest)) { return false; } diff --git a/common/inventory.h b/common/inventory.h index 75a33b690..d4ef2a8cf 100644 --- a/common/inventory.h +++ b/common/inventory.h @@ -130,7 +130,7 @@ namespace EQEmu void SetRace(int race); void SetClass(int class_); void SetDeity(int deity); - void SetDataMode(InventoryDataModel *dm); + void SetDataModel(InventoryDataModel *dm); std::shared_ptr Get(const InventorySlot &slot); bool Put(const InventorySlot &slot, std::shared_ptr inst); diff --git a/common/inventory_data_model.h b/common/inventory_data_model.h index c35922147..5bf6a2ec9 100644 --- a/common/inventory_data_model.h +++ b/common/inventory_data_model.h @@ -30,10 +30,10 @@ namespace EQEmu virtual ~InventoryDataModel() { } virtual void Begin() = 0; - virtual void Commit() = 0; + virtual bool Commit() = 0; virtual void Rollback() = 0; - virtual bool Insert(const InventorySlot &slot, std::shared_ptr inst) = 0; - virtual bool Delete(const InventorySlot &slot) = 0; + virtual void Insert(const InventorySlot &slot, std::shared_ptr inst) = 0; + virtual void Delete(const InventorySlot &slot) = 0; }; } // EQEmu diff --git a/common/inventory_db_data_model.cpp b/common/inventory_db_data_model.cpp new file mode 100644 index 000000000..080467341 --- /dev/null +++ b/common/inventory_db_data_model.cpp @@ -0,0 +1,197 @@ +#include "inventory_db_data_model.h" +#include "shareddb.h" +#include "string_util.h" +#include +#include + +enum DataEventTypes +{ + DB_Insert, + DB_Delete +}; + +struct DataEvent +{ + DataEventTypes evt; + EQEmu::InventorySlot slot; + std::shared_ptr inst; +}; + +struct EQEmu::InventoryDatabaseDataModel::impl { + SharedDatabase *db_; + std::list events_; + uint32 char_id_; +}; + +EQEmu::InventoryDatabaseDataModel::InventoryDatabaseDataModel(SharedDatabase *db, uint32 char_id) { + impl_ = new impl; + impl_->db_ = db; + impl_->char_id_ = char_id; +} + +EQEmu::InventoryDatabaseDataModel::~InventoryDatabaseDataModel() { + delete impl_; +} + +void EQEmu::InventoryDatabaseDataModel::Begin() { + impl_->db_->TransactionBegin(); + impl_->events_.clear(); +} + +bool EQEmu::InventoryDatabaseDataModel::Commit() { + std::string base_insert = "INSERT INTO character_inventory(id, type, slot, bag_index, aug_index, " + "item_id, charges, color, attuned, custom_data, ornament_icon, ornament_idfile, ornament_hero_model" + ", tracking_id) VALUES"; + + std::string current_insert = base_insert; + bool insert = false; + for(auto iter : impl_->events_) { + if(iter.evt == DB_Delete) { + if(insert) { + insert = false; + + //commit the current_insert + auto res = impl_->db_->QueryDatabase(current_insert); + if(!res.Success()) { + Rollback(); + return false; + } + + current_insert = base_insert; + } + + std::string current_delete; + if(iter.slot.BagIndex() > -1) { + if(iter.slot.AugIndex() > -1) { + current_delete = StringFormat("DELETE FROM character_inventory WHERE id=%u AND type=%u AND slot=%u AND bag_index=%u AND aug_index=%u", + impl_->char_id_, iter.slot.Type(), iter.slot.Slot(), iter.slot.BagIndex(), iter.slot.AugIndex()); + } + else { + current_delete = StringFormat("DELETE FROM character_inventory WHERE id=%u AND type=%u AND slot=%u AND bag_index=%u", + impl_->char_id_, iter.slot.Type(), iter.slot.Slot(), iter.slot.BagIndex()); + } + } + else if(iter.slot.AugIndex() > -1) { + current_delete = StringFormat("DELETE FROM character_inventory WHERE id=%u AND type=%u AND slot=%u AND aug_index=%u", + impl_->char_id_, iter.slot.Type(), iter.slot.Slot(), iter.slot.AugIndex()); + } + else { + current_delete = StringFormat("DELETE FROM character_inventory WHERE id=%u AND type=%u AND slot=%u", + impl_->char_id_, iter.slot.Type(), iter.slot.Slot()); + } + + auto res = impl_->db_->QueryDatabase(current_delete); + if(!res.Success()) { + Rollback(); + return false; + } + + } else { + //insert + if(!insert) { + insert = true; + } else { + current_insert += ","; + } + + current_insert += StringFormat("(%u, %i, %i, %i, %i, %u, %i, %u, %u, '%s', %u, %u, %u, %llu)", + impl_->char_id_, + iter.slot.Type(), + iter.slot.Slot(), + iter.slot.BagIndex(), + iter.slot.AugIndex(), + iter.inst->GetBaseItem()->ID, + iter.inst->GetCharges(), + iter.inst->GetColor(), + iter.inst->GetAttuned(), + EscapeString(iter.inst->GetCustomData()).c_str(), + iter.inst->GetOrnamentIcon(), + iter.inst->GetOrnamentIDFile(), + iter.inst->GetOrnamentHeroModel(), + iter.inst->GetTrackingID()); + } + } + + if(insert) { + insert = false; + + //commit the current_insert + auto res = impl_->db_->QueryDatabase(current_insert); + if(!res.Success()) { + Rollback(); + return false; + } + + current_insert = base_insert; + } + + impl_->db_->TransactionCommit(); + impl_->events_.clear(); + return true; +} + +void EQEmu::InventoryDatabaseDataModel::Rollback() { + impl_->db_->TransactionRollback(); + impl_->events_.clear(); +} + +void EQEmu::InventoryDatabaseDataModel::Insert(const InventorySlot &slot, std::shared_ptr inst) { + DataEvent evt; + evt.evt = DB_Insert; + evt.inst = inst; + evt.slot = slot; + impl_->events_.push_back(evt); + + //insert current item + if(slot.BagIndex() < 0 && slot.AugIndex() < 0) { + //if bag put all bag contents in + //if common put all augment contents in + if(inst->GetBaseItem()->ItemClass == ItemClassContainer) { + auto container = inst->GetContainer(); + auto iter = container->Begin(); + while(iter != container->End()) { + DataEvent evt; + evt.evt = DB_Insert; + evt.inst = iter->second; + evt.slot = InventorySlot(slot.Type(), slot.Slot(), -1, iter->first); + impl_->events_.push_back(evt); + + ++iter; + } + } + else if(inst->GetBaseItem()->ItemClass == ItemClassCommon) { + auto container = inst->GetContainer(); + auto iter = container->Begin(); + while(iter != container->End()) { + DataEvent evt; + evt.evt = DB_Insert; + evt.inst = iter->second; + evt.slot = InventorySlot(slot.Type(), slot.Slot(), iter->first); + impl_->events_.push_back(evt); + + ++iter; + } + } + } + else if(inst->GetBaseItem()->ItemClass == ItemClassCommon) { + //if common put all augment contents in + auto container = inst->GetContainer(); + auto iter = container->Begin(); + while(iter != container->End()) { + DataEvent evt; + evt.evt = DB_Insert; + evt.inst = iter->second; + evt.slot = InventorySlot(slot.Type(), slot.Slot(), iter->first, slot.BagIndex()); + impl_->events_.push_back(evt); + + ++iter; + } + } +} + +void EQEmu::InventoryDatabaseDataModel::Delete(const InventorySlot &slot) { + DataEvent evt; + evt.evt = DB_Delete; + evt.slot = slot; + impl_->events_.push_back(evt); +} diff --git a/common/inventory_db_data_model.h b/common/inventory_db_data_model.h new file mode 100644 index 000000000..b43ec6412 --- /dev/null +++ b/common/inventory_db_data_model.h @@ -0,0 +1,45 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_INVENTORY_DB_DATA_MODEL_H +#define COMMON_INVENTORY_DB_DATA_MODEL_H + +#include "inventory_data_model.h" + +class SharedDatabase; + +namespace EQEmu +{ + class InventoryDatabaseDataModel : public InventoryDataModel + { + public: + InventoryDatabaseDataModel(SharedDatabase *db, uint32 char_id); + virtual ~InventoryDatabaseDataModel(); + + virtual void Begin(); + virtual bool Commit(); + virtual void Rollback(); + virtual void Insert(const InventorySlot &slot, std::shared_ptr inst); + virtual void Delete(const InventorySlot &slot); + private: + struct impl; + impl *impl_; + }; +} // EQEmu + +#endif diff --git a/common/inventory_null_data_model.h b/common/inventory_null_data_model.h index 3f3433df0..460fe1b3b 100644 --- a/common/inventory_null_data_model.h +++ b/common/inventory_null_data_model.h @@ -30,10 +30,10 @@ namespace EQEmu virtual ~InventoryNullDataModel() { } virtual void Begin() { printf("NDM: Begin\n"); } - virtual void Commit() { printf("NDM: Commit\n"); } + virtual bool Commit() { printf("NDM: Commit\n"); return true; } virtual void Rollback() { printf("NDM: Rollback\n"); } - virtual bool Insert(const InventorySlot &slot, std::shared_ptr inst) { printf("NDM: Insert %s %s\n", slot.ToString().c_str(), inst ? inst->GetBaseItem()->Name : "Null" ); return true; } - virtual bool Delete(const InventorySlot &slot) { printf("NDM: Delete %s\n", slot.ToString().c_str()); return true; } + virtual void Insert(const InventorySlot &slot, std::shared_ptr inst) { printf("NDM: Insert %s %s\n", slot.ToString().c_str(), inst ? inst->GetBaseItem()->Name : "Null" ); } + virtual void Delete(const InventorySlot &slot) { printf("NDM: Delete %s\n", slot.ToString().c_str()); } }; } // EQEmu diff --git a/common/item_instance.cpp b/common/item_instance.cpp index afa902404..f727f0d79 100644 --- a/common/item_instance.cpp +++ b/common/item_instance.cpp @@ -188,6 +188,14 @@ void EQEmu::ItemInstance::SetCharges(const int16 charges) { impl_->charges_ = charges; } +uint32 EQEmu::ItemInstance::GetColor() { + return impl_->color_; +} + +uint32 EQEmu::ItemInstance::GetColor() const { + return impl_->color_; +} + void EQEmu::ItemInstance::SetColor(const uint32 color) { impl_->color_ = color; } @@ -204,6 +212,14 @@ void EQEmu::ItemInstance::SetAttuned(const bool attuned) { impl_->attuned_ = attuned; } +std::string EQEmu::ItemInstance::GetCustomData() { + return impl_->custom_data_; +} + +std::string EQEmu::ItemInstance::GetCustomData() const { + return impl_->custom_data_; +} + void EQEmu::ItemInstance::SetCustomData(const std::string &custom_data) { //We need to actually set the custom data stuff based on this string impl_->custom_data_ = custom_data; @@ -233,6 +249,14 @@ void EQEmu::ItemInstance::SetOrnamentIcon(const uint32 ornament_icon) { impl_->ornament_icon_ = ornament_icon; } +uint32 EQEmu::ItemInstance::GetOrnamentHeroModel() { + return impl_->ornament_hero_model_; +} + +uint32 EQEmu::ItemInstance::GetOrnamentHeroModel() const { + return impl_->ornament_hero_model_; +} + uint32 EQEmu::ItemInstance::GetOrnamentHeroModel(int material_slot) { uint32 hero_model = 0; if(impl_->ornament_hero_model_ > 0) diff --git a/common/item_instance.h b/common/item_instance.h index 4b21aaa35..93cbecf6f 100644 --- a/common/item_instance.h +++ b/common/item_instance.h @@ -49,12 +49,16 @@ namespace EQEmu int16 GetCharges() const; void SetCharges(const int16 charges); + uint32 GetColor(); + uint32 GetColor() const; void SetColor(const uint32 color); bool GetAttuned(); bool GetAttuned() const; void SetAttuned(const bool attuned); + std::string GetCustomData(); + std::string GetCustomData() const; void SetCustomData(const std::string &custom_data); uint32 GetOrnamentIDFile(); @@ -65,6 +69,8 @@ namespace EQEmu uint32 GetOrnamentIcon() const; void SetOrnamentIcon(const uint32 ornament_icon); + uint32 GetOrnamentHeroModel(); + uint32 GetOrnamentHeroModel() const; uint32 GetOrnamentHeroModel(int material_slot); uint32 GetOrnamentHeroModel(int material_slot) const; void SetOrnamentHeroModel(const uint32 ornament_hero_model); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 84c102817..09f64e8b2 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -47,6 +47,7 @@ #include "../common/spdat.h" #include "../common/string_util.h" #include "../common/zone_numbers.h" +#include "../common/inventory_db_data_model.h" #include "event_codes.h" #include "guild_mgr.h" #include "merc.h" @@ -1289,6 +1290,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) m_inventory.SetRace(GetBaseRace()); m_inventory.SetClass(GetBaseClass()); m_inventory.SetDeity(GetDeity()); + m_inventory.SetDataModel(new EQEmu::InventoryDatabaseDataModel(&database, CharacterID())); loaditems = database.GetInventory(cid, &m_inventory); /* Load Character Inventory */ /* Load AdventureStats */