Merge MWLua::ObjectRegistry and MWWorld::WorldModel

iwyu_full
Petr Mikheev 2 years ago
parent 80e2cd79ec
commit b8fb013edf

@ -36,8 +36,6 @@ namespace MWBase
virtual void newGameStarted() = 0;
virtual void gameLoaded() = 0;
virtual void registerObject(const MWWorld::Ptr& ptr) = 0;
virtual void deregisterObject(const MWWorld::Ptr& ptr) = 0;
virtual void objectAddedToScene(const MWWorld::Ptr& ptr) = 0;
virtual void objectRemovedFromScene(const MWWorld::Ptr& ptr) = 0;
virtual void itemConsumed(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor) = 0;

@ -57,11 +57,11 @@ namespace MWLua
if constexpr (std::is_same_v<CellT, GCell>)
{ // only for global scripts
cellT["getAll"] = [worldView = context.mWorldView, ids = getPackageToTypeTable(context.mLua->sol())](
cellT["getAll"] = [ids = getPackageToTypeTable(context.mLua->sol())](
const CellT& cell, sol::optional<sol::table> type) {
ObjectIdList res = std::make_shared<std::vector<ObjectId>>();
auto visitor = [&](const MWWorld::Ptr& ptr) {
worldView->getObjectRegistry()->registerPtr(ptr);
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
if (getLiveCellRefType(ptr.mRef) == ptr.getType())
res->push_back(getId(ptr));
return true;

@ -92,14 +92,13 @@ namespace MWLua
return "Unknown";
}
});
aiPackage["target"]
= sol::readonly_property([worldView = context.mWorldView](const AiPackage& p) -> sol::optional<LObject> {
MWWorld::Ptr target = p.getTarget();
if (target.isEmpty())
return sol::nullopt;
else
return LObject(getId(target), worldView->getObjectRegistry());
});
aiPackage["target"] = sol::readonly_property([](const AiPackage& p) -> sol::optional<LObject> {
MWWorld::Ptr target = p.getTarget();
if (target.isEmpty())
return sol::nullopt;
else
return LObject(getId(target));
});
aiPackage["sideWithTarget"] = sol::readonly_property([](const AiPackage& p) { return p.sideWithTarget(); });
aiPackage["destPosition"] = sol::readonly_property([](const AiPackage& p) { return p.getDestination(); });

@ -55,10 +55,10 @@ namespace MWLua
Log(Debug::Info) << "Lua version: " << LuaUtil::getLuaVersion();
mLua.addInternalLibSearchPath(libsDir);
mGlobalSerializer = createUserdataSerializer(false, mWorldView.getObjectRegistry());
mLocalSerializer = createUserdataSerializer(true, mWorldView.getObjectRegistry());
mGlobalLoader = createUserdataSerializer(false, mWorldView.getObjectRegistry(), &mContentFileMapping);
mLocalLoader = createUserdataSerializer(true, mWorldView.getObjectRegistry(), &mContentFileMapping);
mGlobalSerializer = createUserdataSerializer(false);
mLocalSerializer = createUserdataSerializer(true);
mGlobalLoader = createUserdataSerializer(false, &mContentFileMapping);
mLocalLoader = createUserdataSerializer(true, &mContentFileMapping);
mGlobalScripts.setSerializer(mGlobalSerializer.get());
}
@ -141,7 +141,6 @@ namespace MWLua
return; // The game is not started yet.
float frameDuration = MWBase::Environment::get().getFrameDuration();
ObjectRegistry* objectRegistry = mWorldView.getObjectRegistry();
MWWorld::Ptr newPlayerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr();
if (!(getId(mPlayer) == getId(newPlayerPtr)))
@ -149,7 +148,7 @@ namespace MWLua
if (!mPlayer.isInCell() || !newPlayerPtr.isInCell() || mPlayer.getCell() != newPlayerPtr.getCell())
{
mPlayer = newPlayerPtr; // player was moved to another cell, update ptr in registry
objectRegistry->registerPtr(mPlayer);
MWBase::Environment::get().getWorldModel()->registerPtr(mPlayer);
}
mWorldView.update();
@ -179,7 +178,7 @@ namespace MWLua
mGlobalScripts.receiveEvent(e.mEventName, e.mEventData);
for (LocalEvent& e : localEvents)
{
LObject obj(e.mDest, objectRegistry);
LObject obj(e.mDest);
LocalScripts* scripts = obj.isValid() ? obj.ptr().getRefData().getLuaScripts() : nullptr;
if (scripts)
scripts->receiveEvent(e.mEventName, e.mEventData);
@ -196,7 +195,7 @@ namespace MWLua
// Engine handlers in local scripts
for (const LocalEngineEvent& e : mLocalEngineEvents)
{
LObject obj(e.mDest, objectRegistry);
LObject obj(e.mDest);
if (!obj.isValid())
{
if (luaDebug)
@ -220,7 +219,7 @@ namespace MWLua
if (mPlayerChanged)
{
mPlayerChanged = false;
mGlobalScripts.playerAdded(GObject(getId(mPlayer), objectRegistry));
mGlobalScripts.playerAdded(GObject(getId(mPlayer)));
}
if (mNewGameStarted)
{
@ -230,7 +229,7 @@ namespace MWLua
for (ObjectId id : mObjectAddedEvents)
{
GObject obj(id, objectRegistry);
GObject obj(id);
if (obj.isValid())
{
mGlobalScripts.objectActive(obj);
@ -378,32 +377,20 @@ namespace MWLua
if (localScripts)
{
mActiveLocalScripts.erase(localScripts);
if (!mWorldView.getObjectRegistry()->getPtr(getId(ptr), true).isEmpty())
if (!MWBase::Environment::get().getWorldModel()->getPtr(getId(ptr)).isEmpty())
mLocalEngineEvents.push_back({ getId(ptr), LocalScripts::OnInactive{} });
}
}
void LuaManager::registerObject(const MWWorld::Ptr& ptr)
{
mWorldView.getObjectRegistry()->registerPtr(ptr);
}
void LuaManager::deregisterObject(const MWWorld::Ptr& ptr)
{
mWorldView.getObjectRegistry()->deregisterPtr(ptr);
}
void LuaManager::itemConsumed(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor)
{
mWorldView.getObjectRegistry()->registerPtr(consumable);
mLocalEngineEvents.push_back(
{ getId(actor), LocalScripts::OnConsume{ LObject(getId(consumable), mWorldView.getObjectRegistry()) } });
MWBase::Environment::get().getWorldModel()->registerPtr(consumable);
mLocalEngineEvents.push_back({ getId(actor), LocalScripts::OnConsume{ LObject(getId(consumable)) } });
}
void LuaManager::objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor)
{
mLocalEngineEvents.push_back(
{ getId(object), LocalScripts::OnActivated{ LObject(getId(actor), mWorldView.getObjectRegistry()) } });
mLocalEngineEvents.push_back({ getId(object), LocalScripts::OnActivated{ LObject(getId(actor)) } });
}
MWBase::LuaManager::ActorControls* LuaManager::getActorControls(const MWWorld::Ptr& ptr) const
@ -437,7 +424,7 @@ namespace MWLua
throw std::runtime_error("Lua scripts on static objects are not allowed");
else if (type == ESM::REC_INTERNAL_PLAYER)
{
scripts = std::make_shared<PlayerScripts>(&mLua, LObject(getId(ptr), mWorldView.getObjectRegistry()));
scripts = std::make_shared<PlayerScripts>(&mLua, LObject(getId(ptr)));
scripts->setAutoStartConf(mConfiguration.getPlayerConf());
scripts->addPackage("openmw.ui", mUserInterfacePackage);
scripts->addPackage("openmw.camera", mCameraPackage);
@ -448,7 +435,7 @@ namespace MWLua
}
else
{
scripts = std::make_shared<LocalScripts>(&mLua, LObject(getId(ptr), mWorldView.getObjectRegistry()));
scripts = std::make_shared<LocalScripts>(&mLua, LObject(getId(ptr)));
if (!autoStartConf.has_value())
autoStartConf = mConfiguration.getLocalConf(type, ptr.getCellRef().getRefId(), getId(ptr));
scripts->setAutoStartConf(std::move(*autoStartConf));
@ -507,7 +494,7 @@ namespace MWLua
return;
}
mWorldView.getObjectRegistry()->registerPtr(ptr);
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
LocalScripts* scripts = createLocalScripts(ptr);
scripts->setSerializer(mLocalSerializer.get());
@ -515,7 +502,7 @@ namespace MWLua
scripts->load(data);
// LiveCellRef is usually copied after loading, so this Ptr will become invalid and should be deregistered.
mWorldView.getObjectRegistry()->deregisterPtr(ptr);
MWBase::Environment::get().getWorldModel()->deregisterPtr(ptr);
}
void LuaManager::reloadAllScripts()
@ -536,7 +523,7 @@ namespace MWLua
mGlobalScripts.load(data);
}
for (const auto& [id, ptr] : mWorldView.getObjectRegistry()->mObjectMapping)
for (const auto& [id, ptr] : MWBase::Environment::get().getWorldModel()->getAllPtrs())
{ // Reload local scripts
LocalScripts* scripts = ptr.getRefData().getLuaScripts();
if (scripts == nullptr)
@ -564,7 +551,7 @@ namespace MWLua
}
sol::object selected = sol::nil;
if (!selectedPtr.isEmpty())
selected = sol::make_object(mLua.sol(), LObject(getId(selectedPtr), mWorldView.getObjectRegistry()));
selected = sol::make_object(mLua.sol(), LObject(getId(selectedPtr)));
if (!playerScripts->consoleCommand(consoleMode, command, selected))
MWBase::Environment::get().getWindowManager()->printToConsole(
"No Lua handlers for console\n", MWBase::WindowManager::sConsoleColor_Error);

@ -47,8 +47,6 @@ namespace MWLua
void gameLoaded() override;
void objectAddedToScene(const MWWorld::Ptr& ptr) override;
void objectRemovedFromScene(const MWWorld::Ptr& ptr) override;
void registerObject(const MWWorld::Ptr& ptr) override;
void deregisterObject(const MWWorld::Ptr& ptr) override;
void inputEvent(const InputEvent& event) override { mInputEvents.push_back(event); }
void itemConsumed(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor) override;
void objectActivated(const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override;

@ -45,11 +45,11 @@ namespace MWLua
return sol::nullopt;
});
rayResult["hitObject"]
= sol::readonly_property([worldView](const MWPhysics::RayCastingResult& r) -> sol::optional<LObject> {
= sol::readonly_property([](const MWPhysics::RayCastingResult& r) -> sol::optional<LObject> {
if (r.mHitObject.isEmpty())
return sol::nullopt;
else
return LObject(getId(r.mHitObject), worldView->getObjectRegistry());
return LObject(getId(r.mHitObject));
});
api["COLLISION_TYPE"]

@ -39,10 +39,11 @@ namespace MWLua
bool Object::isValid() const
{
if (mLastUpdate < mObjectRegistry->mUpdateCounter)
MWWorld::WorldModel& w = *MWBase::Environment::get().getWorldModel();
if (mLastUpdate < w.getPtrIndexUpdateCounter())
{
updatePtr();
mLastUpdate = mObjectRegistry->mUpdateCounter;
mPtr = w.getPtr(mId);
mLastUpdate = w.getPtrIndexUpdateCounter();
}
return !mPtr.isEmpty();
}
@ -53,56 +54,4 @@ namespace MWLua
throw std::runtime_error("Object is not available: " + idToString(mId));
return mPtr;
}
void ObjectRegistry::update()
{
if (mChanged)
{
mUpdateCounter++;
mChanged = false;
}
}
void ObjectRegistry::clear()
{
mObjectMapping.clear();
mChanged = false;
mUpdateCounter = 0;
mLastAssignedId.unset();
}
MWWorld::Ptr ObjectRegistry::getPtr(ObjectId id, bool local)
{
MWWorld::Ptr ptr;
auto it = mObjectMapping.find(id);
if (it != mObjectMapping.end())
ptr = it->second;
if (local)
{
// TODO: Return ptr only if it is active or was active in the previous frame, otherwise return empty.
// Needed because in multiplayer inactive objects will not be synchronized, so an be out of date.
}
else
{
// TODO: If Ptr is empty then try to load the object from esp/esm3.
}
return ptr;
}
ObjectId ObjectRegistry::registerPtr(const MWWorld::Ptr& ptr)
{
ObjectId id = ptr.getCellRef().getOrAssignRefNum(mLastAssignedId);
mChanged = true;
mObjectMapping[id] = ptr;
return id;
}
ObjectId ObjectRegistry::deregisterPtr(const MWWorld::Ptr& ptr)
{
ObjectId id = getId(ptr);
mChanged = true;
mObjectMapping.erase(id);
return id;
}
}

@ -8,7 +8,9 @@
#include <components/esm3/cellref.hpp>
#include "../mwbase/environment.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/worldmodel.hpp"
namespace MWLua
{
@ -23,46 +25,14 @@ namespace MWLua
std::string ptrToString(const MWWorld::Ptr& ptr);
bool isMarker(const MWWorld::Ptr& ptr);
// Holds a mapping ObjectId -> MWWord::Ptr.
class ObjectRegistry
{
public:
ObjectRegistry() { mLastAssignedId.unset(); }
void update(); // Should be called every frame.
void clear(); // Should be called before starting or loading a new game.
ObjectId registerPtr(const MWWorld::Ptr& ptr);
ObjectId deregisterPtr(const MWWorld::Ptr& ptr);
// Returns Ptr by id. If object is not found, returns empty Ptr.
// If local = true, returns non-empty ptr only if it can be used in local scripts
// (i.e. is active or was active in the previous frame).
MWWorld::Ptr getPtr(ObjectId id, bool local);
// Needed only for saving/loading.
const ObjectId& getLastAssignedId() const { return mLastAssignedId; }
void setLastAssignedId(ObjectId id) { mLastAssignedId = id; }
private:
friend class Object;
friend class LuaManager;
bool mChanged = false;
int64_t mUpdateCounter = 0;
std::map<ObjectId, MWWorld::Ptr> mObjectMapping;
ObjectId mLastAssignedId;
};
// Lua scripts can't use MWWorld::Ptr directly, because lifetime of a script can be longer than lifetime of Ptr.
// `GObject` and `LObject` are intended to be passed to Lua as a userdata.
// It automatically updates the underlying Ptr when needed.
class Object
{
public:
Object(ObjectId id, ObjectRegistry* reg)
Object(ObjectId id)
: mId(id)
, mObjectRegistry(reg)
{
}
virtual ~Object() {}
@ -80,13 +50,10 @@ namespace MWLua
virtual sol::object getCell(lua_State* lua, MWWorld::CellStore* store) const = 0; // returns LCell or GCell
protected:
virtual void updatePtr() const = 0;
const ObjectId mId;
ObjectRegistry* mObjectRegistry;
mutable MWWorld::Ptr mPtr;
mutable int64_t mLastUpdate = -1;
mutable size_t mLastUpdate = 0;
};
// Used only in local scripts
@ -97,11 +64,7 @@ namespace MWLua
class LObject : public Object
{
using Object::Object;
void updatePtr() const final { mPtr = mObjectRegistry->getPtr(mId, true); }
sol::object getObject(lua_State* lua, ObjectId id) const final
{
return sol::make_object<LObject>(lua, id, mObjectRegistry);
}
sol::object getObject(lua_State* lua, ObjectId id) const final { return sol::make_object<LObject>(lua, id); }
sol::object getCell(lua_State* lua, MWWorld::CellStore* store) const final
{
return sol::make_object(lua, LCell{ store });
@ -116,11 +79,7 @@ namespace MWLua
class GObject : public Object
{
using Object::Object;
void updatePtr() const final { mPtr = mObjectRegistry->getPtr(mId, false); }
sol::object getObject(lua_State* lua, ObjectId id) const final
{
return sol::make_object<GObject>(lua, id, mObjectRegistry);
}
sol::object getObject(lua_State* lua, ObjectId id) const final { return sol::make_object<GObject>(lua, id); }
sol::object getCell(lua_State* lua, MWWorld::CellStore* store) const final
{
return sol::make_object(lua, GCell{ store });

@ -68,7 +68,7 @@ namespace MWLua
throw std::runtime_error(std::string("cell not found: '") + mCell.getRefIdString() + "'");
MWBase::World* world = MWBase::Environment::get().getWorld();
MWWorld::Ptr obj = worldView.getObjectRegistry()->getPtr(mObject, false);
MWWorld::Ptr obj = MWBase::Environment::get().getWorldModel()->getPtr(mObject);
const MWWorld::Class& cls = obj.getClass();
bool isPlayer = obj == world->getPlayerPtr();
if (cls.isActor())
@ -113,10 +113,10 @@ namespace MWLua
void apply(WorldView& worldView) const override
{
MWWorld::Ptr object = worldView.getObjectRegistry()->getPtr(mObject, true);
MWWorld::Ptr object = MWBase::Environment::get().getWorldModel()->getPtr(mObject);
if (object.isEmpty())
throw std::runtime_error(std::string("Object not found: " + idToString(mObject)));
MWWorld::Ptr actor = worldView.getObjectRegistry()->getPtr(mActor, true);
MWWorld::Ptr actor = MWBase::Environment::get().getWorldModel()->getPtr(mActor);
if (actor.isEmpty())
throw std::runtime_error(std::string("Actor not found: " + idToString(mActor)));
@ -147,14 +147,13 @@ namespace MWLua
{
using ListT = ObjectList<ObjectT>;
sol::state_view& lua = context.mLua->sol();
ObjectRegistry* registry = context.mWorldView->getObjectRegistry();
sol::usertype<ListT> listT = lua.new_usertype<ListT>(prefix + "ObjectList");
listT[sol::meta_function::to_string]
= [](const ListT& list) { return "{" + std::to_string(list.mIds->size()) + " objects}"; };
listT[sol::meta_function::length] = [](const ListT& list) { return list.mIds->size(); };
listT[sol::meta_function::index] = [registry](const ListT& list, size_t index) {
listT[sol::meta_function::index] = [](const ListT& list, size_t index) {
if (index > 0 && index <= list.mIds->size())
return ObjectT((*list.mIds)[index - 1], registry);
return ObjectT((*list.mIds)[index - 1]);
else
throw std::runtime_error("Index out of range");
};
@ -265,7 +264,7 @@ namespace MWLua
inventoryT[sol::meta_function::to_string]
= [](const InventoryT& inv) { return "Inventory[" + inv.mObj.toString() + "]"; };
inventoryT["getAll"] = [worldView = context.mWorldView, ids = getPackageToTypeTable(context.mLua->sol())](
inventoryT["getAll"] = [ids = getPackageToTypeTable(context.mLua->sol())](
const InventoryT& inventory, sol::optional<sol::table> type) {
int mask = -1;
sol::optional<uint32_t> typeId = sol::nullopt;
@ -329,7 +328,7 @@ namespace MWLua
while (it.getType() != -1)
{
const MWWorld::Ptr& item = *(it++);
worldView->getObjectRegistry()->registerPtr(item);
MWBase::Environment::get().getWorldModel()->registerPtr(item);
list->push_back(getId(item));
}
return ObjectList<ObjectT>{ list };

@ -99,7 +99,7 @@ namespace MWLua
void apply(WorldView& worldView) const override
{
LObject obj(mId, worldView.getObjectRegistry());
LObject obj(mId);
LocalScripts* scripts = obj.ptr().getRefData().getLuaScripts();
if (scripts)
scripts->applyStatsCache();

@ -31,18 +31,18 @@ namespace MWLua
void apply(WorldView& worldView) const override
{
MWWorld::Ptr actor = worldView.getObjectRegistry()->getPtr(mActor, false);
MWWorld::Ptr actor = MWBase::Environment::get().getWorldModel()->getPtr(mActor);
MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor);
std::array<bool, MWWorld::InventoryStore::Slots> usedSlots;
std::fill(usedSlots.begin(), usedSlots.end(), false);
static constexpr int anySlot = -1;
auto tryEquipToSlot = [&actor, &store, &usedSlots, &worldView](int slot, const Item& item) -> bool {
auto tryEquipToSlot = [&actor, &store, &usedSlots](int slot, const Item& item) -> bool {
auto old_it = slot != anySlot ? store.getSlot(slot) : store.end();
MWWorld::Ptr itemPtr;
if (std::holds_alternative<ObjectId>(item))
{
itemPtr = worldView.getObjectRegistry()->getPtr(std::get<ObjectId>(item), false);
itemPtr = MWBase::Environment::get().getWorldModel()->getPtr(std::get<ObjectId>(item));
if (old_it != store.end() && *old_it == itemPtr)
return true; // already equipped
if (itemPtr.isEmpty() || itemPtr.getRefData().getCount() == 0
@ -187,7 +187,7 @@ namespace MWLua
auto it = store.getSlot(slot);
if (it == store.end())
continue;
context.mWorldView->getObjectRegistry()->registerPtr(*it);
MWBase::Environment::get().getWorldModel()->registerPtr(*it);
equipment[slot] = o.getObject(context.mLua->sol(), getId(*it));
}
return equipment;
@ -201,7 +201,7 @@ namespace MWLua
auto it = store.getSlot(slot);
if (it == store.end())
return sol::nil;
context.mWorldView->getObjectRegistry()->registerPtr(*it);
MWBase::Environment::get().getWorldModel()->registerPtr(*it);
return o.getObject(context.mLua->sol(), getId(*it));
};
actor["equipment"] = sol::overload(getAllEquipment, getEquipmentFromSlot);

@ -10,9 +10,8 @@ namespace MWLua
class Serializer final : public LuaUtil::UserdataSerializer
{
public:
explicit Serializer(bool localSerializer, ObjectRegistry* registry, std::map<int, int>* contentFileMapping)
explicit Serializer(bool localSerializer, std::map<int, int>* contentFileMapping)
: mLocalSerializer(localSerializer)
, mObjectRegistry(registry)
, mContentFileMapping(contentFileMapping)
{
}
@ -44,23 +43,22 @@ namespace MWLua
id.mContentFile = iter->second;
}
if (mLocalSerializer)
sol::stack::push<LObject>(lua, LObject(id, mObjectRegistry));
sol::stack::push<LObject>(lua, LObject(id));
else
sol::stack::push<GObject>(lua, GObject(id, mObjectRegistry));
sol::stack::push<GObject>(lua, GObject(id));
return true;
}
return false;
}
bool mLocalSerializer;
ObjectRegistry* mObjectRegistry;
std::map<int, int>* mContentFileMapping;
};
std::unique_ptr<LuaUtil::UserdataSerializer> createUserdataSerializer(
bool local, ObjectRegistry* registry, std::map<int, int>* contentFileMapping)
bool local, std::map<int, int>* contentFileMapping)
{
return std::make_unique<Serializer>(local, registry, contentFileMapping);
return std::make_unique<Serializer>(local, contentFileMapping);
}
}

@ -16,7 +16,7 @@ namespace MWLua
// contentFileMapping is used only for deserialization. Needed to fix references if the order
// of content files was changed.
std::unique_ptr<LuaUtil::UserdataSerializer> createUserdataSerializer(
bool local, ObjectRegistry* registry, std::map<int, int>* contentFileMapping = nullptr);
bool local, std::map<int, int>* contentFileMapping = nullptr);
}
#endif // MWLUA_USERDATASERIALIZER_H

@ -18,7 +18,6 @@ namespace MWLua
void WorldView::update()
{
mObjectRegistry.update();
mActivatorsInScene.updateList();
mActorsInScene.updateList();
mContainersInScene.updateList();
@ -29,7 +28,6 @@ namespace MWLua
void WorldView::clear()
{
mObjectRegistry.clear();
mActivatorsInScene.clear();
mActorsInScene.clear();
mContainersInScene.clear();
@ -59,7 +57,7 @@ namespace MWLua
void WorldView::objectAddedToScene(const MWWorld::Ptr& ptr)
{
mObjectRegistry.registerPtr(ptr);
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
ObjectGroup* group = chooseGroup(ptr);
if (group)
addToGroup(*group, ptr);
@ -84,13 +82,13 @@ namespace MWLua
esm.getHNT(mSimulationTime, "LUAW");
ObjectId lastAssignedId;
lastAssignedId.load(esm, true);
mObjectRegistry.setLastAssignedId(lastAssignedId);
MWBase::Environment::get().getWorldModel()->setLastGeneratedRefNum(lastAssignedId);
}
void WorldView::save(ESM::ESMWriter& esm) const
{
esm.writeHNT("LUAW", mSimulationTime);
mObjectRegistry.getLastAssignedId().save(esm, true);
MWBase::Environment::get().getWorldModel()->getLastGeneratedRefNum().save(esm, true);
}
void WorldView::ObjectGroup::updateList()

@ -17,7 +17,11 @@ namespace ESM
namespace MWLua
{
// Tracks all used game objects.
// WorldView is a kind of an extension to mwworld. It was created on initial stage of
// OpenMW Lua development in order to minimize the risk of merge conflicts.
// TODO: Move get*InScene functions to mwworld/scene
// TODO: Move time-related stuff to mwworld; maybe create a new class TimeManager.
// TODO: Remove WorldView.
class WorldView
{
public:
@ -43,10 +47,6 @@ namespace MWLua
ObjectIdList getDoorsInScene() const { return mDoorsInScene.mList; }
ObjectIdList getItemsInScene() const { return mItemsInScene.mList; }
ObjectRegistry* getObjectRegistry() { return &mObjectRegistry; }
void objectUnloaded(const MWWorld::Ptr& ptr) { mObjectRegistry.deregisterPtr(ptr); }
void objectAddedToScene(const MWWorld::Ptr& ptr);
void objectRemovedFromScene(const MWWorld::Ptr& ptr);
@ -79,7 +79,6 @@ namespace MWLua
void addToGroup(ObjectGroup& group, const MWWorld::Ptr& ptr);
void removeFromGroup(ObjectGroup& group, const MWWorld::Ptr& ptr);
ObjectRegistry mObjectRegistry;
ObjectGroup mActivatorsInScene;
ObjectGroup mActorsInScene;
ObjectGroup mContainersInScene;

@ -53,6 +53,7 @@
#include "containerstore.hpp"
#include "esmstore.hpp"
#include "ptr.hpp"
#include "worldmodel.hpp"
namespace
{
@ -266,7 +267,7 @@ namespace
MWBase::Environment::get().getWorld()->disable(MWWorld::Ptr(&*iter, cellstore));
}
else
MWBase::Environment::get().getLuaManager()->registerObject(MWWorld::Ptr(&*iter, cellstore));
MWBase::Environment::get().getWorldModel()->registerPtr(MWWorld::Ptr(&*iter, cellstore));
return;
}
@ -281,7 +282,7 @@ namespace
collection.mList.push_back(ref);
MWWorld::LiveCellRefBase* base = &collection.mList.back();
MWBase::Environment::get().getLuaManager()->registerObject(MWWorld::Ptr(base, cellstore));
MWBase::Environment::get().getWorldModel()->registerPtr(MWWorld::Ptr(base, cellstore));
}
// this function allows us to link a CellRefList<T> to the associated recNameInt, and apply a function
@ -416,7 +417,7 @@ namespace MWWorld
if (searchViaRefNum(object.getCellRef().getRefNum()).isEmpty())
throw std::runtime_error("moveTo: object is not in this cell");
MWBase::Environment::get().getLuaManager()->registerObject(MWWorld::Ptr(object.getBase(), cellToMoveTo));
MWBase::Environment::get().getWorldModel()->registerPtr(MWWorld::Ptr(object.getBase(), cellToMoveTo));
MovedRefTracker::iterator found = mMovedHere.find(object.getBase());
if (found != mMovedHere.end())

@ -317,6 +317,7 @@ namespace MWWorld
mLocalScripts.clear();
mWorldScene->clear();
mWorldModel.clear();
mStore.clearDynamic();
@ -328,8 +329,6 @@ namespace MWWorld
mPlayer->set(mStore.get<ESM::NPC>().find(ESM::RefId::stringRefId("Player")));
}
mWorldModel.clear();
mDoorStates.clear();
mGoToJail = false;
@ -816,7 +815,7 @@ namespace MWWorld
void World::enable(const Ptr& reference)
{
MWBase::Environment::get().getLuaManager()->registerObject(reference);
MWBase::Environment::get().getWorldModel()->registerPtr(reference);
if (!reference.isInCell())
return;
@ -868,7 +867,7 @@ namespace MWWorld
if (reference == getPlayerPtr())
throw std::runtime_error("can not disable player object");
MWBase::Environment::get().getLuaManager()->deregisterObject(reference);
MWBase::Environment::get().getWorldModel()->deregisterPtr(reference);
reference.getRefData().disable();
if (reference.getCellRef().getRefNum().hasContentFile())

@ -85,12 +85,36 @@ MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell)
void MWWorld::WorldModel::clear()
{
mPtrIndex.clear();
mPtrIndexUpdateCounter = 0;
mLastGeneratedRefnum.unset();
mInteriors.clear();
mExteriors.clear();
std::fill(mIdCache.begin(), mIdCache.end(), std::make_pair(ESM::RefId::sEmpty, (MWWorld::CellStore*)nullptr));
mIdCacheIndex = 0;
}
void MWWorld::WorldModel::registerPtr(const MWWorld::Ptr& ptr)
{
mPtrIndex[ptr.getCellRef().getOrAssignRefNum(mLastGeneratedRefnum)] = ptr;
mPtrIndexUpdateCounter++;
}
void MWWorld::WorldModel::deregisterPtr(const MWWorld::Ptr& ptr)
{
mPtrIndex.erase(ptr.getCellRef().getRefNum());
mPtrIndexUpdateCounter++;
}
MWWorld::Ptr MWWorld::WorldModel::getPtr(const ESM::RefNum& refNum) const
{
auto it = mPtrIndex.find(refNum);
if (it != mPtrIndex.end())
return it->second;
else
return MWWorld::Ptr();
}
MWWorld::Ptr MWWorld::WorldModel::getPtrAndCache(const ESM::RefId& name, CellStore& cellStore)
{
Ptr ptr = getPtr(name, cellStore);

@ -4,6 +4,7 @@
#include <list>
#include <map>
#include <string>
#include <unordered_map>
#include "ptr.hpp"
@ -48,6 +49,10 @@ namespace MWWorld
void writeCell(ESM::ESMWriter& writer, CellStore& cell) const;
std::unordered_map<ESM::RefNum, Ptr> mPtrIndex;
size_t mPtrIndexUpdateCounter;
ESM::RefNum mLastGeneratedRefnum;
public:
void clear();
@ -55,11 +60,20 @@ namespace MWWorld
CellStore* getExterior(int x, int y);
CellStore* getInterior(const ESM::RefId& name);
CellStore* getInterior(std::string_view name);
CellStore* getCell(const ESM::CellId& id);
Ptr getPtr(const ESM::RefId& name, CellStore& cellStore, bool searchInContainers = false);
void registerPtr(const MWWorld::Ptr& ptr);
void deregisterPtr(const MWWorld::Ptr& ptr);
ESM::RefNum getLastGeneratedRefNum() const { return mLastGeneratedRefnum; }
void setLastGeneratedRefNum(ESM::RefNum v) { mLastGeneratedRefnum = v; }
size_t getPtrIndexUpdateCounter() const { return mPtrIndexUpdateCounter; }
const std::unordered_map<ESM::RefNum, Ptr>& getAllPtrs() const { return mPtrIndex; }
Ptr getPtr(const ESM::RefNum& refNum) const;
Ptr getPtr(std::string_view name, CellStore& cellStore, bool searchInContainers = false);
///< \param searchInContainers Only affect loaded cells.
/// @note name must be lower case

@ -135,4 +135,22 @@ namespace ESM
}
namespace std
{
// Needed to use ESM::RefNum as a key in std::unordered_map
template <>
struct hash<ESM::RefNum>
{
size_t operator()(const ESM::RefNum& refNum) const
{
assert(sizeof(ESM::RefNum) == sizeof(size_t));
size_t s;
memcpy(&s, &refNum, sizeof(size_t));
return hash<size_t>()(s);
}
};
}
#endif

Loading…
Cancel
Save