mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-06 18:40:23 +00:00
Add ESM records that are needed to store Lua scripts configuration;
Use ptr.getType() (i.e. esm record names) instead of typeid(ptr.getClass()) in apps/openmw/mwlua.
This commit is contained in:
parent
3006c496fc
commit
6aab246879
@ -1,19 +1,6 @@
|
||||
#include "object.hpp"
|
||||
|
||||
#include "../mwclass/activator.hpp"
|
||||
#include "../mwclass/armor.hpp"
|
||||
#include "../mwclass/book.hpp"
|
||||
#include "../mwclass/clothing.hpp"
|
||||
#include "../mwclass/container.hpp"
|
||||
#include "../mwclass/creature.hpp"
|
||||
#include "../mwclass/door.hpp"
|
||||
#include "../mwclass/ingredient.hpp"
|
||||
#include "../mwclass/light.hpp"
|
||||
#include "../mwclass/misc.hpp"
|
||||
#include "../mwclass/npc.hpp"
|
||||
#include "../mwclass/potion.hpp"
|
||||
#include "../mwclass/static.hpp"
|
||||
#include "../mwclass/weapon.hpp"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
@ -23,28 +10,34 @@ namespace MWLua
|
||||
return std::to_string(id.mIndex) + "_" + std::to_string(id.mContentFile);
|
||||
}
|
||||
|
||||
const static std::map<std::type_index, std::string_view> classNames = {
|
||||
{typeid(MWClass::Activator), "Activator"},
|
||||
{typeid(MWClass::Armor), "Armor"},
|
||||
{typeid(MWClass::Book), "Book"},
|
||||
{typeid(MWClass::Clothing), "Clothing"},
|
||||
{typeid(MWClass::Container), "Container"},
|
||||
{typeid(MWClass::Creature), "Creature"},
|
||||
{typeid(MWClass::Door), "Door"},
|
||||
{typeid(MWClass::Ingredient), "Ingredient"},
|
||||
{typeid(MWClass::Light), "Light"},
|
||||
{typeid(MWClass::Miscellaneous), "Miscellaneous"},
|
||||
{typeid(MWClass::Npc), "NPC"},
|
||||
{typeid(MWClass::Potion), "Potion"},
|
||||
{typeid(MWClass::Static), "Static"},
|
||||
{typeid(MWClass::Weapon), "Weapon"},
|
||||
struct LuaObjectTypeInfo
|
||||
{
|
||||
std::string_view mName;
|
||||
ESM::LuaScriptCfg::Flags mFlag = 0;
|
||||
};
|
||||
|
||||
std::string_view getMWClassName(const std::type_index& cls_type, std::string_view fallback)
|
||||
const static std::unordered_map<ESM::RecNameInts, LuaObjectTypeInfo> luaObjectTypeInfo = {
|
||||
{ESM::REC_ACTI, {"Activator", ESM::LuaScriptCfg::sActivator}},
|
||||
{ESM::REC_ARMO, {"Armor", ESM::LuaScriptCfg::sArmor}},
|
||||
{ESM::REC_BOOK, {"Book", ESM::LuaScriptCfg::sBook}},
|
||||
{ESM::REC_CLOT, {"Clothing", ESM::LuaScriptCfg::sClothing}},
|
||||
{ESM::REC_CONT, {"Container", ESM::LuaScriptCfg::sContainer}},
|
||||
{ESM::REC_CREA, {"Creature", ESM::LuaScriptCfg::sCreature}},
|
||||
{ESM::REC_DOOR, {"Door", ESM::LuaScriptCfg::sDoor}},
|
||||
{ESM::REC_INGR, {"Ingredient", ESM::LuaScriptCfg::sIngredient}},
|
||||
{ESM::REC_LIGH, {"Light", ESM::LuaScriptCfg::sLight}},
|
||||
{ESM::REC_MISC, {"Miscellaneous", ESM::LuaScriptCfg::sMiscItem}},
|
||||
{ESM::REC_NPC_, {"NPC", ESM::LuaScriptCfg::sNPC}},
|
||||
{ESM::REC_ALCH, {"Potion", ESM::LuaScriptCfg::sPotion}},
|
||||
{ESM::REC_STAT, {"Static"}},
|
||||
{ESM::REC_WEAP, {"Weapon", ESM::LuaScriptCfg::sWeapon}},
|
||||
};
|
||||
|
||||
std::string_view getLuaObjectTypeName(ESM::RecNameInts type, std::string_view fallback)
|
||||
{
|
||||
auto it = classNames.find(cls_type);
|
||||
if (it != classNames.end())
|
||||
return it->second;
|
||||
auto it = luaObjectTypeInfo.find(type);
|
||||
if (it != luaObjectTypeInfo.end())
|
||||
return it->second.mName;
|
||||
else
|
||||
return fallback;
|
||||
}
|
||||
@ -55,13 +48,31 @@ namespace MWLua
|
||||
return id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker";
|
||||
}
|
||||
|
||||
std::string_view getMWClassName(const MWWorld::Ptr& ptr)
|
||||
std::string_view getLuaObjectTypeName(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
// Behaviour of this function is a part of OpenMW Lua API. We can not just return
|
||||
// `ptr.getTypeDescription()` because its implementation is distributed over many files
|
||||
// and can be accidentally changed. We use `ptr.getTypeDescription()` only as a fallback
|
||||
// for types that are not present in `luaObjectTypeInfo` (for such types result stability
|
||||
// is not necessary because they are not listed in OpenMW Lua documentation).
|
||||
if (ptr.getCellRef().getRefIdRef() == "player")
|
||||
return "Player";
|
||||
if (isMarker(ptr))
|
||||
return "Marker";
|
||||
return getMWClassName(typeid(ptr.getClass()));
|
||||
return getLuaObjectTypeName(static_cast<ESM::RecNameInts>(ptr.getType()), /*fallback=*/ptr.getTypeDescription());
|
||||
}
|
||||
|
||||
ESM::LuaScriptCfg::Flags getLuaScriptFlag(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
if (ptr.getCellRef().getRefIdRef() == "player")
|
||||
return ESM::LuaScriptCfg::sPlayer;
|
||||
if (isMarker(ptr))
|
||||
return 0;
|
||||
auto it = luaObjectTypeInfo.find(static_cast<ESM::RecNameInts>(ptr.getType()));
|
||||
if (it != luaObjectTypeInfo.end())
|
||||
return it->second.mFlag;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string ptrToString(const MWWorld::Ptr& ptr)
|
||||
@ -69,7 +80,7 @@ namespace MWLua
|
||||
std::string res = "object";
|
||||
res.append(idToString(getId(ptr)));
|
||||
res.append(" (");
|
||||
res.append(getMWClassName(ptr));
|
||||
res.append(getLuaObjectTypeName(ptr));
|
||||
res.append(", ");
|
||||
res.append(ptr.getCellRef().getRefIdRef());
|
||||
res.append(")");
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <typeindex>
|
||||
|
||||
#include <components/esm/cellref.hpp>
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/luascripts.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
@ -19,8 +21,12 @@ namespace MWLua
|
||||
std::string idToString(const ObjectId& id);
|
||||
std::string ptrToString(const MWWorld::Ptr& ptr);
|
||||
bool isMarker(const MWWorld::Ptr& ptr);
|
||||
std::string_view getMWClassName(const std::type_index& cls_type, std::string_view fallback = "Unknown");
|
||||
std::string_view getMWClassName(const MWWorld::Ptr& ptr);
|
||||
std::string_view getLuaObjectTypeName(ESM::RecNameInts recordType, std::string_view fallback = "Unknown");
|
||||
std::string_view getLuaObjectTypeName(const MWWorld::Ptr& ptr);
|
||||
|
||||
// Each script has a set of flags that controls to which objects the script should be
|
||||
// automatically attached. This function maps each object types to one of the flags.
|
||||
ESM::LuaScriptCfg::Flags getLuaScriptFlag(const MWWorld::Ptr& ptr);
|
||||
|
||||
// Holds a mapping ObjectId -> MWWord::Ptr.
|
||||
class ObjectRegistry
|
||||
@ -64,7 +70,7 @@ namespace MWLua
|
||||
ObjectId id() const { return mId; }
|
||||
|
||||
std::string toString() const;
|
||||
std::string_view type() const { return getMWClassName(ptr()); }
|
||||
std::string_view type() const { return getLuaObjectTypeName(ptr()); }
|
||||
|
||||
// Updates and returns the underlying Ptr. Throws an exception if object is not available.
|
||||
const MWWorld::Ptr& ptr() const;
|
||||
|
@ -42,13 +42,12 @@ namespace MWLua
|
||||
template <typename ObjT>
|
||||
using Cell = std::conditional_t<std::is_same_v<ObjT, LObject>, LCell, GCell>;
|
||||
|
||||
template <class Class>
|
||||
static const MWWorld::Ptr& requireClass(const MWWorld::Ptr& ptr)
|
||||
static const MWWorld::Ptr& requireRecord(ESM::RecNameInts recordType, const MWWorld::Ptr& ptr)
|
||||
{
|
||||
if (typeid(Class) != typeid(ptr.getClass()))
|
||||
if (ptr.getType() != recordType)
|
||||
{
|
||||
std::string msg = "Requires type '";
|
||||
msg.append(getMWClassName(typeid(Class)));
|
||||
msg.append(getLuaObjectTypeName(recordType));
|
||||
msg.append("', but applied to ");
|
||||
msg.append(ptrToString(ptr));
|
||||
throw std::runtime_error(msg);
|
||||
@ -189,7 +188,7 @@ namespace MWLua
|
||||
template <class ObjectT>
|
||||
static void addDoorBindings(sol::usertype<ObjectT>& objectT, const Context& context)
|
||||
{
|
||||
auto ptr = [](const ObjectT& o) -> const MWWorld::Ptr& { return requireClass<MWClass::Door>(o.ptr()); };
|
||||
auto ptr = [](const ObjectT& o) -> const MWWorld::Ptr& { return requireRecord(ESM::REC_DOOR, o.ptr()); };
|
||||
|
||||
objectT["isTeleport"] = sol::readonly_property([ptr](const ObjectT& o)
|
||||
{
|
||||
|
@ -5,13 +5,15 @@
|
||||
|
||||
// List of all records, that are related to Lua.
|
||||
//
|
||||
// Record:
|
||||
// LUAM - MWLua::LuaManager
|
||||
// Records:
|
||||
// LUAL - LuaScriptsCfg - list of all scripts (in content files)
|
||||
// LUAM - MWLua::LuaManager (in saves)
|
||||
//
|
||||
// Subrecords:
|
||||
// LUAF - LuaScriptCfg::mFlags
|
||||
// LUAW - Start of MWLua::WorldView data
|
||||
// LUAE - Start of MWLua::LocalEvent or MWLua::GlobalEvent (eventName)
|
||||
// LUAS - Start LuaUtil::ScriptsContainer data (scriptName)
|
||||
// LUAS - VFS path to a Lua script
|
||||
// LUAD - Serialized Lua variable
|
||||
// LUAT - MWLua::ScriptsContainer::Timer
|
||||
// LUAC - Name of a timer callback (string)
|
||||
@ -37,6 +39,28 @@ std::string ESM::loadLuaBinaryData(ESMReader& esm)
|
||||
return data;
|
||||
}
|
||||
|
||||
void ESM::LuaScriptsCfg::load(ESMReader& esm)
|
||||
{
|
||||
while (esm.isNextSub("LUAS"))
|
||||
{
|
||||
std::string name = esm.getHString();
|
||||
uint64_t flags;
|
||||
esm.getHNT(flags, "LUAF");
|
||||
std::string data = loadLuaBinaryData(esm);
|
||||
mScripts.push_back({std::move(name), std::move(data), flags});
|
||||
}
|
||||
}
|
||||
|
||||
void ESM::LuaScriptsCfg::save(ESMWriter& esm) const
|
||||
{
|
||||
for (const LuaScriptCfg& script : mScripts)
|
||||
{
|
||||
esm.writeHNString("LUAS", script.mScriptPath);
|
||||
esm.writeHNT("LUAF", script.mFlags);
|
||||
saveLuaBinaryData(esm, script.mInitializationData);
|
||||
}
|
||||
}
|
||||
|
||||
void ESM::LuaScripts::load(ESMReader& esm)
|
||||
{
|
||||
while (esm.isNextSub("LUAS"))
|
||||
@ -63,8 +87,7 @@ void ESM::LuaScripts::save(ESMWriter& esm) const
|
||||
for (const LuaScript& script : mScripts)
|
||||
{
|
||||
esm.writeHNString("LUAS", script.mScriptPath);
|
||||
if (!script.mData.empty())
|
||||
saveLuaBinaryData(esm, script.mData);
|
||||
saveLuaBinaryData(esm, script.mData);
|
||||
for (const LuaTimer& timer : script.mTimers)
|
||||
{
|
||||
esm.startSubRecord("LUAT");
|
||||
|
@ -9,7 +9,44 @@ namespace ESM
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
||||
// Storage structure for LuaUtil::ScriptsContainer. This is not a top-level record.
|
||||
// LuaScriptCfg, LuaScriptsCfg are used in content files.
|
||||
|
||||
struct LuaScriptCfg
|
||||
{
|
||||
using Flags = uint64_t;
|
||||
static constexpr Flags sGlobal = 1ull << 0;
|
||||
static constexpr Flags sCustom = 1ull << 1; // local; can be attached/detached by a global script
|
||||
static constexpr Flags sPlayer = 1ull << 2; // auto attach to players
|
||||
// auto attach for other classes:
|
||||
static constexpr Flags sActivator = 1ull << 3;
|
||||
static constexpr Flags sArmor = 1ull << 4;
|
||||
static constexpr Flags sBook = 1ull << 5;
|
||||
static constexpr Flags sClothing = 1ull << 6;
|
||||
static constexpr Flags sContainer = 1ull << 7;
|
||||
static constexpr Flags sCreature = 1ull << 8;
|
||||
static constexpr Flags sDoor = 1ull << 9;
|
||||
static constexpr Flags sIngredient = 1ull << 10;
|
||||
static constexpr Flags sLight = 1ull << 11;
|
||||
static constexpr Flags sMiscItem = 1ull << 12;
|
||||
static constexpr Flags sNPC = 1ull << 13;
|
||||
static constexpr Flags sPotion = 1ull << 14;
|
||||
static constexpr Flags sWeapon = 1ull << 15;
|
||||
|
||||
std::string mScriptPath;
|
||||
std::string mInitializationData; // Serialized Lua table. It is a binary data. Can contain '\0'.
|
||||
Flags mFlags; // bitwise OR of Flags.
|
||||
};
|
||||
|
||||
struct LuaScriptsCfg
|
||||
{
|
||||
std::vector<LuaScriptCfg> mScripts;
|
||||
|
||||
void load(ESMReader &esm);
|
||||
void save(ESMWriter &esm) const;
|
||||
};
|
||||
|
||||
// LuaTimer, LuaScript, LuaScripts are used in saved game files.
|
||||
// Storage structure for LuaUtil::ScriptsContainer. These are not top-level records.
|
||||
// Used either for global scripts or for local scripts on a specific object.
|
||||
|
||||
struct LuaTimer
|
||||
@ -37,11 +74,11 @@ namespace ESM
|
||||
{
|
||||
std::vector<LuaScript> mScripts;
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void save (ESMWriter &esm) const;
|
||||
void load(ESMReader &esm);
|
||||
void save(ESMWriter &esm) const;
|
||||
};
|
||||
|
||||
// Saves binary string `data` (can contain '\0') as record LUAD.
|
||||
// Saves binary string `data` (can contain '\0') as LUAD record.
|
||||
void saveLuaBinaryData(ESM::ESMWriter& esm, const std::string& data);
|
||||
|
||||
// Loads LUAD as binary string. If next subrecord is not LUAD, then returns an empty string.
|
||||
|
Loading…
x
Reference in New Issue
Block a user