diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 9d8dea551..c66ff5776 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -142,6 +142,8 @@ SET(common_headers guild_base.h guilds.h inventory.h + inventory_data_model.h + inventory_null_data_model.h ipc_mutex.h item.h item_container.h diff --git a/common/inventory.cpp b/common/inventory.cpp index c9124ced6..5d5a2c9ed 100644 --- a/common/inventory.cpp +++ b/common/inventory.cpp @@ -17,8 +17,9 @@ */ #include "inventory.h" -#include "data_verification.h" +#include "inventory_null_data_model.h" #include "item_container_personal_serialization.h" +#include "data_verification.h" #include "string_util.h" #include @@ -123,6 +124,7 @@ struct EQEmu::Inventory::impl int race_; int class_; int deity_; + std::unique_ptr data_model_; }; EQEmu::Inventory::Inventory(int race, int class_, int deity) { @@ -130,6 +132,7 @@ EQEmu::Inventory::Inventory(int race, int class_, int deity) { impl_->race_ = race; impl_->class_ = class_; impl_->deity_ = deity; + impl_->data_model_ = std::unique_ptr(new InventoryNullDataModel()); } EQEmu::Inventory::~Inventory() { @@ -148,6 +151,10 @@ void EQEmu::Inventory::SetDeity(int deity) { impl_->deity_ = deity; } +void EQEmu::Inventory::SetDataMode(InventoryDataModel *dm) { + impl_->data_model_ = std::unique_ptr(dm); +} + std::shared_ptr EQEmu::Inventory::Get(const InventorySlot &slot) { auto iter = impl_->containers_.find(slot.Type()); if(iter != impl_->containers_.end()) { @@ -218,10 +225,6 @@ bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest, return true; } - if(dest.IsDelete()) { - return _destroy(src); - } - if(!src.IsValid() || !dest.IsValid()) { return false; } @@ -242,6 +245,18 @@ bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest, return false; } + impl_->data_model_->Begin(); + if(dest.IsDelete()) { + bool v = _destroy(src); + if(v) { + impl_->data_model_->Commit(); + } else { + impl_->data_model_->Rollback(); + } + + return v; + } + if(i_src->IsStackable()) { //move # charges from src to dest @@ -252,31 +267,46 @@ bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest, //src needs to have that many charges if(i_src->GetCharges() < charges) { + impl_->data_model_->Rollback(); return false; } - //if dest exists it needs to not only be the same item id but also be able to hold enough charges + //if dest exists it needs to not only be the same item id but also be able to hold enough charges to combine + //we can also swap if src id != dest id if(i_dest) { uint32 src_id = i_src->GetBaseItem()->ID; uint32 dest_id = i_dest->GetBaseItem()->ID; if(src_id != dest_id) { - return false; + bool v = _swap(src, dest); + if(v) { + impl_->data_model_->Commit(); + } + else { + impl_->data_model_->Rollback(); + } + + return v; } int charges_avail = i_dest->GetBaseItem()->StackSize - i_dest->GetCharges(); if(charges_avail < charges) { + impl_->data_model_->Rollback(); return false; } if(i_src->GetCharges() == charges) { if(!_destroy(src)) { + impl_->data_model_->Rollback(); return false; } } else { i_src->SetCharges(i_src->GetCharges() - charges); + impl_->data_model_->Insert(src, i_src); } i_dest->SetCharges(i_dest->GetCharges() + charges); + impl_->data_model_->Insert(dest, i_dest); + impl_->data_model_->Commit(); return true; } else { //if dest does not exist and src charges > # charges then we need to create a new item with # charges in dest @@ -284,19 +314,39 @@ bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest, if(i_src->GetCharges() > charges) { auto split = i_src->Split(charges); if(!split) { + impl_->data_model_->Rollback(); return false; } Put(dest, split); + impl_->data_model_->Insert(src, i_src); + impl_->data_model_->Insert(dest, split); + impl_->data_model_->Commit(); return true; } else { - return _swap(src, dest); + bool v = _swap(src, dest); + if(v) { + impl_->data_model_->Commit(); + } else { + impl_->data_model_->Rollback(); + } + + return v; } } } else { - return _swap(src, dest); + bool v = _swap(src, dest); + if(v) { + impl_->data_model_->Commit(); + } + else { + impl_->data_model_->Rollback(); + } + + return v; } + impl_->data_model_->Commit(); return true; } @@ -408,6 +458,16 @@ bool EQEmu::Inventory::Serialize(MemoryBuffer &buf) { return value; } +void EQEmu::Inventory::Interrogate() { + printf("Inventory:\n"); + printf("Class: %u, Race: %u, Deity: %u\n", impl_->class_, impl_->race_, impl_->deity_); + for(auto &iter : impl_->containers_) { + printf("Container: %u\n", iter.first); + iter.second.Interrogate(1); + } + printf("\n"); +} + bool EQEmu::Inventory::_swap(const InventorySlot &src, const InventorySlot &dest) { auto src_i = Get(src); auto dest_i = Get(dest); @@ -423,12 +483,14 @@ bool EQEmu::Inventory::_swap(const InventorySlot &src, const InventorySlot &dest return false; } + impl_->data_model_->Insert(src, dest_i); if(!Put(src, dest_i)) { return false; } } if(src_i) { + impl_->data_model_->Insert(dest, src_i); if(!Put(dest, src_i)) { return false; } @@ -438,5 +500,7 @@ bool EQEmu::Inventory::_swap(const InventorySlot &src, const InventorySlot &dest } bool EQEmu::Inventory::_destroy(const InventorySlot &slot) { - return Put(slot, std::shared_ptr(nullptr)); + bool v = Put(slot, std::shared_ptr(nullptr)); + impl_->data_model_->Delete(slot); + return v; } diff --git a/common/inventory.h b/common/inventory.h index 24c5e7881..75a33b690 100644 --- a/common/inventory.h +++ b/common/inventory.h @@ -120,6 +120,7 @@ namespace EQEmu lhs.AugIndex() == rhs.AugIndex(); } inline bool operator!=(const InventorySlot &lhs, const InventorySlot &rhs) { return !(lhs == rhs); } + class InventoryDataModel; class Inventory { public: @@ -129,6 +130,7 @@ namespace EQEmu void SetRace(int race); void SetClass(int class_); void SetDeity(int deity); + void SetDataMode(InventoryDataModel *dm); std::shared_ptr Get(const InventorySlot &slot); bool Put(const InventorySlot &slot, std::shared_ptr inst); @@ -139,6 +141,9 @@ namespace EQEmu static InventorySlot CalcSlotFromMaterial(int material); bool CanEquip(std::shared_ptr inst, const EQEmu::InventorySlot &slot); bool Serialize(MemoryBuffer &buf); + + //testing + void Interrogate(); private: bool _swap(const InventorySlot &src, const InventorySlot &dest); bool _destroy(const InventorySlot &slot); diff --git a/common/inventory_data_model.h b/common/inventory_data_model.h new file mode 100644 index 000000000..c35922147 --- /dev/null +++ b/common/inventory_data_model.h @@ -0,0 +1,40 @@ +/* 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_DATA_MODEL_H +#define COMMON_INVENTORY_DATA_MODEL_H + +#include "inventory.h" + +namespace EQEmu +{ + class InventoryDataModel + { + public: + InventoryDataModel() { } + virtual ~InventoryDataModel() { } + + virtual void Begin() = 0; + virtual void Commit() = 0; + virtual void Rollback() = 0; + virtual bool Insert(const InventorySlot &slot, std::shared_ptr inst) = 0; + virtual bool Delete(const InventorySlot &slot) = 0; + }; +} // EQEmu + +#endif diff --git a/common/inventory_null_data_model.h b/common/inventory_null_data_model.h new file mode 100644 index 000000000..3f3433df0 --- /dev/null +++ b/common/inventory_null_data_model.h @@ -0,0 +1,40 @@ +/* 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_NULL_DATA_MODEL_H +#define COMMON_INVENTORY_NULL_DATA_MODEL_H + +#include "inventory_data_model.h" + +namespace EQEmu +{ + class InventoryNullDataModel : public InventoryDataModel + { + public: + InventoryNullDataModel() { } + virtual ~InventoryNullDataModel() { } + + virtual void Begin() { printf("NDM: Begin\n"); } + virtual void Commit() { printf("NDM: Commit\n"); } + 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; } + }; +} // EQEmu + +#endif diff --git a/common/item_container.cpp b/common/item_container.cpp index f602a1f50..f78d28461 100644 --- a/common/item_container.cpp +++ b/common/item_container.cpp @@ -98,3 +98,15 @@ EQEmu::ItemContainer::ItemContainerIter EQEmu::ItemContainer::Begin() { EQEmu::ItemContainer::ItemContainerIter EQEmu::ItemContainer::End() { return impl_->items_.end(); } + +void EQEmu::ItemContainer::Interrogate(int level) { + char buffer[16] = { 0 }; + for(int i = 0; i < level; ++i) { + buffer[i] = '\t'; + } + + for(auto &iter : impl_->items_) { + printf("%s%u: (%u)%s (%u)\n", buffer, iter.first, iter.second->GetBaseItem()->ID, iter.second->GetBaseItem()->Name, iter.second->GetCharges()); + iter.second->Interrogate(level + 1); + } +} \ No newline at end of file diff --git a/common/item_container.h b/common/item_container.h index bde5d3c0d..7900c3840 100644 --- a/common/item_container.h +++ b/common/item_container.h @@ -49,6 +49,9 @@ namespace EQEmu bool Serialize(MemoryBuffer &buf, int container_number); ItemContainerIter Begin(); ItemContainerIter End(); + + //testing + void Interrogate(int level); protected: struct impl; impl *impl_; diff --git a/common/item_instance.cpp b/common/item_instance.cpp index f3c24aad5..afa902404 100644 --- a/common/item_instance.cpp +++ b/common/item_instance.cpp @@ -360,3 +360,6 @@ EQEmu::ItemContainer *EQEmu::ItemInstance::GetContainer() { return &(impl_->contents_); } +void EQEmu::ItemInstance::Interrogate(int level) { + impl_->contents_.Interrogate(level); +} diff --git a/common/item_instance.h b/common/item_instance.h index 18901bff6..4b21aaa35 100644 --- a/common/item_instance.h +++ b/common/item_instance.h @@ -105,6 +105,8 @@ namespace EQEmu //Internal state //Used for low level operations such as encode/decode ItemContainer *GetContainer(); + + void Interrogate(int level); private: struct impl; impl *impl_; diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 72ba9984e..bdb800add 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -3139,8 +3139,11 @@ bool Client::SwapItem(const EQEmu::InventorySlot &src, const EQEmu::InventorySlo if(res) { Message(0, "Swap success\n"); + m_inventory.Interrogate(); } else { Message(0, "Swap failure!\n"); + //should kick the player here... + } if(auto_attack && res && recalc_weapon_speed) {