From 0fe7500f7437b34a6100a73adf5877daebd8e1aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Dec 2014 00:13:56 +0100 Subject: [PATCH 1/9] Work around pathgrid record limitation (Fixes #2195) --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 3 +- apps/openmw/mwmechanics/pathgrid.cpp | 9 +-- apps/openmw/mwmechanics/pathgrid.hpp | 2 +- apps/openmw/mwrender/debugging.cpp | 3 +- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/store.hpp | 87 +++++++++---------------- 7 files changed, 41 insertions(+), 67 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index c8a0c85d5..3224127df 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -382,7 +382,7 @@ namespace MWMechanics { // infrequently used, therefore no benefit in caching it as a member const ESM::Pathgrid * - pathgrid = world->getStore().get().search(*cell); + pathgrid = world->getStore().get().search(*cell, world->getCellName(currentCell)); // cache the current cell location cachedCellX = cell->mData.mX; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f1279c415..f0e5b1d9d 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -188,7 +188,8 @@ namespace MWMechanics if(mCell != cell || !mPathgrid) { mCell = cell; - mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*mCell->getCell()); + mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*mCell->getCell(), + MWBase::Environment::get().getWorld()->getCellName(mCell)); } // Refer to AiWander reseach topic on openmw forums for some background. diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 4983a4a4f..d380cba4e 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -95,7 +95,7 @@ namespace MWMechanics * +----------------> * high cost */ - bool PathgridGraph::load(const ESM::Cell* cell) + bool PathgridGraph::load(const MWWorld::CellStore *cell) { if(!cell) return false; @@ -103,9 +103,10 @@ namespace MWMechanics if(mIsGraphConstructed) return true; - mCell = cell; - mIsExterior = cell->isExterior(); - mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell); + mCell = cell->getCell(); + mIsExterior = cell->getCell()->isExterior(); + mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell->getCell(), + MWBase::Environment::get().getWorld()->getCellName(cell)); if(!mPathgrid) return false; diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index 5d01dca00..2742957a6 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -21,7 +21,7 @@ namespace MWMechanics public: PathgridGraph(); - bool load(const ESM::Cell *cell); + bool load(const MWWorld::CellStore *cell); // returns true if end point is strongly connected (i.e. reachable // from start point) both start and end are pathgrid point indexes diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 4f5536ca3..553a6379f 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -231,8 +231,9 @@ void Debugging::togglePathgrid() void Debugging::enableCellPathgrid(MWWorld::CellStore *store) { + MWBase::World* world = MWBase::Environment::get().getWorld(); const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*store->getCell()); + world->getStore().get().search(*store->getCell(), world->getCellName(store)); if (!pathgrid) return; Vector3 cellPathGridPos(0, 0, 0); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 52e70fef2..f1a8451ea 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -413,7 +413,7 @@ namespace MWWorld // TODO: the pathgrid graph only needs to be loaded for active cells, so move this somewhere else. // In a simple test, loading the graph for all cells in MW + expansions took 200 ms - mPathgridGraph.load(mCell); + mPathgridGraph.load(this); } } diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index c8fa087c2..1aaf902f8 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -843,88 +843,59 @@ namespace MWWorld class Store : public StoreBase { private: - typedef std::map Interior; - typedef std::map, ESM::Pathgrid> Exterior; + // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. + // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. + // mX and mY will be (0,0) for interior cells, but there is also an exterior cell with the coordinates of (0,0), so that doesn't help. + // This is why we keep both interior and exterior pathgrids in the same container here. + typedef std::pair > PathgridKey; + typedef std::map Static; - Interior mInt; - Exterior mExt; + Static mStatic; public: void load(ESM::ESMReader &esm, const std::string &id) { - ESM::Pathgrid pathgrid; pathgrid.load(esm); + PathgridKey key = std::make_pair(pathgrid.mCell, std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY)); + // Try to overwrite existing record - if (!pathgrid.mCell.empty()) - { - std::pair ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); - if (!ret.second) - ret.first->second = pathgrid; - } - else - { - std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), - pathgrid)); - if (!ret.second) - ret.first->second = pathgrid; - } + std::pair ret = mStatic.insert(std::make_pair(key, pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; } size_t getSize() const { - return mInt.size() + mExt.size(); + return mStatic.size(); } void setUp() { } - const ESM::Pathgrid *search(int x, int y) const { - Exterior::const_iterator it = mExt.find(std::make_pair(x,y)); - if (it != mExt.end()) + const ESM::Pathgrid *search(const ESM::Cell &cell, const std::string& cellName) const { + int x=0,y=0; + if (!(cell.mData.mFlags & ESM::Cell::Interior)) + { + x = cell.mData.mX; + y = cell.mData.mY; + } + PathgridKey key = std::make_pair(cellName, std::make_pair(x,y)); + + Static::const_iterator it = mStatic.find(key); + if (it != mStatic.end()) return &(it->second); return NULL; } - const ESM::Pathgrid *find(int x, int y) const { - const ESM::Pathgrid *ptr = search(x, y); - if (ptr == 0) { + const ESM::Pathgrid *find(const ESM::Cell &cell, const std::string& cellName) const { + const ESM::Pathgrid* pathgrid = search(cell, cellName); + if (pathgrid == 0) { std::ostringstream msg; - msg << "Pathgrid at (" << x << ", " << y << ") not found"; + msg << "Pathgrid in cell '" << cellName << "' not found"; throw std::runtime_error(msg.str()); } - return ptr; - } - - const ESM::Pathgrid *search(const std::string &name) const { - Interior::const_iterator it = mInt.find(name); - if (it != mInt.end()) - return &(it->second); - return NULL; - } - - const ESM::Pathgrid *find(const std::string &name) const { - const ESM::Pathgrid *ptr = search(name); - if (ptr == 0) { - std::ostringstream msg; - msg << "Pathgrid in cell '" << name << "' not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - const ESM::Pathgrid *search(const ESM::Cell &cell) const { - if (cell.mData.mFlags & ESM::Cell::Interior) { - return search(cell.mName); - } - return search(cell.mData.mX, cell.mData.mY); - } - - const ESM::Pathgrid *find(const ESM::Cell &cell) const { - if (cell.mData.mFlags & ESM::Cell::Interior) { - return find(cell.mName); - } - return find(cell.mData.mX, cell.mData.mY); + return pathgrid; } }; From 33019b93b4a17c7facb077abb9836efcfa1409b7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Dec 2014 21:10:14 +0100 Subject: [PATCH 2/9] Fix bug setting current launcher profile on startup (Bug #2188) --- apps/launcher/datafilespage.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index f45b44470..4015579c2 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -238,10 +238,8 @@ void Launcher::DataFilesPage::addProfile (const QString &profile, bool setAsCurr if (profile.isEmpty()) return; - if (ui.profilesComboBox->findText (profile) != -1) - return; - - ui.profilesComboBox->addItem (profile); + if (ui.profilesComboBox->findText (profile) == -1) + ui.profilesComboBox->addItem (profile); if (setAsCurrent) setProfile (ui.profilesComboBox->findText (profile), false); From fb1aa096beb67042d3bcb997fead1be4a9b9e1b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Dec 2014 21:46:36 +0100 Subject: [PATCH 3/9] Settings: reduce scope for better readability --- components/config/settingsbase.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/components/config/settingsbase.hpp b/components/config/settingsbase.hpp index 92ca34cdf..e6b0908e0 100644 --- a/components/config/settingsbase.hpp +++ b/components/config/settingsbase.hpp @@ -50,7 +50,7 @@ namespace Config bool readFile(QTextStream &stream) { - mCache.clear(); + Map cache; QString sectionPrefix; @@ -79,31 +79,30 @@ namespace Config mSettings.remove(key); - QStringList values = mCache.values(key); + QStringList values = cache.values(key); if (!values.contains(value)) { if (mMultiValue) { - mCache.insertMulti(key, value); + cache.insertMulti(key, value); } else { - mCache.insert(key, value); + cache.insert(key, value); } } } } if (mSettings.isEmpty()) { - mSettings = mCache; // This is the first time we read a file + mSettings = cache; // This is the first time we read a file return true; } // Merge the changed keys with those which didn't - mSettings.unite(mCache); + mSettings.unite(cache); return true; } private: Map mSettings; - Map mCache; bool mMultiValue; }; From 1937ace1b748e66b9044e679fd3923172601c006 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Dec 2014 21:47:04 +0100 Subject: [PATCH 4/9] Launcher: fix bugs deleting profiles (Fixes #2188) --- apps/launcher/datafilespage.cpp | 18 ++++++++++-------- apps/launcher/datafilespage.hpp | 2 ++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 4015579c2..7192ed784 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -154,9 +154,11 @@ void Launcher::DataFilesPage::setProfile(int index, bool savePrevious) { if (index >= -1 && index < ui.profilesComboBox->count()) { - QString previous = ui.profilesComboBox->itemText(ui.profilesComboBox->currentIndex()); + QString previous = mPreviousProfile; QString current = ui.profilesComboBox->itemText(index); + mPreviousProfile = current; + setProfile (previous, current, savePrevious); } } @@ -167,9 +169,6 @@ void Launcher::DataFilesPage::setProfile (const QString &previous, const QString if (previous == current) return; - if (previous.isEmpty()) - return; - if (!previous.isEmpty() && savePrevious) saveSettings (previous); @@ -212,7 +211,7 @@ void Launcher::DataFilesPage::slotProfileChanged(int index) void Launcher::DataFilesPage::on_newProfileAction_triggered() { - if (!mProfileDialog->exec() == QDialog::Accepted) + if (mProfileDialog->exec() != QDialog::Accepted) return; QString profile = mProfileDialog->lineEdit()->text(); @@ -222,9 +221,10 @@ void Launcher::DataFilesPage::on_newProfileAction_triggered() saveSettings(); - mSelector->clearCheckStates(); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), profile); addProfile(profile, true); + mSelector->clearCheckStates(); mSelector->setGameFile(); @@ -255,10 +255,12 @@ void Launcher::DataFilesPage::on_deleteProfileAction_triggered() if (!showDeleteMessageBox (profile)) return; - // Remove the profile from the combobox - ui.profilesComboBox->removeItem (ui.profilesComboBox->findText (profile)); + // this should work since the Default profile can't be deleted and is always index 0 + int next = ui.profilesComboBox->currentIndex()-1; + ui.profilesComboBox->setCurrentIndex(next); removeProfile(profile); + ui.profilesComboBox->removeItem(ui.profilesComboBox->findText(profile)); saveSettings(); diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 5beeb0e03..15fa00308 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -67,6 +67,8 @@ namespace Launcher Config::GameSettings &mGameSettings; Config::LauncherSettings &mLauncherSettings; + QString mPreviousProfile; + QString mDataLocal; void setPluginsCheckstates(Qt::CheckState state); From cda0363f29f9fa24e603ca0c375e8f8a0e365ba4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 11 Dec 2014 13:51:37 +0100 Subject: [PATCH 5/9] allow a space in the middle of multi-character comparison operators (Fixes #2185) --- components/compiler/scanner.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 16d54ff51..203f27e6e 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -391,6 +391,10 @@ namespace Compiler { if (get (c)) { + /// \todo hack to allow a space in comparison operators (add option to disable) + if (c==' ') + get (c); + if (c=='=') special = S_cmpEQ; else @@ -398,7 +402,7 @@ namespace Compiler special = S_cmpEQ; putback (c); // return false; -// Allow = as synonym for ==. \todo optionally disable for post-1.0 scripting improvements. +/// Allow = as synonym for ==. \todo optionally disable for post-1.0 scripting improvements. } } else @@ -411,6 +415,10 @@ namespace Compiler { if (get (c)) { + /// \todo hack to allow a space in comparison operators (add option to disable) + if (c==' ' && !get (c)) + return false; + if (c=='=') special = S_cmpNE; else @@ -441,6 +449,10 @@ namespace Compiler { if (get (c)) { + /// \todo hack to allow a space in comparison operators (add option to disable) + if (c==' ') + get (c); + if (c=='=') { special = S_cmpLE; @@ -461,6 +473,10 @@ namespace Compiler { if (get (c)) { + /// \todo hack to allow a space in comparison operators (add option to disable) + if (c==' ') + get (c); + if (c=='=') { special = S_cmpGE; From 3270f0e932de557a9e5ec72390e180ad53477de6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Dec 2014 15:19:48 +0100 Subject: [PATCH 6/9] Change pathgrid workaround to check for interior cell name --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 3 +- apps/openmw/mwmechanics/pathgrid.cpp | 4 +- apps/openmw/mwrender/debugging.cpp | 2 +- apps/openmw/mwworld/esmstore.hpp | 2 + apps/openmw/mwworld/store.hpp | 97 ++++++++++++++++++------- 6 files changed, 76 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3224127df..c8a0c85d5 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -382,7 +382,7 @@ namespace MWMechanics { // infrequently used, therefore no benefit in caching it as a member const ESM::Pathgrid * - pathgrid = world->getStore().get().search(*cell, world->getCellName(currentCell)); + pathgrid = world->getStore().get().search(*cell); // cache the current cell location cachedCellX = cell->mData.mX; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index f0e5b1d9d..f1279c415 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -188,8 +188,7 @@ namespace MWMechanics if(mCell != cell || !mPathgrid) { mCell = cell; - mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*mCell->getCell(), - MWBase::Environment::get().getWorld()->getCellName(mCell)); + mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*mCell->getCell()); } // Refer to AiWander reseach topic on openmw forums for some background. diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index d380cba4e..848d2c7a0 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -105,9 +105,7 @@ namespace MWMechanics mCell = cell->getCell(); mIsExterior = cell->getCell()->isExterior(); - mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell->getCell(), - MWBase::Environment::get().getWorld()->getCellName(cell)); - + mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell->getCell()); if(!mPathgrid) return false; diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 553a6379f..972c1b6dd 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -233,7 +233,7 @@ void Debugging::enableCellPathgrid(MWWorld::CellStore *store) { MWBase::World* world = MWBase::Environment::get().getWorld(); const ESM::Pathgrid *pathgrid = - world->getStore().get().search(*store->getCell(), world->getCellName(store)); + world->getStore().get().search(*store->getCell()); if (!pathgrid) return; Vector3 cellPathGridPos(0, 0, 0); diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 90786acd4..83e911174 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -141,6 +141,8 @@ namespace MWWorld mStores[ESM::REC_SSCR] = &mStartScripts; mStores[ESM::REC_STAT] = &mStatics; mStores[ESM::REC_WEAP] = &mWeapons; + + mPathgrids.setCells(mCells); } void clearDynamic () diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 1aaf902f8..c4070f032 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -843,60 +843,103 @@ namespace MWWorld class Store : public StoreBase { private: - // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. - // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. - // mX and mY will be (0,0) for interior cells, but there is also an exterior cell with the coordinates of (0,0), so that doesn't help. - // This is why we keep both interior and exterior pathgrids in the same container here. - typedef std::pair > PathgridKey; - typedef std::map Static; + typedef std::map Interior; + typedef std::map, ESM::Pathgrid> Exterior; - Static mStatic; + Interior mInt; + Exterior mExt; + + Store* mCells; public: + void setCells(Store& cells) + { + mCells = &cells; + } + void load(ESM::ESMReader &esm, const std::string &id) { ESM::Pathgrid pathgrid; pathgrid.load(esm); - PathgridKey key = std::make_pair(pathgrid.mCell, std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY)); + // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. + // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. + // mX and mY will be (0,0) for interior cells, but there is also an exterior cell with the coordinates of (0,0), so that doesn't help. + // Check whether mCell is an interior cell. This isn't perfect, will break if a Region with the same name as an interior cell is created. + // A proper fix should be made for future versions of the file format. + bool interior = mCells->search(pathgrid.mCell) != NULL; // Try to overwrite existing record - std::pair ret = mStatic.insert(std::make_pair(key, pathgrid)); - if (!ret.second) - ret.first->second = pathgrid; + if (interior) + { + std::pair ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; + } + else + { + std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; + } } size_t getSize() const { - return mStatic.size(); + return mInt.size() + mExt.size(); } void setUp() { } - const ESM::Pathgrid *search(const ESM::Cell &cell, const std::string& cellName) const { - int x=0,y=0; - if (!(cell.mData.mFlags & ESM::Cell::Interior)) - { - x = cell.mData.mX; - y = cell.mData.mY; - } - PathgridKey key = std::make_pair(cellName, std::make_pair(x,y)); - - Static::const_iterator it = mStatic.find(key); - if (it != mStatic.end()) + const ESM::Pathgrid *search(int x, int y) const { + Exterior::const_iterator it = mExt.find(std::make_pair(x,y)); + if (it != mExt.end()) return &(it->second); return NULL; } - const ESM::Pathgrid *find(const ESM::Cell &cell, const std::string& cellName) const { - const ESM::Pathgrid* pathgrid = search(cell, cellName); - if (pathgrid == 0) { + const ESM::Pathgrid *search(const std::string& name) const { + Interior::const_iterator it = mInt.find(name); + if (it != mInt.end()) + return &(it->second); + return NULL; + } + + const ESM::Pathgrid *find(int x, int y) const { + const ESM::Pathgrid* pathgrid = search(x,y); + if (!pathgrid) + { std::ostringstream msg; - msg << "Pathgrid in cell '" << cellName << "' not found"; + msg << "Pathgrid in cell '" << x << " " << y << "' not found"; throw std::runtime_error(msg.str()); } return pathgrid; } + + const ESM::Pathgrid* find(const std::string& name) const { + const ESM::Pathgrid* pathgrid = search(name); + if (!pathgrid) + { + std::ostringstream msg; + msg << "Pathgrid in cell '" << name << "' not found"; + throw std::runtime_error(msg.str()); + } + return pathgrid; + } + + const ESM::Pathgrid *search(const ESM::Cell &cell) const { + if (!(cell.mData.mFlags & ESM::Cell::Interior)) + return search(cell.mData.mX, cell.mData.mY); + else + return search(cell.mName); + } + + const ESM::Pathgrid *find(const ESM::Cell &cell) const { + if (!(cell.mData.mFlags & ESM::Cell::Interior)) + return find(cell.mData.mX, cell.mData.mY); + else + return find(cell.mName); + } }; template From 8ed376af5e09a975895fd858654c43f8318a46ad Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Dec 2014 15:59:27 +0100 Subject: [PATCH 7/9] Launcher: fix changing active profile through the Play page --- apps/launcher/datafilespage.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 7192ed784..3c4d36de7 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -206,6 +206,10 @@ void Launcher::DataFilesPage::slotProfileRenamed(const QString &previous, const void Launcher::DataFilesPage::slotProfileChanged(int index) { + // in case the event was triggered externally + if (ui.profilesComboBox->currentIndex() != index) + ui.profilesComboBox->setCurrentIndex(index); + setProfile (index, true); } From 7e8ca3fff1837b632145d9f076a5769d0c9a7fd8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Dec 2014 19:27:13 +0100 Subject: [PATCH 8/9] Fix object movement between cells producing a stale Ptr within the script execution (Bug #1942) --- apps/openmw/mwbase/world.hpp | 3 +- apps/openmw/mwscript/interpretercontext.cpp | 6 ++++ apps/openmw/mwscript/interpretercontext.hpp | 3 ++ .../mwscript/transformationextensions.cpp | 36 ++++++++++++------- apps/openmw/mwworld/worldimp.cpp | 10 +++--- apps/openmw/mwworld/worldimp.hpp | 7 ++-- 6 files changed, 45 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 2dd135f3d..c674145ae 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -281,7 +281,8 @@ namespace MWBase virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0; - virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; + virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; + ///< @return an updated Ptr in case the Ptr's cell changes virtual void moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index d8d13a921..430389e30 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -590,4 +590,10 @@ namespace MWScript { return mTargetId; } + + void InterpreterContext::updatePtr(const MWWorld::Ptr& updated) + { + if (!mReference.isEmpty()) + mReference = updated; + } } diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index b54339965..7f3172dd1 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -169,6 +169,9 @@ namespace MWScript MWWorld::Ptr getReference(bool required=true); ///< Reference, that the script is running from (can be empty) + void updatePtr(const MWWorld::Ptr& updated); + ///< Update the Ptr stored in mReference, if there is one stored there. Should be called after the reference has been moved to a new cell. + virtual std::string getTargetId() const; }; } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 8e6d925b7..ac9dea408 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -224,20 +224,23 @@ namespace MWScript float ay = ptr.getRefData().getPosition().pos[1]; float az = ptr.getRefData().getPosition().pos[2]; + MWWorld::Ptr updated = ptr; if(axis == "x") { - MWBase::Environment::get().getWorld()->moveObject(ptr,pos,ay,az); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr,pos,ay,az); } else if(axis == "y") { - MWBase::Environment::get().getWorld()->moveObject(ptr,ax,pos,az); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr,ax,pos,az); } else if(axis == "z") { - MWBase::Environment::get().getWorld()->moveObject(ptr,ax,ay,pos); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr,ax,ay,pos); } else throw std::runtime_error ("invalid axis: " + axis); + + dynamic_cast(runtime.getContext()).updatePtr(updated); } }; @@ -317,6 +320,8 @@ namespace MWScript { MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); ptr = MWWorld::Ptr(ptr.getBase(), store); + dynamic_cast(runtime.getContext()).updatePtr(ptr); + float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) @@ -365,15 +370,18 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. + MWWorld::Ptr updated; if (ptr.getRefData().getHandle() == "player") { - MWBase::Environment::get().getWorld()->moveObject(ptr, - MWBase::Environment::get().getWorld()->getExterior(cx,cy),x,y,z); + MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); + updated = MWWorld::Ptr(ptr.getBase(), cell); } else { - MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z); } + dynamic_cast(runtime.getContext()).updatePtr(updated); float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); @@ -638,8 +646,10 @@ namespace MWScript ptr.getRefData().setLocalRotation(rot); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0,0,0,true); - MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], - ptr.getCellRef().getPosition().pos[1], ptr.getCellRef().getPosition().pos[2]); + + dynamic_cast(runtime.getContext()).updatePtr( + MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], + ptr.getCellRef().getPosition().pos[1], ptr.getCellRef().getPosition().pos[2])); } }; @@ -678,7 +688,8 @@ namespace MWScript throw std::runtime_error ("invalid movement axis: " + axis); Ogre::Vector3 worldPos = ptr.getRefData().getBaseNode()->convertLocalToWorldPosition(posChange); - MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); + dynamic_cast(runtime.getContext()).updatePtr( + MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z)); } }; @@ -701,17 +712,18 @@ namespace MWScript const float *objPos = ptr.getRefData().getPosition().pos; + MWWorld::Ptr updated; if (axis == "x") { - MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+movement, objPos[1], objPos[2]); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+movement, objPos[1], objPos[2]); } else if (axis == "y") { - MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1]+movement, objPos[2]); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1]+movement, objPos[2]); } else if (axis == "z") { - MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1], objPos[2]+movement); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1], objPos[2]+movement); } else throw std::runtime_error ("invalid movement axis: " + axis); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2607a6d4d..75de050e1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1187,7 +1187,7 @@ namespace MWWorld } } - bool World::moveObjectImp(const Ptr& ptr, float x, float y, float z) + MWWorld::Ptr World::moveObjectImp(const Ptr& ptr, float x, float y, float z) { CellStore *cell = ptr.getCell(); @@ -1200,12 +1200,14 @@ namespace MWWorld moveObject(ptr, cell, x, y, z); - return cell != ptr.getCell(); + MWWorld::Ptr updated = ptr; + updated.mCell = cell; + return updated; } - void World::moveObject (const Ptr& ptr, float x, float y, float z) + MWWorld::Ptr World::moveObject (const Ptr& ptr, float x, float y, float z) { - moveObjectImp(ptr, x, y, z); + return moveObjectImp(ptr, x, y, z); } void World::scaleObject (const Ptr& ptr, float scale) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 555ed7fb7..1548d0c87 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -104,8 +104,8 @@ namespace MWWorld void rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust); - bool moveObjectImp (const Ptr& ptr, float x, float y, float z); - ///< @return true if the active cell (cell player is in) changed + Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z); + ///< @return an updated Ptr in case the Ptr's cell changes Ptr copyObjectToCell(const Ptr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true); @@ -341,7 +341,8 @@ namespace MWWorld virtual void deleteObject (const Ptr& ptr); virtual void undeleteObject (const Ptr& ptr); - virtual void moveObject (const Ptr& ptr, float x, float y, float z); + virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z); + ///< @return an updated Ptr in case the Ptr's cell changes virtual void moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z); virtual void scaleObject (const Ptr& ptr, float scale); From ed2aa5a233e16d3d2fa8419607e866f67a7a5589 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Dec 2014 20:32:05 +0100 Subject: [PATCH 9/9] Fix crash caused by dangling baseNode pointer --- apps/openmw/mwworld/worldimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 75de050e1..e24e99c30 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1158,6 +1158,7 @@ namespace MWWorld ptr.getClass().copyToCell(ptr, *newCell, pos); mRendering->updateObjectCell(ptr, copy); + ptr.getRefData().setBaseNode(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy); MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager();