From 38f56cfcddcab6f4a42ac264a33a12fd3c511a73 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sun, 10 Sep 2023 18:16:34 +0200 Subject: [PATCH 1/5] Fix #7453: wrong position of dynamically placed CreatureLevList --- apps/openmw/mwclass/creaturelevlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index dd346306e9..461cf07276 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -148,7 +148,7 @@ namespace MWClass manualRef.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition()); manualRef.getPtr().getCellRef().setScale(ptr.getCellRef().getScale()); MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject( - manualRef.getPtr(), ptr.getCell(), ptr.getCellRef().getPosition()); + manualRef.getPtr(), ptr.getCell(), ptr.getRefData().getPosition()); customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId(); customData.mSpawn = false; } From 641f34a3c9f45718f14deac16ea837282917ec7e Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 25 Sep 2023 21:01:32 +0200 Subject: [PATCH 2/5] Treat teleportation out of the draft cell as object creation --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/misc.cpp | 3 ++- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwlua/cellbindings.cpp | 4 ++++ apps/openmw/mwlua/objectbindings.cpp | 29 ++++++++++++++++++++++------ apps/openmw/mwworld/cellstore.cpp | 11 +++++------ apps/openmw/mwworld/cellstore.hpp | 2 +- apps/openmw/mwworld/class.cpp | 3 ++- files/lua_api/openmw/world.lua | 1 + 9 files changed, 40 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index df1ada96f4..9b705b805f 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -692,7 +692,7 @@ namespace MWClass if (newPtr.getRefData().getCustomData()) { MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); - newPtr.getContainerStore()->setPtr(newPtr); + newPtr.getClass().getContainerStore(newPtr).setPtr(newPtr); } return newPtr; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 6c517e3dde..c5f9de23b1 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -205,7 +205,8 @@ namespace MWClass newPtr = MWWorld::Ptr(cell.insert(ref), &cell); newPtr.getRefData().setCount(count); } - newPtr.getCellRef().unsetRefNum(); + if (ptr.getCell() != &MWBase::Environment::get().getWorldModel()->getDraftCell()) + newPtr.getCellRef().unsetRefNum(); newPtr.getRefData().setLuaScripts(nullptr); MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); return newPtr; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 1e7dae3600..27d72c61b7 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1338,7 +1338,7 @@ namespace MWClass if (newPtr.getRefData().getCustomData()) { MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); - newPtr.getContainerStore()->setPtr(newPtr); + newPtr.getClass().getContainerStore(newPtr).setPtr(newPtr); } return newPtr; } diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index 48c7141ab8..9e779b0da4 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -198,6 +199,9 @@ namespace MWLua case ESM::REC_STAT: cell.mStore->template forEachType(visitor); break; + case ESM::REC_LEVC: + cell.mStore->template forEachType(visitor); + break; case ESM::REC_ACTI4: cell.mStore->template forEachType(visitor); diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index ee746001ae..c607dc9d14 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -77,20 +77,25 @@ namespace MWLua return &wm->getExterior(ESM::positionToExteriorCellLocation(pos.x(), pos.y(), worldspace)); } - void teleportPlayer( - MWWorld::CellStore* destCell, const osg::Vec3f& pos, const osg::Vec3f& rot, bool placeOnGround) + ESM::Position toPos(const osg::Vec3f& pos, const osg::Vec3f& rot) { - MWBase::World* world = MWBase::Environment::get().getWorld(); ESM::Position esmPos; static_assert(sizeof(esmPos) == sizeof(osg::Vec3f) * 2); std::memcpy(esmPos.pos, &pos, sizeof(osg::Vec3f)); std::memcpy(esmPos.rot, &rot, sizeof(osg::Vec3f)); + return esmPos; + } + + void teleportPlayer( + MWWorld::CellStore* destCell, const osg::Vec3f& pos, const osg::Vec3f& rot, bool placeOnGround) + { + MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr ptr = world->getPlayerPtr(); auto& stats = ptr.getClass().getCreatureStats(ptr); stats.land(true); stats.setTeleported(true); world->getPlayer().setTeleported(true); - world->changeToCell(destCell->getCell()->getId(), esmPos, false); + world->changeToCell(destCell->getCell()->getId(), toPos(pos, rot), false); MWWorld::Ptr newPtr = world->getPlayerPtr(); world->moveObject(newPtr, pos); world->rotateObject(newPtr, rot); @@ -103,6 +108,7 @@ namespace MWLua const osg::Vec3f& rot, bool placeOnGround) { MWBase::World* world = MWBase::Environment::get().getWorld(); + MWWorld::WorldModel* wm = MWBase::Environment::get().getWorldModel(); const MWWorld::Class& cls = ptr.getClass(); if (cls.isActor()) { @@ -110,8 +116,19 @@ namespace MWLua stats.land(false); stats.setTeleported(true); } - MWWorld::Ptr newPtr = world->moveObject(ptr, destCell, pos); - world->rotateObject(newPtr, rot, MWBase::RotationFlag_none); + MWWorld::Ptr newPtr; + if (ptr.getCell() == &wm->getDraftCell()) + { + newPtr = world->placeObject(ptr, destCell, toPos(pos, rot)); + ptr.getCellRef().unsetRefNum(); + ptr.getRefData().setLuaScripts(nullptr); + ptr.getRefData().setCount(0); + } + else + { + newPtr = world->moveObject(ptr, destCell, pos); + world->rotateObject(newPtr, rot, MWBase::RotationFlag_none); + } if (placeOnGround) world->adjustPosition(newPtr, true); if (cls.isDoor()) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index f7ec3ddcba..a41fbb150a 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -1235,13 +1235,12 @@ namespace MWWorld clearCorpse(ptr, mStore); ptr.getClass().respawn(ptr); } - for (CellRefList::List::iterator it(get().mList.begin()); - it != get().mList.end(); ++it) - { - Ptr ptr = getCurrentPtr(&*it); + forEachType([](Ptr ptr) { // no need to clearCorpse, handled as part of get() - ptr.getClass().respawn(ptr); - } + if (!ptr.getRefData().isDeleted()) + ptr.getClass().respawn(ptr); + return false; + }); } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 23bd071ff1..94d0fd6d67 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -262,7 +262,7 @@ namespace MWWorld /// unintended behaviour. \attention This function also lists deleted (count 0) objects! \return Iteration /// completed? template - bool forEachType(Visitor& visitor) + bool forEachType(Visitor&& visitor) { if (mState != State_Loaded) return false; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index de3c2b011d..c5e30fc5c3 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -372,7 +372,8 @@ namespace MWWorld MWWorld::Ptr Class::copyToCell(const ConstPtr& ptr, CellStore& cell, int count) const { Ptr newPtr = copyToCellImpl(ptr, cell); - newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference + if (ptr.getCell() != &MWBase::Environment::get().getWorldModel()->getDraftCell()) + newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference newPtr.getRefData().setCount(count); newPtr.getRefData().setLuaScripts(nullptr); MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); diff --git a/files/lua_api/openmw/world.lua b/files/lua_api/openmw/world.lua index c55860ee26..97f596e4a6 100644 --- a/files/lua_api/openmw/world.lua +++ b/files/lua_api/openmw/world.lua @@ -134,6 +134,7 @@ --- -- Create a new instance of the given record. -- After creation the object is in the disabled state. Use :teleport to place to the world or :moveInto to put it into a container or an inventory. +-- Note that dynamically created creatures, NPCs, and container inventories will not respawn. -- @function [parent=#world] createObject -- @param #string recordId Record ID in lowercase -- @param #number count (optional, 1 by default) The number of objects in stack From 33b57d9134f30f9e25b8a6acb1251d96cf3705e0 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 27 Sep 2023 21:23:07 +0200 Subject: [PATCH 3/5] Use moveToCell and init mwscript --- apps/openmw/mwclass/misc.cpp | 3 +-- apps/openmw/mwlua/objectbindings.cpp | 12 +++++++++--- apps/openmw/mwworld/class.cpp | 3 +-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index c5f9de23b1..6c517e3dde 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -205,8 +205,7 @@ namespace MWClass newPtr = MWWorld::Ptr(cell.insert(ref), &cell); newPtr.getRefData().setCount(count); } - if (ptr.getCell() != &MWBase::Environment::get().getWorldModel()->getDraftCell()) - newPtr.getCellRef().unsetRefNum(); + newPtr.getCellRef().unsetRefNum(); newPtr.getRefData().setLuaScripts(nullptr); MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); return newPtr; diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index c607dc9d14..b2d5824629 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -11,6 +11,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/localscripts.hpp" #include "../mwworld/player.hpp" #include "../mwworld/scene.hpp" #include "../mwworld/worldmodel.hpp" @@ -112,17 +113,22 @@ namespace MWLua const MWWorld::Class& cls = ptr.getClass(); if (cls.isActor()) { - auto& stats = ptr.getClass().getCreatureStats(ptr); + auto& stats = cls.getCreatureStats(ptr); stats.land(false); stats.setTeleported(true); } + const MWWorld::CellStore* srcCell = ptr.getCell(); MWWorld::Ptr newPtr; - if (ptr.getCell() == &wm->getDraftCell()) + if (srcCell == &wm->getDraftCell()) { - newPtr = world->placeObject(ptr, destCell, toPos(pos, rot)); + newPtr = cls.moveToCell(ptr, *destCell, toPos(pos, rot)); ptr.getCellRef().unsetRefNum(); ptr.getRefData().setLuaScripts(nullptr); ptr.getRefData().setCount(0); + ESM::RefId script = cls.getScript(newPtr); + if (!script.empty()) + world->getLocalScripts().add(script, newPtr); + world->addContainerScripts(newPtr, newPtr.getCell()); } else { diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c5e30fc5c3..de3c2b011d 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -372,8 +372,7 @@ namespace MWWorld MWWorld::Ptr Class::copyToCell(const ConstPtr& ptr, CellStore& cell, int count) const { Ptr newPtr = copyToCellImpl(ptr, cell); - if (ptr.getCell() != &MWBase::Environment::get().getWorldModel()->getDraftCell()) - newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference + newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference newPtr.getRefData().setCount(count); newPtr.getRefData().setLuaScripts(nullptr); MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); From f6626e36cf162013eee43e0919c10b25e3e4b5c4 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 27 Sep 2023 22:07:55 +0200 Subject: [PATCH 4/5] Unbreak respawns and fix #7588 --- apps/openmw/mwlua/objectbindings.cpp | 6 ++++++ apps/openmw/mwworld/cellstore.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index b2d5824629..0a1098f450 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -133,6 +133,12 @@ namespace MWLua else { newPtr = world->moveObject(ptr, destCell, pos); + if (MWBase::Environment::get().getWorldScene()->isCellActive(*srcCell)) + { + ESM::RefId script = cls.getScript(newPtr); + if (!script.empty()) + world->getLocalScripts().add(script, newPtr); + } world->rotateObject(newPtr, rot, MWBase::RotationFlag_none); } if (placeOnGround) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index a41fbb150a..8fb86f2cad 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -1239,7 +1239,7 @@ namespace MWWorld // no need to clearCorpse, handled as part of get() if (!ptr.getRefData().isDeleted()) ptr.getClass().respawn(ptr); - return false; + return true; }); } } From 7594d9402407c2420141e6fcc2fcb3a47c926a68 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 27 Sep 2023 22:24:28 +0200 Subject: [PATCH 5/5] Prevent re-adding local scripts --- apps/openmw/mwlua/objectbindings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 0a1098f450..ef25dadfab 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -133,7 +133,7 @@ namespace MWLua else { newPtr = world->moveObject(ptr, destCell, pos); - if (MWBase::Environment::get().getWorldScene()->isCellActive(*srcCell)) + if (srcCell == destCell) { ESM::RefId script = cls.getScript(newPtr); if (!script.empty())