mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-10 03:39:55 +00:00
Merge branch 'ptr3' into 'master'
Refactoring related to WorldModel See merge request OpenMW/openmw!2549
This commit is contained in:
commit
114daa5938
@ -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;
|
||||
|
@ -156,9 +156,6 @@ namespace MWBase
|
||||
|
||||
virtual bool isCellQuasiExterior() const = 0;
|
||||
|
||||
virtual osg::Vec2f getNorthVector(const MWWorld::CellStore* cell) = 0;
|
||||
///< get north vector for given interior cell
|
||||
|
||||
virtual void getDoorMarkers(MWWorld::CellStore* cell, std::vector<DoorMarker>& out) = 0;
|
||||
///< get a list of teleport door markers for a given cell, to be displayed on the local map
|
||||
|
||||
@ -263,9 +260,6 @@ namespace MWBase
|
||||
= 0;
|
||||
///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes
|
||||
|
||||
virtual const ESM::Cell* getExterior(const ESM::RefId& cellName) const = 0;
|
||||
///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
|
||||
|
||||
virtual MWWorld::Ptr getFacedObject() = 0;
|
||||
///< Return pointer to the object the player is looking at, if it is within activation range
|
||||
|
||||
|
@ -38,8 +38,10 @@ namespace MWLua
|
||||
return res.str();
|
||||
};
|
||||
|
||||
cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mName; });
|
||||
cellT["region"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mRegion; });
|
||||
cellT["name"]
|
||||
= sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mName.getRefIdString(); });
|
||||
cellT["region"]
|
||||
= sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mRegion.getRefIdString(); });
|
||||
cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); });
|
||||
cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); });
|
||||
cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); });
|
||||
@ -57,11 +59,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(); });
|
||||
|
||||
|
@ -78,20 +78,11 @@ namespace MWLua
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
WorldView* worldView = context.mWorldView;
|
||||
addTimeBindings(api, context, true);
|
||||
api["getCellByName"] = [worldView = context.mWorldView](const std::string& name) -> sol::optional<GCell> {
|
||||
MWWorld::CellStore* cell = worldView->findNamedCell(ESM::RefId::stringRefId(name));
|
||||
if (cell)
|
||||
return GCell{ cell };
|
||||
else
|
||||
return sol::nullopt;
|
||||
};
|
||||
api["getExteriorCell"] = [worldView = context.mWorldView](int x, int y) -> sol::optional<GCell> {
|
||||
MWWorld::CellStore* cell = worldView->findExteriorCell(x, y);
|
||||
if (cell)
|
||||
return GCell{ cell };
|
||||
else
|
||||
return sol::nullopt;
|
||||
api["getCellByName"] = [](std::string_view name) {
|
||||
return GCell{ MWBase::Environment::get().getWorldModel()->getCell(ESM::RefId::stringRefId(name)) };
|
||||
};
|
||||
api["getExteriorCell"]
|
||||
= [](int x, int y) { return GCell{ MWBase::Environment::get().getWorldModel()->getExterior(x, y) }; };
|
||||
api["activeActors"] = GObjectList{ worldView->getActorsInScene() };
|
||||
// TODO: add world.placeNewObject(recordId, cell, pos, [rot])
|
||||
return LuaUtil::makeReadOnly(api);
|
||||
|
@ -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);
|
||||
@ -277,11 +276,11 @@ namespace MWLua
|
||||
mInGameConsoleMessages.clear();
|
||||
|
||||
for (std::unique_ptr<Action>& action : mActionQueue)
|
||||
action->safeApply(mWorldView);
|
||||
action->safeApply();
|
||||
mActionQueue.clear();
|
||||
|
||||
if (mTeleportPlayerAction)
|
||||
mTeleportPlayerAction->safeApply(mWorldView);
|
||||
mTeleportPlayerAction->safeApply();
|
||||
mTeleportPlayerAction.reset();
|
||||
}
|
||||
|
||||
@ -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);
|
||||
@ -577,11 +564,11 @@ namespace MWLua
|
||||
mCallerTraceback = state->debugTraceback();
|
||||
}
|
||||
|
||||
void LuaManager::Action::safeApply(WorldView& w) const
|
||||
void LuaManager::Action::safeApply() const
|
||||
{
|
||||
try
|
||||
{
|
||||
apply(w);
|
||||
apply();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
@ -606,7 +593,7 @@ namespace MWLua
|
||||
{
|
||||
}
|
||||
|
||||
void apply(WorldView&) const override { mFn(); }
|
||||
void apply() const override { mFn(); }
|
||||
std::string toString() const override { return "FunctionAction " + mName; }
|
||||
|
||||
private:
|
||||
|
@ -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;
|
||||
@ -75,8 +73,8 @@ namespace MWLua
|
||||
Action(LuaUtil::LuaState* state);
|
||||
virtual ~Action() {}
|
||||
|
||||
void safeApply(WorldView&) const;
|
||||
virtual void apply(WorldView&) const = 0;
|
||||
void safeApply() const;
|
||||
virtual void apply() const = 0;
|
||||
virtual std::string toString() const = 0;
|
||||
|
||||
private:
|
||||
|
@ -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 });
|
||||
|
@ -61,14 +61,12 @@ namespace MWLua
|
||||
{
|
||||
}
|
||||
|
||||
void apply(WorldView& worldView) const override
|
||||
void apply() const override
|
||||
{
|
||||
MWWorld::CellStore* cell = worldView.findCell(mCell, mPos);
|
||||
if (!cell)
|
||||
throw std::runtime_error(std::string("cell not found: '") + mCell.getRefIdString() + "'");
|
||||
|
||||
MWWorld::WorldModel& wm = *MWBase::Environment::get().getWorldModel();
|
||||
MWWorld::CellStore* cell = wm.getCellByPosition(mPos, mCell);
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
MWWorld::Ptr obj = worldView.getObjectRegistry()->getPtr(mObject, false);
|
||||
MWWorld::Ptr obj = wm.getPtr(mObject);
|
||||
const MWWorld::Class& cls = obj.getClass();
|
||||
bool isPlayer = obj == world->getPlayerPtr();
|
||||
if (cls.isActor())
|
||||
@ -111,12 +109,12 @@ namespace MWLua
|
||||
{
|
||||
}
|
||||
|
||||
void apply(WorldView& worldView) const override
|
||||
void apply() 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 +145,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");
|
||||
};
|
||||
@ -167,7 +164,7 @@ namespace MWLua
|
||||
{
|
||||
objectT["isValid"] = [](const ObjectT& o) { return o.isValid(); };
|
||||
objectT["recordId"] = sol::readonly_property(
|
||||
[](const ObjectT& o) -> ESM::RefId { return o.ptr().getCellRef().getRefId(); });
|
||||
[](const ObjectT& o) -> std::string { return o.ptr().getCellRef().getRefId().getRefIdString(); });
|
||||
objectT["cell"] = sol::readonly_property([](const ObjectT& o) -> sol::optional<Cell<ObjectT>> {
|
||||
const MWWorld::Ptr& ptr = o.ptr();
|
||||
if (ptr.isInCell())
|
||||
@ -265,7 +262,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,16 +326,16 @@ 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 };
|
||||
};
|
||||
|
||||
inventoryT["countOf"] = [](const InventoryT& inventory, const ESM::RefId& recordId) {
|
||||
inventoryT["countOf"] = [](const InventoryT& inventory, const std::string& recordId) {
|
||||
const MWWorld::Ptr& ptr = inventory.mObj.ptr();
|
||||
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore(ptr);
|
||||
return store.count(recordId);
|
||||
return store.count(ESM::RefId::stringRefId(recordId));
|
||||
};
|
||||
|
||||
if constexpr (std::is_same_v<ObjectT, GObject>)
|
||||
|
@ -20,7 +20,7 @@ namespace
|
||||
{
|
||||
}
|
||||
|
||||
void apply(MWLua::WorldView&) const override
|
||||
void apply() const override
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->getPostProcessor()->setUniform(mShader, mName, mValue);
|
||||
}
|
||||
|
@ -97,9 +97,9 @@ namespace MWLua
|
||||
{
|
||||
}
|
||||
|
||||
void apply(WorldView& worldView) const override
|
||||
void apply() const override
|
||||
{
|
||||
LObject obj(mId, worldView.getObjectRegistry());
|
||||
LObject obj(mId);
|
||||
LocalScripts* scripts = obj.ptr().getRefData().getLuaScripts();
|
||||
if (scripts)
|
||||
scripts->applyStatsCache();
|
||||
|
@ -29,20 +29,20 @@ namespace MWLua
|
||||
{
|
||||
}
|
||||
|
||||
void apply(WorldView& worldView) const override
|
||||
void apply() 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);
|
||||
|
@ -32,15 +32,14 @@ namespace MWLua
|
||||
= [](const Object& o) -> osg::Vec3f { return doorPtr(o).getCellRef().getDoorDest().asVec3(); };
|
||||
door["destRotation"]
|
||||
= [](const Object& o) -> osg::Vec3f { return doorPtr(o).getCellRef().getDoorDest().asRotationVec3(); };
|
||||
door["destCell"] = [worldView = context.mWorldView](sol::this_state lua, const Object& o) -> sol::object {
|
||||
door["destCell"] = [](sol::this_state lua, const Object& o) -> sol::object {
|
||||
const MWWorld::CellRef& cellRef = doorPtr(o).getCellRef();
|
||||
if (!cellRef.getTeleport())
|
||||
return sol::nil;
|
||||
MWWorld::CellStore* cell = worldView->findCell(cellRef.getDestCell(), cellRef.getDoorDest().asVec3());
|
||||
if (cell)
|
||||
return o.getCell(lua, cell);
|
||||
else
|
||||
return sol::nil;
|
||||
MWWorld::CellStore* cell = MWBase::Environment::get().getWorldModel()->getCellByPosition(
|
||||
cellRef.getDoorDest().asVec3(), cellRef.getDestCell());
|
||||
assert(cell);
|
||||
return o.getCell(lua, cell);
|
||||
};
|
||||
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
@ -35,7 +35,7 @@ namespace MWLua
|
||||
{
|
||||
}
|
||||
|
||||
void apply(WorldView&) const override
|
||||
void apply() const override
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -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()
|
||||
@ -122,35 +120,4 @@ namespace MWLua
|
||||
group.mSet.erase(getId(ptr));
|
||||
group.mChanged = true;
|
||||
}
|
||||
|
||||
// TODO: If Lua scripts will use several threads at the same time, then `find*Cell` functions should have critical
|
||||
// sections.
|
||||
MWWorld::CellStore* WorldView::findCell(const ESM::RefId& name, osg::Vec3f position)
|
||||
{
|
||||
MWWorld::WorldModel* worldModel = MWBase::Environment::get().getWorldModel();
|
||||
bool exterior = name.empty() || MWBase::Environment::get().getWorld()->getExterior(name);
|
||||
if (exterior)
|
||||
{
|
||||
const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(position.x(), position.y());
|
||||
return worldModel->getExterior(cellIndex.x(), cellIndex.y());
|
||||
}
|
||||
else
|
||||
return worldModel->getInterior(name);
|
||||
}
|
||||
|
||||
MWWorld::CellStore* WorldView::findNamedCell(const ESM::RefId& name)
|
||||
{
|
||||
MWWorld::WorldModel* worldModel = MWBase::Environment::get().getWorldModel();
|
||||
const ESM::Cell* esmCell = MWBase::Environment::get().getWorld()->getExterior(name);
|
||||
if (esmCell)
|
||||
return worldModel->getExterior(esmCell->getGridX(), esmCell->getGridY());
|
||||
else
|
||||
return worldModel->getInterior(name);
|
||||
}
|
||||
|
||||
MWWorld::CellStore* WorldView::findExteriorCell(int x, int y)
|
||||
{
|
||||
return MWBase::Environment::get().getWorldModel()->getExterior(x, y);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,21 +47,9 @@ 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);
|
||||
|
||||
// Returns list of objects that meets the `query` criteria.
|
||||
// If onlyActive = true, then search only among the objects that are currently in the scene.
|
||||
// TODO: ObjectIdList selectObjects(const Queries::Query& query, bool onlyActive);
|
||||
|
||||
MWWorld::CellStore* findCell(const ESM::RefId& name, osg::Vec3f position);
|
||||
MWWorld::CellStore* findNamedCell(const ESM::RefId& name);
|
||||
MWWorld::CellStore* findExteriorCell(int x, int y);
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
void save(ESM::ESMWriter& esm) const;
|
||||
|
||||
@ -79,7 +71,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;
|
||||
|
@ -281,6 +281,19 @@ namespace MWRender
|
||||
}
|
||||
}
|
||||
|
||||
static osg::Vec2f getNorthVector(const MWWorld::CellStore* cell)
|
||||
{
|
||||
MWWorld::ConstPtr northmarker = cell->searchConst(ESM::RefId::stringRefId("northmarker"));
|
||||
|
||||
if (northmarker.isEmpty())
|
||||
return osg::Vec2f(0, 1);
|
||||
|
||||
osg::Quat orient(-northmarker.getRefData().getPosition().rot[2], osg::Vec3f(0, 0, 1));
|
||||
osg::Vec3f dir = orient * osg::Vec3f(0, 1, 0);
|
||||
osg::Vec2f d(dir.x(), dir.y());
|
||||
return d;
|
||||
}
|
||||
|
||||
void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell)
|
||||
{
|
||||
osg::ComputeBoundsVisitor computeBoundsVisitor;
|
||||
@ -299,7 +312,7 @@ namespace MWRender
|
||||
mBounds = bounds;
|
||||
|
||||
// Get the cell's NorthMarker rotation. This is used to rotate the entire map.
|
||||
osg::Vec2f north = MWBase::Environment::get().getWorld()->getNorthVector(cell);
|
||||
osg::Vec2f north = getNorthVector(cell);
|
||||
|
||||
mAngle = std::atan2(north.x(), north.y());
|
||||
|
||||
|
@ -399,24 +399,20 @@ namespace MWScript
|
||||
MWWorld::CellStore* store = nullptr;
|
||||
try
|
||||
{
|
||||
store = worldModel->getInterior(cellID);
|
||||
store = worldModel->getCell(cellID);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// cell not found, move to exterior instead if moving the player (vanilla PositionCell
|
||||
// compatibility)
|
||||
const ESM::Cell* cell = world->getExterior(cellID);
|
||||
if (!cell)
|
||||
{
|
||||
std::string error
|
||||
= "Warning: PositionCell: unknown interior cell (" + cellID.getRefIdString() + ")";
|
||||
if (isPlayer)
|
||||
error += ", moving to exterior instead";
|
||||
runtime.getContext().report(error);
|
||||
Log(Debug::Warning) << error;
|
||||
if (!isPlayer)
|
||||
return;
|
||||
}
|
||||
std::string error
|
||||
= "Warning: PositionCell: unknown interior cell (" + cellID.getRefIdString() + ")";
|
||||
if (isPlayer)
|
||||
error += ", moving to exterior instead";
|
||||
runtime.getContext().report(error);
|
||||
Log(Debug::Warning) << error;
|
||||
if (!isPlayer)
|
||||
return;
|
||||
const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y);
|
||||
store = worldModel->getExterior(cellIndex.x(), cellIndex.y());
|
||||
}
|
||||
@ -519,18 +515,12 @@ namespace MWScript
|
||||
MWWorld::CellStore* store = nullptr;
|
||||
try
|
||||
{
|
||||
store = MWBase::Environment::get().getWorldModel()->getInterior(cellID);
|
||||
store = MWBase::Environment::get().getWorldModel()->getCell(cellID);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID);
|
||||
const osg::Vec2i cellIndex = MWWorld::positionToCellIndex(x, y);
|
||||
store = MWBase::Environment::get().getWorldModel()->getExterior(cellIndex.x(), cellIndex.y());
|
||||
if (!cell)
|
||||
{
|
||||
runtime.getContext().report("unknown cell (" + cellID.getRefIdString() + ")");
|
||||
Log(Debug::Error) << "Error: unknown cell (" << cellID << ")";
|
||||
}
|
||||
runtime.getContext().report("unknown cell (" + cellID.getRefIdString() + ")");
|
||||
Log(Debug::Error) << "Error: unknown cell (" << cellID << ")";
|
||||
}
|
||||
if (store)
|
||||
{
|
||||
|
@ -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;
|
||||
@ -565,34 +564,6 @@ namespace MWWorld
|
||||
mRandomSeed = seed;
|
||||
}
|
||||
|
||||
const ESM::Cell* World::getExterior(const ESM::RefId& cellName) const
|
||||
{
|
||||
// first try named cells
|
||||
const ESM::Cell* cell = mStore.get<ESM::Cell>().searchExtByName(cellName);
|
||||
if (cell)
|
||||
return cell;
|
||||
// treat "Wilderness" like an empty string
|
||||
static const ESM::RefId defaultName
|
||||
= ESM::RefId::stringRefId(mStore.get<ESM::GameSetting>().find("sDefaultCellname")->mValue.getString());
|
||||
if (cellName == defaultName)
|
||||
{
|
||||
cell = mStore.get<ESM::Cell>().searchExtByName(ESM::RefId::sEmpty);
|
||||
if (cell)
|
||||
return cell;
|
||||
}
|
||||
|
||||
// didn't work -> now check for regions
|
||||
for (const ESM::Region& region : mStore.get<ESM::Region>())
|
||||
{
|
||||
if (cellName == ESM::RefId::stringRefId(region.mName))
|
||||
{
|
||||
return mStore.get<ESM::Cell>().searchExtByRegion(region.mId);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void World::useDeathCamera()
|
||||
{
|
||||
mRendering->getCamera()->setMode(MWRender::Camera::Mode::ThirdPerson);
|
||||
@ -816,7 +787,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 +839,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())
|
||||
@ -2051,19 +2022,6 @@ namespace MWWorld
|
||||
mWeatherManager->modRegion(regionid, chances);
|
||||
}
|
||||
|
||||
osg::Vec2f World::getNorthVector(const CellStore* cell)
|
||||
{
|
||||
MWWorld::ConstPtr northmarker = cell->searchConst(ESM::RefId::stringRefId("northmarker"));
|
||||
|
||||
if (northmarker.isEmpty())
|
||||
return osg::Vec2f(0, 1);
|
||||
|
||||
osg::Quat orient(-northmarker.getRefData().getPosition().rot[2], osg::Vec3f(0, 0, 1));
|
||||
osg::Vec3f dir = orient * osg::Vec3f(0, 1, 0);
|
||||
osg::Vec2f d(dir.x(), dir.y());
|
||||
return d;
|
||||
}
|
||||
|
||||
struct GetDoorMarkerVisitor
|
||||
{
|
||||
std::vector<World::DoorMarker>& mOut;
|
||||
@ -2860,7 +2818,17 @@ namespace MWWorld
|
||||
{
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
const std::string& name = nameId.getRefIdString();
|
||||
const ESM::Cell* ext = getExterior(nameId);
|
||||
|
||||
const ESM::Cell* ext = nullptr;
|
||||
try
|
||||
{
|
||||
ext = mWorldModel.getCell(nameId)->getCell();
|
||||
if (!ext->isExterior())
|
||||
return false;
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
}
|
||||
if (!ext)
|
||||
{
|
||||
size_t comma = name.find(',');
|
||||
@ -3402,7 +3370,7 @@ namespace MWWorld
|
||||
|
||||
void World::rest(double hours)
|
||||
{
|
||||
mWorldModel.rest(hours);
|
||||
mWorldModel.forEachLoadedCellStore([hours](CellStore& store) { store.rest(hours); });
|
||||
}
|
||||
|
||||
void World::rechargeItems(double duration, bool activeOnly)
|
||||
@ -3418,7 +3386,7 @@ namespace MWWorld
|
||||
}
|
||||
}
|
||||
else
|
||||
mWorldModel.recharge(duration);
|
||||
mWorldModel.forEachLoadedCellStore([duration](CellStore& store) { store.recharge(duration); });
|
||||
}
|
||||
|
||||
void World::teleportToClosestMarker(const MWWorld::Ptr& ptr, const ESM::RefId& id)
|
||||
|
@ -246,9 +246,6 @@ namespace MWWorld
|
||||
|
||||
bool isCellQuasiExterior() const override;
|
||||
|
||||
osg::Vec2f getNorthVector(const CellStore* cell) override;
|
||||
///< get north vector for given interior cell
|
||||
|
||||
void getDoorMarkers(MWWorld::CellStore* cell, std::vector<DoorMarker>& out) override;
|
||||
///< get a list of teleport door markers for a given cell, to be displayed on the local map
|
||||
|
||||
@ -358,9 +355,6 @@ namespace MWWorld
|
||||
bool changeEvent = true) override;
|
||||
///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes
|
||||
|
||||
const ESM::Cell* getExterior(const ESM::RefId& cellName) const override;
|
||||
///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
|
||||
|
||||
MWWorld::Ptr getFacedObject() override;
|
||||
///< Return pointer to the object the player is looking at, if it is within activation range
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <components/esm3/cellstate.hpp>
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <components/esm3/esmwriter.hpp>
|
||||
#include <components/esm3/loadregn.hpp>
|
||||
#include <components/loadinglistener/loadinglistener.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
@ -13,6 +14,7 @@
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "cellstore.hpp"
|
||||
#include "cellutils.hpp"
|
||||
#include "esmstore.hpp"
|
||||
|
||||
namespace
|
||||
@ -85,12 +87,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);
|
||||
@ -188,32 +214,6 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(const ESM::RefId& name)
|
||||
return &result->second;
|
||||
}
|
||||
|
||||
void MWWorld::WorldModel::rest(double hours)
|
||||
{
|
||||
for (auto& interior : mInteriors)
|
||||
{
|
||||
interior.second.rest(hours);
|
||||
}
|
||||
|
||||
for (auto& exterior : mExteriors)
|
||||
{
|
||||
exterior.second.rest(hours);
|
||||
}
|
||||
}
|
||||
|
||||
void MWWorld::WorldModel::recharge(float duration)
|
||||
{
|
||||
for (auto& interior : mInteriors)
|
||||
{
|
||||
interior.second.recharge(duration);
|
||||
}
|
||||
|
||||
for (auto& exterior : mExteriors)
|
||||
{
|
||||
exterior.second.recharge(duration);
|
||||
}
|
||||
}
|
||||
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::CellId& id)
|
||||
{
|
||||
if (id.mPaged)
|
||||
@ -222,6 +222,57 @@ MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::CellId& id)
|
||||
return getInterior(id.mWorldspace);
|
||||
}
|
||||
|
||||
const ESM::Cell* MWWorld::WorldModel::getESMCellByName(const ESM::RefId& name)
|
||||
{
|
||||
const ESM::Cell* cell = mStore.get<ESM::Cell>().search(name); // first try interiors
|
||||
if (!cell) // try named exteriors
|
||||
cell = mStore.get<ESM::Cell>().searchExtByName(name);
|
||||
if (!cell)
|
||||
{
|
||||
// treat "Wilderness" like an empty string
|
||||
static const ESM::RefId defaultName
|
||||
= ESM::RefId::stringRefId(mStore.get<ESM::GameSetting>().find("sDefaultCellname")->mValue.getString());
|
||||
if (name == defaultName)
|
||||
cell = mStore.get<ESM::Cell>().searchExtByName(ESM::RefId::sEmpty);
|
||||
}
|
||||
if (!cell)
|
||||
{
|
||||
// now check for regions
|
||||
for (const ESM::Region& region : mStore.get<ESM::Region>())
|
||||
{
|
||||
if (name == ESM::RefId::stringRefId(region.mName))
|
||||
{
|
||||
cell = mStore.get<ESM::Cell>().searchExtByRegion(region.mId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!cell)
|
||||
throw std::runtime_error(std::string("Can't find cell with name ") + name.getRefIdString());
|
||||
return cell;
|
||||
}
|
||||
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::RefId& name)
|
||||
{
|
||||
const ESM::Cell* cell = getESMCellByName(name);
|
||||
if (cell->isExterior())
|
||||
return getExterior(cell->getGridX(), cell->getGridY());
|
||||
else
|
||||
return getInterior(name);
|
||||
}
|
||||
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getCellByPosition(
|
||||
const osg::Vec3f& pos, const ESM::RefId& cellNameInSameWorldSpace)
|
||||
{
|
||||
if (cellNameInSameWorldSpace.empty() || getESMCellByName(cellNameInSameWorldSpace)->isExterior())
|
||||
{
|
||||
const osg::Vec2i cellIndex = positionToCellIndex(pos.x(), pos.y());
|
||||
return getExterior(cellIndex.x(), cellIndex.y());
|
||||
}
|
||||
else
|
||||
return getInterior(cellNameInSameWorldSpace);
|
||||
}
|
||||
|
||||
MWWorld::Ptr MWWorld::WorldModel::getPtr(const ESM::RefId& name, CellStore& cell, bool searchInContainers)
|
||||
{
|
||||
if (cell.getState() == CellStore::State_Unloaded)
|
||||
|
@ -4,7 +4,9 @@
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "cellstore.hpp"
|
||||
#include "ptr.hpp"
|
||||
|
||||
namespace ESM
|
||||
@ -40,6 +42,7 @@ namespace MWWorld
|
||||
WorldModel(const WorldModel&);
|
||||
WorldModel& operator=(const WorldModel&);
|
||||
|
||||
const ESM::Cell* getESMCellByName(const ESM::RefId& name);
|
||||
CellStore* getCellStore(const ESM::Cell* cell);
|
||||
|
||||
Ptr getPtrAndCache(const ESM::RefId& name, CellStore& cellStore);
|
||||
@ -48,17 +51,34 @@ 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();
|
||||
|
||||
explicit WorldModel(const MWWorld::ESMStore& store, ESM::ReadersCache& reader);
|
||||
|
||||
CellStore* getExterior(int x, int y);
|
||||
|
||||
CellStore* getInterior(const ESM::RefId& name);
|
||||
|
||||
CellStore* getCell(const ESM::RefId& name); // interior or named exterior
|
||||
CellStore* getCell(const ESM::CellId& id);
|
||||
|
||||
// If cellNameInSameWorldSpace is an interior - returns this interior.
|
||||
// Otherwise returns exterior cell for given position in the same world space.
|
||||
// At the moment multiple world spaces are not supported, so all exteriors are in one world space.
|
||||
CellStore* getCellByPosition(const osg::Vec3f& pos, const ESM::RefId& cellNameInSameWorldSpace);
|
||||
|
||||
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(const ESM::RefId& name, CellStore& cellStore, bool searchInContainers = false);
|
||||
///< \param searchInContainers Only affect loaded cells.
|
||||
/// @note name must be lower case
|
||||
@ -68,8 +88,14 @@ namespace MWWorld
|
||||
|
||||
Ptr getPtr(const ESM::RefId& id, const ESM::RefNum& refNum);
|
||||
|
||||
void rest(double hours);
|
||||
void recharge(float duration);
|
||||
template <typename Fn>
|
||||
void forEachLoadedCellStore(Fn&& fn)
|
||||
{
|
||||
for (auto& [_, store] : mInteriors)
|
||||
fn(store);
|
||||
for (auto& [_, store] : mExteriors)
|
||||
fn(store);
|
||||
}
|
||||
|
||||
/// Get all Ptrs referencing \a name in exterior cells
|
||||
/// @note Due to the current implementation of getPtr this only supports one Ptr per cell.
|
||||
|
@ -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…
x
Reference in New Issue
Block a user