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.

This commit is contained in:
KimLS 2015-03-04 19:33:01 -08:00
parent 972d3d8874
commit 9fcdf5367e
10 changed files with 290 additions and 8 deletions

View File

@ -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

View File

@ -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<InventoryDataModel>(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;
}

View File

@ -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<ItemInstance> Get(const InventorySlot &slot);
bool Put(const InventorySlot &slot, std::shared_ptr<ItemInstance> inst);

View File

@ -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<ItemInstance> inst) = 0;
virtual bool Delete(const InventorySlot &slot) = 0;
virtual void Insert(const InventorySlot &slot, std::shared_ptr<ItemInstance> inst) = 0;
virtual void Delete(const InventorySlot &slot) = 0;
};
} // EQEmu

View File

@ -0,0 +1,197 @@
#include "inventory_db_data_model.h"
#include "shareddb.h"
#include "string_util.h"
#include <list>
#include <string>
enum DataEventTypes
{
DB_Insert,
DB_Delete
};
struct DataEvent
{
DataEventTypes evt;
EQEmu::InventorySlot slot;
std::shared_ptr<EQEmu::ItemInstance> inst;
};
struct EQEmu::InventoryDatabaseDataModel::impl {
SharedDatabase *db_;
std::list<DataEvent> 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<ItemInstance> 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);
}

View File

@ -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<ItemInstance> inst);
virtual void Delete(const InventorySlot &slot);
private:
struct impl;
impl *impl_;
};
} // EQEmu
#endif

View File

@ -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<ItemInstance> 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<ItemInstance> 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

View File

@ -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)

View File

@ -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);

View File

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