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 */