From ae4bf04798b3ad25a8490d448f8d53b06347e567 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Tue, 28 May 2024 23:30:28 +0200 Subject: [PATCH 1/4] Fix soul gems losing their souls when splitting stacks between containers. --- apps/openmw/mwgui/containeritemmodel.cpp | 4 +- apps/openmw/mwgui/inventoryitemmodel.cpp | 6 +- apps/openmw/mwworld/manualref.cpp | 94 ++++++++++++++++++++++++ apps/openmw/mwworld/manualref.hpp | 1 + 4 files changed, 102 insertions(+), 3 deletions(-) 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..d4979eb494 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -19,6 +19,14 @@ namespace refValue = MWWorld::LiveCellRef(cellRef, base); ptrValue = MWWorld::Ptr(&std::any_cast&>(refValue), nullptr); } + + template + void create( + const MWWorld::Store& list, const MWWorld::Ptr& template_, std::any& refValue, MWWorld::Ptr& ptrValue) + { + refValue = *static_cast*>(template_.getBase()); + ptrValue = MWWorld::Ptr(&std::any_cast&>(refValue), nullptr); + } } MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const ESM::RefId& name, const int count) @@ -103,3 +111,89 @@ MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const ESM::RefId& mPtr.getCellRef().setCount(count); } + +MWWorld::ManualRef::ManualRef(const ESMStore& store, const Ptr& template_, const int count) +{ + ESM::RefId name = template_.getCellRef().getRefId(); + switch (store.find(name)) + { + case ESM::REC_ACTI: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_ALCH: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_APPA: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_ARMO: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_BOOK: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_CLOT: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_CONT: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_CREA: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_DOOR: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_INGR: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_LEVC: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_LEVI: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_LIGH: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_LOCK: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_MISC: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_NPC_: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_PROB: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_REPA: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_STAT: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_WEAP: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_BODY: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_STAT4: + create(store.get(), template_, mRef, mPtr); + break; + case ESM::REC_TERM4: + create(store.get(), template_, 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)"); + } + + 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..f46cde7322 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -18,6 +18,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; } }; From a1b695a8d5692ac79f6919c9746a19be5366c877 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Fri, 31 May 2024 23:10:54 +0200 Subject: [PATCH 2/4] De-duplicate ManualRef constructor --- apps/openmw/mwworld/manualref.cpp | 243 +++++++++++------------------- 1 file changed, 88 insertions(+), 155 deletions(-) diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index d4979eb494..fce66d2919 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -27,171 +27,104 @@ namespace refValue = *static_cast*>(template_.getBase()); ptrValue = MWWorld::Ptr(&std::any_cast&>(refValue), nullptr); } + + template + void createGeneric(F func, const MWWorld::ESMStore& store, ESM::RefId name) + { + switch (store.find(name)) + { + case ESM::REC_ACTI: + func(store.get()); + break; + case ESM::REC_ALCH: + func(store.get()); + break; + case ESM::REC_APPA: + func(store.get()); + break; + case ESM::REC_ARMO: + func(store.get()); + break; + case ESM::REC_BOOK: + func(store.get()); + break; + case ESM::REC_CLOT: + func(store.get()); + break; + case ESM::REC_CONT: + func(store.get()); + break; + case ESM::REC_CREA: + func(store.get()); + break; + case ESM::REC_DOOR: + func(store.get()); + break; + case ESM::REC_INGR: + func(store.get()); + break; + case ESM::REC_LEVC: + func(store.get()); + break; + case ESM::REC_LEVI: + func(store.get()); + break; + case ESM::REC_LIGH: + func(store.get()); + break; + case ESM::REC_LOCK: + func(store.get()); + break; + case ESM::REC_MISC: + func(store.get()); + break; + case ESM::REC_NPC_: + func(store.get()); + break; + case ESM::REC_PROB: + func(store.get()); + break; + case ESM::REC_REPA: + func(store.get()); + break; + case ESM::REC_STAT: + func(store.get()); + break; + case ESM::REC_WEAP: + func(store.get()); + break; + case ESM::REC_BODY: + func(store.get()); + break; + case ESM::REC_STAT4: + func(store.get()); + break; + case ESM::REC_TERM4: + func(store.get()); + 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)"); + } + } } 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); }; + createGeneric(cb, store, name); mPtr.getCellRef().setCount(count); } MWWorld::ManualRef::ManualRef(const ESMStore& store, const Ptr& template_, const int count) { - ESM::RefId name = template_.getCellRef().getRefId(); - switch (store.find(name)) - { - case ESM::REC_ACTI: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_ALCH: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_APPA: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_ARMO: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_BOOK: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_CLOT: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_CONT: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_CREA: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_DOOR: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_INGR: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_LEVC: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_LEVI: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_LIGH: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_LOCK: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_MISC: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_NPC_: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_PROB: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_REPA: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_STAT: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_WEAP: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_BODY: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_STAT4: - create(store.get(), template_, mRef, mPtr); - break; - case ESM::REC_TERM4: - create(store.get(), template_, 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, template_, mRef, mPtr); }; + createGeneric(cb, store, template_.getCellRef().getRefId()); mPtr.getCellRef().setCount(count); mPtr.getCellRef().unsetRefNum(); From 90b415a8dd930a718eb929de5b784a1b02ea4391 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Thu, 6 Jun 2024 11:20:14 +0200 Subject: [PATCH 3/4] comments by elsid --- apps/openmw/mwworld/manualref.cpp | 75 +++++++++++-------------------- apps/openmw/mwworld/manualref.hpp | 4 +- 2 files changed, 29 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index fce66d2919..e9a3f08c79 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -29,79 +29,56 @@ namespace } template - void createGeneric(F func, const MWWorld::ESMStore& store, ESM::RefId name) + void visitRefStore(const MWWorld::ESMStore& store, ESM::RefId name, F func) { switch (store.find(name)) { case ESM::REC_ACTI: - func(store.get()); - break; + return func(store.get()); case ESM::REC_ALCH: - func(store.get()); - break; + return func(store.get()); case ESM::REC_APPA: - func(store.get()); - break; + return func(store.get()); case ESM::REC_ARMO: - func(store.get()); - break; + return func(store.get()); case ESM::REC_BOOK: - func(store.get()); - break; + return func(store.get()); case ESM::REC_CLOT: - func(store.get()); - break; + return func(store.get()); case ESM::REC_CONT: - func(store.get()); - break; + return func(store.get()); case ESM::REC_CREA: - func(store.get()); - break; + return func(store.get()); case ESM::REC_DOOR: - func(store.get()); - break; + return func(store.get()); case ESM::REC_INGR: - func(store.get()); - break; + return func(store.get()); case ESM::REC_LEVC: - func(store.get()); - break; + return func(store.get()); case ESM::REC_LEVI: - func(store.get()); - break; + return func(store.get()); case ESM::REC_LIGH: - func(store.get()); - break; + return func(store.get()); case ESM::REC_LOCK: - func(store.get()); - break; + return func(store.get()); case ESM::REC_MISC: - func(store.get()); - break; + return func(store.get()); case ESM::REC_NPC_: - func(store.get()); - break; + return func(store.get()); case ESM::REC_PROB: - func(store.get()); - break; + return func(store.get()); case ESM::REC_REPA: - func(store.get()); - break; + return func(store.get()); case ESM::REC_STAT: - func(store.get()); - break; + return func(store.get()); case ESM::REC_WEAP: - func(store.get()); - break; + return func(store.get()); case ESM::REC_BODY: - func(store.get()); - break; + return func(store.get()); case ESM::REC_STAT4: - func(store.get()); - break; + return func(store.get()); case ESM::REC_TERM4: - func(store.get()); - break; + return func(store.get()); case 0: throw std::logic_error( "failed to create manual cell ref for " + name.toDebugString() + " (unknown ID)"); @@ -116,7 +93,7 @@ namespace MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const ESM::RefId& name, const int count) { auto cb = [&](const auto& store) { create(store, name, mRef, mPtr); }; - createGeneric(cb, store, name); + visitRefStore(store, name, cb); mPtr.getCellRef().setCount(count); } @@ -124,7 +101,7 @@ MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const ESM::RefId& MWWorld::ManualRef::ManualRef(const ESMStore& store, const Ptr& template_, const int count) { auto cb = [&](const auto& store) { create(store, template_, mRef, mPtr); }; - createGeneric(cb, store, template_.getCellRef().getRefId()); + visitRefStore(store, template_.getCellRef().getRefId(), cb); mPtr.getCellRef().setCount(count); mPtr.getCellRef().unsetRefNum(); diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index f46cde7322..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; From e063fa5b23062529d4268921b16d2def1406fe4d Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Thu, 6 Jun 2024 16:51:51 +0200 Subject: [PATCH 4/4] rename template_ to templatePtr --- apps/openmw/mwworld/manualref.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index e9a3f08c79..81ab4b5419 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -22,9 +22,9 @@ namespace template void create( - const MWWorld::Store& list, const MWWorld::Ptr& template_, std::any& refValue, MWWorld::Ptr& ptrValue) + const MWWorld::Store& list, const MWWorld::Ptr& templatePtr, std::any& refValue, MWWorld::Ptr& ptrValue) { - refValue = *static_cast*>(template_.getBase()); + refValue = *static_cast*>(templatePtr.getBase()); ptrValue = MWWorld::Ptr(&std::any_cast&>(refValue), nullptr); }