Merge branch 'vfs_normalized_path_20' into 'master'

Use normalized path for correctMeshPath and getLODMeshName (#8138)

See merge request OpenMW/openmw!4455
master
psi29a 1 month ago
commit 79dbbceb10

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadacti.hpp> #include <components/esm3/loadacti.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
@ -49,9 +51,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Activator& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Activator& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Activator& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Activator& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property([](const ESM::Activator& rec) -> std::string { addModelProperty(record);
return Misc::ResourceHelpers::correctMeshPath(rec.mModel);
});
record["mwscript"] = sol::readonly_property([](const ESM::Activator& rec) -> sol::optional<std::string> { record["mwscript"] = sol::readonly_property([](const ESM::Activator& rec) -> sol::optional<std::string> {
return LuaUtil::serializeRefId(rec.mScript); return LuaUtil::serializeRefId(rec.mScript);
}); });

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadappa.hpp> #include <components/esm3/loadappa.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
@ -39,9 +41,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property([](const ESM::Apparatus& rec) -> std::string { addModelProperty(record);
return Misc::ResourceHelpers::correctMeshPath(rec.mModel);
});
record["mwscript"] = sol::readonly_property([](const ESM::Apparatus& rec) -> sol::optional<std::string> { record["mwscript"] = sol::readonly_property([](const ESM::Apparatus& rec) -> sol::optional<std::string> {
return LuaUtil::serializeRefId(rec.mScript); return LuaUtil::serializeRefId(rec.mScript);
}); });

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadarmo.hpp> #include <components/esm3/loadarmo.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
@ -96,8 +98,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Armor& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Armor& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["icon"] = sol::readonly_property([vfs](const ESM::Armor& rec) -> std::string { record["icon"] = sol::readonly_property([vfs](const ESM::Armor& rec) -> std::string {
return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs);
}); });

@ -1,13 +1,14 @@
#include "types.hpp" #include "types.hpp"
#include <components/misc/strings/algorithm.hpp> #include "modelproperty.hpp"
#include <components/misc/strings/lower.hpp>
#include <components/esm3/loadbook.hpp> #include <components/esm3/loadbook.hpp>
#include <components/esm3/loadskil.hpp> #include <components/esm3/loadskil.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/misc/strings/algorithm.hpp>
#include <components/misc/strings/lower.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include "apps/openmw/mwbase/environment.hpp" #include "apps/openmw/mwbase/environment.hpp"
@ -104,8 +105,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Book& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Book& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["mwscript"] = sol::readonly_property( record["mwscript"] = sol::readonly_property(
[](const ESM::Book& rec) -> sol::optional<std::string> { return LuaUtil::serializeRefId(rec.mScript); }); [](const ESM::Book& rec) -> sol::optional<std::string> { return LuaUtil::serializeRefId(rec.mScript); });
record["icon"] = sol::readonly_property([vfs](const ESM::Book& rec) -> std::string { record["icon"] = sol::readonly_property([vfs](const ESM::Book& rec) -> std::string {

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadclot.hpp> #include <components/esm3/loadclot.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
@ -91,8 +93,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Clothing& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Clothing& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Clothing& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Clothing& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Clothing& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["icon"] = sol::readonly_property([vfs](const ESM::Clothing& rec) -> std::string { record["icon"] = sol::readonly_property([vfs](const ESM::Clothing& rec) -> std::string {
return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs);
}); });

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadcont.hpp> #include <components/esm3/loadcont.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
@ -49,9 +51,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Container& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Container& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Container& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Container& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property([](const ESM::Container& rec) -> std::string { addModelProperty(record);
return Misc::ResourceHelpers::correctMeshPath(rec.mModel);
});
record["mwscript"] = sol::readonly_property([](const ESM::Container& rec) -> sol::optional<std::string> { record["mwscript"] = sol::readonly_property([](const ESM::Container& rec) -> sol::optional<std::string> {
return LuaUtil::serializeRefId(rec.mScript); return LuaUtil::serializeRefId(rec.mScript);
}); });

@ -1,6 +1,8 @@
#include "types.hpp"
#include "../stats.hpp" #include "../stats.hpp"
#include "actor.hpp" #include "actor.hpp"
#include "types.hpp" #include "modelproperty.hpp"
#include <components/esm3/loadcrea.hpp> #include <components/esm3/loadcrea.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
@ -37,8 +39,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Creature& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Creature& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Creature& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Creature& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Creature& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["mwscript"] = sol::readonly_property([](const ESM::Creature& rec) -> sol::optional<std::string> { record["mwscript"] = sol::readonly_property([](const ESM::Creature& rec) -> sol::optional<std::string> {
return LuaUtil::serializeRefId(rec.mScript); return LuaUtil::serializeRefId(rec.mScript);
}); });

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include "../localscripts.hpp" #include "../localscripts.hpp"
#include <components/esm3/loaddoor.hpp> #include <components/esm3/loaddoor.hpp>
@ -107,8 +109,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Door& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Door& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["mwscript"] = sol::readonly_property( record["mwscript"] = sol::readonly_property(
[](const ESM::Door& rec) -> sol::optional<std::string> { return LuaUtil::serializeRefId(rec.mScript); }); [](const ESM::Door& rec) -> sol::optional<std::string> { return LuaUtil::serializeRefId(rec.mScript); });
record["openSound"] = sol::readonly_property( record["openSound"] = sol::readonly_property(
@ -145,8 +146,7 @@ namespace MWLua
record["id"] = sol::readonly_property( record["id"] = sol::readonly_property(
[](const ESM4::Door& rec) -> std::string { return ESM::RefId(rec.mId).serializeText(); }); [](const ESM4::Door& rec) -> std::string { return ESM::RefId(rec.mId).serializeText(); });
record["name"] = sol::readonly_property([](const ESM4::Door& rec) -> std::string { return rec.mFullName; }); record["name"] = sol::readonly_property([](const ESM4::Door& rec) -> std::string { return rec.mFullName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM4::Door& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["isAutomatic"] = sol::readonly_property( record["isAutomatic"] = sol::readonly_property(
[](const ESM4::Door& rec) -> bool { return rec.mDoorFlags & ESM4::Door::Flag_AutomaticDoor; }); [](const ESM4::Door& rec) -> bool { return rec.mDoorFlags & ESM4::Door::Flag_AutomaticDoor; });
} }

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadalch.hpp> #include <components/esm3/loadalch.hpp>
#include <components/esm3/loadingr.hpp> #include <components/esm3/loadingr.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
@ -31,9 +33,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Ingredient& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Ingredient& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Ingredient& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Ingredient& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property([](const ESM::Ingredient& rec) -> std::string { addModelProperty(record);
return Misc::ResourceHelpers::correctMeshPath(rec.mModel);
});
record["mwscript"] = sol::readonly_property([](const ESM::Ingredient& rec) -> sol::optional<std::string> { record["mwscript"] = sol::readonly_property([](const ESM::Ingredient& rec) -> sol::optional<std::string> {
return LuaUtil::serializeRefId(rec.mScript); return LuaUtil::serializeRefId(rec.mScript);
}); });

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadligh.hpp> #include <components/esm3/loadligh.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
@ -90,8 +92,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Light& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Light& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["icon"] = sol::readonly_property([vfs](const ESM::Light& rec) -> std::string { record["icon"] = sol::readonly_property([vfs](const ESM::Light& rec) -> std::string {
return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs);
}); });

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadlock.hpp> #include <components/esm3/loadlock.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
@ -30,8 +32,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Lockpick& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Lockpick& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Lockpick& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Lockpick& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Lockpick& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["mwscript"] = sol::readonly_property([](const ESM::Lockpick& rec) -> sol::optional<std::string> { record["mwscript"] = sol::readonly_property([](const ESM::Lockpick& rec) -> sol::optional<std::string> {
return LuaUtil::serializeRefId(rec.mScript); return LuaUtil::serializeRefId(rec.mScript);
}); });

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadcrea.hpp> #include <components/esm3/loadcrea.hpp>
#include <components/esm3/loadmisc.hpp> #include <components/esm3/loadmisc.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
@ -81,9 +83,7 @@ namespace MWLua
record["id"] = sol::readonly_property( record["id"] = sol::readonly_property(
[](const ESM::Miscellaneous& rec) -> std::string { return rec.mId.serializeText(); }); [](const ESM::Miscellaneous& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> std::string { addModelProperty(record);
return Misc::ResourceHelpers::correctMeshPath(rec.mModel);
});
record["mwscript"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> sol::optional<std::string> { record["mwscript"] = sol::readonly_property([](const ESM::Miscellaneous& rec) -> sol::optional<std::string> {
return LuaUtil::serializeRefId(rec.mScript); return LuaUtil::serializeRefId(rec.mScript);
}); });

@ -0,0 +1,21 @@
#ifndef OPENMW_APPS_OPENMW_MWLUA_TYPES_MODELPROPERTY_H
#define OPENMW_APPS_OPENMW_MWLUA_TYPES_MODELPROPERTY_H
#include <components/misc/resourcehelpers.hpp>
#include <components/vfs/pathutil.hpp>
#include <sol/property.hpp>
#include <sol/usertype.hpp>
namespace MWLua
{
template <class T>
void addModelProperty(sol::usertype<T>& recordType)
{
recordType["model"] = sol::readonly_property([](const T& recordValue) -> std::string {
return Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(recordValue.mModel)).value();
});
}
}
#endif

@ -1,6 +1,8 @@
#include "actor.hpp"
#include "types.hpp" #include "types.hpp"
#include "actor.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadfact.hpp> #include <components/esm3/loadfact.hpp>
#include <components/esm3/loadnpc.hpp> #include <components/esm3/loadnpc.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
@ -93,8 +95,7 @@ namespace MWLua
= sol::readonly_property([](const ESM::NPC& rec) -> int { return (int)rec.mNpdt.mDisposition; }); = sol::readonly_property([](const ESM::NPC& rec) -> int { return (int)rec.mNpdt.mDisposition; });
record["head"] record["head"]
= sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHead.serializeText(); }); = sol::readonly_property([](const ESM::NPC& rec) -> std::string { return rec.mHead.serializeText(); });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::NPC& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["isEssential"] record["isEssential"]
= sol::readonly_property([](const ESM::NPC& rec) -> bool { return rec.mFlags & ESM::NPC::Essential; }); = sol::readonly_property([](const ESM::NPC& rec) -> bool { return rec.mFlags & ESM::NPC::Essential; });
record["isMale"] = sol::readonly_property([](const ESM::NPC& rec) -> bool { return rec.isMale(); }); record["isMale"] = sol::readonly_property([](const ESM::NPC& rec) -> bool { return rec.isMale(); });

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadalch.hpp> #include <components/esm3/loadalch.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
@ -76,8 +78,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Potion& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Potion& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Potion& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Potion& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Potion& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["icon"] = sol::readonly_property([vfs](const ESM::Potion& rec) -> std::string { record["icon"] = sol::readonly_property([vfs](const ESM::Potion& rec) -> std::string {
return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs);
}); });

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadprob.hpp> #include <components/esm3/loadprob.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
@ -30,8 +32,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Probe& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Probe& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["mwscript"] = sol::readonly_property( record["mwscript"] = sol::readonly_property(
[](const ESM::Probe& rec) -> sol::optional<std::string> { return LuaUtil::serializeRefId(rec.mScript); }); [](const ESM::Probe& rec) -> sol::optional<std::string> { return LuaUtil::serializeRefId(rec.mScript); });
record["icon"] = sol::readonly_property([vfs](const ESM::Probe& rec) -> std::string { record["icon"] = sol::readonly_property([vfs](const ESM::Probe& rec) -> std::string {

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadrepa.hpp> #include <components/esm3/loadrepa.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
@ -30,8 +32,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Repair& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Repair& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["mwscript"] = sol::readonly_property( record["mwscript"] = sol::readonly_property(
[](const ESM::Repair& rec) -> sol::optional<std::string> { return LuaUtil::serializeRefId(rec.mScript); }); [](const ESM::Repair& rec) -> sol::optional<std::string> { return LuaUtil::serializeRefId(rec.mScript); });
record["icon"] = sol::readonly_property([vfs](const ESM::Repair& rec) -> std::string { record["icon"] = sol::readonly_property([vfs](const ESM::Repair& rec) -> std::string {

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadstat.hpp> #include <components/esm3/loadstat.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
@ -24,7 +26,6 @@ namespace MWLua
= [](const ESM::Static& rec) -> std::string { return "ESM3_Static[" + rec.mId.toDebugString() + "]"; }; = [](const ESM::Static& rec) -> std::string { return "ESM3_Static[" + rec.mId.toDebugString() + "]"; };
record["id"] record["id"]
= sol::readonly_property([](const ESM::Static& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Static& rec) -> std::string { return rec.mId.serializeText(); });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Static& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
} }
} }

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm4/loadterm.hpp> #include <components/esm4/loadterm.hpp>
#include <components/lua/utilpackage.hpp> #include <components/lua/utilpackage.hpp>
#include <components/misc/convert.hpp> #include <components/misc/convert.hpp>
@ -33,8 +35,6 @@ namespace MWLua
record["resultText"] record["resultText"]
= sol::readonly_property([](const ESM4::Terminal& rec) -> std::string { return rec.mResultText; }); = sol::readonly_property([](const ESM4::Terminal& rec) -> std::string { return rec.mResultText; });
record["name"] = sol::readonly_property([](const ESM4::Terminal& rec) -> std::string { return rec.mFullName; }); record["name"] = sol::readonly_property([](const ESM4::Terminal& rec) -> std::string { return rec.mFullName; });
record["model"] = sol::readonly_property([](const ESM4::Terminal& rec) -> std::string { addModelProperty(record);
return Misc::ResourceHelpers::correctMeshPath(rec.mModel);
});
} }
} }

@ -1,5 +1,7 @@
#include "types.hpp" #include "types.hpp"
#include "modelproperty.hpp"
#include <components/esm3/loadweap.hpp> #include <components/esm3/loadweap.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
@ -129,8 +131,7 @@ namespace MWLua
record["id"] record["id"]
= sol::readonly_property([](const ESM::Weapon& rec) -> std::string { return rec.mId.serializeText(); }); = sol::readonly_property([](const ESM::Weapon& rec) -> std::string { return rec.mId.serializeText(); });
record["name"] = sol::readonly_property([](const ESM::Weapon& rec) -> std::string { return rec.mName; }); record["name"] = sol::readonly_property([](const ESM::Weapon& rec) -> std::string { return rec.mName; });
record["model"] = sol::readonly_property( addModelProperty(record);
[](const ESM::Weapon& rec) -> std::string { return Misc::ResourceHelpers::correctMeshPath(rec.mModel); });
record["icon"] = sol::readonly_property([vfs](const ESM::Weapon& rec) -> std::string { record["icon"] = sol::readonly_property([vfs](const ESM::Weapon& rec) -> std::string {
return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs); return Misc::ResourceHelpers::correctIconPath(rec.mIcon, vfs);
}); });

@ -367,8 +367,12 @@ namespace MWMechanics
ESM::RefId::stringRefId("VFX_Reflect")); ESM::RefId::stringRefId("VFX_Reflect"));
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr); MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr);
if (animation && !reflectStatic->mModel.empty()) if (animation && !reflectStatic->mModel.empty())
animation->addEffect(Misc::ResourceHelpers::correctMeshPath(reflectStatic->mModel), {
ESM::MagicEffect::indexToName(ESM::MagicEffect::Reflect), false); const VFS::Path::Normalized reflectStaticModel
= Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(reflectStatic->mModel));
animation->addEffect(
reflectStaticModel, ESM::MagicEffect::indexToName(ESM::MagicEffect::Reflect), false);
}
caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell(*reflected); caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell(*reflected);
} }
if (removedSpell) if (removedSpell)

@ -214,7 +214,7 @@ namespace
const ESM::Static* const fx const ESM::Static* const fx
= world->getStore().get<ESM::Static>().search(ESM::RefId::stringRefId("VFX_Soul_Trap")); = world->getStore().get<ESM::Static>().search(ESM::RefId::stringRefId("VFX_Soul_Trap"));
if (fx != nullptr) if (fx != nullptr)
world->spawnEffect(VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(fx->mModel)), "", world->spawnEffect(Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(fx->mModel)), "",
creature.getRefData().getPosition().asVec3()); creature.getRefData().getPosition().asVec3());
MWBase::Environment::get().getSoundManager()->playSound3D( MWBase::Environment::get().getSoundManager()->playSound3D(
@ -1806,7 +1806,7 @@ namespace MWMechanics
ESM::RefId::stringRefId("VFX_Summon_End")); ESM::RefId::stringRefId("VFX_Summon_End"));
if (fx) if (fx)
MWBase::Environment::get().getWorld()->spawnEffect( MWBase::Environment::get().getWorld()->spawnEffect(
VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(fx->mModel)), "", Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(fx->mModel)), "",
ptr.getRefData().getPosition().asVec3()); ptr.getRefData().getPosition().asVec3());
// Remove the summoned creature's summoned creatures as well // Remove the summoned creature's summoned creatures as well

@ -1590,13 +1590,16 @@ namespace MWMechanics
const ESM::Static* castStatic const ESM::Static* castStatic
= world->getStore().get<ESM::Static>().find(ESM::RefId::stringRefId("VFX_Hands")); = world->getStore().get<ESM::Static>().find(ESM::RefId::stringRefId("VFX_Hands"));
const VFS::Path::Normalized castStaticModel
= Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(castStatic->mModel));
if (mAnimation->getNode("Bip01 L Hand")) if (mAnimation->getNode("Bip01 L Hand"))
mAnimation->addEffect(Misc::ResourceHelpers::correctMeshPath(castStatic->mModel), mAnimation->addEffect(
"", false, "Bip01 L Hand", effect->mParticle); castStaticModel.value(), "", false, "Bip01 L Hand", effect->mParticle);
if (mAnimation->getNode("Bip01 R Hand")) if (mAnimation->getNode("Bip01 R Hand"))
mAnimation->addEffect(Misc::ResourceHelpers::correctMeshPath(castStatic->mModel), mAnimation->addEffect(
"", false, "Bip01 R Hand", effect->mParticle); castStaticModel.value(), "", false, "Bip01 R Hand", effect->mParticle);
} }
// first effect used for casting animation // first effect used for casting animation
const ESM::ENAMstruct& firstEffect = effects->front().mData; const ESM::ENAMstruct& firstEffect = effects->front().mData;

@ -72,12 +72,12 @@ namespace MWMechanics
{ {
if (effectInfo.mData.mRange == ESM::RT_Target) if (effectInfo.mData.mRange == ESM::RT_Target)
world->spawnEffect( world->spawnEffect(
VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(areaStatic->mModel)), texture, Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(areaStatic->mModel)), texture,
mHitPosition, 1.0f); mHitPosition, 1.0f);
continue; continue;
} }
else else
world->spawnEffect(VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(areaStatic->mModel)), world->spawnEffect(Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(areaStatic->mModel)),
texture, mHitPosition, static_cast<float>(effectInfo.mData.mArea * 2)); texture, mHitPosition, static_cast<float>(effectInfo.mData.mArea * 2));
// Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now)
@ -487,7 +487,7 @@ namespace MWMechanics
void CastSpell::playSpellCastingEffects(const std::vector<ESM::IndexedENAMstruct>& effects) const void CastSpell::playSpellCastingEffects(const std::vector<ESM::IndexedENAMstruct>& effects) const
{ {
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
std::vector<std::string> addedEffects; std::vector<VFS::Path::Normalized> addedEffects;
for (const ESM::IndexedENAMstruct& effectData : effects) for (const ESM::IndexedENAMstruct& effectData : effects)
{ {
@ -500,17 +500,18 @@ namespace MWMechanics
else else
castStatic = store.get<ESM::Static>().find(ESM::RefId::stringRefId("VFX_DefaultCast")); castStatic = store.get<ESM::Static>().find(ESM::RefId::stringRefId("VFX_DefaultCast"));
VFS::Path::Normalized castStaticModel
= Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(castStatic->mModel));
// check if the effect was already added // check if the effect was already added
if (std::find(addedEffects.begin(), addedEffects.end(), if (std::find(addedEffects.begin(), addedEffects.end(), castStaticModel) != addedEffects.end())
Misc::ResourceHelpers::correctMeshPath(castStatic->mModel))
!= addedEffects.end())
continue; continue;
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster); MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
if (animation) if (animation)
{ {
animation->addEffect(Misc::ResourceHelpers::correctMeshPath(castStatic->mModel), animation->addEffect(castStaticModel.value(), ESM::MagicEffect::indexToName(effect->mIndex), false, {},
ESM::MagicEffect::indexToName(effect->mIndex), false, {}, effect->mParticle); effect->mParticle);
} }
else else
{ {
@ -539,15 +540,13 @@ namespace MWMechanics
scale *= npcScaleVec.z(); scale *= npcScaleVec.z();
} }
scale = std::max(scale, 1.f); scale = std::max(scale, 1.f);
MWBase::Environment::get().getWorld()->spawnEffect( MWBase::Environment::get().getWorld()->spawnEffect(castStaticModel, effect->mParticle, pos, scale);
VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(castStatic->mModel)),
effect->mParticle, pos, scale);
} }
if (animation && !mCaster.getClass().isActor()) if (animation && !mCaster.getClass().isActor())
animation->addSpellCastGlow(effect->getColor()); animation->addSpellCastGlow(effect->getColor());
addedEffects.push_back(Misc::ResourceHelpers::correctMeshPath(castStatic->mModel)); addedEffects.push_back(std::move(castStaticModel));
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
if (!effect->mCastSound.empty()) if (!effect->mCastSound.empty())
@ -584,8 +583,12 @@ namespace MWMechanics
{ {
// Don't play particle VFX unless the effect is new or it should be looping. // Don't play particle VFX unless the effect is new or it should be looping.
if (playNonLooping || loop) if (playNonLooping || loop)
anim->addEffect(Misc::ResourceHelpers::correctMeshPath(castStatic->mModel), {
ESM::MagicEffect::indexToName(magicEffect.mIndex), loop, {}, magicEffect.mParticle); const VFS::Path::Normalized castStaticModel
= Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(castStatic->mModel));
anim->addEffect(castStaticModel.value(), ESM::MagicEffect::indexToName(magicEffect.mIndex), loop, {},
magicEffect.mParticle);
}
} }
} }
} }

@ -286,8 +286,13 @@ namespace
const ESM::Static* absorbStatic = esmStore.get<ESM::Static>().find(ESM::RefId::stringRefId("VFX_Absorb")); const ESM::Static* absorbStatic = esmStore.get<ESM::Static>().find(ESM::RefId::stringRefId("VFX_Absorb"));
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(target); MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(target);
if (animation && !absorbStatic->mModel.empty()) if (animation && !absorbStatic->mModel.empty())
animation->addEffect(Misc::ResourceHelpers::correctMeshPath(absorbStatic->mModel), {
ESM::MagicEffect::indexToName(ESM::MagicEffect::SpellAbsorption), false); const VFS::Path::Normalized absorbStaticModel
= Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(absorbStatic->mModel));
animation->addEffect(
absorbStaticModel.value(), ESM::MagicEffect::indexToName(ESM::MagicEffect::SpellAbsorption), false);
}
int spellCost = 0; int spellCost = 0;
if (const ESM::Spell* spell = esmStore.get<ESM::Spell>().search(spellParams.getSourceSpellId())) if (const ESM::Spell* spell = esmStore.get<ESM::Spell>().search(spellParams.getSourceSpellId()))
{ {
@ -455,8 +460,12 @@ namespace MWMechanics
anim->removeEffect(ESM::MagicEffect::indexToName(effect.mEffectId)); anim->removeEffect(ESM::MagicEffect::indexToName(effect.mEffectId));
const ESM::Static* fx const ESM::Static* fx
= world->getStore().get<ESM::Static>().search(ESM::RefId::stringRefId("VFX_Summon_end")); = world->getStore().get<ESM::Static>().search(ESM::RefId::stringRefId("VFX_Summon_end"));
if (fx) if (fx != nullptr)
anim->addEffect(Misc::ResourceHelpers::correctMeshPath(fx->mModel), ""); {
const VFS::Path::Normalized fxModel
= Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(fx->mModel));
anim->addEffect(fxModel.value(), "");
}
} }
} }
else if (caster == getPlayer()) else if (caster == getPlayer())

@ -105,7 +105,9 @@ namespace MWMechanics
const ESM::Static* fx const ESM::Static* fx
= world->getStore().get<ESM::Static>().search(ESM::RefId::stringRefId("VFX_Summon_Start")); = world->getStore().get<ESM::Static>().search(ESM::RefId::stringRefId("VFX_Summon_Start"));
if (fx) if (fx)
anim->addEffect(Misc::ResourceHelpers::correctMeshPath(fx->mModel), "", false); anim->addEffect(
Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(fx->mModel)).value(), "",
false);
} }
} }
catch (std::exception& e) catch (std::exception& e)

@ -131,7 +131,7 @@ namespace MWRender
if (bodypart == nullptr || bodypart->mData.mType != ESM::BodyPart::MT_Armor) if (bodypart == nullptr || bodypart->mData.mType != ESM::BodyPart::MT_Armor)
return std::string(); return std::string();
if (!bodypart->mModel.empty()) if (!bodypart->mModel.empty())
return Misc::ResourceHelpers::correctMeshPath(bodypart->mModel); return Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(bodypart->mModel)).value();
} }
} }
} }

@ -53,7 +53,7 @@ namespace MWRender
if (model.empty()) if (model.empty())
return; return;
mResourceSystem->getSceneManager()->getInstance( mResourceSystem->getSceneManager()->getInstance(
VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(model)), mObjectRoot.get()); Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(model)), mObjectRoot.get());
} }
template <class Record> template <class Record>

@ -78,7 +78,7 @@ namespace
const ESM::BodyPart* bodyPart = sVampireMapping[thisCombination]; const ESM::BodyPart* bodyPart = sVampireMapping[thisCombination];
if (!bodyPart) if (!bodyPart)
return std::string(); return std::string();
return Misc::ResourceHelpers::correctMeshPath(bodyPart->mModel); return Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(bodyPart->mModel)).value();
} }
} }
@ -463,7 +463,7 @@ namespace MWRender
{ {
const ESM::BodyPart* bp = store.get<ESM::BodyPart>().search(headName); const ESM::BodyPart* bp = store.get<ESM::BodyPart>().search(headName);
if (bp) if (bp)
mHeadModel = Misc::ResourceHelpers::correctMeshPath(bp->mModel); mHeadModel = Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(bp->mModel));
else else
Log(Debug::Warning) << "Warning: Failed to load body part '" << headName << "'"; Log(Debug::Warning) << "Warning: Failed to load body part '" << headName << "'";
} }
@ -472,7 +472,7 @@ namespace MWRender
{ {
const ESM::BodyPart* bp = store.get<ESM::BodyPart>().search(hairName); const ESM::BodyPart* bp = store.get<ESM::BodyPart>().search(hairName);
if (bp) if (bp)
mHairModel = Misc::ResourceHelpers::correctMeshPath(bp->mModel); mHairModel = Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(bp->mModel));
else else
Log(Debug::Warning) << "Warning: Failed to load body part '" << hairName << "'"; Log(Debug::Warning) << "Warning: Failed to load body part '" << hairName << "'";
} }
@ -501,7 +501,7 @@ namespace MWRender
bool isCustomModel = false; bool isCustomModel = false;
if (!is1stPerson && !isWerewolf && !mNpc->mModel.empty()) if (!is1stPerson && !isWerewolf && !mNpc->mModel.empty())
{ {
VFS::Path::Normalized model = Misc::ResourceHelpers::correctMeshPath(mNpc->mModel); VFS::Path::Normalized model = Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(mNpc->mModel));
isCustomModel = !isDefaultActorSkeleton(model); isCustomModel = !isDefaultActorSkeleton(model);
smodel = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS()); smodel = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS());
} }
@ -648,8 +648,7 @@ namespace MWRender
{ {
const ESM::Light* light = part.get<ESM::Light>()->mBase; const ESM::Light* light = part.get<ESM::Light>()->mBase;
addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1,
VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(light->mModel)), false, nullptr, Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(light->mModel)), false, nullptr, true);
true);
if (mObjectParts[ESM::PRT_Shield]) if (mObjectParts[ESM::PRT_Shield])
addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), SceneUtil::LightCommon(*light)); addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), SceneUtil::LightCommon(*light));
} }
@ -669,7 +668,7 @@ namespace MWRender
{ {
if (const ESM::BodyPart* bodypart = parts[part]) if (const ESM::BodyPart* bodypart = parts[part])
addOrReplaceIndividualPart(static_cast<ESM::PartReferenceType>(part), -1, 1, addOrReplaceIndividualPart(static_cast<ESM::PartReferenceType>(part), -1, 1,
VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(bodypart->mModel))); Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(bodypart->mModel)));
} }
} }
@ -899,7 +898,7 @@ namespace MWRender
if (bodypart) if (bodypart)
addOrReplaceIndividualPart(static_cast<ESM::PartReferenceType>(part.mPart), group, priority, addOrReplaceIndividualPart(static_cast<ESM::PartReferenceType>(part.mPart), group, priority,
VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(bodypart->mModel)), enchantedGlow, Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(bodypart->mModel)), enchantedGlow,
glowColor); glowColor);
else else
reserveIndividualPart((ESM::PartReferenceType)part.mPart, group, priority); reserveIndividualPart((ESM::PartReferenceType)part.mPart, group, priority);

@ -668,7 +668,7 @@ namespace MWRender
model = mLODNameCache model = mLODNameCache
.emplace_hint(found, std::move(key), .emplace_hint(found, std::move(key),
Misc::ResourceHelpers::getLODMeshName(world.getESMVersions()[refNum.mContentFile], Misc::ResourceHelpers::getLODMeshName(world.getESMVersions()[refNum.mContentFile],
model, mSceneManager->getVFS(), lod)) model, *mSceneManager->getVFS(), lod))
->second; ->second;
} }

@ -79,7 +79,7 @@ namespace MWRender
std::mutex mLODNameCacheMutex; std::mutex mLODNameCacheMutex;
typedef std::pair<std::string, unsigned char> LODNameCacheKey; // Key: mesh name, lod level typedef std::pair<std::string, unsigned char> LODNameCacheKey; // Key: mesh name, lod level
typedef std::map<LODNameCacheKey, std::string> LODNameCache; // Cache: key, mesh name to use using LODNameCache = std::map<LODNameCacheKey, VFS::Path::Normalized>; // Cache: key, mesh name to use
LODNameCache mLODNameCache; LODNameCache mLODNameCache;
}; };

@ -116,7 +116,7 @@ namespace MWWorld
try try
{ {
const VFS::Manager& vfs = *mSceneManager->getVFS(); const VFS::Manager& vfs = *mSceneManager->getVFS();
mesh = Misc::ResourceHelpers::correctMeshPath(path); mesh = Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(path));
mesh = Misc::ResourceHelpers::correctActorModelPath(mesh, &vfs); mesh = Misc::ResourceHelpers::correctActorModelPath(mesh, &vfs);
if (!vfs.exists(mesh)) if (!vfs.exists(mesh))

@ -315,7 +315,7 @@ namespace MWWorld
{ {
std::string_view model = getModel(ptr); std::string_view model = getModel(ptr);
if (!model.empty()) if (!model.empty())
return Misc::ResourceHelpers::correctMeshPath(model); return Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(model));
return {}; return {};
} }

@ -222,7 +222,7 @@ namespace MWWorld
attachTo->accept(findVisitor); attachTo->accept(findVisitor);
if (findVisitor.mFoundNode) if (findVisitor.mFoundNode)
mResourceSystem->getSceneManager()->getInstance( mResourceSystem->getSceneManager()->getInstance(
VFS::Path::toNormalized(Misc::ResourceHelpers::correctMeshPath(weapon->mModel)), Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(weapon->mModel)),
findVisitor.mFoundNode); findVisitor.mFoundNode);
} }
} }
@ -330,8 +330,8 @@ namespace MWWorld
// shape // shape
if (state.mIdMagic.size() > 1) if (state.mIdMagic.size() > 1)
{ {
model = Misc::ResourceHelpers::correctMeshPath( model = Misc::ResourceHelpers::correctMeshPath(VFS::Path::Normalized(
MWBase::Environment::get().getESMStore()->get<ESM::Weapon>().find(state.mIdMagic[1])->mModel); MWBase::Environment::get().getESMStore()->get<ESM::Weapon>().find(state.mIdMagic[1])->mModel));
} }
state.mProjectileId = mPhysics->addProjectile(caster, pos, model, true); state.mProjectileId = mPhysics->addProjectile(caster, pos, model, true);
state.mToDelete = false; state.mToDelete = false;

@ -3682,8 +3682,10 @@ namespace MWWorld
if (texture.empty()) if (texture.empty())
texture = Fallback::Map::getString("Blood_Texture_0"); texture = Fallback::Map::getString("Blood_Texture_0");
VFS::Path::Normalized model(Misc::ResourceHelpers::correctMeshPath(std::string{ // [0, 2]
Fallback::Map::getString("Blood_Model_" + std::to_string(Misc::Rng::rollDice(3))) } /*[0, 2]*/)); const int number = Misc::Rng::rollDice(3);
const VFS::Path::Normalized model = Misc::ResourceHelpers::correctMeshPath(
VFS::Path::Normalized(Fallback::Map::getString("Blood_Model_" + std::to_string(number))));
mRendering->spawnEffect(model, texture, worldPosition, 1.0f, false); mRendering->spawnEffect(model, texture, worldPosition, 1.0f, false);
} }

@ -167,11 +167,10 @@ std::string Misc::ResourceHelpers::correctMaterialPath(std::string_view resPath,
return correctResourcePath({ { "materials" } }, resPath, vfs); return correctResourcePath({ { "materials" } }, resPath, vfs);
} }
std::string Misc::ResourceHelpers::correctMeshPath(std::string_view resPath) VFS::Path::Normalized Misc::ResourceHelpers::correctMeshPath(VFS::Path::NormalizedView resPath)
{ {
std::string res = "meshes\\"; static constexpr VFS::Path::NormalizedView prefix("meshes");
res.append(resPath); return prefix / resPath;
return res;
} }
VFS::Path::Normalized Misc::ResourceHelpers::correctSoundPath(VFS::Path::NormalizedView resPath) VFS::Path::Normalized Misc::ResourceHelpers::correctSoundPath(VFS::Path::NormalizedView resPath)
@ -217,45 +216,56 @@ bool Misc::ResourceHelpers::isHiddenMarker(const ESM::RefId& id)
namespace namespace
{ {
std::string getLODMeshNameImpl(std::string resPath, std::string_view pattern) VFS::Path::Normalized getLODMeshNameImpl(VFS::Path::NormalizedView resPath, std::string_view pattern)
{ {
if (auto w = Misc::findExtension(resPath); w != std::string::npos) const std::string_view::size_type position = Misc::findExtension(resPath.value());
resPath.insert(w, pattern); if (position == std::string::npos)
return VFS::Path::normalizeFilename(resPath); return VFS::Path::Normalized(resPath);
std::string withPattern(resPath.value());
withPattern.insert(position, pattern);
return VFS::Path::Normalized(std::move(withPattern));
} }
std::string getBestLODMeshName(std::string const& resPath, const VFS::Manager* vfs, std::string_view pattern) VFS::Path::Normalized getBestLODMeshName(
VFS::Path::NormalizedView resPath, const VFS::Manager& vfs, std::string_view pattern)
{ {
if (std::string result = getLODMeshNameImpl(resPath, pattern); vfs->exists(result)) if (VFS::Path::Normalized result = getLODMeshNameImpl(resPath, pattern); vfs.exists(result))
return result; return result;
return resPath; return VFS::Path::Normalized(resPath);
} }
}
std::string Misc::ResourceHelpers::getLODMeshName( std::string_view getDistantMeshPattern(int esmVersion)
int esmVersion, std::string resPath, const VFS::Manager* vfs, unsigned char lod) {
{ static constexpr std::string_view dist = "_dist";
const std::string distantMeshPattern = [&esmVersion] { static constexpr std::string_view far = "_far";
static constexpr std::string_view lod = "_lod";
switch (esmVersion) switch (esmVersion)
{ {
case ESM::VER_120: case ESM::VER_120:
case ESM::VER_130: case ESM::VER_130:
return "_dist"; return dist;
case ESM::VER_080: case ESM::VER_080:
case ESM::VER_100: case ESM::VER_100:
return "_far"; return far;
case ESM::VER_094: case ESM::VER_094:
case ESM::VER_170: case ESM::VER_170:
return "_lod"; return lod;
default: default:
return ""; return std::string_view();
}
} }
}(); }
VFS::Path::Normalized Misc::ResourceHelpers::getLODMeshName(
int esmVersion, VFS::Path::NormalizedView resPath, const VFS::Manager& vfs, unsigned char lod)
{
const std::string_view distantMeshPattern = getDistantMeshPattern(esmVersion);
for (int l = lod; l >= 0; --l) for (int l = lod; l >= 0; --l)
{ {
std::stringstream patern; std::stringstream patern;
patern << distantMeshPattern << "_" << l; patern << distantMeshPattern << "_" << l;
std::string const meshName = getBestLODMeshName(resPath, vfs, patern.str()); const VFS::Path::Normalized meshName = getBestLODMeshName(resPath, vfs, patern.view());
if (meshName != resPath) if (meshName != resPath)
return meshName; return meshName;
} }

@ -36,8 +36,8 @@ namespace Misc
VFS::Path::Normalized correctActorModelPath(VFS::Path::NormalizedView resPath, const VFS::Manager* vfs); VFS::Path::Normalized correctActorModelPath(VFS::Path::NormalizedView resPath, const VFS::Manager* vfs);
std::string correctMaterialPath(std::string_view resPath, const VFS::Manager* vfs); std::string correctMaterialPath(std::string_view resPath, const VFS::Manager* vfs);
// Adds "meshes\\". // Prepends "meshes/".
std::string correctMeshPath(std::string_view resPath); VFS::Path::Normalized correctMeshPath(VFS::Path::NormalizedView resPath);
// Prepends "sound/". // Prepends "sound/".
VFS::Path::Normalized correctSoundPath(VFS::Path::NormalizedView resPath); VFS::Path::Normalized correctSoundPath(VFS::Path::NormalizedView resPath);
@ -52,7 +52,9 @@ namespace Misc
/// marker objects that have a hardcoded function in the game logic, should be hidden from the player /// marker objects that have a hardcoded function in the game logic, should be hidden from the player
bool isHiddenMarker(const ESM::RefId& id); bool isHiddenMarker(const ESM::RefId& id);
std::string getLODMeshName(int esmVersion, std::string resPath, const VFS::Manager* vfs, unsigned char lod = 0);
VFS::Path::Normalized getLODMeshName(
int esmVersion, VFS::Path::NormalizedView resPath, const VFS::Manager& vfs, unsigned char lod = 0);
} }
} }

@ -119,7 +119,6 @@ local function testRecordStore(store, storeName, skipPairs)
end) end)
testing.expectEqual(status, true, storeName) testing.expectEqual(status, true, storeName)
end end
local function testRecordStores() local function testRecordStores()
@ -159,7 +158,7 @@ local function testRecordCreation()
radius = 30, radius = 30,
color = 5, color = 5,
name = "TestLight", name = "TestLight",
model = "meshes\\marker_door.dae" model = "meshes/marker_door.dae"
} }
local draft = types.Light.createRecordDraft(newLight) local draft = types.Light.createRecordDraft(newLight)
local record = world.createRecord(draft) local record = world.createRecord(draft)
@ -285,6 +284,12 @@ local function testCommitCrime()
testing.expectEqual(types.Player.getCrimeLevel(player), 0, "Crime level should not change if the victim's alarm value is low and there's no other witnesses") testing.expectEqual(types.Player.getCrimeLevel(player), 0, "Crime level should not change if the victim's alarm value is low and there's no other witnesses")
end end
local function testRecordModelProperty()
initPlayer()
local player = world.players[1]
testing.expectEqual(types.NPC.record(player).model, 'meshes/basicplayer.dae')
end
tests = { tests = {
{'timers', testTimers}, {'timers', testTimers},
{'rotating player with controls.yawChange should change rotation', function() {'rotating player with controls.yawChange should change rotation', function()
@ -345,7 +350,8 @@ tests = {
testing.runLocalTest(player, 'playerWeaponAttack') testing.runLocalTest(player, 'playerWeaponAttack')
end}, end},
{'vfs', testVFS}, {'vfs', testVFS},
{'testCommitCrime', testCommitCrime} {'testCommitCrime', testCommitCrime},
{'recordModelProperty', testRecordModelProperty},
} }
return { return {

Loading…
Cancel
Save