mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-26 09:35:28 +00:00
Merge branch 'lua_esm4' into 'master'
Initial Lua bindings for ESM4 types See merge request OpenMW/openmw!2916
This commit is contained in:
commit
5212f4f623
@ -90,7 +90,7 @@ add_openmw_dir (mwphysics
|
||||
add_openmw_dir (mwclass
|
||||
classes activator creature npc weapon armor potion apparatus book clothing container door
|
||||
ingredient creaturelevlist itemlevlist light lockpick misc probe repair static actor bodypart
|
||||
light4
|
||||
esm4base light4
|
||||
)
|
||||
|
||||
add_openmw_dir (mwmechanics
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "static.hpp"
|
||||
#include "weapon.hpp"
|
||||
|
||||
#include "esm4base.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
void registerClasses()
|
||||
@ -51,18 +53,18 @@ namespace MWClass
|
||||
Static::registerSelf();
|
||||
BodyPart::registerSelf();
|
||||
|
||||
ESM4Static<ESM4::Activator>::registerSelf();
|
||||
ESM4Static<ESM4::Potion>::registerSelf();
|
||||
ESM4Static<ESM4::Ammunition>::registerSelf();
|
||||
ESM4Static<ESM4::Armor>::registerSelf();
|
||||
ESM4Static<ESM4::Book>::registerSelf();
|
||||
ESM4Static<ESM4::Clothing>::registerSelf();
|
||||
ESM4Static<ESM4::Container>::registerSelf();
|
||||
ESM4Static<ESM4::Door>::registerSelf();
|
||||
ESM4Static<ESM4::Ingredient>::registerSelf();
|
||||
ESM4Static<ESM4::MiscItem>::registerSelf();
|
||||
ESM4Static<ESM4::Static>::registerSelf();
|
||||
ESM4Static<ESM4::Weapon>::registerSelf();
|
||||
ESM4Named<ESM4::Activator>::registerSelf();
|
||||
ESM4Named<ESM4::Potion>::registerSelf();
|
||||
ESM4Named<ESM4::Ammunition>::registerSelf();
|
||||
ESM4Named<ESM4::Armor>::registerSelf();
|
||||
ESM4Named<ESM4::Book>::registerSelf();
|
||||
ESM4Named<ESM4::Clothing>::registerSelf();
|
||||
ESM4Named<ESM4::Container>::registerSelf();
|
||||
ESM4Named<ESM4::Door>::registerSelf();
|
||||
ESM4Named<ESM4::Ingredient>::registerSelf();
|
||||
ESM4Named<ESM4::MiscItem>::registerSelf();
|
||||
ESM4Static::registerSelf();
|
||||
ESM4Named<ESM4::Weapon>::registerSelf();
|
||||
ESM4Light::registerSelf();
|
||||
}
|
||||
}
|
||||
|
44
apps/openmw/mwclass/esm4base.cpp
Normal file
44
apps/openmw/mwclass/esm4base.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "esm4base.hpp"
|
||||
|
||||
#include <MyGUI_TextIterator.h>
|
||||
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
#include "../mwgui/ustring.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
#include "../mwrender/vismask.hpp"
|
||||
|
||||
#include "../mwphysics/physicssystem.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
#include "classmodel.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
void ESM4Impl::insertObjectRendering(
|
||||
const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface)
|
||||
{
|
||||
if (!model.empty())
|
||||
{
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static);
|
||||
}
|
||||
}
|
||||
|
||||
void ESM4Impl::insertObjectPhysics(
|
||||
const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics)
|
||||
{
|
||||
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World);
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo ESM4Impl::getToolTipInfo(std::string_view name, int count)
|
||||
{
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption
|
||||
= MyGUI::TextIterator::toTagsString(MWGui::toUString(name)) + MWGui::ToolTips::getCountString(count);
|
||||
return info;
|
||||
}
|
||||
}
|
112
apps/openmw/mwclass/esm4base.hpp
Normal file
112
apps/openmw/mwclass/esm4base.hpp
Normal file
@ -0,0 +1,112 @@
|
||||
#ifndef GAME_MWCLASS_ESM4BASE_H
|
||||
#define GAME_MWCLASS_ESM4BASE_H
|
||||
|
||||
#include <components/esm4/loadstat.hpp>
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/registeredclass.hpp"
|
||||
|
||||
#include "classmodel.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
|
||||
namespace ESM4Impl
|
||||
{
|
||||
void insertObjectRendering(
|
||||
const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface);
|
||||
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||
MWPhysics::PhysicsSystem& physics);
|
||||
MWGui::ToolTipInfo getToolTipInfo(std::string_view name, int count);
|
||||
}
|
||||
|
||||
// Base for all ESM4 Classes
|
||||
template <typename Record>
|
||||
class ESM4Base : public MWWorld::Class
|
||||
{
|
||||
|
||||
MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const override
|
||||
{
|
||||
const MWWorld::LiveCellRef<Record>* ref = ptr.get<Record>();
|
||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit ESM4Base(unsigned type)
|
||||
: MWWorld::Class(type)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
void insertObjectRendering(const MWWorld::Ptr& ptr, const std::string& model,
|
||||
MWRender::RenderingInterface& renderingInterface) const override
|
||||
{
|
||||
const MWWorld::LiveCellRef<Record>* ref = ptr.get<Record>();
|
||||
if (ref->mBase->mFlags & ESM4::Rec_Marker)
|
||||
return;
|
||||
ESM4Impl::insertObjectRendering(ptr, model, renderingInterface);
|
||||
}
|
||||
|
||||
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||
MWPhysics::PhysicsSystem& physics) const override
|
||||
{
|
||||
insertObjectPhysics(ptr, model, rotation, physics);
|
||||
}
|
||||
|
||||
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||
MWPhysics::PhysicsSystem& physics) const override
|
||||
{
|
||||
const MWWorld::LiveCellRef<Record>* ref = ptr.get<Record>();
|
||||
if (ref->mBase->mFlags & ESM4::Rec_Marker)
|
||||
return;
|
||||
ESM4Impl::insertObjectPhysics(ptr, model, rotation, physics);
|
||||
}
|
||||
|
||||
bool hasToolTip(const MWWorld::ConstPtr& ptr) const override { return false; }
|
||||
|
||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override { return ""; }
|
||||
|
||||
std::string getModel(const MWWorld::ConstPtr& ptr) const override { return getClassModel<Record>(ptr); }
|
||||
};
|
||||
|
||||
class ESM4Static final : public MWWorld::RegisteredClass<ESM4Static, ESM4Base<ESM4::Static>>
|
||||
{
|
||||
friend MWWorld::RegisteredClass<ESM4Static, ESM4Base<ESM4::Static>>;
|
||||
ESM4Static()
|
||||
: MWWorld::RegisteredClass<ESM4Static, ESM4Base<ESM4::Static>>(ESM4::Static::sRecordId)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// For records with `mFullName` that should be shown as a tooltip.
|
||||
// All objects with a tooltip can be activated (activation can be handled in Lua).
|
||||
template <typename Record>
|
||||
class ESM4Named : public MWWorld::RegisteredClass<ESM4Named<Record>, ESM4Base<Record>>
|
||||
{
|
||||
public:
|
||||
friend MWWorld::RegisteredClass<ESM4Named, ESM4Base<Record>>;
|
||||
|
||||
ESM4Named()
|
||||
: MWWorld::RegisteredClass<ESM4Named, ESM4Base<Record>>(Record::sRecordId)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
bool hasToolTip(const MWWorld::ConstPtr& ptr) const override { return true; }
|
||||
|
||||
MWGui::ToolTipInfo getToolTipInfo(const MWWorld::ConstPtr& ptr, int count) const override
|
||||
{
|
||||
return ESM4Impl::getToolTipInfo(ptr.get<Record>()->mBase->mFullName, count);
|
||||
}
|
||||
|
||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override
|
||||
{
|
||||
return ptr.get<Record>()->mBase->mFullName;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // GAME_MWCLASS_ESM4BASE_H
|
@ -12,7 +12,7 @@
|
||||
namespace MWClass
|
||||
{
|
||||
ESM4Light::ESM4Light()
|
||||
: MWWorld::RegisteredClass<ESM4Light>(ESM4::Light::sRecordId)
|
||||
: MWWorld::RegisteredClass<ESM4Light, ESM4Base<ESM4::Light>>(ESM4::Light::sRecordId)
|
||||
{
|
||||
}
|
||||
|
||||
@ -24,38 +24,4 @@ namespace MWClass
|
||||
// Insert even if model is empty, so that the light is added
|
||||
renderingInterface.getObjects().insertModel(ptr, model, !(ref->mBase->mData.flags & ESM4::Light::OffDefault));
|
||||
}
|
||||
|
||||
void ESM4Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||
MWPhysics::PhysicsSystem& physics) const
|
||||
{
|
||||
insertObjectPhysics(ptr, model, rotation, physics);
|
||||
}
|
||||
|
||||
void ESM4Light::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||
MWPhysics::PhysicsSystem& physics) const
|
||||
{
|
||||
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World);
|
||||
}
|
||||
|
||||
std::string ESM4Light::getModel(const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
return getClassModel<ESM4::Light>(ptr);
|
||||
}
|
||||
|
||||
std::string_view ESM4Light ::getName(const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ESM4Light::hasToolTip(const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MWWorld::Ptr ESM4Light::copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM4::Light>* ref = ptr.get<ESM4::Light>();
|
||||
|
||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,22 @@
|
||||
#ifndef OPENW_MWCLASS_LIGHT4
|
||||
#define OPENW_MWCLASS_LIGHT4
|
||||
|
||||
#include "../mwworld/registeredclass.hpp"
|
||||
|
||||
#include "esm4base.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
class ESM4Light : public MWWorld::RegisteredClass<ESM4Light>
|
||||
class ESM4Light : public MWWorld::RegisteredClass<ESM4Light, ESM4Base<ESM4::Light>>
|
||||
{
|
||||
friend MWWorld::RegisteredClass<ESM4Light>;
|
||||
friend MWWorld::RegisteredClass<ESM4Light, ESM4Base<ESM4::Light>>;
|
||||
|
||||
ESM4Light();
|
||||
|
||||
MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const override;
|
||||
|
||||
public:
|
||||
void insertObjectRendering(const MWWorld::Ptr& ptr, const std::string& model,
|
||||
MWRender::RenderingInterface& renderingInterface) const override;
|
||||
///< Add reference into a cell for rendering
|
||||
|
||||
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||
MWPhysics::PhysicsSystem& physics) const override;
|
||||
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||
MWPhysics::PhysicsSystem& physics) const override;
|
||||
|
||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override;
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
bool hasToolTip(const MWWorld::ConstPtr& ptr) const override;
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
std::string getModel(const MWWorld::ConstPtr& ptr) const override;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -64,20 +64,4 @@ namespace MWClass
|
||||
|
||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||
}
|
||||
|
||||
void ESM4StaticImpl::insertObjectRendering(
|
||||
const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface)
|
||||
{
|
||||
if (!model.empty())
|
||||
{
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static);
|
||||
}
|
||||
}
|
||||
|
||||
void ESM4StaticImpl::insertObjectPhysics(
|
||||
const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics)
|
||||
{
|
||||
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
#ifndef GAME_MWCLASS_STATIC_H
|
||||
#define GAME_MWCLASS_STATIC_H
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/registeredclass.hpp"
|
||||
|
||||
#include "classmodel.hpp"
|
||||
|
||||
#include "../mwgui/ustring.hpp"
|
||||
#include <MyGUI_TextIterator.h>
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
class Static : public MWWorld::RegisteredClass<Static>
|
||||
@ -34,64 +38,6 @@ namespace MWClass
|
||||
|
||||
std::string getModel(const MWWorld::ConstPtr& ptr) const override;
|
||||
};
|
||||
|
||||
namespace ESM4StaticImpl
|
||||
{
|
||||
void insertObjectRendering(
|
||||
const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface);
|
||||
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||
MWPhysics::PhysicsSystem& physics);
|
||||
}
|
||||
|
||||
// Templated because it is used as a dummy MWClass implementation for several ESM4 recors
|
||||
template <typename Record>
|
||||
class ESM4Static : public MWWorld::RegisteredClass<ESM4Static<Record>>
|
||||
{
|
||||
friend MWWorld::RegisteredClass<ESM4Static>;
|
||||
|
||||
ESM4Static()
|
||||
: MWWorld::RegisteredClass<ESM4Static>(Record::sRecordId)
|
||||
{
|
||||
}
|
||||
|
||||
MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const override
|
||||
{
|
||||
const MWWorld::LiveCellRef<Record>* ref = ptr.get<Record>();
|
||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||
}
|
||||
|
||||
public:
|
||||
void insertObjectRendering(const MWWorld::Ptr& ptr, const std::string& model,
|
||||
MWRender::RenderingInterface& renderingInterface) const override
|
||||
{
|
||||
const MWWorld::LiveCellRef<Record>* ref = ptr.get<Record>();
|
||||
if (ref->mBase->mFlags & ESM4::Rec_Marker)
|
||||
return;
|
||||
ESM4StaticImpl::insertObjectRendering(ptr, model, renderingInterface);
|
||||
}
|
||||
|
||||
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||
MWPhysics::PhysicsSystem& physics) const override
|
||||
{
|
||||
insertObjectPhysics(ptr, model, rotation, physics);
|
||||
}
|
||||
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
|
||||
MWPhysics::PhysicsSystem& physics) const override
|
||||
{
|
||||
const MWWorld::LiveCellRef<Record>* ref = ptr.get<Record>();
|
||||
if (ref->mBase->mFlags & ESM4::Rec_Marker)
|
||||
return;
|
||||
ESM4StaticImpl::insertObjectPhysics(ptr, model, rotation, physics);
|
||||
}
|
||||
|
||||
std::string_view getName(const MWWorld::ConstPtr& ptr) const override { return ""; }
|
||||
///< \return name or ID; can return an empty string.
|
||||
|
||||
bool hasToolTip(const MWWorld::ConstPtr& ptr) const override { return false; }
|
||||
///< @return true if this object has a tooltip when focused (default implementation: true)
|
||||
|
||||
std::string getModel(const MWWorld::ConstPtr& ptr) const override { return getClassModel<Record>(ptr); }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -158,6 +158,50 @@ namespace MWLua
|
||||
case ESM::REC_REPA:
|
||||
cell.mStore->template forEachType<ESM::Repair>(visitor);
|
||||
break;
|
||||
case ESM::REC_STAT:
|
||||
cell.mStore->template forEachType<ESM::Static>(visitor);
|
||||
break;
|
||||
|
||||
case ESM::REC_ACTI4:
|
||||
cell.mStore->template forEachType<ESM4::Activator>(visitor);
|
||||
break;
|
||||
case ESM::REC_AMMO4:
|
||||
cell.mStore->template forEachType<ESM4::Ammunition>(visitor);
|
||||
break;
|
||||
case ESM::REC_ARMO4:
|
||||
cell.mStore->template forEachType<ESM4::Armor>(visitor);
|
||||
break;
|
||||
case ESM::REC_BOOK4:
|
||||
cell.mStore->template forEachType<ESM4::Book>(visitor);
|
||||
break;
|
||||
case ESM::REC_CLOT4:
|
||||
cell.mStore->template forEachType<ESM4::Clothing>(visitor);
|
||||
break;
|
||||
case ESM::REC_CONT4:
|
||||
cell.mStore->template forEachType<ESM4::Container>(visitor);
|
||||
break;
|
||||
case ESM::REC_DOOR4:
|
||||
cell.mStore->template forEachType<ESM4::Door>(visitor);
|
||||
break;
|
||||
case ESM::REC_INGR4:
|
||||
cell.mStore->template forEachType<ESM4::Ingredient>(visitor);
|
||||
break;
|
||||
case ESM::REC_LIGH4:
|
||||
cell.mStore->template forEachType<ESM4::Light>(visitor);
|
||||
break;
|
||||
case ESM::REC_MISC4:
|
||||
cell.mStore->template forEachType<ESM4::MiscItem>(visitor);
|
||||
break;
|
||||
case ESM::REC_ALCH4:
|
||||
cell.mStore->template forEachType<ESM4::Potion>(visitor);
|
||||
break;
|
||||
case ESM::REC_STAT4:
|
||||
cell.mStore->template forEachType<ESM4::Static>(visitor);
|
||||
break;
|
||||
case ESM::REC_WEAP4:
|
||||
cell.mStore->template forEachType<ESM4::Weapon>(visitor);
|
||||
break;
|
||||
|
||||
default:
|
||||
ok = false;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "types.hpp"
|
||||
|
||||
#include <components/esm3/loaddoor.hpp>
|
||||
#include <components/esm4/loaddoor.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
|
||||
@ -15,6 +16,11 @@ namespace sol
|
||||
struct is_automagical<ESM::Door> : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_automagical<ESM4::Door> : std::false_type
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
@ -25,6 +31,11 @@ namespace MWLua
|
||||
return verifyType(ESM::REC_DOOR, o.ptr());
|
||||
}
|
||||
|
||||
static const MWWorld::Ptr& door4Ptr(const Object& o)
|
||||
{
|
||||
return verifyType(ESM::REC_DOOR4, o.ptr());
|
||||
}
|
||||
|
||||
void addDoorBindings(sol::table door, const Context& context)
|
||||
{
|
||||
door["isTeleport"] = [](const Object& o) { return doorPtr(o).getCellRef().getTeleport(); };
|
||||
@ -62,4 +73,34 @@ namespace MWLua
|
||||
[](const ESM::Door& rec) -> std::string { return rec.mCloseSound.serializeText(); });
|
||||
}
|
||||
|
||||
void addESM4DoorBindings(sol::table door, const Context& context)
|
||||
{
|
||||
door["isTeleport"] = [](const Object& o) { return door4Ptr(o).getCellRef().getTeleport(); };
|
||||
door["destPosition"]
|
||||
= [](const Object& o) -> osg::Vec3f { return door4Ptr(o).getCellRef().getDoorDest().asVec3(); };
|
||||
door["destRotation"]
|
||||
= [](const Object& o) -> osg::Vec3f { return door4Ptr(o).getCellRef().getDoorDest().asRotationVec3(); };
|
||||
door["destCell"] = [](sol::this_state lua, const Object& o) -> sol::object {
|
||||
const MWWorld::CellRef& cellRef = door4Ptr(o).getCellRef();
|
||||
if (!cellRef.getTeleport())
|
||||
return sol::nil;
|
||||
MWWorld::CellStore* cell = MWBase::Environment::get().getWorldModel()->getCell(cellRef.getDestCell());
|
||||
assert(cell);
|
||||
return o.getCell(lua, cell);
|
||||
};
|
||||
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
addRecordFunctionBinding<ESM4::Door>(door, context, "ESM4Door");
|
||||
|
||||
sol::usertype<ESM4::Door> record = context.mLua->sol().new_usertype<ESM4::Door>("ESM4_Door");
|
||||
record[sol::meta_function::to_string]
|
||||
= [](const ESM4::Door& rec) -> std::string { return "ESM4_Door[" + rec.mId.toDebugString() + "]"; };
|
||||
record["id"]
|
||||
= sol::readonly_property([](const ESM4::Door& rec) -> std::string { return rec.mId.serializeText(); });
|
||||
record["name"] = sol::readonly_property([](const ESM4::Door& rec) -> std::string { return rec.mFullName; });
|
||||
record["model"] = sol::readonly_property([vfs](const ESM4::Door& rec) -> std::string {
|
||||
return Misc::ResourceHelpers::correctMeshPath(rec.mModel, vfs);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,20 @@ namespace MWLua
|
||||
constexpr std::string_view Probe = "Probe";
|
||||
constexpr std::string_view Repair = "Repair";
|
||||
constexpr std::string_view Marker = "Marker";
|
||||
|
||||
constexpr std::string_view ESM4Activator = "ESM4Activator";
|
||||
constexpr std::string_view ESM4Ammunition = "ESM4Ammunition";
|
||||
constexpr std::string_view ESM4Armor = "ESM4Armor";
|
||||
constexpr std::string_view ESM4Book = "ESM4Book";
|
||||
constexpr std::string_view ESM4Clothing = "ESM4Clothing";
|
||||
constexpr std::string_view ESM4Container = "ESM4Container";
|
||||
constexpr std::string_view ESM4Door = "ESM4Door";
|
||||
constexpr std::string_view ESM4Ingredient = "ESM4Ingredient";
|
||||
constexpr std::string_view ESM4Light = "ESM4Light";
|
||||
constexpr std::string_view ESM4MiscItem = "ESM4Miscellaneous";
|
||||
constexpr std::string_view ESM4Potion = "ESM4Potion";
|
||||
constexpr std::string_view ESM4Static = "ESM4Static";
|
||||
constexpr std::string_view ESM4Weapon = "ESM4Weapon";
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -57,6 +71,20 @@ namespace MWLua
|
||||
{ ESM::REC_LOCK, ObjectTypeName::Lockpick },
|
||||
{ ESM::REC_PROB, ObjectTypeName::Probe },
|
||||
{ ESM::REC_REPA, ObjectTypeName::Repair },
|
||||
|
||||
{ ESM::REC_ACTI4, ObjectTypeName::ESM4Activator },
|
||||
{ ESM::REC_AMMO4, ObjectTypeName::ESM4Ammunition },
|
||||
{ ESM::REC_ARMO4, ObjectTypeName::ESM4Armor },
|
||||
{ ESM::REC_BOOK4, ObjectTypeName::ESM4Book },
|
||||
{ ESM::REC_CLOT4, ObjectTypeName::ESM4Clothing },
|
||||
{ ESM::REC_CONT4, ObjectTypeName::ESM4Container },
|
||||
{ ESM::REC_DOOR4, ObjectTypeName::ESM4Door },
|
||||
{ ESM::REC_INGR4, ObjectTypeName::ESM4Ingredient },
|
||||
{ ESM::REC_LIGH4, ObjectTypeName::ESM4Light },
|
||||
{ ESM::REC_MISC4, ObjectTypeName::ESM4MiscItem },
|
||||
{ ESM::REC_ALCH4, ObjectTypeName::ESM4Potion },
|
||||
{ ESM::REC_STAT4, ObjectTypeName::ESM4Static },
|
||||
{ ESM::REC_WEAP4, ObjectTypeName::ESM4Weapon },
|
||||
};
|
||||
}
|
||||
|
||||
@ -175,6 +203,20 @@ namespace MWLua
|
||||
addDoorBindings(addType(ObjectTypeName::Door, { ESM::REC_DOOR }), context);
|
||||
addStaticBindings(addType(ObjectTypeName::Static, { ESM::REC_STAT }), context);
|
||||
|
||||
addType(ObjectTypeName::ESM4Activator, { ESM::REC_ACTI4 });
|
||||
addType(ObjectTypeName::ESM4Ammunition, { ESM::REC_AMMO4 });
|
||||
addType(ObjectTypeName::ESM4Armor, { ESM::REC_ARMO4 });
|
||||
addType(ObjectTypeName::ESM4Book, { ESM::REC_BOOK4 });
|
||||
addType(ObjectTypeName::ESM4Clothing, { ESM::REC_CLOT4 });
|
||||
addType(ObjectTypeName::ESM4Container, { ESM::REC_CONT4 });
|
||||
addESM4DoorBindings(addType(ObjectTypeName::ESM4Door, { ESM::REC_DOOR4 }), context);
|
||||
addType(ObjectTypeName::ESM4Ingredient, { ESM::REC_INGR4 });
|
||||
addType(ObjectTypeName::ESM4Light, { ESM::REC_LIGH4 });
|
||||
addType(ObjectTypeName::ESM4MiscItem, { ESM::REC_MISC4 });
|
||||
addType(ObjectTypeName::ESM4Potion, { ESM::REC_ALCH4 });
|
||||
addType(ObjectTypeName::ESM4Static, { ESM::REC_STAT4 });
|
||||
addType(ObjectTypeName::ESM4Weapon, { ESM::REC_WEAP4 });
|
||||
|
||||
sol::table typeToPackage = getTypeToPackageTable(context.mLua->sol());
|
||||
sol::table packageToType = getPackageToTypeTable(context.mLua->sol());
|
||||
for (const auto& [type, name] : luaObjectTypeInfo)
|
||||
|
@ -63,8 +63,11 @@ namespace MWLua
|
||||
void addStaticBindings(sol::table stat, const Context& context);
|
||||
void addLightBindings(sol::table light, const Context& context);
|
||||
|
||||
void addESM4DoorBindings(sol::table door, const Context& context);
|
||||
|
||||
template <class T>
|
||||
void addRecordFunctionBinding(sol::table table, const Context& context)
|
||||
void addRecordFunctionBinding(
|
||||
sol::table table, const Context& context, const std::string& recordName = std::string(T::getRecordType()))
|
||||
{
|
||||
const MWWorld::Store<T>& store = MWBase::Environment::get().getWorld()->getStore().get<T>();
|
||||
|
||||
@ -75,9 +78,9 @@ namespace MWLua
|
||||
// Provide the interface of a read-only array.
|
||||
using StoreT = MWWorld::Store<T>;
|
||||
sol::state_view& lua = context.mLua->sol();
|
||||
sol::usertype<StoreT> storeT = lua.new_usertype<StoreT>(std::string(T::getRecordType()) + "WorldStore");
|
||||
storeT[sol::meta_function::to_string] = [](const StoreT& store) {
|
||||
return "{" + std::to_string(store.getSize()) + " " + std::string(T::getRecordType()) + " records}";
|
||||
sol::usertype<StoreT> storeT = lua.new_usertype<StoreT>(recordName + "WorldStore");
|
||||
storeT[sol::meta_function::to_string] = [recordName](const StoreT& store) {
|
||||
return "{" + std::to_string(store.getSize()) + " " + recordName + " records}";
|
||||
};
|
||||
storeT[sol::meta_function::length] = [](const StoreT& store) { return store.getSize(); };
|
||||
storeT[sol::meta_function::index] = [](const StoreT& store, size_t index) -> const T* {
|
||||
|
@ -3,10 +3,15 @@
|
||||
#include <cassert>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/esm/refid.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm3/objectstate.hpp>
|
||||
#include <components/esm4/loadrefr.hpp>
|
||||
|
||||
#include <apps/openmw/mwbase/environment.hpp>
|
||||
#include <apps/openmw/mwbase/world.hpp>
|
||||
#include <apps/openmw/mwworld/cellutils.hpp>
|
||||
#include <apps/openmw/mwworld/esmstore.hpp>
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
@ -25,7 +30,7 @@ namespace MWWorld
|
||||
const ESM::RefNum& CellRef::getRefNum() const
|
||||
{
|
||||
return std::visit(ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& ref) -> const ESM::RefNum& { return ref.mFormId; },
|
||||
[&](const ESM4::Reference& ref) -> const ESM::RefNum& { return ref.mId; },
|
||||
[&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
@ -34,7 +39,7 @@ namespace MWWorld
|
||||
const ESM::RefNum& CellRef::getOrAssignRefNum(ESM::RefNum& lastAssignedRefNum)
|
||||
{
|
||||
ESM::RefNum& refNum = std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& ref) -> ESM::RefNum& { return ref.mFormId; },
|
||||
[&](ESM4::Reference& ref) -> ESM::RefNum& { return ref.mId; },
|
||||
[&](ESM::CellRef& ref) -> ESM::RefNum& { return ref.mRefNum; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
@ -59,7 +64,7 @@ namespace MWWorld
|
||||
void CellRef::unsetRefNum()
|
||||
{
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& ref) { ref.mFormId = emptyRefNum; },
|
||||
[&](ESM4::Reference& ref) { ref.mId = emptyRefNum; },
|
||||
[&](ESM::CellRef& ref) { ref.mRefNum = emptyRefNum; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
@ -90,13 +95,18 @@ namespace MWWorld
|
||||
return ESM::RefId::esm3ExteriorCell(index.x(), index.y());
|
||||
}
|
||||
};
|
||||
auto esm4Visit = [&](const ESM4::Reference& ref) -> ESM::RefId {
|
||||
if (ref.mDoor.destDoor.isZeroOrUnset())
|
||||
return ESM::RefId::sEmpty;
|
||||
const ESM4::Reference* refDest
|
||||
= MWBase::Environment::get().getWorld()->getStore().get<ESM4::Reference>().searchStatic(
|
||||
ref.mDoor.destDoor);
|
||||
if (refDest)
|
||||
return refDest->mParent;
|
||||
return ESM::RefId::sEmpty;
|
||||
};
|
||||
|
||||
return std::visit(
|
||||
ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& ref) -> ESM::RefId { return ESM::RefId::sEmpty; },
|
||||
esm3Visit,
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
return std::visit(ESM::VisitOverload{ esm3Visit, esm4Visit }, mCellRef.mVariant);
|
||||
}
|
||||
|
||||
void CellRef::setScale(float scale)
|
||||
|
@ -55,7 +55,7 @@ namespace MWWorld
|
||||
struct Visitor
|
||||
{
|
||||
bool operator()(const ESM::CellRef& ref) { return ref.mTeleport; }
|
||||
bool operator()(const ESM4::Reference& ref) { return 0; }
|
||||
bool operator()(const ESM4::Reference& ref) { return !ref.mDoor.destDoor.isZeroOrUnset(); }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ namespace MWWorld
|
||||
auto recordType = static_cast<ESM4::RecordTypes>(reader.hdr().record.typeId);
|
||||
|
||||
ESM::RecNameInts esm4RecName = static_cast<ESM::RecNameInts>(ESM::esm4Recname(recordType));
|
||||
if constexpr (std::is_convertible_v<Store<T>*, DynamicStore*> && HasRecordId<T>::value)
|
||||
if constexpr (HasRecordId<T>::value)
|
||||
{
|
||||
if constexpr (ESM::isESM4Rec(T::sRecordId))
|
||||
{
|
||||
|
@ -16,8 +16,8 @@
|
||||
namespace
|
||||
{
|
||||
// TODO: Switch to C++23 to get a working version of std::unordered_map::erase
|
||||
template <class T>
|
||||
bool eraseFromMap(T& map, const ESM::RefId& value)
|
||||
template <class T, class Id>
|
||||
bool eraseFromMap(T& map, const Id& value)
|
||||
{
|
||||
auto it = map.find(value);
|
||||
if (it != map.end())
|
||||
@ -95,19 +95,19 @@ namespace MWWorld
|
||||
template class IndexedStore<ESM::MagicEffect>;
|
||||
template class IndexedStore<ESM::Skill>;
|
||||
|
||||
template <typename T>
|
||||
TypedDynamicStore<T>::TypedDynamicStore()
|
||||
template <class T, class Id>
|
||||
TypedDynamicStore<T, Id>::TypedDynamicStore()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TypedDynamicStore<T>::TypedDynamicStore(const TypedDynamicStore<T>& orig)
|
||||
template <class T, class Id>
|
||||
TypedDynamicStore<T, Id>::TypedDynamicStore(const TypedDynamicStore<T, Id>& orig)
|
||||
: mStatic(orig.mStatic)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TypedDynamicStore<T>::clearDynamic()
|
||||
template <class T, class Id>
|
||||
void TypedDynamicStore<T, Id>::clearDynamic()
|
||||
{
|
||||
// remove the dynamic part of mShared
|
||||
assert(mShared.size() >= mStatic.size());
|
||||
@ -115,8 +115,8 @@ namespace MWWorld
|
||||
mDynamic.clear();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T* TypedDynamicStore<T>::search(const ESM::RefId& id) const
|
||||
template <class T, class Id>
|
||||
const T* TypedDynamicStore<T, Id>::search(const Id& id) const
|
||||
{
|
||||
typename Dynamic::const_iterator dit = mDynamic.find(id);
|
||||
if (dit != mDynamic.end())
|
||||
@ -128,8 +128,8 @@ namespace MWWorld
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
const T* TypedDynamicStore<T>::searchStatic(const ESM::RefId& id) const
|
||||
template <class T, class Id>
|
||||
const T* TypedDynamicStore<T, Id>::searchStatic(const Id& id) const
|
||||
{
|
||||
typename Static::const_iterator it = mStatic.find(id);
|
||||
if (it != mStatic.end())
|
||||
@ -138,24 +138,29 @@ namespace MWWorld
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool TypedDynamicStore<T>::isDynamic(const ESM::RefId& id) const
|
||||
template <class T, class Id>
|
||||
bool TypedDynamicStore<T, Id>::isDynamic(const Id& id) const
|
||||
{
|
||||
typename Dynamic::const_iterator dit = mDynamic.find(id);
|
||||
return (dit != mDynamic.end());
|
||||
}
|
||||
template <typename T>
|
||||
const T* TypedDynamicStore<T>::searchRandom(const std::string_view prefix, Misc::Rng::Generator& prng) const
|
||||
template <class T, class Id>
|
||||
const T* TypedDynamicStore<T, Id>::searchRandom(const std::string_view prefix, Misc::Rng::Generator& prng) const
|
||||
{
|
||||
std::vector<const T*> results;
|
||||
std::copy_if(mShared.begin(), mShared.end(), std::back_inserter(results),
|
||||
[prefix](const T* item) { return item->mId.startsWith(prefix); });
|
||||
if (!results.empty())
|
||||
return results[Misc::Rng::rollDice(results.size(), prng)];
|
||||
return nullptr;
|
||||
if constexpr (std::is_same_v<Id, ESM::RefId>)
|
||||
{
|
||||
std::vector<const T*> results;
|
||||
std::copy_if(mShared.begin(), mShared.end(), std::back_inserter(results),
|
||||
[prefix](const T* item) { return item->mId.startsWith(prefix); });
|
||||
if (!results.empty())
|
||||
return results[Misc::Rng::rollDice(results.size(), prng)];
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Store<T>::searchRandom is supported only if Id is ESM::RefId");
|
||||
}
|
||||
template <typename T>
|
||||
const T* TypedDynamicStore<T>::find(const ESM::RefId& id) const
|
||||
template <class T, class Id>
|
||||
const T* TypedDynamicStore<T, Id>::find(const Id& id) const
|
||||
{
|
||||
const T* ptr = search(id);
|
||||
if (ptr == nullptr)
|
||||
@ -174,8 +179,8 @@ namespace MWWorld
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
template <typename T>
|
||||
RecordId TypedDynamicStore<T>::load(ESM::ESMReader& esm)
|
||||
template <class T, class Id>
|
||||
RecordId TypedDynamicStore<T, Id>::load(ESM::ESMReader& esm)
|
||||
{
|
||||
T record;
|
||||
bool isDeleted = false;
|
||||
@ -188,37 +193,41 @@ namespace MWWorld
|
||||
if (inserted.second)
|
||||
mShared.push_back(&inserted.first->second);
|
||||
|
||||
return RecordId(record.mId, isDeleted);
|
||||
if constexpr (std::is_same_v<Id, ESM::RefId>)
|
||||
return RecordId(record.mId, isDeleted);
|
||||
else
|
||||
return RecordId();
|
||||
}
|
||||
template <typename T>
|
||||
void TypedDynamicStore<T>::setUp()
|
||||
|
||||
template <class T, class Id>
|
||||
void TypedDynamicStore<T, Id>::setUp()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename TypedDynamicStore<T>::iterator TypedDynamicStore<T>::begin() const
|
||||
template <class T, class Id>
|
||||
typename TypedDynamicStore<T, Id>::iterator TypedDynamicStore<T, Id>::begin() const
|
||||
{
|
||||
return mShared.begin();
|
||||
}
|
||||
template <typename T>
|
||||
typename TypedDynamicStore<T>::iterator TypedDynamicStore<T>::end() const
|
||||
template <class T, class Id>
|
||||
typename TypedDynamicStore<T, Id>::iterator TypedDynamicStore<T, Id>::end() const
|
||||
{
|
||||
return mShared.end();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t TypedDynamicStore<T>::getSize() const
|
||||
template <class T, class Id>
|
||||
size_t TypedDynamicStore<T, Id>::getSize() const
|
||||
{
|
||||
return mShared.size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int TypedDynamicStore<T>::getDynamicSize() const
|
||||
template <class T, class Id>
|
||||
int TypedDynamicStore<T, Id>::getDynamicSize() const
|
||||
{
|
||||
return mDynamic.size();
|
||||
}
|
||||
template <typename T>
|
||||
void TypedDynamicStore<T>::listIdentifier(std::vector<ESM::RefId>& list) const
|
||||
template <class T, class Id>
|
||||
void TypedDynamicStore<T, Id>::listIdentifier(std::vector<Id>& list) const
|
||||
{
|
||||
list.reserve(list.size() + getSize());
|
||||
typename std::vector<T*>::const_iterator it = mShared.begin();
|
||||
@ -227,8 +236,8 @@ namespace MWWorld
|
||||
list.push_back((*it)->mId);
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
T* TypedDynamicStore<T>::insert(const T& item, bool overrideOnly)
|
||||
template <class T, class Id>
|
||||
T* TypedDynamicStore<T, Id>::insert(const T& item, bool overrideOnly)
|
||||
{
|
||||
if (overrideOnly)
|
||||
{
|
||||
@ -242,8 +251,8 @@ namespace MWWorld
|
||||
mShared.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
template <typename T>
|
||||
T* TypedDynamicStore<T>::insertStatic(const T& item)
|
||||
template <class T, class Id>
|
||||
T* TypedDynamicStore<T, Id>::insertStatic(const T& item)
|
||||
{
|
||||
std::pair<typename Static::iterator, bool> result = mStatic.insert_or_assign(item.mId, item);
|
||||
T* ptr = &result.first->second;
|
||||
@ -251,8 +260,8 @@ namespace MWWorld
|
||||
mShared.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
template <typename T>
|
||||
bool TypedDynamicStore<T>::eraseStatic(const ESM::RefId& id)
|
||||
template <class T, class Id>
|
||||
bool TypedDynamicStore<T, Id>::eraseStatic(const Id& id)
|
||||
{
|
||||
typename Static::iterator it = mStatic.find(id);
|
||||
|
||||
@ -277,8 +286,8 @@ namespace MWWorld
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool TypedDynamicStore<T>::erase(const ESM::RefId& id)
|
||||
template <class T, class Id>
|
||||
bool TypedDynamicStore<T, Id>::erase(const Id& id)
|
||||
{
|
||||
if (!eraseFromMap(mDynamic, id))
|
||||
return false;
|
||||
@ -292,13 +301,13 @@ namespace MWWorld
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <typename T>
|
||||
bool TypedDynamicStore<T>::erase(const T& item)
|
||||
template <class T, class Id>
|
||||
bool TypedDynamicStore<T, Id>::erase(const T& item)
|
||||
{
|
||||
return erase(item.mId);
|
||||
}
|
||||
template <typename T>
|
||||
void TypedDynamicStore<T>::write(ESM::ESMWriter& writer, Loading::Listener& progress) const
|
||||
template <class T, class Id>
|
||||
void TypedDynamicStore<T, Id>::write(ESM::ESMWriter& writer, Loading::Listener& progress) const
|
||||
{
|
||||
for (typename Dynamic::const_iterator iter(mDynamic.begin()); iter != mDynamic.end(); ++iter)
|
||||
{
|
||||
@ -310,8 +319,8 @@ namespace MWWorld
|
||||
}
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
RecordId TypedDynamicStore<T>::read(ESM::ESMReader& reader, bool overrideOnly)
|
||||
template <class T, class Id>
|
||||
RecordId TypedDynamicStore<T, Id>::read(ESM::ESMReader& reader, bool overrideOnly)
|
||||
{
|
||||
T record;
|
||||
bool isDeleted = false;
|
||||
@ -321,7 +330,10 @@ namespace MWWorld
|
||||
}
|
||||
insert(record, overrideOnly);
|
||||
|
||||
return RecordId(record.mId, isDeleted);
|
||||
if constexpr (std::is_same_v<Id, ESM::RefId>)
|
||||
return RecordId(record.mId, isDeleted);
|
||||
else
|
||||
return RecordId();
|
||||
}
|
||||
|
||||
// LandTexture
|
||||
@ -1232,6 +1244,6 @@ template class MWWorld::TypedDynamicStore<ESM4::Ingredient>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::MiscItem>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Static>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Light>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Reference>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Reference, ESM::FormId>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Cell>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Weapon>;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <components/esm3/loadland.hpp>
|
||||
#include <components/esm3/loadpgrd.hpp>
|
||||
#include <components/esm4/loadcell.hpp>
|
||||
#include <components/esm4/loadrefr.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
|
||||
@ -52,22 +53,23 @@ namespace MWWorld
|
||||
{
|
||||
}; // Empty interface to be parent of all store types
|
||||
|
||||
class DynamicStore : public StoreBase
|
||||
template <class Id>
|
||||
class DynamicStoreBase : public StoreBase
|
||||
{
|
||||
public:
|
||||
virtual ~DynamicStore() {}
|
||||
virtual ~DynamicStoreBase() {}
|
||||
|
||||
virtual void setUp() {}
|
||||
|
||||
/// List identifiers of records contained in this Store (case-smashed). No-op for Stores that don't use string
|
||||
/// IDs.
|
||||
virtual void listIdentifier(std::vector<ESM::RefId>& list) const {}
|
||||
virtual void listIdentifier(std::vector<Id>& list) const {}
|
||||
|
||||
virtual size_t getSize() const = 0;
|
||||
virtual int getDynamicSize() const { return 0; }
|
||||
virtual RecordId load(ESM::ESMReader& esm) = 0;
|
||||
|
||||
virtual bool eraseStatic(const ESM::RefId& id) { return false; }
|
||||
virtual bool eraseStatic(const Id& id) { return false; }
|
||||
virtual void clearDynamic() {}
|
||||
|
||||
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress) const {}
|
||||
@ -76,6 +78,8 @@ namespace MWWorld
|
||||
///< Read into dynamic storage
|
||||
};
|
||||
|
||||
using DynamicStore = DynamicStoreBase<ESM::RefId>;
|
||||
|
||||
template <class T>
|
||||
class IndexedStore : public StoreBase
|
||||
{
|
||||
@ -169,23 +173,23 @@ namespace MWWorld
|
||||
|
||||
class ESMStore;
|
||||
|
||||
template <class T>
|
||||
class TypedDynamicStore : public DynamicStore
|
||||
template <class T, class Id = ESM::RefId>
|
||||
class TypedDynamicStore : public DynamicStoreBase<Id>
|
||||
{
|
||||
typedef std::unordered_map<ESM::RefId, T> Static;
|
||||
typedef std::unordered_map<Id, T> Static;
|
||||
Static mStatic;
|
||||
/// @par mShared usually preserves the record order as it came from the content files (this
|
||||
/// is relevant for the spell autocalc code and selection order
|
||||
/// for heads/hairs in the character creation)
|
||||
std::vector<T*> mShared;
|
||||
typedef std::unordered_map<ESM::RefId, T> Dynamic;
|
||||
typedef std::unordered_map<Id, T> Dynamic;
|
||||
Dynamic mDynamic;
|
||||
|
||||
friend class ESMStore;
|
||||
|
||||
public:
|
||||
TypedDynamicStore();
|
||||
TypedDynamicStore(const TypedDynamicStore<T>& orig);
|
||||
TypedDynamicStore(const TypedDynamicStore<T, Id>& orig);
|
||||
|
||||
typedef SharedIterator<T> iterator;
|
||||
|
||||
@ -193,19 +197,19 @@ namespace MWWorld
|
||||
void clearDynamic() override;
|
||||
void setUp() override;
|
||||
|
||||
const T* search(const ESM::RefId& id) const;
|
||||
const T* searchStatic(const ESM::RefId& id) const;
|
||||
const T* search(const Id& id) const;
|
||||
const T* searchStatic(const Id& id) const;
|
||||
|
||||
/**
|
||||
* Does the record with this ID come from the dynamic store?
|
||||
*/
|
||||
bool isDynamic(const ESM::RefId& id) const;
|
||||
bool isDynamic(const Id& id) const;
|
||||
|
||||
/** Returns a random record that starts with the named ID, or nullptr if not found. */
|
||||
const T* searchRandom(const std::string_view prefix, Misc::Rng::Generator& prng) const;
|
||||
|
||||
// calls `search` and throws an exception if not found
|
||||
const T* find(const ESM::RefId& id) const;
|
||||
const T* find(const Id& id) const;
|
||||
|
||||
iterator begin() const;
|
||||
iterator end() const;
|
||||
@ -215,13 +219,13 @@ namespace MWWorld
|
||||
int getDynamicSize() const override;
|
||||
|
||||
/// @note The record identifiers are listed in the order that the records were defined by the content files.
|
||||
void listIdentifier(std::vector<ESM::RefId>& list) const override;
|
||||
void listIdentifier(std::vector<Id>& list) const override;
|
||||
|
||||
T* insert(const T& item, bool overrideOnly = false);
|
||||
T* insertStatic(const T& item);
|
||||
|
||||
bool eraseStatic(const ESM::RefId& id) override;
|
||||
bool erase(const ESM::RefId& id);
|
||||
bool eraseStatic(const Id& id) override;
|
||||
bool erase(const Id& id);
|
||||
bool erase(const T& item);
|
||||
|
||||
RecordId load(ESM::ESMReader& esm) override;
|
||||
@ -533,6 +537,11 @@ namespace MWWorld
|
||||
const MWDialogue::KeywordSearch<std::string, int>& getDialogIdKeywordSearch() const;
|
||||
};
|
||||
|
||||
template <>
|
||||
class Store<ESM4::Reference> : public TypedDynamicStore<ESM4::Reference, ESM::FormId>
|
||||
{
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
||||
#endif
|
||||
|
@ -18,8 +18,8 @@ namespace ESM
|
||||
bool hasContentFile() const { return mContentFile >= 0; }
|
||||
bool isSet() const { return mIndex != 0 || mContentFile != -1; }
|
||||
|
||||
// Used in ESM4 as a null reference
|
||||
bool isZero() const { return mIndex == 0 && mContentFile == 0; }
|
||||
// Zero is used in ESM4 as a null reference
|
||||
bool isZeroOrUnset() const { return mIndex == 0 && (mContentFile == 0 || mContentFile == -1); }
|
||||
|
||||
std::string toString() const;
|
||||
FormId32 toUint32() const;
|
||||
|
@ -213,7 +213,7 @@ void ESM4::Land::load(ESM4::Reader& reader)
|
||||
bool missing = false;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (mTextures[i].base.formId.isZero())
|
||||
if (mTextures[i].base.formId.isZeroOrUnset())
|
||||
{
|
||||
// std::cout << "ESM4::LAND " << ESM4::formIdToString(mFormId) << " missing base, quad " << i << std::endl;
|
||||
// std::cout << "layers " << mTextures[i].layers.size() << std::endl;
|
||||
|
@ -34,9 +34,8 @@
|
||||
|
||||
void ESM4::Reference::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.getFormId();
|
||||
reader.adjustFormId(mFormId);
|
||||
mId = ESM::RefId::formIdRefId(mFormId);
|
||||
mId = reader.hdr().record.getFormId();
|
||||
reader.adjustFormId(mId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
mParentFormId = reader.currCell(); // NOTE: only for persistent refs?
|
||||
mParent = ESM::RefId::formIdRefId(mParentFormId);
|
||||
|
@ -74,8 +74,7 @@ namespace ESM4
|
||||
|
||||
struct Reference
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
ESM::RefId mId;
|
||||
FormId mId; // from the header
|
||||
|
||||
FormId mParentFormId; // cell FormId (currently persistent refs only), from the loading sequence
|
||||
// NOTE: for exterior cells it will be the dummy cell FormId
|
||||
|
@ -1223,4 +1223,90 @@
|
||||
-- @field #string id Record id
|
||||
-- @field #string model VFS path to the model
|
||||
|
||||
--- Functions for @{#ESM4Activator} objects
|
||||
-- @field [parent=#types] #ESM4Activator ESM4Activator
|
||||
|
||||
--- Functions for @{#ESM4Ammunition} objects
|
||||
-- @field [parent=#types] #ESM4Ammunition ESM4Ammunition
|
||||
|
||||
--- Functions for @{#ESM4Armor} objects
|
||||
-- @field [parent=#types] #ESM4Armor ESM4Armor
|
||||
|
||||
--- Functions for @{#ESM4Book} objects
|
||||
-- @field [parent=#types] #ESM4Book ESM4Book
|
||||
|
||||
--- Functions for @{#ESM4Clothing} objects
|
||||
-- @field [parent=#types] #ESM4Clothing ESM4Clothing
|
||||
|
||||
--- Functions for @{#ESM4Door} objects
|
||||
-- @field [parent=#types] #ESM4Door ESM4Door
|
||||
|
||||
--- Functions for @{#ESM4Ingredient} objects
|
||||
-- @field [parent=#types] #ESM4Ingredient ESM4Ingredient
|
||||
|
||||
--- Functions for @{#ESM4Light} objects
|
||||
-- @field [parent=#types] #ESM4Light ESM4Light
|
||||
|
||||
--- Functions for @{#ESM4Miscellaneous} objects
|
||||
-- @field [parent=#types] #ESM4Miscellaneous ESM4Miscellaneous
|
||||
|
||||
--- Functions for @{#ESM4Potion} objects
|
||||
-- @field [parent=#types] #ESM4Potion ESM4Potion
|
||||
|
||||
--- Functions for @{#ESM4Static} objects
|
||||
-- @field [parent=#types] #ESM4Static ESM4Static
|
||||
|
||||
--- Functions for @{#ESM4Weapon} objects
|
||||
-- @field [parent=#types] #ESM4Weapon ESM4Weapon
|
||||
|
||||
---
|
||||
-- @type ESM4Door
|
||||
|
||||
---
|
||||
-- Whether the object is a ESM4Door.
|
||||
-- @function [parent=#ESM4Door] objectIsInstance
|
||||
-- @param openmw.core#GameObject object
|
||||
-- @return #boolean
|
||||
|
||||
---
|
||||
-- Whether the door is a teleport.
|
||||
-- @function [parent=#ESM4Door] isTeleport
|
||||
-- @param openmw.core#GameObject object
|
||||
-- @return #boolean
|
||||
|
||||
---
|
||||
-- Destination (only if a teleport door).
|
||||
-- @function [parent=#ESM4Door] destPosition
|
||||
-- @param openmw.core#GameObject object
|
||||
-- @return openmw.util#Vector3
|
||||
|
||||
---
|
||||
-- Destination rotation (only if a teleport door).
|
||||
-- @function [parent=#ESM4Door] destRotation
|
||||
-- @param openmw.core#GameObject object
|
||||
-- @return openmw.util#Vector3
|
||||
|
||||
---
|
||||
-- Destination cell (only if a teleport door).
|
||||
-- @function [parent=#ESM4Door] destCell
|
||||
-- @param openmw.core#GameObject object
|
||||
-- @return openmw.core#Cell
|
||||
|
||||
---
|
||||
-- Returns the read-only @{#ESM4DoorRecord} of a door
|
||||
-- @function [parent=#ESM4Door] record
|
||||
-- @param #any objectOrRecordId
|
||||
-- @return #ESM4DoorRecord
|
||||
|
||||
---
|
||||
-- Returns a read-only list of all @{#ESM4DoorRecord}s in the world database.
|
||||
-- @function [parent=#ESM4Door] records
|
||||
-- @return #list<#ESM4DoorRecord>
|
||||
|
||||
---
|
||||
-- @type ESM4DoorRecord
|
||||
-- @field #string id Record id
|
||||
-- @field #string name Human-readable name
|
||||
-- @field #string model VFS path to the model
|
||||
|
||||
return nil
|
||||
|
Loading…
x
Reference in New Issue
Block a user