From 607bd8b8535b0021c87d149d64c14c3cde03d58e Mon Sep 17 00:00:00 2001 From: MAtahualpa Date: Tue, 14 Feb 2017 11:48:37 +0100 Subject: [PATCH 1/7] Replace "Scroll" check box with a combo box (fixes #3748) Replaces the "Scroll" check box in Book records with a "Book Type" combo box. Related issue: - Fixes #3748: OpenMW-CS: Replace "Scroll" check box in Book records with "Book Type" combo box. (https://bugs.openmw.org/issues/3748) Tests: The changes were successfully tested in OpenMW-CS by manipulating several Book records. Please note that the actual logic behind this entry is not implemented yet: Books which are of type "Scroll" can have an enchantment attached, normal books ("Book") cannot. --- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columns.cpp | 8 +++++++- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/refidadapterimp.cpp | 8 ++++---- apps/opencs/model/world/refidadapterimp.hpp | 4 ++-- apps/opencs/model/world/refidcollection.cpp | 6 +++--- apps/opencs/view/doc/viewmanager.cpp | 1 + 7 files changed, 19 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 1eb6a88c1..951af4b6a 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -131,6 +131,7 @@ namespace CSMWorld Display_InfoCondComp, Display_String32, Display_LongString256, + Display_BookType, Display_EffectSkill, // must display at least one, unlike Display_Skill Display_EffectAttribute, // must display at least one, unlike Display_Attribute diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 028a759dc..5c041894f 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -98,7 +98,7 @@ namespace CSMWorld { ColumnId_ArmorType, "Armor Type" }, { ColumnId_Health, "Health" }, { ColumnId_ArmorValue, "Armor Value" }, - { ColumnId_Scroll, "Scroll" }, + { ColumnId_BookType, "Book Type" }, { ColumnId_ClothingType, "Clothing Type" }, { ColumnId_WeightCapacity, "Weight Capacity" }, { ColumnId_OrganicContainer, "Organic Container" }, @@ -553,6 +553,11 @@ namespace "AI Wander", "AI Travel", "AI Follow", "AI Escort", "AI Activate", 0 }; + static const char *sBookType[] = + { + "Book", "Scroll", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -582,6 +587,7 @@ namespace case CSMWorld::Columns::ColumnId_AiPackageType: return sAiPackageType; case CSMWorld::Columns::ColumnId_InfoCondFunc: return CSMWorld::ConstInfoSelectWrapper::FunctionEnumStrings; case CSMWorld::Columns::ColumnId_InfoCondComp: return CSMWorld::ConstInfoSelectWrapper::RelationEnumStrings; + case CSMWorld::Columns::ColumnId_BookType: return sBookType; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index e3899af73..c1586bf6c 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -92,7 +92,7 @@ namespace CSMWorld ColumnId_ArmorType = 77, ColumnId_Health = 78, ColumnId_ArmorValue = 79, - ColumnId_Scroll = 80, + ColumnId_BookType = 80, ColumnId_ClothingType = 81, ColumnId_WeightCapacity = 82, ColumnId_OrganicContainer = 83, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 0da4769a8..7d0927c8b 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -301,9 +301,9 @@ void CSMWorld::ArmorRefIdAdapter::setData (const RefIdColumn *column, RefIdData& } CSMWorld::BookRefIdAdapter::BookRefIdAdapter (const EnchantableColumns& columns, - const RefIdColumn *scroll, const RefIdColumn *skill, const RefIdColumn *text) + const RefIdColumn *bookType, const RefIdColumn *skill, const RefIdColumn *text) : EnchantableRefIdAdapter (UniversalId::Type_Book, columns), - mScroll (scroll), mSkill (skill), mText (text) + mBookType (bookType), mSkill (skill), mText (text) {} QVariant CSMWorld::BookRefIdAdapter::getData (const RefIdColumn *column, @@ -312,7 +312,7 @@ QVariant CSMWorld::BookRefIdAdapter::getData (const RefIdColumn *column, const Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Book))); - if (column==mScroll) + if (column==mBookType) return record.get().mData.mIsScroll!=0; if (column==mSkill) @@ -332,7 +332,7 @@ void CSMWorld::BookRefIdAdapter::setData (const RefIdColumn *column, RefIdData& ESM::Book book = record.get(); - if (column==mScroll) + if (column==mBookType) book.mData.mIsScroll = value.toInt(); else if (column==mSkill) book.mData.mSkillId = value.toInt(); diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 757a8ad77..390d1f1b4 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -694,13 +694,13 @@ namespace CSMWorld class BookRefIdAdapter : public EnchantableRefIdAdapter { - const RefIdColumn *mScroll; + const RefIdColumn *mBookType; const RefIdColumn *mSkill; const RefIdColumn *mText; public: - BookRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *scroll, + BookRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *bookType, const RefIdColumn *skill, const RefIdColumn *text); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 5674ba327..150077fd8 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -291,8 +291,8 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_ArmorValue, ColumnBase::Display_Integer)); const RefIdColumn *armor = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Scroll, ColumnBase::Display_Boolean)); - const RefIdColumn *scroll = &mColumns.back(); + mColumns.push_back (RefIdColumn (Columns::ColumnId_BookType, ColumnBase::Display_BookType)); + const RefIdColumn *bookType = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId)); const RefIdColumn *skill = &mColumns.back(); @@ -659,7 +659,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Armor, new ArmorRefIdAdapter (enchantableColumns, armorType, health, armor, partRef))); mAdapters.insert (std::make_pair (UniversalId::Type_Book, - new BookRefIdAdapter (enchantableColumns, scroll, skill, text))); + new BookRefIdAdapter (enchantableColumns, bookType, skill, text))); mAdapters.insert (std::make_pair (UniversalId::Type_Clothing, new ClothingRefIdAdapter (enchantableColumns, clothingType, partRef))); mAdapters.insert (std::make_pair (UniversalId::Type_Container, diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 024636f34..12d52d3dd 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -107,6 +107,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_IngredEffectId, CSMWorld::Columns::ColumnId_EffectId, true }, { CSMWorld::ColumnBase::Display_EffectSkill, CSMWorld::Columns::ColumnId_Skill, false }, { CSMWorld::ColumnBase::Display_EffectAttribute, CSMWorld::Columns::ColumnId_Attribute, false }, + { CSMWorld::ColumnBase::Display_BookType, CSMWorld::Columns::ColumnId_BookType, false}, }; for (std::size_t i=0; i Date: Wed, 15 Feb 2017 18:59:55 +0100 Subject: [PATCH 2/7] Replace "Scroll" check box with a combo box (fixes #3748) Replaces the "Scroll" check box in Book records with a "Book Type" combo box. Related issue: - Fixes #3748: OpenMW-CS: Replace "Scroll" check box in Book records with "Book Type" combo box. (https://bugs.openmw.org/issues/3748) Tests: The changes were successfully tested in OpenMW-CS by manipulating several Book records. Please note that the actual logic behind this entry is not implemented yet: Books which are of type "Scroll" can have an enchantment attached, normal books ("Book") cannot. --- apps/opencs/model/world/refidadapterimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 7d0927c8b..fb19d943b 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -313,7 +313,7 @@ QVariant CSMWorld::BookRefIdAdapter::getData (const RefIdColumn *column, data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Book))); if (column==mBookType) - return record.get().mData.mIsScroll!=0; + return record.get().mData.mIsScroll; if (column==mSkill) return record.get().mData.mSkillId; From 57b585570a6e4a76716497e0eee66fc01b0ab58d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Feb 2017 00:55:35 +0100 Subject: [PATCH 3/7] Preload magic effect visuals of the player's selected weapon/spell --- apps/openmw/mwbase/windowmanager.hpp | 2 + apps/openmw/mwbase/world.hpp | 3 ++ apps/openmw/mwgui/hud.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 15 ++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 6 +++ apps/openmw/mwworld/scene.cpp | 30 ++++++++++++ apps/openmw/mwworld/scene.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 68 +++++++++++++++++++++++++- apps/openmw/mwworld/worldimp.hpp | 7 +++ components/resource/objectcache.cpp | 12 +++++ components/resource/objectcache.hpp | 3 ++ components/resource/scenemanager.cpp | 8 +++ components/resource/scenemanager.hpp | 3 ++ 13 files changed, 158 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 3a53c3253..f103ce191 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -215,7 +215,9 @@ namespace MWBase virtual std::string getSelectedSpell() = 0; virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; virtual void setSelectedEnchantItem(const MWWorld::Ptr& item) = 0; + virtual const MWWorld::Ptr& getSelectedEnchantItem() const = 0; virtual void setSelectedWeapon(const MWWorld::Ptr& item) = 0; + virtual const MWWorld::Ptr& getSelectedWeapon() const = 0; virtual void unsetSelectedSpell() = 0; virtual void unsetSelectedWeapon() = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 59f28fcc8..86d26d3a7 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -569,6 +569,9 @@ namespace MWBase /// Export scene graph to a file and return the filename. /// \param ptr object to export scene graph for (if empty, export entire scene graph) virtual std::string exportSceneGraph(const MWWorld::Ptr& ptr) = 0; + + /// Preload VFX associated with this effect list + virtual void preloadEffects(const ESM::EffectList* effectList) = 0; }; } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index c5ae45789..e2ef52be0 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -39,6 +39,7 @@ namespace MWGui void setSelectedSpell(const std::string& spellId, int successChancePercent); void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); + const MWWorld::Ptr& getSelectedEnchantItem(); void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent); void unsetSelectedSpell(); void unsetSelectedWeapon(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 937463ecd..55c9355a1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1282,6 +1282,7 @@ namespace MWGui void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) { mSelectedSpell = spellId; + mSelectedEnchantItem = MWWorld::Ptr(); mHud->setSelectedSpell(spellId, successChancePercent); const ESM::Spell* spell = mStore->get().find(spellId); @@ -1291,6 +1292,7 @@ namespace MWGui void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) { + mSelectedEnchantItem = item; mSelectedSpell = ""; const ESM::Enchantment* ench = mStore->get() .find(item.getClass().getEnchantment(item)); @@ -1301,17 +1303,29 @@ namespace MWGui mSpellWindow->setTitle(item.getClass().getName(item)); } + const MWWorld::Ptr &WindowManager::getSelectedEnchantItem() const + { + return mSelectedEnchantItem; + } + void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) { + mSelectedWeapon = item; int durabilityPercent = static_cast(item.getClass().getItemHealth(item) / static_cast(item.getClass().getItemMaxHealth(item)) * 100); mHud->setSelectedWeapon(item, durabilityPercent); mInventoryWindow->setTitle(item.getClass().getName(item)); } + const MWWorld::Ptr &WindowManager::getSelectedWeapon() const + { + return mSelectedWeapon; + } + void WindowManager::unsetSelectedSpell() { mSelectedSpell = ""; + mSelectedEnchantItem = MWWorld::Ptr(); mHud->unsetSelectedSpell(); MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer(); @@ -1323,6 +1337,7 @@ namespace MWGui void WindowManager::unsetSelectedWeapon() { + mSelectedWeapon = MWWorld::Ptr(); mHud->unsetSelectedWeapon(); mInventoryWindow->setTitle("#{sSkillHandtohand}"); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 4e2cef8af..a8f6263c2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -13,6 +13,8 @@ #include "../mwbase/windowmanager.hpp" +#include "../mwworld/ptr.hpp" + #include #include @@ -244,7 +246,9 @@ namespace MWGui virtual std::string getSelectedSpell() { return mSelectedSpell; } virtual void setSelectedSpell(const std::string& spellId, int successChancePercent); virtual void setSelectedEnchantItem(const MWWorld::Ptr& item); + virtual const MWWorld::Ptr& getSelectedEnchantItem() const; virtual void setSelectedWeapon(const MWWorld::Ptr& item); + virtual const MWWorld::Ptr& getSelectedWeapon() const; virtual void unsetSelectedSpell(); virtual void unsetSelectedWeapon(); @@ -403,6 +407,8 @@ namespace MWGui void onWindowChangeCoord(MyGUI::Window* _sender); std::string mSelectedSpell; + MWWorld::Ptr mSelectedEnchantItem; + MWWorld::Ptr mSelectedWeapon; std::stack mCurrentModals; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8a3178e6c..0e8a1fecb 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -652,6 +653,35 @@ namespace MWWorld return Ptr(); } + class PreloadMeshItem : public SceneUtil::WorkItem + { + public: + PreloadMeshItem(const std::string& mesh, Resource::SceneManager* sceneManager) + : mMesh(mesh), mSceneManager(sceneManager) + { + } + + virtual void doWork() + { + try + { + mSceneManager->getTemplate(mMesh); + } + catch (std::exception& e) + { + } + } + private: + std::string mMesh; + Resource::SceneManager* mSceneManager; + }; + + void Scene::preload(const std::string &mesh) + { + if (!mRendering.getResourceSystem()->getSceneManager()->checkLoaded(mesh, mRendering.getReferenceTime())) + mRendering.getWorkQueue()->addWorkItem(new PreloadMeshItem(mesh, mRendering.getResourceSystem()->getSceneManager())); + } + void Scene::preloadCells(float dt) { const MWWorld::ConstPtr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 328538076..cbceb14f5 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -132,6 +132,8 @@ namespace MWWorld bool isCellActive(const CellStore &cell); Ptr searchPtrViaActorId (int actorId); + + void preload(const std::string& mesh); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 399525a8e..83b2b4d54 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -152,7 +152,7 @@ namespace MWWorld mGodMode(false), mScriptsEnabled(true), mContentFiles (contentFiles), mUserDataPath(userDataPath), mActivationDistanceOverride (activationDistanceOverride), mStartupScript(startupScript), mStartCell (startCell), mDistanceToFacedObject(-1), mTeleportEnabled(true), - mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0) + mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0), mSpellPreloadTimer(0.f) { mPhysics = new MWPhysics::PhysicsSystem(resourceSystem, rootNode); mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, &mFallback, resourcePath); @@ -1627,6 +1627,13 @@ namespace MWWorld updateSoundListener(); updatePlayer(paused); + + mSpellPreloadTimer -= duration; + if (mSpellPreloadTimer <= 0.f) + { + mSpellPreloadTimer = 0.1f; + preloadSpells(); + } } void World::updatePlayer(bool paused) @@ -1683,7 +1690,39 @@ namespace MWWorld if (result.mHit) mRendering->getCamera()->setCameraDistance((result.mHitPos - focal).length() - radius, false, false); } + } + void World::preloadSpells() + { + std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); + if (!selectedSpell.empty()) + { + const ESM::Spell* spell = mStore.get().search(selectedSpell); + if (spell) + preloadEffects(&spell->mEffects); + } + const MWWorld::Ptr& selectedEnchantItem = MWBase::Environment::get().getWindowManager()->getSelectedEnchantItem(); + if (!selectedEnchantItem.isEmpty()) + { + std::string enchantId = selectedEnchantItem.getClass().getEnchantment(selectedEnchantItem); + if (!enchantId.empty()) + { + const ESM::Enchantment* ench = mStore.get().search(selectedEnchantItem.getClass().getEnchantment(selectedEnchantItem)); + if (ench) + preloadEffects(&ench->mEffects); + } + } + const MWWorld::Ptr& selectedWeapon = MWBase::Environment::get().getWindowManager()->getSelectedWeapon(); + if (!selectedWeapon.isEmpty()) + { + std::string enchantId = selectedWeapon.getClass().getEnchantment(selectedWeapon); + if (!enchantId.empty()) + { + const ESM::Enchantment* ench = mStore.get().search(enchantId); + if (ench && ench->mData.mType == ESM::Enchantment::WhenStrikes) + preloadEffects(&ench->mEffects); + } + } } void World::updateSoundListener() @@ -2720,7 +2759,6 @@ namespace MWWorld if (!selectedSpell.empty()) { const ESM::Spell* spell = getStore().get().find(selectedSpell); - cast.cast(spell); } else if (actor.getClass().hasInventoryStore(actor)) @@ -3356,4 +3394,30 @@ namespace MWWorld return mPhysics->getHitDistance(weaponPos, target) - halfExtents.y(); } + void preload(MWWorld::Scene* scene, const ESMStore& store, const std::string& obj) + { + if (obj.empty()) + return; + MWWorld::ManualRef ref(store, obj); + std::string model = ref.getPtr().getClass().getModel(ref.getPtr()); + if (!model.empty()) + scene->preload(model); + } + + void World::preloadEffects(const ESM::EffectList *effectList) + { + for (std::vector::const_iterator it = effectList->mList.begin(); it != effectList->mList.end(); ++it) + { + const ESM::MagicEffect *effect = mStore.get().find(it->mEffectID); + + preload(mWorldScene, mStore, effect->mCasting); + preload(mWorldScene, mStore, effect->mHit); + + if (it->mArea > 0) + preload(mWorldScene, mStore, effect->mArea); + if (it->mRange == ESM::RT_Target) + preload(mWorldScene, mStore, effect->mBolt); + } + } + } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 688ff4751..ce6e27672 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -135,6 +135,8 @@ namespace MWWorld void updateWindowManager (); void updatePlayer(bool paused); + void preloadSpells(); + MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); public: // FIXME @@ -174,6 +176,8 @@ namespace MWWorld bool mGoToJail; int mDaysInPrison; + float mSpellPreloadTimer; + float feetToGameUnits(float feet); float getActivationDistancePlusTelekinesis(); @@ -677,6 +681,9 @@ namespace MWWorld /// Export scene graph to a file and return the filename. /// \param ptr object to export scene graph for (if empty, export entire scene graph) virtual std::string exportSceneGraph(const MWWorld::Ptr& ptr); + + /// Preload VFX associated with this effect list + virtual void preloadEffects(const ESM::EffectList* effectList); }; } diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index 7caf5366c..d80561c24 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -49,6 +49,18 @@ osg::ref_ptr ObjectCache::getRefFromObjectCache(const std::string& else return 0; } +bool ObjectCache::checkInObjectCache(const std::string &fileName, double timeStamp) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCacheMap::iterator itr = _objectCache.find(fileName); + if (itr!=_objectCache.end()) + { + itr->second.second = timeStamp; + return true; + } + else return false; +} + void ObjectCache::updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime) { OpenThreads::ScopedLock lock(_objectCacheMutex); diff --git a/components/resource/objectcache.hpp b/components/resource/objectcache.hpp index 82aca76f0..3d65df546 100644 --- a/components/resource/objectcache.hpp +++ b/components/resource/objectcache.hpp @@ -64,6 +64,9 @@ class ObjectCache : public osg::Referenced /** Get an ref_ptr from the object cache*/ osg::ref_ptr getRefFromObjectCache(const std::string& fileName); + /** Check if an object is in the cache, and if it is, update its usage time stamp. */ + bool checkInObjectCache(const std::string& fileName, double timeStamp); + /** call releaseGLObjects on all objects attached to the object cache.*/ void releaseGLObjects(osg::State* state); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index c975286ce..9cda7d755 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -272,6 +272,14 @@ namespace Resource mShaderManager->setShaderPath(path); } + bool SceneManager::checkLoaded(const std::string &name, double timeStamp) + { + std::string normalized = name; + mVFS->normalizeFilename(normalized); + + return mCache->checkInObjectCache(normalized, timeStamp); + } + /// @brief Callback to read image files from the VFS. class ImageReadCallback : public osgDB::ReadFileCallback { diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index ee4a453a3..97e5b43be 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -77,6 +77,9 @@ namespace Resource void setShaderPath(const std::string& path); + /// Check if a given scene is loaded and if so, update its usage timestamp to prevent it from being unloaded + bool checkLoaded(const std::string& name, double referenceTime); + /// Get a read-only copy of this scene "template" /// @note If the given filename does not exist or fails to load, an error marker mesh will be used instead. /// If even the error marker mesh can not be found, an exception is thrown. From c4a89065a2588c8c4580b1a5b6bef20d9ce1c82b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Feb 2017 01:01:53 +0100 Subject: [PATCH 4/7] Preload VFX of spells selected by AI actors --- apps/openmw/mwmechanics/aicombataction.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 437aae277..cc1434d52 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -426,6 +426,9 @@ namespace MWMechanics MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor); inv.setSelectedEnchantItem(inv.end()); } + + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(mSpellId); + MWBase::Environment::get().getWorld()->preloadEffects(&spell->mEffects); } float ActionSpell::getCombatRange (bool& isRanged) const From f10edb71cc201bd2a499fd7dc785beddc7f5a7b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Feb 2017 20:57:12 +0100 Subject: [PATCH 5/7] Add environment variable for disabling IncrementalCompileOperation --- apps/openmw/mwrender/renderingmanager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 551e20888..33bb84345 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -202,7 +203,8 @@ namespace MWRender mObjects.reset(new Objects(mResourceSystem, sceneRoot, mUnrefQueue.get())); - mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); + if (getenv("OPENMW_DONT_PRECOMPILE") == NULL) + mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); mResourceSystem->getSceneManager()->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); From d4972ab166677cb30dbc918af59ddda6f0f252c8 Mon Sep 17 00:00:00 2001 From: MAtahualpa Date: Wed, 15 Feb 2017 23:06:36 +0100 Subject: [PATCH 6/7] Replace "Xyz blood" check boxes with a combo box (fixes #3751) Replaces the two "Xyz blood" check boxes in NPC and Creature records with a "Blood Type" combo box. Related issue: - Fixes #3751: OpenMW-CS: Replace "Xyz Blood" check boxes in NPC and Creature records with "Blood Type" combo box (https://bugs.openmw.org/issues/3751) Tests: The changes were successfully tested in OpenMW-CS by manipulating several NPC and Creature records. Please note that this fix also prevents users from erroneously assigning two blood types at the same time. (I don't know which one would prevail in that case.) --- apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columns.cpp | 10 +++- apps/opencs/model/world/columns.hpp | 4 +- apps/opencs/model/world/refidadapterimp.cpp | 54 ++++++++++++++++++++- apps/opencs/model/world/refidadapterimp.hpp | 2 + apps/opencs/model/world/refidcollection.cpp | 16 +++--- apps/opencs/view/doc/viewmanager.cpp | 1 + 7 files changed, 73 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 951af4b6a..19028de08 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -132,6 +132,7 @@ namespace CSMWorld Display_String32, Display_LongString256, Display_BookType, + Display_BloodType, Display_EffectSkill, // must display at least one, unlike Display_Skill Display_EffectAttribute, // must display at least one, unlike Display_Attribute diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 5c041894f..534d7da05 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -112,8 +112,8 @@ namespace CSMWorld { ColumnId_Flies, "Flies" }, { ColumnId_Walks, "Walks" }, { ColumnId_Essential, "Essential" }, - { ColumnId_SkeletonBlood, "Skeleton Blood" }, - { ColumnId_MetalBlood, "Metal Blood" }, + { ColumnId_BloodType, "Blood Type" }, + { ColumnId_OpenSound, "Open Sound" }, { ColumnId_CloseSound, "Close Sound" }, { ColumnId_Duration, "Duration" }, @@ -558,6 +558,11 @@ namespace "Book", "Scroll", 0 }; + static const char *sBloodType[] = + { + "Default (Red)", "Skeleton Blood (White)", "Metal Blood (Golden)", 0 + }; + const char **getEnumNames (CSMWorld::Columns::ColumnId column) { switch (column) @@ -588,6 +593,7 @@ namespace case CSMWorld::Columns::ColumnId_InfoCondFunc: return CSMWorld::ConstInfoSelectWrapper::FunctionEnumStrings; case CSMWorld::Columns::ColumnId_InfoCondComp: return CSMWorld::ConstInfoSelectWrapper::RelationEnumStrings; case CSMWorld::Columns::ColumnId_BookType: return sBookType; + case CSMWorld::Columns::ColumnId_BloodType: return sBloodType; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index c1586bf6c..2438d2de2 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -107,8 +107,8 @@ namespace CSMWorld ColumnId_Flies = 92, ColumnId_Walks = 93, ColumnId_Essential = 94, - ColumnId_SkeletonBlood = 95, - ColumnId_MetalBlood = 96, + ColumnId_BloodType = 95, + // unused ColumnId_OpenSound = 97, ColumnId_CloseSound = 98, ColumnId_Duration = 99, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index fb19d943b..5e792e91f 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -458,7 +458,8 @@ CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) mOriginal(NULL), mAttributes(NULL), mAttacks(NULL), - mMisc(NULL) + mMisc(NULL), + mBloodType(NULL) {} CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns) @@ -489,6 +490,19 @@ QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, con if (column==mColumns.mMisc) return QVariant::fromValue(ColumnBase::TableEdit_Full); + if (column == mColumns.mBloodType) + { + int mask = ESM::Creature::Flags::Skeleton | ESM::Creature::Flags::Metal; + + if ((record.get().mFlags & mask) == ESM::Creature::Flags::Skeleton) + return 1; + + if ((record.get().mFlags & mask) == ESM::Creature::Flags::Metal) + return 2; + + return 0; + } + std::map::const_iterator iter = mColumns.mFlags.find (column); @@ -512,6 +526,17 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa creature.mScale = value.toFloat(); else if (column==mColumns.mOriginal) creature.mOriginal = value.toString().toUtf8().constData(); + else if (column == mColumns.mBloodType) + { + int mask = !(ESM::Creature::Flags::Skeleton | ESM::Creature::Flags::Metal); + + if (value.toInt() == 1) + creature.mFlags = (creature.mFlags & mask) | ESM::Creature::Flags::Skeleton; + else if (value.toInt() == 2) + creature.mFlags = (creature.mFlags & mask) | ESM::Creature::Flags::Metal; + else + creature.mFlags = creature.mFlags & mask; + } else { std::map::const_iterator iter = @@ -696,7 +721,8 @@ CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) mHead(NULL), mAttributes(NULL), mSkills(NULL), - mMisc(NULL) + mMisc(NULL), + mBloodType(NULL) {} CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns) @@ -735,6 +761,19 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mMisc) return QVariant::fromValue(ColumnBase::TableEdit_Full); + if (column == mColumns.mBloodType) + { + int mask = ESM::NPC::Flags::Skeleton | ESM::NPC::Flags::Metal; + + if ((record.get().mFlags & mask) == ESM::NPC::Flags::Skeleton) + return 1; + + if ((record.get().mFlags & mask) == ESM::NPC::Flags::Metal) + return 2; + + return 0; + } + std::map::const_iterator iter = mColumns.mFlags.find (column); @@ -762,6 +801,17 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d npc.mHair = value.toString().toUtf8().constData(); else if (column==mColumns.mHead) npc.mHead = value.toString().toUtf8().constData(); + else if (column == mColumns.mBloodType) + { + int mask = !(ESM::NPC::Flags::Skeleton | ESM::NPC::Flags::Metal); + + if (value.toInt() == 1) + npc.mFlags = (npc.mFlags & mask) | ESM::NPC::Flags::Skeleton; + else if (value.toInt() == 2) + npc.mFlags = (npc.mFlags & mask) | ESM::NPC::Flags::Metal; + else + npc.mFlags = npc.mFlags & mask; + } else { std::map::const_iterator iter = diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 390d1f1b4..b89b87ab1 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -757,6 +757,7 @@ namespace CSMWorld const RefIdColumn *mAttributes; const RefIdColumn *mAttacks; const RefIdColumn *mMisc; + const RefIdColumn *mBloodType; CreatureColumns (const ActorColumns& actorColumns); }; @@ -849,6 +850,7 @@ namespace CSMWorld const RefIdColumn *mAttributes; // depends on npc type const RefIdColumn *mSkills; // depends on npc type const RefIdColumn *mMisc; // may depend on npc type, e.g. FactionID + const RefIdColumn *mBloodType; NpcColumns (const ActorColumns& actorColumns); }; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 150077fd8..a85ee5d25 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -346,15 +346,11 @@ CSMWorld::RefIdCollection::RefIdCollection() { Columns::ColumnId_Flies, ESM::Creature::Flies }, { Columns::ColumnId_Walks, ESM::Creature::Walks }, { Columns::ColumnId_Essential, ESM::Creature::Essential }, - { Columns::ColumnId_SkeletonBlood, ESM::Creature::Skeleton }, - { Columns::ColumnId_MetalBlood, ESM::Creature::Metal }, { -1, 0 } }; // for re-use in NPC records const RefIdColumn *essential = 0; - const RefIdColumn *skeletonBlood = 0; - const RefIdColumn *metalBlood = 0; for (int i=0; sCreatureFlagTable[i].mName!=-1; ++i) { @@ -364,11 +360,14 @@ CSMWorld::RefIdCollection::RefIdCollection() switch (sCreatureFlagTable[i].mFlag) { case ESM::Creature::Essential: essential = &mColumns.back(); break; - case ESM::Creature::Skeleton: skeletonBlood = &mColumns.back(); break; - case ESM::Creature::Metal: metalBlood = &mColumns.back(); break; } } + mColumns.push_back(RefIdColumn(Columns::ColumnId_BloodType, ColumnBase::Display_BloodType)); + // For re-use in NPC records. + const RefIdColumn *bloodType = &mColumns.back(); + creatureColumns.mBloodType = bloodType; + creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn)); // Nested table @@ -497,9 +496,8 @@ CSMWorld::RefIdCollection::RefIdCollection() npcColumns.mFlags.insert (std::make_pair (autoCalc, ESM::NPC::Autocalc)); - npcColumns.mFlags.insert (std::make_pair (skeletonBlood, ESM::NPC::Skeleton)); - - npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal)); + // Re-used from Creature records. + npcColumns.mBloodType = bloodType; // Need a way to add a table of stats and values (rather than adding a long list of // entries in the dialogue subview) E.g. attributes+stats(health, mana, fatigue), skills diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 12d52d3dd..b3a8d03d4 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -108,6 +108,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_EffectSkill, CSMWorld::Columns::ColumnId_Skill, false }, { CSMWorld::ColumnBase::Display_EffectAttribute, CSMWorld::Columns::ColumnId_Attribute, false }, { CSMWorld::ColumnBase::Display_BookType, CSMWorld::Columns::ColumnId_BookType, false}, + { CSMWorld::ColumnBase::Display_BloodType, CSMWorld::Columns::ColumnId_BloodType, false} }; for (std::size_t i=0; i Date: Thu, 16 Feb 2017 00:08:38 +0100 Subject: [PATCH 7/7] Fix for commit "d4972ab..." in PR 1208 (fixes #3751) Replaces the two "Xyz blood" check boxes in NPC and Creature records with a "Blood Type" combo box. Fix: - corrected false logic operation in refidadapterimp.cpp - corrected names of the used flags --- apps/opencs/model/world/refidadapterimp.cpp | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 5e792e91f..b80f1ac2f 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -492,12 +492,12 @@ QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, con if (column == mColumns.mBloodType) { - int mask = ESM::Creature::Flags::Skeleton | ESM::Creature::Flags::Metal; + int mask = ESM::Creature::Skeleton | ESM::Creature::Metal; - if ((record.get().mFlags & mask) == ESM::Creature::Flags::Skeleton) + if ((record.get().mFlags & mask) == ESM::Creature::Skeleton) return 1; - if ((record.get().mFlags & mask) == ESM::Creature::Flags::Metal) + if ((record.get().mFlags & mask) == ESM::Creature::Metal) return 2; return 0; @@ -528,12 +528,12 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa creature.mOriginal = value.toString().toUtf8().constData(); else if (column == mColumns.mBloodType) { - int mask = !(ESM::Creature::Flags::Skeleton | ESM::Creature::Flags::Metal); + int mask = ~(ESM::Creature::Skeleton | ESM::Creature::Metal); if (value.toInt() == 1) - creature.mFlags = (creature.mFlags & mask) | ESM::Creature::Flags::Skeleton; + creature.mFlags = (creature.mFlags & mask) | ESM::Creature::Skeleton; else if (value.toInt() == 2) - creature.mFlags = (creature.mFlags & mask) | ESM::Creature::Flags::Metal; + creature.mFlags = (creature.mFlags & mask) | ESM::Creature::Metal; else creature.mFlags = creature.mFlags & mask; } @@ -763,12 +763,12 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column == mColumns.mBloodType) { - int mask = ESM::NPC::Flags::Skeleton | ESM::NPC::Flags::Metal; + int mask = ESM::NPC::Skeleton | ESM::NPC::Metal; - if ((record.get().mFlags & mask) == ESM::NPC::Flags::Skeleton) + if ((record.get().mFlags & mask) == ESM::NPC::Skeleton) return 1; - if ((record.get().mFlags & mask) == ESM::NPC::Flags::Metal) + if ((record.get().mFlags & mask) == ESM::NPC::Metal) return 2; return 0; @@ -803,12 +803,12 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d npc.mHead = value.toString().toUtf8().constData(); else if (column == mColumns.mBloodType) { - int mask = !(ESM::NPC::Flags::Skeleton | ESM::NPC::Flags::Metal); + int mask = ~(ESM::NPC::Skeleton | ESM::NPC::Metal); if (value.toInt() == 1) - npc.mFlags = (npc.mFlags & mask) | ESM::NPC::Flags::Skeleton; + npc.mFlags = (npc.mFlags & mask) | ESM::NPC::Skeleton; else if (value.toInt() == 2) - npc.mFlags = (npc.mFlags & mask) | ESM::NPC::Flags::Metal; + npc.mFlags = (npc.mFlags & mask) | ESM::NPC::Metal; else npc.mFlags = npc.mFlags & mask; }