From 045bb7cbd7d206f9de9e4b624aa6dd6dc0d4d55a Mon Sep 17 00:00:00 2001
From: elsid <elsid.mail@gmail.com>
Date: Sat, 3 Apr 2021 00:48:35 +0200
Subject: [PATCH 1/3] Store CustomData and ContainerStore as unique_ptr

---
 apps/openmw/mwclass/container.cpp       |  8 +++---
 apps/openmw/mwclass/container.hpp       |  2 +-
 apps/openmw/mwclass/creature.cpp        | 36 ++++++++++++++-----------
 apps/openmw/mwclass/creaturelevlist.cpp | 10 +++----
 apps/openmw/mwclass/door.cpp            |  9 +++----
 apps/openmw/mwclass/npc.cpp             | 11 ++++----
 apps/openmw/mwworld/containerstore.hpp  |  2 +-
 apps/openmw/mwworld/customdata.hpp      |  4 ++-
 apps/openmw/mwworld/inventorystore.hpp  |  2 +-
 apps/openmw/mwworld/refdata.cpp         | 11 +++-----
 apps/openmw/mwworld/refdata.hpp         |  5 ++--
 11 files changed, 52 insertions(+), 48 deletions(-)

diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp
index 28305c394..2d7f30047 100644
--- a/apps/openmw/mwclass/container.cpp
+++ b/apps/openmw/mwclass/container.cpp
@@ -46,9 +46,9 @@ namespace MWClass
         mStore.readState(inventory);
     }
 
-    MWWorld::CustomData *ContainerCustomData::clone() const
+    std::unique_ptr<MWWorld::CustomData> ContainerCustomData::clone() const
     {
-        return new ContainerCustomData (*this);
+        return std::make_unique<ContainerCustomData>(*this);
     }
 
     ContainerCustomData& ContainerCustomData::asContainerCustomData()
@@ -72,7 +72,7 @@ namespace MWClass
             MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
 
             // store
-            ptr.getRefData().setCustomData (std::make_unique<ContainerCustomData>(*ref->mBase, ptr.getCell()).release());
+            ptr.getRefData().setCustomData (std::make_unique<ContainerCustomData>(*ref->mBase, ptr.getCell()));
 
             MWBase::Environment::get().getWorld()->addContainerScripts(ptr, ptr.getCell());
         }
@@ -317,7 +317,7 @@ namespace MWClass
             return;
 
         const ESM::ContainerState& containerState = state.asContainerState();
-        ptr.getRefData().setCustomData(std::make_unique<ContainerCustomData>(containerState.mInventory).release());
+        ptr.getRefData().setCustomData(std::make_unique<ContainerCustomData>(containerState.mInventory));
     }
 
     void Container::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const
diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp
index 2dc0c06ca..fc3e046f1 100644
--- a/apps/openmw/mwclass/container.hpp
+++ b/apps/openmw/mwclass/container.hpp
@@ -20,7 +20,7 @@ namespace MWClass
         ContainerCustomData(const ESM::Container& container, MWWorld::CellStore* cell);
         ContainerCustomData(const ESM::InventoryState& inventory);
 
-        MWWorld::CustomData *clone() const override;
+        std::unique_ptr<MWWorld::CustomData> clone() const override;
 
         ContainerCustomData& asContainerCustomData() override;
         const ContainerCustomData& asContainerCustomData() const override;
diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp
index 31341db73..2a55fb9fd 100644
--- a/apps/openmw/mwclass/creature.cpp
+++ b/apps/openmw/mwclass/creature.cpp
@@ -55,10 +55,14 @@ namespace MWClass
     {
     public:
         MWMechanics::CreatureStats mCreatureStats;
-        MWWorld::ContainerStore* mContainerStore; // may be InventoryStore for some creatures
+        std::unique_ptr<MWWorld::ContainerStore> mContainerStore; // may be InventoryStore for some creatures
         MWMechanics::Movement mMovement;
 
-        MWWorld::CustomData *clone() const override;
+        CreatureCustomData() = default;
+        CreatureCustomData(const CreatureCustomData& other);
+        CreatureCustomData(CreatureCustomData&& other) noexcept = default;
+
+        std::unique_ptr<MWWorld::CustomData> clone() const override;
 
         CreatureCustomData& asCreatureCustomData() override
         {
@@ -68,16 +72,18 @@ namespace MWClass
         {
             return *this;
         }
-
-        CreatureCustomData() : mContainerStore(nullptr) {}
-        virtual ~CreatureCustomData() { delete mContainerStore; }
     };
 
-    MWWorld::CustomData *CreatureCustomData::clone() const
+    CreatureCustomData::CreatureCustomData(const CreatureCustomData& other)
+        : mCreatureStats(other.mCreatureStats),
+          mContainerStore(other.mContainerStore->clone()),
+          mMovement(other.mMovement)
     {
-        CreatureCustomData* cloned = new CreatureCustomData (*this);
-        cloned->mContainerStore = mContainerStore->clone();
-        return cloned;
+    }
+
+    std::unique_ptr<MWWorld::CustomData> CreatureCustomData::clone() const
+    {
+        return std::make_unique<CreatureCustomData>(*this);
     }
 
     const Creature::GMST& Creature::getGmst()
@@ -148,16 +154,16 @@ namespace MWClass
             // inventory
             bool hasInventory = hasInventoryStore(ptr);
             if (hasInventory)
-                data->mContainerStore = new MWWorld::InventoryStore();
+                data->mContainerStore = std::make_unique<MWWorld::InventoryStore>();
             else
-                data->mContainerStore = new MWWorld::ContainerStore();
+                data->mContainerStore = std::make_unique<MWWorld::ContainerStore>();
 
             data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold);
 
             data->mCreatureStats.setNeedRecalcDynamicStats(false);
 
             // store
-            ptr.getRefData().setCustomData(data.release());
+            ptr.getRefData().setCustomData(std::move(data));
 
             getContainerStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId());
 
@@ -758,11 +764,11 @@ namespace MWClass
                 std::unique_ptr<CreatureCustomData> data (new CreatureCustomData);
 
                 if (hasInventoryStore(ptr))
-                    data->mContainerStore = new MWWorld::InventoryStore();
+                    data->mContainerStore = std::make_unique<MWWorld::InventoryStore>();
                 else
-                    data->mContainerStore = new MWWorld::ContainerStore();
+                    data->mContainerStore = std::make_unique<MWWorld::ContainerStore>();
 
-                ptr.getRefData().setCustomData (data.release());
+                ptr.getRefData().setCustomData (std::move(data));
             }
         }
         else
diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp
index e3e52901e..3b401f1a3 100644
--- a/apps/openmw/mwclass/creaturelevlist.cpp
+++ b/apps/openmw/mwclass/creaturelevlist.cpp
@@ -17,7 +17,7 @@ namespace MWClass
         int mSpawnActorId;
         bool mSpawn; // Should a new creature be spawned?
 
-        MWWorld::CustomData *clone() const override;
+        std::unique_ptr<MWWorld::CustomData> clone() const override;
 
         CreatureLevListCustomData& asCreatureLevListCustomData() override
         {
@@ -29,9 +29,9 @@ namespace MWClass
         }
     };
 
-    MWWorld::CustomData *CreatureLevListCustomData::clone() const
+    std::unique_ptr<MWWorld::CustomData> CreatureLevListCustomData::clone() const
     {
-        return new CreatureLevListCustomData (*this);
+        return std::make_unique<CreatureLevListCustomData>(*this);
     }
 
     std::string CreatureLevList::getName (const MWWorld::ConstPtr& ptr) const
@@ -138,11 +138,11 @@ namespace MWClass
     {
         if (!ptr.getRefData().getCustomData())
         {
-            std::unique_ptr<CreatureLevListCustomData> data (new CreatureLevListCustomData);
+            std::unique_ptr<CreatureLevListCustomData> data = std::make_unique<CreatureLevListCustomData>();
             data->mSpawnActorId = -1;
             data->mSpawn = true;
 
-            ptr.getRefData().setCustomData(data.release());
+            ptr.getRefData().setCustomData(std::move(data));
         }
     }
 
diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp
index 25f7fc456..ae8085586 100644
--- a/apps/openmw/mwclass/door.cpp
+++ b/apps/openmw/mwclass/door.cpp
@@ -36,7 +36,7 @@ namespace MWClass
     public:
         MWWorld::DoorState mDoorState = MWWorld::DoorState::Idle;
 
-        MWWorld::CustomData *clone() const override;
+        std::unique_ptr<MWWorld::CustomData> clone() const override;
 
         DoorCustomData& asDoorCustomData() override
         {
@@ -48,9 +48,9 @@ namespace MWClass
         }
     };
 
-    MWWorld::CustomData *DoorCustomData::clone() const
+    std::unique_ptr<MWWorld::CustomData> DoorCustomData::clone() const
     {
-        return new DoorCustomData (*this);
+        return std::make_unique<DoorCustomData>(*this);
     }
 
     void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
@@ -327,8 +327,7 @@ namespace MWClass
     {
         if (!ptr.getRefData().getCustomData())
         {
-            std::unique_ptr<DoorCustomData> data(new DoorCustomData);
-            ptr.getRefData().setCustomData(data.release());
+            ptr.getRefData().setCustomData(std::make_unique<DoorCustomData>());
         }
     }
 
diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp
index 5de4c197e..248ef5d01 100644
--- a/apps/openmw/mwclass/npc.cpp
+++ b/apps/openmw/mwclass/npc.cpp
@@ -253,7 +253,7 @@ namespace MWClass
         MWMechanics::Movement mMovement;
         MWWorld::InventoryStore mInventoryStore;
 
-        MWWorld::CustomData *clone() const override;
+        std::unique_ptr<MWWorld::CustomData> clone() const override;
 
         NpcCustomData& asNpcCustomData() override
         {
@@ -265,9 +265,9 @@ namespace MWClass
         }
     };
 
-    MWWorld::CustomData *NpcCustomData::clone() const
+    std::unique_ptr<MWWorld::CustomData> NpcCustomData::clone() const
     {
-        return new NpcCustomData (*this);
+        return std::make_unique<NpcCustomData>(*this);
     }
 
     const Npc::GMST& Npc::getGmst()
@@ -397,7 +397,7 @@ namespace MWClass
             data->mNpcStats.setGoldPool(gold);
 
             // store
-            ptr.getRefData().setCustomData (data.release());
+            ptr.getRefData().setCustomData(std::move(data));
 
             getInventoryStore(ptr).autoEquip(ptr);
         }
@@ -1302,8 +1302,7 @@ namespace MWClass
             if (!ptr.getRefData().getCustomData())
             {
                 // Create a CustomData, but don't fill it from ESM records (not needed)
-                std::unique_ptr<NpcCustomData> data (new NpcCustomData);
-                ptr.getRefData().setCustomData (data.release());
+                ptr.getRefData().setCustomData(std::make_unique<NpcCustomData>());
             }
         }
         else
diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp
index 882f5efc4..bb8ca5273 100644
--- a/apps/openmw/mwworld/containerstore.hpp
+++ b/apps/openmw/mwworld/containerstore.hpp
@@ -153,7 +153,7 @@ namespace MWWorld
 
             virtual ~ContainerStore();
 
-            virtual ContainerStore* clone() { return new ContainerStore(*this); }
+            virtual std::unique_ptr<ContainerStore> clone() { return std::make_unique<ContainerStore>(*this); }
 
             ConstContainerStoreIterator cbegin (int mask = Type_All) const;
             ConstContainerStoreIterator cend() const;
diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp
index 8af45e36a..ee89dd2a8 100644
--- a/apps/openmw/mwworld/customdata.hpp
+++ b/apps/openmw/mwworld/customdata.hpp
@@ -1,6 +1,8 @@
 #ifndef GAME_MWWORLD_CUSTOMDATA_H
 #define GAME_MWWORLD_CUSTOMDATA_H
 
+#include <memory>
+
 namespace MWClass
 {
     class CreatureCustomData;
@@ -19,7 +21,7 @@ namespace MWWorld
 
             virtual ~CustomData() {}
 
-            virtual CustomData *clone() const = 0;
+            virtual std::unique_ptr<CustomData> clone() const = 0;
 
             // Fast version of dynamic_cast<X&>. Needs to be overridden in the respective class.
 
diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp
index 6809e63b2..32dc0d2e9 100644
--- a/apps/openmw/mwworld/inventorystore.hpp
+++ b/apps/openmw/mwworld/inventorystore.hpp
@@ -123,7 +123,7 @@ namespace MWWorld
 
             InventoryStore& operator= (const InventoryStore& store);
 
-            InventoryStore* clone() override { return new InventoryStore(*this); }
+            std::unique_ptr<ContainerStore> clone() override { return std::make_unique<InventoryStore>(*this); }
 
             ContainerStoreIterator add (const Ptr& itemPtr, int count, const Ptr& actorPtr, bool allowAutoEquip = true, bool resolve = true) override;
             ///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed)
diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp
index 71ff6d040..f6a445d61 100644
--- a/apps/openmw/mwworld/refdata.cpp
+++ b/apps/openmw/mwworld/refdata.cpp
@@ -40,8 +40,6 @@ namespace MWWorld
     void RefData::cleanup()
     {
         mBaseNode = nullptr;
-
-        delete mCustomData;
         mCustomData = nullptr;
     }
 
@@ -223,21 +221,20 @@ namespace MWWorld
         return mPosition;
     }
 
-    void RefData::setCustomData (CustomData *data)
+    void RefData::setCustomData(std::unique_ptr<CustomData>&& value) noexcept
     {
         mChanged = true; // We do not currently track CustomData, so assume anything with a CustomData is changed
-        delete mCustomData;
-        mCustomData = data;
+        mCustomData = std::move(value);
     }
 
     CustomData *RefData::getCustomData()
     {
-        return mCustomData;
+        return mCustomData.get();
     }
 
     const CustomData *RefData::getCustomData() const
     {
-        return mCustomData;
+        return mCustomData.get();
     }
 
     bool RefData::hasChanged() const
diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp
index 738a6d53a..5419a261b 100644
--- a/apps/openmw/mwworld/refdata.hpp
+++ b/apps/openmw/mwworld/refdata.hpp
@@ -7,6 +7,7 @@
 #include "../mwscript/locals.hpp"
 
 #include <string>
+#include <memory>
 
 namespace SceneUtil
 {
@@ -44,7 +45,7 @@ namespace MWWorld
 
             ESM::AnimationState mAnimationState;
 
-            CustomData *mCustomData;
+            std::unique_ptr<CustomData> mCustomData;
 
             void copy (const RefData& refData);
 
@@ -117,7 +118,7 @@ namespace MWWorld
             void setPosition (const ESM::Position& pos);
             const ESM::Position& getPosition() const;
 
-            void setCustomData (CustomData *data);
+            void setCustomData(std::unique_ptr<CustomData>&& value) noexcept;
             ///< Set custom data (potentially replacing old custom data). The ownership of \a data is
             /// transferred to this.
 

From e380470558a1d810d7e5cd51c09a31ace376c1e6 Mon Sep 17 00:00:00 2001
From: elsid <elsid.mail@gmail.com>
Date: Sat, 3 Apr 2021 00:49:14 +0200
Subject: [PATCH 2/3] Add move ctor and assignment operator to RefData

---
 apps/openmw/mwworld/refdata.hpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp
index 5419a261b..8979c8505 100644
--- a/apps/openmw/mwworld/refdata.hpp
+++ b/apps/openmw/mwworld/refdata.hpp
@@ -5,6 +5,7 @@
 #include <components/esm/animationstate.hpp>
 
 #include "../mwscript/locals.hpp"
+#include "../mwworld/customdata.hpp"
 
 #include <string>
 #include <memory>
@@ -69,6 +70,7 @@ namespace MWWorld
             /// perform these operations).
 
             RefData (const RefData& refData);
+            RefData (RefData&& other) noexcept = default;
 
             ~RefData();
 
@@ -77,6 +79,7 @@ namespace MWWorld
             /// perform this operations).
 
             RefData& operator= (const RefData& refData);
+            RefData& operator= (RefData&& other) noexcept = default;
 
             /// Return base node (can be a null pointer).
             SceneUtil::PositionAttitudeTransform* getBaseNode();

From bd33fa76b63536398e00ba416d3289a44beaf461 Mon Sep 17 00:00:00 2001
From: elsid <elsid.mail@gmail.com>
Date: Sat, 3 Apr 2021 12:59:44 +0200
Subject: [PATCH 3/3] Use CRTP to define CustomData clone function

---
 apps/openmw/mwclass/container.cpp       | 5 -----
 apps/openmw/mwclass/container.hpp       | 4 +---
 apps/openmw/mwclass/creature.cpp        | 9 +--------
 apps/openmw/mwclass/creaturelevlist.cpp | 9 +--------
 apps/openmw/mwclass/door.cpp            | 9 +--------
 apps/openmw/mwclass/npc.cpp             | 9 +--------
 apps/openmw/mwworld/customdata.hpp      | 9 +++++++++
 7 files changed, 14 insertions(+), 40 deletions(-)

diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp
index 2d7f30047..de560608c 100644
--- a/apps/openmw/mwclass/container.cpp
+++ b/apps/openmw/mwclass/container.cpp
@@ -46,11 +46,6 @@ namespace MWClass
         mStore.readState(inventory);
     }
 
-    std::unique_ptr<MWWorld::CustomData> ContainerCustomData::clone() const
-    {
-        return std::make_unique<ContainerCustomData>(*this);
-    }
-
     ContainerCustomData& ContainerCustomData::asContainerCustomData()
     {
         return *this;
diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp
index fc3e046f1..1c8937006 100644
--- a/apps/openmw/mwclass/container.hpp
+++ b/apps/openmw/mwclass/container.hpp
@@ -13,15 +13,13 @@ namespace ESM
 
 namespace MWClass
 {
-    class ContainerCustomData : public MWWorld::CustomData
+    class ContainerCustomData : public MWWorld::TypedCustomData<ContainerCustomData>
     {
         MWWorld::ContainerStore mStore;
     public:
         ContainerCustomData(const ESM::Container& container, MWWorld::CellStore* cell);
         ContainerCustomData(const ESM::InventoryState& inventory);
 
-        std::unique_ptr<MWWorld::CustomData> clone() const override;
-
         ContainerCustomData& asContainerCustomData() override;
         const ContainerCustomData& asContainerCustomData() const override;
 
diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp
index 2a55fb9fd..6b8d2f3f2 100644
--- a/apps/openmw/mwclass/creature.cpp
+++ b/apps/openmw/mwclass/creature.cpp
@@ -51,7 +51,7 @@ namespace
 namespace MWClass
 {
 
-    class CreatureCustomData : public MWWorld::CustomData
+    class CreatureCustomData : public MWWorld::TypedCustomData<CreatureCustomData>
     {
     public:
         MWMechanics::CreatureStats mCreatureStats;
@@ -62,8 +62,6 @@ namespace MWClass
         CreatureCustomData(const CreatureCustomData& other);
         CreatureCustomData(CreatureCustomData&& other) noexcept = default;
 
-        std::unique_ptr<MWWorld::CustomData> clone() const override;
-
         CreatureCustomData& asCreatureCustomData() override
         {
             return *this;
@@ -81,11 +79,6 @@ namespace MWClass
     {
     }
 
-    std::unique_ptr<MWWorld::CustomData> CreatureCustomData::clone() const
-    {
-        return std::make_unique<CreatureCustomData>(*this);
-    }
-
     const Creature::GMST& Creature::getGmst()
     {
         static GMST gmst;
diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp
index 3b401f1a3..f86004c61 100644
--- a/apps/openmw/mwclass/creaturelevlist.cpp
+++ b/apps/openmw/mwclass/creaturelevlist.cpp
@@ -10,15 +10,13 @@
 
 namespace MWClass
 {
-    class CreatureLevListCustomData : public MWWorld::CustomData
+    class CreatureLevListCustomData : public MWWorld::TypedCustomData<CreatureLevListCustomData>
     {
     public:
         // actorId of the creature we spawned
         int mSpawnActorId;
         bool mSpawn; // Should a new creature be spawned?
 
-        std::unique_ptr<MWWorld::CustomData> clone() const override;
-
         CreatureLevListCustomData& asCreatureLevListCustomData() override
         {
             return *this;
@@ -29,11 +27,6 @@ namespace MWClass
         }
     };
 
-    std::unique_ptr<MWWorld::CustomData> CreatureLevListCustomData::clone() const
-    {
-        return std::make_unique<CreatureLevListCustomData>(*this);
-    }
-
     std::string CreatureLevList::getName (const MWWorld::ConstPtr& ptr) const
     {
         return "";
diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp
index ae8085586..3a5ff0d9a 100644
--- a/apps/openmw/mwclass/door.cpp
+++ b/apps/openmw/mwclass/door.cpp
@@ -31,13 +31,11 @@
 
 namespace MWClass
 {
-    class DoorCustomData : public MWWorld::CustomData
+    class DoorCustomData : public MWWorld::TypedCustomData<DoorCustomData>
     {
     public:
         MWWorld::DoorState mDoorState = MWWorld::DoorState::Idle;
 
-        std::unique_ptr<MWWorld::CustomData> clone() const override;
-
         DoorCustomData& asDoorCustomData() override
         {
             return *this;
@@ -48,11 +46,6 @@ namespace MWClass
         }
     };
 
-    std::unique_ptr<MWWorld::CustomData> DoorCustomData::clone() const
-    {
-        return std::make_unique<DoorCustomData>(*this);
-    }
-
     void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
     {
         if (!model.empty())
diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp
index 248ef5d01..c5b352cb4 100644
--- a/apps/openmw/mwclass/npc.cpp
+++ b/apps/openmw/mwclass/npc.cpp
@@ -246,15 +246,13 @@ namespace
 namespace MWClass
 {
 
-    class NpcCustomData : public MWWorld::CustomData
+    class NpcCustomData : public MWWorld::TypedCustomData<NpcCustomData>
     {
     public:
         MWMechanics::NpcStats mNpcStats;
         MWMechanics::Movement mMovement;
         MWWorld::InventoryStore mInventoryStore;
 
-        std::unique_ptr<MWWorld::CustomData> clone() const override;
-
         NpcCustomData& asNpcCustomData() override
         {
             return *this;
@@ -265,11 +263,6 @@ namespace MWClass
         }
     };
 
-    std::unique_ptr<MWWorld::CustomData> NpcCustomData::clone() const
-    {
-        return std::make_unique<NpcCustomData>(*this);
-    }
-
     const Npc::GMST& Npc::getGmst()
     {
         static GMST gmst;
diff --git a/apps/openmw/mwworld/customdata.hpp b/apps/openmw/mwworld/customdata.hpp
index ee89dd2a8..7200e7684 100644
--- a/apps/openmw/mwworld/customdata.hpp
+++ b/apps/openmw/mwworld/customdata.hpp
@@ -40,6 +40,15 @@ namespace MWWorld
             virtual MWClass::CreatureLevListCustomData& asCreatureLevListCustomData();
             virtual const MWClass::CreatureLevListCustomData& asCreatureLevListCustomData() const;
     };
+
+    template <class T>
+    struct TypedCustomData : CustomData
+    {
+        std::unique_ptr<CustomData> clone() const final
+        {
+            return std::make_unique<T>(*static_cast<const T*>(this));
+        }
+    };
 }
 
 #endif