diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index af1b585cff..09b66672ba 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -7,6 +7,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/manualref.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -114,7 +115,8 @@ namespace MWGui MWWorld::ContainerStore& store = source.first.getClass().getContainerStore(source.first); if (item.mBase.getContainerStore() == &store) throw std::runtime_error("Item to copy needs to be from a different container!"); - return *store.add(item.mBase.getCellRef().getRefId(), count, allowAutoEquip); + MWWorld::ManualRef newRef(*MWBase::Environment::get().getESMStore(), item.mBase, count); + return *store.add(newRef.getPtr(), count, allowAutoEquip); } void ContainerItemModel::removeItem(const ItemStack& item, size_t count) diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index b52d49b7c2..7464290947 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -8,6 +8,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/manualref.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -57,8 +58,9 @@ namespace MWGui { if (item.mBase.getContainerStore() == &mActor.getClass().getContainerStore(mActor)) throw std::runtime_error("Item to copy needs to be from a different container!"); - return *mActor.getClass().getContainerStore(mActor).add( - item.mBase.getCellRef().getRefId(), count, allowAutoEquip); + + MWWorld::ManualRef newRef(*MWBase::Environment::get().getESMStore(), item.mBase, count); + return *mActor.getClass().getContainerStore(mActor).add(newRef.getPtr(), count, allowAutoEquip); } void InventoryItemModel::removeItem(const ItemStack& item, size_t count) diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index c6c0444754..81ab4b5419 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -19,87 +19,91 @@ namespace refValue = MWWorld::LiveCellRef(cellRef, base); ptrValue = MWWorld::Ptr(&std::any_cast&>(refValue), nullptr); } + + template + void create( + const MWWorld::Store& list, const MWWorld::Ptr& templatePtr, std::any& refValue, MWWorld::Ptr& ptrValue) + { + refValue = *static_cast*>(templatePtr.getBase()); + ptrValue = MWWorld::Ptr(&std::any_cast&>(refValue), nullptr); + } + + template + void visitRefStore(const MWWorld::ESMStore& store, ESM::RefId name, F func) + { + switch (store.find(name)) + { + case ESM::REC_ACTI: + return func(store.get()); + case ESM::REC_ALCH: + return func(store.get()); + case ESM::REC_APPA: + return func(store.get()); + case ESM::REC_ARMO: + return func(store.get()); + case ESM::REC_BOOK: + return func(store.get()); + case ESM::REC_CLOT: + return func(store.get()); + case ESM::REC_CONT: + return func(store.get()); + case ESM::REC_CREA: + return func(store.get()); + case ESM::REC_DOOR: + return func(store.get()); + case ESM::REC_INGR: + return func(store.get()); + case ESM::REC_LEVC: + return func(store.get()); + case ESM::REC_LEVI: + return func(store.get()); + case ESM::REC_LIGH: + return func(store.get()); + case ESM::REC_LOCK: + return func(store.get()); + case ESM::REC_MISC: + return func(store.get()); + case ESM::REC_NPC_: + return func(store.get()); + case ESM::REC_PROB: + return func(store.get()); + case ESM::REC_REPA: + return func(store.get()); + case ESM::REC_STAT: + return func(store.get()); + case ESM::REC_WEAP: + return func(store.get()); + case ESM::REC_BODY: + return func(store.get()); + case ESM::REC_STAT4: + return func(store.get()); + case ESM::REC_TERM4: + return func(store.get()); + case 0: + throw std::logic_error( + "failed to create manual cell ref for " + name.toDebugString() + " (unknown ID)"); + + default: + throw std::logic_error( + "failed to create manual cell ref for " + name.toDebugString() + " (unknown type)"); + } + } } MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const ESM::RefId& name, const int count) { - switch (store.find(name)) - { - case ESM::REC_ACTI: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_ALCH: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_APPA: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_ARMO: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_BOOK: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_CLOT: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_CONT: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_CREA: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_DOOR: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_INGR: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_LEVC: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_LEVI: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_LIGH: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_LOCK: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_MISC: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_NPC_: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_PROB: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_REPA: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_STAT: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_WEAP: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_BODY: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_STAT4: - create(store.get(), name, mRef, mPtr); - break; - case ESM::REC_TERM4: - create(store.get(), name, mRef, mPtr); - break; - case 0: - throw std::logic_error("failed to create manual cell ref for " + name.toDebugString() + " (unknown ID)"); - - default: - throw std::logic_error("failed to create manual cell ref for " + name.toDebugString() + " (unknown type)"); - } + auto cb = [&](const auto& store) { create(store, name, mRef, mPtr); }; + visitRefStore(store, name, cb); mPtr.getCellRef().setCount(count); } + +MWWorld::ManualRef::ManualRef(const ESMStore& store, const Ptr& template_, const int count) +{ + auto cb = [&](const auto& store) { create(store, template_, mRef, mPtr); }; + visitRefStore(store, template_.getCellRef().getRefId(), cb); + + mPtr.getCellRef().setCount(count); + mPtr.getCellRef().unsetRefNum(); + mPtr.getRefData().setLuaScripts(nullptr); +} diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 8356fd0a03..4611ed95bb 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -7,9 +7,11 @@ namespace MWWorld { - /// \brief Manually constructed live cell ref + /// \brief Manually constructed live cell ref. The resulting Ptr shares its lifetime with this ManualRef and must + /// not be used past its end. class ManualRef { + // Stores the ref (LiveCellRef) by value. std::any mRef; Ptr mPtr; @@ -18,6 +20,7 @@ namespace MWWorld public: ManualRef(const MWWorld::ESMStore& store, const ESM::RefId& name, const int count = 1); + ManualRef(const MWWorld::ESMStore& store, const MWWorld::Ptr& template_, const int count = 1); const Ptr& getPtr() const { return mPtr; } };