Fix for swapping a stack with another item that is not of the same stack size. Added some console visualization for testing and added basics of data modeling for inventory, saving soon.

This commit is contained in:
KimLS 2015-03-02 19:38:57 -08:00
parent abc5ddc5f8
commit 972d3d8874
10 changed files with 184 additions and 10 deletions

View File

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

View File

@ -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 <map>
@ -123,6 +124,7 @@ struct EQEmu::Inventory::impl
int race_;
int class_;
int deity_;
std::unique_ptr<InventoryDataModel> 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<InventoryDataModel>(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<InventoryDataModel>(dm);
}
std::shared_ptr<EQEmu::ItemInstance> 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<EQEmu::ItemInstance>(nullptr));
bool v = Put(slot, std::shared_ptr<EQEmu::ItemInstance>(nullptr));
impl_->data_model_->Delete(slot);
return v;
}

View File

@ -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<ItemInstance> Get(const InventorySlot &slot);
bool Put(const InventorySlot &slot, std::shared_ptr<ItemInstance> inst);
@ -139,6 +141,9 @@ namespace EQEmu
static InventorySlot CalcSlotFromMaterial(int material);
bool CanEquip(std::shared_ptr<EQEmu::ItemInstance> 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);

View File

@ -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<ItemInstance> inst) = 0;
virtual bool Delete(const InventorySlot &slot) = 0;
};
} // EQEmu
#endif

View File

@ -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<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; }
};
} // EQEmu
#endif

View File

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

View File

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

View File

@ -360,3 +360,6 @@ EQEmu::ItemContainer *EQEmu::ItemInstance::GetContainer() {
return &(impl_->contents_);
}
void EQEmu::ItemInstance::Interrogate(int level) {
impl_->contents_.Interrogate(level);
}

View File

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

View File

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