diff --git a/CMakeLists.txt b/CMakeLists.txt index 313cc46cbe..d62cda4f2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,7 +72,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 49) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 52) +set(OPENMW_LUA_API_REVISION 53) set(OPENMW_POSTPROCESSING_API_REVISION 1) set(OPENMW_VERSION_COMMITHASH "") diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 01437b2abd..678c4e054b 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -62,7 +62,7 @@ namespace MWClass physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World); } - std::string Activator::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Activator::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } @@ -141,15 +141,14 @@ namespace MWClass ESM::RefId Activator::getSoundIdFromSndGen(const MWWorld::Ptr& ptr, std::string_view name) const { - const std::string model - = getModel(ptr); // Assume it's not empty, since we wouldn't have gotten the soundgen otherwise + // Assume it's not empty, since we wouldn't have gotten the soundgen otherwise + const std::string_view model = getModel(ptr); const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); const ESM::RefId* creatureId = nullptr; for (const ESM::Creature& iter : store.get()) { - if (!iter.mModel.empty() - && Misc::StringUtils::ciEqual(model, Misc::ResourceHelpers::correctMeshPath(iter.mModel))) + if (!iter.mModel.empty() && Misc::StringUtils::ciEqual(model, iter.mModel)) { creatureId = !iter.mOriginal.empty() ? &iter.mOriginal : &iter.mId; break; diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 309e163abe..ec0f1bf282 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -41,7 +41,7 @@ namespace MWClass std::unique_ptr activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const override; ///< Generate action for activation - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; bool useAnim() const override; ///< Whether or not to use animated variant of model (default false) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 1ff7ef5bd6..1bf6f9c845 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -35,7 +35,7 @@ namespace MWClass } } - std::string Apparatus::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Apparatus::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index ce0916c079..c6bd45858a 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -49,7 +49,7 @@ namespace MWClass std::unique_ptr use(const MWWorld::Ptr& ptr, bool force = false) const override; ///< Generate action for using via inventory menu - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; bool canSell(const MWWorld::ConstPtr& item, int npcServices) const override; }; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 28bb1ff35c..ffa5b36a4d 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -44,7 +44,7 @@ namespace MWClass } } - std::string Armor::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Armor::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index d464360623..808bc078f4 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -74,7 +74,7 @@ namespace MWClass std::unique_ptr use(const MWWorld::Ptr& ptr, bool force = false) const override; ///< Generate action for using via inventory menu - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; int getEnchantmentPoints(const MWWorld::ConstPtr& ptr) const override; diff --git a/apps/openmw/mwclass/bodypart.cpp b/apps/openmw/mwclass/bodypart.cpp index 431fb69652..81e42ac725 100644 --- a/apps/openmw/mwclass/bodypart.cpp +++ b/apps/openmw/mwclass/bodypart.cpp @@ -42,7 +42,7 @@ namespace MWClass return false; } - std::string BodyPart::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view BodyPart::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/bodypart.hpp b/apps/openmw/mwclass/bodypart.hpp index 4a2d9d3620..4268c1ecf5 100644 --- a/apps/openmw/mwclass/bodypart.hpp +++ b/apps/openmw/mwclass/bodypart.hpp @@ -25,7 +25,7 @@ namespace MWClass 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; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index d731f56394..2c375547d0 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -41,7 +41,7 @@ namespace MWClass } } - std::string Book::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Book::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index a30e85c107..ca804a32e6 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -54,7 +54,7 @@ namespace MWClass std::unique_ptr use(const MWWorld::Ptr& ptr, bool force = false) const override; ///< Generate action for using via inventory menu - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; int getEnchantmentPoints(const MWWorld::ConstPtr& ptr) const override; diff --git a/apps/openmw/mwclass/classmodel.hpp b/apps/openmw/mwclass/classmodel.hpp index 65c2f87a14..f063ae7292 100644 --- a/apps/openmw/mwclass/classmodel.hpp +++ b/apps/openmw/mwclass/classmodel.hpp @@ -4,22 +4,16 @@ #include "../mwworld/livecellref.hpp" #include "../mwworld/ptr.hpp" -#include -#include - #include +#include namespace MWClass { template - std::string getClassModel(const MWWorld::ConstPtr& ptr) + std::string_view getClassModel(const MWWorld::ConstPtr& ptr) { const MWWorld::LiveCellRef* ref = ptr.get(); - - if (!ref->mBase->mModel.empty()) - return Misc::ResourceHelpers::correctMeshPath(ref->mBase->mModel); - - return {}; + return ref->mBase->mModel; } } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 32a0b62729..17519405de 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -39,7 +39,7 @@ namespace MWClass } } - std::string Clothing::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Clothing::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index a1e8348713..f95559f9c0 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -66,7 +66,7 @@ namespace MWClass std::unique_ptr use(const MWWorld::Ptr& ptr, bool force = false) const override; ///< Generate action for using via inventory menu - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; int getEnchantmentPoints(const MWWorld::ConstPtr& ptr) const override; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 28779f971f..e2023ef8c3 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -126,7 +126,7 @@ namespace MWClass physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World); } - std::string Container::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Container::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 5f8b962e4a..88d8148fdc 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -85,7 +85,7 @@ namespace MWClass void respawn(const MWWorld::Ptr& ptr) const override; - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; bool useAnim() const override; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 66a195489e..d19e5d5c43 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -178,14 +178,14 @@ namespace MWClass objects.insertCreature(ptr, model, hasInventoryStore(ptr)); } - std::string Creature::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Creature::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } - void Creature::getModelsToPreload(const MWWorld::ConstPtr& ptr, std::vector& models) const + void Creature::getModelsToPreload(const MWWorld::ConstPtr& ptr, std::vector& models) const { - std::string model = getModel(ptr); + std::string_view model = getModel(ptr); if (!model.empty()) models.push_back(model); @@ -651,13 +651,13 @@ namespace MWClass if (sounds.empty()) { - const std::string model = getModel(ptr); + const std::string_view model = getModel(ptr); if (!model.empty()) { for (const ESM::Creature& creature : store.get()) { if (creature.mId != ourId && creature.mOriginal != ourId && !creature.mModel.empty() - && Misc::StringUtils::ciEqual(model, Misc::ResourceHelpers::correctMeshPath(creature.mModel))) + && Misc::StringUtils::ciEqual(model, creature.mModel)) { const ESM::RefId& fallbackId = !creature.mOriginal.empty() ? creature.mOriginal : creature.mId; sound = store.get().begin(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 38b7bb0ec1..b8619128c2 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -105,9 +105,9 @@ namespace MWClass float getMaxSpeed(const MWWorld::Ptr& ptr) const override; - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; - void getModelsToPreload(const MWWorld::ConstPtr& ptr, std::vector& models) const override; + void getModelsToPreload(const MWWorld::ConstPtr& ptr, std::vector& models) const override; ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: ///< list getModel(). diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 99acfcf4df..015c454915 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -94,7 +94,7 @@ namespace MWClass return true; } - std::string Door::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Door::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 17ada40c6f..18dd2348ab 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -51,7 +51,7 @@ namespace MWClass ESM::RefId getScript(const MWWorld::ConstPtr& ptr) const override; ///< Return name of the script attached to ptr - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; MWWorld::DoorState getDoorState(const MWWorld::ConstPtr& ptr) const override; /// This does not actually cause the door to move. Use World::activateDoor instead. diff --git a/apps/openmw/mwclass/esm4base.hpp b/apps/openmw/mwclass/esm4base.hpp index 7059ae07cb..f5fd346637 100644 --- a/apps/openmw/mwclass/esm4base.hpp +++ b/apps/openmw/mwclass/esm4base.hpp @@ -96,9 +96,9 @@ namespace MWClass std::string_view getName(const MWWorld::ConstPtr& ptr) const override { return {}; } - std::string getModel(const MWWorld::ConstPtr& ptr) const override + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override { - std::string model = getClassModel(ptr); + std::string_view model = getClassModel(ptr); // Hide meshes meshes/marker/* and *LOD.nif in ESM4 cells. It is a temporarty hack. // Needed because otherwise LOD meshes are rendered on top of normal meshes. diff --git a/apps/openmw/mwclass/esm4npc.cpp b/apps/openmw/mwclass/esm4npc.cpp index 2da7342de4..a7fb0a3544 100644 --- a/apps/openmw/mwclass/esm4npc.cpp +++ b/apps/openmw/mwclass/esm4npc.cpp @@ -175,17 +175,14 @@ namespace MWClass return getCustomData(ptr).mIsFemale; } - std::string ESM4Npc::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view ESM4Npc::getModel(const MWWorld::ConstPtr& ptr) const { const ESM4NpcCustomData& data = getCustomData(ptr); if (data.mTraits == nullptr) return {}; - std::string_view model; if (data.mTraits->mIsTES4) - model = data.mTraits->mModel; - else - model = data.mIsFemale ? data.mRace->mModelFemale : data.mRace->mModelMale; - return Misc::ResourceHelpers::correctMeshPath(model); + return data.mTraits->mModel; + return data.mIsFemale ? data.mRace->mModelFemale : data.mRace->mModelMale; } std::string_view ESM4Npc::getName(const MWWorld::ConstPtr& ptr) const diff --git a/apps/openmw/mwclass/esm4npc.hpp b/apps/openmw/mwclass/esm4npc.hpp index 7830f20f32..39116586f1 100644 --- a/apps/openmw/mwclass/esm4npc.hpp +++ b/apps/openmw/mwclass/esm4npc.hpp @@ -54,7 +54,7 @@ namespace MWClass return ESM4Impl::getToolTipInfo(getName(ptr), count); } - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; std::string_view getName(const MWWorld::ConstPtr& ptr) const override; static const ESM4::Npc* getTraitsRecord(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 6bd28103f8..9af9a5703b 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -39,7 +39,7 @@ namespace MWClass } } - std::string Ingredient::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Ingredient::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index b7a36d300f..2e7632cd5e 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -47,7 +47,7 @@ namespace MWClass const std::string& getInventoryIcon(const MWWorld::ConstPtr& ptr) const override; ///< Return name of inventory icon. - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; float getWeight(const MWWorld::ConstPtr& ptr) const override; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 6e34e3c2bd..dc37b8d154 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -70,7 +70,7 @@ namespace MWClass return true; } - std::string Light::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Light::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 70d6852ff8..97625ee5f8 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -69,7 +69,7 @@ namespace MWClass float getRemainingUsageTime(const MWWorld::ConstPtr& ptr) const override; ///< Returns the remaining duration of the object. - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; float getWeight(const MWWorld::ConstPtr& ptr) const override; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index d3c3d479e4..42b5634b64 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -38,7 +38,7 @@ namespace MWClass } } - std::string Lockpick::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Lockpick::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index fc65a038a6..48c18411a6 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -59,7 +59,7 @@ namespace MWClass std::unique_ptr use(const MWWorld::Ptr& ptr, bool force = false) const override; ///< Generate action for using via inventory menu - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; bool canSell(const MWWorld::ConstPtr& item, int npcServices) const override; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 0f26dfd2df..0470a89a16 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -49,7 +49,7 @@ namespace MWClass } } - std::string Miscellaneous::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Miscellaneous::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index dafeb0c764..6b7b838953 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -45,7 +45,7 @@ namespace MWClass const std::string& getInventoryIcon(const MWWorld::ConstPtr& ptr) const override; ///< Return name of inventory icon. - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; std::unique_ptr use(const MWWorld::Ptr& ptr, bool force = false) const override; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index de587954b8..b8cd4cd23d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/environment.hpp" @@ -424,45 +425,51 @@ namespace MWClass return (ref->mBase->mRecordFlags & ESM::FLAG_Persistent) != 0; } - std::string Npc::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Npc::getModel(const MWWorld::ConstPtr& ptr) const + { + const MWWorld::LiveCellRef* ref = ptr.get(); + std::string_view model = Settings::models().mBaseanim.get(); + const ESM::Race* race = MWBase::Environment::get().getESMStore()->get().find(ref->mBase->mRace); + if (race->mData.mFlags & ESM::Race::Beast) + model = Settings::models().mBaseanimkna.get(); + // Base animations should be in the meshes dir + constexpr std::string_view prefix = "meshes/"; + assert(VFS::Path::pathEqual(prefix, model.substr(0, prefix.size()))); + return model.substr(prefix.size()); + } + + std::string Npc::getCorrectedModel(const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef* ref = ptr.get(); - std::string model = Settings::models().mBaseanim; + const std::string& model = Settings::models().mBaseanim; const ESM::Race* race = MWBase::Environment::get().getESMStore()->get().find(ref->mBase->mRace); if (race->mData.mFlags & ESM::Race::Beast) - model = Settings::models().mBaseanimkna; + return Settings::models().mBaseanimkna; return model; } - void Npc::getModelsToPreload(const MWWorld::ConstPtr& ptr, std::vector& models) const + void Npc::getModelsToPreload(const MWWorld::ConstPtr& ptr, std::vector& models) const { const MWWorld::LiveCellRef* npc = ptr.get(); const auto& esmStore = MWBase::Environment::get().getESMStore(); - const ESM::Race* race = esmStore->get().search(npc->mBase->mRace); - if (race && race->mData.mFlags & ESM::Race::Beast) - models.push_back(Settings::models().mBaseanimkna); - - // keep these always loaded just in case - models.push_back(Settings::models().mXargonianswimkna); - models.push_back(Settings::models().mXbaseanimfemale); - models.push_back(Settings::models().mXbaseanim); + models.push_back(getModel(ptr)); if (!npc->mBase->mModel.empty()) - models.push_back(Misc::ResourceHelpers::correctMeshPath(npc->mBase->mModel)); + models.push_back(npc->mBase->mModel); if (!npc->mBase->mHead.empty()) { const ESM::BodyPart* head = esmStore->get().search(npc->mBase->mHead); if (head) - models.push_back(Misc::ResourceHelpers::correctMeshPath(head->mModel)); + models.push_back(head->mModel); } if (!npc->mBase->mHair.empty()) { const ESM::BodyPart* hair = esmStore->get().search(npc->mBase->mHair); if (hair) - models.push_back(Misc::ResourceHelpers::correctMeshPath(hair->mModel)); + models.push_back(hair->mModel); } bool female = (npc->mBase->mFlags & ESM::NPC::Female); @@ -486,7 +493,7 @@ namespace MWClass const ESM::BodyPart* part = esmStore->get().search(partname); if (part && !part->mModel.empty()) - models.push_back(Misc::ResourceHelpers::correctMeshPath(part->mModel)); + models.push_back(part->mModel); } }; if (equipped->getType() == ESM::Clothing::sRecordId) @@ -501,7 +508,7 @@ namespace MWClass } else { - std::string model = equipped->getClass().getModel(*equipped); + std::string_view model = equipped->getClass().getModel(*equipped); if (!model.empty()) models.push_back(model); } @@ -510,14 +517,14 @@ namespace MWClass } // preload body parts - if (race) + if (const ESM::Race* race = esmStore->get().search(npc->mBase->mRace)) { const std::vector& parts = MWRender::NpcAnimation::getBodyParts(race->mId, female, false, false); for (const ESM::BodyPart* part : parts) { if (part && !part->mModel.empty()) - models.push_back(Misc::ResourceHelpers::correctMeshPath(part->mModel)); + models.push_back(part->mModel); } } } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 95245bb994..1d70c5e1ba 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -85,7 +85,7 @@ namespace MWClass const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful, const MWMechanics::DamageSourceType sourceType) const override; - void getModelsToPreload(const MWWorld::ConstPtr& ptr, std::vector& models) const override; + void getModelsToPreload(const MWWorld::ConstPtr& ptr, std::vector& models) const override; ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: ///< list getModel(). @@ -131,7 +131,9 @@ namespace MWClass ESM::RefId getSoundIdFromSndGen(const MWWorld::Ptr& ptr, std::string_view name) const override; - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; + + std::string getCorrectedModel(const MWWorld::ConstPtr& ptr) const override; float getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const override; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 7cf0c54f5c..e5da876d06 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -38,7 +38,7 @@ namespace MWClass } } - std::string Potion::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Potion::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 66b11b8ef4..057874ca1e 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -47,7 +47,7 @@ namespace MWClass const std::string& getInventoryIcon(const MWWorld::ConstPtr& ptr) const override; ///< Return name of inventory icon. - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; float getWeight(const MWWorld::ConstPtr& ptr) const override; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 96c94339bb..4f5e7be5cb 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -38,7 +38,7 @@ namespace MWClass } } - std::string Probe::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Probe::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 9a66d7a4bf..fc1092546e 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -54,7 +54,7 @@ namespace MWClass std::unique_ptr use(const MWWorld::Ptr& ptr, bool force = false) const override; ///< Generate action for using via inventory menu - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; bool canSell(const MWWorld::ConstPtr& item, int npcServices) const override; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index cf4a42be70..3000ea4087 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -36,7 +36,7 @@ namespace MWClass } } - std::string Repair::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Repair::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index ee96c83eeb..50c58231ce 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -44,7 +44,7 @@ namespace MWClass const std::string& getInventoryIcon(const MWWorld::ConstPtr& ptr) const override; ///< Return name of inventory icon. - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; std::unique_ptr use(const MWWorld::Ptr& ptr, bool force = false) const override; ///< Generate action for using via inventory menu (default implementation: return a diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index fe1226f19b..502a4fcb66 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -43,7 +43,7 @@ namespace MWClass physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World); } - std::string Static::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Static::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index 65f60f7653..a3ea68a86f 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -32,7 +32,7 @@ namespace MWClass 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; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 2c9a9b5c7a..b5a3415717 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -43,7 +43,7 @@ namespace MWClass } } - std::string Weapon::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Weapon::getModel(const MWWorld::ConstPtr& ptr) const { return getClassModel(ptr); } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 110069341d..9e79532bc0 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -72,7 +72,7 @@ namespace MWClass std::unique_ptr use(const MWWorld::Ptr& ptr, bool force = false) const override; ///< Generate action for using via inventory menu - std::string getModel(const MWWorld::ConstPtr& ptr) const override; + std::string_view getModel(const MWWorld::ConstPtr& ptr) const override; bool canSell(const MWWorld::ConstPtr& item, int npcServices) const override; diff --git a/apps/openmw/mwlua/object.hpp b/apps/openmw/mwlua/object.hpp index b42b092302..d032515314 100644 --- a/apps/openmw/mwlua/object.hpp +++ b/apps/openmw/mwlua/object.hpp @@ -71,6 +71,12 @@ namespace MWLua { Obj mObj; }; + + template + struct Owner + { + Obj mObj; + }; } #endif // MWLUA_OBJECT_H diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 2a30e31948..c594af2944 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -200,6 +200,80 @@ namespace MWLua return Misc::Convert::makeOsgQuat(pos.rot); } + template + void addOwnerbindings(sol::usertype& objectT, const std::string& prefix, const Context& context) + { + using OwnerT = Owner; + sol::usertype ownerT = context.mLua->sol().new_usertype(prefix + "Owner"); + + ownerT[sol::meta_function::to_string] = [](const OwnerT& o) { return "Owner[" + o.mObj.toString() + "]"; }; + + auto getOwnerRecordId = [](const OwnerT& o) -> sol::optional { + ESM::RefId owner = o.mObj.ptr().getCellRef().getOwner(); + if (owner.empty()) + return sol::nullopt; + else + return owner.serializeText(); + }; + auto setOwnerRecordId = [](const OwnerT& o, sol::optional ownerId) { + if (std::is_same_v && !dynamic_cast(&o.mObj)) + throw std::runtime_error("Local scripts can set an owner only on self"); + const MWWorld::Ptr& ptr = o.mObj.ptr(); + + if (!ownerId) + { + ptr.getCellRef().setOwner(ESM::RefId()); + return; + } + ESM::RefId owner = ESM::RefId::deserializeText(*ownerId); + const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); + if (!store.get().search(owner)) + throw std::runtime_error("Invalid owner record id"); + ptr.getCellRef().setOwner(owner); + }; + ownerT["recordId"] = sol::property(getOwnerRecordId, setOwnerRecordId); + + auto getOwnerFactionId = [](const OwnerT& o) -> sol::optional { + ESM::RefId owner = o.mObj.ptr().getCellRef().getFaction(); + if (owner.empty()) + return sol::nullopt; + else + return owner.serializeText(); + }; + auto setOwnerFactionId = [](const OwnerT& o, sol::optional ownerId) { + ESM::RefId ownerFac; + if (std::is_same_v && !dynamic_cast(&o.mObj)) + throw std::runtime_error("Local scripts can set an owner faction only on self"); + if (!ownerId) + { + o.mObj.ptr().getCellRef().setFaction(ESM::RefId()); + return; + } + ownerFac = ESM::RefId::deserializeText(*ownerId); + const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); + if (!store.get().search(ownerFac)) + throw std::runtime_error("Invalid owner faction id"); + o.mObj.ptr().getCellRef().setFaction(ownerFac); + }; + ownerT["factionId"] = sol::property(getOwnerFactionId, setOwnerFactionId); + + auto getOwnerFactionRank = [](const OwnerT& o) -> sol::optional { + int rank = o.mObj.ptr().getCellRef().getFactionRank(); + if (rank < 0) + return sol::nullopt; + else + return rank; + }; + auto setOwnerFactionRank = [](const OwnerT& o, sol::optional factionRank) { + if (std::is_same_v && !dynamic_cast(&o.mObj)) + throw std::runtime_error("Local scripts can set an owner faction rank only on self"); + o.mObj.ptr().getCellRef().setFactionRank(factionRank.value_or(-1)); + }; + ownerT["factionRank"] = sol::property(getOwnerFactionRank, setOwnerFactionRank); + + objectT["owner"] = sol::readonly_property([](const ObjectT& object) { return OwnerT{ object }; }); + } + template void addBasicBindings(sol::usertype& objectT, const Context& context) { @@ -266,68 +340,6 @@ namespace MWLua context.mLuaEvents->addLocalEvent( { dest.id(), std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) }); }; - auto getOwnerRecordId = [](const ObjectT& o) -> sol::optional { - ESM::RefId owner = o.ptr().getCellRef().getOwner(); - if (owner.empty()) - return sol::nullopt; - else - return owner.serializeText(); - }; - auto setOwnerRecordId = [](const ObjectT& obj, sol::optional ownerId) { - if (std::is_same_v && !dynamic_cast(&obj)) - throw std::runtime_error("Local scripts can set an owner only on self"); - const MWWorld::Ptr& ptr = obj.ptr(); - - if (!ownerId) - { - ptr.getCellRef().setOwner(ESM::RefId()); - return; - } - ESM::RefId owner = ESM::RefId::deserializeText(*ownerId); - const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); - if (!store.get().search(owner)) - throw std::runtime_error("Invalid owner record id"); - ptr.getCellRef().setOwner(owner); - }; - objectT["ownerRecordId"] = sol::property(getOwnerRecordId, setOwnerRecordId); - - auto getOwnerFactionId = [](const ObjectT& o) -> sol::optional { - ESM::RefId owner = o.ptr().getCellRef().getFaction(); - if (owner.empty()) - return sol::nullopt; - else - return owner.serializeText(); - }; - auto setOwnerFactionId = [](const ObjectT& object, sol::optional ownerId) { - ESM::RefId ownerFac; - if (std::is_same_v && !dynamic_cast(&object)) - throw std::runtime_error("Local scripts can set an owner faction only on self"); - if (!ownerId) - { - object.ptr().getCellRef().setFaction(ESM::RefId()); - return; - } - ownerFac = ESM::RefId::deserializeText(*ownerId); - const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); - if (!store.get().search(ownerFac)) - throw std::runtime_error("Invalid owner faction id"); - object.ptr().getCellRef().setFaction(ownerFac); - }; - objectT["ownerFactionId"] = sol::property(getOwnerFactionId, setOwnerFactionId); - - auto getOwnerFactionRank = [](const ObjectT& o) -> sol::optional { - int rank = o.ptr().getCellRef().getFactionRank(); - if (rank < 0) - return sol::nullopt; - else - return rank; - }; - auto setOwnerFactionRank = [](const ObjectT& object, sol::optional factionRank) { - if (std::is_same_v && !dynamic_cast(&object)) - throw std::runtime_error("Local scripts can set an owner faction rank only on self"); - object.ptr().getCellRef().setFactionRank(factionRank.value_or(-1)); - }; - objectT["ownerFactionRank"] = sol::property(getOwnerFactionRank, setOwnerFactionRank); objectT["activateBy"] = [](const ObjectT& object, const ObjectT& actor) { const MWWorld::Ptr& objPtr = object.ptr(); @@ -672,6 +684,7 @@ namespace MWLua = context.mLua->sol().new_usertype(prefix + "Object", sol::base_classes, sol::bases()); addBasicBindings(objectT, context); addInventoryBindings(objectT, prefix, context); + addOwnerbindings(objectT, prefix, context); registerObjectList(prefix, context); } diff --git a/apps/openmw/mwlua/uibindings.cpp b/apps/openmw/mwlua/uibindings.cpp index b5bd30fbe6..f21fdb337a 100644 --- a/apps/openmw/mwlua/uibindings.cpp +++ b/apps/openmw/mwlua/uibindings.cpp @@ -241,7 +241,7 @@ namespace MWLua for (unsigned i = 0; i < newStack.size(); ++i) newStack[i] = nameToMode.at(LuaUtil::cast(modes[i + 1])); luaManager->addAction( - [windowManager, newStack = std::move(newStack), arg]() { + [windowManager, newStack = std::move(newStack), arg = std::move(arg)]() { MWWorld::Ptr ptr; if (arg.has_value()) ptr = arg->ptr(); diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index 2c70cd0436..7da29a1cf0 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -134,7 +134,7 @@ namespace MWRender } } } - return shield.getClass().getModel(shield); + return shield.getClass().getCorrectedModel(shield); } std::string ActorAnimation::getSheathedShieldMesh(const MWWorld::ConstPtr& shield) const @@ -339,7 +339,7 @@ namespace MWRender if (MWMechanics::getWeaponType(type)->mWeaponClass == ESM::WeaponType::Thrown) showHolsteredWeapons = false; - std::string mesh = weapon->getClass().getModel(*weapon); + std::string mesh = weapon->getClass().getCorrectedModel(*weapon); std::string scabbardName = mesh; std::string_view boneName = getHolsteredWeaponBoneName(*weapon); @@ -409,7 +409,7 @@ namespace MWRender if (weapon == inv.end() || weapon->getType() != ESM::Weapon::sRecordId) return; - std::string mesh = weapon->getClass().getModel(*weapon); + std::string_view mesh = weapon->getClass().getModel(*weapon); std::string_view boneName = getHolsteredWeaponBoneName(*weapon); if (mesh.empty() || boneName.empty()) return; @@ -466,7 +466,7 @@ namespace MWRender // Add new ones osg::Vec4f glowColor = ammo->getClass().getEnchantmentColor(*ammo); - std::string model = ammo->getClass().getModel(*ammo); + std::string model = ammo->getClass().getCorrectedModel(*ammo); for (unsigned int i = 0; i < ammoCount; ++i) { osg::ref_ptr arrowNode = ammoNode->getChild(i)->asGroup(); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 58e03aa0a2..b56035eb5f 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -110,7 +110,7 @@ namespace MWRender MWWorld::ConstPtr item = *it; std::string_view bonename; - std::string itemModel = item.getClass().getModel(item); + std::string itemModel = item.getClass().getCorrectedModel(item); if (slot == MWWorld::InventoryStore::Slot_CarriedRight) { if (item.getType() == ESM::Weapon::sRecordId) diff --git a/apps/openmw/mwrender/esm4npcanimation.cpp b/apps/openmw/mwrender/esm4npcanimation.cpp index 7771735920..4193fb60b4 100644 --- a/apps/openmw/mwrender/esm4npcanimation.cpp +++ b/apps/openmw/mwrender/esm4npcanimation.cpp @@ -22,7 +22,7 @@ namespace MWRender const MWWorld::Ptr& ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem) : Animation(ptr, std::move(parentNode), resourceSystem) { - setObjectRoot(mPtr.getClass().getModel(mPtr), true, true, false); + setObjectRoot(mPtr.getClass().getCorrectedModel(mPtr), true, true, false); updateParts(); } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 1467f8e737..61260e687e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -952,7 +952,7 @@ namespace MWRender if (weapon != inv.end()) { osg::Vec4f glowColor = weapon->getClass().getEnchantmentColor(*weapon); - std::string mesh = weapon->getClass().getModel(*weapon); + std::string mesh = weapon->getClass().getCorrectedModel(*weapon); addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor); @@ -1012,7 +1012,7 @@ namespace MWRender if (show && iter != inv.end()) { osg::Vec4f glowColor = iter->getClass().getEnchantmentColor(*iter); - std::string mesh = iter->getClass().getModel(*iter); + std::string mesh = iter->getClass().getCorrectedModel(*iter); // For shields we must try to use the body part model if (iter->getType() == ESM::Armor::sRecordId) { diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c2c6abd1bc..15faabb6df 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1497,7 +1497,7 @@ namespace MWRender osg::Vec3f RenderingManager::getHalfExtents(const MWWorld::ConstPtr& object) const { osg::Vec3f halfExtents(0, 0, 0); - std::string modelName = object.getClass().getModel(object); + std::string modelName = object.getClass().getCorrectedModel(object); if (modelName.empty()) return halfExtents; @@ -1519,7 +1519,7 @@ namespace MWRender osg::BoundingBox RenderingManager::getCullSafeBoundingBox(const MWWorld::Ptr& ptr) const { - const std::string model = ptr.getClass().getModel(ptr); + const std::string model = ptr.getClass().getCorrectedModel(ptr); if (model.empty()) return {}; diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index c19062168e..5db2a5e196 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -86,7 +86,7 @@ namespace MWRender MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); if (ammo == inv.end()) return; - std::string model = ammo->getClass().getModel(*ammo); + std::string model = ammo->getClass().getCorrectedModel(*ammo); osg::ref_ptr arrow = getResourceSystem()->getSceneManager()->getInstance(model, parent); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 476cacafd0..481a0e2ec1 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1435,7 +1435,7 @@ namespace MWScript msg << "Coordinates: " << pos.x() << " " << pos.y() << " " << pos.z() << std::endl; auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); std::string model - = ::Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr), vfs); + = ::Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getCorrectedModel(ptr), vfs); msg << "Model: " << model << std::endl; if (!model.empty()) { @@ -1711,7 +1711,7 @@ namespace MWScript for (const T& record : store.get()) { MWWorld::ManualRef ref(store, record.mId); - std::string model = ref.getPtr().getClass().getModel(ref.getPtr()); + std::string model = ref.getPtr().getClass().getCorrectedModel(ref.getPtr()); if (!model.empty()) { sceneManager->getTemplate(model); diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index fe14856364..364f3e169e 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,7 @@ namespace MWWorld return true; } - std::vector& mOut; + std::vector& mOut; }; /// Worker thread item: preload models in a cell. @@ -105,28 +106,28 @@ namespace MWWorld } } - for (std::string& mesh : mMeshes) + std::string mesh; + std::string kfname; + for (std::string_view path : mMeshes) { if (mAbort) break; try { + mesh = Misc::ResourceHelpers::correctMeshPath(path); mesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mSceneManager->getVFS()); size_t slashpos = mesh.find_last_of("/\\"); if (slashpos != std::string::npos && slashpos != mesh.size() - 1) { - Misc::StringUtils::lowerCaseInPlace(mesh); - if (mesh[slashpos + 1] == 'x') + if (Misc::StringUtils::toLower(mesh[slashpos + 1]) == 'x' + && Misc::StringUtils::ciEndsWith(mesh, ".nif")) { - if (mesh.size() > 4 && mesh.ends_with(".nif")) - { - std::string kfname = mesh; - kfname.replace(kfname.size() - 4, 4, ".kf"); - if (mSceneManager->getVFS()->exists(kfname)) - mPreloadedObjects.insert(mKeyframeManager->get(kfname)); - } + kfname = mesh; + kfname.replace(kfname.size() - 4, 4, ".kf"); + if (mSceneManager->getVFS()->exists(kfname)) + mPreloadedObjects.insert(mKeyframeManager->get(kfname)); } } mPreloadedObjects.insert(mSceneManager->getTemplate(mesh)); @@ -144,11 +145,10 @@ namespace MWWorld } private: - typedef std::vector MeshList; bool mIsExterior; int mX; int mY; - MeshList mMeshes; + std::vector mMeshes; Resource::SceneManager* mSceneManager; Resource::BulletShapeManager* mBulletShapeManager; Resource::KeyframeManager* mKeyframeManager; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 82aa83e7c6..932c290aaa 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -305,19 +306,27 @@ namespace MWWorld void Class::adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const {} - std::string Class::getModel(const MWWorld::ConstPtr& ptr) const + std::string_view Class::getModel(const MWWorld::ConstPtr& ptr) const { return {}; } + std::string Class::getCorrectedModel(const MWWorld::ConstPtr& ptr) const + { + std::string_view model = getModel(ptr); + if (!model.empty()) + return Misc::ResourceHelpers::correctMeshPath(model); + return {}; + } + bool Class::useAnim() const { return false; } - void Class::getModelsToPreload(const ConstPtr& ptr, std::vector& models) const + void Class::getModelsToPreload(const ConstPtr& ptr, std::vector& models) const { - std::string model = getModel(ptr); + std::string_view model = getModel(ptr); if (!model.empty()) models.push_back(model); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index c787505238..0c6d55692f 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -275,12 +275,14 @@ namespace MWWorld virtual int getServices(const MWWorld::ConstPtr& actor) const; - virtual std::string getModel(const MWWorld::ConstPtr& ptr) const; + virtual std::string_view getModel(const MWWorld::ConstPtr& ptr) const; + + virtual std::string getCorrectedModel(const MWWorld::ConstPtr& ptr) const; virtual bool useAnim() const; ///< Whether or not to use animated variant of model (default false) - virtual void getModelsToPreload(const MWWorld::ConstPtr& ptr, std::vector& models) const; + virtual void getModelsToPreload(const MWWorld::ConstPtr& ptr, std::vector& models) const; ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: ///< list getModel(). diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index b25d138814..6fc515981b 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -311,7 +311,7 @@ namespace MWWorld osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects); - auto model = ptr.getClass().getModel(ptr); + auto model = ptr.getClass().getCorrectedModel(ptr); createModel(state, model, pos, orient, true, true, lightDiffuseColor, texture); MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager(); @@ -351,7 +351,7 @@ namespace MWWorld MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - const auto model = ptr.getClass().getModel(ptr); + const auto model = ptr.getClass().getCorrectedModel(ptr); createModel(state, model, pos, orient, false, false, osg::Vec4(0, 0, 0, 0)); if (!ptr.getClass().getEnchantment(ptr).empty()) SceneUtil::addEnchantedGlow(state.mNode, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr)); @@ -696,7 +696,7 @@ namespace MWWorld { MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), esm.mId); MWWorld::Ptr ptr = ref.getPtr(); - model = ptr.getClass().getModel(ptr); + model = ptr.getClass().getCorrectedModel(ptr); int weaponType = ptr.get()->mBase->mData.mType; state.mThrown = MWMechanics::getWeaponType(weaponType)->mWeaponClass == ESM::WeaponType::Thrown; @@ -749,7 +749,7 @@ namespace MWWorld { MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), state.mIdMagic.at(0)); MWWorld::Ptr ptr = ref.getPtr(); - model = ptr.getClass().getModel(ptr); + model = ptr.getClass().getCorrectedModel(ptr); } catch (...) { diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 80f52f2375..8424076758 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -96,7 +96,7 @@ namespace { if (Misc::ResourceHelpers::isHiddenMarker(ptr.getCellRef().getRefId())) return {}; - return ptr.getClass().getModel(ptr); + return ptr.getClass().getCorrectedModel(ptr); } void addObject(const MWWorld::Ptr& ptr, const MWWorld::World& world, const std::vector& pagedRefs, diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a265ff0a76..689edaf62e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2306,7 +2306,7 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->watchActor(getPlayerPtr()); mPhysics->remove(getPlayerPtr()); - mPhysics->addActor(getPlayerPtr(), getPlayerPtr().getClass().getModel(getPlayerPtr())); + mPhysics->addActor(getPlayerPtr(), getPlayerPtr().getClass().getCorrectedModel(getPlayerPtr())); applyLoopingParticles(player); @@ -3696,7 +3696,7 @@ namespace MWWorld try { MWWorld::ManualRef ref(store, obj); - std::string model = ref.getPtr().getClass().getModel(ref.getPtr()); + std::string model = ref.getPtr().getClass().getCorrectedModel(ref.getPtr()); if (!model.empty()) scene->preload(model, ref.getPtr().getClass().useAnim()); } diff --git a/files/lua_api/CMakeLists.txt b/files/lua_api/CMakeLists.txt index 06c90e4633..0b960ea259 100644 --- a/files/lua_api/CMakeLists.txt +++ b/files/lua_api/CMakeLists.txt @@ -10,18 +10,23 @@ set(LUA_API_FILES string.doclua table.doclua openmw/ambient.lua + openmw/animation.lua openmw/async.lua + openmw/camera.lua openmw/core.lua openmw/debug.lua + openmw/input.lua + openmw/interfaces.lua + openmw/menu.lua openmw/nearby.lua openmw/postprocessing.lua openmw/self.lua + openmw/storage.lua openmw/types.lua openmw/ui.lua openmw/util.lua openmw/vfs.lua openmw/world.lua - openmw/menu.lua ) foreach (f ${LUA_API_FILES}) diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 33f21a6cce..ca2da8bb23 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -164,9 +164,7 @@ -- @field openmw.util#Transform rotation Object rotation. -- @field openmw.util#Vector3 startingPosition The object original position -- @field openmw.util#Transform startingRotation The object original rotation --- @field #string ownerRecordId NPC who owns the object (nil if missing). Global and self scripts can set the value. --- @field #string ownerFactionId Faction who owns the object (nil if missing). Global and self scripts can set the value. --- @field #number ownerFactionRank Rank required to be allowed to pick up the object (`nil` if any rank is allowed). Global and self scripts can set the value. +-- @field #ObjectOwner owner Ownership information -- @field #Cell cell The cell where the object currently is. During loading a game and for objects in an inventory or a container `cell` is nil. -- @field #GameObject parentContainer Container or actor that contains (or has in inventory) this object. It is nil if the object is in a cell. -- @field #any type Type of the object (one of the tables from the package @{openmw.types#types}). @@ -174,6 +172,14 @@ -- @field #string recordId Returns record ID of the object in lowercase. -- @field #string globalVariable Global Variable associated with this object(read only). + +--- +-- Object owner information +-- @type ObjectOwner +-- @field #string recordId NPC who owns the object (nil if missing). Global and self scripts can set the value. +-- @field #string factionId Faction who owns the object (nil if missing). Global and self scripts can set the value. +-- @field #number factionRank Rank required to be allowed to pick up the object (`nil` if any rank is allowed). Global and self scripts can set the value. + --- -- Does the object still exist and is available. -- Returns true if the object exists and loaded, and false otherwise. If false, then every