From df7d2e46c01aabe8cafc552cefceaea7d4552dc3 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 25 Aug 2022 22:34:50 +0100 Subject: [PATCH 01/36] Added a uniform to indicate whether rendering is occurring in a reflection --- apps/openmw/mwrender/renderingmanager.cpp | 1 + apps/openmw/mwrender/water.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1385147c4c..947384000e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -173,6 +173,7 @@ namespace MWRender stateset->addUniform(new osg::Uniform("far", 0.f)); stateset->addUniform(new osg::Uniform("skyBlendingStart", 0.f)); stateset->addUniform(new osg::Uniform("screenRes", osg::Vec2f{})); + stateset->addUniform(new osg::Uniform("isReflection", false)); if (mUsePlayerUniforms) { stateset->addUniform(new osg::Uniform("windSpeed", 0.0f)); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 159380b786..0f67a333ab 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -351,6 +351,9 @@ public: camera->setName("ReflectionCamera"); camera->addCullCallback(new InheritViewPointCallback); + // Inform the shader that we're in a reflection + camera->getOrCreateStateSet()->addUniform(new osg::Uniform("isReflection", true)); + // XXX: should really flip the FrontFace on each renderable instead of forcing clockwise. osg::ref_ptr frontFace(new osg::FrontFace); frontFace->setMode(osg::FrontFace::CLOCKWISE); @@ -474,7 +477,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem geom2->setNodeMask(Mask_SimpleWater); geom2->setName("Simple Water Geometry"); mWaterNode->addChild(geom2); - + mSceneRoot->addChild(mWaterNode); setHeight(mTop); @@ -701,7 +704,7 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R normalMap->setMaxAnisotropy(16); normalMap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR); normalMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - + mRainIntensityUpdater = new RainIntensityUpdater(); node->setUpdateCallback(mRainIntensityUpdater); From d15e1dca848ff66d19bf27d30e0fddab511cbf48 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 28 Aug 2022 16:43:43 +0200 Subject: [PATCH 02/36] Use R-tree for objects to be used for navmesh generation Instead of storing a set of objects per tile. --- .../tilecachedrecastmeshmanager.cpp | 22 +- components/CMakeLists.txt | 4 +- .../cachedrecastmeshmanager.cpp | 100 --- .../cachedrecastmeshmanager.hpp | 53 -- .../detournavigator/commulativeaabb.cpp | 27 + .../detournavigator/commulativeaabb.hpp | 24 + components/detournavigator/debug.cpp | 6 + components/detournavigator/debug.hpp | 3 + components/detournavigator/navigatorimpl.cpp | 6 +- components/detournavigator/navmeshmanager.cpp | 41 +- components/detournavigator/navmeshmanager.hpp | 6 +- .../oscillatingrecastmeshobject.cpp | 57 -- .../oscillatingrecastmeshobject.hpp | 31 - .../detournavigator/recastmeshbuilder.cpp | 2 + .../detournavigator/recastmeshmanager.cpp | 167 ----- .../detournavigator/recastmeshmanager.hpp | 79 --- .../tilecachedrecastmeshmanager.cpp | 632 ++++++++++-------- .../tilecachedrecastmeshmanager.hpp | 110 ++- .../detournavigator/tilespositionsrange.hpp | 12 + 19 files changed, 526 insertions(+), 856 deletions(-) delete mode 100644 components/detournavigator/cachedrecastmeshmanager.cpp delete mode 100644 components/detournavigator/cachedrecastmeshmanager.hpp create mode 100644 components/detournavigator/commulativeaabb.cpp create mode 100644 components/detournavigator/commulativeaabb.hpp delete mode 100644 components/detournavigator/oscillatingrecastmeshobject.cpp delete mode 100644 components/detournavigator/oscillatingrecastmeshobject.hpp delete mode 100644 components/detournavigator/recastmeshmanager.cpp delete mode 100644 components/detournavigator/recastmeshmanager.hpp diff --git a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp index 4ccd4c6712..71ef657e22 100644 --- a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp @@ -43,14 +43,6 @@ namespace EXPECT_EQ(manager.getRevision(), 0); } - TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, for_each_tile_position_for_empty_should_call_none) - { - TileCachedRecastMeshManager manager(mSettings); - std::size_t calls = 0; - manager.forEachTile([&] (const TilePosition&, const CachedRecastMeshManager&) { ++calls; }); - EXPECT_EQ(calls, 0); - } - TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_for_new_object_should_return_true) { TileCachedRecastMeshManager manager(mSettings); @@ -105,7 +97,7 @@ namespace manager.setBounds(bounds); manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground); manager.takeChangedTiles(); - EXPECT_TRUE(manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); + EXPECT_TRUE(manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground)); EXPECT_THAT(manager.takeChangedTiles(), ElementsAre( std::pair(TilePosition(-1, -1), ChangeType::add), std::pair(TilePosition(-1, 0), ChangeType::add), @@ -123,7 +115,7 @@ namespace const CollisionShape shape(mInstance, boxShape, mObjectTransform); manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); manager.takeChangedTiles(); - EXPECT_FALSE(manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); + EXPECT_FALSE(manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground)); EXPECT_THAT(manager.takeChangedTiles(), IsEmpty()); } @@ -184,7 +176,7 @@ namespace EXPECT_NE(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(1, -1)), nullptr); - manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr); @@ -204,7 +196,7 @@ namespace EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr); EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr); - manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground); EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr); EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, -1)), nullptr); } @@ -236,7 +228,7 @@ namespace EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr); - manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr); @@ -272,7 +264,7 @@ namespace const CollisionShape shape(mInstance, boxShape, mObjectTransform); manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground); const auto beforeUpdateRevision = manager.getRevision(); - manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground); EXPECT_EQ(manager.getRevision(), beforeUpdateRevision + 1); } @@ -284,7 +276,7 @@ namespace const CollisionShape shape(mInstance, boxShape, mObjectTransform); manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); const auto beforeUpdateRevision = manager.getRevision(); - manager.updateObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground); EXPECT_EQ(manager.getRevision(), beforeUpdateRevision); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9dc752e4aa..cbfcece2c2 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -290,8 +290,6 @@ add_component_dir(detournavigator makenavmesh findsmoothpath recastmeshbuilder - recastmeshmanager - cachedrecastmeshmanager navmeshmanager navigatorimpl asyncnavmeshupdater @@ -304,7 +302,6 @@ add_component_dir(detournavigator findrandompointaroundcircle raycast navmeshtileview - oscillatingrecastmeshobject offmeshconnectionsmanager preparednavmeshdata navmeshcacheitem @@ -317,6 +314,7 @@ add_component_dir(detournavigator gettilespositions collisionshapetype stats + commulativeaabb ) add_component_dir(loadinglistener diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp deleted file mode 100644 index 65f99fae1e..0000000000 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "cachedrecastmeshmanager.hpp" - -namespace DetourNavigator -{ - CachedRecastMeshManager::CachedRecastMeshManager(const TileBounds& bounds, std::size_t generation) - : mImpl(bounds, generation) - {} - - bool CachedRecastMeshManager::addObject(const ObjectId id, const CollisionShape& shape, - const btTransform& transform, const AreaType areaType) - { - if (!mImpl.addObject(id, shape, transform, areaType)) - return false; - mOutdatedCache = true; - return true; - } - - bool CachedRecastMeshManager::updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType) - { - if (!mImpl.updateObject(id, transform, areaType)) - return false; - mOutdatedCache = true; - return true; - } - - bool CachedRecastMeshManager::removeObject(const ObjectId id) - { - const bool result = mImpl.removeObject(id); - if (result) - mOutdatedCache = true; - return result; - } - - bool CachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level) - { - if (!mImpl.addWater(cellPosition, cellSize, level)) - return false; - mOutdatedCache = true; - return true; - } - - bool CachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition) - { - const bool result = mImpl.removeWater(cellPosition); - if (result) - mOutdatedCache = true; - return result; - } - - bool CachedRecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, - const HeightfieldShape& shape) - { - if (!mImpl.addHeightfield(cellPosition, cellSize, shape)) - return false; - mOutdatedCache = true; - return true; - } - - bool CachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) - { - const bool result = mImpl.removeHeightfield(cellPosition); - if (result) - mOutdatedCache = true; - return result; - } - - std::shared_ptr CachedRecastMeshManager::getMesh() - { - bool outdated = true; - if (!mOutdatedCache.compare_exchange_strong(outdated, false)) - { - std::shared_ptr cached = getCachedMesh(); - if (cached != nullptr) - return cached; - } - std::shared_ptr mesh = mImpl.getMesh(); - *mCached.lock() = mesh; - return mesh; - } - - std::shared_ptr CachedRecastMeshManager::getCachedMesh() const - { - return *mCached.lockConst(); - } - - std::shared_ptr CachedRecastMeshManager::getNewMesh() const - { - return mImpl.getMesh(); - } - - bool CachedRecastMeshManager::isEmpty() const - { - return mImpl.isEmpty(); - } - - void CachedRecastMeshManager::reportNavMeshChange(const Version& recastMeshVersion, const Version& navMeshVersion) - { - mImpl.reportNavMeshChange(recastMeshVersion, navMeshVersion); - } -} diff --git a/components/detournavigator/cachedrecastmeshmanager.hpp b/components/detournavigator/cachedrecastmeshmanager.hpp deleted file mode 100644 index df4a5b3319..0000000000 --- a/components/detournavigator/cachedrecastmeshmanager.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_CACHEDRECASTMESHMANAGER_H -#define OPENMW_COMPONENTS_DETOURNAVIGATOR_CACHEDRECASTMESHMANAGER_H - -#include "recastmeshmanager.hpp" -#include "version.hpp" -#include "heightfieldshape.hpp" - -#include - -#include - -namespace DetourNavigator -{ - class CachedRecastMeshManager - { - public: - explicit CachedRecastMeshManager(const TileBounds& bounds, std::size_t generation); - - bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, - const AreaType areaType); - - bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType); - - bool removeObject(const ObjectId id); - - bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level); - - bool removeWater(const osg::Vec2i& cellPosition); - - bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape); - - bool removeHeightfield(const osg::Vec2i& cellPosition); - - std::shared_ptr getMesh(); - - std::shared_ptr getCachedMesh() const; - - std::shared_ptr getNewMesh() const; - - bool isEmpty() const; - - void reportNavMeshChange(const Version& recastMeshVersion, const Version& navMeshVersion); - - Version getVersion() const { return mImpl.getVersion(); } - - private: - RecastMeshManager mImpl; - Misc::ScopeGuarded> mCached; - std::atomic_bool mOutdatedCache {true}; - }; -} - -#endif diff --git a/components/detournavigator/commulativeaabb.cpp b/components/detournavigator/commulativeaabb.cpp new file mode 100644 index 0000000000..1274c3203d --- /dev/null +++ b/components/detournavigator/commulativeaabb.cpp @@ -0,0 +1,27 @@ +#include "commulativeaabb.hpp" + +#include + +namespace DetourNavigator +{ + CommulativeAabb::CommulativeAabb(std::size_t lastChangeRevision, const btAABB& aabb) + : mLastChangeRevision(lastChangeRevision) + , mAabb(aabb) + { + } + + bool CommulativeAabb::update(std::size_t lastChangeRevision, const btAABB& aabb) + { + if (mLastChangeRevision != lastChangeRevision) + { + mLastChangeRevision = lastChangeRevision; + // btAABB doesn't have copy-assignment operator + mAabb.m_min = aabb.m_min; + mAabb.m_max = aabb.m_max; + return true; + } + const btAABB currentAabb = mAabb; + mAabb.merge(aabb); + return currentAabb != mAabb; + } +} diff --git a/components/detournavigator/commulativeaabb.hpp b/components/detournavigator/commulativeaabb.hpp new file mode 100644 index 0000000000..3559d3b000 --- /dev/null +++ b/components/detournavigator/commulativeaabb.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_COMMULATIVEAABB_H +#define OPENMW_COMPONENTS_DETOURNAVIGATOR_COMMULATIVEAABB_H + +#include +#include + +#include + +namespace DetourNavigator +{ + class CommulativeAabb + { + public: + explicit CommulativeAabb(std::size_t lastChangeRevision, const btAABB& aabb); + + bool update(std::size_t lastChangeRevision, const btAABB& aabb); + + private: + std::size_t mLastChangeRevision; + btAABB mAabb; + }; +} + +#endif diff --git a/components/detournavigator/debug.cpp b/components/detournavigator/debug.cpp index 740be10337..2c3cb998d7 100644 --- a/components/detournavigator/debug.cpp +++ b/components/detournavigator/debug.cpp @@ -4,6 +4,7 @@ #include "settings.hpp" #include "settingsutils.hpp" #include "version.hpp" +#include "tilespositionsrange.hpp" #include @@ -196,6 +197,11 @@ namespace DetourNavigator return stream << "Version {" << value.mGeneration << ", " << value.mRevision << "}"; } + std::ostream& operator<<(std::ostream& stream, const TilesPositionsRange& value) + { + return stream << "TilesPositionsRange {" << value.mBegin << ", " << value.mEnd << "}"; + } + void writeToFile(const RecastMesh& recastMesh, const std::string& pathPrefix, const std::string& revision, const RecastSettings& settings) { diff --git a/components/detournavigator/debug.hpp b/components/detournavigator/debug.hpp index 5dcbe55ffb..328eafa514 100644 --- a/components/detournavigator/debug.hpp +++ b/components/detournavigator/debug.hpp @@ -19,6 +19,7 @@ class dtNavMesh; namespace DetourNavigator { struct Version; + struct TilesPositionsRange; std::ostream& operator<<(std::ostream& stream, const TileBounds& value); @@ -58,6 +59,8 @@ namespace DetourNavigator std::ostream& operator<<(std::ostream& stream, const Version& value); + std::ostream& operator<<(std::ostream& stream, const TilesPositionsRange& value); + class RecastMesh; struct RecastSettings; diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 6a194a7615..575e7c7e7b 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -77,13 +77,11 @@ namespace DetourNavigator void NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) { - const CollisionShape collisionShape(shapes.mShapeInstance, *shapes.mShapeInstance->mCollisionShape, shapes.mTransform); - mNavMeshManager.updateObject(id, collisionShape, transform, AreaType_ground); + mNavMeshManager.updateObject(id, transform, AreaType_ground); if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->mAvoidCollisionShape.get()) { const ObjectId avoidId(avoidShape); - const CollisionShape avoidCollisionShape(shapes.mShapeInstance, *avoidShape, shapes.mTransform); - if (mNavMeshManager.updateObject(avoidId, avoidCollisionShape, transform, AreaType_null)) + if (mNavMeshManager.updateObject(avoidId, transform, AreaType_null)) updateAvoidShapeId(id, avoidId); } } diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index 07035b17cc..a6734d41e3 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -7,7 +7,6 @@ #include "settings.hpp" #include "waitconditiontype.hpp" #include "settingsutils.hpp" -#include "cachedrecastmeshmanager.hpp" #include #include @@ -81,10 +80,9 @@ namespace DetourNavigator return mRecastMeshManager.addObject(id, shape, transform, areaType); } - bool NavMeshManager::updateObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, - const AreaType areaType) + bool NavMeshManager::updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType) { - return mRecastMeshManager.updateObject(id, shape, transform, areaType); + return mRecastMeshManager.updateObject(id, transform, areaType); } void NavMeshManager::removeObject(const ObjectId id) @@ -165,36 +163,33 @@ namespace DetourNavigator mLastRecastMeshManagerRevision = mRecastMeshManager.getRevision(); mPlayerTile = playerTile; const auto changedTiles = mRecastMeshManager.takeChangedTiles(); + const TilesPositionsRange range = mRecastMeshManager.getRange(); for (const auto& [agentBounds, cached] : mCache) - update(agentBounds, playerTile, cached, changedTiles); + update(agentBounds, playerTile, range, cached, changedTiles); } void NavMeshManager::update(const AgentBounds& agentBounds, const TilePosition& playerTile, - const SharedNavMeshCacheItem& cached, const std::map& changedTiles) + const TilesPositionsRange& range, const SharedNavMeshCacheItem& cached, + const std::map& changedTiles) { - std::map tilesToPost; + std::map tilesToPost = changedTiles; { const auto locked = cached->lockConst(); const auto& navMesh = locked->getImpl(); - for (const auto& [tilePosition, changeType] : changedTiles) - if (navMesh.getTileAt(tilePosition.x(), tilePosition.y(), 0)) - tilesToPost.emplace(tilePosition, changeType); const auto maxTiles = std::min(mSettings.mMaxTilesNumber, navMesh.getParams()->maxTiles); - mRecastMeshManager.forEachTile([&] (const TilePosition& tile, CachedRecastMeshManager& recastMeshManager) + getTilesPositions(range, [&] (const TilePosition& tile) { - if (tilesToPost.count(tile)) + if (changedTiles.find(tile) != changedTiles.end()) return; - const auto shouldAdd = shouldAddTile(tile, playerTile, maxTiles); - const auto presentInNavMesh = bool(navMesh.getTileAt(tile.x(), tile.y(), 0)); + const bool shouldAdd = shouldAddTile(tile, playerTile, maxTiles); + const bool presentInNavMesh = navMesh.getTileAt(tile.x(), tile.y(), 0) != nullptr; if (shouldAdd && !presentInNavMesh) tilesToPost.emplace(tile, locked->isEmptyTile(tile) ? ChangeType::update : ChangeType::add); else if (!shouldAdd && presentInNavMesh) tilesToPost.emplace(tile, ChangeType::mixed); - else - recastMeshManager.reportNavMeshChange(recastMeshManager.getVersion(), Version {0, 0}); }); } - mAsyncNavMeshUpdater.post(agentBounds, cached, playerTile, mRecastMeshManager.getWorldspace(), tilesToPost); + mAsyncNavMeshUpdater.post(agentBounds, cached, playerTile, mWorldspace, tilesToPost); Log(Debug::Debug) << "Cache update posted for agent=" << agentBounds << " playerTile=" << playerTile << " recastMeshManagerRevision=" << mLastRecastMeshManagerRevision; } @@ -221,14 +216,12 @@ namespace DetourNavigator RecastMeshTiles NavMeshManager::getRecastMeshTiles() const { - std::vector tiles; - mRecastMeshManager.forEachTile( - [&tiles] (const TilePosition& tile, const CachedRecastMeshManager&) { tiles.push_back(tile); }); - const std::string worldspace = mRecastMeshManager.getWorldspace(); RecastMeshTiles result; - for (const TilePosition& tile : tiles) - if (auto mesh = mRecastMeshManager.getCachedMesh(worldspace, tile)) - result.emplace(tile, std::move(mesh)); + getTilesPositions(mRecastMeshManager.getRange(), [&] (const TilePosition& v) + { + if (auto mesh = mRecastMeshManager.getCachedMesh(mWorldspace, v)) + result.emplace(v, std::move(mesh)); + }); return result; } diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index adaefb14c4..b9c3bc7c21 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -29,8 +29,7 @@ namespace DetourNavigator bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, const AreaType areaType); - bool updateObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, - const AreaType areaType); + bool updateObject(ObjectId id, const btTransform& transform, AreaType areaType); void removeObject(const ObjectId id); @@ -76,7 +75,8 @@ namespace DetourNavigator inline SharedNavMeshCacheItem getCached(const AgentBounds& agentBounds) const; inline void update(const AgentBounds& agentBounds, const TilePosition& playerTile, - const SharedNavMeshCacheItem& cached, const std::map& changedTiles); + const TilesPositionsRange& range, const SharedNavMeshCacheItem& cached, + const std::map& changedTiles); }; } diff --git a/components/detournavigator/oscillatingrecastmeshobject.cpp b/components/detournavigator/oscillatingrecastmeshobject.cpp deleted file mode 100644 index fbe4b77ffd..0000000000 --- a/components/detournavigator/oscillatingrecastmeshobject.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "oscillatingrecastmeshobject.hpp" -#include "tilebounds.hpp" - -#include - -#include - -namespace DetourNavigator -{ - namespace - { - void limitBy(btAABB& aabb, const TileBounds& bounds) - { - aabb.m_min.setX(std::max(aabb.m_min.x(), static_cast(bounds.mMin.x()))); - aabb.m_min.setY(std::max(aabb.m_min.y(), static_cast(bounds.mMin.y()))); - aabb.m_max.setX(std::min(aabb.m_max.x(), static_cast(bounds.mMax.x()))); - aabb.m_max.setY(std::min(aabb.m_max.y(), static_cast(bounds.mMax.y()))); - } - } - - OscillatingRecastMeshObject::OscillatingRecastMeshObject(RecastMeshObject&& impl, std::size_t lastChangeRevision) - : mImpl(std::move(impl)) - , mLastChangeRevision(lastChangeRevision) - , mAabb(BulletHelpers::getAabb(mImpl.getShape(), mImpl.getTransform())) - { - } - - OscillatingRecastMeshObject::OscillatingRecastMeshObject(const RecastMeshObject& impl, std::size_t lastChangeRevision) - : mImpl(impl) - , mLastChangeRevision(lastChangeRevision) - , mAabb(BulletHelpers::getAabb(mImpl.getShape(), mImpl.getTransform())) - { - } - - bool OscillatingRecastMeshObject::update(const btTransform& transform, const AreaType areaType, - std::size_t lastChangeRevision, const TileBounds& bounds) - { - const btTransform oldTransform = mImpl.getTransform(); - if (!mImpl.update(transform, areaType)) - return false; - if (transform == oldTransform) - return true; - if (mLastChangeRevision != lastChangeRevision) - { - mLastChangeRevision = lastChangeRevision; - // btAABB doesn't have copy-assignment operator - const btAABB aabb = BulletHelpers::getAabb(mImpl.getShape(), transform); - mAabb.m_min = aabb.m_min; - mAabb.m_max = aabb.m_max; - return true; - } - const btAABB currentAabb = mAabb; - mAabb.merge(BulletHelpers::getAabb(mImpl.getShape(), transform)); - limitBy(mAabb, bounds); - return currentAabb != mAabb; - } -} diff --git a/components/detournavigator/oscillatingrecastmeshobject.hpp b/components/detournavigator/oscillatingrecastmeshobject.hpp deleted file mode 100644 index f8aabce628..0000000000 --- a/components/detournavigator/oscillatingrecastmeshobject.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_OSCILLATINGRECASTMESHOBJECT_H -#define OPENMW_COMPONENTS_DETOURNAVIGATOR_OSCILLATINGRECASTMESHOBJECT_H - -#include "areatype.hpp" -#include "recastmeshobject.hpp" -#include "tilebounds.hpp" - -#include -#include - -namespace DetourNavigator -{ - class OscillatingRecastMeshObject - { - public: - explicit OscillatingRecastMeshObject(RecastMeshObject&& impl, std::size_t lastChangeRevision); - explicit OscillatingRecastMeshObject(const RecastMeshObject& impl, std::size_t lastChangeRevision); - - bool update(const btTransform& transform, const AreaType areaType, std::size_t lastChangeRevision, - const TileBounds& bounds); - - const RecastMeshObject& getImpl() const { return mImpl; } - - private: - RecastMeshObject mImpl; - std::size_t mLastChangeRevision; - btAABB mAabb; - }; -} - -#endif diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index ff216b0b0e..b8e455c732 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -277,6 +277,8 @@ namespace DetourNavigator mTriangles.erase(std::remove_if(mTriangles.begin(), mTriangles.end(), isNan), mTriangles.end()); std::sort(mTriangles.begin(), mTriangles.end()); std::sort(mWater.begin(), mWater.end()); + std::sort(mHeightfields.begin(), mHeightfields.end()); + std::sort(mFlatHeightfields.begin(), mFlatHeightfields.end()); Mesh mesh = makeMesh(std::move(mTriangles)); return std::make_shared(version, std::move(mesh), std::move(mWater), std::move(mHeightfields), std::move(mFlatHeightfields), diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp deleted file mode 100644 index a883f7839b..0000000000 --- a/components/detournavigator/recastmeshmanager.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include "recastmeshmanager.hpp" -#include "recastmeshbuilder.hpp" -#include "heightfieldshape.hpp" - -#include -#include - -#include - -namespace -{ - struct AddHeightfield - { - osg::Vec2i mCellPosition; - int mCellSize; - DetourNavigator::RecastMeshBuilder& mBuilder; - - void operator()(const DetourNavigator::HeightfieldSurface& v) - { - mBuilder.addHeightfield(mCellPosition, mCellSize, v.mHeights, v.mSize, v.mMinHeight, v.mMaxHeight); - } - - void operator()(DetourNavigator::HeightfieldPlane v) - { - mBuilder.addHeightfield(mCellPosition, mCellSize, v.mHeight); - } - }; -} - -namespace DetourNavigator -{ - RecastMeshManager::RecastMeshManager(const TileBounds& bounds, std::size_t generation) - : mGeneration(generation) - , mTileBounds(bounds) - { - } - - bool RecastMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, - const AreaType areaType) - { - const std::lock_guard lock(mMutex); - const auto object = mObjects.lower_bound(id); - if (object != mObjects.end() && object->first == id) - return false; - mObjects.emplace_hint(object, id, - OscillatingRecastMeshObject(RecastMeshObject(shape, transform, areaType), mRevision + 1)); - ++mRevision; - return true; - } - - bool RecastMeshManager::updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType) - { - const std::lock_guard lock(mMutex); - const auto object = mObjects.find(id); - if (object == mObjects.end()) - return false; - const std::size_t lastChangeRevision = mLastNavMeshReportedChange.has_value() - ? mLastNavMeshReportedChange->mRevision : mRevision; - if (!object->second.update(transform, areaType, lastChangeRevision, mTileBounds)) - return false; - ++mRevision; - return true; - } - - bool RecastMeshManager::removeObject(const ObjectId id) - { - const std::lock_guard lock(mMutex); - const auto object = mObjects.find(id); - if (object == mObjects.end()) - return false; - mObjects.erase(object); - ++mRevision; - return true; - } - - bool RecastMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level) - { - const std::lock_guard lock(mMutex); - if (!mWater.emplace(cellPosition, Water {cellSize, level}).second) - return false; - ++mRevision; - return true; - } - - bool RecastMeshManager::removeWater(const osg::Vec2i& cellPosition) - { - const std::lock_guard lock(mMutex); - const auto water = mWater.find(cellPosition); - if (water == mWater.end()) - return false; - ++mRevision; - mWater.erase(water); - return true; - } - - bool RecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, - const HeightfieldShape& shape) - { - const std::lock_guard lock(mMutex); - if (!mHeightfields.emplace(cellPosition, SizedHeightfieldShape {cellSize, shape}).second) - return false; - ++mRevision; - return true; - } - - bool RecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) - { - const std::lock_guard lock(mMutex); - const auto it = mHeightfields.find(cellPosition); - if (it == mHeightfields.end()) - return false; - ++mRevision; - mHeightfields.erase(it); - return true; - } - - std::shared_ptr RecastMeshManager::getMesh() const - { - RecastMeshBuilder builder(mTileBounds); - using Object = std::tuple< - osg::ref_ptr, - ObjectTransform, - std::reference_wrapper, - btTransform, - AreaType - >; - std::vector objects; - std::size_t revision; - { - const std::lock_guard lock(mMutex); - for (const auto& [k, v] : mWater) - builder.addWater(k, v); - for (const auto& [cellPosition, v] : mHeightfields) - std::visit(AddHeightfield {cellPosition, v.mCellSize, builder}, v.mShape); - objects.reserve(mObjects.size()); - for (const auto& [k, object] : mObjects) - { - const RecastMeshObject& impl = object.getImpl(); - objects.emplace_back(impl.getInstance(), impl.getObjectTransform(), impl.getShape(), - impl.getTransform(), impl.getAreaType()); - } - revision = mRevision; - } - for (const auto& [instance, objectTransform, shape, transform, areaType] : objects) - builder.addObject(shape, transform, areaType, instance->getSource(), objectTransform); - return std::move(builder).create(Version {.mGeneration = mGeneration, .mRevision = revision}); - } - - bool RecastMeshManager::isEmpty() const - { - const std::lock_guard lock(mMutex); - return mObjects.empty() && mWater.empty() && mHeightfields.empty(); - } - - void RecastMeshManager::reportNavMeshChange(const Version& recastMeshVersion, const Version& navMeshVersion) - { - if (recastMeshVersion.mGeneration != mGeneration) - return; - const std::lock_guard lock(mMutex); - if (mLastNavMeshReport.has_value() && navMeshVersion < mLastNavMeshReport->mNavMeshVersion) - return; - mLastNavMeshReport = {recastMeshVersion.mRevision, navMeshVersion}; - if (!mLastNavMeshReportedChange.has_value() - || mLastNavMeshReportedChange->mNavMeshVersion < mLastNavMeshReport->mNavMeshVersion) - mLastNavMeshReportedChange = mLastNavMeshReport; - } -} diff --git a/components/detournavigator/recastmeshmanager.hpp b/components/detournavigator/recastmeshmanager.hpp deleted file mode 100644 index ad27933807..0000000000 --- a/components/detournavigator/recastmeshmanager.hpp +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHMANAGER_H -#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTMESHMANAGER_H - -#include "oscillatingrecastmeshobject.hpp" -#include "objectid.hpp" -#include "version.hpp" -#include "recastmesh.hpp" -#include "heightfieldshape.hpp" - -#include - -#include - -#include -#include -#include -#include - -class btCollisionShape; - -namespace DetourNavigator -{ - struct Settings; - class RecastMesh; - - struct SizedHeightfieldShape - { - int mCellSize; - HeightfieldShape mShape; - }; - - class RecastMeshManager - { - public: - explicit RecastMeshManager(const TileBounds& bounds, std::size_t generation); - - bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, - const AreaType areaType); - - bool updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType); - - bool removeObject(const ObjectId id); - - bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level); - - bool removeWater(const osg::Vec2i& cellPosition); - - bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape); - - bool removeHeightfield(const osg::Vec2i& cellPosition); - - std::shared_ptr getMesh() const; - - bool isEmpty() const; - - void reportNavMeshChange(const Version& recastMeshVersion, const Version& navMeshVersion); - - Version getVersion() const { return Version {mGeneration, mRevision}; } - - private: - struct Report - { - std::size_t mRevision; - Version mNavMeshVersion; - }; - - const std::size_t mGeneration; - const TileBounds mTileBounds; - mutable std::mutex mMutex; - std::size_t mRevision = 0; - std::map mObjects; - std::map mWater; - std::map mHeightfields; - std::optional mLastNavMeshReportedChange; - std::optional mLastNavMeshReport; - }; -} - -#endif diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 18c8ef26ca..3c2049942a 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -2,10 +2,12 @@ #include "gettilespositions.hpp" #include "settingsutils.hpp" #include "changetype.hpp" -#include "cachedrecastmeshmanager.hpp" +#include "recastmeshbuilder.hpp" -#include #include +#include + +#include #include #include @@ -20,11 +22,26 @@ namespace DetourNavigator osg::Vec2f(std::numeric_limits::max(), std::numeric_limits::max()) }; - bool updateTile(const ObjectId id, const btTransform& transform, const AreaType areaType, - const TilePosition& tilePosition, std::map>& tiles) + struct AddHeightfield { - const auto tile = tiles.find(tilePosition); - return tile != tiles.end() && tile->second->updateObject(id, transform, areaType); + osg::Vec2i mCellPosition; + int mCellSize; + RecastMeshBuilder& mBuilder; + + void operator()(const HeightfieldSurface& v) + { + mBuilder.addHeightfield(mCellPosition, mCellSize, v.mHeights, v.mSize, v.mMinHeight, v.mMaxHeight); + } + + void operator()(HeightfieldPlane v) + { + mBuilder.addHeightfield(mCellPosition, mCellSize, v.mHeight); + } + }; + + TilePosition makeTilePosition(const boost::geometry::model::point& v) + { + return TilePosition(v.get<0>(), v.get<1>()); } } @@ -41,345 +58,318 @@ namespace DetourNavigator bool changed = false; const auto newRange = makeTilesPositionsRange(bounds.mMin, bounds.mMax, mSettings); - if (mBounds != infiniteTileBounds) { - const auto locked = mWorldspaceTiles.lock(); - for (auto& object : mObjects) + for (const auto& [id, data] : mObjects) { - const ObjectId id = object.first; - ObjectData& data = object.second; - const TilesPositionsRange objectRange = makeTilesPositionsRange(data.mShape.getShape(), data.mTransform, mSettings); + const TilesPositionsRange objectRange = makeTilesPositionsRange(data->mObject.getShape(), + data->mObject.getTransform(), mSettings); - const auto onOldTilePosition = [&] (const TilePosition& position) + getTilesPositions(getIntersection(mRange, objectRange), [&] (const TilePosition& v) { - if (isInTilesPositionsRange(newRange, position)) - return; - const auto it = data.mTiles.find(position); - if (it == data.mTiles.end()) - return; - data.mTiles.erase(it); - if (removeTile(id, position, locked->mTiles)) + if (!isInTilesPositionsRange(newRange, v)) { - addChangedTile(position, ChangeType::remove); + addChangedTile(v, ChangeType::remove); changed = true; } - }; - getTilesPositions(getIntersection(mRange, objectRange), onOldTilePosition); + }); - const auto onNewTilePosition = [&] (const TilePosition& position) + getTilesPositions(getIntersection(newRange, objectRange), [&] (const TilePosition& v) { - if (data.mTiles.find(position) != data.mTiles.end()) - return; - if (addTile(id, data.mShape, data.mTransform, data.mAreaType, position, locked->mTiles)) + if (!isInTilesPositionsRange(mRange, v)) { - data.mTiles.insert(position); - addChangedTile(position, ChangeType::add); + addChangedTile(v, ChangeType::add); + changed = true; } - }; - getTilesPositions(getIntersection(newRange, objectRange), onNewTilePosition); + }); } } if (changed) + { + const std::lock_guard lock(mMutex); ++mRevision; + } mBounds = bounds; mRange = newRange; } - std::string TileCachedRecastMeshManager::getWorldspace() const + TilesPositionsRange TileCachedRecastMeshManager::getRange() const { - return mWorldspaceTiles.lockConst()->mWorldspace; + const auto bounds = mObjectIndex.bounds(); + return TilesPositionsRange { + .mBegin = makeTilePosition(bounds.min_corner()), + .mEnd = makeTilePosition(bounds.max_corner()) + TilePosition(1, 1), + }; } void TileCachedRecastMeshManager::setWorldspace(std::string_view worldspace) { - const auto locked = mWorldspaceTiles.lock(); - if (locked->mWorldspace == worldspace) + const std::lock_guard lock(mMutex); + if (mWorldspace == worldspace) return; - locked->mTiles.clear(); - locked->mWorldspace = worldspace; + mWorldspace = worldspace; + ++mGeneration; + ++mRevision; + mObjectIndex.clear(); + mObjects.clear(); + mWater.clear(); + mHeightfields.clear(); + mCache.clear(); } - bool TileCachedRecastMeshManager::addObject(const ObjectId id, const CollisionShape& shape, - const btTransform& transform, const AreaType areaType) + bool TileCachedRecastMeshManager::addObject(ObjectId id, const CollisionShape& shape, const btTransform& transform, + const AreaType areaType) { - auto it = mObjects.find(id); - if (it != mObjects.end()) - return false; - const TilesPositionsRange objectRange = makeTilesPositionsRange(shape.getShape(), transform, mSettings); - const TilesPositionsRange range = getIntersection(mRange, objectRange); - std::set tilesPositions; - if (range.mBegin != range.mEnd) + const TilesPositionsRange range = makeTilesPositionsRange(shape.getShape(), transform, mSettings); { - const auto locked = mWorldspaceTiles.lock(); - getTilesPositions(range, - [&] (const TilePosition& tilePosition) - { - if (addTile(id, shape, transform, areaType, tilePosition, locked->mTiles)) - { - tilesPositions.insert(tilePosition); - addChangedTile(tilePosition, ChangeType::add); - } - }); + const std::lock_guard lock(mMutex); + const auto it = mObjects.find(id); + if (it != mObjects.end()) + return false; + const std::size_t revision = mRevision + 1; + ObjectData* const dataPtr = mObjects.emplace_hint(it, id, std::unique_ptr(new ObjectData { + .mObject = RecastMeshObject(shape, transform, areaType), + .mRange = range, + .mAabb = CommulativeAabb(revision, BulletHelpers::getAabb(shape.getShape(), transform)), + .mGeneration = mGeneration, + .mRevision = revision, + .mLastNavMeshReportedChange = {}, + .mLastNavMeshReport = {}, + }))->second.get(); + assert(range.mBegin != range.mEnd); + mObjectIndex.insert(makeObjectIndexValue(range, dataPtr)); + mRevision = revision; } - mObjects.emplace_hint(it, id, ObjectData {shape, transform, areaType, std::move(tilesPositions)}); - ++mRevision; + getTilesPositions(getIntersection(range, mRange), + [&] (const TilePosition& v) { addChangedTile(v, ChangeType::add); }); return true; } - bool TileCachedRecastMeshManager::updateObject(const ObjectId id, const CollisionShape& shape, - const btTransform& transform, AreaType areaType) + bool TileCachedRecastMeshManager::updateObject(ObjectId id, const btTransform& transform, const AreaType areaType) { - const auto object = mObjects.find(id); - if (object == mObjects.end()) - return false; - auto& data = object->second; - bool changed = false; - std::set newTiles; + TilesPositionsRange newRange; + TilesPositionsRange oldRange; { - const TilesPositionsRange objectRange = makeTilesPositionsRange(shape.getShape(), transform, mSettings); - const TilesPositionsRange range = getIntersection(mRange, objectRange); - const auto locked = mWorldspaceTiles.lock(); - const auto onTilePosition = [&] (const TilePosition& tilePosition) + const std::lock_guard lock(mMutex); + const auto it = mObjects.find(id); + if (it == mObjects.end()) + return false; + if (!it->second->mObject.update(transform, areaType)) + return false; + const std::size_t lastChangeRevision = it->second->mLastNavMeshReportedChange.has_value() + ? it->second->mLastNavMeshReportedChange->mRevision : mRevision; + const btCollisionShape& shape = it->second->mObject.getShape(); + if (!it->second->mAabb.update(lastChangeRevision, BulletHelpers::getAabb(shape, transform))) + return false; + newRange = makeTilesPositionsRange(shape, transform, mSettings); + oldRange = it->second->mRange; + if (newRange != oldRange) { - if (data.mTiles.find(tilePosition) != data.mTiles.end()) - { - newTiles.insert(tilePosition); - if (updateTile(id, transform, areaType, tilePosition, locked->mTiles)) - { - addChangedTile(tilePosition, ChangeType::update); - changed = true; - } - } - else if (addTile(id, shape, transform, areaType, tilePosition, locked->mTiles)) - { - newTiles.insert(tilePosition); - addChangedTile(tilePosition, ChangeType::add); - changed = true; - } - }; - getTilesPositions(range, onTilePosition); - for (const auto& tile : data.mTiles) - { - if (newTiles.find(tile) == newTiles.end() && removeTile(id, tile, locked->mTiles)) - { - addChangedTile(tile, ChangeType::remove); - changed = true; - } + mObjectIndex.remove(makeObjectIndexValue(oldRange, it->second.get())); + mObjectIndex.insert(makeObjectIndexValue(newRange, it->second.get())); + it->second->mRange = newRange; } - } - if (changed) - { - data.mTiles = std::move(newTiles); ++mRevision; + it->second->mRevision = mRevision; } - return changed; + if (newRange == oldRange) + { + getTilesPositions(getIntersection(newRange, mRange), + [&] (const TilePosition& v) { addChangedTile(v, ChangeType::update); }); + } + else + { + getTilesPositions(getIntersection(newRange, mRange), [&] (const TilePosition& v) + { + const ChangeType changeType = isInTilesPositionsRange(oldRange, v) + ? ChangeType::update : ChangeType::add; + addChangedTile(v, changeType); + }); + getTilesPositions(getIntersection(oldRange, mRange), [&] (const TilePosition& v) + { + if (!isInTilesPositionsRange(newRange, v)) + addChangedTile(v, ChangeType::remove); + }); + } + return true; } - void TileCachedRecastMeshManager::removeObject(const ObjectId id) + void TileCachedRecastMeshManager::removeObject(ObjectId id) { - const auto object = mObjects.find(id); - if (object == mObjects.end()) - return; - bool changed = false; + TilesPositionsRange range; { - const auto locked = mWorldspaceTiles.lock(); - for (const auto& tilePosition : object->second.mTiles) - { - if (removeTile(id, tilePosition, locked->mTiles)) - { - addChangedTile(tilePosition, ChangeType::remove); - changed = true; - } - } - } - mObjects.erase(object); - if (changed) + const std::lock_guard lock(mMutex); + const auto it = mObjects.find(id); + if (it == mObjects.end()) + return; + range = it->second->mRange; + mObjectIndex.remove(makeObjectIndexValue(range, it->second.get())); + mObjects.erase(it); ++mRevision; + } + getTilesPositions(getIntersection(range, mRange), + [&] (const TilePosition& v) { addChangedTile(v, ChangeType::remove); }); } void TileCachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const float level) { - const auto it = mWaterTilesPositions.find(cellPosition); - if (it != mWaterTilesPositions.end()) - return; - - std::vector& tilesPositions = mWaterTilesPositions.emplace_hint( - it, cellPosition, std::vector())->second; - - bool changed = false; - - if (cellSize == std::numeric_limits::max()) + const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, cellSize, level)); + const std::optional range = cellSize == std::numeric_limits::max() + ? std::optional() + : makeTilesPositionsRange(cellSize, shift, mSettings); { - const auto locked = mWorldspaceTiles.lock(); - for (auto& [tilePosition, data] : locked->mTiles) - { - if (data->addWater(cellPosition, cellSize, level)) - { - tilesPositions.push_back(tilePosition); - addChangedTile(tilePosition, ChangeType::add); - changed = true; - } - } + const std::lock_guard lock(mMutex); + auto it = mWater.find(cellPosition); + if (it != mWater.end()) + return; + const std::size_t revision = mRevision + 1; + it = mWater.emplace_hint(it, cellPosition, WaterData { + .mWater = Water {.mCellSize = cellSize, .mLevel = level}, + .mRange = range, + .mRevision = revision, + }); + if (range.has_value()) + mWaterIndex.insert(makeWaterIndexValue(*range, it)); + else + mInfiniteWater = it; + mRevision = revision; } - else - { - const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, cellSize, level)); - const auto worldspaceTiles = mWorldspaceTiles.lock(); - getTilesPositions(makeTilesPositionsRange(cellSize, shift, mSettings), - [&] (const TilePosition& tilePosition) - { - auto tile = worldspaceTiles->mTiles.find(tilePosition); - if (tile == worldspaceTiles->mTiles.end()) - { - const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition); - tile = worldspaceTiles->mTiles.emplace_hint(tile, tilePosition, - std::make_shared(tileBounds, mTilesGeneration)); - } - if (tile->second->addWater(cellPosition, cellSize, level)) - { - tilesPositions.push_back(tilePosition); - addChangedTile(tilePosition, ChangeType::add); - changed = true; - } - }); - } - - if (changed) - ++mRevision; + addChangedTiles(range, ChangeType::add); } void TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition) { - const auto object = mWaterTilesPositions.find(cellPosition); - if (object == mWaterTilesPositions.end()) - return; - bool changed = false; + std::optional range; { - const auto worldspaceTiles = mWorldspaceTiles.lock(); - for (const auto& tilePosition : object->second) - { - const auto tile = worldspaceTiles->mTiles.find(tilePosition); - if (tile == worldspaceTiles->mTiles.end()) - continue; - if (tile->second->removeWater(cellPosition)) - { - addChangedTile(tilePosition, ChangeType::remove); - changed = true; - } - if (tile->second->isEmpty()) - { - worldspaceTiles->mTiles.erase(tile); - ++mTilesGeneration; - } - } - } - mWaterTilesPositions.erase(object); - if (changed) + const std::lock_guard lock(mMutex); + const auto it = mWater.find(cellPosition); + if (it == mWater.end()) + return; + range = it->second.mRange; + if (range.has_value()) + mWaterIndex.remove(makeWaterIndexValue(*range, it)); + else + mInfiniteWater = mWater.end(); + mWater.erase(it); ++mRevision; + } + addChangedTiles(range, ChangeType::remove); } void TileCachedRecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, const int cellSize, const HeightfieldShape& shape) { - const auto it = mHeightfieldTilesPositions.find(cellPosition); - if (it != mHeightfieldTilesPositions.end()) - return; - - std::vector& tilesPositions = mHeightfieldTilesPositions.emplace_hint( - it, cellPosition, std::vector())->second; const btVector3 shift = getHeightfieldShift(shape, cellPosition, cellSize); - - bool changed = false; - + const std::optional range = cellSize == std::numeric_limits::max() + ? std::optional() + : makeTilesPositionsRange(cellSize, shift, mSettings); { - const auto worldspaceTiles = mWorldspaceTiles.lock(); - getTilesPositions(makeTilesPositionsRange(cellSize, shift, mSettings), - [&] (const TilePosition& tilePosition) - { - auto tile = worldspaceTiles->mTiles.find(tilePosition); - if (tile == worldspaceTiles->mTiles.end()) - { - const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition); - tile = worldspaceTiles->mTiles.emplace_hint(tile, tilePosition, - std::make_shared(tileBounds, mTilesGeneration)); - } - if (tile->second->addHeightfield(cellPosition, cellSize, shape)) - { - tilesPositions.push_back(tilePosition); - addChangedTile(tilePosition, ChangeType::add); - changed = true; - } - }); + const std::lock_guard lock(mMutex); + auto it = mHeightfields.find(cellPosition); + if (it != mHeightfields.end()) + return; + const std::size_t revision = mRevision + 1; + it = mHeightfields.emplace_hint(it, cellPosition, HeightfieldData { + .mCellSize = cellSize, + .mShape = shape, + .mRange = range, + .mRevision = revision, + }); + if (range.has_value()) + mHeightfieldIndex.insert(makeHeightfieldIndexValue(*range, it)); + else + mInfiniteHeightfield = it; + mRevision = revision; } - - if (changed) - ++mRevision; + addChangedTiles(range, ChangeType::add); } void TileCachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) { - const auto object = mHeightfieldTilesPositions.find(cellPosition); - if (object == mHeightfieldTilesPositions.end()) - return; - bool changed = false; + std::optional range; { - const auto worldspaceTiles = mWorldspaceTiles.lock(); - for (const auto& tilePosition : object->second) - { - const auto tile = worldspaceTiles->mTiles.find(tilePosition); - if (tile == worldspaceTiles->mTiles.end()) - continue; - if (tile->second->removeHeightfield(cellPosition)) - { - addChangedTile(tilePosition, ChangeType::remove); - changed = true; - } - if (tile->second->isEmpty()) - { - worldspaceTiles->mTiles.erase(tile); - ++mTilesGeneration; - } - } - } - mHeightfieldTilesPositions.erase(object); - if (changed) + const std::lock_guard lock(mMutex); + const auto it = mHeightfields.find(cellPosition); + if (it == mHeightfields.end()) + return; + range = it->second.mRange; + if (range.has_value()) + mHeightfieldIndex.remove(makeHeightfieldIndexValue(*range, it)); + else + mInfiniteHeightfield = mHeightfields.end(); + mHeightfields.erase(it); ++mRevision; + } + addChangedTiles(range, ChangeType::remove); } - std::shared_ptr TileCachedRecastMeshManager::getMesh(std::string_view worldspace, const TilePosition& tilePosition) const + std::shared_ptr TileCachedRecastMeshManager::getMesh(std::string_view worldspace, + const TilePosition& tilePosition) { - if (const auto manager = getManager(worldspace, tilePosition)) - return manager->getMesh(); - return nullptr; + { + const std::lock_guard lock(mMutex); + if (mWorldspace != worldspace) + return nullptr; + const auto it = mCache.find(tilePosition); + if (it != mCache.end() && it->second.mRecastMesh->getVersion() == it->second.mVersion) + return it->second.mRecastMesh; + } + auto result = makeMesh(tilePosition); + if (result != nullptr) + { + const std::lock_guard lock(mMutex); + mCache.insert_or_assign(tilePosition, CachedTile { + .mVersion = result->getVersion(), + .mRecastMesh = result, + }); + } + return result; } - std::shared_ptr TileCachedRecastMeshManager::getCachedMesh(std::string_view worldspace, const TilePosition& tilePosition) const + std::shared_ptr TileCachedRecastMeshManager::getCachedMesh(std::string_view worldspace, + const TilePosition& tilePosition) const { - if (const auto manager = getManager(worldspace, tilePosition)) - return manager->getCachedMesh(); - return nullptr; + const std::lock_guard lock(mMutex); + if (mWorldspace != worldspace) + return nullptr; + const auto it = mCache.find(tilePosition); + if (it == mCache.end()) + return nullptr; + return it->second.mRecastMesh; } - std::shared_ptr TileCachedRecastMeshManager::getNewMesh(std::string_view worldspace, const TilePosition& tilePosition) const + std::shared_ptr TileCachedRecastMeshManager::getNewMesh(std::string_view worldspace, + const TilePosition& tilePosition) const { - if (const auto manager = getManager(worldspace, tilePosition)) - return manager->getNewMesh(); - return nullptr; + { + const std::lock_guard lock(mMutex); + if (mWorldspace != worldspace) + return nullptr; + } + return makeMesh(tilePosition); } - void TileCachedRecastMeshManager::reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion) const + void TileCachedRecastMeshManager::reportNavMeshChange(const TilePosition& tilePosition, + Version recastMeshVersion, Version navMeshVersion) { - const auto locked = mWorldspaceTiles.lockConst(); - const auto it = locked->mTiles.find(tilePosition); - if (it == locked->mTiles.end()) - return; - it->second->reportNavMeshChange(recastMeshVersion, navMeshVersion); + const std::lock_guard lock(mMutex); + for (auto it = mObjectIndex.qbegin(makeIndexQuery(tilePosition)); it != mObjectIndex.qend(); ++it) + { + ObjectData& object = *it->second; + if (recastMeshVersion.mGeneration != object.mGeneration) + continue; + if (object.mLastNavMeshReport.has_value() && navMeshVersion < object.mLastNavMeshReport->mNavMeshVersion) + continue; + object.mLastNavMeshReport = {recastMeshVersion.mRevision, navMeshVersion}; + if (!object.mLastNavMeshReportedChange.has_value() + || object.mLastNavMeshReportedChange->mNavMeshVersion < object.mLastNavMeshReport->mNavMeshVersion) + object.mLastNavMeshReportedChange = object.mLastNavMeshReport; + } } - void TileCachedRecastMeshManager::addChangedTile(const TilePosition& tilePosition, ChangeType changeType) + void TileCachedRecastMeshManager::addChangedTile(const TilePosition& tilePosition, const ChangeType changeType) { auto tile = mChangedTiles.find(tilePosition); if (tile == mChangedTiles.end()) @@ -388,44 +378,112 @@ namespace DetourNavigator tile->second = addChangeType(tile->second, changeType); } - bool TileCachedRecastMeshManager::addTile(const ObjectId id, const CollisionShape& shape, - const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, - TilesMap& tiles) + std::map TileCachedRecastMeshManager::takeChangedTiles() { - auto tile = tiles.find(tilePosition); - if (tile == tiles.end()) { - const TileBounds tileBounds = makeRealTileBoundsWithBorder(mSettings, tilePosition); - tile = tiles.emplace_hint(tile, tilePosition, - std::make_shared(tileBounds, mTilesGeneration)); + const std::lock_guard lock(mMutex); + for (const auto& [tilePosition, changeType] : mChangedTiles) + if (const auto it = mCache.find(tilePosition); it != mCache.end()) + ++it->second.mVersion.mRevision; } - return tile->second->addObject(id, shape, transform, areaType); + return std::move(mChangedTiles); } - bool TileCachedRecastMeshManager::removeTile(const ObjectId id, - const TilePosition& tilePosition, TilesMap& tiles) + TileCachedRecastMeshManager::IndexPoint TileCachedRecastMeshManager::makeIndexPoint(const TilePosition& tilePosition) { - const auto tile = tiles.find(tilePosition); - if (tile == tiles.end()) - return false; - const bool result = tile->second->removeObject(id); - if (tile->second->isEmpty()) - { - tiles.erase(tile); - ++mTilesGeneration; - } - return result; + return IndexPoint(tilePosition.x(), tilePosition.y()); } - std::shared_ptr TileCachedRecastMeshManager::getManager(std::string_view worldspace, - const TilePosition& tilePosition) const + TileCachedRecastMeshManager::IndexBox TileCachedRecastMeshManager::makeIndexBox(const TilesPositionsRange& range) { - const auto locked = mWorldspaceTiles.lockConst(); - if (locked->mWorldspace != worldspace) + assert(range.mBegin != range.mEnd); + return IndexBox(makeIndexPoint(range.mBegin), makeIndexPoint(range.mEnd - TilePosition(1, 1))); + } + + TileCachedRecastMeshManager::ObjectIndexValue TileCachedRecastMeshManager::makeObjectIndexValue( + const TilesPositionsRange& range, ObjectData* id) + { + return {makeIndexBox(range), id}; + } + + TileCachedRecastMeshManager::WaterIndexValue TileCachedRecastMeshManager::makeWaterIndexValue( + const TilesPositionsRange& range, std::map::const_iterator it) + { + return {makeIndexBox(range), it}; + } + + TileCachedRecastMeshManager::HeightfieldIndexValue TileCachedRecastMeshManager::makeHeightfieldIndexValue( + const TilesPositionsRange& range, std::map::const_iterator it) + { + return {makeIndexBox(range), it}; + } + + auto TileCachedRecastMeshManager::makeIndexQuery(const TilePosition& tilePosition) + -> decltype(boost::geometry::index::intersects(IndexBox())) + { + const IndexPoint point = makeIndexPoint(tilePosition); + return boost::geometry::index::intersects(IndexBox(point, point)); + } + + std::shared_ptr TileCachedRecastMeshManager::makeMesh(const TilePosition& tilePosition) const + { + RecastMeshBuilder builder(makeRealTileBoundsWithBorder(mSettings, tilePosition)); + using Object = std::tuple< + osg::ref_ptr, + ObjectTransform, + std::reference_wrapper, + btTransform, + AreaType + >; + std::vector objects; + Version version; + bool hasInput = false; + { + const std::lock_guard lock(mMutex); + for (auto it = mWaterIndex.qbegin(makeIndexQuery(tilePosition)); it != mWaterIndex.qend(); ++it) + { + const auto& [cellPosition, data] = *it->second; + builder.addWater(cellPosition, data.mWater); + hasInput = true; + } + for (auto it = mHeightfieldIndex.qbegin(makeIndexQuery(tilePosition)); it != mHeightfieldIndex.qend(); ++it) + { + const auto& [cellPosition, data] = *it->second; + std::visit(AddHeightfield {cellPosition, data.mCellSize, builder}, data.mShape); + hasInput = true; + } + objects.reserve(mObjects.size()); + for (auto it = mObjectIndex.qbegin(makeIndexQuery(tilePosition)); it != mObjectIndex.qend(); ++it) + { + const auto& object = it->second->mObject; + objects.emplace_back(object.getInstance(), object.getObjectTransform(), object.getShape(), + object.getTransform(), object.getAreaType()); + hasInput = true; + } + if (hasInput) + { + if (mInfiniteWater != mWater.end()) + builder.addWater(mInfiniteWater->first, mInfiniteWater->second.mWater); + if (mInfiniteHeightfield != mHeightfields.end()) + std::visit( + AddHeightfield {mInfiniteHeightfield->first, mInfiniteHeightfield->second.mCellSize, builder}, + mInfiniteHeightfield->second.mShape + ); + version.mGeneration = mGeneration; + version.mRevision = mRevision; + } + } + if (!hasInput) return nullptr; - const auto it = locked->mTiles.find(tilePosition); - if (it == locked->mTiles.end()) - return nullptr; - return it->second; + for (const auto& [instance, objectTransform, shape, transform, areaType] : objects) + builder.addObject(shape, transform, areaType, instance->getSource(), objectTransform); + return std::move(builder).create(version); + } + + void TileCachedRecastMeshManager::addChangedTiles(const std::optional& range, + ChangeType changeType) + { + if (range.has_value()) + getTilesPositions(*range, [&] (const TilePosition& v) { addChangedTile(v, changeType); }); } } diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index b1bcfa9319..42d79fe383 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -9,17 +9,23 @@ #include "objectid.hpp" #include "areatype.hpp" #include "recastmeshobject.hpp" +#include "commulativeaabb.hpp" +#include "version.hpp" +#include "recastmesh.hpp" #include +#include +#include +#include + #include #include #include -#include +#include namespace DetourNavigator { - class CachedRecastMeshManager; class RecastMesh; class TileCachedRecastMeshManager @@ -29,13 +35,13 @@ namespace DetourNavigator void setBounds(const TileBounds& bounds); - std::string getWorldspace() const; + TilesPositionsRange getRange() const; void setWorldspace(std::string_view worldspace); bool addObject(ObjectId id, const CollisionShape& shape, const btTransform& transform, AreaType areaType); - bool updateObject(ObjectId id, const CollisionShape& shape, const btTransform& transform, AreaType areaType); + bool updateObject(ObjectId id, const btTransform& transform, AreaType areaType); void removeObject(ObjectId id); @@ -47,63 +53,101 @@ namespace DetourNavigator void removeHeightfield(const osg::Vec2i& cellPosition); - std::shared_ptr getMesh(std::string_view worldspace, const TilePosition& tilePosition) const; + std::shared_ptr getMesh(std::string_view worldspace, const TilePosition& tilePosition); std::shared_ptr getCachedMesh(std::string_view worldspace, const TilePosition& tilePosition) const; std::shared_ptr getNewMesh(std::string_view worldspace, const TilePosition& tilePosition) const; - template - void forEachTile(Function&& function) const - { - const auto& locked = mWorldspaceTiles.lockConst(); - for (const auto& [tilePosition, recastMeshManager] : locked->mTiles) - function(tilePosition, *recastMeshManager); - } - std::size_t getRevision() const { return mRevision; } - void reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion) const; + void reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion); void addChangedTile(const TilePosition& tilePosition, ChangeType changeType); - std::map takeChangedTiles() { return std::move(mChangedTiles); } + std::map takeChangedTiles(); private: - using TilesMap = std::map>; + struct Report + { + std::size_t mRevision; + Version mNavMeshVersion; + }; struct ObjectData { - const CollisionShape mShape; - const btTransform mTransform; - const AreaType mAreaType; - std::set mTiles; + RecastMeshObject mObject; + TilesPositionsRange mRange; + CommulativeAabb mAabb; + std::size_t mGeneration = 0; + std::size_t mRevision = 0; + std::optional mLastNavMeshReportedChange; + std::optional mLastNavMeshReport; }; - struct WorldspaceTiles + struct WaterData { - std::string mWorldspace; - TilesMap mTiles; + Water mWater; + std::optional mRange; + std::size_t mRevision; }; + struct HeightfieldData + { + int mCellSize; + HeightfieldShape mShape; + std::optional mRange; + std::size_t mRevision; + }; + + struct CachedTile + { + Version mVersion; + std::shared_ptr mRecastMesh; + }; + + using IndexPoint = boost::geometry::model::point; + using IndexBox = boost::geometry::model::box; + using ObjectIndexValue = std::pair; + using WaterIndexValue = std::pair::const_iterator>; + using HeightfieldIndexValue = std::pair::const_iterator>; + const RecastSettings& mSettings; TileBounds mBounds; TilesPositionsRange mRange; - Misc::ScopeGuarded mWorldspaceTiles; - std::unordered_map mObjects; - std::map> mWaterTilesPositions; - std::map> mHeightfieldTilesPositions; + std::string mWorldspace; + std::unordered_map> mObjects; + boost::geometry::index::rtree> mObjectIndex; + std::map mWater; + std::map::const_iterator mInfiniteWater = mWater.end(); + boost::geometry::index::rtree> mWaterIndex; + std::map mHeightfields; + std::map::const_iterator mInfiniteHeightfield = mHeightfields.end(); + boost::geometry::index::rtree> mHeightfieldIndex; std::map mChangedTiles; + std::map mCache; + std::size_t mGeneration = 0; std::size_t mRevision = 0; - std::size_t mTilesGeneration = 0; + mutable std::mutex mMutex; - inline bool addTile(ObjectId id, const CollisionShape& shape, const btTransform& transform, - AreaType areaType, const TilePosition& tilePosition, TilesMap& tiles); + inline static IndexPoint makeIndexPoint(const TilePosition& tilePosition); - inline bool removeTile(ObjectId id, const TilePosition& tilePosition, TilesMap& tiles); + inline static IndexBox makeIndexBox(const TilesPositionsRange& range); - inline std::shared_ptr getManager(std::string_view worldspace, - const TilePosition& tilePosition) const; + inline static ObjectIndexValue makeObjectIndexValue(const TilesPositionsRange& range, ObjectData* data); + + inline static WaterIndexValue makeWaterIndexValue(const TilesPositionsRange& range, + std::map::const_iterator it); + + inline static HeightfieldIndexValue makeHeightfieldIndexValue(const TilesPositionsRange& range, + std::map::const_iterator it); + + inline static auto makeIndexQuery(const TilePosition& tilePosition) + -> decltype(boost::geometry::index::intersects(IndexBox())); + + inline std::shared_ptr makeMesh(const TilePosition& tilePosition) const; + + inline void addChangedTiles(const std::optional& range, ChangeType changeType); }; } diff --git a/components/detournavigator/tilespositionsrange.hpp b/components/detournavigator/tilespositionsrange.hpp index d5f2622ba1..0d92dd0e6d 100644 --- a/components/detournavigator/tilespositionsrange.hpp +++ b/components/detournavigator/tilespositionsrange.hpp @@ -3,6 +3,8 @@ #include "tileposition.hpp" +#include + namespace DetourNavigator { struct TilesPositionsRange @@ -10,6 +12,16 @@ namespace DetourNavigator TilePosition mBegin; TilePosition mEnd; }; + + inline auto tie(const TilesPositionsRange& value) + { + return std::tie(value.mBegin, value.mEnd); + } + + inline bool operator==(const TilesPositionsRange& lhs, const TilesPositionsRange& rhs) + { + return tie(lhs) == tie(rhs); + } } #endif From 22ee592dd36304e771da758f06d4c30b23f8b0b6 Mon Sep 17 00:00:00 2001 From: elsid Date: Mon, 5 Sep 2022 09:23:14 +0200 Subject: [PATCH 03/36] Lock TileCachedRecastMeshManager once per changing a cell To save time on locking mutex and prevent AsyncNavMeshUpdater to use RecastMesh for a tile in the middle of objects loading. --- apps/navmeshtool/worldspacedata.cpp | 14 +- apps/openmw/mwworld/scene.cpp | 100 +++++--- apps/openmw/mwworld/scene.hpp | 10 +- apps/openmw/mwworld/worldimp.cpp | 19 +- apps/openmw/mwworld/worldimp.hpp | 3 +- .../detournavigator/asyncnavmeshupdater.cpp | 52 ++--- .../detournavigator/navigator.cpp | 221 +++++++++--------- .../tilecachedrecastmeshmanager.cpp | 164 ++++++------- .../detournavigator/asyncnavmeshupdater.cpp | 21 +- .../detournavigator/asyncnavmeshupdater.hpp | 4 +- components/detournavigator/navigator.hpp | 37 +-- components/detournavigator/navigatorimpl.cpp | 88 +++---- components/detournavigator/navigatorimpl.hpp | 66 ++++-- components/detournavigator/navigatorstub.hpp | 35 +-- components/detournavigator/navmeshmanager.cpp | 44 ++-- components/detournavigator/navmeshmanager.hpp | 38 ++- .../tilecachedrecastmeshmanager.cpp | 52 +++-- .../tilecachedrecastmeshmanager.hpp | 31 ++- 18 files changed, 570 insertions(+), 429 deletions(-) diff --git a/apps/navmeshtool/worldspacedata.cpp b/apps/navmeshtool/worldspacedata.cpp index b3efa69430..e43cfec96c 100644 --- a/apps/navmeshtool/worldspacedata.cpp +++ b/apps/navmeshtool/worldspacedata.cpp @@ -276,11 +276,13 @@ namespace NavMeshTool { it = navMeshInputs.emplace(cell.mCellId.mWorldspace, std::make_unique(cell.mCellId.mWorldspace, settings.mRecast)).first; - it->second->mTileCachedRecastMeshManager.setWorldspace(cell.mCellId.mWorldspace); + it->second->mTileCachedRecastMeshManager.setWorldspace(cell.mCellId.mWorldspace, nullptr); } return *it->second; } (); + const TileCachedRecastMeshManager::UpdateGuard guard(navMeshInput.mTileCachedRecastMeshManager); + if (exterior) { const auto it = std::lower_bound(esmData.mLands.begin(), esmData.mLands.end(), cellPosition, LessByXY {}); @@ -292,14 +294,14 @@ namespace NavMeshTool mergeOrAssign(getAabb(cellPosition, minHeight, maxHeight), navMeshInput.mAabb, navMeshInput.mAabbInitialized); - navMeshInput.mTileCachedRecastMeshManager.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, heightfieldShape); + navMeshInput.mTileCachedRecastMeshManager.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, heightfieldShape, &guard); - navMeshInput.mTileCachedRecastMeshManager.addWater(cellPosition, ESM::Land::REAL_SIZE, -1); + navMeshInput.mTileCachedRecastMeshManager.addWater(cellPosition, ESM::Land::REAL_SIZE, -1, &guard); } else { if ((cell.mData.mFlags & ESM::Cell::HasWater) != 0) - navMeshInput.mTileCachedRecastMeshManager.addWater(cellPosition, std::numeric_limits::max(), cell.mWater); + navMeshInput.mTileCachedRecastMeshManager.addWater(cellPosition, std::numeric_limits::max(), cell.mWater, &guard); } forEachObject(cell, esmData, vfs, bulletShapeManager, readers, @@ -318,13 +320,13 @@ namespace NavMeshTool const CollisionShape shape(object.getShapeInstance(), *object.getCollisionObject().getCollisionShape(), object.getObjectTransform()); navMeshInput.mTileCachedRecastMeshManager.addObject(objectId, shape, transform, - DetourNavigator::AreaType_ground); + DetourNavigator::AreaType_ground, &guard); if (const btCollisionShape* avoid = object.getShapeInstance()->mAvoidCollisionShape.get()) { const CollisionShape avoidShape(object.getShapeInstance(), *avoid, object.getObjectTransform()); navMeshInput.mTileCachedRecastMeshManager.addObject(objectId, avoidShape, transform, - DetourNavigator::AreaType_null); + DetourNavigator::AreaType_null, &guard); } data.mObjects.emplace_back(std::move(object)); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 29c8b6f76b..09c757a874 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -135,7 +136,7 @@ namespace } void addObject(const MWWorld::Ptr& ptr, const MWWorld::World& world, const MWPhysics::PhysicsSystem& physics, - DetourNavigator::Navigator& navigator) + DetourNavigator::Navigator& navigator, const DetourNavigator::UpdateGuard* navigatorUpdateGuard = nullptr) { if (const auto object = physics.getObject(ptr)) { @@ -173,7 +174,8 @@ namespace navigator.addObject( DetourNavigator::ObjectId(object), DetourNavigator::DoorShapes(object->getShapeInstance(), objectTransform, connectionStart, connectionEnd), - transform + transform, + navigatorUpdateGuard ); } else if (object->getShapeInstance()->mVisualCollisionType == Resource::VisualCollisionType::None) @@ -181,7 +183,8 @@ namespace navigator.addObject( DetourNavigator::ObjectId(object), DetourNavigator::ObjectShapes(object->getShapeInstance(), objectTransform), - object->getTransform() + object->getTransform(), + navigatorUpdateGuard ); } } @@ -320,7 +323,7 @@ namespace MWWorld preloadCells(duration); } - void Scene::unloadCell(CellStore* cell) + void Scene::unloadCell(CellStore* cell, const DetourNavigator::UpdateGuard* navigatorUpdateGuard) { if (mActiveCells.find(cell) == mActiveCells.end()) return; @@ -335,7 +338,7 @@ namespace MWWorld if (const auto object = mPhysics->getObject(ptr)) { if (object->getShapeInstance()->mVisualCollisionType == Resource::VisualCollisionType::None) - mNavigator.removeObject(DetourNavigator::ObjectId(object)); + mNavigator.removeObject(DetourNavigator::ObjectId(object), navigatorUpdateGuard); mPhysics->remove(ptr); ptr.mRef->mData.mPhysicsPostponed = false; } @@ -354,13 +357,13 @@ namespace MWWorld if (cell->getCell()->isExterior()) { if (mPhysics->getHeightField(cellX, cellY) != nullptr) - mNavigator.removeHeightfield(osg::Vec2i(cellX, cellY)); + mNavigator.removeHeightfield(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); mPhysics->removeHeightField(cellX, cellY); } if (cell->getCell()->hasWater()) - mNavigator.removeWater(osg::Vec2i(cellX, cellY)); + mNavigator.removeWater(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); if (const auto pathgrid = mWorld.getStore().get().search(*cell->getCell())) mNavigator.removePathgrid(*pathgrid); @@ -379,7 +382,8 @@ namespace MWWorld mRendering.notifyWorldSpaceChanged(); } - void Scene::loadCell(CellStore *cell, Loading::Listener* loadingListener, bool respawn, const osg::Vec3f& position) + void Scene::loadCell(CellStore *cell, Loading::Listener* loadingListener, bool respawn, const osg::Vec3f& position, + const DetourNavigator::UpdateGuard* navigatorUpdateGuard) { using DetourNavigator::HeightfieldShape; @@ -428,7 +432,7 @@ namespace MWWorld return heights; } } (); - mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape); + mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape, navigatorUpdateGuard); } } @@ -442,7 +446,7 @@ namespace MWWorld if (respawn) cell->respawn(); - insertCell(*cell, loadingListener); + insertCell(*cell, loadingListener, navigatorUpdateGuard); mRendering.addCell(cell); @@ -458,18 +462,18 @@ namespace MWWorld if (cell->getCell()->isExterior()) { if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) - mNavigator.addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, waterLevel); + mNavigator.addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, waterLevel, + navigatorUpdateGuard); } else { - mNavigator.addWater(osg::Vec2i(cellX, cellY), std::numeric_limits::max(), waterLevel); + mNavigator.addWater(osg::Vec2i(cellX, cellY), std::numeric_limits::max(), waterLevel, + navigatorUpdateGuard); } } else mPhysics->disableWater(); - mNavigator.update(position); - if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) mRendering.configureAmbient(cell->getCell()); @@ -478,11 +482,13 @@ namespace MWWorld void Scene::clear() { + auto navigatorUpdateGuard = mNavigator.makeUpdateGuard(); for (auto iter = mActiveCells.begin(); iter!=mActiveCells.end(); ) { auto* cell = *iter++; - unloadCell (cell); + unloadCell(cell, navigatorUpdateGuard.get()); } + navigatorUpdateGuard.reset(); assert(mActiveCells.empty()); mCurrentCell = nullptr; @@ -525,6 +531,8 @@ namespace MWWorld void Scene::changeCellGrid (const osg::Vec3f &pos, int playerCellX, int playerCellY, bool changeEvent) { + auto navigatorUpdateGuard = mNavigator.makeUpdateGuard(); + for (auto iter = mActiveCells.begin(); iter != mActiveCells.end(); ) { auto* cell = *iter++; @@ -533,14 +541,15 @@ namespace MWWorld const auto dx = std::abs(playerCellX - cell->getCell()->getGridX()); const auto dy = std::abs(playerCellY - cell->getCell()->getGridY()); if (dx > mHalfGridSize || dy > mHalfGridSize) - unloadCell(cell); + unloadCell(cell, navigatorUpdateGuard.get()); } else - unloadCell (cell); + unloadCell(cell, navigatorUpdateGuard.get()); } - mNavigator.setWorldspace(mWorld.getExterior(playerCellX, playerCellY)->getCell()->mCellId.mWorldspace); - mNavigator.updateBounds(pos); + mNavigator.setWorldspace(mWorld.getExterior(playerCellX, playerCellY)->getCell()->mCellId.mWorldspace, + navigatorUpdateGuard.get()); + mNavigator.updateBounds(pos, navigatorUpdateGuard.get()); mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY); osg::Vec4i newGrid = gridCenterToBounds(mCurrentGridCenter); @@ -601,10 +610,14 @@ namespace MWWorld if (!isCellInCollection(x, y, mActiveCells)) { CellStore *cell = mWorld.getExterior(x, y); - loadCell(cell, loadingListener, changeEvent, pos); + loadCell(cell, loadingListener, changeEvent, pos, navigatorUpdateGuard.get()); } } + mNavigator.update(pos, navigatorUpdateGuard.get()); + + navigatorUpdateGuard.reset(); + CellStore* current = mWorld.getExterior(playerCellX, playerCellY); MWBase::Environment::get().getWindowManager()->changeCell(current); @@ -653,15 +666,21 @@ namespace MWWorld MWWorld::Store::iterator it = cells.extBegin(); int i = 1; + auto navigatorUpdateGuard = mNavigator.makeUpdateGuard(); for (; it != cells.extEnd(); ++it) { loadingListener->setLabel("Testing exterior cells ("+std::to_string(i)+"/"+std::to_string(cells.getExtSize())+")..."); CellStore *cell = mWorld.getExterior(it->mData.mX, it->mData.mY); - mNavigator.setWorldspace(cell->getCell()->mCellId.mWorldspace); + mNavigator.setWorldspace(cell->getCell()->mCellId.mWorldspace, navigatorUpdateGuard.get()); const osg::Vec3f position = osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits; - mNavigator.updateBounds(position); - loadCell(cell, nullptr, false, position); + mNavigator.updateBounds(position, navigatorUpdateGuard.get()); + loadCell(cell, nullptr, false, position, navigatorUpdateGuard.get()); + + mNavigator.update(position, navigatorUpdateGuard.get()); + navigatorUpdateGuard.reset(); + mNavigator.wait(DetourNavigator::WaitConditionType::requiredTilesPresent, nullptr); + navigatorUpdateGuard = mNavigator.makeUpdateGuard(); auto iter = mActiveCells.begin(); while (iter != mActiveCells.end()) @@ -669,7 +688,7 @@ namespace MWWorld if (it->isExterior() && it->mData.mX == (*iter)->getCell()->getGridX() && it->mData.mY == (*iter)->getCell()->getGridY()) { - unloadCell(*iter); + unloadCell(*iter, navigatorUpdateGuard.get()); break; } @@ -701,16 +720,22 @@ namespace MWWorld int i = 1; MWWorld::Store::iterator it = cells.intBegin(); + auto navigatorUpdateGuard = mNavigator.makeUpdateGuard(); for (; it != cells.intEnd(); ++it) { loadingListener->setLabel("Testing interior cells ("+std::to_string(i)+"/"+std::to_string(cells.getIntSize())+")..."); CellStore *cell = mWorld.getInterior(it->mName); - mNavigator.setWorldspace(cell->getCell()->mCellId.mWorldspace); + mNavigator.setWorldspace(cell->getCell()->mCellId.mWorldspace, navigatorUpdateGuard.get()); ESM::Position position; mWorld.findInteriorPosition(it->mName, position); - mNavigator.updateBounds(position.asVec3()); - loadCell(cell, nullptr, false, position.asVec3()); + mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); + loadCell(cell, nullptr, false, position.asVec3(), navigatorUpdateGuard.get()); + + mNavigator.update(position.asVec3(), navigatorUpdateGuard.get()); + navigatorUpdateGuard.reset(); + mNavigator.wait(DetourNavigator::WaitConditionType::requiredTilesPresent, nullptr); + navigatorUpdateGuard = mNavigator.makeUpdateGuard(); auto iter = mActiveCells.begin(); while (iter != mActiveCells.end()) @@ -719,7 +744,7 @@ namespace MWWorld if (it->mName == (*iter)->getCell()->mName) { - unloadCell(*iter); + unloadCell(*iter, navigatorUpdateGuard.get()); break; } @@ -838,22 +863,26 @@ namespace MWWorld Log(Debug::Info) << "Changing to interior"; + auto navigatorUpdateGuard = mNavigator.makeUpdateGuard(); + // unload for (auto iter = mActiveCells.begin(); iter!=mActiveCells.end(); ) { auto* cellToUnload = *iter++; - unloadCell(cellToUnload); + unloadCell(cellToUnload, navigatorUpdateGuard.get()); } assert(mActiveCells.empty()); loadingListener->setProgressRange(cell->count()); - mNavigator.setWorldspace(cell->getCell()->mCellId.mWorldspace); - mNavigator.updateBounds(position.asVec3()); + mNavigator.setWorldspace(cell->getCell()->mCellId.mWorldspace, navigatorUpdateGuard.get()); + mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); // Load cell. mPagedRefs.clear(); - loadCell(cell, loadingListener, changeEvent, position.asVec3()); + loadCell(cell, loadingListener, changeEvent, position.asVec3(), navigatorUpdateGuard.get()); + + navigatorUpdateGuard.reset(); changePlayerCell(cell, position, adjustPlayerPos); @@ -904,12 +933,13 @@ namespace MWWorld mCellChanged = false; } - void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener) + void Scene::insertCell(CellStore &cell, Loading::Listener* loadingListener, + const DetourNavigator::UpdateGuard* navigatorUpdateGuard) { InsertVisitor insertVisitor(cell, loadingListener); cell.forEach (insertVisitor); insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, mWorld, mPagedRefs, *mPhysics, mRendering); }); - insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, mWorld, *mPhysics, mNavigator); }); + insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, mWorld, *mPhysics, mNavigator, navigatorUpdateGuard); }); } void Scene::addObjectToScene (const Ptr& ptr) @@ -938,7 +968,7 @@ namespace MWWorld if (const auto object = mPhysics->getObject(ptr)) { if (object->getShapeInstance()->mVisualCollisionType == Resource::VisualCollisionType::None) - mNavigator.removeObject(DetourNavigator::ObjectId(object)); + mNavigator.removeObject(DetourNavigator::ObjectId(object), nullptr); } else if (mPhysics->getActor(ptr)) { diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 7e69e8e97d..f0246f0882 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -38,6 +38,7 @@ namespace Loading namespace DetourNavigator { struct Navigator; + class UpdateGuard; } namespace MWRender @@ -110,7 +111,9 @@ namespace MWWorld std::optional mChangeCellGridRequest; - void insertCell(CellStore &cell, Loading::Listener* loadingListener); + void insertCell(CellStore &cell, Loading::Listener* loadingListener, + const DetourNavigator::UpdateGuard* navigatorUpdateGuard); + osg::Vec2i mCurrentGridCenter; // Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center @@ -128,8 +131,9 @@ namespace MWWorld osg::Vec4i gridCenterToBounds(const osg::Vec2i ¢erCell) const; osg::Vec2i getNewGridCenter(const osg::Vec3f &pos, const osg::Vec2i *currentGridCenter = nullptr) const; - void unloadCell(CellStore* cell); - void loadCell(CellStore *cell, Loading::Listener* loadingListener, bool respawn, const osg::Vec3f& position); + void unloadCell(CellStore* cell, const DetourNavigator::UpdateGuard* navigatorUpdateGuard); + void loadCell(CellStore *cell, Loading::Listener* loadingListener, bool respawn, const osg::Vec3f& position, + const DetourNavigator::UpdateGuard* navigatorUpdateGuard); public: diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fc90a14b25..375351e606 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -1541,28 +1542,32 @@ namespace MWWorld void World::updateNavigator() { + auto navigatorUpdateGuard = mNavigator->makeUpdateGuard(); + mPhysics->forEachAnimatedObject([&] (const auto& pair) { const auto [object, changed] = pair; if (changed) - updateNavigatorObject(*object); + updateNavigatorObject(*object, navigatorUpdateGuard.get()); }); for (const auto& door : mDoorStates) if (const auto object = mPhysics->getObject(door.first)) - updateNavigatorObject(*object); + updateNavigatorObject(*object, navigatorUpdateGuard.get()); - mNavigator->update(getPlayerPtr().getRefData().getPosition().asVec3()); + mNavigator->update(getPlayerPtr().getRefData().getPosition().asVec3(), navigatorUpdateGuard.get()); } - void World::updateNavigatorObject(const MWPhysics::Object& object) + void World::updateNavigatorObject(const MWPhysics::Object& object, + const DetourNavigator::UpdateGuard* navigatorUpdateGuard) { if (object.getShapeInstance()->mVisualCollisionType != Resource::VisualCollisionType::None) return; const MWWorld::Ptr ptr = object.getPtr(); const DetourNavigator::ObjectShapes shapes(object.getShapeInstance(), DetourNavigator::ObjectTransform {ptr.getRefData().getPosition(), ptr.getCellRef().getScale()}); - mNavigator->updateObject(DetourNavigator::ObjectId(&object), shapes, object.getTransform()); + mNavigator->updateObject(DetourNavigator::ObjectId(&object), shapes, object.getTransform(), + navigatorUpdateGuard); } const MWPhysics::RayCastingInterface* World::getRayCasting() const @@ -1854,8 +1859,8 @@ namespace MWWorld if (mWorldScene->hasCellLoaded()) { - mNavigator->wait(*MWBase::Environment::get().getWindowManager()->getLoadingScreen(), - DetourNavigator::WaitConditionType::requiredTilesPresent); + mNavigator->wait(DetourNavigator::WaitConditionType::requiredTilesPresent, + MWBase::Environment::get().getWindowManager()->getLoadingScreen()); mWorldScene->resetCellLoaded(); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1110478074..e6085b7f79 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -166,7 +166,8 @@ namespace MWWorld void updateNavigator(); - void updateNavigatorObject(const MWPhysics::Object& object); + void updateNavigatorObject(const MWPhysics::Object& object, + const DetourNavigator::UpdateGuard* navigatorUpdateGuard = nullptr); void ensureNeededRecords(); diff --git a/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp b/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp index b43cdf329f..1c7db0d31d 100644 --- a/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp +++ b/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp @@ -25,7 +25,7 @@ namespace void addHeightFieldPlane(TileCachedRecastMeshManager& recastMeshManager, const osg::Vec2i cellPosition = osg::Vec2i(0, 0)) { const int cellSize = 8192; - recastMeshManager.addHeightfield(cellPosition, cellSize, HeightfieldPlane {0}); + recastMeshManager.addHeightfield(cellPosition, cellSize, HeightfieldPlane {0}, nullptr); } void addObject(const btBoxShape& shape, TileCachedRecastMeshManager& recastMeshManager) @@ -42,7 +42,7 @@ namespace osg::ref_ptr(new Resource::BulletShapeInstance(bulletShape)), shape, objectTransform ); - recastMeshManager.addObject(id, collisionShape, btTransform::getIdentity(), AreaType_ground); + recastMeshManager.addObject(id, collisionShape, btTransform::getIdentity(), AreaType_ground, nullptr); } struct DetourNavigatorAsyncNavMeshUpdaterTest : Test @@ -60,43 +60,43 @@ namespace TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, for_all_jobs_done_when_empty_wait_should_terminate) { AsyncNavMeshUpdater updater {mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr}; - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); } TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, for_required_tiles_present_when_empty_wait_should_terminate) { AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr); - updater.wait(mListener, WaitConditionType::requiredTilesPresent); + updater.wait(WaitConditionType::requiredTilesPresent, &mListener); } TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_should_generate_navmesh_tile) { - mRecastMeshManager.setWorldspace(mWorldspace); + mRecastMeshManager.setWorldspace(mWorldspace, nullptr); addHeightFieldPlane(mRecastMeshManager); AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr); const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const std::map changedTiles {{TilePosition {0, 0}, ChangeType::add}}; updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); EXPECT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0u); } TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, repeated_post_should_lead_to_cache_hit) { - mRecastMeshManager.setWorldspace(mWorldspace); + mRecastMeshManager.setWorldspace(mWorldspace, nullptr); addHeightFieldPlane(mRecastMeshManager); AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr); const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const std::map changedTiles {{TilePosition {0, 0}, ChangeType::add}}; updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); { const auto stats = updater.getStats(); ASSERT_EQ(stats.mCache.mGetCount, 1); ASSERT_EQ(stats.mCache.mHitCount, 0); } updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); { const auto stats = updater.getStats(); EXPECT_EQ(stats.mCache.mGetCount, 2); @@ -106,20 +106,20 @@ namespace TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_for_update_change_type_should_not_update_cache) { - mRecastMeshManager.setWorldspace(mWorldspace); + mRecastMeshManager.setWorldspace(mWorldspace, nullptr); addHeightFieldPlane(mRecastMeshManager); AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr); const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const std::map changedTiles {{TilePosition {0, 0}, ChangeType::update}}; updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); { const auto stats = updater.getStats(); ASSERT_EQ(stats.mCache.mGetCount, 1); ASSERT_EQ(stats.mCache.mHitCount, 0); } updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); { const auto stats = updater.getStats(); EXPECT_EQ(stats.mCache.mGetCount, 2); @@ -129,7 +129,7 @@ namespace TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_should_write_generated_tile_to_db) { - mRecastMeshManager.setWorldspace(mWorldspace); + mRecastMeshManager.setWorldspace(mWorldspace, nullptr); addHeightFieldPlane(mRecastMeshManager); addObject(mBox, mRecastMeshManager); auto db = std::make_unique(":memory:", std::numeric_limits::max()); @@ -139,7 +139,7 @@ namespace const TilePosition tilePosition {0, 0}; const std::map changedTiles {{tilePosition, ChangeType::add}}; updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); updater.stop(); const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition); ASSERT_NE(recastMesh, nullptr); @@ -155,7 +155,7 @@ namespace TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_when_writing_to_db_disabled_should_not_write_tiles) { - mRecastMeshManager.setWorldspace(mWorldspace); + mRecastMeshManager.setWorldspace(mWorldspace, nullptr); addHeightFieldPlane(mRecastMeshManager); addObject(mBox, mRecastMeshManager); auto db = std::make_unique(":memory:", std::numeric_limits::max()); @@ -166,7 +166,7 @@ namespace const TilePosition tilePosition {0, 0}; const std::map changedTiles {{tilePosition, ChangeType::add}}; updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); updater.stop(); const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition); ASSERT_NE(recastMesh, nullptr); @@ -180,7 +180,7 @@ namespace TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_when_writing_to_db_disabled_should_not_write_shapes) { - mRecastMeshManager.setWorldspace(mWorldspace); + mRecastMeshManager.setWorldspace(mWorldspace, nullptr); addHeightFieldPlane(mRecastMeshManager); addObject(mBox, mRecastMeshManager); auto db = std::make_unique(":memory:", std::numeric_limits::max()); @@ -191,7 +191,7 @@ namespace const TilePosition tilePosition {0, 0}; const std::map changedTiles {{tilePosition, ChangeType::add}}; updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); updater.stop(); const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition); ASSERT_NE(recastMesh, nullptr); @@ -202,7 +202,7 @@ namespace TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_should_read_from_db_on_cache_miss) { - mRecastMeshManager.setWorldspace(mWorldspace); + mRecastMeshManager.setWorldspace(mWorldspace, nullptr); addHeightFieldPlane(mRecastMeshManager); mSettings.mMaxNavMeshTilesCacheSize = 0; AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, @@ -210,7 +210,7 @@ namespace const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const std::map changedTiles {{TilePosition {0, 0}, ChangeType::add}}; updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); { const auto stats = updater.getStats(); ASSERT_EQ(stats.mCache.mGetCount, 1); @@ -220,7 +220,7 @@ namespace ASSERT_EQ(stats.mDbGetTileHits, 0); } updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); { const auto stats = updater.getStats(); EXPECT_EQ(stats.mCache.mGetCount, 2); @@ -233,24 +233,24 @@ namespace TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, on_changing_player_tile_post_should_remove_tiles_out_of_range) { - mRecastMeshManager.setWorldspace(mWorldspace); + mRecastMeshManager.setWorldspace(mWorldspace, nullptr); addHeightFieldPlane(mRecastMeshManager); AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr); const auto navMeshCacheItem = std::make_shared(makeEmptyNavMesh(mSettings), 1); const std::map changedTilesAdd {{TilePosition {0, 0}, ChangeType::add}}; updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTilesAdd); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); ASSERT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0u); const std::map changedTilesRemove {{TilePosition {0, 0}, ChangeType::remove}}; const TilePosition playerTile(100, 100); updater.post(mAgentBounds, navMeshCacheItem, playerTile, mWorldspace, changedTilesRemove); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); EXPECT_EQ(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0u); } TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, should_stop_writing_to_db_when_size_limit_is_reached) { - mRecastMeshManager.setWorldspace(mWorldspace); + mRecastMeshManager.setWorldspace(mWorldspace, nullptr); for (int x = -1; x <= 1; ++x) for (int y = -1; y <= 1; ++y) addHeightFieldPlane(mRecastMeshManager, osg::Vec2i(x, y)); @@ -264,7 +264,7 @@ namespace for (int y = -5; y <= 5; ++y) changedTiles.emplace(TilePosition {x, y}, ChangeType::add); updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); - updater.wait(mListener, WaitConditionType::allJobsDone); + updater.wait(WaitConditionType::allJobsDone, &mListener); updater.stop(); const std::set present { TilePosition(-2, 0), diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 765f27e88a..23df6c1e93 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -155,9 +155,11 @@ namespace const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent); + auto updateGuard = mNavigator->makeUpdateGuard(); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, updateGuard.get()); + mNavigator->update(mPlayerPosition, updateGuard.get()); + updateGuard.reset(); + mNavigator->wait(WaitConditionType::requiredTilesPresent, &mListener); EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); @@ -207,9 +209,9 @@ namespace compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100))); mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); @@ -239,9 +241,12 @@ namespace Vec3fEq(460, 56.66666412353515625, 1.99998295307159423828125) )) << mPath; - mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + { + auto updateGuard = mNavigator->makeUpdateGuard(); + mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, updateGuard.get()); + mNavigator->update(mPlayerPosition, updateGuard.get()); + } + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); mPath.clear(); mOut = std::back_inserter(mPath); @@ -291,10 +296,10 @@ namespace compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100))); mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); @@ -327,9 +332,9 @@ namespace compound.shape().updateChildTransform(0, btTransform(btMatrix3x3::getIdentity(), btVector3(1000, 0, 0))); - mNavigator->updateObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->updateObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); mPath.clear(); mOut = std::back_inserter(mPath); @@ -385,10 +390,10 @@ namespace heightfield2.shape().setLocalScaling(btVector3(128, 128, 1)); mNavigator->addAgent(mAgentBounds); - mNavigator->addObject(ObjectId(&heightfield1.shape()), ObjectShapes(heightfield1.instance(), mObjectTransform), mTransform); - mNavigator->addObject(ObjectId(&heightfield2.shape()), ObjectShapes(heightfield2.instance(), mObjectTransform), mTransform); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addObject(ObjectId(&heightfield1.shape()), ObjectShapes(heightfield1.instance(), mObjectTransform), mTransform, nullptr); + mNavigator->addObject(ObjectId(&heightfield2.shape()), ObjectShapes(heightfield2.instance(), mObjectTransform), mTransform, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); @@ -442,15 +447,15 @@ namespace const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1); mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize1, surface1); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addHeightfield(mCellPosition, cellSize1, surface1, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); const Version version = mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(); - mNavigator->addHeightfield(mCellPosition, cellSize2, surface2); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addHeightfield(mCellPosition, cellSize2, surface2, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); EXPECT_EQ(mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(), version); } @@ -484,9 +489,9 @@ namespace osg::ref_ptr instance(new Resource::BulletShapeInstance(bulletShape)); mNavigator->addAgent(mAgentBounds); - mNavigator->addObject(ObjectId(instance->mCollisionShape.get()), ObjectShapes(instance, mObjectTransform), mTransform); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addObject(ObjectId(instance->mCollisionShape.get()), ObjectShapes(instance, mObjectTransform), mTransform, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); @@ -531,10 +536,10 @@ namespace const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); mNavigator->addAgent(mAgentBounds); - mNavigator->addWater(mCellPosition, cellSize, 300); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addWater(mCellPosition, cellSize, 300, nullptr); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); mStart.x() = 256; mStart.z() = 300; @@ -579,10 +584,10 @@ namespace const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); mNavigator->addAgent(mAgentBounds); - mNavigator->addWater(mCellPosition, cellSize, -25); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addWater(mCellPosition, cellSize, -25, nullptr); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); mStart.x() = 256; mEnd.x() = 256; @@ -625,10 +630,10 @@ namespace const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->addWater(mCellPosition, std::numeric_limits::max(), -25); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->addWater(mCellPosition, std::numeric_limits::max(), -25, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); mStart.x() = 256; mEnd.x() = 256; @@ -671,10 +676,10 @@ namespace const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); mNavigator->addAgent(mAgentBounds); - mNavigator->addWater(mCellPosition, cellSize, -25); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addWater(mCellPosition, cellSize, -25, nullptr); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); mStart.x() = 256; mEnd.x() = 256; @@ -715,17 +720,17 @@ namespace heightfield.shape().setLocalScaling(btVector3(128, 128, 1)); mNavigator->addAgent(mAgentBounds); - mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance(), mObjectTransform), mTransform); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance(), mObjectTransform), mTransform, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); - mNavigator->removeObject(ObjectId(&heightfield.shape())); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->removeObject(ObjectId(&heightfield.shape()), nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); - mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance(), mObjectTransform), mTransform); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance(), mObjectTransform), mTransform, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); @@ -769,17 +774,17 @@ namespace const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); - mNavigator->removeHeightfield(mCellPosition); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->removeHeightfield(mCellPosition, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); @@ -824,9 +829,9 @@ namespace const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); Misc::Rng::init(42); @@ -862,12 +867,12 @@ namespace mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); for (std::size_t i = 0; i < boxes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(shift.x() + i * 10, shift.y() + i * 10, i * 10)); - mNavigator->addObject(ObjectId(&boxes[i].shape()), ObjectShapes(boxes[i].instance(), mObjectTransform), transform); + mNavigator->addObject(ObjectId(&boxes[i].shape()), ObjectShapes(boxes[i].instance(), mObjectTransform), transform, nullptr); } std::this_thread::sleep_for(std::chrono::microseconds(1)); @@ -875,11 +880,11 @@ namespace for (std::size_t i = 0; i < boxes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(shift.x() + i * 10 + 1, shift.y() + i * 10 + 1, i * 10 + 1)); - mNavigator->updateObject(ObjectId(&boxes[i].shape()), ObjectShapes(boxes[i].instance(), mObjectTransform), transform); + mNavigator->updateObject(ObjectId(&boxes[i].shape()), ObjectShapes(boxes[i].instance(), mObjectTransform), transform, nullptr); } - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); @@ -921,27 +926,27 @@ namespace for (std::size_t i = 0; i < shapes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 32, i * 32, i * 32)); - mNavigator->addObject(ObjectId(&shapes[i].shape()), ObjectShapes(shapes[i].instance(), mObjectTransform), transform); + mNavigator->addObject(ObjectId(&shapes[i].shape()), ObjectShapes(shapes[i].instance(), mObjectTransform), transform, nullptr); } - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); const auto start = std::chrono::steady_clock::now(); for (std::size_t i = 0; i < shapes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 32 + 1, i * 32 + 1, i * 32 + 1)); - mNavigator->updateObject(ObjectId(&shapes[i].shape()), ObjectShapes(shapes[i].instance(), mObjectTransform), transform); + mNavigator->updateObject(ObjectId(&shapes[i].shape()), ObjectShapes(shapes[i].instance(), mObjectTransform), transform, nullptr); } - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); for (std::size_t i = 0; i < shapes.size(); ++i) { const btTransform transform(btMatrix3x3::getIdentity(), btVector3(i * 32 + 2, i * 32 + 2, i * 32 + 2)); - mNavigator->updateObject(ObjectId(&shapes[i].shape()), ObjectShapes(shapes[i].instance(), mObjectTransform), transform); + mNavigator->updateObject(ObjectId(&shapes[i].shape()), ObjectShapes(shapes[i].instance(), mObjectTransform), transform, nullptr); } - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); const auto duration = std::chrono::steady_clock::now() - start; @@ -962,9 +967,9 @@ namespace const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); const osg::Vec3f start(57, 460, 1); const osg::Vec3f end(460, 57, 1); @@ -991,14 +996,14 @@ namespace CollisionShapeInstance borderBox(std::make_unique(btVector3(50, 50, 50))); mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->addObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance(), mObjectTransform), - btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition)); + btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition), nullptr); // add this box to make navmesh bound box independent from oscillatingBoxShape rotations mNavigator->addObject(ObjectId(&borderBox.shape()), ObjectShapes(borderBox.instance(), mObjectTransform), - btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition + btVector3(0, 0, 200))); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition + btVector3(0, 0, 200)), nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); const Version expectedVersion {1, 4}; @@ -1010,9 +1015,9 @@ namespace { const btTransform transform(btQuaternion(btVector3(0, 0, 1), n * 2 * osg::PI / 10), oscillatingBoxShapePosition); - mNavigator->updateObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance(), mObjectTransform), transform); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->updateObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance(), mObjectTransform), transform, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); } ASSERT_EQ(navMeshes.size(), 1); @@ -1025,9 +1030,9 @@ namespace const int cellSize = mHeightfieldTileSize * 4; mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, plane); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent); + mNavigator->addHeightfield(mCellPosition, cellSize, plane, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::requiredTilesPresent, &mListener); EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::Success); @@ -1075,10 +1080,10 @@ namespace new btBoxShape(btVector3(200, 200, 1000))); mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::PartialPath); @@ -1114,10 +1119,10 @@ namespace new btBoxShape(btVector3(100, 100, 1000))); mNavigator->addAgent(mAgentBounds); - mNavigator->addHeightfield(mCellPosition, cellSize, surface); - mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); + mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); const float endTolerance = 1000.0f; @@ -1154,15 +1159,15 @@ namespace const float level2 = 2; mNavigator->addAgent(mAgentBounds); - mNavigator->addWater(mCellPosition, cellSize1, level1); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addWater(mCellPosition, cellSize1, level1, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); const Version version = mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(); - mNavigator->addWater(mCellPosition, cellSize2, level2); - mNavigator->update(mPlayerPosition); - mNavigator->wait(mListener, WaitConditionType::allJobsDone); + mNavigator->addWater(mCellPosition, cellSize2, level2, nullptr); + mNavigator->update(mPlayerPosition, nullptr); + mNavigator->wait(WaitConditionType::allJobsDone, &mListener); EXPECT_EQ(mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(), version); } diff --git a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp index 71ef657e22..1068bedea0 100644 --- a/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/apps/openmw_test_suite/detournavigator/tilecachedrecastmeshmanager.cpp @@ -48,7 +48,7 @@ namespace TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - EXPECT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); + EXPECT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr)); } TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_for_existing_object_should_return_false) @@ -56,17 +56,17 @@ namespace TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); - EXPECT_FALSE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); + EXPECT_FALSE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr)); } TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_object_should_add_tiles) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); + ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr)); for (int x = -1; x < 1; ++x) for (int y = -1; y < 1; ++y) ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr); @@ -80,9 +80,9 @@ namespace TileBounds bounds; bounds.mMin = osg::Vec2f(182, 182); bounds.mMax = osg::Vec2f(1000, 1000); - manager.setBounds(bounds); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); - EXPECT_THAT(manager.takeChangedTiles(), ElementsAre(std::pair(TilePosition(0, 0), ChangeType::add))); + manager.setBounds(bounds, nullptr); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); + EXPECT_THAT(manager.takeChangedTiles(nullptr), ElementsAre(std::pair(TilePosition(0, 0), ChangeType::add))); } TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, update_object_for_changed_object_should_add_changed_tiles) @@ -94,11 +94,11 @@ namespace TileBounds bounds; bounds.mMin = osg::Vec2f(-1000, -1000); bounds.mMax = osg::Vec2f(1000, 1000); - manager.setBounds(bounds); - manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground); - manager.takeChangedTiles(); - EXPECT_TRUE(manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground)); - EXPECT_THAT(manager.takeChangedTiles(), ElementsAre( + manager.setBounds(bounds, nullptr); + manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground, nullptr); + manager.takeChangedTiles(nullptr); + EXPECT_TRUE(manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground, nullptr)); + EXPECT_THAT(manager.takeChangedTiles(nullptr), ElementsAre( std::pair(TilePosition(-1, -1), ChangeType::add), std::pair(TilePosition(-1, 0), ChangeType::add), std::pair(TilePosition(0, -1), ChangeType::update), @@ -113,10 +113,10 @@ namespace TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); - manager.takeChangedTiles(); - EXPECT_FALSE(manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground)); - EXPECT_THAT(manager.takeChangedTiles(), IsEmpty()); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); + manager.takeChangedTiles(nullptr); + EXPECT_FALSE(manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground, nullptr)); + EXPECT_THAT(manager.takeChangedTiles(nullptr), IsEmpty()); } TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_object_should_return_add_changed_tiles) @@ -127,20 +127,20 @@ namespace TileBounds bounds; bounds.mMin = osg::Vec2f(182, 182); bounds.mMax = osg::Vec2f(1000, 1000); - manager.setBounds(bounds); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); - manager.takeChangedTiles(); - manager.removeObject(ObjectId(&boxShape)); - EXPECT_THAT(manager.takeChangedTiles(), ElementsAre(std::pair(TilePosition(0, 0), ChangeType::remove))); + manager.setBounds(bounds, nullptr); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); + manager.takeChangedTiles(nullptr); + manager.removeObject(ObjectId(&boxShape), nullptr); + EXPECT_THAT(manager.takeChangedTiles(nullptr), ElementsAre(std::pair(TilePosition(0, 0), ChangeType::remove))); } TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_after_add_object_should_return_recast_mesh_for_each_used_tile) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr); @@ -150,10 +150,10 @@ namespace TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_after_add_object_should_return_nullptr_for_unused_tile) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr); } @@ -163,20 +163,20 @@ namespace TileBounds bounds; bounds.mMin = osg::Vec2f(-1000, -1000); bounds.mMax = osg::Vec2f(1000, 1000); - manager.setBounds(bounds); - manager.setWorldspace("worldspace"); + manager.setBounds(bounds, nullptr); + manager.setWorldspace("worldspace", nullptr); const btBoxShape boxShape(btVector3(20, 20, 100)); const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground, nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(1, -1)), nullptr); - manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground); + manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr); @@ -186,17 +186,17 @@ namespace TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_moved_object_should_return_nullptr_for_unused_tile) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const btBoxShape boxShape(btVector3(20, 20, 100)); const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground, nullptr); EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr); EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr); - manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground); + manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, 0)), nullptr); EXPECT_EQ(manager.getMesh("worldspace", TilePosition(1, -1)), nullptr); } @@ -204,11 +204,11 @@ namespace TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_removed_object_should_return_nullptr_for_all_previously_used_tiles) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); - manager.removeObject(ObjectId(&boxShape)); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); + manager.removeObject(ObjectId(&boxShape), nullptr); EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr); EXPECT_EQ(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr); EXPECT_EQ(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr); @@ -218,17 +218,17 @@ namespace TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_mesh_for_not_changed_object_after_update_should_return_recast_mesh_for_same_tiles) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, 0)), nullptr); - manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground); + manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, -1)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(-1, 0)), nullptr); EXPECT_NE(manager.getMesh("worldspace", TilePosition(0, -1)), nullptr); @@ -241,7 +241,7 @@ namespace const auto initialRevision = manager.getRevision(); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); EXPECT_EQ(manager.getRevision(), initialRevision + 1); } @@ -250,9 +250,9 @@ namespace TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); const auto beforeAddRevision = manager.getRevision(); - EXPECT_FALSE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); + EXPECT_FALSE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr)); EXPECT_EQ(manager.getRevision(), beforeAddRevision); } @@ -262,21 +262,21 @@ namespace const btBoxShape boxShape(btVector3(20, 20, 100)); const btTransform transform(btMatrix3x3::getIdentity(), btVector3(getTileSize(mSettings) / mSettings.mRecastScaleFactor, 0, 0)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, transform, AreaType::AreaType_ground, nullptr); const auto beforeUpdateRevision = manager.getRevision(); - manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground); + manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); EXPECT_EQ(manager.getRevision(), beforeUpdateRevision + 1); } TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, get_revision_after_update_not_changed_object_should_return_same_value) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); const auto beforeUpdateRevision = manager.getRevision(); - manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground); + manager.updateObject(ObjectId(&boxShape), btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); EXPECT_EQ(manager.getRevision(), beforeUpdateRevision); } @@ -285,9 +285,9 @@ namespace TileCachedRecastMeshManager manager(mSettings); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); const auto beforeRemoveRevision = manager.getRevision(); - manager.removeObject(ObjectId(&boxShape)); + manager.removeObject(ObjectId(&boxShape), nullptr); EXPECT_EQ(manager.getRevision(), beforeRemoveRevision + 1); } @@ -295,7 +295,7 @@ namespace { TileCachedRecastMeshManager manager(mSettings); const auto beforeRemoveRevision = manager.getRevision(); - manager.removeObject(ObjectId(&manager)); + manager.removeObject(ObjectId(&manager), nullptr); EXPECT_EQ(manager.getRevision(), beforeRemoveRevision); } @@ -304,8 +304,8 @@ namespace TileCachedRecastMeshManager manager(mSettings); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; - manager.addWater(cellPosition, cellSize, 0.0f); - const auto changedTiles = manager.takeChangedTiles(); + manager.addWater(cellPosition, cellSize, 0.0f, nullptr); + const auto changedTiles = manager.takeChangedTiles(nullptr); EXPECT_EQ(changedTiles.begin()->first, TilePosition(-1, -1)); EXPECT_EQ(changedTiles.rbegin()->first, TilePosition(11, 11)); for (const auto& [k, v] : changedTiles) @@ -315,10 +315,10 @@ namespace TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_water_for_not_max_int_should_add_new_tiles) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; - manager.addWater(cellPosition, cellSize, 0.0f); + manager.addWater(cellPosition, cellSize, 0.0f, nullptr); for (int x = -1; x < 12; ++x) for (int y = -1; y < 12; ++y) ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr); @@ -327,13 +327,13 @@ namespace TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, add_water_for_max_int_should_not_add_new_tiles) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); + ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr)); const osg::Vec2i cellPosition(0, 0); const int cellSize = std::numeric_limits::max(); - manager.addWater(cellPosition, cellSize, 0.0f); + manager.addWater(cellPosition, cellSize, 0.0f, nullptr); for (int x = -6; x < 6; ++x) for (int y = -6; y < 6; ++y) ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)) != nullptr, -1 <= x && x <= 0 && -1 <= y && y <= 0); @@ -342,8 +342,8 @@ namespace TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_absent_cell_should_not_add_changed_tiles) { TileCachedRecastMeshManager manager(mSettings); - manager.removeWater(osg::Vec2i(0, 0)); - EXPECT_THAT(manager.takeChangedTiles(), ElementsAre()); + manager.removeWater(osg::Vec2i(0, 0), nullptr); + EXPECT_THAT(manager.takeChangedTiles(nullptr), ElementsAre()); } TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_existing_cell_should_add_changed_tiles) @@ -351,10 +351,10 @@ namespace TileCachedRecastMeshManager manager(mSettings); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; - manager.addWater(cellPosition, cellSize, 0.0f); - manager.takeChangedTiles(); - manager.removeWater(cellPosition); - const auto changedTiles = manager.takeChangedTiles(); + manager.addWater(cellPosition, cellSize, 0.0f, nullptr); + manager.takeChangedTiles(nullptr); + manager.removeWater(cellPosition, nullptr); + const auto changedTiles = manager.takeChangedTiles(nullptr); EXPECT_EQ(changedTiles.begin()->first, TilePosition(-1, -1)); EXPECT_EQ(changedTiles.rbegin()->first, TilePosition(11, 11)); for (const auto& [k, v] : changedTiles) @@ -364,11 +364,11 @@ namespace TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_existing_cell_should_remove_empty_tiles) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; - manager.addWater(cellPosition, cellSize, 0.0f); - manager.removeWater(cellPosition); + manager.addWater(cellPosition, cellSize, 0.0f, nullptr); + manager.removeWater(cellPosition, nullptr); for (int x = -6; x < 6; ++x) for (int y = -6; y < 6; ++y) ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)), nullptr); @@ -377,14 +377,14 @@ namespace TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_water_for_existing_cell_should_leave_not_empty_tiles) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); + ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr)); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; - manager.addWater(cellPosition, cellSize, 0.0f); - manager.removeWater(cellPosition); + manager.addWater(cellPosition, cellSize, 0.0f, nullptr); + manager.removeWater(cellPosition, nullptr); for (int x = -6; x < 6; ++x) for (int y = -6; y < 6; ++y) ASSERT_EQ(manager.getMesh("worldspace", TilePosition(x, y)) != nullptr, -1 <= x && x <= 0 && -1 <= y && y <= 0); @@ -393,14 +393,14 @@ namespace TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, remove_object_should_not_remove_tile_with_water) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const osg::Vec2i cellPosition(0, 0); const int cellSize = 8192; const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(mInstance, boxShape, mObjectTransform); - ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); - manager.addWater(cellPosition, cellSize, 0.0f); - manager.removeObject(ObjectId(&boxShape)); + ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr)); + manager.addWater(cellPosition, cellSize, 0.0f, nullptr); + manager.removeObject(ObjectId(&boxShape), nullptr); for (int x = -1; x < 12; ++x) for (int y = -1; y < 12; ++y) ASSERT_NE(manager.getMesh("worldspace", TilePosition(x, y)), nullptr); @@ -409,11 +409,11 @@ namespace TEST_F(DetourNavigatorTileCachedRecastMeshManagerTest, set_new_worldspace_should_remove_tiles) { TileCachedRecastMeshManager manager(mSettings); - manager.setWorldspace("worldspace"); + manager.setWorldspace("worldspace", nullptr); const btBoxShape boxShape(btVector3(20, 20, 100)); const CollisionShape shape(nullptr, boxShape, mObjectTransform); - ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground)); - manager.setWorldspace("other"); + ASSERT_TRUE(manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr)); + manager.setWorldspace("other", nullptr); for (int x = -1; x < 1; ++x) for (int y = -1; y < 1; ++y) ASSERT_EQ(manager.getMesh("other", TilePosition(x, y)), nullptr); @@ -427,13 +427,13 @@ namespace TileBounds bounds; bounds.mMin = osg::Vec2f(182, 0); bounds.mMax = osg::Vec2f(1000, 1000); - manager.setBounds(bounds); - manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground); + manager.setBounds(bounds, nullptr); + manager.addObject(ObjectId(&boxShape), shape, btTransform::getIdentity(), AreaType::AreaType_ground, nullptr); bounds.mMin = osg::Vec2f(-1000, -1000); bounds.mMax = osg::Vec2f(0, -182); - manager.takeChangedTiles(); - manager.setBounds(bounds); - EXPECT_THAT(manager.takeChangedTiles(), ElementsAre( + manager.takeChangedTiles(nullptr); + manager.setBounds(bounds, nullptr); + EXPECT_THAT(manager.takeChangedTiles(nullptr), ElementsAre( std::pair(TilePosition(-1, -1), ChangeType::add), std::pair(TilePosition(0, 0), ChangeType::remove) )); diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 28f8666943..933046798a 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -227,7 +227,7 @@ namespace DetourNavigator mDbWorker->updateJobs(playerTile, maxTiles); } - void AsyncNavMeshUpdater::wait(Loading::Listener& listener, WaitConditionType waitConditionType) + void AsyncNavMeshUpdater::wait(WaitConditionType waitConditionType, Loading::Listener* listener) { switch (waitConditionType) { @@ -254,7 +254,7 @@ namespace DetourNavigator thread.join(); } - void AsyncNavMeshUpdater::waitUntilJobsDoneForNotPresentTiles(Loading::Listener& listener) + void AsyncNavMeshUpdater::waitUntilJobsDoneForNotPresentTiles(Loading::Listener* listener) { const int maxDistanceToPlayer = mSettings.get().mWaitUntilMinDistanceToPlayer; if (maxDistanceToPlayer <= 0) @@ -276,23 +276,28 @@ namespace DetourNavigator if (!isAbsentTileTooClose(playerPosition, maxDistanceToPlayer, mPushed, mPresentTiles, mProcessingTiles) || mJobs.empty()) return; - Loading::ScopedLoad load(&listener); - listener.setLabel("#{Navigation:BuildingNavigationMesh}"); - listener.setProgressRange(maxProgress); + const Loading::ScopedLoad load(listener); + if (listener != nullptr) + { + listener->setLabel("#{Navigation:BuildingNavigationMesh}"); + listener->setProgressRange(maxProgress); + } while (!mDone.wait_for(lock, std::chrono::milliseconds(20), isDone)) { + if (listener == nullptr) + continue; if (maxProgress < jobsLeft) { maxProgress = jobsLeft; - listener.setProgressRange(maxProgress); - listener.setProgress(jobsDone); + listener->setProgressRange(maxProgress); + listener->setProgress(jobsDone); } else if (jobsLeft < prevJobsLeft) { const std::size_t newJobsDone = prevJobsLeft - jobsLeft; jobsDone += newJobsDone; prevJobsLeft = jobsLeft; - listener.increaseProgress(newJobsDone); + listener->increaseProgress(newJobsDone); } } } diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index 541e39f18c..b19ef9006d 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -151,7 +151,7 @@ namespace DetourNavigator const TilePosition& playerTile, std::string_view worldspace, const std::map& changedTiles); - void wait(Loading::Listener& listener, WaitConditionType waitConditionType); + void wait(WaitConditionType waitConditionType, Loading::Listener* listener); void stop(); @@ -209,7 +209,7 @@ namespace DetourNavigator void cleanupLastUpdates(); - inline void waitUntilJobsDoneForNotPresentTiles(Loading::Listener& listener); + inline void waitUntilJobsDoneForNotPresentTiles(Loading::Listener* listener); inline void waitUntilAllJobsDone(); }; diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index c110fd3eb2..f78ce30c2b 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -55,6 +55,8 @@ namespace DetourNavigator {} }; + class UpdateGuard; + /** * @brief Top level interface of detournavigator component. Navigator allows to build a scene with navmesh and find * a path for an agent there. Scene contains agents, geometry objects and water. Agent are distinguished only by @@ -66,6 +68,8 @@ namespace DetourNavigator { virtual ~Navigator() = default; + virtual std::unique_ptr makeUpdateGuard() = 0; + /** * @brief addAgent should be called for each agent even if all of them has same half extents. * @param agentBounds allows to setup bounding cylinder for each agent, for each different half extents @@ -83,13 +87,13 @@ namespace DetourNavigator * @brief setWorldspace should be called before adding object from new worldspace * @param worldspace */ - virtual void setWorldspace(std::string_view worldspace) = 0; + virtual void setWorldspace(std::string_view worldspace, const UpdateGuard* guard) = 0; /** * @brief updateBounds should be called before adding object from loading cell * @param playerPosition corresponds to the bounds center */ - virtual void updateBounds(const osg::Vec3f& playerPosition) = 0; + virtual void updateBounds(const osg::Vec3f& playerPosition, const UpdateGuard* guard) = 0; /** * @brief addObject is used to add complex object with allowed to walk and avoided to walk shapes @@ -97,7 +101,8 @@ namespace DetourNavigator * @param shape members must live until object is updated by another shape removed from Navigator * @param transform allows to setup objects geometry according to its world state */ - virtual void addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0; + virtual void addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) = 0; /** * @brief addObject is used to add doors. @@ -105,7 +110,8 @@ namespace DetourNavigator * @param shape members must live until object is updated by another shape or removed from Navigator. * @param transform allows to setup objects geometry according to its world state. */ - virtual void addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0; + virtual void addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) = 0; /** * @brief updateObject replace object geometry by given data. @@ -113,7 +119,8 @@ namespace DetourNavigator * @param shape members must live until object is updated by another shape removed from Navigator. * @param transform allows to setup objects geometry according to its world state. */ - virtual void updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0; + virtual void updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) = 0; /** * @brief updateObject replace object geometry by given data. @@ -121,13 +128,14 @@ namespace DetourNavigator * @param shape members must live until object is updated by another shape removed from Navigator. * @param transform allows to setup objects geometry according to its world state. */ - virtual void updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0; + virtual void updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) = 0; /** * @brief removeObject to make it no more available at the scene. * @param id is used to find object. */ - virtual void removeObject(const ObjectId id) = 0; + virtual void removeObject(const ObjectId id, const UpdateGuard* guard) = 0; /** * @brief addWater is used to set water level at given world cell. @@ -135,17 +143,19 @@ namespace DetourNavigator * @param cellSize set cell borders. std::numeric_limits::max() disables cell borders. * @param shift set global shift of cell center. */ - virtual void addWater(const osg::Vec2i& cellPosition, int cellSize, float level) = 0; + virtual void addWater(const osg::Vec2i& cellPosition, int cellSize, float level, + const UpdateGuard* guard) = 0; /** * @brief removeWater to make it no more available at the scene. * @param cellPosition allows to find cell. */ - virtual void removeWater(const osg::Vec2i& cellPosition) = 0; + virtual void removeWater(const osg::Vec2i& cellPosition, const UpdateGuard* guard) = 0; - virtual void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) = 0; + virtual void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape, + const UpdateGuard* guard) = 0; - virtual void removeHeightfield(const osg::Vec2i& cellPosition) = 0; + virtual void removeHeightfield(const osg::Vec2i& cellPosition, const UpdateGuard* guard) = 0; virtual void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) = 0; @@ -155,13 +165,14 @@ namespace DetourNavigator * @brief update starts background navmesh update using current scene state. * @param playerPosition setup initial point to order build tiles of navmesh. */ - virtual void update(const osg::Vec3f& playerPosition) = 0; + virtual void update(const osg::Vec3f& playerPosition, const UpdateGuard* guard) = 0; /** * @brief wait locks thread until tiles are updated from last update call based on passed condition type. * @param waitConditionType defines when waiting will stop + * @param listener optional listener for a progress bar */ - virtual void wait(Loading::Listener& listener, WaitConditionType waitConditionType) = 0; + virtual void wait(WaitConditionType waitConditionType, Loading::Listener* listener) = 0; /** * @brief getNavMesh returns navmesh for specific agent half extents diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 575e7c7e7b..f23da1eb22 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -32,41 +32,44 @@ namespace DetourNavigator --it->second; } - void NavigatorImpl::setWorldspace(std::string_view worldspace) + void NavigatorImpl::setWorldspace(std::string_view worldspace, const UpdateGuard* guard) { - mNavMeshManager.setWorldspace(worldspace); + mNavMeshManager.setWorldspace(worldspace, getImpl(guard)); } - void NavigatorImpl::updateBounds(const osg::Vec3f& playerPosition) + void NavigatorImpl::updateBounds(const osg::Vec3f& playerPosition, const UpdateGuard* guard) { - mNavMeshManager.updateBounds(playerPosition); + mNavMeshManager.updateBounds(playerPosition, getImpl(guard)); } - void NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) + void NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) { - addObjectImpl(id, shapes, transform); + addObjectImpl(id, shapes, transform, guard); } - bool NavigatorImpl::addObjectImpl(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) + bool NavigatorImpl::addObjectImpl(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) { const CollisionShape collisionShape(shapes.mShapeInstance, *shapes.mShapeInstance->mCollisionShape, shapes.mTransform); - bool result = mNavMeshManager.addObject(id, collisionShape, transform, AreaType_ground); + bool result = mNavMeshManager.addObject(id, collisionShape, transform, AreaType_ground, getImpl(guard)); if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->mAvoidCollisionShape.get()) { const ObjectId avoidId(avoidShape); const CollisionShape avoidCollisionShape(shapes.mShapeInstance, *avoidShape, shapes.mTransform); - if (mNavMeshManager.addObject(avoidId, avoidCollisionShape, transform, AreaType_null)) + if (mNavMeshManager.addObject(avoidId, avoidCollisionShape, transform, AreaType_null, getImpl(guard))) { - updateAvoidShapeId(id, avoidId); + updateAvoidShapeId(id, avoidId, guard); result = true; } } return result; } - void NavigatorImpl::addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) + void NavigatorImpl::addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) { - if (addObjectImpl(id, static_cast(shapes), transform)) + if (addObjectImpl(id, static_cast(shapes), transform, guard)) { const osg::Vec3f start = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionStart); const osg::Vec3f end = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionEnd); @@ -75,52 +78,55 @@ namespace DetourNavigator } } - void NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) + void NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) { - mNavMeshManager.updateObject(id, transform, AreaType_ground); + mNavMeshManager.updateObject(id, transform, AreaType_ground, getImpl(guard)); if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->mAvoidCollisionShape.get()) { const ObjectId avoidId(avoidShape); - if (mNavMeshManager.updateObject(avoidId, transform, AreaType_null)) - updateAvoidShapeId(id, avoidId); + if (mNavMeshManager.updateObject(avoidId, transform, AreaType_null, getImpl(guard))) + updateAvoidShapeId(id, avoidId, guard); } } - void NavigatorImpl::updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) + void NavigatorImpl::updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) { - return updateObject(id, static_cast(shapes), transform); + return updateObject(id, static_cast(shapes), transform, guard); } - void NavigatorImpl::removeObject(const ObjectId id) + void NavigatorImpl::removeObject(const ObjectId id, const UpdateGuard* guard) { - mNavMeshManager.removeObject(id); + mNavMeshManager.removeObject(id, getImpl(guard)); const auto avoid = mAvoidIds.find(id); if (avoid != mAvoidIds.end()) - mNavMeshManager.removeObject(avoid->second); + mNavMeshManager.removeObject(avoid->second, getImpl(guard)); const auto water = mWaterIds.find(id); if (water != mWaterIds.end()) - mNavMeshManager.removeObject(water->second); + mNavMeshManager.removeObject(water->second, getImpl(guard)); mNavMeshManager.removeOffMeshConnections(id); } - void NavigatorImpl::addWater(const osg::Vec2i& cellPosition, int cellSize, float level) + void NavigatorImpl::addWater(const osg::Vec2i& cellPosition, int cellSize, float level, const UpdateGuard* guard) { - mNavMeshManager.addWater(cellPosition, cellSize, level); + mNavMeshManager.addWater(cellPosition, cellSize, level, getImpl(guard)); } - void NavigatorImpl::removeWater(const osg::Vec2i& cellPosition) + void NavigatorImpl::removeWater(const osg::Vec2i& cellPosition, const UpdateGuard* guard) { - mNavMeshManager.removeWater(cellPosition); + mNavMeshManager.removeWater(cellPosition, getImpl(guard)); } - void NavigatorImpl::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) + void NavigatorImpl::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape, + const UpdateGuard* guard) { - mNavMeshManager.addHeightfield(cellPosition, cellSize, shape); + mNavMeshManager.addHeightfield(cellPosition, cellSize, shape, getImpl(guard)); } - void NavigatorImpl::removeHeightfield(const osg::Vec2i& cellPosition) + void NavigatorImpl::removeHeightfield(const osg::Vec2i& cellPosition, const UpdateGuard* guard) { - mNavMeshManager.removeHeightfield(cellPosition); + mNavMeshManager.removeHeightfield(cellPosition, getImpl(guard)); } void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) @@ -144,15 +150,15 @@ namespace DetourNavigator mNavMeshManager.removeOffMeshConnections(ObjectId(&pathgrid)); } - void NavigatorImpl::update(const osg::Vec3f& playerPosition) + void NavigatorImpl::update(const osg::Vec3f& playerPosition, const UpdateGuard* guard) { removeUnusedNavMeshes(); - mNavMeshManager.update(playerPosition); + mNavMeshManager.update(playerPosition, getImpl(guard)); } - void NavigatorImpl::wait(Loading::Listener& listener, WaitConditionType waitConditionType) + void NavigatorImpl::wait(WaitConditionType waitConditionType, Loading::Listener* listener) { - mNavMeshManager.wait(listener, waitConditionType); + mNavMeshManager.wait(waitConditionType, listener); } SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const AgentBounds& agentBounds) const @@ -180,22 +186,18 @@ namespace DetourNavigator return mNavMeshManager.getRecastMeshTiles(); } - void NavigatorImpl::updateAvoidShapeId(const ObjectId id, const ObjectId avoidId) + void NavigatorImpl::updateAvoidShapeId(const ObjectId id, const ObjectId avoidId, const UpdateGuard* guard) { - updateId(id, avoidId, mWaterIds); + updateId(id, avoidId, mWaterIds, guard); } - void NavigatorImpl::updateWaterShapeId(const ObjectId id, const ObjectId waterId) - { - updateId(id, waterId, mWaterIds); - } - - void NavigatorImpl::updateId(const ObjectId id, const ObjectId updateId, std::unordered_map& ids) + void NavigatorImpl::updateId(const ObjectId id, const ObjectId updateId, + std::unordered_map& ids, const UpdateGuard* guard) { auto inserted = ids.insert(std::make_pair(id, updateId)); if (!inserted.second) { - mNavMeshManager.removeObject(inserted.first->second); + mNavMeshManager.removeObject(inserted.first->second, getImpl(guard)); inserted.first->second = updateId; } } diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index f671c7e9bd..a33197b8d4 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -18,39 +18,49 @@ namespace DetourNavigator */ explicit NavigatorImpl(const Settings& settings, std::unique_ptr&& db); + std::unique_ptr makeUpdateGuard() override + { + return std::make_unique(*this); + } + void addAgent(const AgentBounds& agentBounds) override; void removeAgent(const AgentBounds& agentBounds) override; - void setWorldspace(std::string_view worldspace) override; + void setWorldspace(std::string_view worldspace, const UpdateGuard* guard) override; - void updateBounds(const osg::Vec3f& playerPosition) override; + void updateBounds(const osg::Vec3f& playerPosition, const UpdateGuard* guard) override; - void addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override; + void addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) override; - void addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override; + void addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) override; - void updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override; + void updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) override; - void updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override; + void updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform, + const UpdateGuard* guard) override; - void removeObject(const ObjectId id) override; + void removeObject(const ObjectId id, const UpdateGuard* guard) override; - void addWater(const osg::Vec2i& cellPosition, int cellSize, float level) override; + void addWater(const osg::Vec2i& cellPosition, int cellSize, float level, const UpdateGuard* guard) override; - void removeWater(const osg::Vec2i& cellPosition) override; + void removeWater(const osg::Vec2i& cellPosition, const UpdateGuard* guard) override; - void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) override; + void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape, + const UpdateGuard* guard) override; - void removeHeightfield(const osg::Vec2i& cellPosition) override; + void removeHeightfield(const osg::Vec2i& cellPosition, const UpdateGuard* guard) override; void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) override; void removePathgrid(const ESM::Pathgrid& pathgrid) override; - void update(const osg::Vec3f& playerPosition) override; + void update(const osg::Vec3f& playerPosition, const UpdateGuard* guard) override; - void wait(Loading::Listener& listener, WaitConditionType waitConditionType) override; + void wait(WaitConditionType waitConditionType, Loading::Listener* listener) override; SharedNavMeshCacheItem getNavMesh(const AgentBounds& agentBounds) const override; @@ -72,11 +82,31 @@ namespace DetourNavigator std::unordered_map mAvoidIds; std::unordered_map mWaterIds; - inline bool addObjectImpl(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform); - void updateAvoidShapeId(const ObjectId id, const ObjectId avoidId); - void updateWaterShapeId(const ObjectId id, const ObjectId waterId); - void updateId(const ObjectId id, const ObjectId waterId, std::unordered_map& ids); - void removeUnusedNavMeshes(); + inline bool addObjectImpl(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, + const UpdateGuard* guard); + + inline void updateAvoidShapeId(const ObjectId id, const ObjectId avoidId, const UpdateGuard* guard); + + inline void updateId(const ObjectId id, const ObjectId waterId, std::unordered_map& ids, + const UpdateGuard* guard); + + inline void removeUnusedNavMeshes(); + + friend class UpdateGuard; + }; + + class UpdateGuard + { + public: + explicit UpdateGuard(NavigatorImpl& navigator) : mImpl(navigator.mNavMeshManager) {} + + private: + NavMeshManager::UpdateGuard mImpl; + + friend inline const NavMeshManager::UpdateGuard* getImpl(const UpdateGuard* guard) + { + return guard == nullptr ? nullptr : &guard->mImpl; + } }; } diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index 771df43f64..8b3d3328d1 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -17,40 +17,47 @@ namespace DetourNavigator public: NavigatorStub() = default; + std::unique_ptr makeUpdateGuard() override { return nullptr; } + void addAgent(const AgentBounds& /*agentBounds*/) override {} void removeAgent(const AgentBounds& /*agentBounds*/) override {} - void setWorldspace(std::string_view /*worldspace*/) override {} + void setWorldspace(std::string_view /*worldspace*/, const UpdateGuard* /*guard*/) override {} - void addObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override {} + void addObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/, + const UpdateGuard* /*guard*/) override {} - void addObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override {} + void addObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/, + const UpdateGuard* /*guard*/) override {} - void updateObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override {} + void updateObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/, + const UpdateGuard* /*guard*/) override {} - void updateObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override {} + void updateObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/, + const UpdateGuard* /*guard*/) override {} - void removeObject(const ObjectId /*id*/) override {} + void removeObject(const ObjectId /*id*/, const UpdateGuard* /*guard*/) override {} - void addWater(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, float /*level*/) override {} + void addWater(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, float /*level*/, + const UpdateGuard* /*guard*/) override {} - void removeWater(const osg::Vec2i& /*cellPosition*/) override {} + void removeWater(const osg::Vec2i& /*cellPosition*/, const UpdateGuard* /*guard*/) override {} - void addHeightfield(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, const HeightfieldShape& /*height*/) - override {} + void addHeightfield(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, const HeightfieldShape& /*height*/, + const UpdateGuard* /*guard*/) override {} - void removeHeightfield(const osg::Vec2i& /*cellPosition*/) override {} + void removeHeightfield(const osg::Vec2i& /*cellPosition*/, const UpdateGuard* /*guard*/) override {} void addPathgrid(const ESM::Cell& /*cell*/, const ESM::Pathgrid& /*pathgrid*/) override {} void removePathgrid(const ESM::Pathgrid& /*pathgrid*/) override {} - void update(const osg::Vec3f& /*playerPosition*/) override {} + void update(const osg::Vec3f& /*playerPosition*/, const UpdateGuard* /*guard*/) override {} - void updateBounds(const osg::Vec3f& /*playerPosition*/) override {} + void updateBounds(const osg::Vec3f& /*playerPosition*/, const UpdateGuard* /*guard*/) override {} - void wait(Loading::Listener& /*listener*/, WaitConditionType /*waitConditionType*/) override {} + void wait(WaitConditionType /*waitConditionType*/, Loading::Listener* /*listener*/) override {} SharedNavMeshCacheItem getNavMesh(const AgentBounds& /*agentBounds*/) const override { diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index a6734d41e3..a86dae75e8 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -57,57 +57,57 @@ namespace DetourNavigator , mAsyncNavMeshUpdater(settings, mRecastMeshManager, mOffMeshConnectionsManager, std::move(db)) {} - void NavMeshManager::setWorldspace(std::string_view worldspace) + void NavMeshManager::setWorldspace(std::string_view worldspace, const UpdateGuard* guard) { if (worldspace == mWorldspace) return; - mRecastMeshManager.setWorldspace(worldspace); + mRecastMeshManager.setWorldspace(worldspace, getImpl(guard)); for (auto& [agent, cache] : mCache) cache = std::make_shared(makeEmptyNavMesh(mSettings), ++mGenerationCounter); mWorldspace = worldspace; } - void NavMeshManager::updateBounds(const osg::Vec3f& playerPosition) + void NavMeshManager::updateBounds(const osg::Vec3f& playerPosition, const UpdateGuard* guard) { const TileBounds bounds = makeBounds(mSettings.mRecast, osg::Vec2f(playerPosition.x(), playerPosition.y()), mSettings.mMaxTilesNumber); - mRecastMeshManager.setBounds(bounds); + mRecastMeshManager.setBounds(bounds, getImpl(guard)); } bool NavMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, - const AreaType areaType) + const AreaType areaType, const UpdateGuard* guard) { - return mRecastMeshManager.addObject(id, shape, transform, areaType); + return mRecastMeshManager.addObject(id, shape, transform, areaType, getImpl(guard)); } - bool NavMeshManager::updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType) + bool NavMeshManager::updateObject(const ObjectId id, const btTransform& transform, const AreaType areaType, const UpdateGuard* guard) { - return mRecastMeshManager.updateObject(id, transform, areaType); + return mRecastMeshManager.updateObject(id, transform, areaType, getImpl(guard)); } - void NavMeshManager::removeObject(const ObjectId id) + void NavMeshManager::removeObject(const ObjectId id, const UpdateGuard* guard) { - mRecastMeshManager.removeObject(id); + mRecastMeshManager.removeObject(id, getImpl(guard)); } - void NavMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level) + void NavMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level, const UpdateGuard* guard) { - mRecastMeshManager.addWater(cellPosition, cellSize, level); + mRecastMeshManager.addWater(cellPosition, cellSize, level, getImpl(guard)); } - void NavMeshManager::removeWater(const osg::Vec2i& cellPosition) + void NavMeshManager::removeWater(const osg::Vec2i& cellPosition, const UpdateGuard* guard) { - mRecastMeshManager.removeWater(cellPosition); + mRecastMeshManager.removeWater(cellPosition, getImpl(guard)); } - void NavMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) + void NavMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape, const UpdateGuard* guard) { - mRecastMeshManager.addHeightfield(cellPosition, cellSize, shape); + mRecastMeshManager.addHeightfield(cellPosition, cellSize, shape, getImpl(guard)); } - void NavMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) + void NavMeshManager::removeHeightfield(const osg::Vec2i& cellPosition, const UpdateGuard* guard) { - mRecastMeshManager.removeHeightfield(cellPosition); + mRecastMeshManager.removeHeightfield(cellPosition, getImpl(guard)); } void NavMeshManager::addAgent(const AgentBounds& agentBounds) @@ -153,7 +153,7 @@ namespace DetourNavigator mRecastMeshManager.addChangedTile(tile, ChangeType::update); } - void NavMeshManager::update(const osg::Vec3f& playerPosition) + void NavMeshManager::update(const osg::Vec3f& playerPosition, const UpdateGuard* guard) { const auto playerTile = getTilePosition(mSettings.mRecast, toNavMeshCoordinates(mSettings.mRecast, playerPosition)); @@ -162,7 +162,7 @@ namespace DetourNavigator return; mLastRecastMeshManagerRevision = mRecastMeshManager.getRevision(); mPlayerTile = playerTile; - const auto changedTiles = mRecastMeshManager.takeChangedTiles(); + const auto changedTiles = mRecastMeshManager.takeChangedTiles(getImpl(guard)); const TilesPositionsRange range = mRecastMeshManager.getRange(); for (const auto& [agentBounds, cached] : mCache) update(agentBounds, playerTile, range, cached, changedTiles); @@ -194,9 +194,9 @@ namespace DetourNavigator " playerTile=" << playerTile << " recastMeshManagerRevision=" << mLastRecastMeshManagerRevision; } - void NavMeshManager::wait(Loading::Listener& listener, WaitConditionType waitConditionType) + void NavMeshManager::wait(WaitConditionType waitConditionType, Loading::Listener* listener) { - mAsyncNavMeshUpdater.wait(listener, waitConditionType); + mAsyncNavMeshUpdater.wait(waitConditionType, listener); } SharedNavMeshCacheItem NavMeshManager::getNavMesh(const AgentBounds& agentBounds) const diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index b9c3bc7c21..d9c378a19c 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -20,28 +20,44 @@ namespace DetourNavigator class NavMeshManager { public: + class UpdateGuard + { + public: + explicit UpdateGuard(NavMeshManager& manager) : mImpl(manager.mRecastMeshManager) {} + + friend const TileCachedRecastMeshManager::UpdateGuard* getImpl(const UpdateGuard* guard) + { + return guard == nullptr ? nullptr : &guard->mImpl; + } + + private: + const TileCachedRecastMeshManager::UpdateGuard mImpl; + }; + explicit NavMeshManager(const Settings& settings, std::unique_ptr&& db); - void setWorldspace(std::string_view worldspace); + void setWorldspace(std::string_view worldspace, const UpdateGuard* guard); - void updateBounds(const osg::Vec3f& playerPosition); + void updateBounds(const osg::Vec3f& playerPosition, const UpdateGuard* guard); bool addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform, - const AreaType areaType); + const AreaType areaType, const UpdateGuard* guard); - bool updateObject(ObjectId id, const btTransform& transform, AreaType areaType); + bool updateObject(ObjectId id, const btTransform& transform, AreaType areaType, + const UpdateGuard* guard); - void removeObject(const ObjectId id); + void removeObject(const ObjectId id, const UpdateGuard* guard); void addAgent(const AgentBounds& agentBounds); - void addWater(const osg::Vec2i& cellPosition, int cellSize, float level); + void addWater(const osg::Vec2i& cellPosition, int cellSize, float level, const UpdateGuard* guard); - void removeWater(const osg::Vec2i& cellPosition); + void removeWater(const osg::Vec2i& cellPosition, const UpdateGuard* guard); - void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape); + void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape, + const UpdateGuard* guard); - void removeHeightfield(const osg::Vec2i& cellPosition); + void removeHeightfield(const osg::Vec2i& cellPosition, const UpdateGuard* guard); bool reset(const AgentBounds& agentBounds); @@ -49,9 +65,9 @@ namespace DetourNavigator void removeOffMeshConnections(const ObjectId id); - void update(const osg::Vec3f& playerPosition); + void update(const osg::Vec3f& playerPosition, const UpdateGuard* guard); - void wait(Loading::Listener& listener, WaitConditionType waitConditionType); + void wait(WaitConditionType waitConditionType, Loading::Listener* listener); SharedNavMeshCacheItem getNavMesh(const AgentBounds& agentBounds) const; diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 3c2049942a..d8eb773e22 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -43,6 +43,18 @@ namespace DetourNavigator { return TilePosition(v.get<0>(), v.get<1>()); } + + template + class MaybeLockGuard + { + public: + explicit MaybeLockGuard(Mutex& mutex, const TileCachedRecastMeshManager::UpdateGuard* guard) + : mImpl(guard == nullptr ? std::optional>(mutex) : std::nullopt) + {} + + private: + const std::optional> mImpl; + }; } TileCachedRecastMeshManager::TileCachedRecastMeshManager(const RecastSettings& settings) @@ -51,7 +63,7 @@ namespace DetourNavigator , mRange(makeTilesPositionsRange(mBounds.mMin, mBounds.mMax, mSettings)) {} - void TileCachedRecastMeshManager::setBounds(const TileBounds& bounds) + void TileCachedRecastMeshManager::setBounds(const TileBounds& bounds, const UpdateGuard* guard) { if (mBounds == bounds) return; @@ -87,7 +99,7 @@ namespace DetourNavigator if (changed) { - const std::lock_guard lock(mMutex); + const MaybeLockGuard lock(mMutex, guard); ++mRevision; } @@ -104,9 +116,9 @@ namespace DetourNavigator }; } - void TileCachedRecastMeshManager::setWorldspace(std::string_view worldspace) + void TileCachedRecastMeshManager::setWorldspace(std::string_view worldspace, const UpdateGuard* guard) { - const std::lock_guard lock(mMutex); + const MaybeLockGuard lock(mMutex, guard); if (mWorldspace == worldspace) return; mWorldspace = worldspace; @@ -120,11 +132,11 @@ namespace DetourNavigator } bool TileCachedRecastMeshManager::addObject(ObjectId id, const CollisionShape& shape, const btTransform& transform, - const AreaType areaType) + const AreaType areaType, const UpdateGuard* guard) { const TilesPositionsRange range = makeTilesPositionsRange(shape.getShape(), transform, mSettings); { - const std::lock_guard lock(mMutex); + const MaybeLockGuard lock(mMutex, guard); const auto it = mObjects.find(id); if (it != mObjects.end()) return false; @@ -147,12 +159,12 @@ namespace DetourNavigator return true; } - bool TileCachedRecastMeshManager::updateObject(ObjectId id, const btTransform& transform, const AreaType areaType) + bool TileCachedRecastMeshManager::updateObject(ObjectId id, const btTransform& transform, const AreaType areaType, const UpdateGuard* guard) { TilesPositionsRange newRange; TilesPositionsRange oldRange; { - const std::lock_guard lock(mMutex); + const MaybeLockGuard lock(mMutex, guard); const auto it = mObjects.find(id); if (it == mObjects.end()) return false; @@ -196,11 +208,11 @@ namespace DetourNavigator return true; } - void TileCachedRecastMeshManager::removeObject(ObjectId id) + void TileCachedRecastMeshManager::removeObject(ObjectId id, const UpdateGuard* guard) { TilesPositionsRange range; { - const std::lock_guard lock(mMutex); + const MaybeLockGuard lock(mMutex, guard); const auto it = mObjects.find(id); if (it == mObjects.end()) return; @@ -213,14 +225,14 @@ namespace DetourNavigator [&] (const TilePosition& v) { addChangedTile(v, ChangeType::remove); }); } - void TileCachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const float level) + void TileCachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize, const float level, const UpdateGuard* guard) { const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, cellSize, level)); const std::optional range = cellSize == std::numeric_limits::max() ? std::optional() : makeTilesPositionsRange(cellSize, shift, mSettings); { - const std::lock_guard lock(mMutex); + const MaybeLockGuard lock(mMutex, guard); auto it = mWater.find(cellPosition); if (it != mWater.end()) return; @@ -239,11 +251,11 @@ namespace DetourNavigator addChangedTiles(range, ChangeType::add); } - void TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition) + void TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition, const UpdateGuard* guard) { std::optional range; { - const std::lock_guard lock(mMutex); + const MaybeLockGuard lock(mMutex, guard); const auto it = mWater.find(cellPosition); if (it == mWater.end()) return; @@ -259,14 +271,14 @@ namespace DetourNavigator } void TileCachedRecastMeshManager::addHeightfield(const osg::Vec2i& cellPosition, const int cellSize, - const HeightfieldShape& shape) + const HeightfieldShape& shape, const UpdateGuard* guard) { const btVector3 shift = getHeightfieldShift(shape, cellPosition, cellSize); const std::optional range = cellSize == std::numeric_limits::max() ? std::optional() : makeTilesPositionsRange(cellSize, shift, mSettings); { - const std::lock_guard lock(mMutex); + const MaybeLockGuard lock(mMutex, guard); auto it = mHeightfields.find(cellPosition); if (it != mHeightfields.end()) return; @@ -286,11 +298,11 @@ namespace DetourNavigator addChangedTiles(range, ChangeType::add); } - void TileCachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition) + void TileCachedRecastMeshManager::removeHeightfield(const osg::Vec2i& cellPosition, const UpdateGuard* guard) { std::optional range; { - const std::lock_guard lock(mMutex); + const MaybeLockGuard lock(mMutex, guard); const auto it = mHeightfields.find(cellPosition); if (it == mHeightfields.end()) return; @@ -378,10 +390,10 @@ namespace DetourNavigator tile->second = addChangeType(tile->second, changeType); } - std::map TileCachedRecastMeshManager::takeChangedTiles() + std::map TileCachedRecastMeshManager::takeChangedTiles(const UpdateGuard* guard) { { - const std::lock_guard lock(mMutex); + const MaybeLockGuard lock(mMutex, guard); for (const auto& [tilePosition, changeType] : mChangedTiles) if (const auto it = mCache.find(tilePosition); it != mCache.end()) ++it->second.mVersion.mRevision; diff --git a/components/detournavigator/tilecachedrecastmeshmanager.hpp b/components/detournavigator/tilecachedrecastmeshmanager.hpp index 42d79fe383..52fc1736cd 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.hpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.hpp @@ -31,27 +31,38 @@ namespace DetourNavigator class TileCachedRecastMeshManager { public: + class UpdateGuard + { + public: + explicit UpdateGuard(TileCachedRecastMeshManager& manager) : mImpl(manager.mMutex) {} + + private: + const std::lock_guard mImpl; + }; + explicit TileCachedRecastMeshManager(const RecastSettings& settings); - void setBounds(const TileBounds& bounds); + void setBounds(const TileBounds& bounds, const UpdateGuard* guard); TilesPositionsRange getRange() const; - void setWorldspace(std::string_view worldspace); + void setWorldspace(std::string_view worldspace, const UpdateGuard* guard); - bool addObject(ObjectId id, const CollisionShape& shape, const btTransform& transform, AreaType areaType); + bool addObject(ObjectId id, const CollisionShape& shape, const btTransform& transform, AreaType areaType, + const UpdateGuard* guard); - bool updateObject(ObjectId id, const btTransform& transform, AreaType areaType); + bool updateObject(ObjectId id, const btTransform& transform, AreaType areaType, const UpdateGuard* guard); - void removeObject(ObjectId id); + void removeObject(ObjectId id, const UpdateGuard* guard); - void addWater(const osg::Vec2i& cellPosition, int cellSize, float level); + void addWater(const osg::Vec2i& cellPosition, int cellSize, float level, const UpdateGuard* guard); - void removeWater(const osg::Vec2i& cellPosition); + void removeWater(const osg::Vec2i& cellPosition, const UpdateGuard* guard); - void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape); + void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape, + const UpdateGuard* guard); - void removeHeightfield(const osg::Vec2i& cellPosition); + void removeHeightfield(const osg::Vec2i& cellPosition, const UpdateGuard* guard); std::shared_ptr getMesh(std::string_view worldspace, const TilePosition& tilePosition); @@ -65,7 +76,7 @@ namespace DetourNavigator void addChangedTile(const TilePosition& tilePosition, ChangeType changeType); - std::map takeChangedTiles(); + std::map takeChangedTiles(const UpdateGuard* guard); private: struct Report From 98ffe5e885b0d06ce93db9c60b552d8dee857753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <3397065-ZehMatt@users.noreply.gitlab.com> Date: Fri, 9 Sep 2022 18:10:56 +0300 Subject: [PATCH 04/36] Only run one pipeline for merge requests --- .gitlab-ci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 54c9251880..24203a25e6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,14 @@ default: interruptible: true + +# Merge requests have two pipelines, filter pipelines using branch and merge request event together. +# See https://docs.gitlab.com/ee/ci/pipelines/merge_request_pipelines.html#two-pipelines-when-pushing-to-a-branch +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS + when: never + - if: $CI_COMMIT_BRANCH # Note: We set `needs` on each job to control the job DAG. # See https://docs.gitlab.com/ee/ci/yaml/#needs From 2dde5983266efa0befdd8052f3a5f9a975f11dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <3397065-ZehMatt@users.noreply.gitlab.com> Date: Fri, 9 Sep 2022 18:20:00 +0300 Subject: [PATCH 05/36] Adjust rules and remove them from templates --- .gitlab-ci.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 24203a25e6..bd58217b33 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -29,8 +29,6 @@ variables: - docker - linux image: ubuntu:22.04 - rules: - - if: $CI_PIPELINE_SOURCE == "push" .Ubuntu: extends: .Ubuntu_Image @@ -397,8 +395,6 @@ macOS12_Xcode13: .Windows_Ninja_Base: tags: - windows - rules: - - if: $CI_PIPELINE_SOURCE == "push" before_script: - Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1" - choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1 @@ -500,8 +496,6 @@ macOS12_Xcode13: .Windows_MSBuild_Base: tags: - windows - rules: - - if: $CI_PIPELINE_SOURCE == "push" before_script: - Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1" - choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1 @@ -599,9 +593,9 @@ Windows_MSBuild_RelWithDebInfo: rules: # run this for both pushes and schedules so 'latest successful pipeline for branch' always includes it - if: $CI_PIPELINE_SOURCE == "push" + - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_PIPELINE_SOURCE == "schedule" - .Ubuntu_AndroidNDK_arm64-v8a: tags: - linux From e55caa9d20258333b56c04f9b5579bcb57bd95e6 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 10 Sep 2022 12:55:14 +0200 Subject: [PATCH 06/36] Resolve issue #6931 Ugly warning with cmake 3.24 or newer --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d58ad43af..6928e37935 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,11 @@ if(POLICY CMP0092) cmake_policy(SET CMP0092 NEW) endif() +# set the timestamps of extracted contents to the time of extraction +if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) +endif() + project(OpenMW) set(CMAKE_CXX_STANDARD 20) From ac1688f9c1166ff8dbbd6c53b835f45d10bd5fb2 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 9 Sep 2022 21:47:20 +0200 Subject: [PATCH 07/36] Remove ESM::Reader base class This class does not serve any useful purpose now. It was added as a first step in attempt to define common interface for ESM3 and ESM4 readers. But this is not going to happen. --- apps/esmtool/tes4.cpp | 1 + components/CMakeLists.txt | 2 +- components/esm/reader.cpp | 86 ------------------------------------ components/esm/reader.hpp | 59 ------------------------- components/esm4/loadbptd.cpp | 1 + components/esm4/reader.cpp | 48 ++++++++++++++++++++ components/esm4/reader.hpp | 39 ++++++++++------ 7 files changed, 77 insertions(+), 159 deletions(-) delete mode 100644 components/esm/reader.cpp delete mode 100644 components/esm/reader.hpp diff --git a/apps/esmtool/tes4.cpp b/apps/esmtool/tes4.cpp index 3f213ff0b7..815eb6dd34 100644 --- a/apps/esmtool/tes4.cpp +++ b/apps/esmtool/tes4.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace EsmTool { diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index cbfcece2c2..af4b8c7f14 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -80,7 +80,7 @@ add_component_dir (to_utf8 to_utf8 ) -add_component_dir(esm attr common defs esmcommon reader records util luascripts format) +add_component_dir(esm attr common defs esmcommon records util luascripts format) add_component_dir(fx pass technique lexer widgets stateupdater) diff --git a/components/esm/reader.cpp b/components/esm/reader.cpp deleted file mode 100644 index 5fafbb45ee..0000000000 --- a/components/esm/reader.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "reader.hpp" - -//#ifdef NDEBUG -//#undef NDEBUG -//#endif - -#include -#include - -#include - -#include "components/esm3/esmreader.hpp" -#include "components/esm4/reader.hpp" - -namespace ESM -{ - Reader* Reader::getReader(const std::string &filename) - { - Files::IStreamPtr esmStream(Files::openConstrainedFileStream(filename)); - - std::uint32_t modVer = 0; // get the first 4 bytes of the record header only - esmStream->read((char*)&modVer, sizeof(modVer)); - if (esmStream->gcount() == sizeof(modVer)) - { - esmStream->seekg(0); - - if (modVer == ESM4::REC_TES4) - { - return new ESM4::Reader(std::move(esmStream), filename); - } - else - { - //return new ESM3::ESMReader(esmStream, filename); - } - } - - throw std::runtime_error("Unknown file format"); - } - - bool Reader::getStringImpl(std::string& str, std::size_t size, - std::istream& stream, const ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull) - { - std::size_t newSize = size; - - if (encoder) - { - std::string input(size, '\0'); - stream.read(input.data(), size); - if (stream.gcount() == static_cast(size)) - { - encoder->getUtf8(input, ToUTF8::BufferAllocationPolicy::FitToRequiredSize, str); - return true; - } - } - else - { - if (hasNull) - newSize -= 1; // don't read the null terminator yet - - str.resize(newSize); // assumed C++11 - stream.read(str.data(), newSize); - if (static_cast(stream.gcount()) == newSize) - { - if (hasNull) - { - char ch; - stream.read(&ch, 1); // read the null terminator - assert (ch == '\0' - && "ESM4::Reader::getString string is not terminated with a null"); - } -#if 0 - else - { - // NOTE: normal ESMs don't but omwsave has locals or spells with null terminator - assert (str[newSize - 1] != '\0' - && "ESM4::Reader::getString string is unexpectedly terminated with a null"); - } -#endif - return true; - } - } - - str.clear(); - return false; // FIXME: throw instead? - } -} diff --git a/components/esm/reader.hpp b/components/esm/reader.hpp deleted file mode 100644 index a1ddf35641..0000000000 --- a/components/esm/reader.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef COMPONENT_ESM_READER_H -#define COMPONENT_ESM_READER_H - -#include - -#include - -#include "common.hpp" // MasterData - -namespace ToUTF8 -{ - class Utf8Encoder; -} - -namespace ESM -{ - class Reader - { - std::vector* mGlobalReaderList; - - public: - virtual ~Reader() {} - - static Reader* getReader(const std::string& filename); - - void setGlobalReaderList(std::vector *list) {mGlobalReaderList = list;} - std::vector *getGlobalReaderList() {return mGlobalReaderList;} - - virtual inline bool isEsm4() const = 0; - - virtual inline bool hasMoreRecs() const = 0; - - virtual inline void setEncoder(const ToUTF8::StatelessUtf8Encoder* encoder) = 0; - - // used to check for dependencies e.g. CS::Editor::run() - virtual inline const std::vector& getGameFiles() const = 0; - - // used by ContentSelector::ContentModel::addFiles() - virtual inline const std::string getAuthor() const = 0; - virtual inline const std::string getDesc() const = 0; - virtual inline int getFormat() const = 0; - - virtual inline std::string getFileName() const = 0; - - // used by CSMWorld::Data::startLoading() and getTotalRecords() for loading progress bar - virtual inline int getRecordCount() const = 0; - - virtual void setModIndex(std::uint32_t index) = 0; - - // used by CSMWorld::Data::getTotalRecords() - virtual void close() = 0; - - protected: - bool getStringImpl(std::string& str, std::size_t size, - std::istream& stream, const ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull = false); - }; -} - -#endif // COMPONENT_ESM_READER_H diff --git a/components/esm4/loadbptd.cpp b/components/esm4/loadbptd.cpp index 33229edd07..da40df0de9 100644 --- a/components/esm4/loadbptd.cpp +++ b/components/esm4/loadbptd.cpp @@ -28,6 +28,7 @@ #include #include // FIXME: testing only +#include #include "reader.hpp" //#include "writer.hpp" diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp index f33fb0aed1..b7179ef125 100644 --- a/components/esm4/reader.cpp +++ b/components/esm4/reader.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include "formid.hpp" @@ -646,4 +647,51 @@ void Reader::adjustGRUPFormId() throw std::runtime_error(ss.str()); } +bool Reader::getStringImpl(std::string& str, std::size_t size, + std::istream& stream, const ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull) +{ + std::size_t newSize = size; + + if (encoder) + { + std::string input(size, '\0'); + stream.read(input.data(), size); + if (stream.gcount() == static_cast(size)) + { + encoder->getUtf8(input, ToUTF8::BufferAllocationPolicy::FitToRequiredSize, str); + return true; + } + } + else + { + if (hasNull) + newSize -= 1; // don't read the null terminator yet + + str.resize(newSize); // assumed C++11 + stream.read(str.data(), newSize); + if (static_cast(stream.gcount()) == newSize) + { + if (hasNull) + { + char ch; + stream.read(&ch, 1); // read the null terminator + assert (ch == '\0' + && "ESM4::Reader::getString string is not terminated with a null"); + } +#if 0 + else + { + // NOTE: normal ESMs don't but omwsave has locals or spells with null terminator + assert (str[newSize - 1] != '\0' + && "ESM4::Reader::getString string is unexpectedly terminated with a null"); + } +#endif + return true; + } + } + + str.clear(); + return false; // FIXME: throw instead? +} + } diff --git a/components/esm4/reader.hpp b/components/esm4/reader.hpp index d4979d034a..e620cae932 100644 --- a/components/esm4/reader.hpp +++ b/components/esm4/reader.hpp @@ -30,10 +30,14 @@ #include "common.hpp" #include "loadtes4.hpp" -#include "../esm/reader.hpp" #include +namespace ToUTF8 +{ + class StatelessUtf8Encoder; +} + namespace ESM4 { // bytes read from group, updated by // getRecordHeader() in advance @@ -75,7 +79,7 @@ namespace ESM4 { ReaderContext(); }; - class Reader : public ESM::Reader + class Reader { Header mHeader; // ESM4 header @@ -107,6 +111,8 @@ namespace ESM4 { std::map mLStringIndex; + std::vector* mGlobalReaderList = nullptr; + void buildLStringIndex(const std::string& stringFile, LocalizedStringType stringType); inline bool hasLocalizedStrings() const { return (mHeader.mFlags & Rec_Localized) != 0; } @@ -126,6 +132,9 @@ namespace ESM4 { Reader() = default; + bool getStringImpl(std::string& str, std::size_t size, + std::istream& stream, const ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull = false); + public: Reader(Files::IStreamPtr&& esmStream, const std::string& filename); @@ -136,22 +145,22 @@ namespace ESM4 { void open(const std::string& filename); - void close() final; + void close(); - inline bool isEsm4() const final { return true; } + inline bool isEsm4() const { return true; } - inline void setEncoder(const ToUTF8::StatelessUtf8Encoder* encoder) final { mEncoder = encoder; }; + inline void setEncoder(const ToUTF8::StatelessUtf8Encoder* encoder) { mEncoder = encoder; }; - const std::vector& getGameFiles() const final { return mHeader.mMaster; } + const std::vector& getGameFiles() const { return mHeader.mMaster; } - inline int getRecordCount() const final { return mHeader.mData.records; } - inline const std::string getAuthor() const final { return mHeader.mAuthor; } - inline int getFormat() const final { return 0; }; // prob. not relevant for ESM4 - inline const std::string getDesc() const final { return mHeader.mDesc; } + inline int getRecordCount() const { return mHeader.mData.records; } + inline const std::string getAuthor() const { return mHeader.mAuthor; } + inline int getFormat() const { return 0; }; // prob. not relevant for ESM4 + inline const std::string getDesc() const { return mHeader.mDesc; } - inline std::string getFileName() const final { return mCtx.filename; }; // not used + inline std::string getFileName() const { return mCtx.filename; }; // not used - inline bool hasMoreRecs() const final { return (mFileSize - mCtx.fileRead) > 0; } + inline bool hasMoreRecs() const { return (mFileSize - mCtx.fileRead) > 0; } // Methods added for updating loading progress bars inline std::size_t getFileSize() const { return mFileSize; } @@ -195,7 +204,7 @@ namespace ESM4 { // The object setting up this reader needs to supply the file's load order index // so that the formId's in this file can be adjusted with the file (i.e. mod) index. - void setModIndex(std::uint32_t index) final { mCtx.modIndex = (index << 24) & 0xff000000; } + void setModIndex(std::uint32_t index) { mCtx.modIndex = (index << 24) & 0xff000000; } void updateModIndices(const std::vector& files); // Maybe should throw an exception if called when not valid? @@ -292,6 +301,10 @@ namespace ESM4 { // Used for error handling [[noreturn]] void fail(const std::string& msg); + + void setGlobalReaderList(std::vector *list) { mGlobalReaderList = list; } + + std::vector *getGlobalReaderList() { return mGlobalReaderList; } }; } From 4bb07282c922634f8b3f2366b17b7859f8275b67 Mon Sep 17 00:00:00 2001 From: Project579 Date: Wed, 8 Jun 2022 23:25:50 +0200 Subject: [PATCH 08/36] Replace all remaining occurrences of boost::filesystem with std::filesystem. --- apps/mwiniimporter/CMakeLists.txt | 1 - apps/mwiniimporter/importer.cpp | 35 ++++++----- apps/mwiniimporter/importer.hpp | 12 ++-- apps/mwiniimporter/main.cpp | 20 +++--- apps/opencs/CMakeLists.txt | 2 - apps/opencs/editor.cpp | 30 ++++----- apps/opencs/editor.hpp | 20 +++--- apps/opencs/model/doc/document.cpp | 31 +++++---- apps/opencs/model/doc/document.hpp | 23 ++++--- apps/opencs/model/doc/documentmanager.cpp | 18 +++--- apps/opencs/model/doc/documentmanager.hpp | 15 +++-- apps/opencs/model/doc/loader.cpp | 2 +- apps/opencs/model/doc/runner.cpp | 6 +- apps/opencs/model/doc/runner.hpp | 7 +-- apps/opencs/model/doc/saving.cpp | 2 +- apps/opencs/model/doc/saving.hpp | 4 +- apps/opencs/model/doc/savingstages.cpp | 21 +++---- apps/opencs/model/doc/savingstate.cpp | 15 ++--- apps/opencs/model/doc/savingstate.hpp | 20 +++--- apps/opencs/model/prefs/state.cpp | 2 +- apps/opencs/model/tools/mergestages.cpp | 2 +- apps/opencs/model/tools/tools.hpp | 3 +- apps/opencs/model/world/data.cpp | 8 +-- apps/opencs/model/world/data.hpp | 9 ++- apps/opencs/view/doc/adjusterwidget.cpp | 11 ++-- apps/opencs/view/doc/adjusterwidget.hpp | 10 +-- apps/opencs/view/doc/filedialog.cpp | 4 +- apps/opencs/view/doc/filedialog.hpp | 12 ++-- apps/opencs/view/doc/newgame.cpp | 2 +- apps/opencs/view/doc/newgame.hpp | 8 +-- apps/opencs/view/tools/merge.cpp | 8 +-- apps/opencs/view/tools/merge.hpp | 4 +- apps/openmw/CMakeLists.txt | 3 - apps/openmw/engine.cpp | 6 +- apps/openmw/engine.hpp | 6 +- apps/openmw/mwstate/character.cpp | 41 ++++++------ apps/openmw/mwstate/character.hpp | 12 ++-- apps/openmw/mwstate/charactermanager.cpp | 24 +++---- apps/openmw/mwstate/charactermanager.hpp | 7 ++- apps/openmw/mwstate/statemanagerimp.cpp | 11 ++-- apps/openmw/mwstate/statemanagerimp.hpp | 5 +- apps/openmw/mwworld/contentloader.hpp | 4 +- apps/openmw/mwworld/esmloader.cpp | 2 +- apps/openmw/mwworld/esmloader.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 6 +- apps/openmw_test_suite/mwworld/test_store.cpp | 2 +- apps/wizard/mainwizard.cpp | 10 +-- apps/wizard/mainwizard.hpp | 4 +- components/CMakeLists.txt | 1 - components/config/gamesettings.cpp | 6 +- components/config/gamesettings.hpp | 6 +- components/debug/debugging.cpp | 4 +- components/debug/debugging.hpp | 4 +- components/files/androidpath.cpp | 30 ++++----- components/files/androidpath.hpp | 16 ++--- components/files/collections.cpp | 14 ++--- components/files/collections.hpp | 4 +- components/files/configurationmanager.cpp | 63 ++++++++++--------- components/files/configurationmanager.hpp | 42 ++++++------- components/files/fixedpath.hpp | 30 ++++----- components/files/linuxpath.cpp | 55 ++++++++-------- components/files/linuxpath.hpp | 16 ++--- components/files/macospath.cpp | 46 +++++++------- components/files/macospath.hpp | 26 ++++---- components/files/multidircollection.cpp | 17 +++-- components/files/multidircollection.hpp | 9 ++- components/files/windowspath.cpp | 34 +++++----- components/files/windowspath.hpp | 28 ++++----- components/misc/timeconvert.hpp | 17 +++++ components/myguiplatform/myguiloglistener.cpp | 2 +- components/myguiplatform/myguiloglistener.hpp | 5 +- components/settings/settings.cpp | 2 +- components/vfs/registerarchives.cpp | 11 ++-- 73 files changed, 500 insertions(+), 500 deletions(-) create mode 100644 components/misc/timeconvert.hpp diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index d35f4f4d33..3f767bc6f6 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -15,7 +15,6 @@ openmw_add_executable(openmw-iniimporter target_link_libraries(openmw-iniimporter ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} components ) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 8e9d992d6d..c4377fc0ac 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -1,16 +1,17 @@ #include "importer.hpp" #include +#include +#include #include #include #include #include -#include -#include -namespace bfs = boost::filesystem; + +namespace sfs = std::filesystem; MwIniImporter::MwIniImporter() : mVerbose(false) @@ -654,12 +655,12 @@ void MwIniImporter::setVerbose(bool verbose) { mVerbose = verbose; } -MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::path& filename) const { +MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::filesystem::path& filename) const { std::cout << "load ini file: " << filename << std::endl; std::string section(""); MwIniImporter::multistrmap map; - bfs::ifstream file((bfs::path(filename))); + std::ifstream file((sfs::path(filename))); ToUTF8::Utf8Encoder encoder(mEncoding); std::string line; @@ -715,11 +716,11 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::p return map; } -MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::path& filename) { +MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::filesystem::path& filename) { std::cout << "load cfg file: " << filename << std::endl; MwIniImporter::multistrmap map; - bfs::ifstream file((bfs::path(filename))); + std::ifstream file((sfs::path(filename))); std::string line; while (std::getline(file, line)) { @@ -861,7 +862,7 @@ std::vector::iterator MwIniImporter::findString(std::vector& output, std::vector input) { +void MwIniImporter::addPaths(std::vector& output, std::vector input) { for (auto& path : input) { if (path.front() == '"') @@ -873,14 +874,14 @@ void MwIniImporter::addPaths(std::vector& output, std:: } } -void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const +void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const std::filesystem::path& iniFilename) const { - std::vector> contentFiles; + std::vector> contentFiles; std::string baseGameFile("Game Files:GameFile"); std::time_t defaultTime = 0; ToUTF8::Utf8Encoder encoder(mEncoding); - std::vector dataPaths; + std::vector dataPaths; if (cfg.count("data")) addPaths(dataPaths, cfg["data"]); @@ -909,7 +910,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co bool found = false; for (auto & dataPath : dataPaths) { - boost::filesystem::path path = dataPath / *entry; + std::filesystem::path path = dataPath / *entry; std::time_t time = lastWriteTime(path, defaultTime); if (time != defaultTime) { @@ -942,7 +943,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co { dependencies.push_back(gameFile.name); } - unsortedFiles.emplace_back(boost::filesystem::path(reader.getName()).filename().string(), dependencies); + unsortedFiles.emplace_back(std::filesystem::path(reader.getName()).filename().string(), dependencies); reader.close(); } @@ -983,13 +984,13 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding) mEncoding = encoding; } -std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) +std::time_t MwIniImporter::lastWriteTime(const std::filesystem::path& filename, std::time_t defaultTime) { std::time_t writeTime(defaultTime); - if (boost::filesystem::exists(filename)) + if (std::filesystem::exists(filename)) { - boost::filesystem::path resolved = boost::filesystem::canonical(filename); - writeTime = boost::filesystem::last_write_time(resolved); + std::filesystem::path resolved = std::filesystem::canonical(filename); + writeTime = std::chrono::system_clock::to_time_t (Misc::clockCast (std::filesystem::last_write_time (resolved)));; // print timestamp const int size=1024; diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index 7b710a4a40..6009b4ecb1 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include @@ -19,12 +19,12 @@ class MwIniImporter { MwIniImporter(); void setInputEncoding(const ToUTF8::FromType& encoding); void setVerbose(bool verbose); - multistrmap loadIniFile(const boost::filesystem::path& filename) const; - static multistrmap loadCfgFile(const boost::filesystem::path& filename); + multistrmap loadIniFile(const std::filesystem::path& filename) const; + static multistrmap loadCfgFile(const std::filesystem::path& filename); void merge(multistrmap &cfg, const multistrmap &ini) const; void mergeFallback(multistrmap &cfg, const multistrmap &ini) const; void importGameFiles(multistrmap &cfg, const multistrmap &ini, - const boost::filesystem::path& iniFilename) const; + const std::filesystem::path& iniFilename) const; void importArchives(multistrmap &cfg, const multistrmap &ini) const; static void writeToFile(std::ostream &out, const multistrmap &cfg); @@ -35,10 +35,10 @@ class MwIniImporter { static std::vector::iterator findString(std::vector& source, const std::string& string); static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); - static void addPaths(std::vector& output, std::vector input); + static void addPaths(std::vector& output, std::vector input); /// \return file's "last modified time", used in original MW to determine plug-in load order - static std::time_t lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime); + static std::time_t lastWriteTime(const std::filesystem::path& filename, std::time_t defaultTime); bool mVerbose; strmap mMergeMap; diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index 8d562059ed..4bab5d8c03 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -1,13 +1,13 @@ #include "importer.hpp" #include +#include +#include #include -#include -#include namespace bpo = boost::program_options; -namespace bfs = boost::filesystem; +namespace sfs = std::filesystem; #ifndef _WIN32 int main(int argc, char *argv[]) { @@ -47,12 +47,12 @@ private: OpenMW application stack assumes UTF-8 encoding, therefore this conversion. - For boost::filesystem::path::imbue see components/files/windowspath.cpp + For std::filesystem::path::imbue see components/files/windowspath.cpp */ int wmain(int argc, wchar_t *wargv[]) { utf8argv converter(argc, wargv); char **argv = converter.get(); - boost::filesystem::path::imbue(boost::locale::generator().generate("")); + std::filesystem::path::imbue(boost::locale::generator().generate("")); #endif try @@ -92,8 +92,8 @@ int wmain(int argc, wchar_t *wargv[]) { bpo::notify(vm); - boost::filesystem::path iniFile(vm["ini"].as()); - boost::filesystem::path cfgFile(vm["cfg"].as()); + std::filesystem::path iniFile(vm["ini"].as()); + std::filesystem::path cfgFile(vm["cfg"].as()); // if no output is given, write back to cfg file std::string outputFile(vm["output"].as()); @@ -101,11 +101,11 @@ int wmain(int argc, wchar_t *wargv[]) { outputFile = vm["cfg"].as(); } - if(!boost::filesystem::exists(iniFile)) { + if(!std::filesystem::exists(iniFile)) { std::cerr << "ini file does not exist" << std::endl; return -3; } - if(!boost::filesystem::exists(cfgFile)) + if(!std::filesystem::exists(cfgFile)) std::cerr << "cfg file does not exist" << std::endl; MwIniImporter importer; @@ -137,7 +137,7 @@ int wmain(int argc, wchar_t *wargv[]) { } std::cout << "write to: " << outputFile << std::endl; - bfs::ofstream file((bfs::path(outputFile))); + std::ofstream file((sfs::path(outputFile))); importer.writeToFile(file, cfg); } catch (std::exception& e) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8a3a41c824..82d160cd20 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -224,8 +224,6 @@ target_link_libraries(openmw-cs ${OSGTEXT_LIBRARIES} ${OSG_LIBRARIES} ${EXTERN_OSGQT_LIBRARY} - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} components_qt ) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 1db49ecf28..ed49c5399a 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -63,7 +63,7 @@ CS::Editor::Editor (int argc, char **argv) connect (&mStartup, &CSVDoc::StartupDialogue::editConfig, this, &Editor::showSettings); connect (&mFileDialog, &CSVDoc::FileDialog::signalOpenFiles, - this, [this](const boost::filesystem::path &savePath){ this->openFiles(savePath); }); + this, [this](const std::filesystem::path &savePath){ this->openFiles(savePath); }); connect (&mFileDialog, &CSVDoc::FileDialog::signalCreateNewFile, this, &Editor::createNewFile); connect (&mFileDialog, &CSVDoc::FileDialog::rejected, this, &Editor::cancelFileDialog); @@ -77,7 +77,7 @@ CS::Editor::~Editor () mPidFile.close(); - if(mServer && boost::filesystem::exists(mPid)) + if(mServer && std::filesystem::exists(mPid)) static_cast ( // silence coverity warning remove(mPid.string().c_str())); // ignore any error } @@ -138,7 +138,7 @@ std::pair > CS::Editor::readConfi Files::PathContainer::value_type local(variables["data-local"].as()); if (!local.empty()) { - boost::filesystem::create_directories(local); + std::filesystem::create_directories(local); dataLocal.push_back(local); } mCfgMgr.filterOutNonExistingPaths(dataDirs); @@ -225,9 +225,9 @@ void CS::Editor::loadDocument() mFileDialog.showDialog (CSVDoc::ContentAction_Edit); } -void CS::Editor::openFiles (const boost::filesystem::path &savePath, const std::vector &discoveredFiles) +void CS::Editor::openFiles (const std::filesystem::path &savePath, const std::vector &discoveredFiles) { - std::vector files; + std::vector files; if(discoveredFiles.empty()) { @@ -244,9 +244,9 @@ void CS::Editor::openFiles (const boost::filesystem::path &savePath, const std:: mFileDialog.hide(); } -void CS::Editor::createNewFile (const boost::filesystem::path &savePath) +void CS::Editor::createNewFile (const std::filesystem::path &savePath) { - std::vector files; + std::vector files; for (const QString &path : mFileDialog.selectedFilePaths()) { files.emplace_back(path.toUtf8().constData()); @@ -259,9 +259,9 @@ void CS::Editor::createNewFile (const boost::filesystem::path &savePath) mFileDialog.hide(); } -void CS::Editor::createNewGame (const boost::filesystem::path& file) +void CS::Editor::createNewGame (const std::filesystem::path& file) { - std::vector files; + std::vector files; files.push_back (file); @@ -292,9 +292,9 @@ bool CS::Editor::makeIPCServer() { try { - mPid = boost::filesystem::temp_directory_path(); + mPid = std::filesystem::temp_directory_path(); mPid /= "openmw-cs.pid"; - bool pidExists = boost::filesystem::exists(mPid); + bool pidExists = std::filesystem::exists(mPid); mPidFile.open(mPid); @@ -321,7 +321,7 @@ bool CS::Editor::makeIPCServer() mServer->close(); fullPath.remove(QRegExp("dummy$")); fullPath += mIpcServerName; - if(boost::filesystem::exists(fullPath.toUtf8().constData())) + if(std::filesystem::exists(fullPath.toUtf8().constData())) { // TODO: compare pid of the current process with that in the file Log(Debug::Info) << "Detected unclean shutdown."; @@ -376,7 +376,7 @@ int CS::Editor::run() fileReader.setEncoder(&encoder); fileReader.open(mFileToLoad.string()); - std::vector discoveredFiles; + std::vector discoveredFiles; for (std::vector::const_iterator itemIter = fileReader.getGameFiles().begin(); itemIter != fileReader.getGameFiles().end(); ++itemIter) @@ -384,8 +384,8 @@ int CS::Editor::run() for (Files::PathContainer::const_iterator pathIter = mDataDirs.begin(); pathIter != mDataDirs.end(); ++pathIter) { - const boost::filesystem::path masterPath = *pathIter / itemIter->name; - if (boost::filesystem::exists(masterPath)) + const std::filesystem::path masterPath = *pathIter / itemIter->name; + if (std::filesystem::exists(masterPath)) { discoveredFiles.push_back(masterPath); break; diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index b99c2d91e8..21fe7df7f1 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -1,8 +1,10 @@ #ifndef CS_EDITOR_H #define CS_EDITOR_H +#include +#include + #include -#include #include #include @@ -48,15 +50,15 @@ namespace CS CSVDoc::NewGameDialogue mNewGame; CSVPrefs::Dialogue mSettings; CSVDoc::FileDialog mFileDialog; - boost::filesystem::path mLocal; - boost::filesystem::path mResources; - boost::filesystem::path mPid; + std::filesystem::path mLocal; + std::filesystem::path mResources; + std::filesystem::path mPid; boost::interprocess::file_lock mLock; - boost::filesystem::ofstream mPidFile; + std::ofstream mPidFile; bool mFsStrict; CSVTools::Merge mMerge; CSVDoc::ViewManager* mViewManager; - boost::filesystem::path mFileToLoad; + std::filesystem::path mFileToLoad; Files::PathContainer mDataDirs; std::string mEncodingName; @@ -88,9 +90,9 @@ namespace CS void cancelFileDialog(); void loadDocument(); - void openFiles (const boost::filesystem::path &path, const std::vector &discoveredFiles = std::vector()); - void createNewFile (const boost::filesystem::path& path); - void createNewGame (const boost::filesystem::path& file); + void openFiles (const std::filesystem::path &path, const std::vector &discoveredFiles = std::vector()); + void createNewFile (const std::filesystem::path& path); + void createNewGame (const std::filesystem::path& file); void showStartup(); diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index bf6858c52e..a4d47ad0f2 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -4,9 +4,7 @@ #include #include - -#include -#include +#include #include "../world/defaultgmsts.hpp" @@ -15,6 +13,7 @@ #endif #include +#include void CSMDoc::Document::addGmsts() { @@ -277,11 +276,11 @@ void CSMDoc::Document::createBase() } CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, - const std::vector< boost::filesystem::path >& files,bool new_, - const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, + std::vector< std::filesystem::path > files,bool new_, + const std::filesystem::path& savePath, const std::filesystem::path& resDir, ToUTF8::FromType encoding, const std::vector& blacklistedScripts, bool fsStrict, const Files::PathContainer& dataPaths, const std::vector& archives) -: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, fsStrict, dataPaths, archives, resDir), +: mSavePath (savePath), mContentFiles (std::move(files)), mNew (new_), mData (encoding, fsStrict, dataPaths, archives, resDir), mTools (*this, encoding), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), @@ -293,19 +292,19 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); - if (mNew || !boost::filesystem::exists (mProjectPath)) + if (mNew || !std::filesystem::exists (mProjectPath)) { - boost::filesystem::path filtersPath (configuration.getUserDataPath() / "defaultfilters"); + std::filesystem::path filtersPath (configuration.getUserDataPath() / "defaultfilters"); - boost::filesystem::ofstream destination(mProjectPath, std::ios::out | std::ios::binary); + std::ofstream destination(mProjectPath, std::ios::out | std::ios::binary); if (!destination.is_open()) throw std::runtime_error("Can not create project file: " + mProjectPath.string()); destination.exceptions(std::ios::failbit | std::ios::badbit); - if (!boost::filesystem::exists (filtersPath)) + if (!std::filesystem::exists (filtersPath)) filtersPath = mResDir / "defaultfilters"; - boost::filesystem::ifstream source(filtersPath, std::ios::in | std::ios::binary); + std::ifstream source(filtersPath, std::ios::in | std::ios::binary); if (!source.is_open()) throw std::runtime_error("Can not read filters file: " + filtersPath.string()); source.exceptions(std::ios::failbit | std::ios::badbit); @@ -369,22 +368,22 @@ int CSMDoc::Document::getState() const return state; } -const boost::filesystem::path& CSMDoc::Document::getResourceDir() const +const std::filesystem::path& CSMDoc::Document::getResourceDir() const { return mResDir; } -const boost::filesystem::path& CSMDoc::Document::getSavePath() const +const std::filesystem::path& CSMDoc::Document::getSavePath() const { return mSavePath; } -const boost::filesystem::path& CSMDoc::Document::getProjectPath() const +const std::filesystem::path& CSMDoc::Document::getProjectPath() const { return mProjectPath; } -const std::vector& CSMDoc::Document::getContentFiles() const +const std::vector& CSMDoc::Document::getContentFiles() const { return mContentFiles; } @@ -483,7 +482,7 @@ void CSMDoc::Document::startRunning (const std::string& profile, { std::vector contentFiles; - for (std::vector::const_iterator iter (mContentFiles.begin()); + for (std::vector::const_iterator iter (mContentFiles.begin()); iter!=mContentFiles.end(); ++iter) contentFiles.push_back (iter->filename().string()); diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 7c9f0e85a5..b88e606d48 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -2,8 +2,7 @@ #define CSM_DOC_DOCUMENT_H #include - -#include +#include #include #include @@ -58,15 +57,15 @@ namespace CSMDoc private: - boost::filesystem::path mSavePath; - std::vector mContentFiles; + std::filesystem::path mSavePath; + std::vector mContentFiles; bool mNew; CSMWorld::Data mData; CSMTools::Tools mTools; - boost::filesystem::path mProjectPath; + std::filesystem::path mProjectPath; Saving mSavingOperation; OperationHolder mSaving; - boost::filesystem::path mResDir; + std::filesystem::path mResDir; Blacklist mBlacklist; Runner mRunner; bool mDirty; @@ -100,8 +99,8 @@ namespace CSMDoc public: Document (const Files::ConfigurationManager& configuration, - const std::vector< boost::filesystem::path >& files, bool new_, - const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, + std::vector< std::filesystem::path > files, bool new_, + const std::filesystem::path& savePath, const std::filesystem::path& resDir, ToUTF8::FromType encoding, const std::vector& blacklistedScripts, bool fsStrict, const Files::PathContainer& dataPaths, const std::vector& archives); @@ -111,13 +110,13 @@ namespace CSMDoc int getState() const; - const boost::filesystem::path& getResourceDir() const; + const std::filesystem::path& getResourceDir() const; - const boost::filesystem::path& getSavePath() const; + const std::filesystem::path& getSavePath() const; - const boost::filesystem::path& getProjectPath() const; + const std::filesystem::path& getProjectPath() const; - const std::vector& getContentFiles() const; + const std::vector& getContentFiles() const; ///< \attention The last element in this collection is the file that is being edited, /// but with its original path instead of the save path. diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 23ee0c425c..6e59baff90 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -1,6 +1,6 @@ #include "documentmanager.hpp" -#include +#include #ifndef Q_MOC_RUN #include @@ -11,10 +11,10 @@ CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration) : mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252), mFsStrict(false) { - boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects"; + std::filesystem::path projectPath = configuration.getUserDataPath() / "projects"; - if (!boost::filesystem::is_directory (projectPath)) - boost::filesystem::create_directories (projectPath); + if (!std::filesystem::is_directory (projectPath)) + std::filesystem::create_directories (projectPath); mLoader.moveToThread (&mLoaderThread); mLoaderThread.start(); @@ -51,7 +51,7 @@ bool CSMDoc::DocumentManager::isEmpty() return mDocuments.empty(); } -void CSMDoc::DocumentManager::addDocument (const std::vector& files, const boost::filesystem::path& savePath, +void CSMDoc::DocumentManager::addDocument (const std::vector& files, const std::filesystem::path& savePath, bool new_) { Document *document = makeDocument (files, savePath, new_); @@ -59,8 +59,8 @@ void CSMDoc::DocumentManager::addDocument (const std::vector& files, - const boost::filesystem::path& savePath, bool new_) + const std::vector< std::filesystem::path >& files, + const std::filesystem::path& savePath, bool new_) { return new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mBlacklistedScripts, mFsStrict, mDataPaths, mArchives); } @@ -93,9 +93,9 @@ void CSMDoc::DocumentManager::removeDocument (CSMDoc::Document *document) emit lastDocumentDeleted(); } -void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& parResDir) +void CSMDoc::DocumentManager::setResourceDir (const std::filesystem::path& parResDir) { - mResDir = boost::filesystem::system_complete(parResDir); + mResDir = std::filesystem::absolute(parResDir); } void CSMDoc::DocumentManager::setEncoding (ToUTF8::FromType encoding) diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index ecb2a1103c..3a69618e74 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -3,8 +3,7 @@ #include #include - -#include +#include #include #include @@ -40,7 +39,7 @@ namespace CSMDoc ToUTF8::FromType mEncoding; std::vector mBlacklistedScripts; - boost::filesystem::path mResDir; + std::filesystem::path mResDir; bool mFsStrict; Files::PathContainer mDataPaths; @@ -55,8 +54,8 @@ namespace CSMDoc ~DocumentManager(); - void addDocument (const std::vector< boost::filesystem::path >& files, - const boost::filesystem::path& savePath, bool new_); + void addDocument (const std::vector< std::filesystem::path >& files, + const std::filesystem::path& savePath, bool new_); ///< \param new_ Do not load the last content file in \a files and instead create in an /// appropriate way. @@ -66,10 +65,10 @@ namespace CSMDoc /// /// \param new_ Do not load the last content file in \a files and instead create in an /// appropriate way. - Document *makeDocument (const std::vector< boost::filesystem::path >& files, - const boost::filesystem::path& savePath, bool new_); + Document *makeDocument (const std::vector< std::filesystem::path >& files, + const std::filesystem::path& savePath, bool new_); - void setResourceDir (const boost::filesystem::path& parResDir); + void setResourceDir (const std::filesystem::path& parResDir); void setEncoding (ToUTF8::FromType encoding); diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index 2ec556a018..4563757020 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -87,7 +87,7 @@ void CSMDoc::Loader::load() if (iter->second.mFilegetContentFiles()[iter->second.mFile]; + std::filesystem::path path = document->getContentFiles()[iter->second.mFile]; int steps = document->getData().startLoading (path, iter->second.mFile!=editedIndex, /*project*/false); iter->second.mRecordsLeft = true; diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index 3bb5c13662..55a8be2ae7 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -1,5 +1,7 @@ #include "runner.hpp" +#include + #include #include #include @@ -7,8 +9,8 @@ #include "operationholder.hpp" -CSMDoc::Runner::Runner (const boost::filesystem::path& projectPath) -: mRunning (false), mStartup (nullptr), mProjectPath (projectPath) +CSMDoc::Runner::Runner (std::filesystem::path projectPath) +: mRunning (false), mStartup (nullptr), mProjectPath (std::move(projectPath)) { connect (&mProcess, qOverload(&QProcess::finished), this, &Runner::finished); diff --git a/apps/opencs/model/doc/runner.hpp b/apps/opencs/model/doc/runner.hpp index 0cfbaab3af..526507f1ee 100644 --- a/apps/opencs/model/doc/runner.hpp +++ b/apps/opencs/model/doc/runner.hpp @@ -3,8 +3,7 @@ #include #include - -#include +#include #include #include @@ -29,11 +28,11 @@ namespace CSMDoc std::string mStartupInstruction; QTemporaryFile *mStartup; QTextDocument mLog; - boost::filesystem::path mProjectPath; + std::filesystem::path mProjectPath; public: - Runner (const boost::filesystem::path& projectPath); + Runner (std::filesystem::path projectPath); ~Runner(); diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 95a2feaf24..ec9589ceb4 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -7,7 +7,7 @@ #include "savingstages.hpp" #include "document.hpp" -CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& projectPath, +CSMDoc::Saving::Saving (Document& document, const std::filesystem::path& projectPath, ToUTF8::FromType encoding) : Operation (State_Saving, true, true), mDocument (document), mState (*this, projectPath, encoding) { diff --git a/apps/opencs/model/doc/saving.hpp b/apps/opencs/model/doc/saving.hpp index 44239b21b5..88d080f0cc 100644 --- a/apps/opencs/model/doc/saving.hpp +++ b/apps/opencs/model/doc/saving.hpp @@ -1,7 +1,7 @@ #ifndef CSM_DOC_SAVING_H #define CSM_DOC_SAVING_H -#include +#include #include @@ -21,7 +21,7 @@ namespace CSMDoc public: - Saving (Document& document, const boost::filesystem::path& projectPath, + Saving (Document& document, const std::filesystem::path& projectPath, ToUTF8::FromType encoding); }; diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 6fdf75eb84..7059188bac 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -1,8 +1,7 @@ #include "savingstages.hpp" #include - -#include +#include #include @@ -67,14 +66,14 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages) mDocument.getData().count (CSMWorld::RecordBase::State_Deleted)); /// \todo refine dependency list (at least remove redundant dependencies) - std::vector dependencies = mDocument.getContentFiles(); - std::vector::const_iterator end (--dependencies.end()); + std::vector dependencies = mDocument.getContentFiles(); + std::vector::const_iterator end (--dependencies.end()); - for (std::vector::const_iterator iter (dependencies.begin()); + for (std::vector::const_iterator iter (dependencies.begin()); iter!=end; ++iter) { std::string name = iter->filename().string(); - uint64_t size = boost::filesystem::file_size (*iter); + uint64_t size = std::filesystem::file_size (*iter); mState.getWriter().addMaster (name, size); } @@ -519,15 +518,15 @@ void CSMDoc::FinalSavingStage::perform (int stage, Messages& messages) mState.getWriter().close(); mState.getStream().close(); - if (boost::filesystem::exists (mState.getTmpPath())) - boost::filesystem::remove (mState.getTmpPath()); + if (std::filesystem::exists (mState.getTmpPath())) + std::filesystem::remove (mState.getTmpPath()); } else if (!mState.isProjectFile()) { - if (boost::filesystem::exists (mState.getPath())) - boost::filesystem::remove (mState.getPath()); + if (std::filesystem::exists (mState.getPath())) + std::filesystem::remove (mState.getPath()); - boost::filesystem::rename (mState.getTmpPath(), mState.getPath()); + std::filesystem::rename (mState.getTmpPath(), mState.getPath()); mDocument.getUndoStack().setClean(); } diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp index 7214735f07..8e6730d22c 100644 --- a/apps/opencs/model/doc/savingstate.cpp +++ b/apps/opencs/model/doc/savingstate.cpp @@ -1,13 +1,14 @@ #include "savingstate.hpp" -#include +#include +#include #include "operation.hpp" #include "document.hpp" -CSMDoc::SavingState::SavingState (Operation& operation, const boost::filesystem::path& projectPath, +CSMDoc::SavingState::SavingState (Operation& operation, std::filesystem::path projectPath, ToUTF8::FromType encoding) -: mOperation (operation), mEncoder (encoding), mProjectPath (projectPath), mProjectFile (false) +: mOperation (operation), mEncoder (encoding), mProjectPath (std::move(projectPath)), mProjectFile (false) { mWriter.setEncoder (&mEncoder); } @@ -33,24 +34,24 @@ void CSMDoc::SavingState::start (Document& document, bool project) else mPath = document.getSavePath(); - boost::filesystem::path file (mPath.filename().string() + ".tmp"); + std::filesystem::path file (mPath.filename().string() + ".tmp"); mTmpPath = mPath.parent_path(); mTmpPath /= file; } -const boost::filesystem::path& CSMDoc::SavingState::getPath() const +const std::filesystem::path& CSMDoc::SavingState::getPath() const { return mPath; } -const boost::filesystem::path& CSMDoc::SavingState::getTmpPath() const +const std::filesystem::path& CSMDoc::SavingState::getTmpPath() const { return mTmpPath; } -boost::filesystem::ofstream& CSMDoc::SavingState::getStream() +std::ofstream& CSMDoc::SavingState::getStream() { return mStream; } diff --git a/apps/opencs/model/doc/savingstate.hpp b/apps/opencs/model/doc/savingstate.hpp index 727352a872..d05c6d504c 100644 --- a/apps/opencs/model/doc/savingstate.hpp +++ b/apps/opencs/model/doc/savingstate.hpp @@ -4,9 +4,7 @@ #include #include #include - -#include -#include +#include #include @@ -20,18 +18,18 @@ namespace CSMDoc class SavingState { Operation& mOperation; - boost::filesystem::path mPath; - boost::filesystem::path mTmpPath; + std::filesystem::path mPath; + std::filesystem::path mTmpPath; ToUTF8::Utf8Encoder mEncoder; - boost::filesystem::ofstream mStream; + std::ofstream mStream; ESM::ESMWriter mWriter; - boost::filesystem::path mProjectPath; + std::filesystem::path mProjectPath; bool mProjectFile; std::map > mSubRecords; // record ID, list of subrecords public: - SavingState (Operation& operation, const boost::filesystem::path& projectPath, + SavingState (Operation& operation, std::filesystem::path projectPath, ToUTF8::FromType encoding); bool hasError() const; @@ -39,11 +37,11 @@ namespace CSMDoc void start (Document& document, bool project); ///< \param project Save project file instead of content file. - const boost::filesystem::path& getPath() const; + const std::filesystem::path& getPath() const; - const boost::filesystem::path& getTmpPath() const; + const std::filesystem::path& getTmpPath() const; - boost::filesystem::ofstream& getStream(); + std::ofstream& getStream(); ESM::ESMWriter& getWriter(); diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index a93684a9f2..673839d47c 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -648,7 +648,7 @@ CSMPrefs::State::~State() void CSMPrefs::State::save() { - boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile; + std::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile; Settings::Manager::saveUser (user.string()); } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 049ec1b1eb..8a7541c0db 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -40,7 +40,7 @@ void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& // We know that the content file list contains at least two entries and that the first one // does exist on disc (otherwise it would have been impossible to initiate a merge on that // document). - boost::filesystem::path path = mState.mSource.getContentFiles()[0]; + std::filesystem::path path = mState.mSource.getContentFiles()[0]; ESM::ESMReader reader; reader.setEncoder (&mEncoder); diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index f544c83127..29ea982f6e 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -3,13 +3,12 @@ #include #include +#include #include #include -#include - #include "../doc/operationholder.hpp" namespace CSMWorld diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d2d6cbdc13..f03aac0837 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -64,7 +64,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec } CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, - const std::vector& archives, const boost::filesystem::path& resDir) + const std::vector& archives, const std::filesystem::path& resDir) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), mReader (nullptr), mDialogue (nullptr), mReaderIndex(1), mFsStrict(fsStrict), mDataPaths(dataPaths), mArchives(archives) @@ -958,7 +958,7 @@ void CSMWorld::Data::merge() mGlobals.merge(); } -int CSMWorld::Data::getTotalRecords (const std::vector& files) +int CSMWorld::Data::getTotalRecords (const std::vector& files) { int records = 0; @@ -966,7 +966,7 @@ int CSMWorld::Data::getTotalRecords (const std::vector& for (unsigned int i = 0; i < files.size(); ++i) { - if (!boost::filesystem::exists(files[i])) + if (!std::filesystem::exists(files[i])) continue; reader->open(files[i].string()); @@ -977,7 +977,7 @@ int CSMWorld::Data::getTotalRecords (const std::vector& return records; } -int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base, bool project) +int CSMWorld::Data::startLoading (const std::filesystem::path& path, bool base, bool project) { // Don't delete the Reader yet. Some record types store a reference to the Reader to handle on-demand loading std::shared_ptr ptr(mReader); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 8a9f42d98a..35c6159cfe 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -3,8 +3,7 @@ #include #include - -#include +#include #include #include @@ -148,7 +147,7 @@ namespace CSMWorld public: Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, - const std::vector& archives, const boost::filesystem::path& resDir); + const std::vector& archives, const std::filesystem::path& resDir); ~Data() override; @@ -290,9 +289,9 @@ namespace CSMWorld void merge(); ///< Merge modified into base. - int getTotalRecords (const std::vector& files); // for better loading bar + int getTotalRecords (const std::vector& files); // for better loading bar - int startLoading (const boost::filesystem::path& path, bool base, bool project); + int startLoading (const std::filesystem::path& path, bool base, bool project); ///< Begin merging content of a file into base or modified. /// /// \param project load project file instead of content file diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 71d84285d7..9ff2da125e 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -1,9 +1,8 @@ #include "adjusterwidget.hpp" +#include #include -#include - #include #include #include @@ -33,12 +32,12 @@ void CSVDoc::AdjusterWidget::setAction (ContentAction action) mAction = action; } -void CSVDoc::AdjusterWidget::setLocalData (const boost::filesystem::path& localData) +void CSVDoc::AdjusterWidget::setLocalData (const std::filesystem::path& localData) { mLocalData = localData; } -boost::filesystem::path CSVDoc::AdjusterWidget::getPath() const +std::filesystem::path CSVDoc::AdjusterWidget::getPath() const { if (!mValid) throw std::logic_error ("invalid content file path"); @@ -69,7 +68,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) } else { - boost::filesystem::path path (name.toUtf8().data()); + std::filesystem::path path (name.toUtf8().data()); std::string extension = Misc::StringUtils::lowerCase(path.extension().string()); @@ -99,7 +98,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str()); mResultPath = path; - if (boost::filesystem::exists (path)) + if (std::filesystem::exists (path)) { /// \todo add an user setting to make this an error. message += "

A file with the same name already exists. If you continue, it will be overwritten."; diff --git a/apps/opencs/view/doc/adjusterwidget.hpp b/apps/opencs/view/doc/adjusterwidget.hpp index cec9ca2291..1a6f2c477b 100644 --- a/apps/opencs/view/doc/adjusterwidget.hpp +++ b/apps/opencs/view/doc/adjusterwidget.hpp @@ -1,7 +1,7 @@ #ifndef CSV_DOC_ADJUSTERWIDGET_H #define CSV_DOC_ADJUSTERWIDGET_H -#include +#include #include @@ -22,11 +22,11 @@ namespace CSVDoc public: - boost::filesystem::path mLocalData; + std::filesystem::path mLocalData; QLabel *mMessage; QLabel *mIcon; bool mValid; - boost::filesystem::path mResultPath; + std::filesystem::path mResultPath; ContentAction mAction; bool mDoFilenameCheck; @@ -34,13 +34,13 @@ namespace CSVDoc AdjusterWidget (QWidget *parent = nullptr); - void setLocalData (const boost::filesystem::path& localData); + void setLocalData (const std::filesystem::path& localData); void setAction (ContentAction action); void setFilenameCheck (bool doCheck); bool isValid() const; - boost::filesystem::path getPath() const; + std::filesystem::path getPath() const; ///< This function must not be called if there is no valid path. public slots: diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index 97ef0505c1..5a7852b4db 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -20,7 +20,7 @@ CSVDoc::FileDialog::FileDialog(QWidget *parent) : mAdjusterWidget = new AdjusterWidget (this); } -void CSVDoc::FileDialog::addFiles(const std::vector& dataDirs) +void CSVDoc::FileDialog::addFiles(const std::vector& dataDirs) { for (auto iter = dataDirs.rbegin(); iter != dataDirs.rend(); ++iter) { @@ -50,7 +50,7 @@ QStringList CSVDoc::FileDialog::selectedFilePaths() return filePaths; } -void CSVDoc::FileDialog::setLocalData (const boost::filesystem::path& localData) +void CSVDoc::FileDialog::setLocalData (const std::filesystem::path& localData) { mAdjusterWidget->setLocalData (localData); } diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp index 6a15b46b7c..69ba77b466 100644 --- a/apps/opencs/view/doc/filedialog.hpp +++ b/apps/opencs/view/doc/filedialog.hpp @@ -6,12 +6,12 @@ #ifndef Q_MOC_RUN -#include +#include #include "adjusterwidget.hpp" #ifndef CS_QT_BOOST_FILESYSTEM_PATH_DECLARED #define CS_QT_BOOST_FILESYSTEM_PATH_DECLARED -Q_DECLARE_METATYPE (boost::filesystem::path) +Q_DECLARE_METATYPE (std::filesystem::path) #endif #endif @@ -45,14 +45,14 @@ namespace CSVDoc explicit FileDialog(QWidget *parent = nullptr); void showDialog (ContentAction action); - void addFiles(const std::vector& dataDirs); + void addFiles(const std::vector& dataDirs); void setEncoding (const QString &encoding); void clearFiles (); QString filename() const; QStringList selectedFilePaths(); - void setLocalData (const boost::filesystem::path& localData); + void setLocalData (const std::filesystem::path& localData); private: @@ -61,8 +61,8 @@ namespace CSVDoc signals: - void signalOpenFiles (const boost::filesystem::path &path); - void signalCreateNewFile (const boost::filesystem::path &path); + void signalOpenFiles (const std::filesystem::path &path); + void signalCreateNewFile (const std::filesystem::path &path); void signalUpdateAcceptButton (bool, int); diff --git a/apps/opencs/view/doc/newgame.cpp b/apps/opencs/view/doc/newgame.cpp index 2ae3b5fe48..5fecf49134 100644 --- a/apps/opencs/view/doc/newgame.cpp +++ b/apps/opencs/view/doc/newgame.cpp @@ -50,7 +50,7 @@ CSVDoc::NewGameDialogue::NewGameDialogue() move (scr.center().x() - rect.center().x(), scr.center().y() - rect.center().y()); } -void CSVDoc::NewGameDialogue::setLocalData (const boost::filesystem::path& localData) +void CSVDoc::NewGameDialogue::setLocalData (const std::filesystem::path& localData) { mAdjusterWidget->setLocalData (localData); } diff --git a/apps/opencs/view/doc/newgame.hpp b/apps/opencs/view/doc/newgame.hpp index e3c6f53ca5..afe0f78e33 100644 --- a/apps/opencs/view/doc/newgame.hpp +++ b/apps/opencs/view/doc/newgame.hpp @@ -1,14 +1,14 @@ #ifndef CSV_DOC_NEWGAME_H #define CSV_DOC_NEWGAME_H -#include +#include #include #include #ifndef CS_QT_BOOST_FILESYSTEM_PATH_DECLARED #define CS_QT_BOOST_FILESYSTEM_PATH_DECLARED -Q_DECLARE_METATYPE (boost::filesystem::path) +Q_DECLARE_METATYPE (std::filesystem::path) #endif class QPushButton; @@ -30,11 +30,11 @@ namespace CSVDoc NewGameDialogue(); - void setLocalData (const boost::filesystem::path& localData); + void setLocalData (const std::filesystem::path& localData); signals: - void createRequest (const boost::filesystem::path& file); + void createRequest (const std::filesystem::path& file); void cancelCreateGame (); diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index 74daa7d8b9..e8b963f235 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -98,14 +98,14 @@ void CSVTools::Merge::configure (CSMDoc::Document *document) while (mFiles->count()) delete mFiles->takeItem (0); - std::vector files = document->getContentFiles(); + std::vector files = document->getContentFiles(); - for (std::vector::const_iterator iter (files.begin()); + for (std::vector::const_iterator iter (files.begin()); iter!=files.end(); ++iter) mFiles->addItem (QString::fromUtf8 (iter->filename().string().c_str())); } -void CSVTools::Merge::setLocalData (const boost::filesystem::path& localData) +void CSVTools::Merge::setLocalData (const std::filesystem::path& localData) { mAdjuster->setLocalData (localData); } @@ -125,7 +125,7 @@ void CSVTools::Merge::accept() { if ((mDocument->getState() & CSMDoc::State_Merging)==0) { - std::vector< boost::filesystem::path > files (1, mAdjuster->getPath()); + std::vector< std::filesystem::path > files (1, mAdjuster->getPath()); std::unique_ptr target ( mDocumentManager.makeDocument (files, files[0], true)); diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp index c7c4585979..39dea6fbb0 100644 --- a/apps/opencs/view/tools/merge.hpp +++ b/apps/opencs/view/tools/merge.hpp @@ -4,7 +4,7 @@ #include #ifndef Q_MOC_RUN -#include +#include #endif class QPushButton; @@ -44,7 +44,7 @@ namespace CSVTools /// Configure dialogue for a new merge void configure (CSMDoc::Document *document); - void setLocalData (const boost::filesystem::path& localData); + void setLocalData (const std::filesystem::path& localData); CSMDoc::Document *getDocument() const; diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 13fb717147..6e177bb0fa 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -143,9 +143,6 @@ target_link_libraries(openmw ${OSGDB_LIBRARIES} ${OSGUTIL_LIBRARIES} ${OSG_LIBRARIES} - - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${OPENAL_LIBRARY} ${FFmpeg_LIBRARIES} diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 067fe50100..07f5f77e98 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1,11 +1,7 @@ #include "engine.hpp" -#include #include #include -#include - -#include #include #include @@ -542,7 +538,7 @@ void OMW::Engine::addArchive (const std::string& archive) { } // Set resource dir -void OMW::Engine::setResourceDir (const boost::filesystem::path& parResDir) +void OMW::Engine::setResourceDir (const std::filesystem::path& parResDir) { mResDir = parResDir; } diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 8f05750bd4..cc3f92cdd2 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -1,6 +1,8 @@ #ifndef ENGINE_H #define ENGINE_H +#include + #include #include #include @@ -135,7 +137,7 @@ namespace OMW std::unique_ptr mEncoder; Files::PathContainer mDataDirs; std::vector mArchives; - boost::filesystem::path mResDir; + std::filesystem::path mResDir; osg::ref_ptr mViewer; osg::ref_ptr mScreenCaptureHandler; osg::ref_ptr mScreenCaptureOperation; @@ -203,7 +205,7 @@ namespace OMW void addArchive(const std::string& archive); /// Set resource dir - void setResourceDir(const boost::filesystem::path& parResDir); + void setResourceDir(const std::filesystem::path& parResDir); /// Set start cell name void setCell(const std::string& cellName); diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index 7845567194..c43229f588 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -1,14 +1,14 @@ #include "character.hpp" #include +#include #include +#include -#include - -#include #include - +#include #include +#include #include @@ -27,11 +27,11 @@ std::string MWState::getFirstGameFile(const std::vector& contentFil return ""; } -void MWState::Character::addSlot (const boost::filesystem::path& path, const std::string& game) +void MWState::Character::addSlot (const std::filesystem::path& path, const std::string& game) { Slot slot; slot.mPath = path; - slot.mTimeStamp = boost::filesystem::last_write_time (path); + slot.mTimeStamp = std::chrono::system_clock::to_time_t (Misc::clockCast (std::filesystem::last_write_time (path))); ESM::ESMReader reader; reader.open (slot.mPath.string()); @@ -71,7 +71,7 @@ void MWState::Character::addSlot (const ESM::SavedGame& profile) // Append an index if necessary to ensure a unique file int i=0; - while (boost::filesystem::exists(slot.mPath)) + while (std::filesystem::exists(slot.mPath)) { const std::string test = stream.str() + " - " + std::to_string(++i); slot.mPath = mPath / (test + ext); @@ -83,19 +83,18 @@ void MWState::Character::addSlot (const ESM::SavedGame& profile) mSlots.push_back (slot); } -MWState::Character::Character (const boost::filesystem::path& saves, const std::string& game) -: mPath (saves) +MWState::Character::Character (std::filesystem::path saves, const std::string& game) + : mPath (std::move(saves)) { - if (!boost::filesystem::is_directory (mPath)) + if (!std::filesystem::is_directory (mPath)) { - boost::filesystem::create_directories (mPath); + std::filesystem::create_directories (mPath); } else { - for (boost::filesystem::directory_iterator iter (mPath); - iter!=boost::filesystem::directory_iterator(); ++iter) + for (std::filesystem::directory_iterator iter (mPath); iter!=std::filesystem::directory_iterator(); ++iter) { - boost::filesystem::path slotPath = *iter; + std::filesystem::path slotPath = *iter; try { @@ -110,15 +109,15 @@ MWState::Character::Character (const boost::filesystem::path& saves, const std:: void MWState::Character::cleanup() { - if (mSlots.size() == 0) + if (mSlots.empty()) { // All slots are gone, no need to keep the empty directory - if (boost::filesystem::is_directory (mPath)) + if (std::filesystem::is_directory (mPath)) { // Extra safety check to make sure the directory is empty (e.g. slots failed to parse header) - boost::filesystem::directory_iterator it(mPath); - if (it == boost::filesystem::directory_iterator()) - boost::filesystem::remove_all(mPath); + std::filesystem::directory_iterator it(mPath); + if (it == std::filesystem::directory_iterator()) + std::filesystem::remove_all(mPath); } } } @@ -140,7 +139,7 @@ void MWState::Character::deleteSlot (const Slot *slot) throw std::logic_error ("slot not found"); } - boost::filesystem::remove(slot->mPath); + std::filesystem::remove(slot->mPath); mSlots.erase (mSlots.begin()+index); } @@ -195,7 +194,7 @@ ESM::SavedGame MWState::Character::getSignature() const return slot.mProfile; } -const boost::filesystem::path& MWState::Character::getPath() const +const std::filesystem::path& MWState::Character::getPath() const { return mPath; } diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp index 2ecd888a7b..31dbde5830 100644 --- a/apps/openmw/mwstate/character.hpp +++ b/apps/openmw/mwstate/character.hpp @@ -1,7 +1,7 @@ #ifndef GAME_STATE_CHARACTER_H #define GAME_STATE_CHARACTER_H -#include +#include #include @@ -9,7 +9,7 @@ namespace MWState { struct Slot { - boost::filesystem::path mPath; + std::filesystem::path mPath; ESM::SavedGame mProfile; std::time_t mTimeStamp; }; @@ -26,16 +26,16 @@ namespace MWState private: - boost::filesystem::path mPath; + std::filesystem::path mPath; std::vector mSlots; - void addSlot (const boost::filesystem::path& path, const std::string& game); + void addSlot (const std::filesystem::path& path, const std::string& game); void addSlot (const ESM::SavedGame& profile); public: - Character (const boost::filesystem::path& saves, const std::string& game); + Character (std::filesystem::path saves, const std::string& game); void cleanup(); ///< Delete the directory we used, if it is empty @@ -60,7 +60,7 @@ namespace MWState SlotIterator end() const; - const boost::filesystem::path& getPath() const; + const std::filesystem::path& getPath() const; ESM::SavedGame getSignature() const; ///< Return signature information for this character. diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index 301f33c5df..c9bcb0b139 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -2,27 +2,27 @@ #include #include - -#include +#include +#include #include -MWState::CharacterManager::CharacterManager (const boost::filesystem::path& saves, +MWState::CharacterManager::CharacterManager (std::filesystem::path saves, const std::vector& contentFiles) -: mPath (saves), mCurrent (nullptr), mGame (getFirstGameFile(contentFiles)) +: mPath (std::move(saves)), mCurrent (nullptr), mGame (getFirstGameFile(contentFiles)) { - if (!boost::filesystem::is_directory (mPath)) + if (!std::filesystem::is_directory (mPath)) { - boost::filesystem::create_directories (mPath); + std::filesystem::create_directories (mPath); } else { - for (boost::filesystem::directory_iterator iter (mPath); - iter!=boost::filesystem::directory_iterator(); ++iter) + for (std::filesystem::directory_iterator iter (mPath); + iter!=std::filesystem::directory_iterator(); ++iter) { - boost::filesystem::path characterDir = *iter; + std::filesystem::path characterDir = *iter; - if (boost::filesystem::is_directory (characterDir)) + if (std::filesystem::is_directory (characterDir)) { Character character (characterDir, mGame); @@ -69,11 +69,11 @@ MWState::Character* MWState::CharacterManager::createCharacter(const std::string stream << '_'; } - boost::filesystem::path path = mPath / stream.str(); + std::filesystem::path path = mPath / stream.str(); // Append an index if necessary to ensure a unique directory int i=0; - while (boost::filesystem::exists(path)) + while (std::filesystem::exists(path)) { std::ostringstream test; test << stream.str(); diff --git a/apps/openmw/mwstate/charactermanager.hpp b/apps/openmw/mwstate/charactermanager.hpp index 8b3f2b8f8f..f2cd45cd10 100644 --- a/apps/openmw/mwstate/charactermanager.hpp +++ b/apps/openmw/mwstate/charactermanager.hpp @@ -1,7 +1,8 @@ #ifndef GAME_STATE_CHARACTERMANAGER_H #define GAME_STATE_CHARACTERMANAGER_H -#include +#include +#include #include "character.hpp" @@ -9,7 +10,7 @@ namespace MWState { class CharacterManager { - boost::filesystem::path mPath; + std::filesystem::path mPath; // Uses std::list, so that mCurrent stays valid when characters are deleted std::list mCharacters; @@ -29,7 +30,7 @@ namespace MWState public: - CharacterManager (const boost::filesystem::path& saves, const std::vector& contentFiles); + CharacterManager (std::filesystem::path saves, const std::vector& contentFiles); Character *getCurrentCharacter (); ///< @note May return null diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index c21713ceca..2b80063265 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -18,9 +18,6 @@ #include -#include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" @@ -91,7 +88,7 @@ std::map MWState::StateManager::buildContentFileIndexMap (const ESM::E return map; } -MWState::StateManager::StateManager (const boost::filesystem::path& saves, const std::vector& contentFiles) +MWState::StateManager::StateManager (const std::filesystem::path& saves, const std::vector& contentFiles) : mQuitRequest (false), mAskLoadRecent(false), mState (State_NoGame), mCharacterManager (saves, contentFiles), mTimePlayed (0) { @@ -301,7 +298,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot throw std::runtime_error("Write operation failed (memory stream)"); // All good, write to file - boost::filesystem::ofstream filestream (slot->mPath, std::ios::binary); + std::ofstream filestream (slot->mPath, std::ios::binary); filestream << stream.rdbuf(); if (filestream.fail()) @@ -327,7 +324,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot MWBase::Environment::get().getWindowManager()->interactiveMessageBox(error.str(), buttons); // If no file was written, clean up the slot - if (character && slot && !boost::filesystem::exists(slot->mPath)) + if (character && slot && !std::filesystem::exists(slot->mPath)) { character->deleteSlot(slot); character->cleanup(); @@ -373,7 +370,7 @@ void MWState::StateManager::loadGame(const std::string& filepath) { for (const auto& slot : character) { - if (slot.mPath == boost::filesystem::path(filepath)) + if (slot.mPath == std::filesystem::path(filepath)) { loadGame(&character, slot.mPath.string()); return; diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 3da71e8401..ae1b592cfe 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -2,11 +2,10 @@ #define GAME_STATE_STATEMANAGER_H #include +#include #include "../mwbase/statemanager.hpp" -#include - #include "charactermanager.hpp" namespace MWState @@ -31,7 +30,7 @@ namespace MWState public: - StateManager (const boost::filesystem::path& saves, const std::vector& contentFiles); + StateManager (const std::filesystem::path& saves, const std::vector& contentFiles); void requestQuit() override; diff --git a/apps/openmw/mwworld/contentloader.hpp b/apps/openmw/mwworld/contentloader.hpp index 55de77ad25..cb228a9ecb 100644 --- a/apps/openmw/mwworld/contentloader.hpp +++ b/apps/openmw/mwworld/contentloader.hpp @@ -1,7 +1,7 @@ #ifndef CONTENTLOADER_HPP #define CONTENTLOADER_HPP -#include +#include namespace Loading { @@ -15,7 +15,7 @@ struct ContentLoader { virtual ~ContentLoader() = default; - virtual void load(const boost::filesystem::path& filepath, int& index, Loading::Listener* listener) = 0; + virtual void load(const std::filesystem::path& filepath, int& index, Loading::Listener* listener) = 0; }; } /* namespace MWWorld */ diff --git a/apps/openmw/mwworld/esmloader.cpp b/apps/openmw/mwworld/esmloader.cpp index 1a215e2608..4fe1df72f8 100644 --- a/apps/openmw/mwworld/esmloader.cpp +++ b/apps/openmw/mwworld/esmloader.cpp @@ -16,7 +16,7 @@ EsmLoader::EsmLoader(MWWorld::ESMStore& store, ESM::ReadersCache& readers, ToUTF { } -void EsmLoader::load(const boost::filesystem::path& filepath, int& index, Loading::Listener* listener) +void EsmLoader::load(const std::filesystem::path& filepath, int& index, Loading::Listener* listener) { const ESM::ReadersCache::BusyItem reader = mReaders.get(static_cast(index)); diff --git a/apps/openmw/mwworld/esmloader.hpp b/apps/openmw/mwworld/esmloader.hpp index a74a200d30..4c7c095b4b 100644 --- a/apps/openmw/mwworld/esmloader.hpp +++ b/apps/openmw/mwworld/esmloader.hpp @@ -27,7 +27,7 @@ struct EsmLoader : public ContentLoader std::optional getMasterFileFormat() const { return mMasterFileFormat; } - void load(const boost::filesystem::path& filepath, int& index, Loading::Listener* listener) override; + void load(const std::filesystem::path& filepath, int& index, Loading::Listener* listener) override; private: ESM::ReadersCache& mReaders; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 375351e606..1a10a53954 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -102,7 +102,7 @@ namespace MWWorld mLoaders.emplace(std::move(extension), &loader); } - void load(const boost::filesystem::path& filepath, int& index, Loading::Listener* listener) override + void load(const std::filesystem::path& filepath, int& index, Loading::Listener* listener) override { const auto it = mLoaders.find(Misc::StringUtils::lowerCase(filepath.extension().string())); if (it != mLoaders.end()) @@ -129,7 +129,7 @@ namespace MWWorld { ESMStore& mStore; OMWScriptsLoader(ESMStore& store) : mStore(store) {} - void load(const boost::filesystem::path& filepath, int& /*index*/, Loading::Listener* /*listener*/) override + void load(const std::filesystem::path& filepath, int& /*index*/, Loading::Listener* /*listener*/) override { mStore.addOMWScripts(filepath.string()); } @@ -2963,7 +2963,7 @@ namespace MWWorld int idx = 0; for (const std::string &file : content) { - boost::filesystem::path filename(file); + std::filesystem::path filename(file); const Files::MultiDirCollection& col = fileCollections.getCollection(filename.extension().string()); if (col.doesExist(file)) { diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 88ea74c804..edba8b3d3a 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -97,7 +97,7 @@ struct ContentFileTest : public ::testing::Test protected: Files::ConfigurationManager mConfigurationManager; MWWorld::ESMStore mEsmStore; - std::vector mContentFiles; + std::vector mContentFiles; }; /// Print results of the dialogue merging process, i.e. the resulting linked list. diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index 5e3dff5ff5..9544ccfbee 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -54,8 +54,8 @@ Wizard::MainWizard::MainWizard(QWidget *parent) :

Please make sure you have the right permissions \ and try again.

"); - boost::filesystem::create_directories(mCfgMgr.getUserConfigPath()); - boost::filesystem::create_directories(mCfgMgr.getUserDataPath()); + std::filesystem::create_directories(mCfgMgr.getUserConfigPath()); + std::filesystem::create_directories(mCfgMgr.getUserDataPath()); setupLog(); setupGameSettings(); @@ -63,10 +63,10 @@ Wizard::MainWizard::MainWizard(QWidget *parent) : setupInstallations(); setupPages(); - const boost::filesystem::path& installationPath = mCfgMgr.getInstallPath(); + const std::filesystem::path& installationPath = mCfgMgr.getInstallPath(); if (!installationPath.empty()) { - const boost::filesystem::path& dataPath = installationPath / "Data Files"; + const std::filesystem::path& dataPath = installationPath / "Data Files"; addInstallation(toQString(dataPath)); } } @@ -469,7 +469,7 @@ bool Wizard::MainWizard::findFiles(const QString &name, const QString &path) && dir.entryList().contains(name + QLatin1String(".bsa"), Qt::CaseInsensitive)); } -QString Wizard::MainWizard::toQString(const boost::filesystem::path& path) +QString Wizard::MainWizard::toQString(const std::filesystem::path& path) { return QString::fromUtf8(path.string().c_str()); } diff --git a/apps/wizard/mainwizard.hpp b/apps/wizard/mainwizard.hpp index a8dec32da7..1316aa2ec0 100644 --- a/apps/wizard/mainwizard.hpp +++ b/apps/wizard/mainwizard.hpp @@ -58,8 +58,8 @@ namespace Wizard void addLogText(const QString &text); private: - /// convert boost::filesystem::path to QString - QString toQString(const boost::filesystem::path& path); + /// convert std::filesystem::path to QString + QString toQString(const std::filesystem::path& path); void setupLog(); void setupGameSettings(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index af4b8c7f14..2e259c2136 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -411,7 +411,6 @@ target_link_libraries(components ${OPENTHREADS_LIBRARIES} ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_IOSTREAMS_LIBRARY} diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index b59c3435e0..d15cb4bb97 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -68,8 +68,8 @@ void Config::GameSettings::validatePaths() std::string Config::GameSettings::getGlobalDataDir() const { // global data dir may not exists if OpenMW is not installed (ie if run from build directory) - if (boost::filesystem::exists(mCfgMgr.getGlobalDataPath())) - return boost::filesystem::canonical(mCfgMgr.getGlobalDataPath()).string(); + if (std::filesystem::exists(mCfgMgr.getGlobalDataPath())) + return std::filesystem::canonical(mCfgMgr.getGlobalDataPath()).string(); return {}; } @@ -173,7 +173,7 @@ bool Config::GameSettings::writeFile(QTextStream &stream) while (i.hasPrevious()) { i.previous(); - // path lines (e.g. 'data=...') need quotes and ampersands escaping to match how boost::filesystem::path uses boost::io::quoted + // path lines (e.g. 'data=...') need quotes and ampersands escaping to match how std::filesystem::path uses boost::io::quoted if (i.key() == QLatin1String("data") || i.key() == QLatin1String("data-local") || i.key() == QLatin1String("resources") diff --git a/components/config/gamesettings.hpp b/components/config/gamesettings.hpp index 970a35a504..89b958bd47 100644 --- a/components/config/gamesettings.hpp +++ b/components/config/gamesettings.hpp @@ -1,17 +1,17 @@ #ifndef GAMESETTINGS_HPP #define GAMESETTINGS_HPP +#include + #include #include #include #include #include -#include - namespace Files { - typedef std::vector PathContainer; + typedef std::vector PathContainer; struct ConfigurationManager; } diff --git a/components/debug/debugging.cpp b/components/debug/debugging.cpp index e37406299d..01dcde7bcc 100644 --- a/components/debug/debugging.cpp +++ b/components/debug/debugging.cpp @@ -2,9 +2,9 @@ #include #include -#include #include -#include + +#include #include #include diff --git a/components/debug/debugging.hpp b/components/debug/debugging.hpp index 8ac4bcd8ef..a250c5d837 100644 --- a/components/debug/debugging.hpp +++ b/components/debug/debugging.hpp @@ -1,8 +1,8 @@ #ifndef DEBUG_DEBUGGING_H #define DEBUG_DEBUGGING_H -#include -#include +#include +#include #include diff --git a/components/files/androidpath.cpp b/components/files/androidpath.cpp index a35b2f75bb..36479d4ebb 100644 --- a/components/files/androidpath.cpp +++ b/components/files/androidpath.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include static const char *g_path_global; //< Path to global directory root, e.g. /data/data/com.libopenmw.openmw static const char *g_path_user; //< Path to user root, e.g. /sdcard/Android/data/com.libopenmw.openmw @@ -29,47 +29,47 @@ AndroidPath::AndroidPath(const std::string& application_name) } // /sdcard/Android/data/com.libopenmw.openmw/config -boost::filesystem::path AndroidPath::getUserConfigPath() const +std::filesystem::path AndroidPath::getUserConfigPath() const { - return boost::filesystem::path(g_path_user) / "config"; + return std::filesystem::path(g_path_user) / "config"; } // /sdcard/Android/data/com.libopenmw.openmw/ // (so that saves are placed at /sdcard/Android/data/com.libopenmw.openmw/saves) -boost::filesystem::path AndroidPath::getUserDataPath() const +std::filesystem::path AndroidPath::getUserDataPath() const { - return boost::filesystem::path(g_path_user); + return std::filesystem::path(g_path_user); } // /data/data/com.libopenmw.openmw/cache // (supposed to be "official" android cache location) -boost::filesystem::path AndroidPath::getCachePath() const +std::filesystem::path AndroidPath::getCachePath() const { - return boost::filesystem::path(g_path_global) / "cache"; + return std::filesystem::path(g_path_global) / "cache"; } // /data/data/com.libopenmw.openmw/files/config // (note the addition of "files") -boost::filesystem::path AndroidPath::getGlobalConfigPath() const +std::filesystem::path AndroidPath::getGlobalConfigPath() const { - return boost::filesystem::path(g_path_global) / "files" / "config"; + return std::filesystem::path(g_path_global) / "files" / "config"; } -boost::filesystem::path AndroidPath::getLocalPath() const +std::filesystem::path AndroidPath::getLocalPath() const { - return boost::filesystem::path("./"); + return std::filesystem::path("./"); } // /sdcard/Android/data/com.libopenmw.openmw // (so that the data is at /sdcard/Android/data/com.libopenmw.openmw/data) -boost::filesystem::path AndroidPath::getGlobalDataPath() const +std::filesystem::path AndroidPath::getGlobalDataPath() const { - return boost::filesystem::path(g_path_user); + return std::filesystem::path(g_path_user); } -boost::filesystem::path AndroidPath::getInstallPath() const +std::filesystem::path AndroidPath::getInstallPath() const { - return boost::filesystem::path(); + return std::filesystem::path(); } diff --git a/components/files/androidpath.hpp b/components/files/androidpath.hpp index cca77858c1..33d89fdce1 100644 --- a/components/files/androidpath.hpp +++ b/components/files/androidpath.hpp @@ -3,7 +3,7 @@ #if defined(__ANDROID__) -#include +#include /** * \namespace Files */ @@ -20,32 +20,32 @@ struct AndroidPath /** * \brief Return path to the user directory. */ - boost::filesystem::path getUserConfigPath() const; + std::filesystem::path getUserConfigPath() const; - boost::filesystem::path getUserDataPath() const; + std::filesystem::path getUserDataPath() const; /** * \brief Return path to the global (system) directory where config files can be placed. */ - boost::filesystem::path getGlobalConfigPath() const; + std::filesystem::path getGlobalConfigPath() const; /** * \brief Return path to the runtime configuration directory which is the * place where an application was started. */ - boost::filesystem::path getLocalPath() const; + std::filesystem::path getLocalPath() const; /** * \brief Return path to the global (system) directory where game files can be placed. */ - boost::filesystem::path getGlobalDataPath() const; + std::filesystem::path getGlobalDataPath() const; /** * \brief */ - boost::filesystem::path getCachePath() const; + std::filesystem::path getCachePath() const; - boost::filesystem::path getInstallPath() const; + std::filesystem::path getInstallPath() const; }; } /* namespace Files */ diff --git a/components/files/collections.cpp b/components/files/collections.cpp index 62da9fdd4e..6146da3347 100644 --- a/components/files/collections.cpp +++ b/components/files/collections.cpp @@ -34,15 +34,15 @@ namespace Files return iter->second; } - boost::filesystem::path Collections::getPath(const std::string& file) const + std::filesystem::path Collections::getPath(const std::string& file) const { for (Files::PathContainer::const_iterator iter = mDirectories.begin(); iter != mDirectories.end(); ++iter) { - for (boost::filesystem::directory_iterator iter2 (*iter); - iter2!=boost::filesystem::directory_iterator(); ++iter2) + for (std::filesystem::directory_iterator iter2 (*iter); + iter2!=std::filesystem::directory_iterator(); ++iter2) { - boost::filesystem::path path = *iter2; + std::filesystem::path path = *iter2; if (mFoldCase) { @@ -62,10 +62,10 @@ namespace Files for (Files::PathContainer::const_iterator iter = mDirectories.begin(); iter != mDirectories.end(); ++iter) { - for (boost::filesystem::directory_iterator iter2 (*iter); - iter2!=boost::filesystem::directory_iterator(); ++iter2) + for (std::filesystem::directory_iterator iter2 (*iter); + iter2!=std::filesystem::directory_iterator(); ++iter2) { - boost::filesystem::path path = *iter2; + std::filesystem::path path = *iter2; if (mFoldCase) { diff --git a/components/files/collections.hpp b/components/files/collections.hpp index def61cf8ef..000160bae7 100644 --- a/components/files/collections.hpp +++ b/components/files/collections.hpp @@ -1,7 +1,7 @@ #ifndef COMPONENTS_FILES_COLLECTION_HPP #define COMPONENTS_FILES_COLLECTION_HPP -#include +#include #include "multidircollection.hpp" @@ -19,7 +19,7 @@ namespace Files /// leading dot and must be all lower-case. const MultiDirCollection& getCollection(const std::string& extension) const; - boost::filesystem::path getPath(const std::string& file) const; + std::filesystem::path getPath(const std::string& file) const; ///< Return full path (including filename) of \a file. /// /// If the file does not exist in any of the collection's diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 5d21bfb6d3..f792af5f3d 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -1,10 +1,11 @@ #include "configurationmanager.hpp" +#include + #include #include #include -#include #include #include @@ -86,18 +87,18 @@ void ConfigurationManager::readConfiguration(bpo::variables_map& variables, return; } - std::stack extraConfigDirs; + std::stack extraConfigDirs; addExtraConfigDirs(extraConfigDirs, variables); if (!hasReplaceConfig(variables)) addExtraConfigDirs(extraConfigDirs, *config); std::vector parsedConfigs{*std::move(config)}; - std::set alreadyParsedPaths; // needed to prevent infinite loop in case of a circular link - alreadyParsedPaths.insert(boost::filesystem::path(mActiveConfigPaths.front())); + std::set alreadyParsedPaths; // needed to prevent infinite loop in case of a circular link + alreadyParsedPaths.insert(std::filesystem::path(mActiveConfigPaths.front())); while (!extraConfigDirs.empty()) { - boost::filesystem::path path = extraConfigDirs.top(); + std::filesystem::path path = extraConfigDirs.top(); extraConfigDirs.pop(); if (alreadyParsedPaths.count(path) > 0) { @@ -145,11 +146,11 @@ void ConfigurationManager::readConfiguration(bpo::variables_map& variables, } mScreenshotPath = mUserDataPath / "screenshots"; - boost::filesystem::create_directories(getUserConfigPath()); - boost::filesystem::create_directories(mScreenshotPath); + std::filesystem::create_directories(getUserConfigPath()); + std::filesystem::create_directories(mScreenshotPath); // probably not necessary but validate the creation of the screenshots directory and fallback to the original behavior if it fails - if (!boost::filesystem::is_directory(mScreenshotPath)) + if (!std::filesystem::is_directory(mScreenshotPath)) mScreenshotPath = mUserDataPath; if (!quiet) @@ -162,7 +163,7 @@ void ConfigurationManager::readConfiguration(bpo::variables_map& variables, mSilent = silent; } -void ConfigurationManager::addExtraConfigDirs(std::stack& dirs, +void ConfigurationManager::addExtraConfigDirs(std::stack& dirs, const bpo::variables_map& variables) const { auto configIt = variables.find("config"); @@ -267,7 +268,7 @@ void mergeComposingVariables(bpo::variables_map& first, bpo::variables_map& seco } } -void ConfigurationManager::processPath(boost::filesystem::path& path, const boost::filesystem::path& basePath) const +void ConfigurationManager::processPath(std::filesystem::path& path, const std::filesystem::path& basePath) const { std::string str = path.string(); @@ -284,7 +285,7 @@ void ConfigurationManager::processPath(boost::filesystem::path& path, const boos auto tokenIt = mTokensMapping.find(str.substr(0, pos + 1)); if (tokenIt != mTokensMapping.end()) { - boost::filesystem::path tempPath(((mFixedPath).*(tokenIt->second))()); + std::filesystem::path tempPath(((mFixedPath).*(tokenIt->second))()); if (pos < str.length() - 1) { // There is something after the token, so we should @@ -303,13 +304,13 @@ void ConfigurationManager::processPath(boost::filesystem::path& path, const boos } } -void ConfigurationManager::processPaths(Files::PathContainer& dataDirs, const boost::filesystem::path& basePath) const +void ConfigurationManager::processPaths(Files::PathContainer& dataDirs, const std::filesystem::path& basePath) const { for (auto& path : dataDirs) processPath(path, basePath); } -void ConfigurationManager::processPaths(boost::program_options::variables_map& variables, const boost::filesystem::path& basePath) const +void ConfigurationManager::processPaths(boost::program_options::variables_map& variables, const std::filesystem::path& basePath) const { for (auto& [name, var] : variables) { @@ -323,7 +324,7 @@ void ConfigurationManager::processPaths(boost::program_options::variables_map& v } else if (var.value().type() == typeid(MaybeQuotedPath)) { - boost::filesystem::path& path = boost::any_cast(var.value()); + std::filesystem::path& path = boost::any_cast(var.value()); processPath(path, basePath); } } @@ -332,9 +333,9 @@ void ConfigurationManager::processPaths(boost::program_options::variables_map& v void ConfigurationManager::filterOutNonExistingPaths(Files::PathContainer& dataDirs) const { dataDirs.erase(std::remove_if(dataDirs.begin(), dataDirs.end(), - [this](const boost::filesystem::path& p) + [this](const std::filesystem::path& p) { - bool exists = boost::filesystem::is_directory(p); + bool exists = std::filesystem::is_directory(p); if (!exists && !mSilent) Log(Debug::Warning) << "No such dir: " << p; return !exists; @@ -343,16 +344,16 @@ void ConfigurationManager::filterOutNonExistingPaths(Files::PathContainer& dataD } std::optional ConfigurationManager::loadConfig( - const boost::filesystem::path& path, const bpo::options_description& description) const + const std::filesystem::path& path, const bpo::options_description& description) const { - boost::filesystem::path cfgFile(path); + std::filesystem::path cfgFile(path); cfgFile /= std::string(openmwCfgFile); - if (boost::filesystem::is_regular_file(cfgFile)) + if (std::filesystem::is_regular_file(cfgFile)) { if (!mSilent) Log(Debug::Info) << "Loading config file: " << cfgFile.string(); - boost::filesystem::ifstream configFileStream(cfgFile); + std::ifstream configFileStream(cfgFile); if (configFileStream.is_open()) { @@ -367,12 +368,12 @@ std::optional ConfigurationManager::loadConfig( return std::nullopt; } -const boost::filesystem::path& ConfigurationManager::getGlobalPath() const +const std::filesystem::path& ConfigurationManager::getGlobalPath() const { return mFixedPath.getGlobalConfigPath(); } -const boost::filesystem::path& ConfigurationManager::getUserConfigPath() const +const std::filesystem::path& ConfigurationManager::getUserConfigPath() const { if (mActiveConfigPaths.empty()) return mFixedPath.getUserConfigPath(); @@ -380,32 +381,32 @@ const boost::filesystem::path& ConfigurationManager::getUserConfigPath() const return mActiveConfigPaths.back(); } -const boost::filesystem::path& ConfigurationManager::getUserDataPath() const +const std::filesystem::path& ConfigurationManager::getUserDataPath() const { return mUserDataPath; } -const boost::filesystem::path& ConfigurationManager::getLocalPath() const +const std::filesystem::path& ConfigurationManager::getLocalPath() const { return mFixedPath.getLocalPath(); } -const boost::filesystem::path& ConfigurationManager::getGlobalDataPath() const +const std::filesystem::path& ConfigurationManager::getGlobalDataPath() const { return mFixedPath.getGlobalDataPath(); } -const boost::filesystem::path& ConfigurationManager::getCachePath() const +const std::filesystem::path& ConfigurationManager::getCachePath() const { return mFixedPath.getCachePath(); } -const boost::filesystem::path& ConfigurationManager::getInstallPath() const +const std::filesystem::path& ConfigurationManager::getInstallPath() const { return mFixedPath.getInstallPath(); } -const boost::filesystem::path& ConfigurationManager::getScreenshotPath() const +const std::filesystem::path& ConfigurationManager::getScreenshotPath() const { return mScreenshotPath; } @@ -426,12 +427,12 @@ void parseConfig(std::istream& stream, bpo::variables_map& variables, const bpo: std::istream& operator>> (std::istream& istream, MaybeQuotedPath& MaybeQuotedPath) { - // If the stream starts with a double quote, read from stream using boost::filesystem::path rules, then discard anything remaining. + // If the stream starts with a double quote, read from stream using std::filesystem::path rules, then discard anything remaining. // This prevents boost::program_options getting upset that we've not consumed the whole stream. // If it doesn't start with a double quote, read the whole thing verbatim if (istream.peek() == '"') { - istream >> static_cast(MaybeQuotedPath); + istream >> static_cast(MaybeQuotedPath); if (istream && !istream.eof() && istream.peek() != EOF) { std::string remainder{std::istreambuf_iterator(istream), {}}; @@ -441,7 +442,7 @@ std::istream& operator>> (std::istream& istream, MaybeQuotedPath& MaybeQuotedPat else { std::string intermediate{std::istreambuf_iterator(istream), {}}; - static_cast(MaybeQuotedPath) = intermediate; + static_cast(MaybeQuotedPath) = intermediate; } return istream; } diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 20387c1ba5..74f035ffb6 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -34,49 +34,49 @@ struct ConfigurationManager void filterOutNonExistingPaths(Files::PathContainer& dataDirs) const; // Replaces tokens (`?local?`, `?global?`, etc.) in paths. Adds `basePath` prefix for relative paths. - void processPath(boost::filesystem::path& path, const boost::filesystem::path& basePath) const; - void processPaths(Files::PathContainer& dataDirs, const boost::filesystem::path& basePath) const; - void processPaths(boost::program_options::variables_map& variables, const boost::filesystem::path& basePath) const; + void processPath(std::filesystem::path& path, const std::filesystem::path& basePath) const; + void processPaths(Files::PathContainer& dataDirs, const std::filesystem::path& basePath) const; + void processPaths(boost::program_options::variables_map& variables, const std::filesystem::path& basePath) const; /**< Fixed paths */ - const boost::filesystem::path& getGlobalPath() const; - const boost::filesystem::path& getLocalPath() const; + const std::filesystem::path& getGlobalPath() const; + const std::filesystem::path& getLocalPath() const; - const boost::filesystem::path& getGlobalDataPath() const; - const boost::filesystem::path& getUserConfigPath() const; - const boost::filesystem::path& getUserDataPath() const; - const boost::filesystem::path& getLocalDataPath() const; - const boost::filesystem::path& getInstallPath() const; - const std::vector& getActiveConfigPaths() const { return mActiveConfigPaths; } + const std::filesystem::path& getGlobalDataPath() const; + const std::filesystem::path& getUserConfigPath() const; + const std::filesystem::path& getUserDataPath() const; + const std::filesystem::path& getLocalDataPath() const; + const std::filesystem::path& getInstallPath() const; + const std::vector& getActiveConfigPaths() const { return mActiveConfigPaths; } - const boost::filesystem::path& getCachePath() const; + const std::filesystem::path& getCachePath() const; - const boost::filesystem::path& getLogPath() const { return getUserConfigPath(); } - const boost::filesystem::path& getScreenshotPath() const; + const std::filesystem::path& getLogPath() const { return getUserConfigPath(); } + const std::filesystem::path& getScreenshotPath() const; static void addCommonOptions(boost::program_options::options_description& description); private: typedef Files::FixedPath<> FixedPathType; - typedef const boost::filesystem::path& (FixedPathType::*path_type_f)() const; + typedef const std::filesystem::path& (FixedPathType::*path_type_f)() const; typedef std::map TokensMappingContainer; std::optional loadConfig( - const boost::filesystem::path& path, + const std::filesystem::path& path, const boost::program_options::options_description& description) const; - void addExtraConfigDirs(std::stack& dirs, + void addExtraConfigDirs(std::stack& dirs, const boost::program_options::variables_map& variables) const; void setupTokensMapping(); - std::vector mActiveConfigPaths; + std::vector mActiveConfigPaths; FixedPathType mFixedPath; - boost::filesystem::path mUserDataPath; - boost::filesystem::path mScreenshotPath; + std::filesystem::path mUserDataPath; + std::filesystem::path mScreenshotPath; TokensMappingContainer mTokensMapping; @@ -95,7 +95,7 @@ void parseArgs(int argc, const char* const argv[], boost::program_options::varia void parseConfig(std::istream& stream, boost::program_options::variables_map& variables, const boost::program_options::options_description& description); -class MaybeQuotedPath : public boost::filesystem::path +class MaybeQuotedPath : public std::filesystem::path { }; diff --git a/components/files/fixedpath.hpp b/components/files/fixedpath.hpp index 2e72b81542..9d0f666409 100644 --- a/components/files/fixedpath.hpp +++ b/components/files/fixedpath.hpp @@ -2,7 +2,7 @@ #define COMPONENTS_FILES_FIXEDPATH_HPP #include -#include +#include #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) #ifndef ANDROID @@ -65,12 +65,12 @@ struct FixedPath /** * \brief Return path pointing to the user local configuration directory. */ - const boost::filesystem::path& getUserConfigPath() const + const std::filesystem::path& getUserConfigPath() const { return mUserConfigPath; } - const boost::filesystem::path& getUserDataPath() const + const std::filesystem::path& getUserDataPath() const { return mUserDataPath; } @@ -78,7 +78,7 @@ struct FixedPath /** * \brief Return path pointing to the global (system) configuration directory. */ - const boost::filesystem::path& getGlobalConfigPath() const + const std::filesystem::path& getGlobalConfigPath() const { return mGlobalConfigPath; } @@ -86,23 +86,23 @@ struct FixedPath /** * \brief Return path pointing to the directory where application was started. */ - const boost::filesystem::path& getLocalPath() const + const std::filesystem::path& getLocalPath() const { return mLocalPath; } - const boost::filesystem::path& getInstallPath() const + const std::filesystem::path& getInstallPath() const { return mInstallPath; } - const boost::filesystem::path& getGlobalDataPath() const + const std::filesystem::path& getGlobalDataPath() const { return mGlobalDataPath; } - const boost::filesystem::path& getCachePath() const + const std::filesystem::path& getCachePath() const { return mCachePath; } @@ -110,16 +110,16 @@ struct FixedPath private: PathType mPath; - boost::filesystem::path mUserConfigPath; /**< User path */ - boost::filesystem::path mUserDataPath; - boost::filesystem::path mGlobalConfigPath; /**< Global path */ - boost::filesystem::path mLocalPath; /**< It is the same directory where application was run */ + std::filesystem::path mUserConfigPath; /**< User path */ + std::filesystem::path mUserDataPath; + std::filesystem::path mGlobalConfigPath; /**< Global path */ + std::filesystem::path mLocalPath; /**< It is the same directory where application was run */ - boost::filesystem::path mGlobalDataPath; /**< Global application data path */ + std::filesystem::path mGlobalDataPath; /**< Global application data path */ - boost::filesystem::path mCachePath; + std::filesystem::path mCachePath; - boost::filesystem::path mInstallPath; + std::filesystem::path mInstallPath; }; diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index da3bfeac77..b6833fd025 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -4,14 +4,15 @@ #include #include -#include +#include +#include #include #include namespace { - boost::filesystem::path getUserHome() + std::filesystem::path getUserHome() { const char* dir = getenv("HOME"); if (dir == nullptr) @@ -23,17 +24,17 @@ namespace } } if (dir == nullptr) - return boost::filesystem::path(); + return std::filesystem::path(); else - return boost::filesystem::path(dir); + return std::filesystem::path(dir); } - boost::filesystem::path getEnv(const std::string& envVariable, const boost::filesystem::path& fallback) + std::filesystem::path getEnv(const std::string& envVariable, const std::filesystem::path& fallback) { const char* result = getenv(envVariable.c_str()); if (!result) return fallback; - boost::filesystem::path dir(result); + std::filesystem::path dir(result); if (dir.empty()) return fallback; else @@ -50,44 +51,44 @@ namespace Files LinuxPath::LinuxPath(const std::string& application_name) : mName(application_name) { - boost::filesystem::path localPath = getLocalPath(); + std::filesystem::path localPath = getLocalPath(); if (chdir(localPath.string().c_str()) != 0) Log(Debug::Warning) << "Error " << errno << " when changing current directory"; } -boost::filesystem::path LinuxPath::getUserConfigPath() const +std::filesystem::path LinuxPath::getUserConfigPath() const { return getEnv("XDG_CONFIG_HOME", getUserHome() / ".config") / mName; } -boost::filesystem::path LinuxPath::getUserDataPath() const +std::filesystem::path LinuxPath::getUserDataPath() const { return getEnv("XDG_DATA_HOME", getUserHome() / ".local/share") / mName; } -boost::filesystem::path LinuxPath::getCachePath() const +std::filesystem::path LinuxPath::getCachePath() const { return getEnv("XDG_CACHE_HOME", getUserHome() / ".cache") / mName; } -boost::filesystem::path LinuxPath::getGlobalConfigPath() const +std::filesystem::path LinuxPath::getGlobalConfigPath() const { - boost::filesystem::path globalPath(GLOBAL_CONFIG_PATH); + std::filesystem::path globalPath(GLOBAL_CONFIG_PATH); return globalPath / mName; } -boost::filesystem::path LinuxPath::getLocalPath() const +std::filesystem::path LinuxPath::getLocalPath() const { - boost::filesystem::path localPath("./"); + std::filesystem::path localPath("./"); const char *statusPaths[] = {"/proc/self/exe", "/proc/self/file", "/proc/curproc/exe", "/proc/curproc/file"}; for(const char *path : statusPaths) { - boost::filesystem::path statusPath(path); - if (!boost::filesystem::exists(statusPath)) continue; + std::filesystem::path statusPath(path); + if (!std::filesystem::exists(statusPath)) continue; - statusPath = boost::filesystem::read_symlink(statusPath); - if (!boost::filesystem::is_empty(statusPath)) + statusPath = std::filesystem::read_symlink(statusPath); + if (!std::filesystem::is_empty(statusPath)) { localPath = statusPath.parent_path() / "/"; break; @@ -97,26 +98,26 @@ boost::filesystem::path LinuxPath::getLocalPath() const return localPath; } -boost::filesystem::path LinuxPath::getGlobalDataPath() const +std::filesystem::path LinuxPath::getGlobalDataPath() const { - boost::filesystem::path globalDataPath(GLOBAL_DATA_PATH); + std::filesystem::path globalDataPath(GLOBAL_DATA_PATH); return globalDataPath / mName; } -boost::filesystem::path LinuxPath::getInstallPath() const +std::filesystem::path LinuxPath::getInstallPath() const { - boost::filesystem::path installPath; + std::filesystem::path installPath; - boost::filesystem::path homePath = getUserHome(); + std::filesystem::path homePath = getUserHome(); if (!homePath.empty()) { - boost::filesystem::path wineDefaultRegistry(homePath); + std::filesystem::path wineDefaultRegistry(homePath); wineDefaultRegistry /= ".wine/system.reg"; - if (boost::filesystem::is_regular_file(wineDefaultRegistry)) + if (std::filesystem::is_regular_file(wineDefaultRegistry)) { - boost::filesystem::ifstream file(wineDefaultRegistry); + std::ifstream file(wineDefaultRegistry); bool isRegEntry = false; std::string line; std::string mwpath; @@ -163,7 +164,7 @@ boost::filesystem::path LinuxPath::getInstallPath() const installPath /= ".wine/dosdevices/"; installPath /= mwpath; - if (!boost::filesystem::is_directory(installPath)) + if (!std::filesystem::is_directory(installPath)) { installPath.clear(); } diff --git a/components/files/linuxpath.hpp b/components/files/linuxpath.hpp index 7950157bbb..e3f99af3fd 100644 --- a/components/files/linuxpath.hpp +++ b/components/files/linuxpath.hpp @@ -3,7 +3,7 @@ #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) -#include +#include /** * \namespace Files @@ -21,35 +21,35 @@ struct LinuxPath /** * \brief Return path to the user directory. */ - boost::filesystem::path getUserConfigPath() const; + std::filesystem::path getUserConfigPath() const; - boost::filesystem::path getUserDataPath() const; + std::filesystem::path getUserDataPath() const; /** * \brief Return path to the global (system) directory where config files can be placed. */ - boost::filesystem::path getGlobalConfigPath() const; + std::filesystem::path getGlobalConfigPath() const; /** * \brief Return path to the runtime configuration directory which is the * place where an application was started. */ - boost::filesystem::path getLocalPath() const; + std::filesystem::path getLocalPath() const; /** * \brief Return path to the global (system) directory where game files can be placed. */ - boost::filesystem::path getGlobalDataPath() const; + std::filesystem::path getGlobalDataPath() const; /** * \brief */ - boost::filesystem::path getCachePath() const; + std::filesystem::path getCachePath() const; /** * \brief Gets the path of the installed Morrowind version if there is one. */ - boost::filesystem::path getInstallPath() const; + std::filesystem::path getInstallPath() const; std::string mName; }; diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index eccaf2f2f8..c0505dbea0 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -5,13 +5,13 @@ #include #include #include -#include +#include #include namespace { - boost::filesystem::path getUserHome() + std::filesystem::path getUserHome() { const char* dir = getenv("HOME"); if (dir == nullptr) @@ -23,9 +23,9 @@ namespace } } if (dir == nullptr) - return boost::filesystem::path(); + return std::filesystem::path(); else - return boost::filesystem::path(dir); + return std::filesystem::path(dir); } } @@ -37,60 +37,60 @@ MacOsPath::MacOsPath(const std::string& application_name) { } -boost::filesystem::path MacOsPath::getUserConfigPath() const +std::filesystem::path MacOsPath::getUserConfigPath() const { - boost::filesystem::path userPath (getUserHome()); + std::filesystem::path userPath (getUserHome()); userPath /= "Library/Preferences/"; return userPath / mName; } -boost::filesystem::path MacOsPath::getUserDataPath() const +std::filesystem::path MacOsPath::getUserDataPath() const { - boost::filesystem::path userPath (getUserHome()); + std::filesystem::path userPath (getUserHome()); userPath /= "Library/Application Support/"; return userPath / mName; } -boost::filesystem::path MacOsPath::getGlobalConfigPath() const +std::filesystem::path MacOsPath::getGlobalConfigPath() const { - boost::filesystem::path globalPath("/Library/Preferences/"); + std::filesystem::path globalPath("/Library/Preferences/"); return globalPath / mName; } -boost::filesystem::path MacOsPath::getCachePath() const +std::filesystem::path MacOsPath::getCachePath() const { - boost::filesystem::path userPath (getUserHome()); + std::filesystem::path userPath (getUserHome()); userPath /= "Library/Caches"; return userPath / mName; } -boost::filesystem::path MacOsPath::getLocalPath() const +std::filesystem::path MacOsPath::getLocalPath() const { - return boost::filesystem::path("../Resources/"); + return std::filesystem::path("../Resources/"); } -boost::filesystem::path MacOsPath::getGlobalDataPath() const +std::filesystem::path MacOsPath::getGlobalDataPath() const { - boost::filesystem::path globalDataPath("/Library/Application Support/"); + std::filesystem::path globalDataPath("/Library/Application Support/"); return globalDataPath / mName; } -boost::filesystem::path MacOsPath::getInstallPath() const +std::filesystem::path MacOsPath::getInstallPath() const { - boost::filesystem::path installPath; + std::filesystem::path installPath; - boost::filesystem::path homePath = getUserHome(); + std::filesystem::path homePath = getUserHome(); if (!homePath.empty()) { - boost::filesystem::path wineDefaultRegistry(homePath); + std::filesystem::path wineDefaultRegistry(homePath); wineDefaultRegistry /= ".wine/system.reg"; - if (boost::filesystem::is_regular_file(wineDefaultRegistry)) + if (std::filesystem::is_regular_file(wineDefaultRegistry)) { - boost::filesystem::ifstream file(wineDefaultRegistry); + std::filesystem::ifstream file(wineDefaultRegistry); bool isRegEntry = false; std::string line; std::string mwpath; @@ -136,7 +136,7 @@ boost::filesystem::path MacOsPath::getInstallPath() const installPath /= ".wine/dosdevices/"; installPath /= mwpath; - if (!boost::filesystem::is_directory(installPath)) + if (!std::filesystem::is_directory(installPath)) { installPath.clear(); } diff --git a/components/files/macospath.hpp b/components/files/macospath.hpp index 7a7dc55778..12c7fd66bc 100644 --- a/components/files/macospath.hpp +++ b/components/files/macospath.hpp @@ -3,7 +3,7 @@ #if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__) -#include +#include /** * \namespace Files @@ -21,42 +21,42 @@ struct MacOsPath /** * \brief Return path to the local directory. * - * \return boost::filesystem::path + * \return std::filesystem::path */ - boost::filesystem::path getUserConfigPath() const; + std::filesystem::path getUserConfigPath() const; - boost::filesystem::path getUserDataPath() const; + std::filesystem::path getUserDataPath() const; /** * \brief Return path to the global (system) directory. * - * \return boost::filesystem::path + * \return std::filesystem::path */ - boost::filesystem::path getGlobalConfigPath() const; + std::filesystem::path getGlobalConfigPath() const; /** * \brief Return path to the runtime directory which is the * place where an application was started. * - * \return boost::filesystem::path + * \return std::filesystem::path */ - boost::filesystem::path getLocalPath() const; + std::filesystem::path getLocalPath() const; /** * \brief * - * \return boost::filesystem::path + * \return std::filesystem::path */ - boost::filesystem::path getCachePath() const; + std::filesystem::path getCachePath() const; /** * \brief * - * \return boost::filesystem::path + * \return std::filesystem::path */ - boost::filesystem::path getGlobalDataPath() const; + std::filesystem::path getGlobalDataPath() const; - boost::filesystem::path getInstallPath() const; + std::filesystem::path getInstallPath() const; std::string mName; }; diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index a052b3016e..50cddcdecf 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -1,6 +1,6 @@ #include "multidircollection.hpp" -#include +#include #include @@ -26,19 +26,18 @@ namespace Files { NameEqual equal (!foldCase); - for (PathContainer::const_iterator iter = directories.begin(); - iter!=directories.end(); ++iter) + for (const auto & directory : directories) { - if (!boost::filesystem::is_directory(*iter)) + if (!std::filesystem::is_directory(directory)) { - Log(Debug::Info) << "Skipping invalid directory: " << (*iter).string(); + Log(Debug::Info) << "Skipping invalid directory: " << directory.string(); continue; } - for (boost::filesystem::directory_iterator dirIter(*iter); - dirIter != boost::filesystem::directory_iterator(); ++dirIter) + for (std::filesystem::directory_iterator dirIter(directory); + dirIter != std::filesystem::directory_iterator(); ++dirIter) { - boost::filesystem::path path = *dirIter; + std::filesystem::path path = *dirIter; if (!equal (extension, path.extension().string())) continue; @@ -65,7 +64,7 @@ namespace Files } } - boost::filesystem::path MultiDirCollection::getPath (const std::string& file) const + std::filesystem::path MultiDirCollection::getPath (const std::string& file) const { TIter iter = mFiles.find (file); diff --git a/components/files/multidircollection.hpp b/components/files/multidircollection.hpp index 7e8884eec0..a89801f573 100644 --- a/components/files/multidircollection.hpp +++ b/components/files/multidircollection.hpp @@ -5,14 +5,13 @@ #include #include #include - -#include +#include #include namespace Files { - typedef std::vector PathContainer; + typedef std::vector PathContainer; struct NameLess { @@ -37,7 +36,7 @@ namespace Files { public: - typedef std::map TContainer; + typedef std::map TContainer; typedef TContainer::const_iterator TIter; private: @@ -53,7 +52,7 @@ namespace Files /// contain the leading dot. /// \param foldCase Ignore filename case - boost::filesystem::path getPath (const std::string& file) const; + std::filesystem::path getPath (const std::string& file) const; ///< Return full path (including filename) of \a file. /// /// If the file does not exist, an exception is thrown. \a file must include diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index d29a275d5f..1daf77a1e5 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -38,79 +38,79 @@ WindowsPath::WindowsPath(const std::string& application_name) with UTF-8 encoding (generated for empty name from boost::locale) to handle Unicode in platform-agnostic way using std::string. - See boost::filesystem and boost::locale reference for details. + See std::filesystem and boost::locale reference for details. */ - boost::filesystem::path::imbue(boost::locale::generator().generate("")); + std::filesystem::path::imbue(boost::locale::generator().generate("")); - boost::filesystem::path localPath = getLocalPath(); + std::filesystem::path localPath = getLocalPath(); if (!SetCurrentDirectoryA(localPath.string().c_str())) Log(Debug::Warning) << "Error " << GetLastError() << " when changing current directory"; } -boost::filesystem::path WindowsPath::getUserConfigPath() const +std::filesystem::path WindowsPath::getUserConfigPath() const { - boost::filesystem::path userPath("."); + std::filesystem::path userPath("."); WCHAR path[MAX_PATH + 1]; memset(path, 0, sizeof(path)); if(SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, nullptr, 0, path))) { - userPath = boost::filesystem::path(bconv::utf_to_utf(path)); + userPath = std::filesystem::path(bconv::utf_to_utf(path)); } return userPath / "My Games" / mName; } -boost::filesystem::path WindowsPath::getUserDataPath() const +std::filesystem::path WindowsPath::getUserDataPath() const { // Have some chaos, windows people! return getUserConfigPath(); } -boost::filesystem::path WindowsPath::getGlobalConfigPath() const +std::filesystem::path WindowsPath::getGlobalConfigPath() const { - boost::filesystem::path globalPath("."); + std::filesystem::path globalPath("."); WCHAR path[MAX_PATH + 1]; memset(path, 0, sizeof(path)); if(SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PROGRAM_FILES | CSIDL_FLAG_CREATE, nullptr, 0, path))) { - globalPath = boost::filesystem::path(bconv::utf_to_utf(path)); + globalPath = std::filesystem::path(bconv::utf_to_utf(path)); } return globalPath / mName; } -boost::filesystem::path WindowsPath::getLocalPath() const +std::filesystem::path WindowsPath::getLocalPath() const { - boost::filesystem::path localPath("./"); + std::filesystem::path localPath("./"); WCHAR path[MAX_PATH + 1]; memset(path, 0, sizeof(path)); if (GetModuleFileNameW(nullptr, path, MAX_PATH + 1) > 0) { - localPath = boost::filesystem::path(bconv::utf_to_utf(path)).parent_path() / "/"; + localPath = std::filesystem::path(bconv::utf_to_utf(path)).parent_path() / "/"; } // lookup exe path return localPath; } -boost::filesystem::path WindowsPath::getGlobalDataPath() const +std::filesystem::path WindowsPath::getGlobalDataPath() const { return getGlobalConfigPath(); } -boost::filesystem::path WindowsPath::getCachePath() const +std::filesystem::path WindowsPath::getCachePath() const { return getUserConfigPath() / "cache"; } -boost::filesystem::path WindowsPath::getInstallPath() const +std::filesystem::path WindowsPath::getInstallPath() const { - boost::filesystem::path installPath(""); + std::filesystem::path installPath(""); HKEY hKey; diff --git a/components/files/windowspath.hpp b/components/files/windowspath.hpp index 31d0e0e7c1..4fd579b0b9 100644 --- a/components/files/windowspath.hpp +++ b/components/files/windowspath.hpp @@ -3,7 +3,7 @@ #if defined(_WIN32) || defined(__WINDOWS__) -#include +#include /** * \namespace Files @@ -27,47 +27,47 @@ struct WindowsPath * \brief Returns user path i.e.: * "X:\Documents And Settings\\My Documents\My Games\" * - * \return boost::filesystem::path + * \return std::filesystem::path */ - boost::filesystem::path getUserConfigPath() const; + std::filesystem::path getUserConfigPath() const; - boost::filesystem::path getUserDataPath() const; + std::filesystem::path getUserDataPath() const; /** * \brief Returns "X:\Program Files\" * - * \return boost::filesystem::path + * \return std::filesystem::path */ - boost::filesystem::path getGlobalConfigPath() const; + std::filesystem::path getGlobalConfigPath() const; /** * \brief Return local path which is a location where * an application was started * - * \return boost::filesystem::path + * \return std::filesystem::path */ - boost::filesystem::path getLocalPath() const; + std::filesystem::path getLocalPath() const; /** * \brief * - * \return boost::filesystem::path + * \return std::filesystem::path */ - boost::filesystem::path getCachePath() const; + std::filesystem::path getCachePath() const; /** * \brief Return same path like getGlobalPath * - * \return boost::filesystem::path + * \return std::filesystem::path */ - boost::filesystem::path getGlobalDataPath() const; + std::filesystem::path getGlobalDataPath() const; /** * \brief Gets the path of the installed Morrowind version if there is one. * - * \return boost::filesystem::path + * \return std::filesystem::path */ - boost::filesystem::path getInstallPath() const; + std::filesystem::path getInstallPath() const; std::string mName; }; diff --git a/components/misc/timeconvert.hpp b/components/misc/timeconvert.hpp new file mode 100644 index 0000000000..dd6f542a44 --- /dev/null +++ b/components/misc/timeconvert.hpp @@ -0,0 +1,17 @@ +#ifndef OPENMW_COMPONENTS_MISC_TIMECONVERT_H +#define OPENMW_COMPONENTS_MISC_TIMECONVERT_H + +namespace Misc +{ +// Very ugly hack to go from std::chrono::file_clock to any other clock, can be replaced with better solution in C++20 +// https://stackoverflow.com/questions/35282308/convert-between-c11-clocks +template +inline DstTimePointT clockCast (const SrcTimePointT tp) +{ + const auto src_now = SrcClockT::now(); + const auto dst_now = DstClockT::now(); + return dst_now + (tp - src_now); +} +} // namespace Misc + +#endif diff --git a/components/myguiplatform/myguiloglistener.cpp b/components/myguiplatform/myguiloglistener.cpp index 74b4b30813..ab5537b6b2 100644 --- a/components/myguiplatform/myguiloglistener.cpp +++ b/components/myguiplatform/myguiloglistener.cpp @@ -8,7 +8,7 @@ namespace osgMyGUI { void CustomLogListener::open() { - mStream.open(boost::filesystem::path(mFileName), std::ios_base::out); + mStream.open(std::filesystem::path(mFileName), std::ios_base::out); if (!mStream.is_open()) Log(Debug::Error) << "Unable to create MyGUI log with path " << mFileName; } diff --git a/components/myguiplatform/myguiloglistener.hpp b/components/myguiplatform/myguiloglistener.hpp index 4bab20ac97..c22b5afb02 100644 --- a/components/myguiplatform/myguiloglistener.hpp +++ b/components/myguiplatform/myguiloglistener.hpp @@ -2,7 +2,8 @@ #define OPENMW_COMPONENTS_MYGUIPLATFORM_LOGLISTENER_H #include -#include +#include +#include #include #include @@ -33,7 +34,7 @@ namespace osgMyGUI const std::string& getFileName() const { return mFileName; } private: - boost::filesystem::ofstream mStream; + std::ofstream mStream; std::string mFileName; }; diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index d77f814468..cd4016900b 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -24,7 +24,7 @@ void Manager::clear() std::string Manager::load(const Files::ConfigurationManager& cfgMgr, bool loadEditorSettings) { SettingsFileParser parser; - const std::vector& paths = cfgMgr.getActiveConfigPaths(); + const std::vector& paths = cfgMgr.getActiveConfigPaths(); if (paths.empty()) throw std::runtime_error("No config dirs! ConfigurationManager::readConfiguration must be called first."); diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp index 25ee9e1f62..80f4561136 100644 --- a/components/vfs/registerarchives.cpp +++ b/components/vfs/registerarchives.cpp @@ -40,17 +40,16 @@ namespace VFS if (useLooseFiles) { std::set seen; - for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) + for (const auto &dataDir : dataDirs) { - // TODO(jvoisin) Get rid of `->native()` when we move PathContainer from boost::filesystem to std::filesystem. - if (seen.insert(iter->native()).second) + if (seen.insert(dataDir).second) { - Log(Debug::Info) << "Adding data directory " << iter->string(); + Log(Debug::Info) << "Adding data directory " << dataDir; // Last data dir has the highest priority - vfs->addArchive(std::make_unique(iter->string())); + vfs->addArchive(std::make_unique(dataDir)); } else - Log(Debug::Info) << "Ignoring duplicate data directory " << iter->string(); + Log(Debug::Info) << "Ignoring duplicate data directory " << dataDir; } } From cd229a965b928156192eb14b336db4e8103ec365 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 11 Jun 2022 14:38:59 +0200 Subject: [PATCH 09/36] Fixed windows build and updated tests to reflect changes of escape character from "&" to "\" --- apps/mwiniimporter/main.cpp | 3 ++- apps/openmw_test_suite/openmw/options.cpp | 26 +++++++++++------------ components/files/windowspath.cpp | 5 +++-- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index 4bab5d8c03..1d4b6b588e 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -52,7 +52,8 @@ private: int wmain(int argc, wchar_t *wargv[]) { utf8argv converter(argc, wargv); char **argv = converter.get(); - std::filesystem::path::imbue(boost::locale::generator().generate("")); + // TODO(Project579): Temporarly disabled until a good solution is found (no solution might actually be needed) + //std::filesystem::path::imbue(boost::locale::generator().generate("")); #endif try diff --git a/apps/openmw_test_suite/openmw/options.cpp b/apps/openmw_test_suite/openmw/options.cpp index 33c38da5df..dacf9c81f3 100644 --- a/apps/openmw_test_suite/openmw/options.cpp +++ b/apps/openmw_test_suite/openmw/options.cpp @@ -33,7 +33,7 @@ namespace std::vector result; (result.emplace_back(makeString(args)) , ...); for (int i = 1; i <= std::numeric_limits::max(); ++i) - if (i != '&' && i != '"' && i != ' ' && i != '\n') + if (i != '\\' && i != '"' && i != ' ' && i != '\n') result.push_back(std::string(1, i)); return result; } @@ -127,22 +127,22 @@ namespace EXPECT_EQ(variables["load-savegame"].as().string(), R"(save)"); } - TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_quote_by_ampersand) + TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_quote) { bpo::options_description description = makeOptionsDescription(); - const std::array arguments {"openmw", "--load-savegame", R"("save&".omwsave")"}; + const std::array arguments {"openmw", "--load-savegame", R"("save\".omwsave")"}; bpo::variables_map variables; parseArgs(arguments, variables, description); EXPECT_EQ(variables["load-savegame"].as().string(), R"(save".omwsave)"); } - TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_ampersand) + TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_backslash) { bpo::options_description description = makeOptionsDescription(); - const std::array arguments {"openmw", "--load-savegame", R"("save.omwsave&&")"}; + const std::array arguments {"openmw", "--load-savegame", R"("save.omwsave\\")"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save.omwsave&"); + EXPECT_EQ(variables["load-savegame"].as().string(), R"(save.omwsave\)"); } TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_ampersand) @@ -274,7 +274,7 @@ namespace TEST(OpenMWOptionsFromConfig, should_support_confusing_savegame_path_with_lots_going_on) { bpo::options_description description = makeOptionsDescription(); - std::istringstream stream(R"(load-savegame="one &"two"three".omwsave")"); + std::istringstream stream(R"(load-savegame="one \"two"three".omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); EXPECT_EQ(variables["load-savegame"].as().string(), R"(one "two)"); @@ -283,7 +283,7 @@ namespace TEST(OpenMWOptionsFromConfig, should_support_confusing_savegame_path_with_even_more_going_on) { bpo::options_description description = makeOptionsDescription(); - std::istringstream stream(R"(load-savegame="one &"two"three ".omwsave")"); + std::istringstream stream(R"(load-savegame="one \"two"three ".omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); EXPECT_EQ(variables["load-savegame"].as().string(), R"(one "two)"); @@ -351,22 +351,22 @@ namespace EXPECT_THAT(variables["data"].as(), ElementsAre(IsPath("1"), IsPath("2"))); } - TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_escaped_quote_by_ampersand) + TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_escaped_quote) { bpo::options_description description = makeOptionsDescription(); - std::istringstream stream(R"(load-savegame="save&".omwsave")"); + std::istringstream stream(R"(load-savegame="save\".omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); EXPECT_EQ(variables["load-savegame"].as().string(), R"(save".omwsave)"); } - TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_escaped_ampersand) + TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_escaped_backslash) { bpo::options_description description = makeOptionsDescription(); - std::istringstream stream(R"(load-savegame="save.omwsave&&")"); + std::istringstream stream(R"(load-savegame="save.omwsave\\")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save.omwsave&"); + EXPECT_EQ(variables["load-savegame"].as().string(), R"(save.omwsave\)"); } TEST(OpenMWOptionsFromConfig, should_support_load_savegame_path_with_ampersand) diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index 1daf77a1e5..1222c2e5cb 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -40,7 +40,8 @@ WindowsPath::WindowsPath(const std::string& application_name) See std::filesystem and boost::locale reference for details. */ - std::filesystem::path::imbue(boost::locale::generator().generate("")); + // TODO(Project579): Temporarly disabled until a good solution is found (no solution might actually be needed) + //std::filesystem::path::imbue(boost::locale::generator().generate("")); std::filesystem::path localPath = getLocalPath(); if (!SetCurrentDirectoryA(localPath.string().c_str())) @@ -91,7 +92,7 @@ std::filesystem::path WindowsPath::getLocalPath() const if (GetModuleFileNameW(nullptr, path, MAX_PATH + 1) > 0) { - localPath = std::filesystem::path(bconv::utf_to_utf(path)).parent_path() / "/"; + localPath = std::filesystem::path(bconv::utf_to_utf(path)).parent_path().string() + "/"; } // lookup exe path From e97eeca28136813b0f1944933b13908484a751a8 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 11 Jun 2022 17:14:32 +0200 Subject: [PATCH 10/36] Attempt to work around QT MOC bugs caused by the filesystem header. --- apps/opencs/editor.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 21fe7df7f1..26f45744c6 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -1,7 +1,6 @@ #ifndef CS_EDITOR_H #define CS_EDITOR_H -#include #include #include From cf0af87c80aa774490401f0079e85662f7c5244c Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 11 Jun 2022 19:15:24 +0200 Subject: [PATCH 11/36] Revert changes from "4c8e1ccf - Fixed windows build and updated tests to reflect changes of escape character from "&" to "\"" in "apps/openmw_test_suite/openmw/options.cpp" --- apps/openmw_test_suite/openmw/options.cpp | 26 +++++++++++------------ components/files/configurationmanager.cpp | 4 +++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/apps/openmw_test_suite/openmw/options.cpp b/apps/openmw_test_suite/openmw/options.cpp index dacf9c81f3..33c38da5df 100644 --- a/apps/openmw_test_suite/openmw/options.cpp +++ b/apps/openmw_test_suite/openmw/options.cpp @@ -33,7 +33,7 @@ namespace std::vector result; (result.emplace_back(makeString(args)) , ...); for (int i = 1; i <= std::numeric_limits::max(); ++i) - if (i != '\\' && i != '"' && i != ' ' && i != '\n') + if (i != '&' && i != '"' && i != ' ' && i != '\n') result.push_back(std::string(1, i)); return result; } @@ -127,22 +127,22 @@ namespace EXPECT_EQ(variables["load-savegame"].as().string(), R"(save)"); } - TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_quote) + TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_quote_by_ampersand) { bpo::options_description description = makeOptionsDescription(); - const std::array arguments {"openmw", "--load-savegame", R"("save\".omwsave")"}; + const std::array arguments {"openmw", "--load-savegame", R"("save&".omwsave")"}; bpo::variables_map variables; parseArgs(arguments, variables, description); EXPECT_EQ(variables["load-savegame"].as().string(), R"(save".omwsave)"); } - TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_backslash) + TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_ampersand) { bpo::options_description description = makeOptionsDescription(); - const std::array arguments {"openmw", "--load-savegame", R"("save.omwsave\\")"}; + const std::array arguments {"openmw", "--load-savegame", R"("save.omwsave&&")"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(save.omwsave\)"); + EXPECT_EQ(variables["load-savegame"].as().string(), "save.omwsave&"); } TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_ampersand) @@ -274,7 +274,7 @@ namespace TEST(OpenMWOptionsFromConfig, should_support_confusing_savegame_path_with_lots_going_on) { bpo::options_description description = makeOptionsDescription(); - std::istringstream stream(R"(load-savegame="one \"two"three".omwsave")"); + std::istringstream stream(R"(load-savegame="one &"two"three".omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); EXPECT_EQ(variables["load-savegame"].as().string(), R"(one "two)"); @@ -283,7 +283,7 @@ namespace TEST(OpenMWOptionsFromConfig, should_support_confusing_savegame_path_with_even_more_going_on) { bpo::options_description description = makeOptionsDescription(); - std::istringstream stream(R"(load-savegame="one \"two"three ".omwsave")"); + std::istringstream stream(R"(load-savegame="one &"two"three ".omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); EXPECT_EQ(variables["load-savegame"].as().string(), R"(one "two)"); @@ -351,22 +351,22 @@ namespace EXPECT_THAT(variables["data"].as(), ElementsAre(IsPath("1"), IsPath("2"))); } - TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_escaped_quote) + TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_escaped_quote_by_ampersand) { bpo::options_description description = makeOptionsDescription(); - std::istringstream stream(R"(load-savegame="save\".omwsave")"); + std::istringstream stream(R"(load-savegame="save&".omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); EXPECT_EQ(variables["load-savegame"].as().string(), R"(save".omwsave)"); } - TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_escaped_backslash) + TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_escaped_ampersand) { bpo::options_description description = makeOptionsDescription(); - std::istringstream stream(R"(load-savegame="save.omwsave\\")"); + std::istringstream stream(R"(load-savegame="save.omwsave&&")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(save.omwsave\)"); + EXPECT_EQ(variables["load-savegame"].as().string(), "save.omwsave&"); } TEST(OpenMWOptionsFromConfig, should_support_load_savegame_path_with_ampersand) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index f792af5f3d..37eca2c460 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -432,7 +432,9 @@ std::istream& operator>> (std::istream& istream, MaybeQuotedPath& MaybeQuotedPat // If it doesn't start with a double quote, read the whole thing verbatim if (istream.peek() == '"') { - istream >> static_cast(MaybeQuotedPath); + std::string intermediate; + istream >> std::quoted(intermediate, '"', '&'); + static_cast(MaybeQuotedPath) = intermediate; if (istream && !istream.eof() && istream.peek() != EOF) { std::string remainder{std::istreambuf_iterator(istream), {}}; From 5446571aec0f16997de054c17b58323b3f527bd6 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 11 Jun 2022 19:23:44 +0200 Subject: [PATCH 12/36] Circumvent QT MOC bugs by including the filesystem header in a specific order. --- apps/opencs/model/doc/document.hpp | 1 - apps/opencs/model/doc/documentmanager.hpp | 1 - apps/opencs/model/doc/runner.hpp | 3 ++- apps/opencs/model/doc/saving.hpp | 2 -- apps/opencs/model/tools/tools.hpp | 1 - apps/opencs/model/world/data.hpp | 1 - apps/opencs/view/doc/adjusterwidget.hpp | 3 ++- apps/opencs/view/doc/filedialog.hpp | 1 - apps/opencs/view/doc/newgame.hpp | 4 ++-- components/config/gamesettings.hpp | 4 ++-- 10 files changed, 8 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index b88e606d48..a012a7dc5a 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -2,7 +2,6 @@ #define CSM_DOC_DOCUMENT_H #include -#include #include #include diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 3a69618e74..4dd5c550bb 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -3,7 +3,6 @@ #include #include -#include #include #include diff --git a/apps/opencs/model/doc/runner.hpp b/apps/opencs/model/doc/runner.hpp index 526507f1ee..fcc12d2f0e 100644 --- a/apps/opencs/model/doc/runner.hpp +++ b/apps/opencs/model/doc/runner.hpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -11,6 +10,8 @@ #include +#include + class QTemporaryFile; namespace CSMDoc diff --git a/apps/opencs/model/doc/saving.hpp b/apps/opencs/model/doc/saving.hpp index 88d080f0cc..0ec68dd942 100644 --- a/apps/opencs/model/doc/saving.hpp +++ b/apps/opencs/model/doc/saving.hpp @@ -1,8 +1,6 @@ #ifndef CSM_DOC_SAVING_H #define CSM_DOC_SAVING_H -#include - #include #include "operation.hpp" diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 29ea982f6e..93ab9b174d 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -3,7 +3,6 @@ #include #include -#include #include diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 35c6159cfe..2764daa8aa 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -3,7 +3,6 @@ #include #include -#include #include #include diff --git a/apps/opencs/view/doc/adjusterwidget.hpp b/apps/opencs/view/doc/adjusterwidget.hpp index 1a6f2c477b..7e6330a652 100644 --- a/apps/opencs/view/doc/adjusterwidget.hpp +++ b/apps/opencs/view/doc/adjusterwidget.hpp @@ -1,10 +1,11 @@ #ifndef CSV_DOC_ADJUSTERWIDGET_H #define CSV_DOC_ADJUSTERWIDGET_H -#include #include +#include + class QLabel; namespace CSVDoc diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp index 69ba77b466..4e4113a178 100644 --- a/apps/opencs/view/doc/filedialog.hpp +++ b/apps/opencs/view/doc/filedialog.hpp @@ -6,7 +6,6 @@ #ifndef Q_MOC_RUN -#include #include "adjusterwidget.hpp" #ifndef CS_QT_BOOST_FILESYSTEM_PATH_DECLARED diff --git a/apps/opencs/view/doc/newgame.hpp b/apps/opencs/view/doc/newgame.hpp index afe0f78e33..12b2f3eefe 100644 --- a/apps/opencs/view/doc/newgame.hpp +++ b/apps/opencs/view/doc/newgame.hpp @@ -1,11 +1,11 @@ #ifndef CSV_DOC_NEWGAME_H #define CSV_DOC_NEWGAME_H -#include - #include #include +#include + #ifndef CS_QT_BOOST_FILESYSTEM_PATH_DECLARED #define CS_QT_BOOST_FILESYSTEM_PATH_DECLARED Q_DECLARE_METATYPE (std::filesystem::path) diff --git a/components/config/gamesettings.hpp b/components/config/gamesettings.hpp index 89b958bd47..961af7657b 100644 --- a/components/config/gamesettings.hpp +++ b/components/config/gamesettings.hpp @@ -1,14 +1,14 @@ #ifndef GAMESETTINGS_HPP #define GAMESETTINGS_HPP -#include - #include #include #include #include #include +#include + namespace Files { typedef std::vector PathContainer; From 35fe214588589151c861777489efc817dd4e5097 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 11 Jun 2022 23:38:09 +0200 Subject: [PATCH 13/36] Updated components/misc/timeconvert.hpp to fix the Android build. --- apps/mwiniimporter/importer.cpp | 3 ++- apps/mwiniimporter/main.cpp | 4 ++-- apps/opencs/view/doc/filedialog.hpp | 4 ++-- apps/opencs/view/doc/newgame.hpp | 4 ++-- apps/opencs/view/tools/merge.hpp | 2 -- apps/openmw/mwgui/savegamedialog.cpp | 3 ++- apps/openmw/mwstate/character.cpp | 7 +++---- apps/openmw/mwstate/character.hpp | 2 +- components/config/gamesettings.cpp | 2 +- components/files/configurationmanager.cpp | 2 +- components/files/windowspath.cpp | 6 +++--- components/misc/timeconvert.hpp | 15 ++++++++------- 12 files changed, 27 insertions(+), 27 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index c4377fc0ac..305587162b 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -7,6 +7,7 @@ #include #include #include +#include @@ -990,7 +991,7 @@ std::time_t MwIniImporter::lastWriteTime(const std::filesystem::path& filename, if (std::filesystem::exists(filename)) { std::filesystem::path resolved = std::filesystem::canonical(filename); - writeTime = std::chrono::system_clock::to_time_t (Misc::clockCast (std::filesystem::last_write_time (resolved)));; + writeTime = Misc::to_time_t(std::filesystem::last_write_time (resolved)); // print timestamp const int size=1024; diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index 1d4b6b588e..d6afecb1ef 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -47,13 +47,13 @@ private: OpenMW application stack assumes UTF-8 encoding, therefore this conversion. - For std::filesystem::path::imbue see components/files/windowspath.cpp + For boost::filesystem::path::imbue see components/files/windowspath.cpp */ int wmain(int argc, wchar_t *wargv[]) { utf8argv converter(argc, wargv); char **argv = converter.get(); // TODO(Project579): Temporarly disabled until a good solution is found (no solution might actually be needed) - //std::filesystem::path::imbue(boost::locale::generator().generate("")); + //boost::filesystem::path::imbue(boost::locale::generator().generate("")); #endif try diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp index 4e4113a178..154efc14ea 100644 --- a/apps/opencs/view/doc/filedialog.hpp +++ b/apps/opencs/view/doc/filedialog.hpp @@ -8,8 +8,8 @@ #include "adjusterwidget.hpp" -#ifndef CS_QT_BOOST_FILESYSTEM_PATH_DECLARED -#define CS_QT_BOOST_FILESYSTEM_PATH_DECLARED +#ifndef CS_QT_STD_FILESYSTEM_PATH_DECLARED +#define CS_QT_STD_FILESYSTEM_PATH_DECLARED Q_DECLARE_METATYPE (std::filesystem::path) #endif diff --git a/apps/opencs/view/doc/newgame.hpp b/apps/opencs/view/doc/newgame.hpp index 12b2f3eefe..f5eace0671 100644 --- a/apps/opencs/view/doc/newgame.hpp +++ b/apps/opencs/view/doc/newgame.hpp @@ -6,8 +6,8 @@ #include -#ifndef CS_QT_BOOST_FILESYSTEM_PATH_DECLARED -#define CS_QT_BOOST_FILESYSTEM_PATH_DECLARED +#ifndef CS_QT_STD_FILESYSTEM_PATH_DECLARED +#define CS_QT_STD_FILESYSTEM_PATH_DECLARED Q_DECLARE_METATYPE (std::filesystem::path) #endif diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp index 39dea6fbb0..51633c5bb4 100644 --- a/apps/opencs/view/tools/merge.hpp +++ b/apps/opencs/view/tools/merge.hpp @@ -3,9 +3,7 @@ #include -#ifndef Q_MOC_RUN #include -#endif class QPushButton; class QListWidget; diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index e39cf16198..413e677917 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -20,6 +20,7 @@ #include #include +#include #include @@ -403,7 +404,7 @@ namespace MWGui throw std::runtime_error("Can't find selected slot"); std::stringstream text; - time_t time = mCurrentSlot->mTimeStamp; + time_t time = Misc::to_time_t(mCurrentSlot->mTimeStamp); struct tm* timeinfo; timeinfo = localtime(&time); diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index c43229f588..0d90ab121a 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include @@ -31,7 +30,7 @@ void MWState::Character::addSlot (const std::filesystem::path& path, const std:: { Slot slot; slot.mPath = path; - slot.mTimeStamp = std::chrono::system_clock::to_time_t (Misc::clockCast (std::filesystem::last_write_time (path))); + slot.mTimeStamp = std::filesystem::last_write_time (path); ESM::ESMReader reader; reader.open (slot.mPath.string()); @@ -78,7 +77,7 @@ void MWState::Character::addSlot (const ESM::SavedGame& profile) } slot.mProfile = profile; - slot.mTimeStamp = std::time (nullptr); + slot.mTimeStamp = std::filesystem::file_time_type (); mSlots.push_back (slot); } @@ -156,7 +155,7 @@ const MWState::Slot *MWState::Character::updateSlot (const Slot *slot, const ESM Slot newSlot = *slot; newSlot.mProfile = profile; - newSlot.mTimeStamp = std::time (nullptr); + newSlot.mTimeStamp = std::filesystem::file_time_type (); mSlots.erase (mSlots.begin()+index); diff --git a/apps/openmw/mwstate/character.hpp b/apps/openmw/mwstate/character.hpp index 31dbde5830..9883eb253c 100644 --- a/apps/openmw/mwstate/character.hpp +++ b/apps/openmw/mwstate/character.hpp @@ -11,7 +11,7 @@ namespace MWState { std::filesystem::path mPath; ESM::SavedGame mProfile; - std::time_t mTimeStamp; + std::filesystem::file_time_type mTimeStamp; }; bool operator< (const Slot& left, const Slot& right); diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index d15cb4bb97..aa63c3191e 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -173,7 +173,7 @@ bool Config::GameSettings::writeFile(QTextStream &stream) while (i.hasPrevious()) { i.previous(); - // path lines (e.g. 'data=...') need quotes and ampersands escaping to match how std::filesystem::path uses boost::io::quoted + // path lines (e.g. 'data=...') need quotes and ampersands escaping to match how boost::filesystem::path uses boost::io::quoted if (i.key() == QLatin1String("data") || i.key() == QLatin1String("data-local") || i.key() == QLatin1String("resources") diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 37eca2c460..900c341edc 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -427,7 +427,7 @@ void parseConfig(std::istream& stream, bpo::variables_map& variables, const bpo: std::istream& operator>> (std::istream& istream, MaybeQuotedPath& MaybeQuotedPath) { - // If the stream starts with a double quote, read from stream using std::filesystem::path rules, then discard anything remaining. + // If the stream starts with a double quote, read from stream using boost::filesystem::path rules, then discard anything remaining. // This prevents boost::program_options getting upset that we've not consumed the whole stream. // If it doesn't start with a double quote, read the whole thing verbatim if (istream.peek() == '"') diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index 1222c2e5cb..da26e773f6 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -38,10 +38,10 @@ WindowsPath::WindowsPath(const std::string& application_name) with UTF-8 encoding (generated for empty name from boost::locale) to handle Unicode in platform-agnostic way using std::string. - See std::filesystem and boost::locale reference for details. + See boost::filesystem and boost::locale reference for details. */ // TODO(Project579): Temporarly disabled until a good solution is found (no solution might actually be needed) - //std::filesystem::path::imbue(boost::locale::generator().generate("")); + //boost::filesystem::path::imbue(boost::locale::generator().generate("")); std::filesystem::path localPath = getLocalPath(); if (!SetCurrentDirectoryA(localPath.string().c_str())) @@ -111,7 +111,7 @@ std::filesystem::path WindowsPath::getCachePath() const std::filesystem::path WindowsPath::getInstallPath() const { - std::filesystem::path installPath(""); + std::filesystem::path installPath(); HKEY hKey; diff --git a/components/misc/timeconvert.hpp b/components/misc/timeconvert.hpp index dd6f542a44..26073025a3 100644 --- a/components/misc/timeconvert.hpp +++ b/components/misc/timeconvert.hpp @@ -1,16 +1,17 @@ #ifndef OPENMW_COMPONENTS_MISC_TIMECONVERT_H #define OPENMW_COMPONENTS_MISC_TIMECONVERT_H +#include +#include + namespace Misc { -// Very ugly hack to go from std::chrono::file_clock to any other clock, can be replaced with better solution in C++20 -// https://stackoverflow.com/questions/35282308/convert-between-c11-clocks -template -inline DstTimePointT clockCast (const SrcTimePointT tp) +template +inline std::time_t to_time_t(TP tp) { - const auto src_now = SrcClockT::now(); - const auto dst_now = DstClockT::now(); - return dst_now + (tp - src_now); + using namespace std::chrono; + auto sctp = time_point_cast(tp - TP::clock::now() + system_clock::now()); + return system_clock::to_time_t(sctp); } } // namespace Misc From e5c417c9689ecffa81d127d6babd96b1db46b055 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sun, 19 Jun 2022 13:28:33 +0200 Subject: [PATCH 14/36] Make sure all paths are passed as std::filesystem::path instead of std::string where possible. --- apps/bsatool/bsatool.cpp | 4 +- apps/bulletobjecttool/main.cpp | 3 +- apps/esmtool/arguments.hpp | 6 +- apps/esmtool/esmtool.cpp | 20 +++--- apps/esmtool/tes4.cpp | 2 +- apps/launcher/datafilespage.cpp | 2 +- apps/launcher/maindialog.cpp | 16 ++--- apps/launcher/settingspage.cpp | 2 +- apps/mwiniimporter/importer.cpp | 8 +-- apps/mwiniimporter/main.cpp | 2 - apps/navmeshtool/main.cpp | 6 +- apps/niftest/niftest.cpp | 38 +++++------ apps/opencs/editor.cpp | 11 ++-- apps/opencs/model/doc/document.cpp | 8 +-- apps/opencs/model/doc/loader.cpp | 2 +- apps/opencs/model/doc/runner.cpp | 4 +- apps/opencs/model/doc/savingstages.cpp | 2 +- apps/opencs/model/doc/savingstate.cpp | 2 +- apps/opencs/model/prefs/state.cpp | 2 +- apps/opencs/model/tools/mergestages.cpp | 2 +- apps/opencs/model/world/data.cpp | 8 +-- apps/opencs/view/doc/adjusterwidget.cpp | 10 +-- apps/opencs/view/doc/loader.cpp | 2 +- apps/opencs/view/doc/view.cpp | 4 +- apps/opencs/view/doc/viewmanager.cpp | 2 +- apps/opencs/view/tools/merge.cpp | 2 +- apps/openmw/engine.cpp | 63 +++++++++---------- apps/openmw/engine.hpp | 4 +- apps/openmw/main.cpp | 8 +-- apps/openmw/mwbase/statemanager.hpp | 4 +- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.hpp | 3 +- apps/openmw/mwinput/bindingsmanager.cpp | 10 +-- apps/openmw/mwinput/bindingsmanager.hpp | 5 +- apps/openmw/mwinput/controllermanager.cpp | 8 +-- apps/openmw/mwinput/controllermanager.hpp | 5 +- apps/openmw/mwinput/inputmanagerimp.cpp | 4 +- apps/openmw/mwinput/inputmanagerimp.hpp | 7 ++- apps/openmw/mwlua/luamanagerimp.cpp | 19 +++--- apps/openmw/mwlua/luamanagerimp.hpp | 7 ++- apps/openmw/mwrender/postprocessor.cpp | 8 +-- apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/renderingmanager.hpp | 4 +- apps/openmw/mwrender/water.cpp | 12 ++-- apps/openmw/mwrender/water.hpp | 4 +- apps/openmw/mwscript/miscextensions.cpp | 4 +- apps/openmw/mwstate/character.cpp | 8 +-- apps/openmw/mwstate/statemanagerimp.cpp | 18 +++--- apps/openmw/mwstate/statemanagerimp.hpp | 4 +- apps/openmw/mwworld/esmloader.cpp | 8 +-- apps/openmw/mwworld/esmstore.cpp | 4 +- apps/openmw/mwworld/esmstore.hpp | 5 +- apps/openmw/mwworld/worldimp.cpp | 16 ++--- apps/openmw/mwworld/worldimp.hpp | 6 +- apps/openmw_test_suite/esm3/readerscache.cpp | 2 +- apps/openmw_test_suite/files/hash.cpp | 8 +-- apps/openmw_test_suite/lua/test_storage.cpp | 2 +- apps/openmw_test_suite/mwworld/test_store.cpp | 10 +-- .../nifloader/testbulletnifloader.cpp | 2 +- apps/openmw_test_suite/settings/parser.cpp | 2 +- .../settings/shadermanager.cpp | 4 +- .../shader/shadermanager.cpp | 42 ++++++------- apps/openmw_test_suite/testing_util.hpp | 10 +-- apps/wizard/installationtargetpage.cpp | 2 +- apps/wizard/mainwizard.cpp | 2 +- components/bsa/bsa_file.cpp | 16 ++--- components/bsa/bsa_file.hpp | 9 +-- components/bsa/compressedbsafile.cpp | 15 +++-- components/bsa/compressedbsafile.hpp | 5 +- components/config/gamesettings.cpp | 8 +-- components/config/gamesettings.hpp | 2 +- components/config/launchersettings.cpp | 2 +- components/crashcatcher/crashcatcher.cpp | 2 +- components/crashcatcher/crashcatcher.hpp | 2 +- .../crashcatcher/windows_crashcatcher.cpp | 11 ++-- .../crashcatcher/windows_crashcatcher.hpp | 6 +- components/debug/debugging.cpp | 6 +- components/debug/debugging.hpp | 2 +- components/detournavigator/navigator.cpp | 4 +- components/detournavigator/navigator.hpp | 5 +- components/esm/esmcommon.hpp | 3 +- components/esm3/esmreader.cpp | 15 +++-- components/esm3/esmreader.hpp | 11 ++-- components/esm3/loadcell.cpp | 2 +- components/esm3/readerscache.hpp | 2 +- components/esm4/reader.cpp | 21 +++---- components/esm4/reader.hpp | 17 +++-- components/esmloader/load.cpp | 4 +- components/files/collections.cpp | 31 +++++---- components/files/collections.hpp | 4 +- components/files/configurationmanager.cpp | 16 ++--- components/files/constrainedfilestream.cpp | 4 +- components/files/constrainedfilestream.hpp | 2 +- components/files/constrainedfilestreambuf.cpp | 5 +- components/files/constrainedfilestreambuf.hpp | 2 +- components/files/hash.cpp | 4 +- components/files/hash.hpp | 4 +- components/files/linuxpath.cpp | 25 ++++---- components/files/multidircollection.cpp | 6 +- components/files/openfile.cpp | 4 +- components/files/openfile.hpp | 3 +- components/files/windowspath.cpp | 59 ++++++----------- components/fontloader/fontloader.cpp | 2 +- components/fx/technique.cpp | 2 +- components/lua/luastate.cpp | 13 ++-- components/lua/luastate.hpp | 6 +- components/lua/storage.cpp | 8 +-- components/lua/storage.hpp | 4 +- components/myguiplatform/myguidatamanager.cpp | 8 +-- components/myguiplatform/myguidatamanager.hpp | 5 +- components/myguiplatform/myguiloglistener.cpp | 4 +- components/myguiplatform/myguiloglistener.hpp | 8 +-- components/myguiplatform/myguiplatform.cpp | 2 +- components/myguiplatform/myguiplatform.hpp | 5 +- components/nif/niffile.cpp | 4 +- components/nif/niffile.hpp | 8 +-- components/nifbullet/bulletnifloader.cpp | 2 +- components/nifosg/nifloader.cpp | 58 ++++++++--------- components/resource/scenemanager.cpp | 6 +- components/resource/scenemanager.hpp | 3 +- components/sceneutil/screencapture.cpp | 17 ++--- components/sceneutil/screencapture.hpp | 10 +-- components/sceneutil/writescene.cpp | 2 +- components/sceneutil/writescene.hpp | 4 +- components/settings/parser.cpp | 13 ++-- components/settings/parser.hpp | 9 +-- components/settings/settings.cpp | 10 +-- components/settings/settings.hpp | 5 +- components/settings/shadermanager.hpp | 10 +-- components/shader/shadermanager.cpp | 10 +-- components/shader/shadermanager.hpp | 5 +- components/version/version.cpp | 8 +-- components/version/version.hpp | 5 +- components/vfs/archive.hpp | 2 +- components/vfs/bsaarchive.cpp | 4 +- components/vfs/bsaarchive.hpp | 8 +-- components/vfs/filesystemarchive.cpp | 29 +++++---- components/vfs/filesystemarchive.hpp | 11 ++-- components/vfs/manager.cpp | 12 ++-- components/vfs/manager.hpp | 2 +- components/vfs/registerarchives.cpp | 6 +- 143 files changed, 593 insertions(+), 594 deletions(-) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index c02c64356f..ad4556ddc6 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -17,7 +17,7 @@ namespace bpo = boost::program_options; struct Arguments { std::string mode; - std::string filename; + std::filesystem::path filename; std::string extractfile; std::string addfile; std::string outdir; @@ -112,7 +112,7 @@ bool parseOptions (int argc, char** argv, Arguments &info) << desc << std::endl; return false; } - info.filename = variables["input-file"].as< std::vector >()[0]; + info.filename = variables["input-file"].as< std::vector >()[0]; //TODO(Project579): This will probably break in windows with unicode paths // Default output to the working directory info.outdir = "."; diff --git a/apps/bulletobjecttool/main.cpp b/apps/bulletobjecttool/main.cpp index aad8c5e082..6f9e7ac376 100644 --- a/apps/bulletobjecttool/main.cpp +++ b/apps/bulletobjecttool/main.cpp @@ -33,6 +33,7 @@ namespace namespace bpo = boost::program_options; using StringsVector = std::vector; + using PathsVector = std::vector; bpo::options_description makeOptionsDescription() { @@ -145,7 +146,7 @@ namespace const auto fsStrict = variables["fs-strict"].as(); const auto resDir = variables["resources"].as(); - Version::Version v = Version::getOpenmwVersion(resDir.string()); + Version::Version v = Version::getOpenmwVersion(resDir); Log(Debug::Info) << v.describe(); dataDirs.insert(dataDirs.begin(), resDir / "vfs"); const auto fileCollections = Files::Collections(dataDirs, !fsStrict); diff --git a/apps/esmtool/arguments.hpp b/apps/esmtool/arguments.hpp index e3be98fd2a..bc5795942f 100644 --- a/apps/esmtool/arguments.hpp +++ b/apps/esmtool/arguments.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include @@ -18,8 +18,8 @@ namespace EsmTool std::string mode; std::string encoding; - std::string filename; - std::string outname; + std::filesystem::path filename; + std::filesystem::path outname; std::vector types; std::string name; diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 381f46c3c4..a9971c1867 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -154,9 +154,9 @@ bool parseOptions (int argc, char** argv, Arguments &info) return false; }*/ - info.filename = variables["input-file"].as< std::vector >()[0]; + info.filename = variables["input-file"].as< std::vector >()[0]; if (variables["input-file"].as< std::vector >().size() > 1) - info.outname = variables["input-file"].as< std::vector >()[1]; + info.outname = variables["input-file"].as< std::vector >()[1]; if (const auto it = variables.find("raw"); it != variables.end()) info.mRawFormat = ESM::parseFormat(it->second.as()); @@ -284,9 +284,9 @@ void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMDa } } -void printRawTes3(std::string_view path) +void printRawTes3(const std::filesystem::path &path) { - std::cout << "TES3 RAW file listing: " << path << '\n'; + std::cout << "TES3 RAW file listing: " << path << '\n'; //TODO(Project579): This will probably break in windows with unicode paths ESM::ESMReader esm; esm.openRaw(path); while(esm.hasMoreRecs()) @@ -310,7 +310,7 @@ void printRawTes3(std::string_view path) int loadTes3(const Arguments& info, std::unique_ptr&& stream, ESMData* data) { - std::cout << "Loading TES3 file: " << info.filename << '\n'; + std::cout << "Loading TES3 file: " << info.filename << '\n'; //TODO(Project579): This will probably break in windows with unicode paths ESM::ESMReader esm; ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding)); @@ -419,7 +419,7 @@ int load(const Arguments& info, ESMData* data) printRawTes3(info.filename); break; case ESM::Format::Tes4: - std::cout << "Printing raw TES4 file is not supported: " << info.filename << "\n"; + std::cout << "Printing raw TES4 file is not supported: " << info.filename << "\n"; //TODO(Project579): This will probably break in windows with unicode paths break; } return 0; @@ -490,7 +490,7 @@ int clone(const Arguments& info) if (i % 3 != 0) std::cout << '\n'; - std::cout << "\nSaving records to: " << info.outname << "...\n"; + std::cout << "\nSaving records to: " << info.outname << "...\n"; //TODO(Project579): This will probably break in windows with unicode paths ESM::ESMWriter esm; ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding)); @@ -499,7 +499,7 @@ int clone(const Arguments& info) esm.setVersion(ESM::VER_13); esm.setRecordCount (recordCount); - std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary); + std::fstream save(info.outname, std::fstream::out | std::fstream::binary); esm.save(save); int saved = 0; @@ -563,14 +563,14 @@ int comp(const Arguments& info) ESMData dataOne; if (load(fileOne, &dataOne) != 0) { - std::cout << "Failed to load " << info.filename << ", aborting comparison." << std::endl; + std::cout << "Failed to load " << info.filename << ", aborting comparison." << std::endl; //TODO(Project579): This will probably break in windows with unicode paths return 1; } ESMData dataTwo; if (load(fileTwo, &dataTwo) != 0) { - std::cout << "Failed to load " << info.outname << ", aborting comparison." << std::endl; + std::cout << "Failed to load " << info.outname << ", aborting comparison." << std::endl; //TODO(Project579): This will probably break in windows with unicode paths return 1; } diff --git a/apps/esmtool/tes4.cpp b/apps/esmtool/tes4.cpp index 815eb6dd34..02e722631d 100644 --- a/apps/esmtool/tes4.cpp +++ b/apps/esmtool/tes4.cpp @@ -289,7 +289,7 @@ namespace EsmTool int loadTes4(const Arguments& info, std::unique_ptr&& stream) { - std::cout << "Loading TES4 file: " << info.filename << '\n'; + std::cout << "Loading TES4 file: " << info.filename << '\n'; //TODO(Project579): This will probably break in windows with unicode paths try { diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 2d52b6a066..d5f2259f2e 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -230,7 +230,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) if (!mDataLocal.isEmpty()) directories.insert(0, mDataLocal); - const auto globalDataDir = QString(mGameSettings.getGlobalDataDir().c_str()); + const auto globalDataDir = QString(mGameSettings.getGlobalDataDir().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths if (!globalDataDir.isEmpty()) directories.insert(0, globalDataDir); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 8e5af37121..447dcb5193 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -155,7 +155,7 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() return FirstRunDialogResultFailure; // Dialog wizard and setup will fail if the config directory does not already exist - QDir userConfigDir = QDir(QString::fromStdString(mCfgMgr.getUserConfigPath().string())); + QDir userConfigDir = QDir(QString::fromStdString(mCfgMgr.getUserConfigPath().string())); //TODO(Project579): This will probably break in windows with unicode paths, in Qt 6 it's possible to convert directly from std::filesystem::path to QDir and that would solve the issue if ( ! userConfigDir.exists() ) { if ( ! userConfigDir.mkpath(".") ) { @@ -295,7 +295,7 @@ bool Launcher::MainDialog::setupLauncherSettings() mLauncherSettings.setMultiValueEnabled(true); - QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); + QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths QStringList paths; paths.append(QString(Config::LauncherSettings::sLauncherConfigFileName)); @@ -328,9 +328,9 @@ bool Launcher::MainDialog::setupGameSettings() { mGameSettings.clear(); - QString localPath = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str()); - QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); - QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); + QString localPath = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths + QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths + QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths QFile file; @@ -479,7 +479,7 @@ bool Launcher::MainDialog::writeSettings() mSettingsPage->saveSettings(); mAdvancedPage->saveSettings(); - QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); + QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths QDir dir(userPath); if (!dir.exists()) { @@ -509,13 +509,13 @@ bool Launcher::MainDialog::writeSettings() file.close(); // Graphics settings - const std::string settingsPath = (mCfgMgr.getUserConfigPath() / "settings.cfg").string(); + const auto settingsPath = mCfgMgr.getUserConfigPath() / "settings.cfg"; try { Settings::Manager::saveUser(settingsPath); } catch (std::exception& e) { std::string msg = "
Error writing settings.cfg

" + - settingsPath + "

" + e.what(); + settingsPath.string() + "

" + e.what(); //TODO(Project579): This will probably break in windows with unicode paths cfgError(tr("Error writing user settings file"), tr(msg.c_str())); return false; } diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 96f11808f0..77d45e48ec 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -102,7 +102,7 @@ void Launcher::SettingsPage::on_importerButton_clicked() mMain->writeSettings(); // Create the file if it doesn't already exist, else the importer will fail - QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); + QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); //TODO(Project579): This will probably break in windows with unicode paths path.append(QLatin1String("openmw.cfg")); QFile file(path); diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 305587162b..912aa2d5ed 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -661,7 +661,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::filesystem::pat std::string section(""); MwIniImporter::multistrmap map; - std::ifstream file((sfs::path(filename))); + std::ifstream file(filename); ToUTF8::Utf8Encoder encoder(mEncoding); std::string line; @@ -721,7 +721,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::filesystem::pat std::cout << "load cfg file: " << filename << std::endl; MwIniImporter::multistrmap map; - std::ifstream file((sfs::path(filename))); + std::ifstream file(filename); std::string line; while (std::getline(file, line)) { @@ -938,13 +938,13 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co reader.setEncoder(&encoder); for (auto& file : contentFiles) { - reader.open(file.second.string()); + reader.open(file.second); std::vector dependencies; for (auto& gameFile : reader.getGameFiles()) { dependencies.push_back(gameFile.name); } - unsortedFiles.emplace_back(std::filesystem::path(reader.getName()).filename().string(), dependencies); + unsortedFiles.emplace_back(reader.getName().filename().string(), dependencies); //TODO(Project579): This will probably break in windows with unicode paths reader.close(); } diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index d6afecb1ef..2de80ffb96 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -52,8 +52,6 @@ private: int wmain(int argc, wchar_t *wargv[]) { utf8argv converter(argc, wargv); char **argv = converter.get(); - // TODO(Project579): Temporarly disabled until a good solution is found (no solution might actually be needed) - //boost::filesystem::path::imbue(boost::locale::generator().generate("")); #endif try diff --git a/apps/navmeshtool/main.cpp b/apps/navmeshtool/main.cpp index de3ccdcf96..21751dca79 100644 --- a/apps/navmeshtool/main.cpp +++ b/apps/navmeshtool/main.cpp @@ -143,7 +143,7 @@ namespace NavMeshTool const auto fsStrict = variables["fs-strict"].as(); const auto resDir = variables["resources"].as(); - Version::Version v = Version::getOpenmwVersion(resDir.string()); + Version::Version v = Version::getOpenmwVersion(resDir); Log(Debug::Info) << v.describe(); dataDirs.insert(dataDirs.begin(), resDir / "vfs"); const auto fileCollections = Files::Collections(dataDirs, !fsStrict); @@ -179,9 +179,9 @@ namespace NavMeshTool const osg::Vec3f agentHalfExtents = Settings::Manager::getVector3("default actor pathfind half extents", "Game"); const DetourNavigator::AgentBounds agentBounds {agentCollisionShape, agentHalfExtents}; const std::uint64_t maxDbFileSize = static_cast(Settings::Manager::getInt64("max navmeshdb file size", "Navigator")); - const std::string dbPath = (config.getUserDataPath() / "navmesh.db").string(); + const auto dbPath = config.getUserDataPath() / "navmesh.db"; - DetourNavigator::NavMeshDb db(dbPath, maxDbFileSize); + DetourNavigator::NavMeshDb db(dbPath.string(), maxDbFileSize); //TODO(Project579): This will probably break in windows with unicode paths ESM::ReadersCache readers; EsmLoader::Query query; diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 67d33c6b9d..60b13ae266 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -16,45 +16,45 @@ namespace bpo = boost::program_options; ///See if the file has the named extension -bool hasExtension(std::string filename, std::string extensionToFind) +bool hasExtension(const std::filesystem::path& filename, const std::string& extensionToFind) { - std::string extension = filename.substr(filename.find_last_of('.')+1); + std::string extension = filename.extension().string(); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break return Misc::StringUtils::ciEqual(extension, extensionToFind); } ///See if the file has the "nif" extension. -bool isNIF(const std::string & filename) +bool isNIF(const std::filesystem::path &filename) { return hasExtension(filename,"nif"); } ///See if the file has the "bsa" extension. -bool isBSA(const std::string & filename) +bool isBSA(const std::filesystem::path &filename) { return hasExtension(filename,"bsa"); } /// Check all the nif files in a given VFS::Archive /// \note Can not read a bsa file inside of a bsa file. -void readVFS(std::unique_ptr&& anArchive, std::string archivePath = "") +void readVFS(std::unique_ptr&& anArchive, const std::filesystem::path& archivePath = {}) { VFS::Manager myManager(true); myManager.addArchive(std::move(anArchive)); myManager.buildIndex(); - for(const auto& name : myManager.getRecursiveDirectoryIterator("")) + for(const auto& name : myManager.getRecursiveDirectoryIterator("")) //TODO(Project579): This will probably break in windows with unicode paths { try{ if(isNIF(name)) { // std::cout << "Decoding: " << name << std::endl; - Nif::NIFFile temp_nif(myManager.get(name),archivePath+name); + Nif::NIFFile temp_nif(myManager.get(name),archivePath / name); } else if(isBSA(name)) { if(!archivePath.empty() && !isBSA(archivePath)) { // std::cout << "Reading BSA File: " << name << std::endl; - readVFS(std::make_unique(archivePath + name), archivePath + name + "/"); + readVFS(std::make_unique(archivePath / name), archivePath / name); // std::cout << "Done with BSA File: " << name << std::endl; } } @@ -75,7 +75,7 @@ bool parseOptions (int argc, char** argv, std::vector& files) "Allowed options"); desc.add_options() ("help,h", "print help message.") - ("input-file", bpo::value< std::vector >(), "input file") + ("input-file", bpo::value< std::vector >(), "input file") ; //Default option if none provided @@ -120,30 +120,30 @@ int main(int argc, char **argv) Nif::NIFFile::setLoadUnsupportedFiles(true); // std::cout << "Reading Files" << std::endl; - for(auto it=files.begin(); it!=files.end(); ++it) + for(const auto& name : files) { - std::string name = *it; - try { - if(isNIF(name)) + const std::filesystem::path path(name); //TODO(Project579): This will probably break in windows with unicode paths + + if(isNIF(path)) { //std::cout << "Decoding: " << name << std::endl; - Nif::NIFFile temp_nif(Files::openConstrainedFileStream(name), name); + Nif::NIFFile temp_nif(Files::openConstrainedFileStream(path), path); } - else if(isBSA(name)) + else if(isBSA(path)) { // std::cout << "Reading BSA File: " << name << std::endl; - readVFS(std::make_unique(name)); + readVFS(std::make_unique(path)); } - else if(std::filesystem::is_directory(std::filesystem::path(name))) + else if(std::filesystem::is_directory(path)) { // std::cout << "Reading All Files in: " << name << std::endl; - readVFS(std::make_unique(name), name); + readVFS(std::make_unique(path), path); } else { - std::cerr << "ERROR: \"" << name << "\" is not a nif file, bsa file, or directory!" << std::endl; + std::cerr << "ERROR: \"" << path << "\" is not a nif file, bsa file, or directory!" << std::endl; } } catch (std::exception& e) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index ed49c5399a..9a988991f0 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -78,8 +78,7 @@ CS::Editor::~Editor () mPidFile.close(); if(mServer && std::filesystem::exists(mPid)) - static_cast ( // silence coverity warning - remove(mPid.string().c_str())); // ignore any error + std::filesystem::remove(mPid); } boost::program_options::variables_map CS::Editor::readConfiguration() @@ -107,7 +106,7 @@ boost::program_options::variables_map CS::Editor::readConfiguration() mCfgMgr.readConfiguration(variables, desc, false); Settings::Manager::load(mCfgMgr, true); - setupLogging(mCfgMgr.getLogPath().string(), "OpenMW-CS"); + setupLogging(mCfgMgr.getLogPath(), "OpenMW-CS"); return variables; } @@ -298,7 +297,7 @@ bool CS::Editor::makeIPCServer() mPidFile.open(mPid); - mLock = boost::interprocess::file_lock(mPid.string().c_str()); + mLock = boost::interprocess::file_lock(mPid.c_str()); if(!mLock.try_lock()) { Log(Debug::Error) << "Error: OpenMW-CS is already running."; @@ -374,7 +373,7 @@ int CS::Editor::run() ESM::ESMReader fileReader; ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncodingName)); fileReader.setEncoder(&encoder); - fileReader.open(mFileToLoad.string()); + fileReader.open(mFileToLoad); std::vector discoveredFiles; @@ -394,7 +393,7 @@ int CS::Editor::run() } discoveredFiles.push_back(mFileToLoad); - QString extension = QString::fromStdString(mFileToLoad.extension().string()).toLower(); + QString extension = QString::fromStdString(mFileToLoad.extension().string()).toLower(); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break if (extension == ".esm") { mFileToLoad.replace_extension(".omwgame"); diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a4d47ad0f2..9a93430dc6 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -283,7 +283,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, : mSavePath (savePath), mContentFiles (std::move(files)), mNew (new_), mData (encoding, fsStrict, dataPaths, archives, resDir), mTools (*this, encoding), mProjectPath ((configuration.getUserDataPath() / "projects") / - (savePath.filename().string() + ".project")), + (savePath.filename().u8string() + u8".project")), mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), mResDir(resDir), mRunner (mProjectPath), @@ -298,7 +298,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, std::ofstream destination(mProjectPath, std::ios::out | std::ios::binary); if (!destination.is_open()) - throw std::runtime_error("Can not create project file: " + mProjectPath.string()); + throw std::runtime_error("Can not create project file: " + mProjectPath.string()); //TODO(Project579): This will probably break in windows with unicode paths destination.exceptions(std::ios::failbit | std::ios::badbit); if (!std::filesystem::exists (filtersPath)) @@ -306,7 +306,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, std::ifstream source(filtersPath, std::ios::in | std::ios::binary); if (!source.is_open()) - throw std::runtime_error("Can not read filters file: " + filtersPath.string()); + throw std::runtime_error("Can not read filters file: " + filtersPath.string()); //TODO(Project579): This will probably break in windows with unicode paths source.exceptions(std::ios::failbit | std::ios::badbit); destination << source.rdbuf(); @@ -484,7 +484,7 @@ void CSMDoc::Document::startRunning (const std::string& profile, for (std::vector::const_iterator iter (mContentFiles.begin()); iter!=mContentFiles.end(); ++iter) - contentFiles.push_back (iter->filename().string()); + contentFiles.push_back (iter->filename().string()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break mRunner.configure (getData().getDebugProfiles().getRecord (profile).get(), contentFiles, startupInstruction); diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index 4563757020..70d114c47e 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -93,7 +93,7 @@ void CSMDoc::Loader::load() iter->second.mRecordsLeft = true; iter->second.mRecordsLoaded = 0; - emit nextStage (document, path.filename().string(), steps); + emit nextStage (document, path.filename().string(), steps); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break } else if (iter->second.mFile==size) // start loading the last (project) file { diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index 55a8be2ae7..c1db116a52 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -83,7 +83,7 @@ void CSMDoc::Runner::start (bool delayed) arguments << ("--script-run="+mStartup->fileName()); arguments << - QString::fromUtf8 (("--data=\""+mProjectPath.parent_path().string()+"\"").c_str()); + QString::fromUtf8 (("--data=\""+mProjectPath.parent_path().string()+"\"").c_str()); //TODO(Project579): This will probably break in windows with unicode paths arguments << "--replace=content"; @@ -94,7 +94,7 @@ void CSMDoc::Runner::start (bool delayed) } arguments - << QString::fromUtf8 (("--content="+mProjectPath.filename().string()).c_str()); + << QString::fromUtf8 (("--content="+mProjectPath.filename().string()).c_str()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break mProcess.start (path, arguments); } diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 7059188bac..20f3ca4ba6 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -72,7 +72,7 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages) for (std::vector::const_iterator iter (dependencies.begin()); iter!=end; ++iter) { - std::string name = iter->filename().string(); + std::string name = iter->filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break uint64_t size = std::filesystem::file_size (*iter); mState.getWriter().addMaster (name, size); diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp index 8e6730d22c..e9a2b55385 100644 --- a/apps/opencs/model/doc/savingstate.cpp +++ b/apps/opencs/model/doc/savingstate.cpp @@ -34,7 +34,7 @@ void CSMDoc::SavingState::start (Document& document, bool project) else mPath = document.getSavePath(); - std::filesystem::path file (mPath.filename().string() + ".tmp"); + std::filesystem::path file (mPath.filename().u8string() + u8".tmp"); mTmpPath = mPath.parent_path(); diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 673839d47c..ae2c94b11a 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -649,7 +649,7 @@ CSMPrefs::State::~State() void CSMPrefs::State::save() { std::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile; - Settings::Manager::saveUser (user.string()); + Settings::Manager::saveUser (user); } CSMPrefs::State::Iterator CSMPrefs::State::begin() diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 8a7541c0db..09a0db4078 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -44,7 +44,7 @@ void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& ESM::ESMReader reader; reader.setEncoder (&mEncoder); - reader.open (path.string()); + reader.open (path); CSMWorld::MetaData source; source.mId = "sys::meta"; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f03aac0837..4fd3939883 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -88,7 +88,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat defines[define.first] = define.second; mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines); - mResourceSystem->getSceneManager()->setShaderPath((resDir / "shaders").string()); + mResourceSystem->getSceneManager()->setShaderPath(resDir / "shaders"); int index = 0; @@ -969,7 +969,7 @@ int CSMWorld::Data::getTotalRecords (const std::vector& f if (!std::filesystem::exists(files[i])) continue; - reader->open(files[i].string()); + reader->open(files[i]); records += reader->getRecordCount(); reader->close(); } @@ -989,9 +989,9 @@ int CSMWorld::Data::startLoading (const std::filesystem::path& path, bool base, mReader = new ESM::ESMReader; mReader->setEncoder (&mEncoder); mReader->setIndex((project || !base) ? 0 : mReaderIndex++); - mReader->open (path.string()); + mReader->open (path); - mContentFileNames.insert(std::make_pair(path.filename().string(), mReader->getIndex())); + mContentFileNames.insert(std::make_pair(path.filename().string(), mReader->getIndex())); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break mBase = base; mProject = project; diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 9ff2da125e..0e6ae73fe6 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -68,14 +68,14 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) } else { - std::filesystem::path path (name.toUtf8().data()); + std::filesystem::path path (name.toUtf8().data()); //TODO(Project579): Replace with char8_t in C++20 - std::string extension = Misc::StringUtils::lowerCase(path.extension().string()); + std::string extension = Misc::StringUtils::lowerCase(path.extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break bool isLegacyPath = (extension == ".esm" || extension == ".esp"); - bool isFilePathChanged = (path.parent_path().string() != mLocalData.string()); + bool isFilePathChanged = (path.parent_path() != mLocalData); if (isLegacyPath) path.replace_extension (addon ? ".omwaddon" : ".omwgame"); @@ -85,7 +85,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) if (!isFilePathChanged && !isLegacyPath) { // path already points to the local data directory - message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str()); + message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str()); //TODO(Project579): This is probably broken on windows with unicode paths mResultPath = path; } //in all other cases, ensure the path points to data-local and do an existing file check @@ -95,7 +95,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) if (isFilePathChanged) path = mLocalData / path.filename(); - message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str()); + message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str()); //TODO(Project579): This is probably broken on windows with unicode paths mResultPath = path; if (std::filesystem::exists (path)) diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index a33aa900fe..188827db2f 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -19,7 +19,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event) CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document) : mDocument (document), mTotalRecordsLabel (0), mRecordsLabel (0), mAborted (false), mMessages (nullptr), mRecords(0) { - setWindowTitle (QString::fromUtf8((std::string("Opening ") + document->getSavePath().filename().string()).c_str())); + setWindowTitle (QString::fromUtf8((std::string("Opening ") + document->getSavePath().filename().string()).c_str())); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break setMinimumWidth (400); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index ca32e5fc79..eaeb6d3957 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -387,7 +387,7 @@ void CSVDoc::View::updateTitle() { std::ostringstream stream; - stream << mDocument->getSavePath().filename().string(); + stream << mDocument->getSavePath().filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break if (mDocument->getState() & CSMDoc::State_Modified) stream << " *"; @@ -747,7 +747,7 @@ void CSVDoc::View::tutorial() void CSVDoc::View::infoAbout() { // Get current OpenMW version - QString versionInfo = (Version::getOpenmwVersionDescription(mDocument->getResourceDir().string())+ + QString versionInfo = (Version::getOpenmwVersionDescription(mDocument->getResourceDir())+ #if defined(__x86_64__) || defined(_M_X64) " (64-bit)").c_str(); #else diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index c1fd21d246..92144ca668 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -261,7 +261,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view) QMessageBox messageBox(view); CSMDoc::Document *document = view->getDocument(); - messageBox.setWindowTitle (QString::fromUtf8(document->getSavePath().filename().string().c_str())); + messageBox.setWindowTitle (QString::fromUtf8(document->getSavePath().filename().string().c_str())); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break messageBox.setText ("The document has been modified."); messageBox.setInformativeText ("Do you want to save your changes?"); messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index e8b963f235..0efce2aec3 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -102,7 +102,7 @@ void CSVTools::Merge::configure (CSMDoc::Document *document) for (std::vector::const_iterator iter (files.begin()); iter!=files.end(); ++iter) - mFiles->addItem (QString::fromUtf8 (iter->filename().string().c_str())); + mFiles->addItem (QString::fromUtf8 (iter->filename().string().c_str())); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break } void CSVTools::Merge::setLocalData (const std::filesystem::path& localData) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 07f5f77e98..22cd339b36 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -528,7 +528,7 @@ void OMW::Engine::enableFSStrict(bool fsStrict) void OMW::Engine::setDataDirs (const Files::PathContainer& dataDirs) { mDataDirs = dataDirs; - mDataDirs.insert(mDataDirs.begin(), (mResDir / "vfs")); + mDataDirs.insert(mDataDirs.begin(), mResDir / "vfs"); mFileCollections = Files::Collections (mDataDirs, !mFSStrict); } @@ -708,10 +708,10 @@ void OMW::Engine::createWindow() void OMW::Engine::setWindowIcon() { std::ifstream windowIconStream; - std::string windowIcon = (mResDir / "openmw.png").string(); + const auto windowIcon = mResDir / "openmw.png"; windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary); if (windowIconStream.fail()) - Log(Debug::Error) << "Error: Failed to open " << windowIcon; + Log(Debug::Error) << "Error: Failed to open " << windowIcon; //TODO(Project579): This will probably break in windows with unicode paths osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); if (!reader) { @@ -720,7 +720,7 @@ void OMW::Engine::setWindowIcon() } osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream); if (!result.success()) - Log(Debug::Error) << "Error: Failed to read " << windowIcon << ": " << result.message() << " code " << result.status(); + Log(Debug::Error) << "Error: Failed to read " << windowIcon << ": " << result.message() << " code " << result.status(); //TODO(Project579): This will probably break in windows with unicode paths else { osg::ref_ptr image = result.getImage(); @@ -765,7 +765,7 @@ void OMW::Engine::prepareEngine() mScreenCaptureOperation = new SceneUtil::AsyncScreenCaptureOperation( mWorkQueue, new SceneUtil::WriteScreenshotToFileOperation( - mCfgMgr.getScreenshotPath().string(), + mCfgMgr.getScreenshotPath(), Settings::Manager::getString("screenshot format", "General"), Settings::Manager::getBool("notify on saved screenshot", "General") ? std::function(ScheduleNonDialogMessageBox {}) @@ -777,35 +777,34 @@ void OMW::Engine::prepareEngine() mViewer->addEventHandler(mScreenCaptureHandler); - mLuaManager = std::make_unique(mVFS.get(), (mResDir / "lua_libs").string()); + mLuaManager = std::make_unique(mVFS.get(), mResDir / "lua_libs"); mEnvironment.setLuaManager(*mLuaManager); // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so - std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v3.xml").string(); + const auto keybinderUser = mCfgMgr.getUserConfigPath() / "input_v3.xml"; bool keybinderUserExists = std::filesystem::exists(keybinderUser); if(!keybinderUserExists) { - std::string input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string(); + const auto input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml"); if(std::filesystem::exists(input2)) { - std::filesystem::copy_file(input2, keybinderUser); - keybinderUserExists = std::filesystem::exists(keybinderUser); - Log(Debug::Info) << "Loading keybindings file: " << keybinderUser; + keybinderUserExists = std::filesystem::copy_file(input2, keybinderUser); + Log(Debug::Info) << "Loading keybindings file: " << keybinderUser; //TODO(Project579): This will probably break in windows with unicode paths } } else - Log(Debug::Info) << "Loading keybindings file: " << keybinderUser; + Log(Debug::Info) << "Loading keybindings file: " << keybinderUser; //TODO(Project579): This will probably break in windows with unicode paths - const std::string userdefault = mCfgMgr.getUserConfigPath().string() + "/gamecontrollerdb.txt"; - const std::string localdefault = mCfgMgr.getLocalPath().string() + "/gamecontrollerdb.txt"; - const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/gamecontrollerdb.txt"; + const auto userdefault = mCfgMgr.getUserConfigPath() / "gamecontrollerdb.txt"; + const auto localdefault = mCfgMgr.getLocalPath() / "gamecontrollerdb.txt"; + const auto globaldefault = mCfgMgr.getGlobalPath() / "gamecontrollerdb.txt"; - std::string userGameControllerdb; + std::filesystem::path userGameControllerdb; if (std::filesystem::exists(userdefault)) userGameControllerdb = userdefault; - std::string gameControllerdb; + std::filesystem::path gameControllerdb; if (std::filesystem::exists(localdefault)) gameControllerdb = localdefault; else if (std::filesystem::exists(globaldefault)) @@ -813,7 +812,7 @@ void OMW::Engine::prepareEngine() //else if it doesn't exist, pass in an empty string // gui needs our shaders path before everything else - mResourceSystem->getSceneManager()->setShaderPath((mResDir / "shaders").string()); + mResourceSystem->getSceneManager()->setShaderPath(mResDir / "shaders"); osg::ref_ptr exts = osg::GLExtensions::Get(0, false); bool shadersSupported = exts && (exts->glslLanguageVersion >= 1.2f); @@ -831,9 +830,9 @@ void OMW::Engine::prepareEngine() rootNode->addChild(guiRoot); mWindowManager = std::make_unique(mWindow, mViewer, guiRoot, mResourceSystem.get(), mWorkQueue.get(), - mCfgMgr.getLogPath().string() + std::string("/"), + mCfgMgr.getLogPath(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, - Version::getOpenmwVersionDescription(mResDir.string()), shadersSupported); + Version::getOpenmwVersionDescription(mResDir), shadersSupported); mEnvironment.setWindowManager(*mWindowManager); mInputManager = std::make_unique(mWindow, mViewer, mScreenCaptureHandler, @@ -854,7 +853,7 @@ void OMW::Engine::prepareEngine() // Create the world mWorld = std::make_unique(mViewer, rootNode, mResourceSystem.get(), mWorkQueue.get(), *mUnrefQueue, mFileCollections, mContentFiles, mGroundcoverFiles, mEncoder.get(), mActivationDistanceOverride, mCellName, - mStartupScript, mResDir.string(), mCfgMgr.getUserDataPath().string()); + mStartupScript, mResDir, mCfgMgr.getUserDataPath()); mWorld->setupPlayer(); mWorld->setRandomSeed(mRandomSeed); mEnvironment.setWorld(*mWorld); @@ -865,8 +864,8 @@ void OMW::Engine::prepareEngine() //Load translation data mTranslationDataStorage.setEncoder(mEncoder.get()); - for (size_t i = 0; i < mContentFiles.size(); i++) - mTranslationDataStorage.loadTranslationData(mFileCollections, mContentFiles[i]); + for (auto & mContentFile : mContentFiles) + mTranslationDataStorage.loadTranslationData(mFileCollections, mContentFile); Compiler::registerExtensions (mExtensions); @@ -910,7 +909,7 @@ void OMW::Engine::prepareEngine() } mLuaManager->init(); - mLuaManager->loadPermanentStorage(mCfgMgr.getUserConfigPath().string()); + mLuaManager->loadPermanentStorage(mCfgMgr.getUserConfigPath()); } class OMW::Engine::LuaWorker @@ -1014,7 +1013,7 @@ void OMW::Engine::go() Misc::Rng::init(mRandomSeed); - Settings::ShaderManager::get().load((mCfgMgr.getUserConfigPath() / "shaders.yaml").string()); + Settings::ShaderManager::get().load(mCfgMgr.getUserConfigPath() / "shaders.yaml"); MWClass::registerClasses(); @@ -1033,13 +1032,13 @@ void OMW::Engine::go() prepareEngine(); std::ofstream stats; - if (const auto path = std::getenv("OPENMW_OSG_STATS_FILE")) + if (const auto path = std::getenv("OPENMW_OSG_STATS_FILE")) //TODO(Project579): This will probably break in windows with unicode paths { - stats.open(path, std::ios_base::out); + stats.open(path, std::ios_base::out); //TODO(Project579): This will probably break in windows with unicode paths if (stats.is_open()) - Log(Debug::Info) << "Stats will be written to: " << path; + Log(Debug::Info) << "Stats will be written to: " << path; //TODO(Project579): This will probably break in windows with unicode paths else - Log(Debug::Warning) << "Failed to open file for stats: " << path; + Log(Debug::Warning) << "Failed to open file for stats: " << path; //TODO(Project579): This will probably break in windows with unicode paths } // Setup profiler @@ -1136,9 +1135,9 @@ void OMW::Engine::go() luaWorker.join(); // Save user settings - Settings::Manager::saveUser((mCfgMgr.getUserConfigPath() / "settings.cfg").string()); + Settings::Manager::saveUser(mCfgMgr.getUserConfigPath() / "settings.cfg"); Settings::ShaderManager::get().save(); - mLuaManager->savePermanentStorage(mCfgMgr.getUserConfigPath().string()); + mLuaManager->savePermanentStorage(mCfgMgr.getUserConfigPath()); Log(Debug::Info) << "Quitting peacefully."; } @@ -1193,7 +1192,7 @@ void OMW::Engine::setScriptBlacklistUse (bool use) mScriptBlacklistUse = use; } -void OMW::Engine::setSaveGameFile(const std::string &savegame) +void OMW::Engine::setSaveGameFile(const std::filesystem::path &savegame) { mSaveGameFile = savegame; } diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index cc3f92cdd2..98d667dc43 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -158,7 +158,7 @@ namespace OMW bool mScriptConsoleMode; std::string mStartupScript; int mActivationDistanceOverride; - std::string mSaveGameFile; + std::filesystem::path mSaveGameFile; // Grab mouse? bool mGrab; @@ -256,7 +256,7 @@ namespace OMW void setScriptBlacklistUse (bool use); /// Set the save game file to load after initialising the engine. - void setSaveGameFile(const std::string& savegame); + void setSaveGameFile(const std::filesystem::path &savegame); void setRandomSeed(unsigned int seed); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index f13d1b39b5..c327683bee 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -61,7 +61,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat { cfgMgr.readConfiguration(variables, desc, true); - Version::Version v = Version::getOpenmwVersion(variables["resources"].as().string()); + Version::Version v = Version::getOpenmwVersion(variables["resources"].as()); getRawStdout() << v.describe() << std::endl; return false; } @@ -69,10 +69,10 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat cfgMgr.readConfiguration(variables, desc); Settings::Manager::load(cfgMgr); - setupLogging(cfgMgr.getLogPath().string(), "OpenMW"); + setupLogging(cfgMgr.getLogPath(), "OpenMW"); MWGui::DebugWindow::startLogRecording(); - Version::Version v = Version::getOpenmwVersion(variables["resources"].as().string()); + Version::Version v = Version::getOpenmwVersion(variables["resources"].as()); Log(Debug::Info) << v.describe(); engine.setGrabMouse(!variables["no-grab"].as()); @@ -150,7 +150,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setWarningsMode (variables["script-warn"].as()); engine.setScriptBlacklist (variables["script-blacklist"].as()); engine.setScriptBlacklistUse (variables["script-blacklist-use"].as()); - engine.setSaveGameFile (variables["load-savegame"].as().string()); + engine.setSaveGameFile (variables["load-savegame"].as()); // other settings Fallback::Map::init(variables["fallback"].as().mMap); diff --git a/apps/openmw/mwbase/statemanager.hpp b/apps/openmw/mwbase/statemanager.hpp index c18db4190d..df4df0943d 100644 --- a/apps/openmw/mwbase/statemanager.hpp +++ b/apps/openmw/mwbase/statemanager.hpp @@ -62,12 +62,12 @@ namespace MWBase /// /// \note Slot must belong to the current character. - virtual void loadGame (const std::string& filepath) = 0; + virtual void loadGame (const std::filesystem::path &filepath) = 0; ///< Load a saved game directly from the given file path. This will search the CharacterManager /// for a Character containing this save file, and set this Character current if one was found. /// Otherwise, a new Character will be created. - virtual void loadGame (const MWState::Character *character, const std::string& filepath) = 0; + virtual void loadGame (const MWState::Character *character, const std::filesystem::path &filepath) = 0; ///< Load a saved game file belonging to the given character. ///Simple saver, writes over the file if already existing diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index e463c812c2..a99adb771e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -639,7 +639,7 @@ 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; + virtual std::filesystem::path 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/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 413e677917..69082bd6bb 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -200,7 +200,7 @@ namespace MWGui if (mCurrentCharacter == &*it || (!mCurrentCharacter && !mSaving && directory==Misc::StringUtils::lowerCase ( - it->begin()->mPath.parent_path().filename().string()))) + it->begin()->mPath.parent_path().filename().string()))) //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break { mCurrentCharacter = &*it; selectedIndex = mCharacterSelection->getItemCount()-1; @@ -303,7 +303,7 @@ namespace MWGui else { assert (mCurrentCharacter && mCurrentSlot); - MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot->mPath.string()); + MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot->mPath); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 51867fc322..8889c970c1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -120,7 +120,7 @@ namespace MWGui { WindowManager::WindowManager( SDL_Window* window, osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, - const std::string& logpath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, + const std::filesystem::path& logpath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, const std::string& versionDescription, bool useShaders) : mOldUpdateMask(0) , mOldCullMask(0) @@ -180,7 +180,7 @@ namespace MWGui mScalingFactor = std::clamp(Settings::Manager::getFloat("scaling factor", "GUI"), 0.5f, 8.f); mGuiPlatform = std::make_unique(viewer, guiRoot, resourceSystem->getImageManager(), resourceSystem->getVFS(), mScalingFactor, "mygui", - (std::filesystem::path(logpath) / "MyGUI.log").generic_string()); + logpath / "MyGUI.log"); mGui = std::make_unique(); mGui->initialise(""); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 107bfdeb75..162f3403aa 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -37,6 +37,7 @@ #include #include #include +#include namespace MyGUI { @@ -124,7 +125,7 @@ namespace MWGui typedef std::vector FactionList; WindowManager(SDL_Window* window, osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, - const std::string& logpath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, + const std::filesystem::path& logpath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, const std::string& versionDescription, bool useShaders); virtual ~WindowManager(); diff --git a/apps/openmw/mwinput/bindingsmanager.cpp b/apps/openmw/mwinput/bindingsmanager.cpp index a1b4845250..376a8a145f 100644 --- a/apps/openmw/mwinput/bindingsmanager.cpp +++ b/apps/openmw/mwinput/bindingsmanager.cpp @@ -43,8 +43,8 @@ namespace MWInput class InputControlSystem : public ICS::InputControlSystem { public: - InputControlSystem(const std::string& bindingsFile) - : ICS::InputControlSystem(bindingsFile, true, nullptr, nullptr, A_Last) + InputControlSystem(const std::filesystem::path &bindingsFile) + : ICS::InputControlSystem(bindingsFile.string(), true, nullptr, nullptr, A_Last) //TODO(Project579): This is probably broken on windows with unicode paths { } }; @@ -167,11 +167,11 @@ namespace MWInput bool mDetectingKeyboard; }; - BindingsManager::BindingsManager(const std::string& userFile, bool userFileExists) + BindingsManager::BindingsManager(const std::filesystem::path &userFile, bool userFileExists) : mUserFile(userFile) , mDragDrop(false) { - std::string file = userFileExists ? userFile : ""; + const auto file = userFileExists ? userFile : std::filesystem::path(); mInputBinder = std::make_unique(file); mListener = std::make_unique(mInputBinder.get(), this); mInputBinder->setDetectingBindingListener(mListener.get()); @@ -192,7 +192,7 @@ namespace MWInput BindingsManager::~BindingsManager() { - mInputBinder->save(mUserFile); + mInputBinder->save(mUserFile.string()); //TODO(Project579): This will probably break in windows with unicode paths } void BindingsManager::update(float dt) diff --git a/apps/openmw/mwinput/bindingsmanager.hpp b/apps/openmw/mwinput/bindingsmanager.hpp index 3808a21dfd..a3b3825b99 100644 --- a/apps/openmw/mwinput/bindingsmanager.hpp +++ b/apps/openmw/mwinput/bindingsmanager.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -15,7 +16,7 @@ namespace MWInput class BindingsManager { public: - BindingsManager(const std::string& userFile, bool userFileExists); + BindingsManager(const std::filesystem::path &userFile, bool userFileExists); virtual ~BindingsManager(); @@ -70,7 +71,7 @@ namespace MWInput std::unique_ptr mInputBinder; std::unique_ptr mListener; - std::string mUserFile; + std::filesystem::path mUserFile; bool mDragDrop; }; diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index adc62a80c5..c95a924280 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -27,8 +27,8 @@ namespace MWInput ControllerManager::ControllerManager(BindingsManager* bindingsManager, ActionManager* actionManager, MouseManager* mouseManager, - const std::string& userControllerBindingsFile, - const std::string& controllerBindingsFile) + const std::filesystem::path &userControllerBindingsFile, + const std::filesystem::path &controllerBindingsFile) : mBindingsManager(bindingsManager) , mActionManager(actionManager) , mMouseManager(mouseManager) @@ -43,12 +43,12 @@ namespace MWInput { if (!controllerBindingsFile.empty()) { - SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.c_str()); + SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths } if (!userControllerBindingsFile.empty()) { - SDL_GameControllerAddMappingsFromFile(userControllerBindingsFile.c_str()); + SDL_GameControllerAddMappingsFromFile(userControllerBindingsFile.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths } // Open all presently connected sticks diff --git a/apps/openmw/mwinput/controllermanager.hpp b/apps/openmw/mwinput/controllermanager.hpp index 2472128c26..ea89c8aec3 100644 --- a/apps/openmw/mwinput/controllermanager.hpp +++ b/apps/openmw/mwinput/controllermanager.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace MWInput { @@ -18,8 +19,8 @@ namespace MWInput ControllerManager(BindingsManager* bindingsManager, ActionManager* actionManager, MouseManager* mouseManager, - const std::string& userControllerBindingsFile, - const std::string& controllerBindingsFile); + const std::filesystem::path &userControllerBindingsFile, + const std::filesystem::path &controllerBindingsFile); virtual ~ControllerManager() = default; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9a7b84722a..abe9996e01 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -28,8 +28,8 @@ namespace MWInput osg::ref_ptr viewer, osg::ref_ptr screenCaptureHandler, osgViewer::ScreenCaptureHandler::CaptureOperation *screenCaptureOperation, - const std::string& userFile, bool userFileExists, const std::string& userControllerBindingsFile, - const std::string& controllerBindingsFile, bool grab) + const std::filesystem::path &userFile, bool userFileExists, const std::filesystem::path &userControllerBindingsFile, + const std::filesystem::path &controllerBindingsFile, bool grab) : mControlsDisabled(false) , mInputWrapper(std::make_unique(window, viewer, grab)) , mBindingsManager(std::make_unique(userFile, userFileExists)) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 738ff98bdf..d31aeff51b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -8,6 +8,7 @@ #include #include +#include #include "../mwbase/inputmanager.hpp" @@ -52,9 +53,9 @@ namespace MWInput osg::ref_ptr viewer, osg::ref_ptr screenCaptureHandler, osgViewer::ScreenCaptureHandler::CaptureOperation *screenCaptureOperation, - const std::string& userFile, bool userFileExists, - const std::string& userControllerBindingsFile, - const std::string& controllerBindingsFile, bool grab); + const std::filesystem::path &userFile, bool userFileExists, + const std::filesystem::path &userControllerBindingsFile, + const std::filesystem::path &controllerBindingsFile, bool grab); ~InputManager() final; diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 2864f3c6dd..2c8754375c 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -31,7 +31,7 @@ namespace MWLua { - LuaManager::LuaManager(const VFS::Manager* vfs, const std::string& libsDir) + LuaManager::LuaManager(const VFS::Manager* vfs, const std::filesystem::path &libsDir) : mLua(vfs, &mConfiguration) , mUiResourceManager(vfs) , mL10n(vfs, &mLua) @@ -110,21 +110,20 @@ namespace MWLua return mL10n.translate(contextName, key); } - void LuaManager::loadPermanentStorage(const std::string& userConfigPath) + void LuaManager::loadPermanentStorage(const std::filesystem::path &userConfigPath) { - auto globalPath = std::filesystem::path(userConfigPath) / "global_storage.bin"; - auto playerPath = std::filesystem::path(userConfigPath) / "player_storage.bin"; + const auto globalPath = userConfigPath / "global_storage.bin"; + const auto playerPath = userConfigPath / "player_storage.bin"; if (std::filesystem::exists(globalPath)) - mGlobalStorage.load(globalPath.string()); + mGlobalStorage.load(globalPath); if (std::filesystem::exists(playerPath)) - mPlayerStorage.load(playerPath.string()); + mPlayerStorage.load(playerPath); } - void LuaManager::savePermanentStorage(const std::string& userConfigPath) + void LuaManager::savePermanentStorage(const std::filesystem::path &userConfigPath) { - std::filesystem::path confDir(userConfigPath); - mGlobalStorage.save((confDir / "global_storage.bin").string()); - mPlayerStorage.save((confDir / "player_storage.bin").string()); + mGlobalStorage.save(userConfigPath / "global_storage.bin"); + mPlayerStorage.save(userConfigPath / "player_storage.bin"); } void LuaManager::update() diff --git a/apps/openmw/mwlua/luamanagerimp.hpp b/apps/openmw/mwlua/luamanagerimp.hpp index 40829e8958..8c4c6f4d95 100644 --- a/apps/openmw/mwlua/luamanagerimp.hpp +++ b/apps/openmw/mwlua/luamanagerimp.hpp @@ -11,6 +11,7 @@ #include #include +#include #include "../mwbase/luamanager.hpp" @@ -26,7 +27,7 @@ namespace MWLua class LuaManager : public MWBase::LuaManager { public: - LuaManager(const VFS::Manager* vfs, const std::string& libsDir); + LuaManager(const VFS::Manager* vfs, const std::filesystem::path &libsDir); // Called by engine.cpp before UI setup. void initL10n(); @@ -34,8 +35,8 @@ namespace MWLua // Called by engine.cpp when the environment is fully initialized. void init(); - void loadPermanentStorage(const std::string& userConfigPath); - void savePermanentStorage(const std::string& userConfigPath); + void loadPermanentStorage(const std::filesystem::path &userConfigPath); + void savePermanentStorage(const std::filesystem::path &userConfigPath); // Called by engine.cpp every frame. For performance reasons it works in a separate // thread (in parallel with osg Cull). Can not use scene graph. diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index 82cfb50a71..be84d8fdff 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -218,11 +218,11 @@ namespace MWRender for (const auto& name : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir)) { std::filesystem::path path = name; - std::string fileExt = Misc::StringUtils::lowerCase(path.extension().string()); + std::string fileExt = Misc::StringUtils::lowerCase(path.extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break if (!path.parent_path().has_parent_path() && fileExt == fx::Technique::sExt) { - auto absolutePath = std::filesystem::path(mVFS->getAbsoluteFileName(name)); - mTechniqueFileMap[absolutePath.stem().string()] = absolutePath; + const auto absolutePath = mVFS->getAbsoluteFileName(name); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + mTechniqueFileMap[absolutePath.stem().string()] = absolutePath; //TODO(Project579): This will probably break in windows with unicode paths } } } @@ -387,7 +387,7 @@ namespace MWRender std::this_thread::sleep_for(std::chrono::milliseconds(5)); if (technique->compile()) - Log(Debug::Info) << "Reloaded technique : " << mTechniqueFileMap[technique->getName()].string(); + Log(Debug::Info) << "Reloaded technique : " << mTechniqueFileMap[technique->getName()].string(); //TODO(Project579): This will probably break in windows with unicode paths mReload = technique->isValid(); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4dbbb5dc91..3662e13283 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -369,7 +369,7 @@ namespace MWRender }; RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, - Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, const std::string& resourcePath, + Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, const std::filesystem::path& resourcePath, DetourNavigator::Navigator& navigator, const MWWorld::GroundcoverStore& groundcoverStore, SceneUtil::UnrefQueue& unrefQueue) : mSkyBlending(Settings::Manager::getBool("sky blending", "Fog")) @@ -1526,7 +1526,7 @@ namespace MWRender updateProjectionMatrix(); } } - void RenderingManager::exportSceneGraph(const MWWorld::Ptr &ptr, const std::string &filename, const std::string &format) + void RenderingManager::exportSceneGraph(const MWWorld::Ptr &ptr, const std::filesystem::path& filename, const std::string &format) { osg::Node* node = mViewer->getSceneData(); if (!ptr.isEmpty()) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 68a77c39f3..2f7a1f0a51 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -102,7 +102,7 @@ namespace MWRender { public: RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, - Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, const std::string& resourcePath, + Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, const std::filesystem::path& resourcePath, DetourNavigator::Navigator& navigator, const MWWorld::GroundcoverStore& groundcoverStore, SceneUtil::UnrefQueue& unrefQueue); ~RenderingManager(); @@ -232,7 +232,7 @@ namespace MWRender osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& object) const; - void exportSceneGraph(const MWWorld::Ptr& ptr, const std::string& filename, const std::string& format); + void exportSceneGraph(const MWWorld::Ptr& ptr, const std::filesystem::path& filename, const std::string& format); LandManager* getLandManager() const; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 8de9191868..8ad7997c2e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -238,21 +238,21 @@ private: float mRainIntensity; }; -osg::ref_ptr readPngImage (const std::string& file) +osg::ref_ptr readPngImage (const std::filesystem::path& file) { std::ifstream inStream; inStream.open(file, std::ios_base::in | std::ios_base::binary); if (inStream.fail()) - Log(Debug::Error) << "Error: Failed to open " << file; + Log(Debug::Error) << "Error: Failed to open " << file; //TODO(Project579): This will probably break in windows with unicode paths osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); if (!reader) { - Log(Debug::Error) << "Error: Failed to read " << file << ", no png readerwriter found"; + Log(Debug::Error) << "Error: Failed to read " << file << ", no png readerwriter found"; //TODO(Project579): This will probably break in windows with unicode paths return osg::ref_ptr(); } osgDB::ReaderWriter::ReadResult result = reader->readImage(inStream); if (!result.success()) - Log(Debug::Error) << "Error: Failed to read " << file << ": " << result.message() << " code " << result.status(); + Log(Debug::Error) << "Error: Failed to read " << file << ": " << result.message() << " code " << result.status(); //TODO(Project579): This will probably break in windows with unicode paths return result.getImage(); } @@ -444,7 +444,7 @@ public: }; Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, - osgUtil::IncrementalCompileOperation *ico, const std::string& resourcePath) + osgUtil::IncrementalCompileOperation *ico, const std::filesystem::path& resourcePath) : mRainIntensityUpdater(nullptr) , mParent(parent) , mSceneRoot(sceneRoot) @@ -695,7 +695,7 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R osg::ref_ptr fragmentShader(shaderMgr.getShader("water_fragment.glsl", defineMap, osg::Shader::FRAGMENT)); osg::ref_ptr program = shaderMgr.getProgram(vertexShader, fragmentShader); - osg::ref_ptr normalMap(new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); + osg::ref_ptr normalMap(new osg::Texture2D(readPngImage(mResourcePath / "shaders" / "water_nm.png"))); if (normalMap->getImage()) normalMap->getImage()->flipVertical(); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index c7acbf708f..8309566031 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -65,7 +65,7 @@ namespace MWRender osg::ref_ptr mRefraction; osg::ref_ptr mReflection; - const std::string mResourcePath; + const std::filesystem::path mResourcePath; bool mEnabled; bool mToggled; @@ -90,7 +90,7 @@ namespace MWRender public: Water(osg::Group* parent, osg::Group* sceneRoot, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, - const std::string& resourcePath); + const std::filesystem::path& resourcePath); ~Water(); void setCullCallback(osg::Callback* callback); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index a005594490..eb82eb9d2e 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1527,8 +1527,8 @@ namespace MWScript runtime.getContext().report("Exporting the entire scene graph will result in a large file. Confirm this action using 'showscenegraph 1' or select an object instead."); else { - const std::string& filename = MWBase::Environment::get().getWorld()->exportSceneGraph(ptr); - runtime.getContext().report("Wrote '" + filename + "'"); + const auto filename = MWBase::Environment::get().getWorld()->exportSceneGraph(ptr); + runtime.getContext().report("Wrote '" + filename.string() + "'"); //TODO(Project579): This will probably break in windows with unicode paths } } }; diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index 0d90ab121a..136adfec89 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -33,7 +33,7 @@ void MWState::Character::addSlot (const std::filesystem::path& path, const std:: slot.mTimeStamp = std::filesystem::last_write_time (path); ESM::ESMReader reader; - reader.open (slot.mPath.string()); + reader.open (slot.mPath); if (reader.getRecName()!=ESM::REC_SAVE) return; // invalid save file -> ignore @@ -91,13 +91,11 @@ MWState::Character::Character (std::filesystem::path saves, const std::string& g } else { - for (std::filesystem::directory_iterator iter (mPath); iter!=std::filesystem::directory_iterator(); ++iter) + for (const auto& iter : std::filesystem::directory_iterator (mPath)) { - std::filesystem::path slotPath = *iter; - try { - addSlot (slotPath, game); + addSlot (iter, game); } catch (...) {} // ignoring bad saved game files for now } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 2b80063265..3142b495a4 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -305,7 +305,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot throw std::runtime_error("Write operation failed (file stream)"); Settings::Manager::setString ("character", "Saves", - slot->mPath.parent_path().filename().string()); + slot->mPath.parent_path().filename().string()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break const auto finish = std::chrono::steady_clock::now(); @@ -364,15 +364,15 @@ void MWState::StateManager::quickSave (std::string name) saveGame(name, saveFinder.getNextQuickSaveSlot()); } -void MWState::StateManager::loadGame(const std::string& filepath) +void MWState::StateManager::loadGame(const std::filesystem::path &filepath) { for (const auto& character : mCharacterManager) { for (const auto& slot : character) { - if (slot.mPath == std::filesystem::path(filepath)) + if (slot.mPath == filepath) { - loadGame(&character, slot.mPath.string()); + loadGame(&character, slot.mPath); return; } } @@ -382,13 +382,13 @@ void MWState::StateManager::loadGame(const std::string& filepath) loadGame(character, filepath); } -void MWState::StateManager::loadGame (const Character *character, const std::string& filepath) +void MWState::StateManager::loadGame (const Character *character, const std::filesystem::path &filepath) { try { cleanup(); - Log(Debug::Info) << "Reading save file " << std::filesystem::path(filepath).filename().string(); + Log(Debug::Info) << "Reading save file " << filepath.filename(); //TODO(Project579): This will probably break in windows with unicode paths ESM::ESMReader reader; reader.open (filepath); @@ -521,7 +521,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str if (character) Settings::Manager::setString ("character", "Saves", - character->getPath().filename().string()); + character->getPath().filename().string()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break MWBase::Environment::get().getWindowManager()->setNewGame(false); MWBase::Environment::get().getWorld()->saveLoaded(); @@ -593,7 +593,7 @@ void MWState::StateManager::quickLoad() { if (currentCharacter->begin() == currentCharacter->end()) return; - loadGame (currentCharacter, currentCharacter->begin()->mPath.string()); //Get newest save + loadGame (currentCharacter, currentCharacter->begin()->mPath); //Get newest save } } @@ -632,7 +632,7 @@ void MWState::StateManager::update (float duration) //Load last saved game for current character MWState::Slot lastSave = *curCharacter->begin(); - loadGame(curCharacter, lastSave.mPath.string()); + loadGame(curCharacter, lastSave.mPath); } else if(iButton==1) { diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index ae1b592cfe..0097a9c490 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -66,12 +66,12 @@ namespace MWState /** Used for quickload **/ void quickLoad() override; - void loadGame (const std::string& filepath) override; + void loadGame (const std::filesystem::path &filepath) override; ///< Load a saved game directly from the given file path. This will search the CharacterManager /// for a Character containing this save file, and set this Character current if one was found. /// Otherwise, a new Character will be created. - void loadGame (const Character *character, const std::string &filepath) override; + void loadGame (const Character *character, const std::filesystem::path &filepath) override; ///< Load a saved game file belonging to the given character. Character *getCurrentCharacter () override; diff --git a/apps/openmw/mwworld/esmloader.cpp b/apps/openmw/mwworld/esmloader.cpp index 4fe1df72f8..861401d60e 100644 --- a/apps/openmw/mwworld/esmloader.cpp +++ b/apps/openmw/mwworld/esmloader.cpp @@ -22,13 +22,13 @@ void EsmLoader::load(const std::filesystem::path& filepath, int& index, Loading: reader->setEncoder(mEncoder); reader->setIndex(index); - reader->open(filepath.string()); + reader->open(filepath); reader->resolveParentFileIndices(mReaders); assert(reader->getGameFiles().size() == reader->getParentFileIndices().size()); for (std::size_t i = 0, n = reader->getParentFileIndices().size(); i < n; ++i) if (i == static_cast(reader->getIndex())) - throw std::runtime_error("File " + reader->getName() + " asks for parent file " + throw std::runtime_error("File " + reader->getName().string() + " asks for parent file " //TODO(Project579): This will probably break in windows with unicode paths + reader->getGameFiles()[i].name + ", but it is not available or has been loaded in the wrong order. " "Please run the launcher to fix this issue."); @@ -36,8 +36,8 @@ void EsmLoader::load(const std::filesystem::path& filepath, int& index, Loading: mESMVersions[index] = reader->getVer(); mStore.load(*reader, listener, mDialogue); - if (!mMasterFileFormat.has_value() && (Misc::StringUtils::ciEndsWith(reader->getName(), ".esm") - || Misc::StringUtils::ciEndsWith(reader->getName(), ".omwgame"))) + if (!mMasterFileFormat.has_value() && (Misc::StringUtils::ciEndsWith(reader->getName().string(), ".esm") //TODO(Project579): This will probably break in windows with unicode paths + || Misc::StringUtils::ciEndsWith(reader->getName().string(), ".omwgame"))) //TODO(Project579): This will probably break in windows with unicode paths mMasterFileFormat = reader->getFormat(); } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 9316dd6c40..d133efd2ac 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -321,13 +321,13 @@ ESM::LuaScriptsCfg ESMStore::getLuaScriptsCfg() const ESM::LuaScriptsCfg cfg; for (const LuaContent& c : mLuaContent) { - if (std::holds_alternative(c)) + if (std::holds_alternative(c)) { // *.omwscripts are intentionally reloaded every time when `getLuaScriptsCfg` is called. // It is important for the `reloadlua` console command. try { - auto file = std::ifstream(std::get(c)); + auto file = std::ifstream(std::get(c)); std::string fileContent(std::istreambuf_iterator(file), {}); LuaUtil::parseOMWScripts(cfg, fileContent); } diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index a4fcf80303..c5a860a823 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -159,11 +160,11 @@ namespace MWWorld using LuaContent = std::variant< ESM::LuaScriptsCfg, // data from an omwaddon - std::string>; // path to an omwscripts file + std::filesystem::path>; // path to an omwscripts file std::vector mLuaContent; public: - void addOMWScripts(std::string filePath) { mLuaContent.push_back(std::move(filePath)); } + void addOMWScripts(std::filesystem::path filePath) { mLuaContent.push_back(std::move(filePath)); } ESM::LuaScriptsCfg getLuaScriptsCfg() const; /// \todo replace with SharedIterator diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1a10a53954..b0828fd69a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -104,10 +104,10 @@ namespace MWWorld void load(const std::filesystem::path& filepath, int& index, Loading::Listener* listener) override { - const auto it = mLoaders.find(Misc::StringUtils::lowerCase(filepath.extension().string())); + const auto it = mLoaders.find(Misc::StringUtils::lowerCase(filepath.extension().string())); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break if (it != mLoaders.end()) { - const std::string filename = filepath.filename().string(); + const std::string filename = filepath.filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break Log(Debug::Info) << "Loading content file " << filename; if (listener != nullptr) listener->setLabel(MyGUI::TextIterator::toTagsString(filename)); @@ -116,7 +116,7 @@ namespace MWWorld else { std::string msg("Cannot load file: "); - msg += filepath.string(); + msg += filepath.string(); //TODO(Project579): This will probably break in windows with unicode paths throw std::runtime_error(msg.c_str()); } } @@ -131,7 +131,7 @@ namespace MWWorld OMWScriptsLoader(ESMStore& store) : mStore(store) {} void load(const std::filesystem::path& filepath, int& /*index*/, Loading::Listener* /*listener*/) override { - mStore.addOMWScripts(filepath.string()); + mStore.addOMWScripts(filepath); } }; @@ -156,7 +156,7 @@ namespace MWWorld const std::vector& groundcoverFiles, ToUTF8::Utf8Encoder* encoder, int activationDistanceOverride, const std::string& startCell, const std::string& startupScript, - const std::string& resourcePath, const std::string& userDataPath) + const std::filesystem::path& resourcePath, const std::filesystem::path& userDataPath) : mResourceSystem(resourceSystem), mLocalScripts(mStore), mCells(mStore, mReaders), mSky(true), mGodMode(false), mScriptsEnabled(true), mDiscardMovements(true), mContentFiles (contentFiles), @@ -2964,7 +2964,7 @@ namespace MWWorld for (const std::string &file : content) { std::filesystem::path filename(file); - const Files::MultiDirCollection& col = fileCollections.getCollection(filename.extension().string()); + const Files::MultiDirCollection& col = fileCollections.getCollection(filename.extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break if (col.doesExist(file)) { gameContentLoader.load(col.getPath(file), idx, listener); @@ -3694,9 +3694,9 @@ namespace MWWorld return mPhysics->getHalfExtents(object); } - std::string World::exportSceneGraph(const Ptr &ptr) + std::filesystem::path World::exportSceneGraph(const Ptr& ptr) { - std::string file = mUserDataPath + "/openmw.osgt"; + auto file = mUserDataPath / "openmw.osgt"; if (!ptr.isEmpty()) { mRendering->pagingBlacklistObject(mStore.find(ptr.getCellRef().getRefId()), ptr); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e6085b7f79..c6bde113f4 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -109,7 +109,7 @@ namespace MWWorld bool mDiscardMovements; std::vector mContentFiles; - std::string mUserDataPath; + std::filesystem::path mUserDataPath; osg::Vec3f mDefaultHalfExtents; DetourNavigator::CollisionShapeType mDefaultActorCollisionShapeType; @@ -203,7 +203,7 @@ namespace MWWorld const std::vector& groundcoverFiles, ToUTF8::Utf8Encoder* encoder, int activationDistanceOverride, const std::string& startCell, const std::string& startupScript, - const std::string& resourcePath, const std::string& userDataPath); + const std::filesystem::path& resourcePath, const std::filesystem::path& userDataPath); virtual ~World(); @@ -730,7 +730,7 @@ 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) - std::string exportSceneGraph(const MWWorld::Ptr& ptr) override; + std::filesystem::path exportSceneGraph(const MWWorld::Ptr& ptr) override; /// Preload VFX associated with this effect list void preloadEffects(const ESM::EffectList* effectList) override; diff --git a/apps/openmw_test_suite/esm3/readerscache.cpp b/apps/openmw_test_suite/esm3/readerscache.cpp index 720b66a04f..826b803b8f 100644 --- a/apps/openmw_test_suite/esm3/readerscache.cpp +++ b/apps/openmw_test_suite/esm3/readerscache.cpp @@ -42,7 +42,7 @@ namespace const Files::PathContainer mDataDirs {{std::string(OPENMW_DATA_DIR)}}; const Files::Collections mFileCollections {mDataDirs, true}; const std::string mContentFile = "template.omwgame"; - const std::string mContentFilePath = mFileCollections.getCollection(".omwgame").getPath(mContentFile).string(); + const std::filesystem::path mContentFilePath = mFileCollections.getCollection(".omwgame").getPath(mContentFile); }; TEST_F(ESM3ReadersCacheWithContentFile, shouldKeepOpenReleasedOpenReader) diff --git a/apps/openmw_test_suite/files/hash.cpp b/apps/openmw_test_suite/files/hash.cpp index f8303ac1f3..dcace6b34e 100644 --- a/apps/openmw_test_suite/files/hash.cpp +++ b/apps/openmw_test_suite/files/hash.cpp @@ -27,7 +27,7 @@ namespace TEST(FilesGetHash, shouldClearErrors) { - const std::string fileName = temporaryFilePath("fileName"); + const auto fileName = temporaryFilePath("fileName"); std::string content; std::fill_n(std::back_inserter(content), 1, 'a'); std::istringstream stream(content); @@ -37,7 +37,7 @@ namespace TEST_P(FilesGetHash, shouldReturnHashForStringStream) { - const std::string fileName = temporaryFilePath("fileName"); + const auto fileName = temporaryFilePath("fileName"); std::string content; std::fill_n(std::back_inserter(content), GetParam().mSize, 'a'); std::istringstream stream(content); @@ -50,10 +50,10 @@ namespace std::replace(fileName.begin(), fileName.end(), '/', '_'); std::string content; std::fill_n(std::back_inserter(content), GetParam().mSize, 'a'); - fileName = outputFilePath(fileName); + fileName = outputFilePath(fileName).string(); //TODO(Project579): This will probably break in windows with unicode paths std::fstream(fileName, std::ios_base::out | std::ios_base::binary) .write(content.data(), static_cast(content.size())); - const auto stream = Files::openConstrainedFileStream(fileName, 0, content.size()); + const auto stream = Files::openConstrainedFileStream(fileName, 0, content.size()); //TODO(Project579): This will probably break in windows with unicode paths EXPECT_EQ(getHash(fileName, *stream), GetParam().mHash); } diff --git a/apps/openmw_test_suite/lua/test_storage.cpp b/apps/openmw_test_suite/lua/test_storage.cpp index c1d8cc4c4f..364cb9d3f6 100644 --- a/apps/openmw_test_suite/lua/test_storage.cpp +++ b/apps/openmw_test_suite/lua/test_storage.cpp @@ -88,7 +88,7 @@ namespace mLua.safe_script("permanent:set('x', 1)"); mLua.safe_script("temporary:set('y', 2)"); - std::string tmpFile = (std::filesystem::temp_directory_path() / "test_storage.bin").string(); + const auto tmpFile = std::filesystem::temp_directory_path() / "test_storage.bin"; storage.save(tmpFile); EXPECT_EQ(get(mLua, "permanent:get('x')"), 1); EXPECT_EQ(get(mLua, "temporary:get('y')"), 2); diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index edba8b3d3a..b5fbf5a291 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -41,7 +41,7 @@ struct ContentFileTest : public ::testing::Test ESM::ESMReader lEsm; lEsm.setEncoder(nullptr); lEsm.setIndex(index); - lEsm.open(mContentFile.string()); + lEsm.open(mContentFile); mEsmStore.load(lEsm, &dummyListener, dialogue); ++index; @@ -109,7 +109,7 @@ TEST_F(ContentFileTest, dialogue_merging_test) return; } - const std::string file = TestingOpenMW::outputFilePath("test_dialogue_merging.txt"); + const auto file = TestingOpenMW::outputFilePath("test_dialogue_merging.txt"); std::ofstream stream(file); const MWWorld::Store& dialStore = mEsmStore.get(); @@ -124,7 +124,7 @@ TEST_F(ContentFileTest, dialogue_merging_test) stream << std::endl; } - std::cout << "dialogue_merging_test successful, results printed to " << file << std::endl; + std::cout << "dialogue_merging_test successful, results printed to " << file << std::endl; //TODO(Project579): This will probably break in windows with unicode paths } // Note: here we don't test records that don't use string names (e.g. Land, Pathgrid, Cell) @@ -189,12 +189,12 @@ TEST_F(ContentFileTest, content_diagnostics_test) return; } - const std::string file = TestingOpenMW::outputFilePath("test_content_diagnostics.txt"); + const auto file = TestingOpenMW::outputFilePath("test_content_diagnostics.txt"); std::ofstream stream(file); RUN_TEST_FOR_TYPES(printRecords, mEsmStore, stream); - std::cout << "diagnostics_test successful, results printed to " << file << std::endl; + std::cout << "diagnostics_test successful, results printed to " << file << std::endl; //TODO(Project579): This will probably break in windows with unicode paths } // TODO: diff --git a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp index 5c368b4e7e..b2570f7704 100644 --- a/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp +++ b/apps/openmw_test_suite/nifloader/testbulletnifloader.cpp @@ -353,7 +353,7 @@ namespace MOCK_METHOD(std::string, getString, (uint32_t), (const, override)); MOCK_METHOD(void, setUseSkinning, (bool), (override)); MOCK_METHOD(bool, getUseSkinning, (), (const, override)); - MOCK_METHOD(std::string, getFilename, (), (const, override)); + MOCK_METHOD(std::filesystem::path, getFilename, (), (const, override)); MOCK_METHOD(std::string, getHash, (), (const, override)); MOCK_METHOD(unsigned int, getVersion, (), (const, override)); MOCK_METHOD(unsigned int, getUserVersion, (), (const, override)); diff --git a/apps/openmw_test_suite/settings/parser.cpp b/apps/openmw_test_suite/settings/parser.cpp index 7e250b43aa..33d6b24ded 100644 --- a/apps/openmw_test_suite/settings/parser.cpp +++ b/apps/openmw_test_suite/settings/parser.cpp @@ -19,7 +19,7 @@ namespace template void withSettingsFile( const std::string& content, F&& f) { - std::string path = TestingOpenMW::outputFilePath( + auto path = TestingOpenMW::outputFilePath( std::string(UnitTest::GetInstance()->current_test_info()->name()) + ".cfg"); { diff --git a/apps/openmw_test_suite/settings/shadermanager.cpp b/apps/openmw_test_suite/settings/shadermanager.cpp index e4f40aaa03..1ed3e7a48c 100644 --- a/apps/openmw_test_suite/settings/shadermanager.cpp +++ b/apps/openmw_test_suite/settings/shadermanager.cpp @@ -17,7 +17,7 @@ namespace template void withSettingsFile( const std::string& content, F&& f) { - std::string path = TestingOpenMW::outputFilePath( + auto path = TestingOpenMW::outputFilePath( std::string(UnitTest::GetInstance()->current_test_info()->name()) + ".yaml"); { @@ -69,4 +69,4 @@ config: EXPECT_FALSE(ShaderManager::get().save()); }); } -} \ No newline at end of file +} diff --git a/apps/openmw_test_suite/shader/shadermanager.cpp b/apps/openmw_test_suite/shader/shadermanager.cpp index 58ca3b6f3f..9e4808b073 100644 --- a/apps/openmw_test_suite/shader/shadermanager.cpp +++ b/apps/openmw_test_suite/shader/shadermanager.cpp @@ -30,7 +30,7 @@ namespace template void withShaderFile(const std::string& suffix, const std::string& content, F&& f) { - std::string path = TestingOpenMW::outputFilePath( + auto path = TestingOpenMW::outputFilePath( std::string(UnitTest::GetInstance()->current_test_info()->name()) + suffix + ".glsl"); { @@ -47,8 +47,8 @@ namespace { const std::string content; - withShaderFile(content, [this] (const std::string& templateName) { - EXPECT_TRUE(mManager.getShader(templateName, {}, osg::Shader::VERTEX)); + withShaderFile(content, [this] (const std::filesystem::path& templateName) { + EXPECT_TRUE(mManager.getShader(templateName.string(), {}, osg::Shader::VERTEX)); //TODO(Project579): This will probably break in windows with unicode paths }); } @@ -58,8 +58,8 @@ namespace "#version 120\n" "void main() {}\n"; - withShaderFile(content, [&] (const std::string& templateName) { - const auto shader = mManager.getShader(templateName, mDefines, osg::Shader::VERTEX); + withShaderFile(content, [&] (const std::filesystem::path& templateName) { + const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths ASSERT_TRUE(shader); EXPECT_EQ(shader->getShaderSource(), content); }); @@ -70,19 +70,19 @@ namespace const std::string content0 = "void foo() {}\n"; - withShaderFile("_0", content0, [&] (const std::string& templateName0) { + withShaderFile("_0", content0, [&] (const std::filesystem::path& templateName0) { const std::string content1 = - "#include \"" + templateName0 + "\"\n" + "#include \"" + templateName0.string() + "\"\n" //TODO(Project579): This will probably break in windows with unicode paths "void bar() { foo() }\n"; - withShaderFile("_1", content1, [&] (const std::string& templateName1) { + withShaderFile("_1", content1, [&] (const std::filesystem::path& templateName1) { const std::string content2 = "#version 120\n" - "#include \"" + templateName1 + "\"\n" + "#include \"" + templateName1.string() + "\"\n" //TODO(Project579): This will probably break in windows with unicode paths "void main() { bar() }\n"; - withShaderFile(content2, [&] (const std::string& templateName2) { - const auto shader = mManager.getShader(templateName2, mDefines, osg::Shader::VERTEX); + withShaderFile(content2, [&] (const std::filesystem::path& templateName2) { + const auto shader = mManager.getShader(templateName2.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths ASSERT_TRUE(shader); const std::string expected = "#version 120\n" @@ -111,9 +111,9 @@ namespace "void main() {}\n" ; - withShaderFile(content, [&] (const std::string& templateName) { + withShaderFile(content, [&] (const std::filesystem::path& templateName) { mDefines["flag"] = "1"; - const auto shader = mManager.getShader(templateName, mDefines, osg::Shader::VERTEX); + const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths ASSERT_TRUE(shader); const std::string expected = "#version 120\n" @@ -133,9 +133,9 @@ namespace "void main() {}\n" ; - withShaderFile(content, [&] (const std::string& templateName) { + withShaderFile(content, [&] (const std::filesystem::path& templateName) { mDefines["list"] = "1,2,3"; - const auto shader = mManager.getShader(templateName, mDefines, osg::Shader::VERTEX); + const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths ASSERT_TRUE(shader); const std::string expected = "#version 120\n" @@ -174,9 +174,9 @@ namespace "}\n" ; - withShaderFile(content, [&] (const std::string& templateName) { + withShaderFile(content, [&] (const std::filesystem::path& templateName) { mDefines["list"] = "1,2,3"; - const auto shader = mManager.getShader(templateName, mDefines, osg::Shader::VERTEX); + const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths ASSERT_TRUE(shader); const std::string expected = "#version 120\n" @@ -222,8 +222,8 @@ namespace "void main() {}\n" ; - withShaderFile(content, [&] (const std::string& templateName) { - EXPECT_FALSE(mManager.getShader(templateName, mDefines, osg::Shader::VERTEX)); + withShaderFile(content, [&] (const std::filesystem::path& templateName) { + EXPECT_FALSE(mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX)); //TODO(Project579): This will probably break in windows with unicode paths }); } @@ -235,8 +235,8 @@ namespace "void main() {}\n" ; - withShaderFile(content, [&] (const std::string& templateName) { - EXPECT_FALSE(mManager.getShader(templateName, mDefines, osg::Shader::VERTEX)); + withShaderFile(content, [&] (const std::filesystem::path& templateName) { + EXPECT_FALSE(mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX)); //TODO(Project579): This will probably break in windows with unicode paths }); } } diff --git a/apps/openmw_test_suite/testing_util.hpp b/apps/openmw_test_suite/testing_util.hpp index 125d2505ed..7b6b008501 100644 --- a/apps/openmw_test_suite/testing_util.hpp +++ b/apps/openmw_test_suite/testing_util.hpp @@ -10,16 +10,16 @@ namespace TestingOpenMW { - inline std::string outputFilePath(const std::string name) + inline std::filesystem::path outputFilePath(const std::string name) { std::filesystem::path dir("tests_output"); std::filesystem::create_directory(dir); - return (dir / name).string(); + return dir / name; } - inline std::string temporaryFilePath(const std::string name) + inline std::filesystem::path temporaryFilePath(const std::string name) { - return (std::filesystem::temp_directory_path() / name).string(); + return std::filesystem::temp_directory_path() / name; } class VFSTestFile : public VFS::File @@ -32,7 +32,7 @@ namespace TestingOpenMW return std::make_unique(mContent, std::ios_base::in); } - std::string getPath() override + std::filesystem::path getPath() override { return "TestFile"; } diff --git a/apps/wizard/installationtargetpage.cpp b/apps/wizard/installationtargetpage.cpp index f55794ccaf..0a41d57f14 100644 --- a/apps/wizard/installationtargetpage.cpp +++ b/apps/wizard/installationtargetpage.cpp @@ -19,7 +19,7 @@ Wizard::InstallationTargetPage::InstallationTargetPage(QWidget *parent, const Fi void Wizard::InstallationTargetPage::initializePage() { - QString path(QFile::decodeName(mCfgMgr.getUserDataPath().string().c_str())); + QString path(QFile::decodeName(mCfgMgr.getUserDataPath().string().c_str())); //TODO(Project579): This will probably break in windows with unicode paths path.append(QDir::separator() + QLatin1String("basedata")); QDir dir(path); diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index 9544ccfbee..a597b11df8 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -471,5 +471,5 @@ bool Wizard::MainWizard::findFiles(const QString &name, const QString &path) QString Wizard::MainWizard::toQString(const std::filesystem::path& path) { - return QString::fromUtf8(path.string().c_str()); + return QString::fromUtf8(path.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths } diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 9fc6448c2b..65d184cf75 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -37,7 +37,7 @@ using namespace Bsa; /// Error handling [[noreturn]] void BSAFile::fail(const std::string &msg) { - throw std::runtime_error("BSA Error: " + msg + "\nArchive: " + mFilename); + throw std::runtime_error("BSA Error: " + msg + "\nArchive: " + mFilepath.string()); //TODO(Project579): This will probably break in windows with unicode paths } //the getHash code is from bsapack from ghostwheel @@ -100,7 +100,7 @@ void BSAFile::readHeader() */ assert(!mIsLoaded); - std::ifstream input(std::filesystem::path(mFilename), std::ios_base::binary); + std::ifstream input(mFilepath, std::ios_base::binary); // Total archive size std::streamoff fsize = 0; @@ -196,7 +196,7 @@ void BSAFile::readHeader() /// Write header information to the output sink void Bsa::BSAFile::writeHeader() { - std::fstream output(mFilename, std::ios::binary | std::ios::in | std::ios::out); + std::fstream output(mFilepath, std::ios::binary | std::ios::in | std::ios::out); uint32_t head[3]; head[0] = 0x100; @@ -231,17 +231,17 @@ void Bsa::BSAFile::writeHeader() } /// Open an archive file. -void BSAFile::open(const std::string &file) +void BSAFile::open(const std::filesystem::path &file) { if (mIsLoaded) close(); - mFilename = file; + mFilepath = file; if(std::filesystem::exists(file)) readHeader(); else { - { std::fstream(mFilename, std::ios::binary | std::ios::out); } + { std::fstream(mFilepath, std::ios::binary | std::ios::out); } writeHeader(); mIsLoaded = true; } @@ -270,9 +270,9 @@ void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file) auto newStartOfDataBuffer = 12 + (12 + 8) * (mFiles.size() + 1) + mStringBuf.size() + filename.size() + 1; if (mFiles.empty()) - std::filesystem::resize_file(mFilename, newStartOfDataBuffer); + std::filesystem::resize_file(mFilepath, newStartOfDataBuffer); - std::fstream stream(mFilename, std::ios::binary | std::ios::in | std::ios::out); + std::fstream stream(mFilepath, std::ios::binary | std::ios::in | std::ios::out); FileStruct newFile; file.seekg(0, std::ios::end); diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index f6af2e3269..d01fb6d421 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -85,7 +86,7 @@ protected: bool mIsLoaded; /// Used for error messages - std::string mFilename; + std::filesystem::path mFilepath; /// Error handling [[noreturn]] void fail(const std::string &msg); @@ -110,7 +111,7 @@ public: } /// Open an archive file. - void open(const std::string &file); + void open(const std::filesystem::path &file); void close(); @@ -131,9 +132,9 @@ public: const FileList &getList() const { return mFiles; } - const std::string& getFilename() const + std::string getFilename() const { - return mFilename; + return mFilepath.string(); //TODO(Project579): This will probably break in windows with unicode paths } }; diff --git a/components/bsa/compressedbsafile.cpp b/components/bsa/compressedbsafile.cpp index 2d553b0986..337570cad1 100644 --- a/components/bsa/compressedbsafile.cpp +++ b/components/bsa/compressedbsafile.cpp @@ -119,7 +119,7 @@ void CompressedBSAFile::readHeader() { assert(!mIsLoaded); - std::ifstream input(std::filesystem::path(mFilename), std::ios_base::binary); + std::ifstream input(mFilepath, std::ios_base::binary); // Total archive size std::streamoff fsize = 0; @@ -299,17 +299,22 @@ void CompressedBSAFile::readHeader() CompressedBSAFile::FileRecord CompressedBSAFile::getFileRecord(const std::string& str) const { - // Force-convert the path into something both Windows and UNIX can handle first - // to make sure Boost doesn't think the entire path is the filename on Linux +#ifdef _WIN32 + const auto& path = str; +#else + // Force-convert the path into something UNIX can handle first + // to make sure std::filesystem::path doesn't think the entire path is the filename on Linux // and subsequently purge it to determine the file folder. std::string path = str; std::replace(path.begin(), path.end(), '\\', '/'); +#endif std::filesystem::path p(path); std::string stem = p.stem().string(); std::string ext = p.extension().string(); - - std::string folder = p.parent_path().string(); + p.remove_filename(); + + std::string folder = p.string(); std::uint64_t folderHash = generateHash(folder, std::string()); auto it = mFolders.find(folderHash); diff --git a/components/bsa/compressedbsafile.hpp b/components/bsa/compressedbsafile.hpp index 2c0b3c0aac..53dcf8f522 100644 --- a/components/bsa/compressedbsafile.hpp +++ b/components/bsa/compressedbsafile.hpp @@ -29,6 +29,7 @@ #include #include +#include namespace Bsa { @@ -82,7 +83,7 @@ namespace Bsa //mFiles used by OpenMW will contain uncompressed file sizes void convertCompressedSizesToUncompressed(); /// \brief Normalizes given filename or folder and generates format-compatible hash. See https://en.uesp.net/wiki/Tes4Mod:Hash_Calculation. - static std::uint64_t generateHash(std::string stem, std::string extension) ; + static std::uint64_t generateHash(std::filesystem::path stem, std::string extension) ; Files::IStreamPtr getFile(const FileRecord& fileRecord); public: using BSAFile::open; @@ -93,7 +94,7 @@ namespace Bsa virtual ~CompressedBSAFile(); //checks version of BSA from file header - static BsaVersion detectVersion(const std::string& filePath); + static BsaVersion detectVersion(const std::filesystem::path &filePath); /// Read header information from the input source void readHeader() override; diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index aa63c3191e..0fe36720f5 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -32,7 +32,7 @@ void Config::GameSettings::validatePaths() mDataDirs.clear(); for (auto & dataDir : dataDirs) { - QString path = QString::fromUtf8(dataDir.string().c_str()); + QString path = QString::fromUtf8(dataDir.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths QDir dir(path); if (dir.exists()) @@ -57,7 +57,7 @@ void Config::GameSettings::validatePaths() mCfgMgr.processPaths(dataDirs, /*basePath=*/""); if (!dataDirs.empty()) { - QString path = QString::fromUtf8(dataDirs.front().string().c_str()); + QString path = QString::fromUtf8(dataDirs.front().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths QDir dir(path); if (dir.exists()) @@ -65,11 +65,11 @@ void Config::GameSettings::validatePaths() } } -std::string Config::GameSettings::getGlobalDataDir() const +std::filesystem::path Config::GameSettings::getGlobalDataDir() const { // global data dir may not exists if OpenMW is not installed (ie if run from build directory) if (std::filesystem::exists(mCfgMgr.getGlobalDataPath())) - return std::filesystem::canonical(mCfgMgr.getGlobalDataPath()).string(); + return std::filesystem::canonical(mCfgMgr.getGlobalDataPath()); return {}; } diff --git a/components/config/gamesettings.hpp b/components/config/gamesettings.hpp index 961af7657b..c40cc92617 100644 --- a/components/config/gamesettings.hpp +++ b/components/config/gamesettings.hpp @@ -54,7 +54,7 @@ namespace Config } QStringList getDataDirs() const; - std::string getGlobalDataDir() const; + std::filesystem::path getGlobalDataDir() const; inline void removeDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.removeAll(dir); } inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); } diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index 11ced3c145..129d04dcc1 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -119,7 +119,7 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) } // global and local data directories are not part of any profile - const auto globalDataDir = QString(gameSettings.getGlobalDataDir().c_str()); + const auto globalDataDir = QString(gameSettings.getGlobalDataDir().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths const auto dataLocal = gameSettings.getDataLocal(); dirs.removeAll(globalDataDir); dirs.removeAll(dataLocal); diff --git a/components/crashcatcher/crashcatcher.cpp b/components/crashcatcher/crashcatcher.cpp index 65924a0d62..fa45fc259b 100644 --- a/components/crashcatcher/crashcatcher.cpp +++ b/components/crashcatcher/crashcatcher.cpp @@ -559,7 +559,7 @@ static bool is_debugger_present() #endif } -void crashCatcherInstall(int argc, char **argv, const std::string &crashLogPath) +void crashCatcherInstall(int argc, char **argv, const std::filesystem::path &crashLogPath) { if ((argc == 2 && strcmp(argv[1], crash_switch) == 0) || !is_debugger_present()) { diff --git a/components/crashcatcher/crashcatcher.hpp b/components/crashcatcher/crashcatcher.hpp index b693ccae43..b029c5460b 100644 --- a/components/crashcatcher/crashcatcher.hpp +++ b/components/crashcatcher/crashcatcher.hpp @@ -12,7 +12,7 @@ constexpr char crash_switch[] = "--cc-handle-crash"; #if USE_CRASH_CATCHER -extern void crashCatcherInstall(int argc, char **argv, const std::string &crashLogPath); +extern void crashCatcherInstall(int argc, char **argv, const std::filesystem::path &crashLogPath); #else inline void crashCatcherInstall(int, char **, const std::string &crashLogPath) { diff --git a/components/crashcatcher/windows_crashcatcher.cpp b/components/crashcatcher/windows_crashcatcher.cpp index d31fdac578..c62a066c59 100644 --- a/components/crashcatcher/windows_crashcatcher.cpp +++ b/components/crashcatcher/windows_crashcatcher.cpp @@ -9,6 +9,8 @@ #include "windows_crashshm.hpp" #include +#include + namespace Crash { @@ -26,7 +28,7 @@ namespace Crash CrashCatcher* CrashCatcher::sInstance = nullptr; - CrashCatcher::CrashCatcher(int argc, char **argv, const std::string& crashLogPath) + CrashCatcher::CrashCatcher(int argc, char **argv, const std::filesystem::path& crashLogPath) { assert(sInstance == nullptr); // don't allow two instances @@ -124,7 +126,7 @@ namespace Crash SetUnhandledExceptionFilter(vectoredExceptionHandler); } - void CrashCatcher::startMonitorProcess(const std::string& crashLogPath) + void CrashCatcher::startMonitorProcess(const std::filesystem::path& crashLogPath) { std::wstring executablePath; DWORD copied = 0; @@ -135,9 +137,10 @@ namespace Crash executablePath.resize(copied); memset(mShm->mStartup.mLogFilePath, 0, sizeof(mShm->mStartup.mLogFilePath)); - size_t length = crashLogPath.length(); + const auto str = crashLogPath.u8string(); + size_t length = str.length(); if (length >= MAX_LONG_PATH) length = MAX_LONG_PATH - 1; - strncpy(mShm->mStartup.mLogFilePath, crashLogPath.c_str(), length); + strncpy_s(mShm->mStartup.mLogFilePath, sizeof mShm->mStartup.mLogFilePath, Misc::StringUtils::char8_to_char(str.c_str()), length); //TODO(Project579): This will probably break in windows with unicode paths mShm->mStartup.mLogFilePath[length] = '\0'; // note that we don't need to lock the SHM here, the other process has not started yet diff --git a/components/crashcatcher/windows_crashcatcher.hpp b/components/crashcatcher/windows_crashcatcher.hpp index 1133afe69c..4379b34d71 100644 --- a/components/crashcatcher/windows_crashcatcher.hpp +++ b/components/crashcatcher/windows_crashcatcher.hpp @@ -1,7 +1,7 @@ #ifndef WINDOWS_CRASHCATCHER_HPP #define WINDOWS_CRASHCATCHER_HPP -#include +#include #include #include @@ -28,7 +28,7 @@ namespace Crash { public: - CrashCatcher(int argc, char **argv, const std::string& crashLogPath); + CrashCatcher(int argc, char **argv, const std::filesystem::path& crashLogPath); ~CrashCatcher(); private: @@ -56,7 +56,7 @@ namespace Crash void shmUnlock(); - void startMonitorProcess(const std::string& crashLogPath); + void startMonitorProcess(const std::filesystem::path& crashLogPath); void waitMonitor(); diff --git a/components/debug/debugging.cpp b/components/debug/debugging.cpp index 01dcde7bcc..e6f159bf81 100644 --- a/components/debug/debugging.cpp +++ b/components/debug/debugging.cpp @@ -269,7 +269,7 @@ Misc::Locked getLockedRawStderr() } // Redirect cout and cerr to the log file -void setupLogging(const std::string& logDir, const std::string& appName, std::ios_base::openmode mode) +void setupLogging(const std::filesystem::path &logDir, const std::string& appName, std::ios_base::openmode mode) { #if defined(_WIN32) && defined(_DEBUG) // Redirect cout and cerr to VS debug output when running in debug mode @@ -278,7 +278,7 @@ void setupLogging(const std::string& logDir, const std::string& appName, std::io std::cerr.rdbuf(&sb); #else const std::string logName = Misc::StringUtils::lowerCase(appName) + ".log"; - logfile.open(std::filesystem::path(logDir) / logName, mode); + logfile.open(logDir / logName, mode); coutsb.open(Debug::Tee(logfile, *rawStdout)); cerrsb.open(Debug::Tee(logfile, *rawStderr)); @@ -311,7 +311,7 @@ int wrapApplication(int (*innerApplication)(int argc, char *argv[]), int argc, c if (argc == 2 && strcmp(argv[1], crash_switch) == 0) mode |= std::ios::app; - setupLogging(cfgMgr.getLogPath().string(), appName, mode); + setupLogging(cfgMgr.getLogPath(), appName, mode); } if (const auto env = std::getenv("OPENMW_DISABLE_CRASH_CATCHER"); env == nullptr || std::atol(env) == 0) diff --git a/components/debug/debugging.hpp b/components/debug/debugging.hpp index a250c5d837..c144000d3f 100644 --- a/components/debug/debugging.hpp +++ b/components/debug/debugging.hpp @@ -34,7 +34,7 @@ std::ostream& getRawStderr(); Misc::Locked getLockedRawStderr(); -void setupLogging(const std::string& logDir, const std::string& appName, std::ios_base::openmode = std::ios::out); +void setupLogging(const std::filesystem::path &logDir, const std::string& appName, std::ios_base::openmode mode = std::ios::out); int wrapApplication(int (*innerApplication)(int argc, char *argv[]), int argc, char *argv[], const std::string& appName, bool autoSetupLogging = true); diff --git a/components/detournavigator/navigator.cpp b/components/detournavigator/navigator.cpp index d40f330771..200582216d 100644 --- a/components/detournavigator/navigator.cpp +++ b/components/detournavigator/navigator.cpp @@ -7,7 +7,7 @@ namespace DetourNavigator { - std::unique_ptr makeNavigator(const Settings& settings, const std::string& userDataPath) + std::unique_ptr makeNavigator(const Settings& settings, const std::filesystem::path& userDataPath) { DetourNavigator::RecastGlobalAllocator::init(); @@ -16,7 +16,7 @@ namespace DetourNavigator { try { - db = std::make_unique(userDataPath + "/navmesh.db", settings.mMaxDbFileSize); + db = std::make_unique((userDataPath / "navmesh.db").string(), settings.mMaxDbFileSize); //TODO(Project579): This will probably break in windows with unicode paths } catch (const std::exception& e) { diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index f78ce30c2b..f561f38cda 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVIGATOR_H #define OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVIGATOR_H +#include + #include "objectid.hpp" #include "sharednavmeshcacheitem.hpp" #include "recastmeshtiles.hpp" @@ -10,7 +12,6 @@ #include -#include namespace ESM { @@ -195,7 +196,7 @@ namespace DetourNavigator virtual float getMaxNavmeshAreaRealRadius() const = 0; }; - std::unique_ptr makeNavigator(const Settings& settings, const std::string& userDataPath); + std::unique_ptr makeNavigator(const Settings& settings, const std::filesystem::path& userDataPath); std::unique_ptr makeNavigatorStub(); } diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 35c659fb7e..9d57a7304d 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace ESM { @@ -187,7 +188,7 @@ static_assert(sizeof(NAME64) == 64); */ struct ESM_Context { - std::string filename; + std::filesystem::path filename; uint32_t leftRec, leftSub; size_t leftFile; NAME recName, subName; diff --git a/components/esm3/esmreader.cpp b/components/esm3/esmreader.cpp index 84acd193f9..5877951d43 100644 --- a/components/esm3/esmreader.cpp +++ b/components/esm3/esmreader.cpp @@ -73,8 +73,7 @@ void ESMReader::resolveParentFileIndices(ReadersCache& readers) const ESM::ReadersCache::BusyItem reader = readers.get(static_cast(i)); if (reader->getFileSize() == 0) continue; // Content file in non-ESM format - const std::string& candidate = reader->getName(); - std::string fnamecandidate = std::filesystem::path(candidate).filename().string(); + std::string fnamecandidate = reader->getName().filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break if (Misc::StringUtils::ciEqual(fname, fnamecandidate)) { index = i; @@ -85,7 +84,7 @@ void ESMReader::resolveParentFileIndices(ReadersCache& readers) } } -void ESMReader::openRaw(std::unique_ptr&& stream, std::string_view name) +void ESMReader::openRaw(std::unique_ptr&& stream, const std::filesystem::path &name) { close(); mEsm = std::move(stream); @@ -95,12 +94,12 @@ void ESMReader::openRaw(std::unique_ptr&& stream, std::string_view mEsm->seekg(0, mEsm->beg); } -void ESMReader::openRaw(std::string_view filename) +void ESMReader::openRaw(const std::filesystem::path &filename) { - openRaw(Files::openBinaryInputFileStream(std::string(filename)), filename); + openRaw(Files::openBinaryInputFileStream(filename), filename); } -void ESMReader::open(std::unique_ptr&& stream, const std::string &name) +void ESMReader::open(std::unique_ptr&& stream, const std::filesystem::path &name) { openRaw(std::move(stream), name); @@ -112,7 +111,7 @@ void ESMReader::open(std::unique_ptr&& stream, const std::string & mHeader.load (*this); } -void ESMReader::open(const std::string &file) +void ESMReader::open(const std::filesystem::path &file) { open(Files::openBinaryInputFileStream(file), file); } @@ -360,7 +359,7 @@ std::string ESMReader::getString(int size) std::stringstream ss; ss << "ESM Error: " << msg; - ss << "\n File: " << mCtx.filename; + ss << "\n File: " << mCtx.filename; //TODO(Project579): This will probably break in windows with unicode paths ss << "\n Record: " << mCtx.recName.toStringView(); ss << "\n Subrecord: " << mCtx.subName.toStringView(); if (mEsm.get()) diff --git a/components/esm3/esmreader.hpp b/components/esm3/esmreader.hpp index 5a58e9d165..521c1fc75d 100644 --- a/components/esm3/esmreader.hpp +++ b/components/esm3/esmreader.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -38,7 +39,7 @@ public: int getFormat() const { return mHeader.mFormat; }; const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } - const std::string& getName() const { return mCtx.filename; }; + const std::filesystem::path& getName() const { return mCtx.filename; }; bool isOpen() const { return mEsm != nullptr; } /************************************************************************* @@ -62,15 +63,15 @@ public: /// Raw opening. Opens the file and sets everything up but doesn't /// parse the header. - void openRaw(std::unique_ptr&& stream, std::string_view name); + void openRaw(std::unique_ptr&& stream, const std::filesystem::path &name); /// Load ES file from a new stream, parses the header. Closes the /// currently open file first, if any. - void open(std::unique_ptr&& stream, const std::string &name); + void open(std::unique_ptr&& stream, const std::filesystem::path &name); - void open(const std::string &file); + void open(const std::filesystem::path &file); - void openRaw(std::string_view filename); + void openRaw(const std::filesystem::path &filename); /// Get the current position in the file. Make sure that the file has been opened! size_t getFileOffset() const { return mEsm->tellg(); }; diff --git a/components/esm3/loadcell.cpp b/components/esm3/loadcell.cpp index dc32ee6a43..2d92bf561e 100644 --- a/components/esm3/loadcell.cpp +++ b/components/esm3/loadcell.cpp @@ -131,7 +131,7 @@ namespace ESM { if(!overriding) mWater = std::numeric_limits::max(); - Log(Debug::Warning) << "Warning: Encountered invalid water level in cell " << mName << " defined in " << esm.getContext().filename; + Log(Debug::Warning) << "Warning: Encountered invalid water level in cell " << mName << " defined in " << esm.getContext().filename; //TODO(Project579): This will probably break in windows with unicode paths } else mWater = waterLevel; diff --git a/components/esm3/readerscache.hpp b/components/esm3/readerscache.hpp index 16511efdd7..df14bb6a8a 100644 --- a/components/esm3/readerscache.hpp +++ b/components/esm3/readerscache.hpp @@ -25,7 +25,7 @@ namespace ESM { State mState = State::Busy; ESMReader mReader; - std::optional mName; + std::optional mName; Item() = default; }; diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp index b7179ef125..4a8e908913 100644 --- a/components/esm4/reader.cpp +++ b/components/esm4/reader.cpp @@ -67,7 +67,7 @@ ReaderContext::ReaderContext() : modIndex(0), recHeaderSize(sizeof(RecordHeader) subRecordHeader.dataSize = 0; } -Reader::Reader(Files::IStreamPtr&& esmStream, const std::string& filename) +Reader::Reader(Files::IStreamPtr&& esmStream, const std::filesystem::path &filename) : mEncoder(nullptr), mFileSize(0), mStream(std::move(esmStream)) { // used by ESMReader only? @@ -150,7 +150,7 @@ void Reader::close() //mHeader.blank(); } -void Reader::openRaw(Files::IStreamPtr&& stream, const std::string& filename) +void Reader::openRaw(Files::IStreamPtr&& stream, const std::filesystem::path &filename) { close(); @@ -163,7 +163,7 @@ void Reader::openRaw(Files::IStreamPtr&& stream, const std::string& filename) } -void Reader::open(Files::IStreamPtr&& stream, const std::string &filename) +void Reader::open(Files::IStreamPtr&& stream, const std::filesystem::path &filename) { openRaw(std::move(stream), filename); @@ -199,21 +199,20 @@ void Reader::setRecHeaderSize(const std::size_t size) mCtx.recHeaderSize = size; } -// FIXME: only "English" strings supported for now void Reader::buildLStringIndex() { if ((mHeader.mFlags & Rec_ESM) == 0 || (mHeader.mFlags & Rec_Localized) == 0) return; - std::filesystem::path p(mCtx.filename); - std::string filename = p.stem().filename().string(); + const auto filename = mCtx.filename.stem().filename().u8string(); - buildLStringIndex("Strings/" + filename + "_English.STRINGS", Type_Strings); - buildLStringIndex("Strings/" + filename + "_English.ILSTRINGS", Type_ILStrings); - buildLStringIndex("Strings/" + filename + "_English.DLSTRINGS", Type_DLStrings); + static const std::filesystem::path s("Strings"); + buildLStringIndex(s / (filename + u8"_English.STRINGS"), Type_Strings); + buildLStringIndex(s / (filename + u8"_English.ILSTRINGS"), Type_ILStrings); + buildLStringIndex(s / (filename + u8"_English.DLSTRINGS"), Type_DLStrings); } -void Reader::buildLStringIndex(const std::string& stringFile, LocalizedStringType stringType) +void Reader::buildLStringIndex(const std::filesystem::path &stringFile, LocalizedStringType stringType) { std::uint32_t numEntries; std::uint32_t dataSize; @@ -638,7 +637,7 @@ void Reader::adjustGRUPFormId() std::stringstream ss; ss << "ESM Error: " << msg; - ss << "\n File: " << mCtx.filename; + ss << "\n File: " << mCtx.filename.string(); //TODO(Project579): This will probably break in windows with unicode paths ss << "\n Record: " << ESM::printName(mCtx.recordHeader.record.typeId); ss << "\n Subrecord: " << ESM::printName(mCtx.subRecordHeader.typeId); if (mStream.get()) diff --git a/components/esm4/reader.hpp b/components/esm4/reader.hpp index e620cae932..dea7360e3c 100644 --- a/components/esm4/reader.hpp +++ b/components/esm4/reader.hpp @@ -47,7 +47,7 @@ namespace ESM4 { struct ReaderContext { - std::string filename; // in case we need to reopen to restore the context + std::filesystem::path filename; // in case we need to reopen to restore the context std::uint32_t modIndex; // the sequential position of this file in the load order: // 0x00 reserved, 0xFF in-game (see notes below) @@ -113,7 +113,7 @@ namespace ESM4 { std::vector* mGlobalReaderList = nullptr; - void buildLStringIndex(const std::string& stringFile, LocalizedStringType stringType); + void buildLStringIndex(const std::filesystem::path& stringFile, LocalizedStringType stringType); inline bool hasLocalizedStrings() const { return (mHeader.mFlags & Rec_Localized) != 0; } @@ -124,11 +124,11 @@ namespace ESM4 { //void close(); // Raw opening. Opens the file and sets everything up but doesn't parse the header. - void openRaw(Files::IStreamPtr&& stream, const std::string& filename); + void openRaw(Files::IStreamPtr&& stream, const std::filesystem::path& filename); // Load ES file from a new stream, parses the header. // Closes the currently open file first, if any. - void open(Files::IStreamPtr&& stream, const std::string& filename); + void open(Files::IStreamPtr&& stream, const std::filesystem::path& filename); Reader() = default; @@ -137,13 +137,12 @@ namespace ESM4 { public: - Reader(Files::IStreamPtr&& esmStream, const std::string& filename); + Reader(Files::IStreamPtr&& esmStream, const std::filesystem::path& filename); ~Reader(); - // FIXME: should be private but ESMTool uses it - void openRaw(const std::string& filename); - void open(const std::string& filename); + + void open(const std::filesystem::path& filename); void close(); @@ -158,7 +157,7 @@ namespace ESM4 { inline int getFormat() const { return 0; }; // prob. not relevant for ESM4 inline const std::string getDesc() const { return mHeader.mDesc; } - inline std::string getFileName() const { return mCtx.filename; }; // not used + inline std::filesystem::path getFileName() const { return mCtx.filename; }; // not used inline bool hasMoreRecs() const { return (mFileSize - mCtx.fileRead) > 0; } diff --git a/components/esmloader/load.cpp b/components/esmloader/load.cpp index 8d407515f2..99d8159f04 100644 --- a/components/esmloader/load.cpp +++ b/components/esmloader/load.cpp @@ -228,7 +228,7 @@ namespace EsmLoader for (std::size_t i = 0; i < contentFiles.size(); ++i) { const std::string &file = contentFiles[i]; - const std::string extension = Misc::StringUtils::lowerCase(std::filesystem::path(file).extension().string()); + const std::string extension = Misc::StringUtils::lowerCase(std::filesystem::path(file).extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break if (supportedFormats.find(extension) == supportedFormats.end()) { @@ -247,7 +247,7 @@ namespace EsmLoader const ESM::ReadersCache::BusyItem reader = readers.get(i); reader->setEncoder(encoder); reader->setIndex(static_cast(i)); - reader->open(collection.getPath(file).string()); + reader->open(collection.getPath(file)); if (query.mLoadCells) reader->resolveParentFileIndices(readers); diff --git a/components/files/collections.cpp b/components/files/collections.cpp index 6146da3347..0929336075 100644 --- a/components/files/collections.cpp +++ b/components/files/collections.cpp @@ -36,21 +36,19 @@ namespace Files std::filesystem::path Collections::getPath(const std::string& file) const { - for (Files::PathContainer::const_iterator iter = mDirectories.begin(); - iter != mDirectories.end(); ++iter) + for (const auto & mDirectorie : mDirectories) { - for (std::filesystem::directory_iterator iter2 (*iter); - iter2!=std::filesystem::directory_iterator(); ++iter2) + for (const auto& iter2 : + std::filesystem::directory_iterator (mDirectorie)) { - std::filesystem::path path = *iter2; - + const auto& path = iter2.path(); if (mFoldCase) { - if (Misc::StringUtils::ciEqual(file, path.filename().string())) - return path.string(); + if (Misc::StringUtils::ciEqual(file, path.filename().string())) //TODO(Project579): This will probably break in windows with unicode paths + return path; } - else if (path.filename().string() == file) - return path.string(); + else if (path.filename().string() == file) //TODO(Project579): This will probably break in windows with unicode paths + return path; } } @@ -59,20 +57,19 @@ namespace Files bool Collections::doesExist(const std::string& file) const { - for (Files::PathContainer::const_iterator iter = mDirectories.begin(); - iter != mDirectories.end(); ++iter) + for (const auto & mDirectorie : mDirectories) { - for (std::filesystem::directory_iterator iter2 (*iter); - iter2!=std::filesystem::directory_iterator(); ++iter2) + for (const auto& iter2 : + std::filesystem::directory_iterator (mDirectorie)) { - std::filesystem::path path = *iter2; + const auto& path = iter2.path(); if (mFoldCase) { - if (Misc::StringUtils::ciEqual(file, path.filename().string())) + if (Misc::StringUtils::ciEqual(file, path.filename().string())) //TODO(Project579): This will probably break in windows with unicode paths return true; } - else if (path.filename().string() == file) + else if (path.filename().string() == file) //TODO(Project579): This will probably break in windows with unicode paths return true; } } diff --git a/components/files/collections.hpp b/components/files/collections.hpp index 000160bae7..69ae7d0d84 100644 --- a/components/files/collections.hpp +++ b/components/files/collections.hpp @@ -19,14 +19,14 @@ namespace Files /// leading dot and must be all lower-case. const MultiDirCollection& getCollection(const std::string& extension) const; - std::filesystem::path getPath(const std::string& file) const; + std::filesystem::path getPath(const std::string& file) const; //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break ///< Return full path (including filename) of \a file. /// /// If the file does not exist in any of the collection's /// directories, an exception is thrown. \a file must include the /// extension. - bool doesExist(const std::string& file) const; + bool doesExist(const std::string& file) const; //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break ///< \return Does a file with the given name exist? const Files::PathContainer& getPaths() const; diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 900c341edc..0fc228abee 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -155,9 +155,9 @@ void ConfigurationManager::readConfiguration(bpo::variables_map& variables, if (!quiet) { - Log(Debug::Info) << "Logs dir: " << getUserConfigPath().string(); - Log(Debug::Info) << "User data dir: " << mUserDataPath.string(); - Log(Debug::Info) << "Screenshots dir: " << mScreenshotPath.string(); + Log(Debug::Info) << "Logs dir: " << getUserConfigPath().string(); //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "User data dir: " << mUserDataPath.string(); //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Screenshots dir: " << mScreenshotPath.string(); //TODO(Project579): This will probably break in windows with unicode paths } mSilent = silent; @@ -270,7 +270,7 @@ void mergeComposingVariables(bpo::variables_map& first, bpo::variables_map& seco void ConfigurationManager::processPath(std::filesystem::path& path, const std::filesystem::path& basePath) const { - std::string str = path.string(); + std::string str = path.string(); //TODO(Project579): This will probably break in windows with unicode paths if (str.empty() || str[0] != '?') { @@ -285,7 +285,7 @@ void ConfigurationManager::processPath(std::filesystem::path& path, const std::f auto tokenIt = mTokensMapping.find(str.substr(0, pos + 1)); if (tokenIt != mTokensMapping.end()) { - std::filesystem::path tempPath(((mFixedPath).*(tokenIt->second))()); + std::filesystem::path tempPath(((mFixedPath).*(tokenIt->second))()); //TODO(Project579): This will probably break in windows with unicode paths if (pos < str.length() - 1) { // There is something after the token, so we should @@ -293,7 +293,7 @@ void ConfigurationManager::processPath(std::filesystem::path& path, const std::f tempPath /= str.substr(pos + 1, str.length() - pos); } - path = tempPath; + path = tempPath; //TODO(Project579): This will probably break in windows with unicode paths } else { @@ -351,7 +351,7 @@ std::optional ConfigurationManager::loadConfig( if (std::filesystem::is_regular_file(cfgFile)) { if (!mSilent) - Log(Debug::Info) << "Loading config file: " << cfgFile.string(); + Log(Debug::Info) << "Loading config file: " << cfgFile.string(); //TODO(Project579): This will probably break in windows with unicode paths std::ifstream configFileStream(cfgFile); @@ -438,7 +438,7 @@ std::istream& operator>> (std::istream& istream, MaybeQuotedPath& MaybeQuotedPat if (istream && !istream.eof() && istream.peek() != EOF) { std::string remainder{std::istreambuf_iterator(istream), {}}; - Log(Debug::Warning) << "Trailing data in path setting. Used '" << MaybeQuotedPath.string() << "' but '" << remainder << "' remained"; + Log(Debug::Warning) << "Trailing data in path setting. Used '" << MaybeQuotedPath.string() << "' but '" << remainder << "' remained"; //TODO(Project579): This will probably break in windows with unicode paths } } else diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index a56ae01aa0..4ac0453139 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -1,8 +1,10 @@ +#include + #include "constrainedfilestream.hpp" namespace Files { - IStreamPtr openConstrainedFileStream(const std::string& filename, std::size_t start, std::size_t length) + IStreamPtr openConstrainedFileStream(const std::filesystem::path &filename, std::size_t start, std::size_t length) { return std::make_unique(std::make_unique(filename, start, length)); } diff --git a/components/files/constrainedfilestream.hpp b/components/files/constrainedfilestream.hpp index f00bd3a488..fd239b2832 100644 --- a/components/files/constrainedfilestream.hpp +++ b/components/files/constrainedfilestream.hpp @@ -14,7 +14,7 @@ namespace Files /// A file stream constrained to a specific region in the file, specified by the 'start' and 'length' parameters. using ConstrainedFileStream = StreamWithBuffer; -IStreamPtr openConstrainedFileStream(const std::string& filename, std::size_t start = 0, +IStreamPtr openConstrainedFileStream(const std::filesystem::path &filename, std::size_t start = 0, std::size_t length = std::numeric_limits::max()); } diff --git a/components/files/constrainedfilestreambuf.cpp b/components/files/constrainedfilestreambuf.cpp index f5fd8ac394..24c0a9b4d8 100644 --- a/components/files/constrainedfilestreambuf.cpp +++ b/components/files/constrainedfilestreambuf.cpp @@ -2,12 +2,13 @@ #include #include +#include namespace Files { namespace File = Platform::File; - - ConstrainedFileStreamBuf::ConstrainedFileStreamBuf(const std::string& fname, std::size_t start, std::size_t length) + + ConstrainedFileStreamBuf::ConstrainedFileStreamBuf(const std::filesystem::path& fname, std::size_t start, std::size_t length) : mOrigin(start) { mFile = File::open(fname.c_str()); diff --git a/components/files/constrainedfilestreambuf.hpp b/components/files/constrainedfilestreambuf.hpp index bb9d6ca89e..7ee18f082a 100644 --- a/components/files/constrainedfilestreambuf.hpp +++ b/components/files/constrainedfilestreambuf.hpp @@ -11,7 +11,7 @@ namespace Files class ConstrainedFileStreamBuf final : public std::streambuf { public: - ConstrainedFileStreamBuf(const std::string& fname, std::size_t start, std::size_t length); + ConstrainedFileStreamBuf(const std::filesystem::path &fname, std::size_t start, std::size_t length); int_type underflow() final; diff --git a/components/files/hash.cpp b/components/files/hash.cpp index b11ecbf838..e8d4c2a3b0 100644 --- a/components/files/hash.cpp +++ b/components/files/hash.cpp @@ -9,7 +9,7 @@ namespace Files { - std::array getHash(const std::string& fileName, std::istream& stream) + std::array getHash(const std::filesystem::path& fileName, std::istream& stream) { std::array hash {0, 0}; try @@ -34,7 +34,7 @@ namespace Files } catch (const std::exception& e) { - throw std::runtime_error("Error while reading \"" + fileName + "\" to get hash: " + std::string(e.what())); + throw std::runtime_error("Error while reading \"" + fileName.string() + "\" to get hash: " + std::string(e.what())); //TODO(Project579): This will probably break in windows with unicode paths } return hash; } diff --git a/components/files/hash.hpp b/components/files/hash.hpp index a39961e4d5..2f525c3222 100644 --- a/components/files/hash.hpp +++ b/components/files/hash.hpp @@ -4,11 +4,11 @@ #include #include #include -#include +#include namespace Files { - std::array getHash(const std::string& fileName, std::istream& stream); + std::array getHash(const std::filesystem::path& fileName, std::istream& stream); } #endif diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index b6833fd025..94f02f8f7c 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -51,9 +51,12 @@ namespace Files LinuxPath::LinuxPath(const std::string& application_name) : mName(application_name) { - std::filesystem::path localPath = getLocalPath(); - if (chdir(localPath.string().c_str()) != 0) - Log(Debug::Warning) << "Error " << errno << " when changing current directory"; + std::error_code ec; + current_path(getLocalPath(), ec); + const auto err = ec.value(); + if (err != 0) { + Log(Debug::Warning) << "Error " << err << " " << std::strerror(err) << " when changing current directory"; + } } std::filesystem::path LinuxPath::getUserConfigPath() const @@ -79,18 +82,16 @@ std::filesystem::path LinuxPath::getGlobalConfigPath() const std::filesystem::path LinuxPath::getLocalPath() const { - std::filesystem::path localPath("./"); - const char *statusPaths[] = {"/proc/self/exe", "/proc/self/file", "/proc/curproc/exe", "/proc/curproc/file"}; + auto localPath = std::filesystem::current_path(); + static const std::filesystem::path statusPaths[] = {"/proc/self/exe", "/proc/self/file", "/proc/curproc/exe", "/proc/curproc/file"}; - for(const char *path : statusPaths) + for(const auto& path : statusPaths) { - std::filesystem::path statusPath(path); - if (!std::filesystem::exists(statusPath)) continue; - - statusPath = std::filesystem::read_symlink(statusPath); - if (!std::filesystem::is_empty(statusPath)) + std::error_code ec; + const auto binPath = read_symlink(path, ec); + if (ec.value() != -1) { - localPath = statusPath.parent_path() / "/"; + localPath = binPath.parent_path(); break; } } diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 50cddcdecf..ad7b54b463 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -30,7 +30,7 @@ namespace Files { if (!std::filesystem::is_directory(directory)) { - Log(Debug::Info) << "Skipping invalid directory: " << directory.string(); + Log(Debug::Info) << "Skipping invalid directory: " << directory.string(); //TODO(Project579): This will probably break in windows with unicode paths continue; } @@ -39,10 +39,10 @@ namespace Files { std::filesystem::path path = *dirIter; - if (!equal (extension, path.extension().string())) + if (!equal (extension, path.extension().string())) //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break continue; - std::string filename = path.filename().string(); + std::string filename = path.filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break TIter result = mFiles.find (filename); diff --git a/components/files/openfile.cpp b/components/files/openfile.cpp index 54b0b28058..2ab4409017 100644 --- a/components/files/openfile.cpp +++ b/components/files/openfile.cpp @@ -9,7 +9,7 @@ namespace Files { - std::unique_ptr openBinaryInputFileStream(const std::string& path) + std::unique_ptr openBinaryInputFileStream(const std::filesystem::path &path) { #if defined(_WIN32) || defined(__WINDOWS__) std::wstring wpath = boost::locale::conv::utf_to_utf(path); @@ -18,7 +18,7 @@ namespace Files auto stream = std::make_unique(path, std::ios::binary); #endif if (!stream->is_open()) - throw std::runtime_error("Failed to open '" + path + "' for reading: " + std::strerror(errno)); + throw std::runtime_error("Failed to open '" + path.string() + "' for reading: " + std::strerror(errno)); //TODO(Project579): This will probably break in windows with unicode paths stream->exceptions(std::ios::badbit); return stream; } diff --git a/components/files/openfile.hpp b/components/files/openfile.hpp index 3cecf7bac1..a65f0a8b18 100644 --- a/components/files/openfile.hpp +++ b/components/files/openfile.hpp @@ -4,10 +4,11 @@ #include #include #include +#include namespace Files { - std::unique_ptr openBinaryInputFileStream(const std::string& path); + std::unique_ptr openBinaryInputFileStream(const std::filesystem::path &path); } #endif diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index da26e773f6..c6a03f4263 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -19,11 +19,6 @@ namespace bconv = boost::locale::conv; #include -/** - * FIXME: Someone with Windows system should check this and correct if necessary - * FIXME: MAX_PATH is irrelevant for extended-length paths, i.e. \\?\... - */ - /** * \namespace Files */ @@ -33,31 +28,21 @@ namespace Files WindowsPath::WindowsPath(const std::string& application_name) : mName(application_name) { - /* Since on Windows boost::path.string() returns string of narrow - characters in local encoding, it is required to path::imbue() - with UTF-8 encoding (generated for empty name from boost::locale) - to handle Unicode in platform-agnostic way using std::string. - - See boost::filesystem and boost::locale reference for details. - */ - // TODO(Project579): Temporarly disabled until a good solution is found (no solution might actually be needed) - //boost::filesystem::path::imbue(boost::locale::generator().generate("")); - - std::filesystem::path localPath = getLocalPath(); - if (!SetCurrentDirectoryA(localPath.string().c_str())) - Log(Debug::Warning) << "Error " << GetLastError() << " when changing current directory"; + std::error_code ec; + current_path(getLocalPath(), ec); + if (ec.value() != 0) + Log(Debug::Warning) << "Error " << ec.value() << " when changing current directory"; } std::filesystem::path WindowsPath::getUserConfigPath() const { - std::filesystem::path userPath("."); + std::filesystem::path userPath = std::filesystem::current_path(); - WCHAR path[MAX_PATH + 1]; - memset(path, 0, sizeof(path)); + WCHAR path[MAX_PATH + 1] = {}; if(SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, nullptr, 0, path))) { - userPath = std::filesystem::path(bconv::utf_to_utf(path)); + userPath = std::filesystem::path(path); } return userPath / "My Games" / mName; @@ -71,14 +56,13 @@ std::filesystem::path WindowsPath::getUserDataPath() const std::filesystem::path WindowsPath::getGlobalConfigPath() const { - std::filesystem::path globalPath("."); + std::filesystem::path globalPath = std::filesystem::current_path(); - WCHAR path[MAX_PATH + 1]; - memset(path, 0, sizeof(path)); + WCHAR path[MAX_PATH + 1] = {}; if(SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PROGRAM_FILES | CSIDL_FLAG_CREATE, nullptr, 0, path))) { - globalPath = std::filesystem::path(bconv::utf_to_utf(path)); + globalPath = std::filesystem::path(path); } return globalPath / mName; @@ -86,13 +70,13 @@ std::filesystem::path WindowsPath::getGlobalConfigPath() const std::filesystem::path WindowsPath::getLocalPath() const { - std::filesystem::path localPath("./"); - WCHAR path[MAX_PATH + 1]; - memset(path, 0, sizeof(path)); + std::filesystem::path localPath = std::filesystem::current_path(); + + WCHAR path[MAX_PATH + 1] = {}; if (GetModuleFileNameW(nullptr, path, MAX_PATH + 1) > 0) { - localPath = std::filesystem::path(bconv::utf_to_utf(path)).parent_path().string() + "/"; + localPath = std::filesystem::path(path).parent_path(); } // lookup exe path @@ -111,20 +95,17 @@ std::filesystem::path WindowsPath::getCachePath() const std::filesystem::path WindowsPath::getInstallPath() const { - std::filesystem::path installPath(); + std::filesystem::path installPath{}; - HKEY hKey; - - LPCTSTR regkey = TEXT("SOFTWARE\\Bethesda Softworks\\Morrowind"); - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS) + if (HKEY hKey; RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Bethesda Softworks\\Morrowind", 0, KEY_READ | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS) { //Key existed, let's try to read the install dir - std::vector buf(512); - int len = 512; + std::array buf{}; + DWORD len = buf.size() * sizeof(wchar_t); - if (RegQueryValueEx(hKey, TEXT("Installed Path"), nullptr, nullptr, (LPBYTE)buf.data(), (LPDWORD)&len) == ERROR_SUCCESS) + if (RegQueryValueExW(hKey, L"Installed Path", nullptr, nullptr, reinterpret_cast(buf.data()), &len) == ERROR_SUCCESS) { - installPath = buf.data(); + installPath = std::filesystem::path (buf.data()); } RegCloseKey(hKey); } diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index a06429ed4b..4e5525d3a5 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -251,7 +251,7 @@ namespace Gui MyGUI::IntSize bookSize = getBookSize(layersStream.get()); float bookScale = osgMyGUI::ScalingLayer::getScaleFactor(bookSize); - std::string oldDataPath = dataManager->getDataPath(""); + const auto oldDataPath = dataManager->getDataPath(""); dataManager->setResourcePath("fonts"); std::unique_ptr dataStream(dataManager->getData(fileName)); diff --git a/components/fx/technique.cpp b/components/fx/technique.cpp index 20042bb9ae..357d8448d1 100644 --- a/components/fx/technique.cpp +++ b/components/fx/technique.cpp @@ -39,7 +39,7 @@ namespace fx { Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, const std::string& name, int width, int height, bool ubo, bool supportsNormals) : mName(name) - , mFileName((std::filesystem::path(Technique::sSubdir) / (mName + Technique::sExt)).string()) + , mFileName((std::filesystem::path(Technique::sSubdir) / (mName + Technique::sExt)).string()) //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break , mLastModificationTime(std::filesystem::file_time_type()) , mWidth(width) , mHeight(height) diff --git a/components/lua/luastate.cpp b/components/lua/luastate.cpp index dbdfde5100..a78eea6dde 100644 --- a/components/lua/luastate.cpp +++ b/components/lua/luastate.cpp @@ -26,21 +26,20 @@ namespace LuaUtil throw std::runtime_error("module not found: " + std::string(packageName)); } - static std::string packageNameToPath(std::string_view packageName, const std::vector& searchDirs) + static std::filesystem::path packageNameToPath(std::string_view packageName, const std::vector &searchDirs) { std::string path(packageName); std::replace(path.begin(), path.end(), '.', '/'); std::string pathWithInit = path + "/init.lua"; path.append(".lua"); - for (const std::string& dir : searchDirs) + for (const auto& base : searchDirs) { - std::filesystem::path base(dir); std::filesystem::path p1 = base / path; if (std::filesystem::exists(p1)) - return p1.string(); + return p1; std::filesystem::path p2 = base / pathWithInit; if (std::filesystem::exists(p2)) - return p2.string(); + return p2; } throw std::runtime_error("module not found: " + std::string(packageName)); } @@ -270,8 +269,8 @@ namespace LuaUtil sol::function LuaState::loadInternalLib(std::string_view libName) { - std::string path = packageNameToPath(libName, mLibSearchPaths); - sol::load_result res = mLua.load_file(path, sol::load_mode::text); + const auto path = packageNameToPath(libName, mLibSearchPaths); + sol::load_result res = mLua.load_file(path.string(), sol::load_mode::text); //TODO(Project579): This will probably break in windows with unicode paths if (!res.valid()) throw std::runtime_error("Lua error: " + res.get()); return res; diff --git a/components/lua/luastate.hpp b/components/lua/luastate.hpp index 3bd27f2250..48d302d44b 100644 --- a/components/lua/luastate.hpp +++ b/components/lua/luastate.hpp @@ -5,6 +5,8 @@ #include +#include + #include "configuration.hpp" namespace VFS @@ -80,7 +82,7 @@ namespace LuaUtil const ScriptsConfiguration& getConfiguration() const { return *mConf; } // Load internal Lua library. All libraries are loaded in one sandbox and shouldn't be exposed to scripts directly. - void addInternalLibSearchPath(const std::string& path) { mLibSearchPaths.push_back(path); } + void addInternalLibSearchPath(const std::filesystem::path &path) { mLibSearchPaths.push_back(path); } sol::function loadInternalLib(std::string_view libName); sol::function loadFromVFS(const std::string& path); sol::environment newInternalLibEnvironment(); @@ -98,7 +100,7 @@ namespace LuaUtil std::map mCompiledScripts; std::map mCommonPackages; const VFS::Manager* mVFS; - std::vector mLibSearchPaths; + std::vector mLibSearchPaths; }; // Should be used for every call of every Lua function. diff --git a/components/lua/storage.cpp b/components/lua/storage.cpp index bff978b633..ffb4f8af82 100644 --- a/components/lua/storage.cpp +++ b/components/lua/storage.cpp @@ -155,12 +155,12 @@ namespace LuaUtil } } - void LuaStorage::load(const std::string& path) + void LuaStorage::load(const std::filesystem::path &path) { assert(mData.empty()); // Shouldn't be used before loading try { - Log(Debug::Info) << "Loading Lua storage \"" << path << "\" (" << std::filesystem::file_size(path) << " bytes)"; + Log(Debug::Info) << "Loading Lua storage \"" << path << "\" (" << std::filesystem::file_size(path) << " bytes)"; //TODO(Project579): This will probably break in windows with unicode paths std::ifstream fin(path, std::fstream::binary); std::string serializedData((std::istreambuf_iterator(fin)), std::istreambuf_iterator()); sol::table data = deserialize(mLua, serializedData); @@ -177,7 +177,7 @@ namespace LuaUtil } } - void LuaStorage::save(const std::string& path) const + void LuaStorage::save(const std::filesystem::path &path) const { sol::table data(mLua, sol::create); for (const auto& [sectionName, section] : mData) @@ -186,7 +186,7 @@ namespace LuaUtil data[sectionName] = section->asTable(); } std::string serializedData = serialize(data); - Log(Debug::Info) << "Saving Lua storage \"" << path << "\" (" << serializedData.size() << " bytes)"; + Log(Debug::Info) << "Saving Lua storage \"" << path << "\" (" << serializedData.size() << " bytes)"; //TODO(Project579): This will probably break in windows with unicode paths std::ofstream fout(path, std::fstream::binary); fout.write(serializedData.data(), serializedData.size()); fout.close(); diff --git a/components/lua/storage.hpp b/components/lua/storage.hpp index 8ae944c5ab..f4047bd2ee 100644 --- a/components/lua/storage.hpp +++ b/components/lua/storage.hpp @@ -18,8 +18,8 @@ namespace LuaUtil explicit LuaStorage(lua_State* lua) : mLua(lua) {} void clearTemporaryAndRemoveCallbacks(); - void load(const std::string& path); - void save(const std::string& path) const; + void load(const std::filesystem::path &path); + void save(const std::filesystem::path &path) const; sol::object getSection(std::string_view sectionName, bool readOnly); sol::object getMutableSection(std::string_view sectionName) { return getSection(sectionName, false); } diff --git a/components/myguiplatform/myguidatamanager.cpp b/components/myguiplatform/myguidatamanager.cpp index 80b7a096bc..3078650a47 100644 --- a/components/myguiplatform/myguidatamanager.cpp +++ b/components/myguiplatform/myguidatamanager.cpp @@ -26,7 +26,7 @@ namespace namespace osgMyGUI { -void DataManager::setResourcePath(const std::string &path) +void DataManager::setResourcePath(const std::filesystem::path &path) { mResourcePath = path; } @@ -39,7 +39,7 @@ DataManager::DataManager(const std::string& resourcePath, const VFS::Manager* vf MyGUI::IDataStream *DataManager::getData(const std::string &name) const { - return new DataStream(mVfs->get(mResourcePath + "/" + name)); + return new DataStream(mVfs->get(mResourcePath / name)); } void DataManager::freeData(MyGUI::IDataStream *data) @@ -49,7 +49,7 @@ void DataManager::freeData(MyGUI::IDataStream *data) bool DataManager::isDataExist(const std::string &name) const { - return mVfs->exists(mResourcePath + "/" + name); + return mVfs->exists(mResourcePath / name); } const MyGUI::VectorString &DataManager::getDataListNames(const std::string &pattern) const @@ -68,7 +68,7 @@ const std::string &DataManager::getDataPath(const std::string &name) const if (!isDataExist(name)) return result; - result = mResourcePath + "/" + name; + result = (mResourcePath / name).string(); //TODO(Project579): This is broken on windows with unicode paths return result; } diff --git a/components/myguiplatform/myguidatamanager.hpp b/components/myguiplatform/myguidatamanager.hpp index 000c3ca1dd..09a427fdac 100644 --- a/components/myguiplatform/myguidatamanager.hpp +++ b/components/myguiplatform/myguidatamanager.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace VFS { @@ -18,7 +19,7 @@ class DataManager : public MyGUI::DataManager public: explicit DataManager(const std::string& path, const VFS::Manager* vfs); - void setResourcePath(const std::string& path); + void setResourcePath(const std::filesystem::path &path); /** Get data stream from specified resource name. @param _name Resource name (usually file name). @@ -47,7 +48,7 @@ public: const std::string& getDataPath(const std::string& _name) const override; private: - std::string mResourcePath; + std::filesystem::path mResourcePath; const VFS::Manager* mVfs; }; diff --git a/components/myguiplatform/myguiloglistener.cpp b/components/myguiplatform/myguiloglistener.cpp index ab5537b6b2..e22b96680a 100644 --- a/components/myguiplatform/myguiloglistener.cpp +++ b/components/myguiplatform/myguiloglistener.cpp @@ -8,9 +8,9 @@ namespace osgMyGUI { void CustomLogListener::open() { - mStream.open(std::filesystem::path(mFileName), std::ios_base::out); + mStream.open(mFileName, std::ios_base::out); if (!mStream.is_open()) - Log(Debug::Error) << "Unable to create MyGUI log with path " << mFileName; + Log(Debug::Error) << "Unable to create MyGUI log with path " << mFileName; //TODO(Project579): This is broken on windows with unicode paths } void CustomLogListener::close() diff --git a/components/myguiplatform/myguiloglistener.hpp b/components/myguiplatform/myguiloglistener.hpp index c22b5afb02..4d6072a1d6 100644 --- a/components/myguiplatform/myguiloglistener.hpp +++ b/components/myguiplatform/myguiloglistener.hpp @@ -19,7 +19,7 @@ namespace osgMyGUI class CustomLogListener : public MyGUI::ILogListener { public: - CustomLogListener(const std::string &name) + CustomLogListener(const std::filesystem::path &name) : mFileName(name) {} @@ -31,11 +31,9 @@ namespace osgMyGUI void log(const std::string& _section, MyGUI::LogLevel _level, const struct tm* _time, const std::string& _message, const char* _file, int _line) override; - const std::string& getFileName() const { return mFileName; } - private: std::ofstream mStream; - std::string mFileName; + std::filesystem::path mFileName; }; /// \brief Helper class holding data that required during @@ -49,7 +47,7 @@ namespace osgMyGUI public: - LogFacility(const std::string &output, bool console) + LogFacility(const std::filesystem::path &output, bool console) : mFile(output) { mConsole.setEnabled(console); diff --git a/components/myguiplatform/myguiplatform.cpp b/components/myguiplatform/myguiplatform.cpp index 203de195f4..5425ddd31d 100644 --- a/components/myguiplatform/myguiplatform.cpp +++ b/components/myguiplatform/myguiplatform.cpp @@ -8,7 +8,7 @@ namespace osgMyGUI { Platform::Platform(osgViewer::Viewer *viewer, osg::Group* guiRoot, Resource::ImageManager* imageManager, - const VFS::Manager* vfs, float uiScalingFactor, const std::string& resourcePath, const std::string& logName) + const VFS::Manager* vfs, float uiScalingFactor, const std::filesystem::path& resourcePath, const std::filesystem::path& logName) : mLogFacility(logName.empty() ? nullptr : std::make_unique(logName, false)) , mLogManager(std::make_unique()) , mDataManager(std::make_unique(resourcePath, vfs)) diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index 666dde8a84..a4812cc0b9 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace osgViewer { @@ -36,8 +37,8 @@ namespace osgMyGUI { public: Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ImageManager* imageManager, - const VFS::Manager* vfs, float uiScalingFactor, const std::string& resourcePath, - const std::string& logName = "MyGUI.log"); + const VFS::Manager* vfs, float uiScalingFactor, const std::filesystem::path& resourcePath, + const std::filesystem::path& logName = "MyGUI.log"); ~Platform(); diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 574ba8bc2b..08d80b0f67 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -22,7 +22,7 @@ namespace Nif { /// Open a NIF stream. The name is used for error messages. -NIFFile::NIFFile(Files::IStreamPtr&& stream, const std::string &name) +NIFFile::NIFFile(Files::IStreamPtr&& stream, const std::filesystem::path &name) : filename(name) { parse(std::move(stream)); @@ -316,7 +316,7 @@ void NIFFile::parse(Files::IStreamPtr&& stream) r = entry->second(); if (!supportedVersion) - Log(Debug::Verbose) << "NIF Debug: Reading record of type " << rec << ", index " << i << " (" << filename << ")"; + Log(Debug::Verbose) << "NIF Debug: Reading record of type " << rec << ", index " << i << " (" << filename << ")"; //TODO(Project579): This will probably break in windows with unicode paths assert(r != nullptr); assert(r->recType != RC_MISSING); diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 6b217df6e1..5b14ad2e46 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -31,7 +31,7 @@ struct File virtual bool getUseSkinning() const = 0; - virtual std::string getFilename() const = 0; + virtual std::filesystem::path getFilename() const = 0; virtual std::string getHash() const = 0; @@ -50,7 +50,7 @@ class NIFFile final : public File unsigned int bethVer = 0; /// File name, used for error messages and opening the file - std::string filename; + std::filesystem::path filename; std::string hash; /// Record list @@ -100,7 +100,7 @@ public: void warn(const std::string &msg) const; /// Open a NIF stream. The name is used for error messages. - NIFFile(Files::IStreamPtr&& stream, const std::string &name); + NIFFile(Files::IStreamPtr&& stream, const std::filesystem::path &name); /// Get a given record Record *getRecord(size_t index) const override @@ -129,7 +129,7 @@ public: bool getUseSkinning() const override; /// Get the name of the file - std::string getFilename() const override { return filename; } + std::filesystem::path getFilename() const override { return filename; } std::string getHash() const override { return hash; } diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 427d33000a..aeaf57c5f4 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -187,7 +187,7 @@ osg::ref_ptr BulletNifLoader::load(const Nif::File& nif) if (node) roots.emplace_back(node); } - const std::string filename = nif.getFilename(); + const std::string filename = nif.getFilename().string(); //TODO(Project579): This will probably break in windows with unicode paths mShape->mFileName = filename; if (roots.empty()) { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 19a83175a3..39ccafdceb 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -225,12 +225,12 @@ namespace NifOsg { public: /// @param filename used for warning messages. - LoaderImpl(const std::string& filename, unsigned int ver, unsigned int userver, unsigned int bethver) + LoaderImpl(const std::filesystem::path& filename, unsigned int ver, unsigned int userver, unsigned int bethver) : mFilename(filename), mVersion(ver), mUserVersion(userver), mBethVersion(bethver) { } - std::string mFilename; + std::filesystem::path mFilename; unsigned int mVersion, mUserVersion, mBethVersion; size_t mFirstRootTextureIndex{~0u}; @@ -299,7 +299,7 @@ namespace NifOsg setupController(key, callback, /*animflags*/0); if (!target.mKeyframeControllers.emplace(strdata->string, callback).second) - Log(Debug::Verbose) << "Controller " << strdata->string << " present more than once in " << nif->getFilename() << ", ignoring later version"; + Log(Debug::Verbose) << "Controller " << strdata->string << " present more than once in " << nif->getFilename() << ", ignoring later version"; //TODO(Project579): This will probably break in windows with unicode paths } } @@ -485,20 +485,20 @@ namespace NifOsg { if (nifNode->recType != Nif::RC_NiTextureEffect) { - Log(Debug::Info) << "Unhandled effect " << nifNode->recName << " in " << mFilename; + Log(Debug::Info) << "Unhandled effect " << nifNode->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return; } const Nif::NiTextureEffect* textureEffect = static_cast(nifNode); if (textureEffect->textureType != Nif::NiTextureEffect::Environment_Map) { - Log(Debug::Info) << "Unhandled NiTextureEffect type " << textureEffect->textureType << " in " << mFilename; + Log(Debug::Info) << "Unhandled NiTextureEffect type " << textureEffect->textureType << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return; } if (textureEffect->texture.empty()) { - Log(Debug::Info) << "NiTextureEffect missing source texture in " << mFilename; + Log(Debug::Info) << "NiTextureEffect missing source texture in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return; } @@ -515,7 +515,7 @@ namespace NifOsg texGen->setMode(osg::TexGen::SPHERE_MAP); break; default: - Log(Debug::Info) << "Unhandled NiTextureEffect coordGenType " << textureEffect->coordGenType << " in " << mFilename; + Log(Debug::Info) << "Unhandled NiTextureEffect coordGenType " << textureEffect->coordGenType << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return; } @@ -875,7 +875,7 @@ namespace NifOsg // These controllers are handled elsewhere } else - Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; + Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths } } @@ -915,7 +915,7 @@ namespace NifOsg composite->addController(osgctrl); } else - Log(Debug::Info) << "Unexpected material controller " << ctrl->recType << " in " << mFilename; + Log(Debug::Info) << "Unexpected material controller " << ctrl->recType << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths } } @@ -959,7 +959,7 @@ namespace NifOsg composite->addController(callback); } else - Log(Debug::Info) << "Unexpected texture controller " << ctrl->recName << " in " << mFilename; + Log(Debug::Info) << "Unexpected texture controller " << ctrl->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths } } @@ -994,7 +994,7 @@ namespace NifOsg // unused } else - Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename; + Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths } for (; !colliders.empty(); colliders = colliders->next) { @@ -1009,7 +1009,7 @@ namespace NifOsg program->addOperator(new SphericalCollider(sphericalcollider)); } else - Log(Debug::Info) << "Unhandled particle collider " << colliders->recName << " in " << mFilename; + Log(Debug::Info) << "Unhandled particle collider " << colliders->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths } } @@ -1152,7 +1152,7 @@ namespace NifOsg } if (!partctrl) { - Log(Debug::Info) << "No particle controller found in " << mFilename; + Log(Debug::Info) << "No particle controller found in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return; } @@ -1247,7 +1247,7 @@ namespace NifOsg unsigned int uvSet = *it; if (uvSet >= uvlist.size()) { - Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << name << "\" in " << mFilename; + Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << name << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths if (uvlist.empty()) continue; uvSet = 0; @@ -1419,7 +1419,7 @@ namespace NifOsg case 9: return osg::BlendFunc::ONE_MINUS_DST_ALPHA; case 10: return osg::BlendFunc::SRC_ALPHA_SATURATE; default: - Log(Debug::Info) << "Unexpected blend mode: "<< mode << " in " << mFilename; + Log(Debug::Info) << "Unexpected blend mode: "<< mode << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return osg::BlendFunc::SRC_ALPHA; } } @@ -1437,7 +1437,7 @@ namespace NifOsg case 6: return osg::AlphaFunc::GEQUAL; case 7: return osg::AlphaFunc::NEVER; default: - Log(Debug::Info) << "Unexpected blend mode: " << mode << " in " << mFilename; + Log(Debug::Info) << "Unexpected blend mode: " << mode << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return osg::AlphaFunc::LEQUAL; } } @@ -1455,7 +1455,7 @@ namespace NifOsg case 6: return osg::Stencil::GEQUAL; case 7: return osg::Stencil::ALWAYS; default: - Log(Debug::Info) << "Unexpected stencil function: " << func << " in " << mFilename; + Log(Debug::Info) << "Unexpected stencil function: " << func << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return osg::Stencil::NEVER; } } @@ -1471,7 +1471,7 @@ namespace NifOsg case 4: return osg::Stencil::DECR; case 5: return osg::Stencil::INVERT; default: - Log(Debug::Info) << "Unexpected stencil operation: " << op << " in " << mFilename; + Log(Debug::Info) << "Unexpected stencil operation: " << op << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return osg::Stencil::KEEP; } } @@ -1514,7 +1514,7 @@ namespace NifOsg packing = 4; break; default: - Log(Debug::Info) << "Unhandled internal pixel format " << pixelData->fmt << " in " << mFilename; + Log(Debug::Info) << "Unhandled internal pixel format " << pixelData->fmt << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return nullptr; } @@ -1572,7 +1572,7 @@ namespace NifOsg { if (pixelData->palette.empty() || pixelData->bpp != 8) { - Log(Debug::Info) << "Palettized texture in " << mFilename << " is invalid, ignoring"; + Log(Debug::Info) << "Palettized texture in " << mFilename << " is invalid, ignoring"; //TODO(Project579): This will probably break in windows with unicode paths return nullptr; } pixelformat = pixelData->fmt == Nif::NiPixelData::NIPXFMT_PAL8 ? GL_RGB : GL_RGBA; @@ -1644,7 +1644,7 @@ namespace NifOsg break; default: { - Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; + Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths continue; } } @@ -1658,7 +1658,7 @@ namespace NifOsg if(tex.texture.empty() && texprop->controller.empty()) { if (i == 0) - Log(Debug::Warning) << "Base texture is in use but empty on shape \"" << nodeName << "\" in " << mFilename; + Log(Debug::Warning) << "Base texture is in use but empty on shape \"" << nodeName << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths continue; } @@ -1815,7 +1815,7 @@ namespace NifOsg break; default: { - Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; + Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths continue; } } @@ -1859,10 +1859,10 @@ namespace NifOsg case Nif::BSShaderType::ShaderType_Water: case Nif::BSShaderType::ShaderType_Lighting30: case Nif::BSShaderType::ShaderType_Tile: - Log(Debug::Warning) << "Unhandled BSShaderType " << type << " in " << mFilename; + Log(Debug::Warning) << "Unhandled BSShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return std::string_view(); } - Log(Debug::Warning) << "Unknown BSShaderType " << type << " in " << mFilename; + Log(Debug::Warning) << "Unknown BSShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return std::string_view(); } @@ -1891,10 +1891,10 @@ namespace NifOsg case Nif::BSLightingShaderType::ShaderType_LODNoise: case Nif::BSLightingShaderType::ShaderType_MultitexLandLODBlend: case Nif::BSLightingShaderType::ShaderType_Dismemberment: - Log(Debug::Warning) << "Unhandled BSLightingShaderType " << type << " in " << mFilename; + Log(Debug::Warning) << "Unhandled BSLightingShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return std::string_view(); } - Log(Debug::Warning) << "Unknown BSLightingShaderType " << type << " in " << mFilename; + Log(Debug::Warning) << "Unknown BSLightingShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths return std::string_view(); } @@ -2057,7 +2057,7 @@ namespace NifOsg break; } default: - Log(Debug::Info) << "Unhandled " << property->recName << " in " << mFilename; + Log(Debug::Info) << "Unhandled " << property->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths break; } } @@ -2304,7 +2304,7 @@ namespace NifOsg else if (type == Nif::RC_NiClusterAccumulator) setBin_BackToFront(stateset); else - Log(Debug::Error) << "Unrecognized NiAccumulator in " << mFilename; + Log(Debug::Error) << "Unrecognized NiAccumulator in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths }; switch (mPushedSorter->mMode) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index bbbdde68d7..ef8d1c66e3 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -477,7 +477,7 @@ namespace Resource return *mShaderManager.get(); } - void SceneManager::setShaderPath(const std::string &path) + void SceneManager::setShaderPath(const std::filesystem::path &path) { mShaderManager->setShaderPath(path); } @@ -498,14 +498,14 @@ namespace Resource osgDB::ReaderWriter::ReadResult readImage(const std::string& filename, const osgDB::Options* options) override { - std::filesystem::path filePath(filename); + std::filesystem::path filePath(filename); //TODO(Project579): This will probably break in windows with unicode paths if (filePath.is_absolute()) // It is a hack. Needed because either OSG or libcollada-dom tries to make an absolute path from // our relative VFS path by adding current working directory. filePath = std::filesystem::relative(filename, osgDB::getCurrentWorkingDirectory()); try { - return osgDB::ReaderWriter::ReadResult(mImageManager->getImage(filePath.string()), + return osgDB::ReaderWriter::ReadResult(mImageManager->getImage(filePath.string()), //TODO(Project579): This will probably break in windows with unicode paths osgDB::ReaderWriter::ReadResult::FILE_LOADED); } catch (std::exception& e) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index d3ad868a99..b27b807447 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -14,6 +14,7 @@ #include "resourcemanager.hpp" #include +#include namespace Resource { @@ -124,7 +125,7 @@ namespace Resource void setConvertAlphaTestToAlphaToCoverage(bool convert); - void setShaderPath(const std::string& path); + void setShaderPath(const std::filesystem::path &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); diff --git a/components/sceneutil/screencapture.cpp b/components/sceneutil/screencapture.cpp index 97a22e94aa..6adff9323d 100644 --- a/components/sceneutil/screencapture.cpp +++ b/components/sceneutil/screencapture.cpp @@ -61,8 +61,9 @@ namespace namespace SceneUtil { - std::string writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat, - const osg::Image& image) + std::filesystem::path writeScreenshotToFile(const std::filesystem::path& screenshotPath, + const std::string& screenshotFormat, + const osg::Image& image) { // Count screenshots. int shotCount = 0; @@ -70,7 +71,7 @@ namespace SceneUtil // Find the first unused filename with a do-while std::ostringstream stream; std::string lastFileName; - std::string lastFilePath; + std::filesystem::path lastFilePath; do { // Reset the stream @@ -80,12 +81,12 @@ namespace SceneUtil stream << "screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << screenshotFormat; lastFileName = stream.str(); - lastFilePath = screenshotPath + "/" + lastFileName; + lastFilePath = screenshotPath / lastFileName; } while (std::filesystem::exists(lastFilePath)); std::ofstream outStream; - outStream.open(std::filesystem::path(std::move(lastFilePath)), std::ios::binary); + outStream.open(lastFilePath, std::ios::binary); osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(screenshotFormat); if (!readerwriter) @@ -104,7 +105,7 @@ namespace SceneUtil return lastFileName; } - WriteScreenshotToFileOperation::WriteScreenshotToFileOperation(const std::string& screenshotPath, + WriteScreenshotToFileOperation::WriteScreenshotToFileOperation(const std::filesystem::path &screenshotPath, const std::string& screenshotFormat, std::function callback) : mScreenshotPath(screenshotPath) @@ -115,7 +116,7 @@ namespace SceneUtil void WriteScreenshotToFileOperation::operator()(const osg::Image& image, const unsigned int /*context_id*/) { - std::string fileName; + std::filesystem::path fileName; try { fileName = writeScreenshotToFile(mScreenshotPath, mScreenshotFormat, image); @@ -128,7 +129,7 @@ namespace SceneUtil if (fileName.empty()) mCallback("Failed to save screenshot"); else - mCallback(fileName + " has been saved"); + mCallback(fileName.string() + " has been saved"); //TODO(Project579): This will probably break in windows with unicode paths } AsyncScreenCaptureOperation::AsyncScreenCaptureOperation(osg::ref_ptr queue, diff --git a/components/sceneutil/screencapture.hpp b/components/sceneutil/screencapture.hpp index 87e396b020..e5a8304896 100644 --- a/components/sceneutil/screencapture.hpp +++ b/components/sceneutil/screencapture.hpp @@ -8,6 +8,7 @@ #include #include +#include namespace osg { @@ -19,19 +20,20 @@ namespace SceneUtil class WorkQueue; class WorkItem; - std::string writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat, - const osg::Image& image); + std::filesystem::path writeScreenshotToFile(const std::filesystem::path& screenshotPath, + const std::string& screenshotFormat, + const osg::Image& image); class WriteScreenshotToFileOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation { public: - WriteScreenshotToFileOperation(const std::string& screenshotPath, const std::string& screenshotFormat, + WriteScreenshotToFileOperation(const std::filesystem::path &screenshotPath, const std::string& screenshotFormat, std::function callback); void operator()(const osg::Image& image, const unsigned int context_id) override; private: - const std::string mScreenshotPath; + const std::filesystem::path mScreenshotPath; const std::string mScreenshotFormat; const std::function mCallback; }; diff --git a/components/sceneutil/writescene.cpp b/components/sceneutil/writescene.cpp index d243f521c0..1a605be5ae 100644 --- a/components/sceneutil/writescene.cpp +++ b/components/sceneutil/writescene.cpp @@ -8,7 +8,7 @@ #include "serialize.hpp" -void SceneUtil::writeScene(osg::Node *node, const std::string& filename, const std::string& format) +void SceneUtil::writeScene(osg::Node *node, const std::filesystem::path& filename, const std::string& format) { registerSerializers(); diff --git a/components/sceneutil/writescene.hpp b/components/sceneutil/writescene.hpp index 307251fe80..0e1701f4ad 100644 --- a/components/sceneutil/writescene.hpp +++ b/components/sceneutil/writescene.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_COMPONENTS_WRITESCENE_H #define OPENMW_COMPONENTS_WRITESCENE_H -#include +#include namespace osg { @@ -11,7 +11,7 @@ namespace osg namespace SceneUtil { - void writeScene(osg::Node* node, const std::string& filename, const std::string& format); + void writeScene(osg::Node* node, const std::filesystem::path& filename, const std::string& format); } diff --git a/components/settings/parser.cpp b/components/settings/parser.cpp index cbc51ff220..44016ad010 100644 --- a/components/settings/parser.cpp +++ b/components/settings/parser.cpp @@ -10,12 +10,12 @@ #include -void Settings::SettingsFileParser::loadSettingsFile(const std::string& file, CategorySettingValueMap& settings, +void Settings::SettingsFileParser::loadSettingsFile(const std::filesystem::path &file, CategorySettingValueMap& settings, bool base64Encoded, bool overrideExisting) { mFile = file; std::ifstream fstream; - fstream.open(std::filesystem::path(file)); + fstream.open(file); auto stream = std::ref(fstream); std::istringstream decodedStream; @@ -82,7 +82,7 @@ void Settings::SettingsFileParser::loadSettingsFile(const std::string& file, Cat } } -void Settings::SettingsFileParser::saveSettingsFile(const std::string& file, const CategorySettingValueMap& settings) +void Settings::SettingsFileParser::saveSettingsFile(const std::filesystem::path &file, const CategorySettingValueMap& settings) { using CategorySettingStatusMap = std::map; @@ -108,8 +108,7 @@ void Settings::SettingsFileParser::saveSettingsFile(const std::string& file, con // as the output file if we're copying the setting from the default settings.cfg for the // first time. A minor change in API to pass the source file might be in order here. std::ifstream istream; - std::filesystem::path ipath(file); - istream.open(ipath); + istream.open(file); // Create a new string stream to write the current settings to. It's likely that the // input file and the output file are the same, so this stream serves as a temporary file @@ -305,9 +304,9 @@ void Settings::SettingsFileParser::saveSettingsFile(const std::string& file, con // Now install the newly written file in the requested place. if (changed) { - Log(Debug::Info) << "Updating settings file: " << ipath; + Log(Debug::Info) << "Updating settings file: " << file; //TODO(Project579): This will probably break in windows with unicode paths std::ofstream ofstream; - ofstream.open(ipath); + ofstream.open(file); ofstream << ostream.rdbuf(); ofstream.close(); } diff --git a/components/settings/parser.hpp b/components/settings/parser.hpp index c934fbea07..a062a39fa2 100644 --- a/components/settings/parser.hpp +++ b/components/settings/parser.hpp @@ -4,16 +4,17 @@ #include "categories.hpp" #include +#include namespace Settings { class SettingsFileParser { public: - void loadSettingsFile(const std::string& file, CategorySettingValueMap& settings, - bool base64encoded = false, bool overrideExisting = false); + void loadSettingsFile(const std::filesystem::path &file, CategorySettingValueMap& settings, + bool base64Encoded = false, bool overrideExisting = false); - void saveSettingsFile(const std::string& file, const CategorySettingValueMap& settings); + void saveSettingsFile(const std::filesystem::path &file, const CategorySettingValueMap& settings); private: /// Increment i until it longer points to a whitespace character @@ -23,7 +24,7 @@ namespace Settings [[noreturn]] void fail(const std::string& message); - std::string mFile; + std::filesystem::path mFile; int mLine = 0; }; } diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index cd4016900b..b252af2ccf 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -21,7 +21,7 @@ void Manager::clear() mChangedSettings.clear(); } -std::string Manager::load(const Files::ConfigurationManager& cfgMgr, bool loadEditorSettings) +std::filesystem::path Manager::load(const Files::ConfigurationManager& cfgMgr, bool loadEditorSettings) { SettingsFileParser parser; const std::vector& paths = cfgMgr.getActiveConfigPaths(); @@ -44,7 +44,7 @@ std::string Manager::load(const Files::ConfigurationManager& cfgMgr, bool loadEd } // Create the settings manager and load default settings file. - const std::string defaultsBin = (paths.front() / defaultSettingsFile).string(); + const auto defaultsBin = paths.front() / defaultSettingsFile; if (!std::filesystem::exists(defaultsBin)) throw std::runtime_error ("No default settings file found! Make sure the file \"" + defaultSettingsFile + "\" was properly installed."); parser.loadSettingsFile(defaultsBin, mDefaultSettings, true, false); @@ -52,20 +52,20 @@ std::string Manager::load(const Files::ConfigurationManager& cfgMgr, bool loadEd // Load "settings.cfg" or "openmw-cs.cfg" from every config dir except the last one as additional default settings. for (int i = 0; i < static_cast(paths.size()) - 1; ++i) { - const std::string additionalDefaults = (paths[i] / userSettingsFile).string(); + const auto additionalDefaults = paths[i] / userSettingsFile; if (std::filesystem::exists(additionalDefaults)) parser.loadSettingsFile(additionalDefaults, mDefaultSettings, false, true); } // Load "settings.cfg" or "openmw-cs.cfg" from the last config dir as user settings. This path will be used to save modified settings. - std::string settingspath = (paths.back() / userSettingsFile).string(); + auto settingspath = paths.back() / userSettingsFile; if (std::filesystem::exists(settingspath)) parser.loadSettingsFile(settingspath, mUserSettings, false, false); return settingspath; } -void Manager::saveUser(const std::string &file) +void Manager::saveUser(const std::filesystem::path &file) { SettingsFileParser parser; parser.saveSettingsFile(file, mUserSettings); diff --git a/components/settings/settings.hpp b/components/settings/settings.hpp index f50449b5de..e5e841e3de 100644 --- a/components/settings/settings.hpp +++ b/components/settings/settings.hpp @@ -11,6 +11,7 @@ #include #include +#include namespace Files { @@ -41,10 +42,10 @@ namespace Settings static void clear(); ///< clears all settings and default settings - static std::string load(const Files::ConfigurationManager& cfgMgr, bool loadEditorSettings = false); + static std::filesystem::path load(const Files::ConfigurationManager& cfgMgr, bool loadEditorSettings = false); ///< load settings from all active config dirs. Returns the path of the last loaded file. - static void saveUser (const std::string& file); + static void saveUser (const std::filesystem::path &file); ///< save user settings to file static void resetPendingChanges(); diff --git a/components/settings/shadermanager.hpp b/components/settings/shadermanager.hpp index eaf10a3a34..effedf63d2 100644 --- a/components/settings/shadermanager.hpp +++ b/components/settings/shadermanager.hpp @@ -104,12 +104,12 @@ namespace Settings return std::nullopt; } - bool load(const std::string& path) + bool load(const std::filesystem::path &path) { mData = YAML::Null; - mPath = std::filesystem::path(path); + mPath = path; - Log(Debug::Info) << "Loading shader settings file: " << mPath; + Log(Debug::Info) << "Loading shader settings file: " << mPath; //TODO(Project579): This will probably break in windows with unicode paths if (!std::filesystem::exists(mPath)) { @@ -123,7 +123,7 @@ namespace Settings try { - mData = YAML::LoadFile(mPath.string()); + mData = YAML::LoadFile(mPath.string()); //TODO(Project579): This will probably break in windows with unicode paths mData.SetStyle(YAML::EmitterStyle::Block); if (!mData["config"]) @@ -153,7 +153,7 @@ namespace Settings out.SetMapFormat(YAML::Block); out << mData; - std::ofstream fout(mPath.string()); + std::ofstream fout(mPath); fout << out.c_str(); if (!fout) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 326615cc05..1e48cf337e 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -25,7 +25,7 @@ namespace Shader ShaderManager::~ShaderManager() = default; - void ShaderManager::setShaderPath(const std::string &path) + void ShaderManager::setShaderPath(const std::filesystem::path &path) { mPath = path; } @@ -126,7 +126,7 @@ namespace Shader includeFstream.open(includePath); if (includeFstream.fail()) { - Log(Debug::Error) << "Shader " << fileName << " error: Failed to open include " << includePath.string(); + Log(Debug::Error) << "Shader " << fileName << " error: Failed to open include " << includePath.string(); //TODO(Project579): This will probably break in windows with unicode paths return false; } int includedFileNumber = fileNumber++; @@ -467,12 +467,12 @@ namespace Shader if (templateIt == mShaderTemplates.end()) { - std::filesystem::path path = (std::filesystem::path(mPath) / templateName); + std::filesystem::path path = mPath / templateName; std::ifstream stream; stream.open(path); if (stream.fail()) { - Log(Debug::Error) << "Failed to open " << path.string(); + Log(Debug::Error) << "Failed to open " << path.string(); //TODO(Project579): This will probably break in windows with unicode paths return nullptr; } std::stringstream buffer; @@ -482,7 +482,7 @@ namespace Shader int fileNumber = 1; std::string source = buffer.str(); if (!addLineDirectivesAfterConditionalBlocks(source) - || !parseIncludes(std::filesystem::path(mPath), source, templateName, fileNumber, {}, insertedPaths)) + || !parseIncludes(mPath, source, templateName, fileNumber, {}, insertedPaths)) return nullptr; mHotReloadManager->templateIncludedFiles[templateName] = insertedPaths; templateIt = mShaderTemplates.insert(std::make_pair(templateName, source)).first; diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index 50c430637e..55bc1cb04a 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -12,6 +12,7 @@ #include #include +#include namespace osgViewer { class Viewer; @@ -29,7 +30,7 @@ namespace Shader ShaderManager(); ~ShaderManager(); - void setShaderPath(const std::string& path); + void setShaderPath(const std::filesystem::path &path); typedef std::map DefineMap; @@ -80,7 +81,7 @@ namespace Shader void getLinkedShaders(osg::ref_ptr shader, const std::vector& linkedShaderNames, const DefineMap& defines); void addLinkedShaders(osg::ref_ptr shader, osg::ref_ptr program); - std::string mPath; + std::filesystem::path mPath; DefineMap mGlobalDefines; diff --git a/components/version/version.cpp b/components/version/version.cpp index 32b8f44ae6..a280bf38d3 100644 --- a/components/version/version.cpp +++ b/components/version/version.cpp @@ -6,11 +6,9 @@ namespace Version { -Version getOpenmwVersion(const std::string &resourcePath) +Version getOpenmwVersion(const std::filesystem::path &resourcePath) { - std::filesystem::path path (resourcePath + "/version"); - - std::ifstream stream (path); + std::ifstream stream (resourcePath / "version"); Version v; std::getline(stream, v.mVersion); @@ -31,7 +29,7 @@ std::string Version::describe() return str; } -std::string getOpenmwVersionDescription(const std::string &resourcePath) +std::string getOpenmwVersionDescription(const std::filesystem::path &resourcePath) { Version v = getOpenmwVersion(resourcePath); return v.describe(); diff --git a/components/version/version.hpp b/components/version/version.hpp index 7371e786e0..0248f869a9 100644 --- a/components/version/version.hpp +++ b/components/version/version.hpp @@ -2,6 +2,7 @@ #define VERSION_HPP #include +#include namespace Version { @@ -16,10 +17,10 @@ namespace Version }; /// Read OpenMW version from the version file located in resourcePath. - Version getOpenmwVersion(const std::string& resourcePath); + Version getOpenmwVersion(const std::filesystem::path &resourcePath); /// Helper function to getOpenmwVersion and describe() it - std::string getOpenmwVersionDescription(const std::string& resourcePath); + std::string getOpenmwVersionDescription(const std::filesystem::path &resourcePath); } diff --git a/components/vfs/archive.hpp b/components/vfs/archive.hpp index 22df09e06c..26db7b8535 100644 --- a/components/vfs/archive.hpp +++ b/components/vfs/archive.hpp @@ -15,7 +15,7 @@ namespace VFS virtual Files::IStreamPtr open() = 0; - virtual std::string getPath() = 0; + virtual std::filesystem::path getPath() = 0; }; class Archive diff --git a/components/vfs/bsaarchive.cpp b/components/vfs/bsaarchive.cpp index c0db4c071c..f2c09cf848 100644 --- a/components/vfs/bsaarchive.cpp +++ b/components/vfs/bsaarchive.cpp @@ -7,7 +7,7 @@ namespace VFS { -BsaArchive::BsaArchive(const std::string &filename) +BsaArchive::BsaArchive(const std::filesystem::path &filename) { mFile = std::make_unique(); mFile->open(filename); @@ -68,7 +68,7 @@ Files::IStreamPtr BsaArchiveFile::open() return mFile->getFile(mInfo); } -CompressedBsaArchive::CompressedBsaArchive(const std::string &filename) +CompressedBsaArchive::CompressedBsaArchive(const std::filesystem::path &filename) : Archive() { mCompressedFile = std::make_unique(); diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index a52104efd7..23811c045b 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -15,7 +15,7 @@ namespace VFS Files::IStreamPtr open() override; - std::string getPath() override { return mInfo->name(); } + std::filesystem::path getPath() override { return mInfo->name(); } const Bsa::BSAFile::FileStruct* mInfo; Bsa::BSAFile* mFile; @@ -28,7 +28,7 @@ namespace VFS Files::IStreamPtr open() override; - std::string getPath() override { return mInfo->name(); } + std::filesystem::path getPath() override { return mInfo->name(); } const Bsa::BSAFile::FileStruct* mInfo; Bsa::CompressedBSAFile* mCompressedFile; @@ -38,7 +38,7 @@ namespace VFS class BsaArchive : public Archive { public: - BsaArchive(const std::string& filename); + BsaArchive(const std::filesystem::path &filename); BsaArchive(); virtual ~BsaArchive(); void listResources(std::map& out, char (*normalize_function) (char)) override; @@ -53,7 +53,7 @@ namespace VFS class CompressedBsaArchive : public Archive { public: - CompressedBsaArchive(const std::string& filename); + CompressedBsaArchive(const std::filesystem::path &filename); virtual ~CompressedBsaArchive() {} void listResources(std::map& out, char (*normalize_function) (char)) override; bool contains(const std::string& file, char (*normalize_function) (char)) const override; diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index 7b57c93944..f6b01a89c4 100644 --- a/components/vfs/filesystemarchive.cpp +++ b/components/vfs/filesystemarchive.cpp @@ -10,7 +10,7 @@ namespace VFS { - FileSystemArchive::FileSystemArchive(const std::string &path) + FileSystemArchive::FileSystemArchive(const std::filesystem::path &path) : mBuiltIndex(false) , mPath(path) { @@ -21,31 +21,30 @@ namespace VFS { if (!mBuiltIndex) { - typedef std::filesystem::recursive_directory_iterator directory_iterator; + const auto str = mPath.string(); //TODO(Project579): This will probably break in windows with unicode paths + size_t prefix = str.size (); - directory_iterator end; - - size_t prefix = mPath.size (); - - if (mPath.size () > 0 && mPath [prefix - 1] != '\\' && mPath [prefix - 1] != '/') + if (!mPath.empty() && str [prefix - 1] != '\\' && str [prefix - 1] != '/') ++prefix; - for (directory_iterator i (std::filesystem::u8path(mPath)); i != end; ++i) + for (const auto& i : + std::filesystem::recursive_directory_iterator(mPath)) { - if(std::filesystem::is_directory (*i)) + if(std::filesystem::is_directory (i)) continue; - auto proper = i->path ().u8string (); + const auto& path = i.path (); + const auto& proper = path.string (); //TODO(Project579): This will probably break in windows with unicode paths - FileSystemArchiveFile file(std::string((char*)proper.c_str(), proper.size())); + FileSystemArchiveFile file(path); std::string searchable; - std::transform(proper.begin() + prefix, proper.end(), std::back_inserter(searchable), normalize_function); + std::transform(std::next(proper.begin(), static_cast(prefix)), proper.end(), std::back_inserter(searchable), normalize_function); const auto inserted = mIndex.insert(std::make_pair(searchable, file)); if (!inserted.second) - Log(Debug::Warning) << "Warning: found duplicate file for '" << std::string((char*)proper.c_str(), proper.size()) << "', please check your file system for two files with the same name in different cases."; + Log(Debug::Warning) << "Warning: found duplicate file for '" << proper << "', please check your file system for two files with the same name in different cases."; //TODO(Project579): This will probably break in windows with unicode paths else out[inserted.first->first] = &inserted.first->second; } @@ -67,12 +66,12 @@ namespace VFS std::string FileSystemArchive::getDescription() const { - return std::string{"DIR: "} + mPath; + return std::string{"DIR: "} + mPath.string(); //TODO(Project579): This will probably break in windows with unicode paths } // ---------------------------------------------------------------------------------- - FileSystemArchiveFile::FileSystemArchiveFile(const std::string &path) + FileSystemArchiveFile::FileSystemArchiveFile(const std::filesystem::path &path) : mPath(path) { } diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp index 2c50e5300b..678eb19f95 100644 --- a/components/vfs/filesystemarchive.hpp +++ b/components/vfs/filesystemarchive.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_COMPONENTS_RESOURCE_FILESYSTEMARCHIVE_H #define OPENMW_COMPONENTS_RESOURCE_FILESYSTEMARCHIVE_H +#include #include "archive.hpp" #include @@ -11,21 +12,21 @@ namespace VFS class FileSystemArchiveFile : public File { public: - FileSystemArchiveFile(const std::string& path); + FileSystemArchiveFile(const std::filesystem::path &path); Files::IStreamPtr open() override; - std::string getPath() override { return mPath; } + std::filesystem::path getPath() override { return mPath; } private: - std::string mPath; + std::filesystem::path mPath; }; class FileSystemArchive : public Archive { public: - FileSystemArchive(const std::string& path); + FileSystemArchive(const std::filesystem::path &path); void listResources(std::map& out, char (*normalize_function) (char)) override; @@ -38,7 +39,7 @@ namespace VFS index mIndex; bool mBuiltIndex; - std::string mPath; + std::filesystem::path mPath; }; diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index c8434fd9fd..8f3963f3f7 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -56,7 +56,7 @@ namespace VFS mIndex.clear(); for (const auto& archive : mArchives) - archive->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); + archive->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); //TODO(Project579): This will probably break in windows with unicode paths } Files::IStreamPtr Manager::get(std::string_view name) const @@ -102,15 +102,15 @@ namespace VFS return {}; } - std::string Manager::getAbsoluteFileName(std::string_view name) const + std::filesystem::path Manager::getAbsoluteFileName(const std::filesystem::path &name) const { - std::string normalized(name); - normalize_path(normalized, mStrict); + std::string normalized(name); //TODO(Project579): This will probably break in windows with unicode paths + normalize_path(normalized, mStrict); //TODO(Project579): This will probably break in windows with unicode paths - std::map::const_iterator found = mIndex.find(normalized); + const auto found = mIndex.find(normalized); if (found == mIndex.end()) throw std::runtime_error("Resource '" + normalized + "' not found"); - return found->second->getPath(); + return found->second->getPath();//TODO(Project579): This will probably break in windows with unicode paths } namespace diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index ab42a643a5..8f8f6e450f 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -94,7 +94,7 @@ namespace VFS /// Retrieve the absolute path to the file /// @note Throws an exception if the file can not be found. /// @note May be called from any thread once the index has been built. - std::string getAbsoluteFileName(std::string_view name) const; + std::filesystem::path getAbsoluteFileName(const std::filesystem::path &name) const; private: bool mStrict; diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp index 80f4561136..dd8287818e 100644 --- a/components/vfs/registerarchives.cpp +++ b/components/vfs/registerarchives.cpp @@ -22,8 +22,8 @@ namespace VFS if (collections.doesExist(*archive)) { // Last BSA has the highest priority - const std::string archivePath = collections.getPath(*archive).string(); - Log(Debug::Info) << "Adding BSA archive " << archivePath; + const auto archivePath = collections.getPath(*archive); + Log(Debug::Info) << "Adding BSA archive " << archivePath; //TODO(Project579): This will probably break in windows with unicode paths Bsa::BsaVersion bsaVersion = Bsa::CompressedBSAFile::detectVersion(archivePath); if (bsaVersion == Bsa::BSAVER_COMPRESSED) @@ -49,7 +49,7 @@ namespace VFS vfs->addArchive(std::make_unique(dataDir)); } else - Log(Debug::Info) << "Ignoring duplicate data directory " << dataDir; + Log(Debug::Info) << "Ignoring duplicate data directory " << dataDir; //TODO(Project579): This will probably break in windows with unicode paths } } From 6bf4c7a04fc0a7148300e9af24c16a3e11b394b6 Mon Sep 17 00:00:00 2001 From: Project579 Date: Mon, 20 Jun 2022 20:48:06 +0200 Subject: [PATCH 15/36] Upgraded "input-file" command line option to Files::MaybeQuotedPath from std::string to allow unicode characters on Windows. --- apps/bsatool/bsatool.cpp | 25 ++++++++++++++----------- apps/esmtool/esmtool.cpp | 8 +++++--- apps/niftest/niftest.cpp | 15 +++++++-------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index ad4556ddc6..16c25594c6 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -8,6 +8,7 @@ #include #include +#include #define BSATOOL_VERSION 1.1 @@ -112,37 +113,39 @@ bool parseOptions (int argc, char** argv, Arguments &info) << desc << std::endl; return false; } - info.filename = variables["input-file"].as< std::vector >()[0]; //TODO(Project579): This will probably break in windows with unicode paths + auto inputFiles = variables["input-file"].as< std::vector >(); + + info.filename = inputFiles[0]; // Default output to the working directory info.outdir = "."; if (info.mode == "extract") { - if (variables["input-file"].as< std::vector >().size() < 2) + if (inputFiles.size() < 2) { std::cout << "\nERROR: file to extract unspecified\n\n" << desc << std::endl; return false; } - if (variables["input-file"].as< std::vector >().size() > 1) - info.extractfile = variables["input-file"].as< std::vector >()[1]; - if (variables["input-file"].as< std::vector >().size() > 2) - info.outdir = variables["input-file"].as< std::vector >()[2]; + if (inputFiles.size() > 1) + info.extractfile = inputFiles[1]; + if (inputFiles.size() > 2) + info.outdir = inputFiles[2]; } else if (info.mode == "add") { - if (variables["input-file"].as< std::vector >().size() < 1) + if (inputFiles.empty()) { std::cout << "\nERROR: file to add unspecified\n\n" << desc << std::endl; return false; } - if (variables["input-file"].as< std::vector >().size() > 1) - info.addfile = variables["input-file"].as< std::vector >()[1]; + if (inputFiles.size() > 1) + info.addfile = inputFiles[1]; } - else if (variables["input-file"].as< std::vector >().size() > 1) - info.outdir = variables["input-file"].as< std::vector >()[1]; + else if (inputFiles.size() > 1) + info.outdir = inputFiles[1]; info.longformat = variables.count("long") != 0; info.fullpath = variables.count("full-path") != 0; diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index a9971c1867..fa46b4d910 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "record.hpp" #include "labels.hpp" @@ -154,9 +155,10 @@ bool parseOptions (int argc, char** argv, Arguments &info) return false; }*/ - info.filename = variables["input-file"].as< std::vector >()[0]; - if (variables["input-file"].as< std::vector >().size() > 1) - info.outname = variables["input-file"].as< std::vector >()[1]; + const auto inputFiles = variables["input-file"].as< std::vector >(); + info.filename = inputFiles[0]; + if (inputFiles.size() > 1) + info.outname = inputFiles[1]; if (const auto it = variables.find("raw"); it != variables.end()) info.mRawFormat = ESM::parseFormat(it->second.as()); diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 60b13ae266..68d5a0f898 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -66,7 +67,7 @@ void readVFS(std::unique_ptr&& anArchive, const std::filesystem::p } } -bool parseOptions (int argc, char** argv, std::vector& files) +bool parseOptions (int argc, char** argv, std::vector &files) { bpo::options_description desc("Ensure that OpenMW can use the provided NIF and BSA files\n\n" "Usages:\n" @@ -75,7 +76,7 @@ bool parseOptions (int argc, char** argv, std::vector& files) "Allowed options"); desc.add_options() ("help,h", "print help message.") - ("input-file", bpo::value< std::vector >(), "input file") + ("input-file", bpo::value< std::vector >(), "input file") ; //Default option if none provided @@ -96,7 +97,7 @@ bool parseOptions (int argc, char** argv, std::vector& files) } if (variables.count("input-file")) { - files = variables["input-file"].as< std::vector >(); + files = variables["input-file"].as< std::vector >(); return true; } } @@ -114,18 +115,16 @@ bool parseOptions (int argc, char** argv, std::vector& files) int main(int argc, char **argv) { - std::vector files; + std::vector files; if(!parseOptions (argc, argv, files)) return 1; Nif::NIFFile::setLoadUnsupportedFiles(true); // std::cout << "Reading Files" << std::endl; - for(const auto& name : files) + for(const auto& path : files) { try { - const std::filesystem::path path(name); //TODO(Project579): This will probably break in windows with unicode paths - if(isNIF(path)) { //std::cout << "Decoding: " << name << std::endl; @@ -143,7 +142,7 @@ int main(int argc, char **argv) } else { - std::cerr << "ERROR: \"" << path << "\" is not a nif file, bsa file, or directory!" << std::endl; + std::cerr << "ERROR: \"" << path << "\" is not a nif file, bsa file, or directory!" << std::endl; //TODO(Project579): This will probably break in windows with unicode paths } } catch (std::exception& e) From 864112b5dbb0fda9c6a0440a09dea23aa8beb3fa Mon Sep 17 00:00:00 2001 From: Project579 Date: Thu, 23 Jun 2022 19:13:10 +0200 Subject: [PATCH 16/36] Fixed Windows build when using MSVC 14.26 and MacOS build. --- apps/bsatool/bsatool.cpp | 33 +++++++++---------- apps/esmtool/esmtool.cpp | 4 +-- apps/opencs/editor.cpp | 4 +-- apps/openmw/main.cpp | 10 +++--- apps/openmw_test_suite/mwworld/test_store.cpp | 2 +- components/files/configurationmanager.cpp | 10 ++++-- components/files/macospath.cpp | 3 +- 7 files changed, 36 insertions(+), 30 deletions(-) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 16c25594c6..6313b92e95 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -19,9 +19,9 @@ struct Arguments { std::string mode; std::filesystem::path filename; - std::string extractfile; - std::string addfile; - std::string outdir; + std::filesystem::path extractfile; + std::filesystem::path addfile; + std::filesystem::path outdir; bool longformat; bool fullpath; @@ -115,10 +115,10 @@ bool parseOptions (int argc, char** argv, Arguments &info) } auto inputFiles = variables["input-file"].as< std::vector >(); - info.filename = inputFiles[0]; + info.filename = inputFiles[0].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. // Default output to the working directory - info.outdir = "."; + info.outdir = std::filesystem::current_path(); if (info.mode == "extract") { @@ -129,9 +129,9 @@ bool parseOptions (int argc, char** argv, Arguments &info) return false; } if (inputFiles.size() > 1) - info.extractfile = inputFiles[1]; + info.extractfile = inputFiles[1].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. if (inputFiles.size() > 2) - info.outdir = inputFiles[2]; + info.outdir = inputFiles[2].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. } else if (info.mode == "add") { @@ -142,10 +142,10 @@ bool parseOptions (int argc, char** argv, Arguments &info) return false; } if (inputFiles.size() > 1) - info.addfile = inputFiles[1]; + info.addfile = inputFiles[1].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. } else if (inputFiles.size() > 1) - info.outdir = inputFiles[1]; + info.outdir = inputFiles[1].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. info.longformat = variables.count("long") != 0; info.fullpath = variables.count("full-path") != 0; @@ -179,10 +179,10 @@ int list(std::unique_ptr& bsa, Arguments& info) template int extract(std::unique_ptr& bsa, Arguments& info) { - std::string archivePath = info.extractfile; + std::string archivePath = info.extractfile.string(); //TODO(Project579): This will probably break in windows with unicode paths Misc::StringUtils::replaceAll(archivePath, "/", "\\"); - std::string extractPath = info.extractfile; + std::string extractPath = info.extractfile.string(); //TODO(Project579): This will probably break in windows with unicode paths Misc::StringUtils::replaceAll(extractPath, "\\", "/"); Files::IStreamPtr stream; @@ -204,13 +204,12 @@ int extract(std::unique_ptr& bsa, Arguments& info) // Get the target path (the path the file will be extracted to) std::filesystem::path relPath (extractPath); - std::filesystem::path outdir (info.outdir); std::filesystem::path target; if (info.fullpath) - target = outdir / relPath; + target = info.outdir / relPath; else - target = outdir / relPath.filename(); + target = info.outdir / relPath.filename(); // Create the directory hierarchy std::filesystem::create_directories(target.parent_path()); @@ -225,7 +224,7 @@ int extract(std::unique_ptr& bsa, Arguments& info) std::ofstream out(target, std::ios::binary); // Write the file to disk - std::cout << "Extracting " << info.extractfile << " to " << target << std::endl; + std::cout << "Extracting " << info.extractfile << " to " << target << std::endl; //TODO(Project579): This will probably break in windows with unicode paths out << stream->rdbuf(); out.close(); @@ -242,7 +241,7 @@ int extractAll(std::unique_ptr& bsa, Arguments& info) Misc::StringUtils::replaceAll(extractPath, "\\", "/"); // Get the target path (the path the file will be extracted to) - std::filesystem::path target (info.outdir); + auto target = info.outdir; target /= extractPath; // Create the directory hierarchy @@ -272,7 +271,7 @@ template int add(std::unique_ptr& bsa, Arguments& info) { std::fstream stream(info.addfile, std::ios_base::binary | std::ios_base::out | std::ios_base::in); - bsa->addFile(info.addfile, stream); + bsa->addFile(info.addfile.string(), stream); //TODO(Project579): This will probably break in windows with unicode paths return 0; } diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index fa46b4d910..f95777d0ef 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -156,9 +156,9 @@ bool parseOptions (int argc, char** argv, Arguments &info) }*/ const auto inputFiles = variables["input-file"].as< std::vector >(); - info.filename = inputFiles[0]; + info.filename = inputFiles[0].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. if (inputFiles.size() > 1) - info.outname = inputFiles[1]; + info.outname = inputFiles[1].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. if (const auto it = variables.find("raw"); it != variables.end()) info.mRawFormat = ESM::parseFormat(it->second.as()); diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 9a988991f0..8dee97bd46 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -121,7 +121,7 @@ std::pair > CS::Editor::readConfi mDocumentManager.setEncoding(ToUTF8::calculateEncoding(mEncodingName)); mFileDialog.setEncoding (QString::fromUtf8(mEncodingName.c_str())); - mDocumentManager.setResourceDir (mResources = variables["resources"].as()); + mDocumentManager.setResourceDir (mResources = variables["resources"].as().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. if (variables["script-blacklist-use"].as()) mDocumentManager.setBlacklistedScripts ( @@ -134,7 +134,7 @@ std::pair > CS::Editor::readConfi dataDirs = asPathContainer(variables["data"].as()); } - Files::PathContainer::value_type local(variables["data-local"].as()); + Files::PathContainer::value_type local(variables["data-local"].as().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. if (!local.empty()) { std::filesystem::create_directories(local); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index c327683bee..9700142ab8 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -61,7 +61,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat { cfgMgr.readConfiguration(variables, desc, true); - Version::Version v = Version::getOpenmwVersion(variables["resources"].as()); + Version::Version v = Version::getOpenmwVersion(variables["resources"].as().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. getRawStdout() << v.describe() << std::endl; return false; } @@ -72,7 +72,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat setupLogging(cfgMgr.getLogPath(), "OpenMW"); MWGui::DebugWindow::startLogRecording(); - Version::Version v = Version::getOpenmwVersion(variables["resources"].as()); + Version::Version v = Version::getOpenmwVersion(variables["resources"].as().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. Log(Debug::Info) << v.describe(); engine.setGrabMouse(!variables["no-grab"].as()); @@ -87,13 +87,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat Files::PathContainer dataDirs(asPathContainer(variables["data"].as())); - Files::PathContainer::value_type local(variables["data-local"].as()); + Files::PathContainer::value_type local(variables["data-local"].as().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. if (!local.empty()) dataDirs.push_back(local); cfgMgr.filterOutNonExistingPaths(dataDirs); - engine.setResourceDir(variables["resources"].as()); + engine.setResourceDir(variables["resources"].as().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. engine.setDataDirs(dataDirs); // fallback archives @@ -150,7 +150,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setWarningsMode (variables["script-warn"].as()); engine.setScriptBlacklist (variables["script-blacklist"].as()); engine.setScriptBlacklistUse (variables["script-blacklist-use"].as()); - engine.setSaveGameFile (variables["load-savegame"].as()); + engine.setSaveGameFile (variables["load-savegame"].as().u8string()); // other settings Fallback::Map::init(variables["fallback"].as().mMap); diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index b5fbf5a291..ba0abd293d 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -74,7 +74,7 @@ struct ContentFileTest : public ::testing::Test dataDirs = asPathContainer(variables["data"].as()); } - Files::PathContainer::value_type local(variables["data-local"].as()); + Files::PathContainer::value_type local(variables["data-local"].as().u8string()); if (!local.empty()) dataLocal.push_back(local); diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 0fc228abee..6ceab167e5 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -137,7 +137,7 @@ void ConfigurationManager::readConfiguration(bpo::variables_map& variables, mergeComposingVariables(variables, composingVariables, description); } - mUserDataPath = variables["user-data"].as(); + mUserDataPath = variables["user-data"].as().u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. if (mUserDataPath.empty()) { if (!quiet) @@ -451,7 +451,13 @@ std::istream& operator>> (std::istream& istream, MaybeQuotedPath& MaybeQuotedPat PathContainer asPathContainer(const MaybeQuotedPathContainer& MaybeQuotedPathContainer) { - return PathContainer(MaybeQuotedPathContainer.begin(), MaybeQuotedPathContainer.end()); + PathContainer res; + res.reserve(MaybeQuotedPathContainer.size()); + for (const auto & maybeQuotedPath : MaybeQuotedPathContainer) + { + res.emplace_back(maybeQuotedPath.u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. + } + return res; } } /* namespace Files */ diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index c0505dbea0..e6dc8e55b7 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -90,7 +91,7 @@ std::filesystem::path MacOsPath::getInstallPath() const if (std::filesystem::is_regular_file(wineDefaultRegistry)) { - std::filesystem::ifstream file(wineDefaultRegistry); + std::ifstream file(wineDefaultRegistry); bool isRegEntry = false; std::string line; std::string mwpath; From b817359bcf5f3d0de7bf7c20da73fc39d013d0e8 Mon Sep 17 00:00:00 2001 From: Project579 Date: Tue, 28 Jun 2022 22:08:30 +0200 Subject: [PATCH 17/36] Revert "Fix regression from https://gitlab.com/OpenMW/openmw/-/merge_requests/1776" This reverts commit 6a5ad4ca43876e13f3a6fcf499c4b5b4c1335687. --- components/files/openfile.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/components/files/openfile.cpp b/components/files/openfile.cpp index 2ab4409017..6eb0ee51c8 100644 --- a/components/files/openfile.cpp +++ b/components/files/openfile.cpp @@ -3,20 +3,11 @@ #include #include -#if defined(_WIN32) || defined(__WINDOWS__) -#include -#endif - namespace Files { std::unique_ptr openBinaryInputFileStream(const std::filesystem::path &path) { -#if defined(_WIN32) || defined(__WINDOWS__) - std::wstring wpath = boost::locale::conv::utf_to_utf(path); - auto stream = std::make_unique(wpath, std::ios::binary); -#else auto stream = std::make_unique(path, std::ios::binary); -#endif if (!stream->is_open()) throw std::runtime_error("Failed to open '" + path.string() + "' for reading: " + std::strerror(errno)); //TODO(Project579): This will probably break in windows with unicode paths stream->exceptions(std::ios::badbit); From 78ab009d5cc4830d3563bd1e769fded29114a531 Mon Sep 17 00:00:00 2001 From: Project579 Date: Wed, 29 Jun 2022 23:08:33 +0200 Subject: [PATCH 18/36] Add required overloads to logger for handling unicode paths, also add conversion functions from std::filesystem::path to std::string without losing unicode data. --- components/debug/debuglog.cpp | 45 ++++++++++++++++++++++- components/debug/debuglog.hpp | 11 ++++++ components/files/configurationmanager.cpp | 25 +++++++++++++ components/files/configurationmanager.hpp | 10 +++++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/components/debug/debuglog.cpp b/components/debug/debuglog.cpp index f4f0fdffa6..ef453283e8 100644 --- a/components/debug/debuglog.cpp +++ b/components/debug/debuglog.cpp @@ -1,6 +1,9 @@ #include "debuglog.hpp" + #include +#include + namespace Debug { Level CurrentDebugLevel = Level::NoLevel; @@ -8,7 +11,7 @@ namespace Debug static std::mutex sLock; -Log::Log(Debug::Level level) +Log::Log(Debug::Level level) : mShouldLog(level <= Debug::CurrentDebugLevel) { // No need to hold the lock if there will be no logging anyway @@ -34,3 +37,43 @@ Log::~Log() std::cout << std::endl; sLock.unlock(); } + +Log& Log::operator<<(std::filesystem::path&& rhs) +{ + if (mShouldLog) + std::cout << Files::pathToUnicodeString(std::move(rhs)); + + return *this; +} + +Log& Log::operator<<(const std::filesystem::path& rhs) +{ + if (mShouldLog) + std::cout << Files::pathToUnicodeString(rhs); + + return *this; +} + +Log& Log::operator<<(std::u8string&& rhs) +{ + if (mShouldLog) + std::cout << Misc::StringUtils::u8StringToString(std::move(rhs)); + + return *this; +} + +Log& Log::operator<<(const std::u8string& rhs) +{ + if (mShouldLog) + std::cout << Misc::StringUtils::u8StringToString(rhs); + + return *this; +} + +Log& Log::operator<<(const char8_t* rhs) +{ + if (mShouldLog) + std::cout << Misc::StringUtils::u8StringToString(rhs); + + return *this; +} diff --git a/components/debug/debuglog.hpp b/components/debug/debuglog.hpp index aa8156e119..526763d9f6 100644 --- a/components/debug/debuglog.hpp +++ b/components/debug/debuglog.hpp @@ -2,6 +2,7 @@ #define DEBUG_LOG_H #include +#include namespace Debug { @@ -36,6 +37,16 @@ public: return *this; } + Log& operator<<(std::filesystem::path&& rhs); + + Log& operator<<(const std::filesystem::path& rhs); + + Log& operator<<(std::u8string&& rhs); + + Log& operator<<(const std::u8string& rhs); + + Log& operator<<(const char8_t* rhs); + private: const bool mShouldLog; }; diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 6ceab167e5..90ac748361 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -460,4 +460,29 @@ PathContainer asPathContainer(const MaybeQuotedPathContainer& MaybeQuotedPathCon return res; } +std::string pathToUnicodeString(const std::filesystem::path& path) +{ + return Misc::StringUtils::u8StringToString(path.u8string()); +} + +std::string pathToUnicodeString(std::filesystem::path&& path) +{ + return Misc::StringUtils::u8StringToString(path.u8string()); +} + +std::filesystem::path unicodeStringToPath(const std::string_view path) +{ + return Misc::StringUtils::stringToU8String(path); +} + +std::filesystem::path unicodeStringToPath(std::string&& path) +{ + return Misc::StringUtils::stringToU8String(std::move(path)); +} + +std::filesystem::path unicodeStringToPath(const char* path) +{ + return Misc::StringUtils::stringToU8String(path); +} + } /* namespace Files */ diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 74f035ffb6..028feb2c0d 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -105,6 +105,16 @@ typedef std::vector MaybeQuotedPathContainer; PathContainer asPathContainer(const MaybeQuotedPathContainer& MaybeQuotedPathContainer); +std::string pathToUnicodeString(const std::filesystem::path& path); + +std::string pathToUnicodeString(std::filesystem::path&& path); + +std::filesystem::path unicodeStringToPath(const std::string_view path); + +std::filesystem::path unicodeStringToPath(std::string&& path); + +std::filesystem::path unicodeStringToPath(const char* path); + } /* namespace Files */ #endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */ From dec3f24375847b70c5ae8854b88475c19308b163 Mon Sep 17 00:00:00 2001 From: Project579 Date: Thu, 30 Jun 2022 19:26:14 +0200 Subject: [PATCH 19/36] filesystem: configurationmanager: Store file path tokens as std::u8string. --- components/files/configurationmanager.cpp | 40 +++++++++++------------ components/files/configurationmanager.hpp | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 90ac748361..cddab2f8b2 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -25,10 +25,10 @@ static const char* const applicationName = "OpenMW"; static const char* const applicationName = "openmw"; #endif -const char* const localToken = "?local?"; -const char* const userConfigToken = "?userconfig?"; -const char* const userDataToken = "?userdata?"; -const char* const globalToken = "?global?"; +static constexpr auto localToken = u8"?local?"; +static constexpr auto userConfigToken = u8"?userconfig?"; +static constexpr auto userDataToken = u8"?userdata?"; +static constexpr auto globalToken = u8"?global?"; ConfigurationManager::ConfigurationManager(bool silent) : mFixedPath(applicationName) @@ -94,7 +94,7 @@ void ConfigurationManager::readConfiguration(bpo::variables_map& variables, std::vector parsedConfigs{*std::move(config)}; std::set alreadyParsedPaths; // needed to prevent infinite loop in case of a circular link - alreadyParsedPaths.insert(std::filesystem::path(mActiveConfigPaths.front())); + alreadyParsedPaths.insert(mActiveConfigPaths.front()); while (!extraConfigDirs.empty()) { @@ -155,9 +155,9 @@ void ConfigurationManager::readConfiguration(bpo::variables_map& variables, if (!quiet) { - Log(Debug::Info) << "Logs dir: " << getUserConfigPath().string(); //TODO(Project579): This will probably break in windows with unicode paths - Log(Debug::Info) << "User data dir: " << mUserDataPath.string(); //TODO(Project579): This will probably break in windows with unicode paths - Log(Debug::Info) << "Screenshots dir: " << mScreenshotPath.string(); //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Logs dir: " << getUserConfigPath(); + Log(Debug::Info) << "User data dir: " << mUserDataPath; + Log(Debug::Info) << "Screenshots dir: " << mScreenshotPath; } mSilent = silent; @@ -239,7 +239,7 @@ void mergeComposingVariables(bpo::variables_map& first, bpo::variables_map& seco boost::any& firstValue = firstPosition->second.value(); const boost::any& secondValue = second[name].value(); - + if (firstValue.type() == typeid(Files::MaybeQuotedPathContainer)) { auto& firstPathContainer = boost::any_cast(firstValue); @@ -270,22 +270,22 @@ void mergeComposingVariables(bpo::variables_map& first, bpo::variables_map& seco void ConfigurationManager::processPath(std::filesystem::path& path, const std::filesystem::path& basePath) const { - std::string str = path.string(); //TODO(Project579): This will probably break in windows with unicode paths + const auto str = path.u8string(); - if (str.empty() || str[0] != '?') + if (str.empty() || str[0] != u8'?') { if (!path.is_absolute()) path = basePath / path; return; } - std::string::size_type pos = str.find('?', 1); - if (pos != std::string::npos && pos != 0) + const auto pos = str.find('?', 1); + if (pos != std::u8string::npos && pos != 0) { auto tokenIt = mTokensMapping.find(str.substr(0, pos + 1)); if (tokenIt != mTokensMapping.end()) { - std::filesystem::path tempPath(((mFixedPath).*(tokenIt->second))()); //TODO(Project579): This will probably break in windows with unicode paths + auto tempPath(((mFixedPath).*(tokenIt->second))()); if (pos < str.length() - 1) { // There is something after the token, so we should @@ -293,7 +293,7 @@ void ConfigurationManager::processPath(std::filesystem::path& path, const std::f tempPath /= str.substr(pos + 1, str.length() - pos); } - path = tempPath; //TODO(Project579): This will probably break in windows with unicode paths + path = tempPath; } else { @@ -347,11 +347,11 @@ std::optional ConfigurationManager::loadConfig( const std::filesystem::path& path, const bpo::options_description& description) const { std::filesystem::path cfgFile(path); - cfgFile /= std::string(openmwCfgFile); + cfgFile /= openmwCfgFile; if (std::filesystem::is_regular_file(cfgFile)) { if (!mSilent) - Log(Debug::Info) << "Loading config file: " << cfgFile.string(); //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Loading config file: " << cfgFile; std::ifstream configFileStream(cfgFile); @@ -434,17 +434,17 @@ std::istream& operator>> (std::istream& istream, MaybeQuotedPath& MaybeQuotedPat { std::string intermediate; istream >> std::quoted(intermediate, '"', '&'); - static_cast(MaybeQuotedPath) = intermediate; + static_cast(MaybeQuotedPath) = Misc::StringUtils::stringToU8String(intermediate); if (istream && !istream.eof() && istream.peek() != EOF) { std::string remainder{std::istreambuf_iterator(istream), {}}; - Log(Debug::Warning) << "Trailing data in path setting. Used '" << MaybeQuotedPath.string() << "' but '" << remainder << "' remained"; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Warning) << "Trailing data in path setting. Used '" << MaybeQuotedPath << "' but '" << remainder << "' remained"; } } else { std::string intermediate{std::istreambuf_iterator(istream), {}}; - static_cast(MaybeQuotedPath) = intermediate; + static_cast(MaybeQuotedPath) = Misc::StringUtils::stringToU8String(intermediate); } return istream; } diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 028feb2c0d..e10d528404 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -60,7 +60,7 @@ struct ConfigurationManager typedef Files::FixedPath<> FixedPathType; typedef const std::filesystem::path& (FixedPathType::*path_type_f)() const; - typedef std::map TokensMappingContainer; + typedef std::map TokensMappingContainer; std::optional loadConfig( const std::filesystem::path& path, From 4d47e8d055b7a0347560b02cab1e141af076976f Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 2 Jul 2022 22:15:25 +0200 Subject: [PATCH 20/36] openmw-cs: model: world: data: Remove dead code. --- apps/opencs/model/world/data.cpp | 2 -- apps/opencs/model/world/data.hpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 4fd3939883..3ac499b4f4 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -991,8 +991,6 @@ int CSMWorld::Data::startLoading (const std::filesystem::path& path, bool base, mReader->setIndex((project || !base) ? 0 : mReaderIndex++); mReader->open (path); - mContentFileNames.insert(std::make_pair(path.filename().string(), mReader->getIndex())); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break - mBase = base; mProject = project; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 2764daa8aa..112ac1b239 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -126,8 +126,6 @@ namespace CSMWorld std::vector > mReaders; - std::map mContentFileNames; - // not implemented Data (const Data&); Data& operator= (const Data&); From a13709c510bb1224eb4ad2743cec420c443b4989 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sun, 3 Jul 2022 00:02:29 +0200 Subject: [PATCH 21/36] Replace implicit convertions from std::filesystem::path to std::string with correctly converting functions. --- apps/bsatool/bsatool.cpp | 21 +++--- apps/bulletobjecttool/main.cpp | 3 +- apps/esmtool/esmtool.cpp | 13 ++-- apps/esmtool/tes4.cpp | 2 +- apps/launcher/datafilespage.cpp | 8 +-- apps/launcher/maindialog.cpp | 32 ++++----- apps/launcher/settingspage.cpp | 8 +-- apps/mwiniimporter/importer.cpp | 3 +- apps/navmeshtool/main.cpp | 5 +- apps/niftest/niftest.cpp | 7 +- apps/opencs/editor.cpp | 2 +- apps/opencs/editor.hpp | 2 +- apps/opencs/model/doc/blacklist.cpp | 2 +- apps/opencs/model/doc/document.cpp | 17 ++--- apps/opencs/model/doc/loader.cpp | 4 +- apps/opencs/model/doc/runner.cpp | 11 ++- apps/opencs/model/doc/runner.hpp | 4 +- apps/opencs/model/doc/savingstages.cpp | 5 +- apps/opencs/model/world/commanddispatcher.cpp | 4 +- apps/opencs/model/world/regionmap.cpp | 4 +- apps/opencs/model/world/scriptcontext.cpp | 4 +- apps/opencs/view/doc/adjusterwidget.cpp | 12 ++-- apps/opencs/view/doc/loader.cpp | 2 +- apps/opencs/view/doc/view.cpp | 3 +- apps/opencs/view/doc/viewmanager.cpp | 2 +- apps/opencs/view/tools/merge.cpp | 4 +- apps/openmw/engine.cpp | 20 +++--- apps/openmw/mwgui/savegamedialog.cpp | 3 +- apps/openmw/mwinput/bindingsmanager.cpp | 5 +- apps/openmw/mwinput/controllermanager.cpp | 6 +- apps/openmw/mwrender/postprocessor.cpp | 11 +-- apps/openmw/mwrender/water.cpp | 6 +- apps/openmw/mwscript/miscextensions.cpp | 3 +- apps/openmw/mwscript/scriptmanagerimp.cpp | 2 +- apps/openmw/mwstate/statemanagerimp.cpp | 7 +- apps/openmw/mwworld/esmloader.cpp | 7 +- apps/openmw/mwworld/worldimp.cpp | 13 ++-- apps/openmw_test_suite/files/hash.cpp | 9 +-- apps/openmw_test_suite/mwworld/test_store.cpp | 5 +- apps/openmw_test_suite/openmw/options.cpp | 67 ++++++++++--------- .../shader/shadermanager.cpp | 21 +++--- apps/openmw_test_suite/testing_util.hpp | 3 +- apps/wizard/installationtargetpage.cpp | 4 +- apps/wizard/mainwizard.cpp | 2 +- components/CMakeLists.txt | 2 +- components/bsa/bsa_file.cpp | 2 +- components/bsa/bsa_file.hpp | 3 +- components/bsa/compressedbsafile.cpp | 48 ++++++------- components/bsa/compressedbsafile.hpp | 2 +- components/config/gamesettings.cpp | 4 +- components/config/launchersettings.cpp | 2 +- .../crashcatcher/windows_crashcatcher.cpp | 2 +- components/debug/debugging.cpp | 6 +- components/debug/debuglog.cpp | 3 +- components/detournavigator/navigator.cpp | 3 +- components/esm3/esmreader.cpp | 5 +- components/esm3/loadcell.cpp | 2 +- components/esm4/reader.cpp | 10 +-- components/esmloader/load.cpp | 3 +- components/files/collections.cpp | 12 ++-- components/files/collections.hpp | 4 +- components/files/configurationmanager.cpp | 25 ------- components/files/configurationmanager.hpp | 10 --- components/files/conversion.cpp | 29 ++++++++ components/files/conversion.hpp | 18 +++++ components/files/hash.cpp | 3 +- components/files/linuxpath.cpp | 4 +- components/files/multidircollection.cpp | 12 ++-- components/files/openfile.cpp | 3 +- components/fx/technique.cpp | 8 ++- components/fx/technique.hpp | 2 +- components/lua/luastate.cpp | 3 +- components/lua/storage.cpp | 4 +- components/myguiplatform/myguidatamanager.cpp | 3 +- components/myguiplatform/myguiloglistener.cpp | 2 +- components/nif/niffile.cpp | 2 +- components/nifbullet/bulletnifloader.cpp | 3 +- components/nifosg/nifloader.cpp | 54 +++++++-------- components/resource/scenemanager.cpp | 5 +- components/sceneutil/screencapture.cpp | 3 +- components/settings/parser.cpp | 2 +- components/settings/shadermanager.hpp | 5 +- components/shader/shadermanager.cpp | 4 +- components/version/version.cpp | 2 +- components/version/version.hpp | 2 +- components/vfs/filesystemarchive.cpp | 9 +-- components/vfs/manager.cpp | 10 +-- components/vfs/registerarchives.cpp | 4 +- 88 files changed, 394 insertions(+), 328 deletions(-) create mode 100644 components/files/conversion.cpp create mode 100644 components/files/conversion.hpp diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 6313b92e95..26fa981cb3 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #define BSATOOL_VERSION 1.1 @@ -179,17 +180,17 @@ int list(std::unique_ptr& bsa, Arguments& info) template int extract(std::unique_ptr& bsa, Arguments& info) { - std::string archivePath = info.extractfile.string(); //TODO(Project579): This will probably break in windows with unicode paths - Misc::StringUtils::replaceAll(archivePath, "/", "\\"); + auto archivePath = info.extractfile.u8string(); + Misc::StringUtils::replaceAll(archivePath, u8"/", u8"\\"); - std::string extractPath = info.extractfile.string(); //TODO(Project579): This will probably break in windows with unicode paths - Misc::StringUtils::replaceAll(extractPath, "\\", "/"); + auto extractPath = info.extractfile.u8string(); + Misc::StringUtils::replaceAll(extractPath, u8"\\", u8"/"); Files::IStreamPtr stream; // Get a stream for the file to extract for (auto it = bsa->getList().rbegin(); it != bsa->getList().rend(); ++it) { - if (Misc::StringUtils::ciEqual(std::string(it->name()), archivePath)) + if (Misc::StringUtils::ciEqual(Misc::StringUtils::stringToU8String(it->name()), archivePath)) { stream = bsa->getFile(&*it); break; @@ -197,8 +198,8 @@ int extract(std::unique_ptr& bsa, Arguments& info) } if (!stream) { - std::cout << "ERROR: file '" << archivePath << "' not found\n"; - std::cout << "In archive: " << info.filename << std::endl; + std::cout << "ERROR: file '" << Misc::StringUtils::u8StringToString(archivePath) << "' not found\n"; + std::cout << "In archive: " << Files::pathToUnicodeString(info.filename) << std::endl; return 3; } @@ -217,14 +218,14 @@ int extract(std::unique_ptr& bsa, Arguments& info) std::filesystem::file_status s = std::filesystem::status(target.parent_path()); if (!std::filesystem::is_directory(s)) { - std::cout << "ERROR: " << target.parent_path() << " is not a directory." << std::endl; + std::cout << "ERROR: " << Files::pathToUnicodeString(target.parent_path()) << " is not a directory." << std::endl; return 3; } std::ofstream out(target, std::ios::binary); // Write the file to disk - std::cout << "Extracting " << info.extractfile << " to " << target << std::endl; //TODO(Project579): This will probably break in windows with unicode paths + std::cout << "Extracting " << Files::pathToUnicodeString(info.extractfile) << " to " << Files::pathToUnicodeString(target) << std::endl; out << stream->rdbuf(); out.close(); @@ -271,7 +272,7 @@ template int add(std::unique_ptr& bsa, Arguments& info) { std::fstream stream(info.addfile, std::ios_base::binary | std::ios_base::out | std::ios_base::in); - bsa->addFile(info.addfile.string(), stream); //TODO(Project579): This will probably break in windows with unicode paths + bsa->addFile(Files::pathToUnicodeString(info.addfile), stream); return 0; } diff --git a/apps/bulletobjecttool/main.cpp b/apps/bulletobjecttool/main.cpp index 6f9e7ac376..5acd57dbb1 100644 --- a/apps/bulletobjecttool/main.cpp +++ b/apps/bulletobjecttool/main.cpp @@ -33,7 +33,6 @@ namespace namespace bpo = boost::program_options; using StringsVector = std::vector; - using PathsVector = std::vector; bpo::options_description makeOptionsDescription() { @@ -146,7 +145,7 @@ namespace const auto fsStrict = variables["fs-strict"].as(); const auto resDir = variables["resources"].as(); - Version::Version v = Version::getOpenmwVersion(resDir); + const auto v = Version::getOpenmwVersion(resDir); Log(Debug::Info) << v.describe(); dataDirs.insert(dataDirs.begin(), resDir / "vfs"); const auto fileCollections = Files::Collections(dataDirs, !fsStrict); diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index f95777d0ef..74e471b948 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "record.hpp" #include "labels.hpp" @@ -288,7 +289,7 @@ void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMDa void printRawTes3(const std::filesystem::path &path) { - std::cout << "TES3 RAW file listing: " << path << '\n'; //TODO(Project579): This will probably break in windows with unicode paths + std::cout << "TES3 RAW file listing: " << path << '\n'; ESM::ESMReader esm; esm.openRaw(path); while(esm.hasMoreRecs()) @@ -312,7 +313,7 @@ void printRawTes3(const std::filesystem::path &path) int loadTes3(const Arguments& info, std::unique_ptr&& stream, ESMData* data) { - std::cout << "Loading TES3 file: " << info.filename << '\n'; //TODO(Project579): This will probably break in windows with unicode paths + std::cout << "Loading TES3 file: " << info.filename << '\n'; ESM::ESMReader esm; ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding)); @@ -421,7 +422,7 @@ int load(const Arguments& info, ESMData* data) printRawTes3(info.filename); break; case ESM::Format::Tes4: - std::cout << "Printing raw TES4 file is not supported: " << info.filename << "\n"; //TODO(Project579): This will probably break in windows with unicode paths + std::cout << "Printing raw TES4 file is not supported: " << Files::pathToUnicodeString(info.filename) << "\n"; break; } return 0; @@ -492,7 +493,7 @@ int clone(const Arguments& info) if (i % 3 != 0) std::cout << '\n'; - std::cout << "\nSaving records to: " << info.outname << "...\n"; //TODO(Project579): This will probably break in windows with unicode paths + std::cout << "\nSaving records to: " << Files::pathToUnicodeString(info.outname) << "...\n"; ESM::ESMWriter esm; ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding)); @@ -565,14 +566,14 @@ int comp(const Arguments& info) ESMData dataOne; if (load(fileOne, &dataOne) != 0) { - std::cout << "Failed to load " << info.filename << ", aborting comparison." << std::endl; //TODO(Project579): This will probably break in windows with unicode paths + std::cout << "Failed to load " << Files::pathToUnicodeString(info.filename) << ", aborting comparison." << std::endl; return 1; } ESMData dataTwo; if (load(fileTwo, &dataTwo) != 0) { - std::cout << "Failed to load " << info.outname << ", aborting comparison." << std::endl; //TODO(Project579): This will probably break in windows with unicode paths + std::cout << "Failed to load " << Files::pathToUnicodeString(info.outname) << ", aborting comparison." << std::endl; return 1; } diff --git a/apps/esmtool/tes4.cpp b/apps/esmtool/tes4.cpp index 02e722631d..815eb6dd34 100644 --- a/apps/esmtool/tes4.cpp +++ b/apps/esmtool/tes4.cpp @@ -289,7 +289,7 @@ namespace EsmTool int loadTes4(const Arguments& info, std::unique_ptr&& stream) { - std::cout << "Loading TES4 file: " << info.filename << '\n'; //TODO(Project579): This will probably break in windows with unicode paths + std::cout << "Loading TES4 file: " << info.filename << '\n'; try { diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index d5f2259f2e..3495d04502 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -230,9 +230,9 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) if (!mDataLocal.isEmpty()) directories.insert(0, mDataLocal); - const auto globalDataDir = QString(mGameSettings.getGlobalDataDir().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths - if (!globalDataDir.isEmpty()) - directories.insert(0, globalDataDir); + const auto& globalDataDir = mGameSettings.getGlobalDataDir(); + if (!globalDataDir.empty()) + directories.insert(0, QString::fromStdWString(globalDataDir.wstring())); // normalize user supplied directories: resolve symlink, convert to native separator, make absolute for (auto& currentDir : directories) @@ -264,7 +264,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) } // deactivate data-local and global data directory: they are always included - if (currentDir == mDataLocal || currentDir == globalDataDir) + if (currentDir == mDataLocal || std::filesystem::path(currentDir.toStdWString()) == globalDataDir) { auto flags = item->flags(); item->setFlags(flags & ~(Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled|Qt::ItemIsEnabled)); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 447dcb5193..7b5fbe5c4c 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -12,6 +12,7 @@ #include #include +#include #include "playpage.hpp" #include "graphicspage.hpp" @@ -155,14 +156,14 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() return FirstRunDialogResultFailure; // Dialog wizard and setup will fail if the config directory does not already exist - QDir userConfigDir = QDir(QString::fromStdString(mCfgMgr.getUserConfigPath().string())); //TODO(Project579): This will probably break in windows with unicode paths, in Qt 6 it's possible to convert directly from std::filesystem::path to QDir and that would solve the issue - if ( ! userConfigDir.exists() ) { - if ( ! userConfigDir.mkpath(".") ) + const auto& userConfigDir = mCfgMgr.getUserConfigPath(); + if ( ! exists(userConfigDir) ) { + if ( ! create_directory(userConfigDir) ) { cfgError(tr("Error opening OpenMW configuration file"), tr("
Could not create directory %0

\ Please make sure you have the right permissions \ - and try again.
").arg(userConfigDir.canonicalPath()) + and try again.
").arg(QString::fromStdWString(canonical(userConfigDir).wstring())) ); return FirstRunDialogResultFailure; } @@ -295,7 +296,7 @@ bool Launcher::MainDialog::setupLauncherSettings() mLauncherSettings.setMultiValueEnabled(true); - QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths + QString userPath = QString::fromStdWString(mCfgMgr.getUserConfigPath().wstring()); QStringList paths; paths.append(QString(Config::LauncherSettings::sLauncherConfigFileName)); @@ -328,9 +329,9 @@ bool Launcher::MainDialog::setupGameSettings() { mGameSettings.clear(); - QString localPath = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths - QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths - QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths + QString localPath = QString::fromStdWString(mCfgMgr.getLocalPath().wstring()); + QString userPath = QString::fromStdWString(mCfgMgr.getUserConfigPath().wstring()); + QString globalPath = QString::fromStdWString(mCfgMgr.getGlobalPath().wstring()); QFile file; @@ -479,21 +480,20 @@ bool Launcher::MainDialog::writeSettings() mSettingsPage->saveSettings(); mAdvancedPage->saveSettings(); - QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths - QDir dir(userPath); + const auto& userPath = mCfgMgr.getUserConfigPath(); - if (!dir.exists()) { - if (!dir.mkpath(userPath)) { + if (!exists(userPath)) { + if (!create_directory(userPath)) { cfgError(tr("Error creating OpenMW configuration directory"), tr("
Could not create %0

\ Please make sure you have the right permissions \ - and try again.
").arg(userPath)); + and try again.
").arg(QString::fromStdWString(userPath.wstring()))); return false; } } // Game settings - QFile file(userPath + QString("openmw.cfg")); + QFile file(QString::fromStdWString((userPath / "openmw.cfg").wstring())); if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { // File cannot be opened or created @@ -515,13 +515,13 @@ bool Launcher::MainDialog::writeSettings() } catch (std::exception& e) { std::string msg = "
Error writing settings.cfg

" + - settingsPath.string() + "

" + e.what(); //TODO(Project579): This will probably break in windows with unicode paths + Files::pathToUnicodeString(settingsPath) + "

" + e.what(); cfgError(tr("Error writing user settings file"), tr(msg.c_str())); return false; } // Launcher settings - file.setFileName(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName)); + file.setFileName(QString::fromStdWString((userPath / Config::LauncherSettings::sLauncherConfigFileName).wstring())); if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 77d45e48ec..1a9670a292 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -102,9 +102,9 @@ void Launcher::SettingsPage::on_importerButton_clicked() mMain->writeSettings(); // Create the file if it doesn't already exist, else the importer will fail - QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); //TODO(Project579): This will probably break in windows with unicode paths - path.append(QLatin1String("openmw.cfg")); - QFile file(path); + auto path = mCfgMgr.getUserConfigPath(); + path /= "openmw.cfg"; + QFile file(QString::fromStdWString(path.wstring())); if (!file.exists()) { if (!file.open(QIODevice::ReadWrite)) { @@ -137,7 +137,7 @@ void Launcher::SettingsPage::on_importerButton_clicked() arguments.append(QString("--ini")); arguments.append(settingsComboBox->currentText()); arguments.append(QString("--cfg")); - arguments.append(path); + arguments.append(QString::fromStdWString(path.wstring())); qDebug() << "arguments " << arguments; diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 912aa2d5ed..ed962c4c5f 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -8,6 +8,7 @@ #include #include #include +#include @@ -944,7 +945,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co { dependencies.push_back(gameFile.name); } - unsortedFiles.emplace_back(reader.getName().filename().string(), dependencies); //TODO(Project579): This will probably break in windows with unicode paths + unsortedFiles.emplace_back(Files::pathToUnicodeString(reader.getName().filename()), dependencies); reader.close(); } diff --git a/apps/navmeshtool/main.cpp b/apps/navmeshtool/main.cpp index 21751dca79..3d80454499 100644 --- a/apps/navmeshtool/main.cpp +++ b/apps/navmeshtool/main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -179,9 +180,9 @@ namespace NavMeshTool const osg::Vec3f agentHalfExtents = Settings::Manager::getVector3("default actor pathfind half extents", "Game"); const DetourNavigator::AgentBounds agentBounds {agentCollisionShape, agentHalfExtents}; const std::uint64_t maxDbFileSize = static_cast(Settings::Manager::getInt64("max navmeshdb file size", "Navigator")); - const auto dbPath = config.getUserDataPath() / "navmesh.db"; + const auto dbPath = Files::pathToUnicodeString(config.getUserDataPath() / "navmesh.db"); - DetourNavigator::NavMeshDb db(dbPath.string(), maxDbFileSize); //TODO(Project579): This will probably break in windows with unicode paths + DetourNavigator::NavMeshDb db(dbPath, maxDbFileSize); ESM::ReadersCache readers; EsmLoader::Query query; diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 68d5a0f898..4919b923c9 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -19,7 +20,7 @@ namespace bpo = boost::program_options; ///See if the file has the named extension bool hasExtension(const std::filesystem::path& filename, const std::string& extensionToFind) { - std::string extension = filename.extension().string(); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break + const auto extension = Files::pathToUnicodeString(filename.extension()); return Misc::StringUtils::ciEqual(extension, extensionToFind); } @@ -42,7 +43,7 @@ void readVFS(std::unique_ptr&& anArchive, const std::filesystem::p myManager.addArchive(std::move(anArchive)); myManager.buildIndex(); - for(const auto& name : myManager.getRecursiveDirectoryIterator("")) //TODO(Project579): This will probably break in windows with unicode paths + for(const auto& name : myManager.getRecursiveDirectoryIterator("")) { try{ if(isNIF(name)) @@ -142,7 +143,7 @@ int main(int argc, char **argv) } else { - std::cerr << "ERROR: \"" << path << "\" is not a nif file, bsa file, or directory!" << std::endl; //TODO(Project579): This will probably break in windows with unicode paths + std::cerr << "ERROR: \"" << Files::pathToUnicodeString(path) << "\" is not a nif file, bsa file, or directory!" << std::endl; } } catch (std::exception& e) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 8dee97bd46..669fa83a4c 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -393,7 +393,7 @@ int CS::Editor::run() } discoveredFiles.push_back(mFileToLoad); - QString extension = QString::fromStdString(mFileToLoad.extension().string()).toLower(); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break + QString extension = QString::fromStdWString(mFileToLoad.extension().wstring()).toLower(); if (extension == ".esm") { mFileToLoad.replace_extension(".omwgame"); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 26f45744c6..c9dba37193 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -89,7 +89,7 @@ namespace CS void cancelFileDialog(); void loadDocument(); - void openFiles (const std::filesystem::path &path, const std::vector &discoveredFiles = std::vector()); + void openFiles (const std::filesystem::path &path, const std::vector &discoveredFiles = {}); void createNewFile (const std::filesystem::path& path); void createNewGame (const std::filesystem::path& file); diff --git a/apps/opencs/model/doc/blacklist.cpp b/apps/opencs/model/doc/blacklist.cpp index 49db56f7f4..cd96618288 100644 --- a/apps/opencs/model/doc/blacklist.cpp +++ b/apps/opencs/model/doc/blacklist.cpp @@ -25,6 +25,6 @@ void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type, list.resize (size+ids.size()); - std::transform (ids.begin(), ids.end(), list.begin()+size, Misc::StringUtils::lowerCase); + std::transform (ids.begin(), ids.end(), list.begin()+size, [](const std::string& s) { return Misc::StringUtils::lowerCase(s); } ); std::sort (list.begin(), list.end()); } diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 9a93430dc6..779c9431d1 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../world/defaultgmsts.hpp" @@ -13,7 +14,7 @@ #endif #include -#include +#include void CSMDoc::Document::addGmsts() { @@ -294,11 +295,11 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, if (mNew || !std::filesystem::exists (mProjectPath)) { - std::filesystem::path filtersPath (configuration.getUserDataPath() / "defaultfilters"); + auto filtersPath = configuration.getUserDataPath() / "defaultfilters"; std::ofstream destination(mProjectPath, std::ios::out | std::ios::binary); if (!destination.is_open()) - throw std::runtime_error("Can not create project file: " + mProjectPath.string()); //TODO(Project579): This will probably break in windows with unicode paths + throw std::runtime_error("Can not create project file: " + Files::pathToUnicodeString(mProjectPath)); destination.exceptions(std::ios::failbit | std::ios::badbit); if (!std::filesystem::exists (filtersPath)) @@ -306,7 +307,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, std::ifstream source(filtersPath, std::ios::in | std::ios::binary); if (!source.is_open()) - throw std::runtime_error("Can not read filters file: " + filtersPath.string()); //TODO(Project579): This will probably break in windows with unicode paths + throw std::runtime_error("Can not read filters file: " + Files::pathToUnicodeString(filtersPath)); source.exceptions(std::ios::failbit | std::ios::badbit); destination << source.rdbuf(); @@ -480,11 +481,11 @@ bool CSMDoc::Document::isBlacklisted (const CSMWorld::UniversalId& id) void CSMDoc::Document::startRunning (const std::string& profile, const std::string& startupInstruction) { - std::vector contentFiles; + std::vector contentFiles; - for (std::vector::const_iterator iter (mContentFiles.begin()); - iter!=mContentFiles.end(); ++iter) - contentFiles.push_back (iter->filename().string()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + for (const auto & mContentFile : mContentFiles) { + contentFiles.emplace_back(mContentFile.filename()); + } mRunner.configure (getData().getDebugProfiles().getRecord (profile).get(), contentFiles, startupInstruction); diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index 70d114c47e..a851707811 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -1,5 +1,7 @@ #include "loader.hpp" +#include + #include #include "../tools/reportmodel.hpp" @@ -93,7 +95,7 @@ void CSMDoc::Loader::load() iter->second.mRecordsLeft = true; iter->second.mRecordsLoaded = 0; - emit nextStage (document, path.filename().string(), steps); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + emit nextStage (document, Files::pathToUnicodeString(path.filename()), steps); } else if (iter->second.mFile==size) // start loading the last (project) file { diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index c1db116a52..2b16ea3eff 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -83,18 +83,17 @@ void CSMDoc::Runner::start (bool delayed) arguments << ("--script-run="+mStartup->fileName()); arguments << - QString::fromUtf8 (("--data=\""+mProjectPath.parent_path().string()+"\"").c_str()); //TODO(Project579): This will probably break in windows with unicode paths + QString::fromStdWString (L"--data=\""+mProjectPath.parent_path().wstring()+L"\""); arguments << "--replace=content"; - for (std::vector::const_iterator iter (mContentFiles.begin()); - iter!=mContentFiles.end(); ++iter) + for (const auto & mContentFile : mContentFiles) { - arguments << QString::fromUtf8 (("--content="+*iter).c_str()); + arguments << QString::fromStdWString (L"--content="+mContentFile.wstring()); } arguments - << QString::fromUtf8 (("--content="+mProjectPath.filename().string()).c_str()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + << QString::fromStdWString (L"--content="+mProjectPath.filename().wstring()); mProcess.start (path, arguments); } @@ -123,7 +122,7 @@ bool CSMDoc::Runner::isRunning() const } void CSMDoc::Runner::configure (const ESM::DebugProfile& profile, - const std::vector& contentFiles, const std::string& startupInstruction) + const std::vector &contentFiles, const std::string& startupInstruction) { mProfile = profile; mContentFiles = contentFiles; diff --git a/apps/opencs/model/doc/runner.hpp b/apps/opencs/model/doc/runner.hpp index fcc12d2f0e..c3ef4477c3 100644 --- a/apps/opencs/model/doc/runner.hpp +++ b/apps/opencs/model/doc/runner.hpp @@ -25,7 +25,7 @@ namespace CSMDoc QProcess mProcess; bool mRunning; ESM::DebugProfile mProfile; - std::vector mContentFiles; + std::vector mContentFiles; std::string mStartupInstruction; QTemporaryFile *mStartup; QTextDocument mLog; @@ -48,7 +48,7 @@ namespace CSMDoc bool isRunning() const; void configure (const ESM::DebugProfile& profile, - const std::vector& contentFiles, + const std::vector &contentFiles, const std::string& startupInstruction); QTextDocument *getLog(); diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 20f3ca4ba6..841c930cf0 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../world/infocollection.hpp" #include "../world/cellcoordinates.hpp" @@ -72,8 +73,8 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages) for (std::vector::const_iterator iter (dependencies.begin()); iter!=end; ++iter) { - std::string name = iter->filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break - uint64_t size = std::filesystem::file_size (*iter); + auto name = Files::pathToUnicodeString(iter->filename()); + auto size = std::filesystem::file_size (*iter); mState.getWriter().addMaster (name, size); } diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index 96b8ac6297..00d949f450 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -95,7 +95,9 @@ void CSMWorld::CommandDispatcher::setEditLock (bool locked) void CSMWorld::CommandDispatcher::setSelection (const std::vector& selection) { mSelection = selection; - std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::lowerCaseInPlace); + for (auto& sel : mSelection) { + Misc::StringUtils::lowerCaseInPlace(sel); + } std::sort (mSelection.begin(), mSelection.end()); } diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index de1c34a5cc..910572af91 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -169,7 +169,9 @@ void CSMWorld::RegionMap::updateRegions (const std::vector& regions { std::vector regions2 (regions); - std::for_each (regions2.begin(), regions2.end(), Misc::StringUtils::lowerCaseInPlace); + for (auto& region2 : regions2) { + Misc::StringUtils::lowerCaseInPlace(region2); + } std::sort (regions2.begin(), regions2.end()); for (std::map::const_iterator iter (mMap.begin()); diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 0bf7de9d95..1088a58a00 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -94,7 +94,9 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const { mIds = mData.getIds(); - std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCaseInPlace); + for (auto& id : mIds) { + Misc::StringUtils::lowerCaseInPlace(id); + } std::sort (mIds.begin(), mIds.end()); mIdsUpdated = true; diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 0e6ae73fe6..6eb479d694 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -68,12 +68,12 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) } else { - std::filesystem::path path (name.toUtf8().data()); //TODO(Project579): Replace with char8_t in C++20 + std::filesystem::path path (name.toStdWString()); - std::string extension = Misc::StringUtils::lowerCase(path.extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break + const auto extension = Misc::StringUtils::lowerCase(path.extension().u8string()); - bool isLegacyPath = (extension == ".esm" || - extension == ".esp"); + bool isLegacyPath = (extension == u8".esm" || + extension == u8".esp"); bool isFilePathChanged = (path.parent_path() != mLocalData); @@ -85,7 +85,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) if (!isFilePathChanged && !isLegacyPath) { // path already points to the local data directory - message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str()); //TODO(Project579): This is probably broken on windows with unicode paths + message = QString::fromStdWString (L"Will be saved as: " + path.wstring()); mResultPath = path; } //in all other cases, ensure the path points to data-local and do an existing file check @@ -95,7 +95,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) if (isFilePathChanged) path = mLocalData / path.filename(); - message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str()); //TODO(Project579): This is probably broken on windows with unicode paths + message = QString::fromStdWString (L"Will be saved as: " + path.wstring()); mResultPath = path; if (std::filesystem::exists (path)) diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index 188827db2f..ffd1d66756 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -19,7 +19,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event) CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document) : mDocument (document), mTotalRecordsLabel (0), mRecordsLabel (0), mAborted (false), mMessages (nullptr), mRecords(0) { - setWindowTitle (QString::fromUtf8((std::string("Opening ") + document->getSavePath().filename().string()).c_str())); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + setWindowTitle (QString::fromStdWString(L"Opening " + document->getSavePath().filename().wstring())); setMinimumWidth (400); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index eaeb6d3957..e47ce65654 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -30,6 +30,7 @@ #include #include +#include #include "viewmanager.hpp" #include "operations.hpp" @@ -387,7 +388,7 @@ void CSVDoc::View::updateTitle() { std::ostringstream stream; - stream << mDocument->getSavePath().filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + stream << Files::pathToUnicodeString(mDocument->getSavePath().filename()); if (mDocument->getState() & CSMDoc::State_Modified) stream << " *"; diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 92144ca668..71e8987bb1 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -261,7 +261,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view) QMessageBox messageBox(view); CSMDoc::Document *document = view->getDocument(); - messageBox.setWindowTitle (QString::fromUtf8(document->getSavePath().filename().string().c_str())); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + messageBox.setWindowTitle (QString::fromStdWString(document->getSavePath().filename().wstring())); messageBox.setText ("The document has been modified."); messageBox.setInformativeText ("Do you want to save your changes?"); messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index 0efce2aec3..6c4d076849 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -102,7 +102,7 @@ void CSVTools::Merge::configure (CSMDoc::Document *document) for (std::vector::const_iterator iter (files.begin()); iter!=files.end(); ++iter) - mFiles->addItem (QString::fromUtf8 (iter->filename().string().c_str())); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + mFiles->addItem (QString::fromStdWString(iter->filename().wstring())); } void CSVTools::Merge::setLocalData (const std::filesystem::path& localData) @@ -125,7 +125,7 @@ void CSVTools::Merge::accept() { if ((mDocument->getState() & CSMDoc::State_Merging)==0) { - std::vector< std::filesystem::path > files (1, mAdjuster->getPath()); + std::vector< std::filesystem::path > files { mAdjuster->getPath() }; std::unique_ptr target ( mDocumentManager.makeDocument (files, files[0], true)); diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 22cd339b36..163fb31ccd 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -711,7 +711,7 @@ void OMW::Engine::setWindowIcon() const auto windowIcon = mResDir / "openmw.png"; windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary); if (windowIconStream.fail()) - Log(Debug::Error) << "Error: Failed to open " << windowIcon; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Error) << "Error: Failed to open " << windowIcon; osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); if (!reader) { @@ -720,7 +720,7 @@ void OMW::Engine::setWindowIcon() } osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream); if (!result.success()) - Log(Debug::Error) << "Error: Failed to read " << windowIcon << ": " << result.message() << " code " << result.status(); //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Error) << "Error: Failed to read " << windowIcon << ": " << result.message() << " code " << result.status(); else { osg::ref_ptr image = result.getImage(); @@ -790,11 +790,11 @@ void OMW::Engine::prepareEngine() const auto input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml"); if(std::filesystem::exists(input2)) { keybinderUserExists = std::filesystem::copy_file(input2, keybinderUser); - Log(Debug::Info) << "Loading keybindings file: " << keybinderUser; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Loading keybindings file: " << keybinderUser; } } else - Log(Debug::Info) << "Loading keybindings file: " << keybinderUser; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Loading keybindings file: " << keybinderUser; const auto userdefault = mCfgMgr.getUserConfigPath() / "gamecontrollerdb.txt"; const auto localdefault = mCfgMgr.getLocalPath() / "gamecontrollerdb.txt"; @@ -1032,13 +1032,17 @@ void OMW::Engine::go() prepareEngine(); std::ofstream stats; - if (const auto path = std::getenv("OPENMW_OSG_STATS_FILE")) //TODO(Project579): This will probably break in windows with unicode paths +#ifdef _WIN32 + if (const auto path = std::filesystem::path{_wgetenv(L"OPENMW_OSG_STATS_FILE")}; !path.empty()) +#else + if (const auto path = std::filesystem::path{std::getenv("OPENMW_OSG_STATS_FILE")}; !path.empty()) +#endif { - stats.open(path, std::ios_base::out); //TODO(Project579): This will probably break in windows with unicode paths + stats.open(path, std::ios_base::out); if (stats.is_open()) - Log(Debug::Info) << "Stats will be written to: " << path; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Stats will be written to: " << path; else - Log(Debug::Warning) << "Failed to open file for stats: " << path; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Warning) << "Failed to open file for stats: " << path; } // Setup profiler diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 69082bd6bb..ebf22b5c83 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -21,6 +21,7 @@ #include #include +#include #include @@ -200,7 +201,7 @@ namespace MWGui if (mCurrentCharacter == &*it || (!mCurrentCharacter && !mSaving && directory==Misc::StringUtils::lowerCase ( - it->begin()->mPath.parent_path().filename().string()))) //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + Files::pathToUnicodeString(it->begin()->mPath.parent_path().filename())))) { mCurrentCharacter = &*it; selectedIndex = mCharacterSelection->getItemCount()-1; diff --git a/apps/openmw/mwinput/bindingsmanager.cpp b/apps/openmw/mwinput/bindingsmanager.cpp index 376a8a145f..c799056f45 100644 --- a/apps/openmw/mwinput/bindingsmanager.cpp +++ b/apps/openmw/mwinput/bindingsmanager.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" @@ -44,7 +45,7 @@ namespace MWInput { public: InputControlSystem(const std::filesystem::path &bindingsFile) - : ICS::InputControlSystem(bindingsFile.string(), true, nullptr, nullptr, A_Last) //TODO(Project579): This is probably broken on windows with unicode paths + : ICS::InputControlSystem(Files::pathToUnicodeString(bindingsFile), true, nullptr, nullptr, A_Last) { } }; @@ -192,7 +193,7 @@ namespace MWInput BindingsManager::~BindingsManager() { - mInputBinder->save(mUserFile.string()); //TODO(Project579): This will probably break in windows with unicode paths + mInputBinder->save(Files::pathToUnicodeString(mUserFile)); } void BindingsManager::update(float dt) diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index c95a924280..96d14a3720 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -7,6 +7,8 @@ #include #include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" @@ -43,12 +45,12 @@ namespace MWInput { if (!controllerBindingsFile.empty()) { - SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths + SDL_GameControllerAddMappingsFromFile(Files::pathToUnicodeString(controllerBindingsFile).c_str()); } if (!userControllerBindingsFile.empty()) { - SDL_GameControllerAddMappingsFromFile(userControllerBindingsFile.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths + SDL_GameControllerAddMappingsFromFile(Files::pathToUnicodeString(userControllerBindingsFile).c_str()); } // Open all presently connected sticks diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index be84d8fdff..555baa7efe 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -217,12 +218,12 @@ namespace MWRender { for (const auto& name : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir)) { - std::filesystem::path path = name; - std::string fileExt = Misc::StringUtils::lowerCase(path.extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break + std::filesystem::path path = Files::pathFromUnicodeString(name); + std::string fileExt = Misc::StringUtils::lowerCase(Files::pathToUnicodeString(path.extension())); if (!path.parent_path().has_parent_path() && fileExt == fx::Technique::sExt) { - const auto absolutePath = mVFS->getAbsoluteFileName(name); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break - mTechniqueFileMap[absolutePath.stem().string()] = absolutePath; //TODO(Project579): This will probably break in windows with unicode paths + const auto absolutePath = mVFS->getAbsoluteFileName(path); + mTechniqueFileMap[Files::pathToUnicodeString(absolutePath.stem())] = absolutePath; } } } @@ -387,7 +388,7 @@ namespace MWRender std::this_thread::sleep_for(std::chrono::milliseconds(5)); if (technique->compile()) - Log(Debug::Info) << "Reloaded technique : " << mTechniqueFileMap[technique->getName()].string(); //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Reloaded technique : " << mTechniqueFileMap[technique->getName()]; mReload = technique->isValid(); } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 8ad7997c2e..d57fbe731e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -243,16 +243,16 @@ osg::ref_ptr readPngImage (const std::filesystem::path& file) std::ifstream inStream; inStream.open(file, std::ios_base::in | std::ios_base::binary); if (inStream.fail()) - Log(Debug::Error) << "Error: Failed to open " << file; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Error) << "Error: Failed to open " << file; osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); if (!reader) { - Log(Debug::Error) << "Error: Failed to read " << file << ", no png readerwriter found"; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Error) << "Error: Failed to read " << file << ", no png readerwriter found"; return osg::ref_ptr(); } osgDB::ReaderWriter::ReadResult result = reader->readImage(inStream); if (!result.success()) - Log(Debug::Error) << "Error: Failed to read " << file << ": " << result.message() << " code " << result.status(); //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Error) << "Error: Failed to read " << file << ": " << result.message() << " code " << result.status(); return result.getImage(); } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index eb82eb9d2e..24c9542d64 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -1528,7 +1529,7 @@ namespace MWScript else { const auto filename = MWBase::Environment::get().getWorld()->exportSceneGraph(ptr); - runtime.getContext().report("Wrote '" + filename.string() + "'"); //TODO(Project579): This will probably break in windows with unicode paths + runtime.getContext().report("Wrote '" + Files::pathToUnicodeString(filename) + "'"); } } }; diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 7a22cda8b1..35593efcba 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -35,7 +35,7 @@ namespace MWScript mScriptBlacklist.resize (scriptBlacklist.size()); std::transform (scriptBlacklist.begin(), scriptBlacklist.end(), - mScriptBlacklist.begin(), Misc::StringUtils::lowerCase); + mScriptBlacklist.begin(), [](const std::string& s) { return Misc::StringUtils::lowerCase(s); }); std::sort (mScriptBlacklist.begin(), mScriptBlacklist.end()); } diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 3142b495a4..814535489e 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -13,6 +13,7 @@ #include #include +#include #include @@ -305,7 +306,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot throw std::runtime_error("Write operation failed (file stream)"); Settings::Manager::setString ("character", "Saves", - slot->mPath.parent_path().filename().string()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + Files::pathToUnicodeString(slot->mPath.parent_path().filename())); const auto finish = std::chrono::steady_clock::now(); @@ -388,7 +389,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::fil { cleanup(); - Log(Debug::Info) << "Reading save file " << filepath.filename(); //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Reading save file " << filepath.filename(); ESM::ESMReader reader; reader.open (filepath); @@ -521,7 +522,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::fil if (character) Settings::Manager::setString ("character", "Saves", - character->getPath().filename().string()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + Files::pathToUnicodeString(character->getPath().filename())); MWBase::Environment::get().getWindowManager()->setNewGame(false); MWBase::Environment::get().getWorld()->saveLoaded(); diff --git a/apps/openmw/mwworld/esmloader.cpp b/apps/openmw/mwworld/esmloader.cpp index 861401d60e..66dd5b856e 100644 --- a/apps/openmw/mwworld/esmloader.cpp +++ b/apps/openmw/mwworld/esmloader.cpp @@ -3,6 +3,7 @@ #include #include +#include namespace MWWorld { @@ -28,7 +29,7 @@ void EsmLoader::load(const std::filesystem::path& filepath, int& index, Loading: assert(reader->getGameFiles().size() == reader->getParentFileIndices().size()); for (std::size_t i = 0, n = reader->getParentFileIndices().size(); i < n; ++i) if (i == static_cast(reader->getIndex())) - throw std::runtime_error("File " + reader->getName().string() + " asks for parent file " //TODO(Project579): This will probably break in windows with unicode paths + throw std::runtime_error("File " + Files::pathToUnicodeString(reader->getName()) + " asks for parent file " + reader->getGameFiles()[i].name + ", but it is not available or has been loaded in the wrong order. " "Please run the launcher to fix this issue."); @@ -36,8 +37,8 @@ void EsmLoader::load(const std::filesystem::path& filepath, int& index, Loading: mESMVersions[index] = reader->getVer(); mStore.load(*reader, listener, mDialogue); - if (!mMasterFileFormat.has_value() && (Misc::StringUtils::ciEndsWith(reader->getName().string(), ".esm") //TODO(Project579): This will probably break in windows with unicode paths - || Misc::StringUtils::ciEndsWith(reader->getName().string(), ".omwgame"))) //TODO(Project579): This will probably break in windows with unicode paths + if (!mMasterFileFormat.has_value() && (Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".esm") + || Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".omwgame"))) mMasterFileFormat = reader->getFormat(); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b0828fd69a..ed19b352d2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -44,6 +44,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -104,19 +105,19 @@ namespace MWWorld void load(const std::filesystem::path& filepath, int& index, Loading::Listener* listener) override { - const auto it = mLoaders.find(Misc::StringUtils::lowerCase(filepath.extension().string())); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break + const auto it = mLoaders.find(Misc::StringUtils::lowerCase( Files::pathToUnicodeString(filepath.extension()))); if (it != mLoaders.end()) { - const std::string filename = filepath.filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + const auto filename = filepath.filename(); Log(Debug::Info) << "Loading content file " << filename; if (listener != nullptr) - listener->setLabel(MyGUI::TextIterator::toTagsString(filename)); + listener->setLabel(MyGUI::TextIterator::toTagsString(Files::pathToUnicodeString(filename))); it->second->load(filepath, index, listener); } else { std::string msg("Cannot load file: "); - msg += filepath.string(); //TODO(Project579): This will probably break in windows with unicode paths + msg += Files::pathToUnicodeString(filepath); throw std::runtime_error(msg.c_str()); } } @@ -2963,8 +2964,8 @@ namespace MWWorld int idx = 0; for (const std::string &file : content) { - std::filesystem::path filename(file); - const Files::MultiDirCollection& col = fileCollections.getCollection(filename.extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break + const auto filename = Files::pathFromUnicodeString( file); + const Files::MultiDirCollection& col = fileCollections.getCollection(Files::pathToUnicodeString(filename.extension())); if (col.doesExist(file)) { gameContentLoader.load(col.getPath(file), idx, listener); diff --git a/apps/openmw_test_suite/files/hash.cpp b/apps/openmw_test_suite/files/hash.cpp index dcace6b34e..ab18d20be7 100644 --- a/apps/openmw_test_suite/files/hash.cpp +++ b/apps/openmw_test_suite/files/hash.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -50,11 +51,11 @@ namespace std::replace(fileName.begin(), fileName.end(), '/', '_'); std::string content; std::fill_n(std::back_inserter(content), GetParam().mSize, 'a'); - fileName = outputFilePath(fileName).string(); //TODO(Project579): This will probably break in windows with unicode paths - std::fstream(fileName, std::ios_base::out | std::ios_base::binary) + const auto file = outputFilePath(fileName); + std::fstream(file, std::ios_base::out | std::ios_base::binary) .write(content.data(), static_cast(content.size())); - const auto stream = Files::openConstrainedFileStream(fileName, 0, content.size()); //TODO(Project579): This will probably break in windows with unicode paths - EXPECT_EQ(getHash(fileName, *stream), GetParam().mHash); + const auto stream = Files::openConstrainedFileStream(file, 0, content.size()); + EXPECT_EQ(getHash(file, *stream), GetParam().mHash); } INSTANTIATE_TEST_SUITE_P(Params, FilesGetHash, Values( diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index ba0abd293d..d3c7176540 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "apps/openmw/mwworld/esmstore.hpp" #include "apps/openmw/mwmechanics/spelllist.hpp" @@ -124,7 +125,7 @@ TEST_F(ContentFileTest, dialogue_merging_test) stream << std::endl; } - std::cout << "dialogue_merging_test successful, results printed to " << file << std::endl; //TODO(Project579): This will probably break in windows with unicode paths + std::cout << "dialogue_merging_test successful, results printed to " << Files::pathToUnicodeString(file) << std::endl; } // Note: here we don't test records that don't use string names (e.g. Land, Pathgrid, Cell) @@ -194,7 +195,7 @@ TEST_F(ContentFileTest, content_diagnostics_test) RUN_TEST_FOR_TYPES(printRecords, mEsmStore, stream); - std::cout << "diagnostics_test successful, results printed to " << file << std::endl; //TODO(Project579): This will probably break in windows with unicode paths + std::cout << "diagnostics_test successful, results printed to " << Files::pathToUnicodeString(file) << std::endl; } // TODO: diff --git a/apps/openmw_test_suite/openmw/options.cpp b/apps/openmw_test_suite/openmw/options.cpp index 33c38da5df..06b848dd16 100644 --- a/apps/openmw_test_suite/openmw/options.cpp +++ b/apps/openmw_test_suite/openmw/options.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -38,7 +39,7 @@ namespace return result; } - MATCHER_P(IsPath, v, "") { return arg.string() == v; } + MATCHER_P(IsPath, v, "") { return Files::pathToUnicodeString(arg) == v; } template void parseArgs(const T& arguments, bpo::variables_map& variables, bpo::options_description& description) @@ -52,7 +53,7 @@ namespace const std::array arguments {"openmw", "--load-savegame=save.omwsave"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "save.omwsave"); } TEST(OpenMWOptionsFromArguments, should_support_single_word_load_savegame_path) @@ -61,7 +62,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", "save.omwsave"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "save.omwsave"); } TEST(OpenMWOptionsFromArguments, should_support_multi_component_load_savegame_path) @@ -70,7 +71,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", "/home/user/openmw/save.omwsave"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "/home/user/openmw/save.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "/home/user/openmw/save.omwsave"); } TEST(OpenMWOptionsFromArguments, should_support_windows_multi_component_load_savegame_path) @@ -79,7 +80,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", R"(C:\OpenMW\save.omwsave)"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(C:\OpenMW\save.omwsave)"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), R"(C:\OpenMW\save.omwsave)"); } TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_spaces) @@ -88,7 +89,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", "my save.omwsave"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "my save.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "my save.omwsave"); } TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_octothorpe) @@ -97,7 +98,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", "my#save.omwsave"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "my#save.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "my#save.omwsave"); } TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_at_sign) @@ -106,7 +107,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", "my@save.omwsave"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "my@save.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "my@save.omwsave"); } TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_quote) @@ -115,7 +116,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", R"(my"save.omwsave)"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(my"save.omwsave)"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), R"(my"save.omwsave)"); } TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path) @@ -124,7 +125,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", R"("save".omwsave)"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(save)"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), R"(save)"); } TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_quote_by_ampersand) @@ -133,7 +134,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", R"("save&".omwsave")"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(save".omwsave)"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), R"(save".omwsave)"); } TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_ampersand) @@ -142,7 +143,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", R"("save.omwsave&&")"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save.omwsave&"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "save.omwsave&"); } TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_ampersand) @@ -151,7 +152,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", "save&.omwsave"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save&.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "save&.omwsave"); } TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_multiple_quotes) @@ -160,7 +161,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", R"(my"save".omwsave)"}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(my"save".omwsave)"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), R"(my"save".omwsave)"); } TEST(OpenMWOptionsFromArguments, should_compose_data) @@ -199,7 +200,7 @@ namespace const std::array arguments {"openmw", "--load-savegame", pathArgument.c_str()}; bpo::variables_map variables; parseArgs(arguments, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), path); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), path); } INSTANTIATE_TEST_SUITE_P( @@ -214,7 +215,7 @@ namespace std::istringstream stream("load-savegame=save.omwsave"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "save.omwsave"); } TEST(OpenMWOptionsFromConfig, should_strip_quotes_from_load_savegame_path) @@ -223,7 +224,7 @@ namespace std::istringstream stream(R"(load-savegame="save.omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "save.omwsave"); } TEST(OpenMWOptionsFromConfig, should_strip_outer_quotes_from_load_savegame_path) @@ -232,7 +233,7 @@ namespace std::istringstream stream(R"(load-savegame=""save".omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), ""); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), ""); } TEST(OpenMWOptionsFromConfig, should_strip_quotes_from_load_savegame_path_with_space) @@ -241,7 +242,7 @@ namespace std::istringstream stream(R"(load-savegame="my save.omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "my save.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "my save.omwsave"); } TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_octothorpe) @@ -250,7 +251,7 @@ namespace std::istringstream stream("load-savegame=save#.omwsave"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save#.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "save#.omwsave"); } TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_at_sign) @@ -259,7 +260,7 @@ namespace std::istringstream stream("load-savegame=save@.omwsave"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save@.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "save@.omwsave"); } TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_quote) @@ -268,7 +269,7 @@ namespace std::istringstream stream(R"(load-savegame=save".omwsave)"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(save".omwsave)"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), R"(save".omwsave)"); } TEST(OpenMWOptionsFromConfig, should_support_confusing_savegame_path_with_lots_going_on) @@ -277,7 +278,7 @@ namespace std::istringstream stream(R"(load-savegame="one &"two"three".omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(one "two)"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), R"(one "two)"); } TEST(OpenMWOptionsFromConfig, should_support_confusing_savegame_path_with_even_more_going_on) @@ -286,7 +287,7 @@ namespace std::istringstream stream(R"(load-savegame="one &"two"three ".omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(one "two)"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), R"(one "two)"); } TEST(OpenMWOptionsFromConfig, should_ignore_commented_option) @@ -295,7 +296,7 @@ namespace std::istringstream stream("#load-savegame=save.omwsave"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), ""); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), ""); } TEST(OpenMWOptionsFromConfig, should_ignore_whitespace_prefixed_commented_option) @@ -304,7 +305,7 @@ namespace std::istringstream stream(" \t#load-savegame=save.omwsave"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), ""); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), ""); } TEST(OpenMWOptionsFromConfig, should_support_whitespace_around_option) @@ -313,7 +314,7 @@ namespace std::istringstream stream(" load-savegame = save.omwsave "); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "save.omwsave"); } TEST(OpenMWOptionsFromConfig, should_throw_on_multiple_load_savegame) @@ -330,7 +331,7 @@ namespace std::istringstream stream("load-savegame=/home/user/openmw/save.omwsave"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "/home/user/openmw/save.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "/home/user/openmw/save.omwsave"); } TEST(OpenMWOptionsFromConfig, should_support_windows_multi_component_load_savegame_path) @@ -339,7 +340,7 @@ namespace std::istringstream stream(R"(load-savegame=C:\OpenMW\save.omwsave)"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(C:\OpenMW\save.omwsave)"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), R"(C:\OpenMW\save.omwsave)"); } TEST(OpenMWOptionsFromConfig, should_compose_data) @@ -357,7 +358,7 @@ namespace std::istringstream stream(R"(load-savegame="save&".omwsave")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), R"(save".omwsave)"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), R"(save".omwsave)"); } TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_escaped_ampersand) @@ -366,7 +367,7 @@ namespace std::istringstream stream(R"(load-savegame="save.omwsave&&")"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save.omwsave&"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "save.omwsave&"); } TEST(OpenMWOptionsFromConfig, should_support_load_savegame_path_with_ampersand) @@ -375,7 +376,7 @@ namespace std::istringstream stream("load-savegame=save&.omwsave"); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), "save&.omwsave"); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), "save&.omwsave"); } struct OpenMWOptionsFromConfigStrings : TestWithParam {}; @@ -387,7 +388,7 @@ namespace std::istringstream stream("load-savegame=\"" + path + "\""); bpo::variables_map variables; Files::parseConfig(stream, variables, description); - EXPECT_EQ(variables["load-savegame"].as().string(), path); + EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as()), path); } INSTANTIATE_TEST_SUITE_P( diff --git a/apps/openmw_test_suite/shader/shadermanager.cpp b/apps/openmw_test_suite/shader/shadermanager.cpp index 9e4808b073..425f6d391f 100644 --- a/apps/openmw_test_suite/shader/shadermanager.cpp +++ b/apps/openmw_test_suite/shader/shadermanager.cpp @@ -1,4 +1,5 @@ #include +#include #include @@ -48,7 +49,7 @@ namespace const std::string content; withShaderFile(content, [this] (const std::filesystem::path& templateName) { - EXPECT_TRUE(mManager.getShader(templateName.string(), {}, osg::Shader::VERTEX)); //TODO(Project579): This will probably break in windows with unicode paths + EXPECT_TRUE(mManager.getShader(Files::pathToUnicodeString(templateName), {}, osg::Shader::VERTEX)); }); } @@ -59,7 +60,7 @@ namespace "void main() {}\n"; withShaderFile(content, [&] (const std::filesystem::path& templateName) { - const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths + const auto shader = mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX); ASSERT_TRUE(shader); EXPECT_EQ(shader->getShaderSource(), content); }); @@ -72,17 +73,17 @@ namespace withShaderFile("_0", content0, [&] (const std::filesystem::path& templateName0) { const std::string content1 = - "#include \"" + templateName0.string() + "\"\n" //TODO(Project579): This will probably break in windows with unicode paths + "#include \"" + Files::pathToUnicodeString(templateName0) + "\"\n" "void bar() { foo() }\n"; withShaderFile("_1", content1, [&] (const std::filesystem::path& templateName1) { const std::string content2 = "#version 120\n" - "#include \"" + templateName1.string() + "\"\n" //TODO(Project579): This will probably break in windows with unicode paths + "#include \"" + Files::pathToUnicodeString(templateName1) + "\"\n" "void main() { bar() }\n"; withShaderFile(content2, [&] (const std::filesystem::path& templateName2) { - const auto shader = mManager.getShader(templateName2.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths + const auto shader = mManager.getShader(Files::pathToUnicodeString(templateName2), mDefines, osg::Shader::VERTEX); ASSERT_TRUE(shader); const std::string expected = "#version 120\n" @@ -113,7 +114,7 @@ namespace withShaderFile(content, [&] (const std::filesystem::path& templateName) { mDefines["flag"] = "1"; - const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths + const auto shader = mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX); ASSERT_TRUE(shader); const std::string expected = "#version 120\n" @@ -135,7 +136,7 @@ namespace withShaderFile(content, [&] (const std::filesystem::path& templateName) { mDefines["list"] = "1,2,3"; - const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths + const auto shader = mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX); ASSERT_TRUE(shader); const std::string expected = "#version 120\n" @@ -176,7 +177,7 @@ namespace withShaderFile(content, [&] (const std::filesystem::path& templateName) { mDefines["list"] = "1,2,3"; - const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths + const auto shader = mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX); ASSERT_TRUE(shader); const std::string expected = "#version 120\n" @@ -223,7 +224,7 @@ namespace ; withShaderFile(content, [&] (const std::filesystem::path& templateName) { - EXPECT_FALSE(mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX)); //TODO(Project579): This will probably break in windows with unicode paths + EXPECT_FALSE(mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX)); }); } @@ -236,7 +237,7 @@ namespace ; withShaderFile(content, [&] (const std::filesystem::path& templateName) { - EXPECT_FALSE(mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX)); //TODO(Project579): This will probably break in windows with unicode paths + EXPECT_FALSE(mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX)); }); } } diff --git a/apps/openmw_test_suite/testing_util.hpp b/apps/openmw_test_suite/testing_util.hpp index 7b6b008501..ce364d6db6 100644 --- a/apps/openmw_test_suite/testing_util.hpp +++ b/apps/openmw_test_suite/testing_util.hpp @@ -6,6 +6,7 @@ #include #include +#include namespace TestingOpenMW { @@ -14,7 +15,7 @@ namespace TestingOpenMW { std::filesystem::path dir("tests_output"); std::filesystem::create_directory(dir); - return dir / name; + return dir / Misc::StringUtils::stringToU8String(name); } inline std::filesystem::path temporaryFilePath(const std::string name) diff --git a/apps/wizard/installationtargetpage.cpp b/apps/wizard/installationtargetpage.cpp index 0a41d57f14..521395f632 100644 --- a/apps/wizard/installationtargetpage.cpp +++ b/apps/wizard/installationtargetpage.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "mainwizard.hpp" Wizard::InstallationTargetPage::InstallationTargetPage(QWidget *parent, const Files::ConfigurationManager &cfg) : @@ -19,7 +21,7 @@ Wizard::InstallationTargetPage::InstallationTargetPage(QWidget *parent, const Fi void Wizard::InstallationTargetPage::initializePage() { - QString path(QFile::decodeName(mCfgMgr.getUserDataPath().string().c_str())); //TODO(Project579): This will probably break in windows with unicode paths + QString path(QFile::decodeName(Files::pathToUnicodeString(mCfgMgr.getUserDataPath()).c_str())); path.append(QDir::separator() + QLatin1String("basedata")); QDir dir(path); diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index a597b11df8..759fe7edd7 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -471,5 +471,5 @@ bool Wizard::MainWizard::findFiles(const QString &name, const QString &path) QString Wizard::MainWizard::toQString(const std::filesystem::path& path) { - return QString::fromUtf8(path.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths + return QString::fromStdWString(path.wstring()); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 2e259c2136..9ddfc4eb5b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -214,7 +214,7 @@ IF(NOT WIN32 AND NOT APPLE) ENDIF() add_component_dir (files linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager - constrainedfilestream memorystream hash configfileparser openfile constrainedfilestreambuf + constrainedfilestream memorystream hash configfileparser openfile constrainedfilestreambuf conversion ) add_component_dir (compiler diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 65d184cf75..76d8e9b092 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -37,7 +37,7 @@ using namespace Bsa; /// Error handling [[noreturn]] void BSAFile::fail(const std::string &msg) { - throw std::runtime_error("BSA Error: " + msg + "\nArchive: " + mFilepath.string()); //TODO(Project579): This will probably break in windows with unicode paths + throw std::runtime_error("BSA Error: " + msg + "\nArchive: " + Files::pathToUnicodeString(mFilepath)); } //the getHash code is from bsapack from ghostwheel diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index d01fb6d421..0d1bda6134 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -30,6 +30,7 @@ #include #include +#include namespace Bsa { @@ -134,7 +135,7 @@ public: std::string getFilename() const { - return mFilepath.string(); //TODO(Project579): This will probably break in windows with unicode paths + return Files::pathToUnicodeString(mFilepath); } }; diff --git a/components/bsa/compressedbsafile.cpp b/components/bsa/compressedbsafile.cpp index 337570cad1..ee7204bd9e 100644 --- a/components/bsa/compressedbsafile.cpp +++ b/components/bsa/compressedbsafile.cpp @@ -48,6 +48,7 @@ #include #include #include +#include namespace Bsa { @@ -214,7 +215,7 @@ void CompressedBSAFile::readHeader() if ((archiveFlags & 0x1) != 0) getBZString(folder, input); - folderHash = generateHash(folder, std::string()); + folderHash = generateHash(folder, {}); auto iter = mFolders.find(folderHash); if (iter == mFolders.end()) @@ -309,13 +310,11 @@ CompressedBSAFile::FileRecord CompressedBSAFile::getFileRecord(const std::string std::replace(path.begin(), path.end(), '\\', '/'); #endif - std::filesystem::path p(path); - std::string stem = p.stem().string(); - std::string ext = p.extension().string(); - p.remove_filename(); + auto p = Files::pathFromUnicodeString(path); + const auto stem = p.stem(); + const auto ext = p.extension().u8string(); - std::string folder = p.string(); - std::uint64_t folderHash = generateHash(folder, std::string()); + std::uint64_t folderHash = generateHash(p.parent_path(), {}); auto it = mFolders.find(folderHash); if (it == mFolders.end()) @@ -358,7 +357,7 @@ Files::IStreamPtr CompressedBSAFile::getFile(const FileRecord& fileRecord) size_t size = fileRecord.getSizeWithoutCompressionFlag(); size_t uncompressedSize = size; bool compressed = fileRecord.isCompressed(mCompressedByDefault); - Files::IStreamPtr streamPtr = Files::openConstrainedFileStream(mFilename, fileRecord.offset, size); + Files::IStreamPtr streamPtr = Files::openConstrainedFileStream(mFilepath, fileRecord.offset, size); std::istream* fileStream = streamPtr.get(); if (mEmbeddedFileNames) { @@ -395,10 +394,10 @@ Files::IStreamPtr CompressedBSAFile::getFile(const FileRecord& fileRecord) LZ4F_decompressOptions_t options = {}; LZ4F_errorCode_t errorCode = LZ4F_decompress(context, memoryStreamPtr->getRawData(), &uncompressedSize, buffer.data(), &size, &options); if (LZ4F_isError(errorCode)) - fail("LZ4 decompression error (file " + mFilename + "): " + LZ4F_getErrorName(errorCode)); + fail("LZ4 decompression error (file " + Files::pathToUnicodeString(mFilepath) + "): " + LZ4F_getErrorName(errorCode)); errorCode = LZ4F_freeDecompressionContext(context); if (LZ4F_isError(errorCode)) - fail("LZ4 decompression error (file " + mFilename + "): " + LZ4F_getErrorName(errorCode)); + fail("LZ4 decompression error (file " + Files::pathToUnicodeString(mFilepath) + "): " + LZ4F_getErrorName(errorCode)); } } else @@ -409,9 +408,9 @@ Files::IStreamPtr CompressedBSAFile::getFile(const FileRecord& fileRecord) return std::make_unique>(std::move(memoryStreamPtr)); } -BsaVersion CompressedBSAFile::detectVersion(const std::string& filePath) +BsaVersion CompressedBSAFile::detectVersion(const std::filesystem::path &filePath) { - std::ifstream input(std::filesystem::path(filePath), std::ios_base::binary); + std::ifstream input(filePath, std::ios_base::binary); // Total archive size std::streamoff fsize = 0; @@ -460,7 +459,7 @@ void CompressedBSAFile::convertCompressedSizesToUncompressed() continue; } - Files::IStreamPtr dataBegin = Files::openConstrainedFileStream(mFilename, fileRecord.offset, fileRecord.getSizeWithoutCompressionFlag()); + Files::IStreamPtr dataBegin = Files::openConstrainedFileStream(mFilepath, fileRecord.offset, fileRecord.getSizeWithoutCompressionFlag()); if (mEmbeddedFileNames) { @@ -472,30 +471,31 @@ void CompressedBSAFile::convertCompressedSizesToUncompressed() } } -std::uint64_t CompressedBSAFile::generateHash(std::string stem, std::string extension) +std::uint64_t CompressedBSAFile::generateHash(const std::filesystem::path& stem, std::u8string extension) { - size_t len = stem.length(); + auto str = stem.u8string(); + size_t len = str.length(); if (len == 0) return 0; - std::replace(stem.begin(), stem.end(), '/', '\\'); - Misc::StringUtils::lowerCaseInPlace(stem); - uint64_t result = stem[len-1] | (len >= 3 ? (stem[len-2] << 8) : 0) | (len << 16) | (stem[0] << 24); + std::replace(str.begin(), str.end(), u8'/', u8'\\'); + Misc::StringUtils::lowerCaseInPlace(str); + uint64_t result = str[len-1] | (len >= 3 ? (str[len-2] << 8) : 0) | (len << 16) | (str[0] << 24); if (len >= 4) { uint32_t hash = 0; for (size_t i = 1; i <= len-3; ++i) - hash = hash * 0x1003f + stem[i]; + hash = hash * 0x1003f + str[i]; result += static_cast(hash) << 32; } if (extension.empty()) return result; Misc::StringUtils::lowerCaseInPlace(extension); - if (extension == ".kf") result |= 0x80; - else if (extension == ".nif") result |= 0x8000; - else if (extension == ".dds") result |= 0x8080; - else if (extension == ".wav") result |= 0x80000000; + if (extension == u8".kf") result |= 0x80; + else if (extension == u8".nif") result |= 0x8000; + else if (extension == u8".dds") result |= 0x8080; + else if (extension == u8".wav") result |= 0x80000000; uint32_t hash = 0; - for (const char &c : extension) + for (const auto &c : extension) hash = hash * 0x1003f + c; result += static_cast(hash) << 32; return result; diff --git a/components/bsa/compressedbsafile.hpp b/components/bsa/compressedbsafile.hpp index 53dcf8f522..71727bfade 100644 --- a/components/bsa/compressedbsafile.hpp +++ b/components/bsa/compressedbsafile.hpp @@ -83,7 +83,7 @@ namespace Bsa //mFiles used by OpenMW will contain uncompressed file sizes void convertCompressedSizesToUncompressed(); /// \brief Normalizes given filename or folder and generates format-compatible hash. See https://en.uesp.net/wiki/Tes4Mod:Hash_Calculation. - static std::uint64_t generateHash(std::filesystem::path stem, std::string extension) ; + static std::uint64_t generateHash(const std::filesystem::path& stem, std::u8string extension) ; Files::IStreamPtr getFile(const FileRecord& fileRecord); public: using BSAFile::open; diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 0fe36720f5..e99e31372a 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -32,7 +32,7 @@ void Config::GameSettings::validatePaths() mDataDirs.clear(); for (auto & dataDir : dataDirs) { - QString path = QString::fromUtf8(dataDir.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths + QString path = QString::fromStdWString(dataDir.wstring()); QDir dir(path); if (dir.exists()) @@ -57,7 +57,7 @@ void Config::GameSettings::validatePaths() mCfgMgr.processPaths(dataDirs, /*basePath=*/""); if (!dataDirs.empty()) { - QString path = QString::fromUtf8(dataDirs.front().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths + QString path = QString::fromStdWString(dataDirs.front().wstring()); QDir dir(path); if (dir.exists()) diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index 129d04dcc1..2932a211cf 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -119,7 +119,7 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) } // global and local data directories are not part of any profile - const auto globalDataDir = QString(gameSettings.getGlobalDataDir().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths + const auto globalDataDir = QString::fromStdWString(gameSettings.getGlobalDataDir().wstring()); const auto dataLocal = gameSettings.getDataLocal(); dirs.removeAll(globalDataDir); dirs.removeAll(dataLocal); diff --git a/components/crashcatcher/windows_crashcatcher.cpp b/components/crashcatcher/windows_crashcatcher.cpp index c62a066c59..47f1ba6c2c 100644 --- a/components/crashcatcher/windows_crashcatcher.cpp +++ b/components/crashcatcher/windows_crashcatcher.cpp @@ -140,7 +140,7 @@ namespace Crash const auto str = crashLogPath.u8string(); size_t length = str.length(); if (length >= MAX_LONG_PATH) length = MAX_LONG_PATH - 1; - strncpy_s(mShm->mStartup.mLogFilePath, sizeof mShm->mStartup.mLogFilePath, Misc::StringUtils::char8_to_char(str.c_str()), length); //TODO(Project579): This will probably break in windows with unicode paths + strncpy_s(mShm->mStartup.mLogFilePath, sizeof mShm->mStartup.mLogFilePath, Misc::StringUtils::u8StringToString(str).c_str(), length); mShm->mStartup.mLogFilePath[length] = '\0'; // note that we don't need to lock the SHM here, the other process has not started yet diff --git a/components/debug/debugging.cpp b/components/debug/debugging.cpp index e6f159bf81..71f27036e8 100644 --- a/components/debug/debugging.cpp +++ b/components/debug/debugging.cpp @@ -8,9 +8,11 @@ #include #include +#include #ifdef _WIN32 #include #include +#include #endif #include @@ -318,12 +320,12 @@ int wrapApplication(int (*innerApplication)(int argc, char *argv[]), int argc, c { #if defined(_WIN32) const std::string crashLogName = Misc::StringUtils::lowerCase(appName) + "-crash.dmp"; - Crash::CrashCatcher crashy(argc, argv, (cfgMgr.getLogPath() / crashLogName).make_preferred().string()); + Crash::CrashCatcher crashy(argc, argv, Files::pathToUnicodeString(cfgMgr.getLogPath() / crashLogName)); #else const std::string crashLogName = Misc::StringUtils::lowerCase(appName) + "-crash.log"; // install the crash handler as soon as possible. note that the log path // does not depend on config being read. - crashCatcherInstall(argc, argv, (cfgMgr.getLogPath() / crashLogName).string()); + crashCatcherInstall(argc, argv, Files::pathToUnicodeString(cfgMgr.getLogPath() / crashLogName)); #endif ret = innerApplication(argc, argv); } diff --git a/components/debug/debuglog.cpp b/components/debug/debuglog.cpp index ef453283e8..bb0c4b57e8 100644 --- a/components/debug/debuglog.cpp +++ b/components/debug/debuglog.cpp @@ -2,7 +2,8 @@ #include -#include +#include +#include namespace Debug { diff --git a/components/detournavigator/navigator.cpp b/components/detournavigator/navigator.cpp index 200582216d..c473221322 100644 --- a/components/detournavigator/navigator.cpp +++ b/components/detournavigator/navigator.cpp @@ -4,6 +4,7 @@ #include "recastglobalallocator.hpp" #include +#include namespace DetourNavigator { @@ -16,7 +17,7 @@ namespace DetourNavigator { try { - db = std::make_unique((userDataPath / "navmesh.db").string(), settings.mMaxDbFileSize); //TODO(Project579): This will probably break in windows with unicode paths + db = std::make_unique(Files::pathToUnicodeString(userDataPath / "navmesh.db"), settings.mMaxDbFileSize); } catch (const std::exception& e) { diff --git a/components/esm3/esmreader.cpp b/components/esm3/esmreader.cpp index 5877951d43..b1c4bea329 100644 --- a/components/esm3/esmreader.cpp +++ b/components/esm3/esmreader.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -73,7 +74,7 @@ void ESMReader::resolveParentFileIndices(ReadersCache& readers) const ESM::ReadersCache::BusyItem reader = readers.get(static_cast(i)); if (reader->getFileSize() == 0) continue; // Content file in non-ESM format - std::string fnamecandidate = reader->getName().filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + const auto fnamecandidate = Files::pathToUnicodeString(reader->getName().filename()); if (Misc::StringUtils::ciEqual(fname, fnamecandidate)) { index = i; @@ -359,7 +360,7 @@ std::string ESMReader::getString(int size) std::stringstream ss; ss << "ESM Error: " << msg; - ss << "\n File: " << mCtx.filename; //TODO(Project579): This will probably break in windows with unicode paths + ss << "\n File: " << Files::pathToUnicodeString(mCtx.filename); ss << "\n Record: " << mCtx.recName.toStringView(); ss << "\n Subrecord: " << mCtx.subName.toStringView(); if (mEsm.get()) diff --git a/components/esm3/loadcell.cpp b/components/esm3/loadcell.cpp index 2d92bf561e..dc32ee6a43 100644 --- a/components/esm3/loadcell.cpp +++ b/components/esm3/loadcell.cpp @@ -131,7 +131,7 @@ namespace ESM { if(!overriding) mWater = std::numeric_limits::max(); - Log(Debug::Warning) << "Warning: Encountered invalid water level in cell " << mName << " defined in " << esm.getContext().filename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Warning) << "Warning: Encountered invalid water level in cell " << mName << " defined in " << esm.getContext().filename; } else mWater = waterLevel; diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp index 4a8e908913..a5696c461b 100644 --- a/components/esm4/reader.cpp +++ b/components/esm4/reader.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include "formid.hpp" @@ -184,12 +185,7 @@ void Reader::open(Files::IStreamPtr&& stream, const std::filesystem::path &filen throw std::runtime_error("Unknown file format"); // can't yet use fail() as mCtx is not setup } -void Reader::openRaw(const std::string& filename) -{ - openRaw(Files::openConstrainedFileStream(filename), filename); -} - -void Reader::open(const std::string& filename) +void Reader::open(const std::filesystem::path& filename) { open(Files::openConstrainedFileStream(filename), filename); } @@ -637,7 +633,7 @@ void Reader::adjustGRUPFormId() std::stringstream ss; ss << "ESM Error: " << msg; - ss << "\n File: " << mCtx.filename.string(); //TODO(Project579): This will probably break in windows with unicode paths + ss << "\n File: " << Files::pathToUnicodeString(mCtx.filename); ss << "\n Record: " << ESM::printName(mCtx.recordHeader.record.typeId); ss << "\n Subrecord: " << ESM::printName(mCtx.subRecordHeader.typeId); if (mStream.get()) diff --git a/components/esmloader/load.cpp b/components/esmloader/load.cpp index 99d8159f04..66e859bf20 100644 --- a/components/esmloader/load.cpp +++ b/components/esmloader/load.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -228,7 +229,7 @@ namespace EsmLoader for (std::size_t i = 0; i < contentFiles.size(); ++i) { const std::string &file = contentFiles[i]; - const std::string extension = Misc::StringUtils::lowerCase(std::filesystem::path(file).extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break + const std::string extension = Misc::StringUtils::lowerCase(Files::pathToUnicodeString(std::filesystem::path(file).extension())); if (supportedFormats.find(extension) == supportedFormats.end()) { diff --git a/components/files/collections.cpp b/components/files/collections.cpp index 0929336075..575beb988d 100644 --- a/components/files/collections.cpp +++ b/components/files/collections.cpp @@ -1,4 +1,5 @@ #include "collections.hpp" +#include "conversion.hpp" #include #include @@ -42,12 +43,14 @@ namespace Files std::filesystem::directory_iterator (mDirectorie)) { const auto& path = iter2.path(); + const auto str = Files::pathToUnicodeString(path.filename()); + if (mFoldCase) { - if (Misc::StringUtils::ciEqual(file, path.filename().string())) //TODO(Project579): This will probably break in windows with unicode paths + if (Misc::StringUtils::ciEqual(file, str)) return path; } - else if (path.filename().string() == file) //TODO(Project579): This will probably break in windows with unicode paths + else if (str == file) return path; } } @@ -63,13 +66,14 @@ namespace Files std::filesystem::directory_iterator (mDirectorie)) { const auto& path = iter2.path(); + const auto str = Files::pathToUnicodeString(path.filename()); if (mFoldCase) { - if (Misc::StringUtils::ciEqual(file, path.filename().string())) //TODO(Project579): This will probably break in windows with unicode paths + if (Misc::StringUtils::ciEqual(file, str)) return true; } - else if (path.filename().string() == file) //TODO(Project579): This will probably break in windows with unicode paths + else if (str == file) return true; } } diff --git a/components/files/collections.hpp b/components/files/collections.hpp index 69ae7d0d84..000160bae7 100644 --- a/components/files/collections.hpp +++ b/components/files/collections.hpp @@ -19,14 +19,14 @@ namespace Files /// leading dot and must be all lower-case. const MultiDirCollection& getCollection(const std::string& extension) const; - std::filesystem::path getPath(const std::string& file) const; //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + std::filesystem::path getPath(const std::string& file) const; ///< Return full path (including filename) of \a file. /// /// If the file does not exist in any of the collection's /// directories, an exception is thrown. \a file must include the /// extension. - bool doesExist(const std::string& file) const; //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + bool doesExist(const std::string& file) const; ///< \return Does a file with the given name exist? const Files::PathContainer& getPaths() const; diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index cddab2f8b2..8f4bc12c6b 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -460,29 +460,4 @@ PathContainer asPathContainer(const MaybeQuotedPathContainer& MaybeQuotedPathCon return res; } -std::string pathToUnicodeString(const std::filesystem::path& path) -{ - return Misc::StringUtils::u8StringToString(path.u8string()); -} - -std::string pathToUnicodeString(std::filesystem::path&& path) -{ - return Misc::StringUtils::u8StringToString(path.u8string()); -} - -std::filesystem::path unicodeStringToPath(const std::string_view path) -{ - return Misc::StringUtils::stringToU8String(path); -} - -std::filesystem::path unicodeStringToPath(std::string&& path) -{ - return Misc::StringUtils::stringToU8String(std::move(path)); -} - -std::filesystem::path unicodeStringToPath(const char* path) -{ - return Misc::StringUtils::stringToU8String(path); -} - } /* namespace Files */ diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index e10d528404..7c999ebd6e 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -105,16 +105,6 @@ typedef std::vector MaybeQuotedPathContainer; PathContainer asPathContainer(const MaybeQuotedPathContainer& MaybeQuotedPathContainer); -std::string pathToUnicodeString(const std::filesystem::path& path); - -std::string pathToUnicodeString(std::filesystem::path&& path); - -std::filesystem::path unicodeStringToPath(const std::string_view path); - -std::filesystem::path unicodeStringToPath(std::string&& path); - -std::filesystem::path unicodeStringToPath(const char* path); - } /* namespace Files */ #endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */ diff --git a/components/files/conversion.cpp b/components/files/conversion.cpp new file mode 100644 index 0000000000..ab32158ff9 --- /dev/null +++ b/components/files/conversion.cpp @@ -0,0 +1,29 @@ + +#include "conversion.hpp" + +#include + +std::string Files::pathToUnicodeString(const std::filesystem::path& path) +{ + return Misc::StringUtils::u8StringToString(path.u8string()); +} + +std::string Files::pathToUnicodeString(std::filesystem::path&& path) +{ + return Misc::StringUtils::u8StringToString(path.u8string()); +} + +std::filesystem::path Files::pathFromUnicodeString(std::string_view path) +{ + return Misc::StringUtils::stringToU8String(path); +} + +std::filesystem::path Files::pathFromUnicodeString(std::string&& path) +{ + return Misc::StringUtils::stringToU8String(std::move(path)); +} + +std::filesystem::path Files::pathFromUnicodeString(const char* path) +{ + return Misc::StringUtils::stringToU8String(path); +} diff --git a/components/files/conversion.hpp b/components/files/conversion.hpp new file mode 100644 index 0000000000..7eb3ebf7b4 --- /dev/null +++ b/components/files/conversion.hpp @@ -0,0 +1,18 @@ +#ifndef COMPONENTS_FILES_CONVERSION_HPP +#define COMPONENTS_FILES_CONVERSION_HPP + +#include + +namespace Files { + std::string pathToUnicodeString(const std::filesystem::path& path); + + std::string pathToUnicodeString(std::filesystem::path&& path); + + std::filesystem::path pathFromUnicodeString(std::string_view path); + + std::filesystem::path pathFromUnicodeString(std::string&& path); + + std::filesystem::path pathFromUnicodeString(const char* path); +} + +#endif //COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP diff --git a/components/files/hash.cpp b/components/files/hash.cpp index e8d4c2a3b0..946ff06272 100644 --- a/components/files/hash.cpp +++ b/components/files/hash.cpp @@ -1,4 +1,5 @@ #include "hash.hpp" +#include "conversion.hpp" #include @@ -34,7 +35,7 @@ namespace Files } catch (const std::exception& e) { - throw std::runtime_error("Error while reading \"" + fileName.string() + "\" to get hash: " + std::string(e.what())); //TODO(Project579): This will probably break in windows with unicode paths + throw std::runtime_error("Error while reading \"" + Files::pathToUnicodeString(fileName) + "\" to get hash: " + e.what()); } return hash; } diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index 94f02f8f7c..c085a07682 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -24,9 +24,9 @@ namespace } } if (dir == nullptr) - return std::filesystem::path(); + return {}; else - return std::filesystem::path(dir); + return dir; } std::filesystem::path getEnv(const std::string& envVariable, const std::filesystem::path& fallback) diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index ad7b54b463..752a1d0275 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -1,4 +1,5 @@ #include "multidircollection.hpp" +#include "conversion.hpp" #include @@ -30,19 +31,18 @@ namespace Files { if (!std::filesystem::is_directory(directory)) { - Log(Debug::Info) << "Skipping invalid directory: " << directory.string(); //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Skipping invalid directory: " << directory; continue; } - for (std::filesystem::directory_iterator dirIter(directory); - dirIter != std::filesystem::directory_iterator(); ++dirIter) + for (const auto& dirIter : std::filesystem::directory_iterator(directory)) { - std::filesystem::path path = *dirIter; + const auto& path = dirIter.path(); - if (!equal (extension, path.extension().string())) //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break + if (!equal (extension, Files::pathToUnicodeString(path.extension()))) continue; - std::string filename = path.filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + const auto filename = Files::pathToUnicodeString(path.filename()); TIter result = mFiles.find (filename); diff --git a/components/files/openfile.cpp b/components/files/openfile.cpp index 6eb0ee51c8..9ffe134e4a 100644 --- a/components/files/openfile.cpp +++ b/components/files/openfile.cpp @@ -1,4 +1,5 @@ #include "openfile.hpp" +#include "conversion.hpp" #include #include @@ -9,7 +10,7 @@ namespace Files { auto stream = std::make_unique(path, std::ios::binary); if (!stream->is_open()) - throw std::runtime_error("Failed to open '" + path.string() + "' for reading: " + std::strerror(errno)); //TODO(Project579): This will probably break in windows with unicode paths + throw std::runtime_error("Failed to open '" + Files::pathToUnicodeString(path) + "' for reading: " + std::strerror(errno)); stream->exceptions(std::ios::badbit); return stream; } diff --git a/components/fx/technique.cpp b/components/fx/technique.cpp index 357d8448d1..c2de7aaa89 100644 --- a/components/fx/technique.cpp +++ b/components/fx/technique.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include "parse_constants.hpp" @@ -37,9 +39,9 @@ namespace namespace fx { - Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, const std::string& name, int width, int height, bool ubo, bool supportsNormals) - : mName(name) - , mFileName((std::filesystem::path(Technique::sSubdir) / (mName + Technique::sExt)).string()) //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break + Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, std::string name, int width, int height, bool ubo, bool supportsNormals) + : mName(std::move(name)) + , mFileName(Files::pathToUnicodeString((Files::pathFromUnicodeString(Technique::sSubdir) / (mName + Technique::sExt)))) , mLastModificationTime(std::filesystem::file_time_type()) , mWidth(width) , mHeight(height) diff --git a/components/fx/technique.hpp b/components/fx/technique.hpp index 4b1c9f19bb..4c01e2a92d 100644 --- a/components/fx/technique.hpp +++ b/components/fx/technique.hpp @@ -123,7 +123,7 @@ namespace fx static constexpr FlagsType Flag_Disable_SunGlare = (1 << 4); static constexpr FlagsType Flag_Hidden = (1 << 5); - Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, const std::string& name, int width, int height, bool ubo, bool supportsNormals); + Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, std::string name, int width, int height, bool ubo, bool supportsNormals); bool compile(); diff --git a/components/lua/luastate.cpp b/components/lua/luastate.cpp index a78eea6dde..8dacdd5267 100644 --- a/components/lua/luastate.cpp +++ b/components/lua/luastate.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace LuaUtil { @@ -270,7 +271,7 @@ namespace LuaUtil sol::function LuaState::loadInternalLib(std::string_view libName) { const auto path = packageNameToPath(libName, mLibSearchPaths); - sol::load_result res = mLua.load_file(path.string(), sol::load_mode::text); //TODO(Project579): This will probably break in windows with unicode paths + sol::load_result res = mLua.load_file(Files::pathToUnicodeString(path), sol::load_mode::text); if (!res.valid()) throw std::runtime_error("Lua error: " + res.get()); return res; diff --git a/components/lua/storage.cpp b/components/lua/storage.cpp index ffb4f8af82..c80181f977 100644 --- a/components/lua/storage.cpp +++ b/components/lua/storage.cpp @@ -160,7 +160,7 @@ namespace LuaUtil assert(mData.empty()); // Shouldn't be used before loading try { - Log(Debug::Info) << "Loading Lua storage \"" << path << "\" (" << std::filesystem::file_size(path) << " bytes)"; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Loading Lua storage \"" << path << "\" (" << std::filesystem::file_size(path) << " bytes)"; std::ifstream fin(path, std::fstream::binary); std::string serializedData((std::istreambuf_iterator(fin)), std::istreambuf_iterator()); sol::table data = deserialize(mLua, serializedData); @@ -186,7 +186,7 @@ namespace LuaUtil data[sectionName] = section->asTable(); } std::string serializedData = serialize(data); - Log(Debug::Info) << "Saving Lua storage \"" << path << "\" (" << serializedData.size() << " bytes)"; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Saving Lua storage \"" << path << "\" (" << serializedData.size() << " bytes)"; std::ofstream fout(path, std::fstream::binary); fout.write(serializedData.data(), serializedData.size()); fout.close(); diff --git a/components/myguiplatform/myguidatamanager.cpp b/components/myguiplatform/myguidatamanager.cpp index 3078650a47..5696cec58f 100644 --- a/components/myguiplatform/myguidatamanager.cpp +++ b/components/myguiplatform/myguidatamanager.cpp @@ -7,6 +7,7 @@ #include #include +#include namespace { @@ -68,7 +69,7 @@ const std::string &DataManager::getDataPath(const std::string &name) const if (!isDataExist(name)) return result; - result = (mResourcePath / name).string(); //TODO(Project579): This is broken on windows with unicode paths + result = Files::pathToUnicodeString(mResourcePath / name); return result; } diff --git a/components/myguiplatform/myguiloglistener.cpp b/components/myguiplatform/myguiloglistener.cpp index e22b96680a..0ca1af3415 100644 --- a/components/myguiplatform/myguiloglistener.cpp +++ b/components/myguiplatform/myguiloglistener.cpp @@ -10,7 +10,7 @@ namespace osgMyGUI { mStream.open(mFileName, std::ios_base::out); if (!mStream.is_open()) - Log(Debug::Error) << "Unable to create MyGUI log with path " << mFileName; //TODO(Project579): This is broken on windows with unicode paths + Log(Debug::Error) << "Unable to create MyGUI log with path " << mFileName; } void CustomLogListener::close() diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 08d80b0f67..8b525e8ae7 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -316,7 +316,7 @@ void NIFFile::parse(Files::IStreamPtr&& stream) r = entry->second(); if (!supportedVersion) - Log(Debug::Verbose) << "NIF Debug: Reading record of type " << rec << ", index " << i << " (" << filename << ")"; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Verbose) << "NIF Debug: Reading record of type " << rec << ", index " << i << " (" << filename << ")"; assert(r != nullptr); assert(r->recType != RC_MISSING); diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index aeaf57c5f4..dcf406ecb2 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -21,6 +21,7 @@ #include #include +#include namespace { @@ -187,7 +188,7 @@ osg::ref_ptr BulletNifLoader::load(const Nif::File& nif) if (node) roots.emplace_back(node); } - const std::string filename = nif.getFilename().string(); //TODO(Project579): This will probably break in windows with unicode paths + const std::string filename = Files::pathToUnicodeString(nif.getFilename()); mShape->mFileName = filename; if (roots.empty()) { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 39ccafdceb..5db3e9280c 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -299,7 +299,7 @@ namespace NifOsg setupController(key, callback, /*animflags*/0); if (!target.mKeyframeControllers.emplace(strdata->string, callback).second) - Log(Debug::Verbose) << "Controller " << strdata->string << " present more than once in " << nif->getFilename() << ", ignoring later version"; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Verbose) << "Controller " << strdata->string << " present more than once in " << nif->getFilename() << ", ignoring later version"; } } @@ -485,20 +485,20 @@ namespace NifOsg { if (nifNode->recType != Nif::RC_NiTextureEffect) { - Log(Debug::Info) << "Unhandled effect " << nifNode->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unhandled effect " << nifNode->recName << " in " << mFilename; return; } const Nif::NiTextureEffect* textureEffect = static_cast(nifNode); if (textureEffect->textureType != Nif::NiTextureEffect::Environment_Map) { - Log(Debug::Info) << "Unhandled NiTextureEffect type " << textureEffect->textureType << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unhandled NiTextureEffect type " << textureEffect->textureType << " in " << mFilename; return; } if (textureEffect->texture.empty()) { - Log(Debug::Info) << "NiTextureEffect missing source texture in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "NiTextureEffect missing source texture in " << mFilename; return; } @@ -515,7 +515,7 @@ namespace NifOsg texGen->setMode(osg::TexGen::SPHERE_MAP); break; default: - Log(Debug::Info) << "Unhandled NiTextureEffect coordGenType " << textureEffect->coordGenType << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unhandled NiTextureEffect coordGenType " << textureEffect->coordGenType << " in " << mFilename; return; } @@ -875,7 +875,7 @@ namespace NifOsg // These controllers are handled elsewhere } else - Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; } } @@ -915,7 +915,7 @@ namespace NifOsg composite->addController(osgctrl); } else - Log(Debug::Info) << "Unexpected material controller " << ctrl->recType << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unexpected material controller " << ctrl->recType << " in " << mFilename; } } @@ -959,7 +959,7 @@ namespace NifOsg composite->addController(callback); } else - Log(Debug::Info) << "Unexpected texture controller " << ctrl->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unexpected texture controller " << ctrl->recName << " in " << mFilename; } } @@ -994,7 +994,7 @@ namespace NifOsg // unused } else - Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename; } for (; !colliders.empty(); colliders = colliders->next) { @@ -1009,7 +1009,7 @@ namespace NifOsg program->addOperator(new SphericalCollider(sphericalcollider)); } else - Log(Debug::Info) << "Unhandled particle collider " << colliders->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unhandled particle collider " << colliders->recName << " in " << mFilename; } } @@ -1152,7 +1152,7 @@ namespace NifOsg } if (!partctrl) { - Log(Debug::Info) << "No particle controller found in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "No particle controller found in " << mFilename; return; } @@ -1247,7 +1247,7 @@ namespace NifOsg unsigned int uvSet = *it; if (uvSet >= uvlist.size()) { - Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << name << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << name << "\" in " << mFilename; if (uvlist.empty()) continue; uvSet = 0; @@ -1419,7 +1419,7 @@ namespace NifOsg case 9: return osg::BlendFunc::ONE_MINUS_DST_ALPHA; case 10: return osg::BlendFunc::SRC_ALPHA_SATURATE; default: - Log(Debug::Info) << "Unexpected blend mode: "<< mode << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unexpected blend mode: "<< mode << " in " << mFilename; return osg::BlendFunc::SRC_ALPHA; } } @@ -1437,7 +1437,7 @@ namespace NifOsg case 6: return osg::AlphaFunc::GEQUAL; case 7: return osg::AlphaFunc::NEVER; default: - Log(Debug::Info) << "Unexpected blend mode: " << mode << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unexpected blend mode: " << mode << " in " << mFilename; return osg::AlphaFunc::LEQUAL; } } @@ -1455,7 +1455,7 @@ namespace NifOsg case 6: return osg::Stencil::GEQUAL; case 7: return osg::Stencil::ALWAYS; default: - Log(Debug::Info) << "Unexpected stencil function: " << func << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unexpected stencil function: " << func << " in " << mFilename; return osg::Stencil::NEVER; } } @@ -1471,7 +1471,7 @@ namespace NifOsg case 4: return osg::Stencil::DECR; case 5: return osg::Stencil::INVERT; default: - Log(Debug::Info) << "Unexpected stencil operation: " << op << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unexpected stencil operation: " << op << " in " << mFilename; return osg::Stencil::KEEP; } } @@ -1514,7 +1514,7 @@ namespace NifOsg packing = 4; break; default: - Log(Debug::Info) << "Unhandled internal pixel format " << pixelData->fmt << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unhandled internal pixel format " << pixelData->fmt << " in " << mFilename; return nullptr; } @@ -1572,7 +1572,7 @@ namespace NifOsg { if (pixelData->palette.empty() || pixelData->bpp != 8) { - Log(Debug::Info) << "Palettized texture in " << mFilename << " is invalid, ignoring"; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Palettized texture in " << mFilename << " is invalid, ignoring"; return nullptr; } pixelformat = pixelData->fmt == Nif::NiPixelData::NIPXFMT_PAL8 ? GL_RGB : GL_RGBA; @@ -1644,7 +1644,7 @@ namespace NifOsg break; default: { - Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; continue; } } @@ -1658,7 +1658,7 @@ namespace NifOsg if(tex.texture.empty() && texprop->controller.empty()) { if (i == 0) - Log(Debug::Warning) << "Base texture is in use but empty on shape \"" << nodeName << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Warning) << "Base texture is in use but empty on shape \"" << nodeName << "\" in " << mFilename; continue; } @@ -1815,7 +1815,7 @@ namespace NifOsg break; default: { - Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; continue; } } @@ -1859,10 +1859,10 @@ namespace NifOsg case Nif::BSShaderType::ShaderType_Water: case Nif::BSShaderType::ShaderType_Lighting30: case Nif::BSShaderType::ShaderType_Tile: - Log(Debug::Warning) << "Unhandled BSShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Warning) << "Unhandled BSShaderType " << type << " in " << mFilename; return std::string_view(); } - Log(Debug::Warning) << "Unknown BSShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Warning) << "Unknown BSShaderType " << type << " in " << mFilename; return std::string_view(); } @@ -1891,10 +1891,10 @@ namespace NifOsg case Nif::BSLightingShaderType::ShaderType_LODNoise: case Nif::BSLightingShaderType::ShaderType_MultitexLandLODBlend: case Nif::BSLightingShaderType::ShaderType_Dismemberment: - Log(Debug::Warning) << "Unhandled BSLightingShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Warning) << "Unhandled BSLightingShaderType " << type << " in " << mFilename; return std::string_view(); } - Log(Debug::Warning) << "Unknown BSLightingShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Warning) << "Unknown BSLightingShaderType " << type << " in " << mFilename; return std::string_view(); } @@ -2057,7 +2057,7 @@ namespace NifOsg break; } default: - Log(Debug::Info) << "Unhandled " << property->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Unhandled " << property->recName << " in " << mFilename; break; } } @@ -2304,7 +2304,7 @@ namespace NifOsg else if (type == Nif::RC_NiClusterAccumulator) setBin_BackToFront(stateset); else - Log(Debug::Error) << "Unrecognized NiAccumulator in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Error) << "Unrecognized NiAccumulator in " << mFilename; }; switch (mPushedSorter->mMode) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index ef8d1c66e3..db08631666 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -48,6 +48,7 @@ #include #include +#include #include "imagemanager.hpp" #include "niffilemanager.hpp" @@ -498,14 +499,14 @@ namespace Resource osgDB::ReaderWriter::ReadResult readImage(const std::string& filename, const osgDB::Options* options) override { - std::filesystem::path filePath(filename); //TODO(Project579): This will probably break in windows with unicode paths + auto filePath = Files::pathFromUnicodeString(filename); if (filePath.is_absolute()) // It is a hack. Needed because either OSG or libcollada-dom tries to make an absolute path from // our relative VFS path by adding current working directory. filePath = std::filesystem::relative(filename, osgDB::getCurrentWorkingDirectory()); try { - return osgDB::ReaderWriter::ReadResult(mImageManager->getImage(filePath.string()), //TODO(Project579): This will probably break in windows with unicode paths + return osgDB::ReaderWriter::ReadResult(mImageManager->getImage(Files::pathToUnicodeString(filePath)), osgDB::ReaderWriter::ReadResult::FILE_LOADED); } catch (std::exception& e) diff --git a/components/sceneutil/screencapture.cpp b/components/sceneutil/screencapture.cpp index 6adff9323d..6c73191014 100644 --- a/components/sceneutil/screencapture.cpp +++ b/components/sceneutil/screencapture.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -129,7 +130,7 @@ namespace SceneUtil if (fileName.empty()) mCallback("Failed to save screenshot"); else - mCallback(fileName.string() + " has been saved"); //TODO(Project579): This will probably break in windows with unicode paths + mCallback(Files::pathToUnicodeString(fileName) + " has been saved"); } AsyncScreenCaptureOperation::AsyncScreenCaptureOperation(osg::ref_ptr queue, diff --git a/components/settings/parser.cpp b/components/settings/parser.cpp index 44016ad010..1c1eeccc90 100644 --- a/components/settings/parser.cpp +++ b/components/settings/parser.cpp @@ -304,7 +304,7 @@ void Settings::SettingsFileParser::saveSettingsFile(const std::filesystem::path // Now install the newly written file in the requested place. if (changed) { - Log(Debug::Info) << "Updating settings file: " << file; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Updating settings file: " << file; std::ofstream ofstream; ofstream.open(file); ofstream << ostream.rdbuf(); diff --git a/components/settings/shadermanager.hpp b/components/settings/shadermanager.hpp index effedf63d2..6aa14e73ef 100644 --- a/components/settings/shadermanager.hpp +++ b/components/settings/shadermanager.hpp @@ -15,6 +15,7 @@ #include #include +#include namespace Settings { @@ -109,7 +110,7 @@ namespace Settings mData = YAML::Null; mPath = path; - Log(Debug::Info) << "Loading shader settings file: " << mPath; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Loading shader settings file: " << mPath; if (!std::filesystem::exists(mPath)) { @@ -123,7 +124,7 @@ namespace Settings try { - mData = YAML::LoadFile(mPath.string()); //TODO(Project579): This will probably break in windows with unicode paths + mData = YAML::LoadFile(Files::pathToUnicodeString(mPath)); mData.SetStyle(YAML::EmitterStyle::Block); if (!mData["config"]) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 1e48cf337e..189881fe97 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -126,7 +126,7 @@ namespace Shader includeFstream.open(includePath); if (includeFstream.fail()) { - Log(Debug::Error) << "Shader " << fileName << " error: Failed to open include " << includePath.string(); //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Error) << "Shader " << fileName << " error: Failed to open include " << includePath; return false; } int includedFileNumber = fileNumber++; @@ -472,7 +472,7 @@ namespace Shader stream.open(path); if (stream.fail()) { - Log(Debug::Error) << "Failed to open " << path.string(); //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Error) << "Failed to open " << path; return nullptr; } std::stringstream buffer; diff --git a/components/version/version.cpp b/components/version/version.cpp index a280bf38d3..eec374b97a 100644 --- a/components/version/version.cpp +++ b/components/version/version.cpp @@ -17,7 +17,7 @@ Version getOpenmwVersion(const std::filesystem::path &resourcePath) return v; } -std::string Version::describe() +std::string Version::describe() const { std::string str = "OpenMW version " + mVersion; std::string rev = mCommitHash; diff --git a/components/version/version.hpp b/components/version/version.hpp index 0248f869a9..6c1998bb60 100644 --- a/components/version/version.hpp +++ b/components/version/version.hpp @@ -13,7 +13,7 @@ namespace Version std::string mCommitHash; std::string mTagHash; - std::string describe(); + std::string describe() const; }; /// Read OpenMW version from the version file located in resourcePath. diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index f6b01a89c4..d04b827d62 100644 --- a/components/vfs/filesystemarchive.cpp +++ b/components/vfs/filesystemarchive.cpp @@ -6,6 +6,7 @@ #include #include +#include namespace VFS { @@ -21,7 +22,7 @@ namespace VFS { if (!mBuiltIndex) { - const auto str = mPath.string(); //TODO(Project579): This will probably break in windows with unicode paths + const auto str = mPath.u8string(); size_t prefix = str.size (); if (!mPath.empty() && str [prefix - 1] != '\\' && str [prefix - 1] != '/') @@ -34,7 +35,7 @@ namespace VFS continue; const auto& path = i.path (); - const auto& proper = path.string (); //TODO(Project579): This will probably break in windows with unicode paths + const auto& proper = Files::pathToUnicodeString(path); FileSystemArchiveFile file(path); @@ -44,7 +45,7 @@ namespace VFS const auto inserted = mIndex.insert(std::make_pair(searchable, file)); if (!inserted.second) - Log(Debug::Warning) << "Warning: found duplicate file for '" << proper << "', please check your file system for two files with the same name in different cases."; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Warning) << "Warning: found duplicate file for '" << proper << "', please check your file system for two files with the same name in different cases."; else out[inserted.first->first] = &inserted.first->second; } @@ -66,7 +67,7 @@ namespace VFS std::string FileSystemArchive::getDescription() const { - return std::string{"DIR: "} + mPath.string(); //TODO(Project579): This will probably break in windows with unicode paths + return "DIR: " + Files::pathToUnicodeString(mPath); } // ---------------------------------------------------------------------------------- diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 8f3963f3f7..118227a5f1 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -5,6 +5,8 @@ #include #include +#include +#include #include "archive.hpp" @@ -56,7 +58,7 @@ namespace VFS mIndex.clear(); for (const auto& archive : mArchives) - archive->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); //TODO(Project579): This will probably break in windows with unicode paths + archive->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); } Files::IStreamPtr Manager::get(std::string_view name) const @@ -104,13 +106,13 @@ namespace VFS std::filesystem::path Manager::getAbsoluteFileName(const std::filesystem::path &name) const { - std::string normalized(name); //TODO(Project579): This will probably break in windows with unicode paths - normalize_path(normalized, mStrict); //TODO(Project579): This will probably break in windows with unicode paths + std::string normalized = Files::pathToUnicodeString(name); + normalize_path(normalized, mStrict); const auto found = mIndex.find(normalized); if (found == mIndex.end()) throw std::runtime_error("Resource '" + normalized + "' not found"); - return found->second->getPath();//TODO(Project579): This will probably break in windows with unicode paths + return found->second->getPath(); } namespace diff --git a/components/vfs/registerarchives.cpp b/components/vfs/registerarchives.cpp index dd8287818e..b496958381 100644 --- a/components/vfs/registerarchives.cpp +++ b/components/vfs/registerarchives.cpp @@ -23,7 +23,7 @@ namespace VFS { // Last BSA has the highest priority const auto archivePath = collections.getPath(*archive); - Log(Debug::Info) << "Adding BSA archive " << archivePath; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Adding BSA archive " << archivePath; Bsa::BsaVersion bsaVersion = Bsa::CompressedBSAFile::detectVersion(archivePath); if (bsaVersion == Bsa::BSAVER_COMPRESSED) @@ -49,7 +49,7 @@ namespace VFS vfs->addArchive(std::make_unique(dataDir)); } else - Log(Debug::Info) << "Ignoring duplicate data directory " << dataDir; //TODO(Project579): This will probably break in windows with unicode paths + Log(Debug::Info) << "Ignoring duplicate data directory " << dataDir; } } From 928b131564f890281d961ad19b62319f096dd9ac Mon Sep 17 00:00:00 2001 From: Project579 Date: Tue, 12 Jul 2022 20:47:15 +0200 Subject: [PATCH 22/36] Implement std::filesystem::path conversion tests. --- apps/openmw_test_suite/CMakeLists.txt | 1 + .../files/conversion_tests.cpp | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 apps/openmw_test_suite/files/conversion_tests.cpp diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 113a0b61ec..106837a67d 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -75,6 +75,7 @@ file(GLOB UNITTEST_SRC_FILES esmloader/record.cpp files/hash.cpp + files/conversion_tests.cpp toutf8/toutf8.cpp diff --git a/apps/openmw_test_suite/files/conversion_tests.cpp b/apps/openmw_test_suite/files/conversion_tests.cpp new file mode 100644 index 0000000000..ec0ec9fb23 --- /dev/null +++ b/apps/openmw_test_suite/files/conversion_tests.cpp @@ -0,0 +1,27 @@ +#include +#include + +#include + +#include + +namespace +{ + using namespace testing; + using namespace Files; + + constexpr auto test_path_u8 = u8"./tmp/ÒĎƎɠˠΏЌԹעڨ/ऊঋਐઊଊ/ஐఋಋഊ/ฎນ༈ႩᄇḮὯ⁂₁₩ℒ/Ⅷ↝∑/☝✌〥ぐズ㌎丕.갔3갛"; + constexpr auto test_path = "./tmp/ÒĎƎɠˠΏЌԹעڨ/ऊঋਐઊଊ/ஐఋಋഊ/ฎນ༈ႩᄇḮὯ⁂₁₩ℒ/Ⅷ↝∑/☝✌〥ぐズ㌎丕.갔3갛"; + + TEST(OpenMWConversion, should_support_unicode_string_to_path) + { + auto p = Files::pathFromUnicodeString(test_path); + EXPECT_EQ(Misc::StringUtils::u8StringToString(p.u8string()), Misc::StringUtils::u8StringToString(test_path_u8)); + } + + TEST(OpenMWConversion, should_support_path_to_unicode_string) + { + std::filesystem::path p{ test_path_u8 }; + EXPECT_EQ(Files::pathToUnicodeString(p), test_path); + } +} From c3175e371a79e1ffda2ddf22780d15c97f7e6bad Mon Sep 17 00:00:00 2001 From: Project579 Date: Thu, 28 Jul 2022 20:15:24 +0200 Subject: [PATCH 23/36] Fix YAML::LoadFile mangling Unicode paths in Windows. --- components/settings/shadermanager.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/settings/shadermanager.hpp b/components/settings/shadermanager.hpp index 6aa14e73ef..9cfca7d945 100644 --- a/components/settings/shadermanager.hpp +++ b/components/settings/shadermanager.hpp @@ -124,7 +124,8 @@ namespace Settings try { - mData = YAML::LoadFile(Files::pathToUnicodeString(mPath)); + std::ifstream file{mPath}; + mData = YAML::Load(file); mData.SetStyle(YAML::EmitterStyle::Block); if (!mData["config"]) From 2df8bfed2559c1cab52ea108496cea12a6ff9e24 Mon Sep 17 00:00:00 2001 From: Project579 Date: Thu, 28 Jul 2022 22:20:44 +0200 Subject: [PATCH 24/36] Fix build errors after rebase against master due to large amount of changes. --- components/bsa/bsa_file.cpp | 2 +- components/files/constrainedfilestreambuf.cpp | 2 +- components/files/constrainedfilestreambuf.hpp | 5 +++-- components/myguiplatform/myguidatamanager.cpp | 11 ++++++----- components/myguiplatform/myguiplatform.cpp | 4 +++- components/nif/niffile.cpp | 3 ++- components/nif/niffile.hpp | 1 + components/platform/file.hpp | 4 ++-- components/platform/file.posix.cpp | 8 +++++--- components/platform/file.stdio.cpp | 8 +++++--- components/platform/file.win32.cpp | 9 +++++---- components/vfs/archive.hpp | 1 + components/vfs/manager.hpp | 1 + 13 files changed, 36 insertions(+), 23 deletions(-) diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 76d8e9b092..4bd47a2c92 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -260,7 +260,7 @@ void Bsa::BSAFile::close() Files::IStreamPtr Bsa::BSAFile::getFile(const FileStruct *file) { - return Files::openConstrainedFileStream(mFilename, file->offset, file->fileSize); + return Files::openConstrainedFileStream(mFilepath, file->offset, file->fileSize); } void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file) diff --git a/components/files/constrainedfilestreambuf.cpp b/components/files/constrainedfilestreambuf.cpp index 24c0a9b4d8..7c568dfe84 100644 --- a/components/files/constrainedfilestreambuf.cpp +++ b/components/files/constrainedfilestreambuf.cpp @@ -11,7 +11,7 @@ namespace Files ConstrainedFileStreamBuf::ConstrainedFileStreamBuf(const std::filesystem::path& fname, std::size_t start, std::size_t length) : mOrigin(start) { - mFile = File::open(fname.c_str()); + mFile = File::open(fname); mSize = length != std::numeric_limits::max() ? length : File::size(mFile) - start; if (start != 0) diff --git a/components/files/constrainedfilestreambuf.hpp b/components/files/constrainedfilestreambuf.hpp index 7ee18f082a..c18dabab4a 100644 --- a/components/files/constrainedfilestreambuf.hpp +++ b/components/files/constrainedfilestreambuf.hpp @@ -1,9 +1,10 @@ #ifndef OPENMW_CONSTRAINEDFILESTREAMBUF_H #define OPENMW_CONSTRAINEDFILESTREAMBUF_H -#include - #include +#include + +#include namespace Files { diff --git a/components/myguiplatform/myguidatamanager.cpp b/components/myguiplatform/myguidatamanager.cpp index 5696cec58f..473076ff12 100644 --- a/components/myguiplatform/myguidatamanager.cpp +++ b/components/myguiplatform/myguidatamanager.cpp @@ -1,6 +1,5 @@ #include "myguidatamanager.hpp" -#include #include #include @@ -40,7 +39,7 @@ DataManager::DataManager(const std::string& resourcePath, const VFS::Manager* vf MyGUI::IDataStream *DataManager::getData(const std::string &name) const { - return new DataStream(mVfs->get(mResourcePath / name)); + return new DataStream(mVfs->get(Files::pathToUnicodeString(mResourcePath / name))); } void DataManager::freeData(MyGUI::IDataStream *data) @@ -50,7 +49,7 @@ void DataManager::freeData(MyGUI::IDataStream *data) bool DataManager::isDataExist(const std::string &name) const { - return mVfs->exists(mResourcePath / name); + return mVfs->exists(Files::pathToUnicodeString(mResourcePath / name)); } const MyGUI::VectorString &DataManager::getDataListNames(const std::string &pattern) const @@ -63,8 +62,10 @@ const std::string &DataManager::getDataPath(const std::string &name) const static std::string result; result.clear(); - if (name.empty()) - return mResourcePath; + if (name.empty()) { + result = Files::pathToUnicodeString(mResourcePath); + return result; + } if (!isDataExist(name)) return result; diff --git a/components/myguiplatform/myguiplatform.cpp b/components/myguiplatform/myguiplatform.cpp index 5425ddd31d..ef9faecfb7 100644 --- a/components/myguiplatform/myguiplatform.cpp +++ b/components/myguiplatform/myguiplatform.cpp @@ -4,6 +4,8 @@ #include "myguidatamanager.hpp" #include "myguiloglistener.hpp" +#include "components/files/conversion.hpp" + namespace osgMyGUI { @@ -11,7 +13,7 @@ Platform::Platform(osgViewer::Viewer *viewer, osg::Group* guiRoot, Resource::Ima const VFS::Manager* vfs, float uiScalingFactor, const std::filesystem::path& resourcePath, const std::filesystem::path& logName) : mLogFacility(logName.empty() ? nullptr : std::make_unique(logName, false)) , mLogManager(std::make_unique()) - , mDataManager(std::make_unique(resourcePath, vfs)) + , mDataManager(std::make_unique(Files::pathToUnicodeString(resourcePath), vfs)) , mRenderManager(std::make_unique(viewer, guiRoot, imageManager, uiScalingFactor)) { if (mLogFacility != nullptr) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 8b525e8ae7..de6f8ec900 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -373,7 +374,7 @@ void NIFFile::warn(const std::string &msg) const [[noreturn]] void NIFFile::fail(const std::string &msg) const { - throw std::runtime_error(" NIFFile Error: " + msg + "\nFile: " + filename); + throw std::runtime_error(" NIFFile Error: " + msg + "\nFile: " + Files::pathToUnicodeString(filename)); } std::string NIFFile::getString(uint32_t index) const diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 5b14ad2e46..1789ab665b 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -5,6 +5,7 @@ #include #include +#include #include diff --git a/components/platform/file.hpp b/components/platform/file.hpp index 8faf9c67cb..0b1ffde027 100644 --- a/components/platform/file.hpp +++ b/components/platform/file.hpp @@ -2,7 +2,7 @@ #define OPENMW_COMPONENTS_PLATFORM_FILE_HPP #include -#include +#include namespace Platform::File { @@ -18,7 +18,7 @@ namespace Platform::File { End }; - Handle open(const char* filename); + Handle open(const std::filesystem::path& filename); void close(Handle handle); diff --git a/components/platform/file.posix.cpp b/components/platform/file.posix.cpp index f79562dcfd..0f859569ba 100644 --- a/components/platform/file.posix.cpp +++ b/components/platform/file.posix.cpp @@ -9,6 +9,8 @@ #include #include +#include + namespace Platform::File { static auto getNativeHandle(Handle handle) @@ -29,7 +31,7 @@ namespace Platform::File { return -1; } - Handle open(const char* filename) + Handle open(const std::filesystem::path& filename) { #ifdef O_BINARY static const int openFlags = O_RDONLY | O_BINARY; @@ -37,10 +39,10 @@ namespace Platform::File { static const int openFlags = O_RDONLY; #endif - auto handle = ::open(filename, openFlags, 0); + auto handle = ::open(filename.c_str(), openFlags, 0); if (handle == -1) { - throw std::runtime_error(std::string("Failed to open '") + filename + "' for reading: " + strerror(errno)); + throw std::runtime_error(std::string("Failed to open '") + Files::pathToUnicodeString(filename) + "' for reading: " + strerror(errno)); } return static_cast(handle); } diff --git a/components/platform/file.stdio.cpp b/components/platform/file.stdio.cpp index 558fea1154..b2287bfcf9 100644 --- a/components/platform/file.stdio.cpp +++ b/components/platform/file.stdio.cpp @@ -6,6 +6,8 @@ #include #include +#include + namespace Platform::File { static auto getNativeHandle(Handle handle) @@ -26,12 +28,12 @@ namespace Platform::File { return -1; } - Handle open(const char* filename) + Handle open(const std::filesystem::path& filename) { - FILE* handle = fopen(filename, "rb"); + FILE* handle = fopen(filename.c_str(), "rb"); if (handle == nullptr) { - throw std::runtime_error(std::string("Failed to open '") + filename + "' for reading: " + strerror(errno)); + throw std::runtime_error(std::string("Failed to open '") + Files::pathToUnicodeString(filename) + "' for reading: " + strerror(errno)); } return static_cast(reinterpret_cast(handle)); } diff --git a/components/platform/file.win32.cpp b/components/platform/file.win32.cpp index a2ba86a4ef..7f80061163 100644 --- a/components/platform/file.win32.cpp +++ b/components/platform/file.win32.cpp @@ -6,6 +6,8 @@ #include #include +#include + namespace Platform::File { static auto getNativeHandle(Handle handle) @@ -26,13 +28,12 @@ namespace Platform::File { return -1; } - Handle open(const char* filename) + Handle open(const std::filesystem::path& filename) { - std::wstring wname = boost::locale::conv::utf_to_utf(filename); - HANDLE handle = CreateFileW(wname.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + HANDLE handle = CreateFileW(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if (handle == INVALID_HANDLE_VALUE) { - throw std::runtime_error(std::string("Failed to open '") + filename + "' for reading: " + std::to_string(GetLastError())); + throw std::runtime_error(std::string("Failed to open '") + Files::pathToUnicodeString(filename) + "' for reading: " + std::to_string(GetLastError())); } return static_cast(reinterpret_cast(handle)); } diff --git a/components/vfs/archive.hpp b/components/vfs/archive.hpp index 26db7b8535..52706ae9fc 100644 --- a/components/vfs/archive.hpp +++ b/components/vfs/archive.hpp @@ -2,6 +2,7 @@ #define OPENMW_COMPONENTS_RESOURCE_ARCHIVE_H #include +#include #include diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index 8f8f6e450f..8ba6790928 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace VFS { From 4e428dee125109557976e5f4280fdd3d74ec7579 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 6 Aug 2022 18:09:50 +0200 Subject: [PATCH 25/36] Update some settings that accept paths by "std::string" to accept them as "std::filesystem::path" instead. --- apps/bsatool/bsatool.cpp | 4 ++-- apps/esmtool/esmtool.cpp | 4 ++-- apps/essimporter/main.cpp | 15 ++++++++------- apps/mwiniimporter/main.cpp | 16 +++++++++------- apps/niftest/niftest.cpp | 4 ++-- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 26fa981cb3..3af5e08ecb 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -57,7 +57,7 @@ bool parseOptions (int argc, char** argv, Arguments &info) hidden.add_options() ( "mode,m", bpo::value(), "bsatool mode") - ( "input-file,i", bpo::value< std::vector >(), "input file") + ( "input-file,i", bpo::value< Files::MaybeQuotedPathContainer >(), "input file") ; bpo::positional_options_description p; @@ -114,7 +114,7 @@ bool parseOptions (int argc, char** argv, Arguments &info) << desc << std::endl; return false; } - auto inputFiles = variables["input-file"].as< std::vector >(); + auto inputFiles = variables["input-file"].as< Files::MaybeQuotedPathContainer >(); info.filename = inputFiles[0].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 74e471b948..dab212c076 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -85,7 +85,7 @@ bool parseOptions (int argc, char** argv, Arguments &info) hidden.add_options() ( "mode,m", bpo::value(), "esmtool mode") - ( "input-file,i", bpo::value< std::vector >(), "input file") + ( "input-file,i", bpo::value< Files::MaybeQuotedPathContainer >(), "input file") ; bpo::positional_options_description p; @@ -156,7 +156,7 @@ bool parseOptions (int argc, char** argv, Arguments &info) return false; }*/ - const auto inputFiles = variables["input-file"].as< std::vector >(); + const auto inputFiles = variables["input-file"].as< Files::MaybeQuotedPathContainer >(); info.filename = inputFiles[0].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. if (inputFiles.size() > 1) info.outname = inputFiles[1].u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp index 9517df2d2a..56c3828c1c 100644 --- a/apps/essimporter/main.cpp +++ b/apps/essimporter/main.cpp @@ -18,8 +18,8 @@ int main(int argc, char** argv) bpo::positional_options_description p_desc; desc.add_options() ("help,h", "produce help message") - ("mwsave,m", bpo::value(), "morrowind .ess save file") - ("output,o", bpo::value(), "output file (.omwsave)") + ("mwsave,m", bpo::value(), "morrowind .ess save file") + ("output,o", bpo::value(), "output file (.omwsave)") ("compare,c", "compare two .ess files") ("encoding", boost::program_options::value()->default_value("win1252"), "encoding of the save file") ; @@ -45,8 +45,8 @@ int main(int argc, char** argv) Files::ConfigurationManager cfgManager(true); cfgManager.readConfiguration(variables, desc); - std::string essFile = variables["mwsave"].as(); - std::string outputFile = variables["output"].as(); + const auto essFile = variables["mwsave"].as(); + const auto outputFile = variables["output"].as(); std::string encoding = variables["encoding"].as(); ESSImport::Importer importer(essFile, outputFile, encoding); @@ -55,9 +55,10 @@ int main(int argc, char** argv) importer.compare(); else { - const std::string& ext = ".omwsave"; - if (std::filesystem::exists(std::filesystem::path(outputFile)) - && (outputFile.size() < ext.size() || outputFile.substr(outputFile.size()-ext.size()) != ext)) + static constexpr std::u8string_view ext{u8".omwsave"}; + const auto length = outputFile.native().size(); + if (std::filesystem::exists(outputFile) + && (length < ext.size() || outputFile.u8string().substr(length-ext.size()) != ext)) { throw std::runtime_error("Output file already exists and does not end in .omwsave. Did you mean to use --compare?"); } diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index 2de80ffb96..ed6ff907f4 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -6,6 +6,8 @@ #include +#include + namespace bpo = boost::program_options; namespace sfs = std::filesystem; @@ -61,9 +63,9 @@ int wmain(int argc, wchar_t *wargv[]) { desc.add_options() ("help,h", "produce help message") ("verbose,v", "verbose output") - ("ini,i", bpo::value(), "morrowind.ini file") - ("cfg,c", bpo::value(), "openmw.cfg file") - ("output,o", bpo::value()->default_value(""), "openmw.cfg file") + ("ini,i", bpo::value(), "morrowind.ini file") + ("cfg,c", bpo::value(), "openmw.cfg file") + ("output,o", bpo::value()->default_value({}), "openmw.cfg file") ("game-files,g", "import esm and esp files") ("fonts,f", "import bitmap fonts") ("no-archives,A", "disable bsa archives import") @@ -91,13 +93,13 @@ int wmain(int argc, wchar_t *wargv[]) { bpo::notify(vm); - std::filesystem::path iniFile(vm["ini"].as()); - std::filesystem::path cfgFile(vm["cfg"].as()); + std::filesystem::path iniFile(vm["ini"].as()); + std::filesystem::path cfgFile(vm["cfg"].as()); // if no output is given, write back to cfg file - std::string outputFile(vm["output"].as()); + std::string outputFile(vm["output"].as()); if(vm["output"].defaulted()) { - outputFile = vm["cfg"].as(); + outputFile = vm["cfg"].as(); } if(!std::filesystem::exists(iniFile)) { diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 4919b923c9..9328c4f2c6 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -77,7 +77,7 @@ bool parseOptions (int argc, char** argv, std::vector &f "Allowed options"); desc.add_options() ("help,h", "print help message.") - ("input-file", bpo::value< std::vector >(), "input file") + ("input-file", bpo::value< Files::MaybeQuotedPathContainer >(), "input file") ; //Default option if none provided @@ -98,7 +98,7 @@ bool parseOptions (int argc, char** argv, std::vector &f } if (variables.count("input-file")) { - files = variables["input-file"].as< std::vector >(); + files = variables["input-file"].as< Files::MaybeQuotedPathContainer >(); return true; } } From 14a786bab0f3b85fabf37645c6e997dbeb30b831 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 6 Aug 2022 18:31:27 +0200 Subject: [PATCH 26/36] iniimporter: Don't convert paths to "std::string". --- apps/mwiniimporter/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index ed6ff907f4..ffd663df6c 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -97,7 +97,7 @@ int wmain(int argc, wchar_t *wargv[]) { std::filesystem::path cfgFile(vm["cfg"].as()); // if no output is given, write back to cfg file - std::string outputFile(vm["output"].as()); + auto outputFile = vm["output"].as(); if(vm["output"].defaulted()) { outputFile = vm["cfg"].as(); } @@ -138,7 +138,7 @@ int wmain(int argc, wchar_t *wargv[]) { } std::cout << "write to: " << outputFile << std::endl; - std::ofstream file((sfs::path(outputFile))); + std::ofstream file(outputFile); importer.writeToFile(file, cfg); } catch (std::exception& e) From 199bf233e8b290fcdd7b8acbbe988aae31c785e0 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 6 Aug 2022 20:47:48 +0200 Subject: [PATCH 27/36] essimporter: Don't use "std::string" to store paths. --- apps/essimporter/importer.cpp | 4 ++-- apps/essimporter/importer.hpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index f0c74a7333..fbb333740b 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -85,7 +85,7 @@ namespace namespace ESSImport { - Importer::Importer(const std::string &essfile, const std::string &outfile, const std::string &encoding) + Importer::Importer(const std::filesystem::path &essfile, const std::filesystem::path &outfile, const std::string &encoding) : mEssFile(essfile) , mOutFile(outfile) , mEncoding(encoding) @@ -112,7 +112,7 @@ namespace ESSImport std::vector mRecords; }; - void read(const std::string& filename, File& file) + void read(const std::filesystem::path &filename, File& file) { ESM::ESMReader esm; esm.open(filename); diff --git a/apps/essimporter/importer.hpp b/apps/essimporter/importer.hpp index ccacd7972d..9d114fad27 100644 --- a/apps/essimporter/importer.hpp +++ b/apps/essimporter/importer.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_ESSIMPORTER_IMPORTER_H #define OPENMW_ESSIMPORTER_IMPORTER_H -#include +#include namespace ESSImport { @@ -9,15 +9,15 @@ namespace ESSImport class Importer { public: - Importer(const std::string& essfile, const std::string& outfile, const std::string& encoding); + Importer(const std::filesystem::path &essfile, const std::filesystem::path &outfile, const std::string& encoding); void run(); void compare(); private: - std::string mEssFile; - std::string mOutFile; + std::filesystem::path mEssFile; + std::filesystem::path mOutFile; std::string mEncoding; }; From 796911e67dc5b2e23c0cc047c01667668e7c3ba6 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sun, 14 Aug 2022 22:49:40 +0200 Subject: [PATCH 28/36] iniimporter: Work around some old MSVC compiler bugs. --- apps/mwiniimporter/main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index ffd663df6c..58b5a9e6c5 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -93,13 +93,13 @@ int wmain(int argc, wchar_t *wargv[]) { bpo::notify(vm); - std::filesystem::path iniFile(vm["ini"].as()); - std::filesystem::path cfgFile(vm["cfg"].as()); + std::filesystem::path iniFile(vm["ini"].as().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. + std::filesystem::path cfgFile(vm["cfg"].as().u8string()); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. // if no output is given, write back to cfg file - auto outputFile = vm["output"].as(); + std::filesystem::path outputFile = vm["output"].as().u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. if(vm["output"].defaulted()) { - outputFile = vm["cfg"].as(); + outputFile = vm["cfg"].as().u8string(); // This call to u8string is redundant, but required to build on MSVC 14.26 due to implementation bugs. } if(!std::filesystem::exists(iniFile)) { From 5456ef1d50aeff97e0c9027003892bfba3f3ff97 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sun, 11 Sep 2022 03:26:06 +0200 Subject: [PATCH 29/36] Add new functions and overloads to support std::u8string and std::filesystem::path. --- apps/bsatool/bsatool.cpp | 1 + apps/openmw/mwinput/controllermanager.cpp | 1 - .../files/conversion_tests.cpp | 4 +- apps/openmw_test_suite/testing_util.hpp | 2 +- .../crashcatcher/windows_crashcatcher.cpp | 2 +- components/debug/debuglog.cpp | 2 +- components/files/configurationmanager.cpp | 1 + components/files/conversion.cpp | 2 +- components/misc/strings/algorithm.hpp | 23 +++++++++ components/misc/strings/conversion.hpp | 49 +++++++++++++++++++ components/misc/strings/lower.hpp | 17 ++++++- 11 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 components/misc/strings/conversion.hpp diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 3af5e08ecb..0f6a7d35e7 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #define BSATOOL_VERSION 1.1 diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index 96d14a3720..d6ed81cd15 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw_test_suite/files/conversion_tests.cpp b/apps/openmw_test_suite/files/conversion_tests.cpp index ec0ec9fb23..6c9d801b9c 100644 --- a/apps/openmw_test_suite/files/conversion_tests.cpp +++ b/apps/openmw_test_suite/files/conversion_tests.cpp @@ -1,10 +1,8 @@ #include -#include +#include #include -#include - namespace { using namespace testing; diff --git a/apps/openmw_test_suite/testing_util.hpp b/apps/openmw_test_suite/testing_util.hpp index ce364d6db6..767f775c6b 100644 --- a/apps/openmw_test_suite/testing_util.hpp +++ b/apps/openmw_test_suite/testing_util.hpp @@ -6,7 +6,7 @@ #include #include -#include +#include namespace TestingOpenMW { diff --git a/components/crashcatcher/windows_crashcatcher.cpp b/components/crashcatcher/windows_crashcatcher.cpp index 47f1ba6c2c..46a09f43f6 100644 --- a/components/crashcatcher/windows_crashcatcher.cpp +++ b/components/crashcatcher/windows_crashcatcher.cpp @@ -9,7 +9,7 @@ #include "windows_crashshm.hpp" #include -#include +#include namespace Crash { diff --git a/components/debug/debuglog.cpp b/components/debug/debuglog.cpp index bb0c4b57e8..bb67847f6e 100644 --- a/components/debug/debuglog.cpp +++ b/components/debug/debuglog.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Debug { diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 8f4bc12c6b..fdd955207f 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include diff --git a/components/files/conversion.cpp b/components/files/conversion.cpp index ab32158ff9..fa9f2a5fb3 100644 --- a/components/files/conversion.cpp +++ b/components/files/conversion.cpp @@ -1,7 +1,7 @@ #include "conversion.hpp" -#include +#include std::string Files::pathToUnicodeString(const std::filesystem::path& path) { diff --git a/components/misc/strings/algorithm.hpp b/components/misc/strings/algorithm.hpp index 3fcaf12709..04fe81b195 100644 --- a/components/misc/strings/algorithm.hpp +++ b/components/misc/strings/algorithm.hpp @@ -27,6 +27,13 @@ namespace Misc::StringUtils return std::equal(std::begin(x), std::end(x), std::begin(y), [] (char l, char r) { return toLower(l) == toLower(r); }); } + inline bool ciEqual(std::u8string_view x, std::u8string_view y) + { + if (std::size(x) != std::size(y)) + return false; + return std::equal(std::begin(x), std::end(x), std::begin(y), + [](char l, char r) { return toLower(l) == toLower(r); }); + } inline bool ciStartsWith(std::string_view value, std::string_view prefix) { @@ -114,12 +121,28 @@ namespace Misc::StringUtils } return str; } + inline std::u8string& replaceAll(std::u8string& str, std::u8string_view what, std::u8string_view with) + { + std::size_t found; + std::size_t offset = 0; + while ((found = str.find(what, offset)) != std::u8string::npos) + { + str.replace(found, what.size(), with); + offset = found + with.size(); + } + return str; + } inline bool ciEndsWith(std::string_view s, std::string_view suffix) { return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin(), [](char l, char r) { return toLower(l) == toLower(r); }); } + inline bool ciEndsWith(std::u8string_view s, std::u8string_view suffix) + { + return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin(), + [](char l, char r) { return toLower(l) == toLower(r); }); + } inline void trim(std::string& s) { diff --git a/components/misc/strings/conversion.hpp b/components/misc/strings/conversion.hpp new file mode 100644 index 0000000000..b1d88e69d9 --- /dev/null +++ b/components/misc/strings/conversion.hpp @@ -0,0 +1,49 @@ +#ifndef COMPONENTS_MISC_STRINGS_CONVERSION_H +#define COMPONENTS_MISC_STRINGS_CONVERSION_H + +#include + +namespace Misc::StringUtils +{ + inline const char* u8StringToString(const char8_t* str) + { + return reinterpret_cast(str); + } + + inline char* u8StringToString(char8_t* str) + { + return reinterpret_cast(str); + } + + inline std::string u8StringToString(std::u8string_view str) + { + return {str.begin(), str.end()}; + } + + inline std::string u8StringToString(std::u8string&& str) + { + return {str.begin(), str.end()}; + } + + inline const char8_t* stringToU8String(const char* str) + { + return reinterpret_cast(str); // Undefined behavior if the contents of "char" aren't UTF8 or ASCII. + } + + inline char8_t* stringToU8String(char* str) + { + return reinterpret_cast(str); // Undefined behavior if the contents of "char" aren't UTF8 or ASCII. + } + + inline std::u8string stringToU8String(std::string_view str) + { + return { str.begin(), str.end() }; // Undefined behavior if the contents of "char" aren't UTF8 or ASCII. + } + + inline std::u8string stringToU8String(std::string&& str) + { + return { str.begin(), str.end() }; // Undefined behavior if the contents of "char" aren't UTF8 or ASCII. + } +} + +#endif //COMPONENTS_MISC_STRINGS_CONVERSION_H \ No newline at end of file diff --git a/components/misc/strings/lower.hpp b/components/misc/strings/lower.hpp index 8486af7c6d..d17ca6aa00 100644 --- a/components/misc/strings/lower.hpp +++ b/components/misc/strings/lower.hpp @@ -32,11 +32,20 @@ namespace Misc::StringUtils { return tolowermap[static_cast(c)]; } + inline constexpr char8_t toLower(char8_t c) + { + return tolowermap[static_cast(c)]; + } /// Transforms input string to lower case w/o copy inline void lowerCaseInPlace(std::string& str) { - for (char& ch : str) + for (auto& ch : str) + ch = toLower(ch); + } + inline void lowerCaseInPlace(std::u8string& str) + { + for (auto& ch : str) ch = toLower(ch); } @@ -47,6 +56,12 @@ namespace Misc::StringUtils lowerCaseInPlace(out); return out; } + inline std::u8string lowerCase(std::u8string_view in) + { + std::u8string out(in); + lowerCaseInPlace(out); + return out; + } } #endif From 1fc197e4048f663e5cb71e67627f8bafebb31df7 Mon Sep 17 00:00:00 2001 From: Project579 Date: Fri, 19 Aug 2022 15:55:02 +0200 Subject: [PATCH 30/36] Check std::getenv output before using it to construct a std::filesystem::path. --- apps/openmw/engine.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 163fb31ccd..c8ea05e15e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1031,12 +1031,18 @@ void OMW::Engine::go() prepareEngine(); - std::ofstream stats; #ifdef _WIN32 - if (const auto path = std::filesystem::path{_wgetenv(L"OPENMW_OSG_STATS_FILE")}; !path.empty()) + const auto* stats_file = _wgetenv(L"OPENMW_OSG_STATS_FILE"); #else - if (const auto path = std::filesystem::path{std::getenv("OPENMW_OSG_STATS_FILE")}; !path.empty()) + const auto* stats_file = std::getenv("OPENMW_OSG_STATS_FILE"); #endif + + std::filesystem::path path; + if (stats_file != nullptr) + path = stats_file; + + std::ofstream stats; + if (!path.empty()) { stats.open(path, std::ios_base::out); if (stats.is_open()) From c226b35f1f409615078c4f72bf8b86b262190774 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 20 Aug 2022 00:26:23 +0200 Subject: [PATCH 31/36] Fix some remaining encoding errors due to std::filesystem transition. --- apps/bsatool/bsatool.cpp | 4 ++-- apps/esmtool/esmtool.cpp | 2 +- apps/essimporter/importer.cpp | 2 +- apps/launcher/datafilespage.cpp | 4 ++-- apps/launcher/maindialog.cpp | 16 ++++++++-------- apps/launcher/settingspage.cpp | 4 ++-- apps/mwiniimporter/importer.cpp | 6 +++--- apps/mwiniimporter/main.cpp | 3 ++- apps/opencs/editor.cpp | 17 +++++++---------- apps/opencs/model/doc/runner.cpp | 6 +++--- apps/opencs/model/prefs/state.cpp | 3 +-- apps/opencs/view/doc/adjusterwidget.cpp | 6 +++--- apps/opencs/view/doc/loader.cpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 2 +- apps/opencs/view/tools/merge.cpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 2 +- apps/wizard/mainwizard.cpp | 2 +- components/config/gamesettings.cpp | 16 ++++++++-------- components/config/launchersettings.cpp | 2 +- components/files/configurationmanager.cpp | 4 ++-- components/settings/parser.cpp | 3 ++- components/shader/shadermanager.cpp | 5 +++-- 22 files changed, 56 insertions(+), 57 deletions(-) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 0f6a7d35e7..b250cf9862 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -244,7 +244,7 @@ int extractAll(std::unique_ptr& bsa, Arguments& info) // Get the target path (the path the file will be extracted to) auto target = info.outdir; - target /= extractPath; + target /= Misc::StringUtils::stringToU8String(extractPath); // Create the directory hierarchy std::filesystem::create_directories(target.parent_path()); @@ -261,7 +261,7 @@ int extractAll(std::unique_ptr& bsa, Arguments& info) std::ofstream out(target, std::ios::binary); // Write the file to disk - std::cout << "Extracting " << target << std::endl; + std::cout << "Extracting " << Files::pathToUnicodeString(target) << std::endl; out << data->rdbuf(); out.close(); } diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index dab212c076..2e274bfe74 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -289,7 +289,7 @@ void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMDa void printRawTes3(const std::filesystem::path &path) { - std::cout << "TES3 RAW file listing: " << path << '\n'; + std::cout << "TES3 RAW file listing: " << Files::pathToUnicodeString(path) << '\n'; ESM::ESMReader esm; esm.openRaw(path); while(esm.hasMoreRecs()) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index fbb333740b..5bc8079bd1 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -345,7 +345,7 @@ namespace ESSImport writer.setFormat (ESM::SavedGame::sCurrentFormat); - std::ofstream stream(std::filesystem::path(mOutFile), std::ios::out | std::ios::binary); + std::ofstream stream(mOutFile, std::ios::out | std::ios::binary); // all unused writer.setVersion(0); writer.setType(0); diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 3495d04502..7d00c05bba 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -232,7 +232,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) const auto& globalDataDir = mGameSettings.getGlobalDataDir(); if (!globalDataDir.empty()) - directories.insert(0, QString::fromStdWString(globalDataDir.wstring())); + directories.insert(0, QString::fromStdU32String(globalDataDir.u32string())); // normalize user supplied directories: resolve symlink, convert to native separator, make absolute for (auto& currentDir : directories) @@ -264,7 +264,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) } // deactivate data-local and global data directory: they are always included - if (currentDir == mDataLocal || std::filesystem::path(currentDir.toStdWString()) == globalDataDir) + if (currentDir == mDataLocal || std::filesystem::path(currentDir.toStdU32String()) == globalDataDir) { auto flags = item->flags(); item->setFlags(flags & ~(Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled|Qt::ItemIsEnabled)); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 7b5fbe5c4c..830a80d01d 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -163,7 +163,7 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() cfgError(tr("Error opening OpenMW configuration file"), tr("
Could not create directory %0

\ Please make sure you have the right permissions \ - and try again.
").arg(QString::fromStdWString(canonical(userConfigDir).wstring())) + and try again.
").arg(QString::fromStdU32String(canonical(userConfigDir).u32string())) ); return FirstRunDialogResultFailure; } @@ -296,7 +296,7 @@ bool Launcher::MainDialog::setupLauncherSettings() mLauncherSettings.setMultiValueEnabled(true); - QString userPath = QString::fromStdWString(mCfgMgr.getUserConfigPath().wstring()); + QString userPath = QString::fromStdU32String(mCfgMgr.getUserConfigPath().u32string()); QStringList paths; paths.append(QString(Config::LauncherSettings::sLauncherConfigFileName)); @@ -329,9 +329,9 @@ bool Launcher::MainDialog::setupGameSettings() { mGameSettings.clear(); - QString localPath = QString::fromStdWString(mCfgMgr.getLocalPath().wstring()); - QString userPath = QString::fromStdWString(mCfgMgr.getUserConfigPath().wstring()); - QString globalPath = QString::fromStdWString(mCfgMgr.getGlobalPath().wstring()); + QString localPath = QString::fromStdU32String(mCfgMgr.getLocalPath().u32string()); + QString userPath = QString::fromStdU32String(mCfgMgr.getUserConfigPath().u32string()); + QString globalPath = QString::fromStdU32String(mCfgMgr.getGlobalPath().u32string()); QFile file; @@ -487,13 +487,13 @@ bool Launcher::MainDialog::writeSettings() cfgError(tr("Error creating OpenMW configuration directory"), tr("
Could not create %0

\ Please make sure you have the right permissions \ - and try again.
").arg(QString::fromStdWString(userPath.wstring()))); + and try again.
").arg(QString::fromStdU32String(userPath.u32string()))); return false; } } // Game settings - QFile file(QString::fromStdWString((userPath / "openmw.cfg").wstring())); + QFile file(QString::fromStdU32String((userPath / "openmw.cfg").u32string())); if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { // File cannot be opened or created @@ -521,7 +521,7 @@ bool Launcher::MainDialog::writeSettings() } // Launcher settings - file.setFileName(QString::fromStdWString((userPath / Config::LauncherSettings::sLauncherConfigFileName).wstring())); + file.setFileName(QString::fromStdU32String((userPath / Config::LauncherSettings::sLauncherConfigFileName).u32string())); if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 1a9670a292..325fa4dfa1 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -104,7 +104,7 @@ void Launcher::SettingsPage::on_importerButton_clicked() // Create the file if it doesn't already exist, else the importer will fail auto path = mCfgMgr.getUserConfigPath(); path /= "openmw.cfg"; - QFile file(QString::fromStdWString(path.wstring())); + QFile file(QString::fromStdU32String(path.u32string())); if (!file.exists()) { if (!file.open(QIODevice::ReadWrite)) { @@ -137,7 +137,7 @@ void Launcher::SettingsPage::on_importerButton_clicked() arguments.append(QString("--ini")); arguments.append(settingsComboBox->currentText()); arguments.append(QString("--cfg")); - arguments.append(QString::fromStdWString(path.wstring())); + arguments.append(QString::fromStdU32String(path.u32string())); qDebug() << "arguments " << arguments; diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index ed962c4c5f..43f2b429b1 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -658,7 +658,7 @@ void MwIniImporter::setVerbose(bool verbose) { } MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::filesystem::path& filename) const { - std::cout << "load ini file: " << filename << std::endl; + std::cout << "load ini file: " << Files::pathToUnicodeString(filename) << std::endl; std::string section(""); MwIniImporter::multistrmap map; @@ -719,7 +719,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::filesystem::pat } MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::filesystem::path& filename) { - std::cout << "load cfg file: " << filename << std::endl; + std::cout << "load cfg file: " << Files::pathToUnicodeString(filename) << std::endl; MwIniImporter::multistrmap map; std::ifstream file(filename); @@ -872,7 +872,7 @@ void MwIniImporter::addPaths(std::vector& output, std::ve // Drop first and last characters - quotation marks path = path.substr(1, path.size() - 2); } - output.emplace_back(path); + output.emplace_back(Files::pathFromUnicodeString(path)); } } diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index 58b5a9e6c5..690afe64c8 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -7,6 +7,7 @@ #include #include +#include namespace bpo = boost::program_options; namespace sfs = std::filesystem; @@ -137,7 +138,7 @@ int wmain(int argc, wchar_t *wargv[]) { importer.importArchives(cfg, ini); } - std::cout << "write to: " << outputFile << std::endl; + std::cout << "write to: " << Files::pathToUnicodeString(outputFile) << std::endl; std::ofstream file(outputFile); importer.writeToFile(file, cfg); } diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 669fa83a4c..5f165a95a4 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -231,7 +231,7 @@ void CS::Editor::openFiles (const std::filesystem::path &savePath, const std::ve if(discoveredFiles.empty()) { for (const QString &path : mFileDialog.selectedFilePaths()) - files.emplace_back(path.toUtf8().constData()); + files.emplace_back(path.toStdU32String()); } else { @@ -248,7 +248,7 @@ void CS::Editor::createNewFile (const std::filesystem::path &savePath) std::vector files; for (const QString &path : mFileDialog.selectedFilePaths()) { - files.emplace_back(path.toUtf8().constData()); + files.emplace_back(path.toStdU32String()); } files.push_back (savePath); @@ -377,23 +377,20 @@ int CS::Editor::run() std::vector discoveredFiles; - for (std::vector::const_iterator itemIter = fileReader.getGameFiles().begin(); - itemIter != fileReader.getGameFiles().end(); ++itemIter) + for (const auto& item : fileReader.getGameFiles()) { - for (Files::PathContainer::const_iterator pathIter = mDataDirs.begin(); - pathIter != mDataDirs.end(); ++pathIter) + for (const auto& path : mDataDirs) { - const std::filesystem::path masterPath = *pathIter / itemIter->name; - if (std::filesystem::exists(masterPath)) + if (auto masterPath = path / item.name; std::filesystem::exists(masterPath)) { - discoveredFiles.push_back(masterPath); + discoveredFiles.emplace_back(std::move(masterPath)); break; } } } discoveredFiles.push_back(mFileToLoad); - QString extension = QString::fromStdWString(mFileToLoad.extension().wstring()).toLower(); + QString extension = QString::fromStdU32String(mFileToLoad.extension().u32string()).toLower(); if (extension == ".esm") { mFileToLoad.replace_extension(".omwgame"); diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index 2b16ea3eff..dd99ede234 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -83,17 +83,17 @@ void CSMDoc::Runner::start (bool delayed) arguments << ("--script-run="+mStartup->fileName()); arguments << - QString::fromStdWString (L"--data=\""+mProjectPath.parent_path().wstring()+L"\""); + QString::fromStdU32String (U"--data=\""+mProjectPath.parent_path().u32string()+U"\""); arguments << "--replace=content"; for (const auto & mContentFile : mContentFiles) { - arguments << QString::fromStdWString (L"--content="+mContentFile.wstring()); + arguments << QString::fromStdU32String (U"--content="+mContentFile.u32string()); } arguments - << QString::fromStdWString (L"--content="+mProjectPath.filename().wstring()); + << QString::fromStdU32String (U"--content="+mProjectPath.filename().u32string()); mProcess.start (path, arguments); } diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index ae2c94b11a..e5a1ef71a5 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -648,8 +648,7 @@ CSMPrefs::State::~State() void CSMPrefs::State::save() { - std::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile; - Settings::Manager::saveUser (user); + Settings::Manager::saveUser (mConfigurationManager.getUserConfigPath() / mConfigFile); } CSMPrefs::State::Iterator CSMPrefs::State::begin() diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 6eb479d694..791a1c556d 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -68,7 +68,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) } else { - std::filesystem::path path (name.toStdWString()); + std::filesystem::path path (name.toStdU32String()); const auto extension = Misc::StringUtils::lowerCase(path.extension().u8string()); @@ -85,7 +85,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) if (!isFilePathChanged && !isLegacyPath) { // path already points to the local data directory - message = QString::fromStdWString (L"Will be saved as: " + path.wstring()); + message = QString::fromStdU32String (U"Will be saved as: " + path.u32string()); mResultPath = path; } //in all other cases, ensure the path points to data-local and do an existing file check @@ -95,7 +95,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) if (isFilePathChanged) path = mLocalData / path.filename(); - message = QString::fromStdWString (L"Will be saved as: " + path.wstring()); + message = QString::fromStdU32String (U"Will be saved as: " + path.u32string()); mResultPath = path; if (std::filesystem::exists (path)) diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index ffd1d66756..4e8eab0541 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -19,7 +19,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event) CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document) : mDocument (document), mTotalRecordsLabel (0), mRecordsLabel (0), mAborted (false), mMessages (nullptr), mRecords(0) { - setWindowTitle (QString::fromStdWString(L"Opening " + document->getSavePath().filename().wstring())); + setWindowTitle (QString::fromStdU32String(U"Opening " + document->getSavePath().filename().u32string())); setMinimumWidth (400); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 71e8987bb1..358bc05e8b 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -261,7 +261,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view) QMessageBox messageBox(view); CSMDoc::Document *document = view->getDocument(); - messageBox.setWindowTitle (QString::fromStdWString(document->getSavePath().filename().wstring())); + messageBox.setWindowTitle (QString::fromStdU32String(document->getSavePath().filename().u32string())); messageBox.setText ("The document has been modified."); messageBox.setInformativeText ("Do you want to save your changes?"); messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index 6c4d076849..8e78364cea 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -102,7 +102,7 @@ void CSVTools::Merge::configure (CSMDoc::Document *document) for (std::vector::const_iterator iter (files.begin()); iter!=files.end(); ++iter) - mFiles->addItem (QString::fromStdWString(iter->filename().wstring())); + mFiles->addItem (QString::fromStdU32String(iter->filename().u32string())); } void CSVTools::Merge::setLocalData (const std::filesystem::path& localData) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index ebf22b5c83..5149552ea9 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -440,7 +440,7 @@ namespace MWGui const std::vector& data = mCurrentSlot->mProfile.mScreenshot; if (!data.size()) { - Log(Debug::Warning) << "Selected save file '" << mCurrentSlot->mPath.filename().string() << "' has no savegame screenshot"; + Log(Debug::Warning) << "Selected save file '" << Files::pathToUnicodeString(mCurrentSlot->mPath.filename()) << "' has no savegame screenshot"; return; } diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index 759fe7edd7..aa25f1fd3e 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -471,5 +471,5 @@ bool Wizard::MainWizard::findFiles(const QString &name, const QString &path) QString Wizard::MainWizard::toQString(const std::filesystem::path& path) { - return QString::fromStdWString(path.wstring()); + return QString::fromStdU32String(path.u32string()); } diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index e99e31372a..36f0cdad08 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -23,8 +24,7 @@ void Config::GameSettings::validatePaths() for (const QString &path : paths) { - QByteArray bytes = path.toUtf8(); - dataDirs.push_back(Files::PathContainer::value_type(std::string(bytes.constData(), bytes.length()))); + dataDirs.emplace_back(path.toStdU32String()); } // Parse the data dirs to convert the tokenized paths @@ -32,7 +32,7 @@ void Config::GameSettings::validatePaths() mDataDirs.clear(); for (auto & dataDir : dataDirs) { - QString path = QString::fromStdWString(dataDir.wstring()); + QString path = QString::fromStdU32String(dataDir.u32string()); QDir dir(path); if (dir.exists()) @@ -51,13 +51,12 @@ void Config::GameSettings::validatePaths() return; dataDirs.clear(); - QByteArray bytes = local.toUtf8(); - dataDirs.push_back(Files::PathContainer::value_type(std::string(bytes.constData(), bytes.length()))); + dataDirs.emplace_back(local.toStdU32String()); mCfgMgr.processPaths(dataDirs, /*basePath=*/""); if (!dataDirs.empty()) { - QString path = QString::fromStdWString(dataDirs.front().wstring()); + QString path = QString::fromStdU32String(dataDirs.front().u32string()); QDir dir(path); if (dir.exists()) @@ -68,8 +67,9 @@ void Config::GameSettings::validatePaths() std::filesystem::path Config::GameSettings::getGlobalDataDir() const { // global data dir may not exists if OpenMW is not installed (ie if run from build directory) - if (std::filesystem::exists(mCfgMgr.getGlobalDataPath())) - return std::filesystem::canonical(mCfgMgr.getGlobalDataPath()); + const auto& path = mCfgMgr.getGlobalDataPath(); + if (std::filesystem::exists(path)) + return std::filesystem::canonical(path); return {}; } diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index 2932a211cf..b06203c2a2 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -119,7 +119,7 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) } // global and local data directories are not part of any profile - const auto globalDataDir = QString::fromStdWString(gameSettings.getGlobalDataDir().wstring()); + const auto globalDataDir = QString::fromStdU32String(gameSettings.getGlobalDataDir().u32string()); const auto dataLocal = gameSettings.getDataLocal(); dirs.removeAll(globalDataDir); dirs.removeAll(dataLocal); diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index fdd955207f..550bb3eb1c 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -99,7 +99,7 @@ void ConfigurationManager::readConfiguration(bpo::variables_map& variables, while (!extraConfigDirs.empty()) { - std::filesystem::path path = extraConfigDirs.top(); + auto path = extraConfigDirs.top(); extraConfigDirs.pop(); if (alreadyParsedPaths.count(path) > 0) { @@ -116,7 +116,7 @@ void ConfigurationManager::readConfiguration(bpo::variables_map& variables, Log(Debug::Info) << "Skipping previous configs except " << (mActiveConfigPaths.front() / "openmw.cfg") << " due to replace=config in " << (path / "openmw.cfg"); } - mActiveConfigPaths.push_back(path); + mActiveConfigPaths.emplace_back(std::move(path)); if (config) { addExtraConfigDirs(extraConfigDirs, *config); diff --git a/components/settings/parser.cpp b/components/settings/parser.cpp index 1c1eeccc90..3232855989 100644 --- a/components/settings/parser.cpp +++ b/components/settings/parser.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -324,6 +325,6 @@ bool Settings::SettingsFileParser::skipWhiteSpace(size_t& i, std::string& str) [[noreturn]] void Settings::SettingsFileParser::fail(const std::string& message) { std::stringstream error; - error << "Error on line " << mLine << " in " << mFile << ":\n" << message; + error << "Error on line " << mLine << " in " << Files::pathToUnicodeString(mFile) << ":\n" << message; throw std::runtime_error(error.str()); } diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 189881fe97..80652eb499 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace Shader { @@ -384,7 +385,7 @@ namespace Shader const std::set& shaderFiles = templateIncludedFiles[templateName]; for (const std::filesystem::path& file : shaderFiles) { - mShaderFiles[file.string()].insert(std::make_pair(templateName, defines)); + mShaderFiles[Files::pathToUnicodeString(file)].insert(std::make_pair(templateName, defines)); } } @@ -426,7 +427,7 @@ namespace Shader stream.open(path); if (stream.fail()) { - Log(Debug::Error) << "Failed to open " << path.string(); + Log(Debug::Error) << "Failed to open " << Files::pathToUnicodeString(path); } std::stringstream buffer; buffer << stream.rdbuf(); From ca14fc00dccadf31bb1de1b3547bf45cac200fb1 Mon Sep 17 00:00:00 2001 From: Project579 Date: Fri, 19 Aug 2022 22:33:51 +0000 Subject: [PATCH 32/36] Added dedicated functions for conversions between QString and std::filesystem::path. --- apps/launcher/datafilespage.cpp | 11 ++++--- apps/launcher/maindialog.cpp | 29 ++++++++++-------- apps/launcher/settingspage.cpp | 11 +++++-- apps/opencs/editor.cpp | 17 +++++++---- apps/opencs/model/doc/runner.cpp | 16 +++++----- apps/opencs/view/doc/adjusterwidget.cpp | 12 ++++---- apps/opencs/view/doc/loader.cpp | 13 ++++---- apps/opencs/view/doc/viewmanager.cpp | 6 ++-- apps/opencs/view/tools/merge.cpp | 15 ++++++---- apps/wizard/mainwizard.cpp | 40 ++++++++++++------------- apps/wizard/mainwizard.hpp | 3 -- components/CMakeLists.txt | 4 +++ components/config/gamesettings.cpp | 25 +++++++--------- components/config/launchersettings.cpp | 4 ++- components/files/qtconversion.cpp | 28 +++++++++++++++++ components/files/qtconversion.hpp | 18 +++++++++++ 16 files changed, 164 insertions(+), 88 deletions(-) create mode 100644 components/files/qtconversion.cpp create mode 100644 components/files/qtconversion.hpp diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 7d00c05bba..e7b03164b6 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -19,13 +19,15 @@ #include #include -#include #include +#include +#include #include +#include #include -#include "utils/textinputdialog.hpp" #include "utils/profilescombobox.hpp" +#include "utils/textinputdialog.hpp" #include "ui_directorypicker.h" @@ -232,7 +234,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) const auto& globalDataDir = mGameSettings.getGlobalDataDir(); if (!globalDataDir.empty()) - directories.insert(0, QString::fromStdU32String(globalDataDir.u32string())); + directories.insert(0, Files::pathToQString(globalDataDir)); // normalize user supplied directories: resolve symlink, convert to native separator, make absolute for (auto& currentDir : directories) @@ -264,7 +266,8 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) } // deactivate data-local and global data directory: they are always included - if (currentDir == mDataLocal || std::filesystem::path(currentDir.toStdU32String()) == globalDataDir) + const auto tmp = currentDir.toUtf8(); + if (currentDir == mDataLocal || std::filesystem::path(Misc::StringUtils::stringToU8String(tmp)) == globalDataDir) { auto flags = item->flags(); item->setFlags(flags & ~(Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled|Qt::ItemIsEnabled)); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 830a80d01d..a8e7a89b54 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -13,12 +13,13 @@ #include #include #include +#include -#include "playpage.hpp" -#include "graphicspage.hpp" -#include "datafilespage.hpp" -#include "settingspage.hpp" #include "advancedpage.hpp" +#include "datafilespage.hpp" +#include "graphicspage.hpp" +#include "playpage.hpp" +#include "settingspage.hpp" using namespace Process; @@ -163,7 +164,7 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() cfgError(tr("Error opening OpenMW configuration file"), tr("
Could not create directory %0

\ Please make sure you have the right permissions \ - and try again.
").arg(QString::fromStdU32String(canonical(userConfigDir).u32string())) + and try again.
").arg(Files::pathToQString(canonical(userConfigDir))) ); return FirstRunDialogResultFailure; } @@ -296,7 +297,7 @@ bool Launcher::MainDialog::setupLauncherSettings() mLauncherSettings.setMultiValueEnabled(true); - QString userPath = QString::fromStdU32String(mCfgMgr.getUserConfigPath().u32string()); + const auto userPath = Files::pathToQString(mCfgMgr.getUserConfigPath()); QStringList paths; paths.append(QString(Config::LauncherSettings::sLauncherConfigFileName)); @@ -329,9 +330,9 @@ bool Launcher::MainDialog::setupGameSettings() { mGameSettings.clear(); - QString localPath = QString::fromStdU32String(mCfgMgr.getLocalPath().u32string()); - QString userPath = QString::fromStdU32String(mCfgMgr.getUserConfigPath().u32string()); - QString globalPath = QString::fromStdU32String(mCfgMgr.getGlobalPath().u32string()); + const auto localPath = Files::pathToQString(mCfgMgr.getLocalPath()); + const auto userPath = Files::pathToQString(mCfgMgr.getUserConfigPath()); + const auto globalPath = Files::pathToQString(mCfgMgr.getGlobalPath()); QFile file; @@ -487,13 +488,17 @@ bool Launcher::MainDialog::writeSettings() cfgError(tr("Error creating OpenMW configuration directory"), tr("
Could not create %0

\ Please make sure you have the right permissions \ - and try again.
").arg(QString::fromStdU32String(userPath.u32string()))); + and try again.
").arg(Files::pathToQString(userPath))); return false; } } // Game settings - QFile file(QString::fromStdU32String((userPath / "openmw.cfg").u32string())); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QFile file(userPath / "openmw.cfg"); +#else + QFile file(Files::pathToQString(userPath / "openmw.cfg")); +#endif if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { // File cannot be opened or created @@ -521,7 +526,7 @@ bool Launcher::MainDialog::writeSettings() } // Launcher settings - file.setFileName(QString::fromStdU32String((userPath / Config::LauncherSettings::sLauncherConfigFileName).u32string())); + file.setFileName(Files::pathToQString(userPath / Config::LauncherSettings::sLauncherConfigFileName)); if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index 325fa4dfa1..474b1a1c72 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -5,6 +5,9 @@ #include #include +#include +#include + #include "utils/textinputdialog.hpp" #include "datafilespage.hpp" @@ -104,7 +107,11 @@ void Launcher::SettingsPage::on_importerButton_clicked() // Create the file if it doesn't already exist, else the importer will fail auto path = mCfgMgr.getUserConfigPath(); path /= "openmw.cfg"; - QFile file(QString::fromStdU32String(path.u32string())); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QFile file(path); +#else + QFile file(Files::pathToQString(path)); +#endif if (!file.exists()) { if (!file.open(QIODevice::ReadWrite)) { @@ -137,7 +144,7 @@ void Launcher::SettingsPage::on_importerButton_clicked() arguments.append(QString("--ini")); arguments.append(settingsComboBox->currentText()); arguments.append(QString("--cfg")); - arguments.append(QString::fromStdU32String(path.u32string())); + arguments.append(Files::pathToQString(path)); qDebug() << "arguments " << arguments; diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 5f165a95a4..24d328e0c5 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -10,7 +10,10 @@ #include #include #include +#include +#include #include +#include #include #include @@ -230,8 +233,9 @@ void CS::Editor::openFiles (const std::filesystem::path &savePath, const std::ve if(discoveredFiles.empty()) { - for (const QString &path : mFileDialog.selectedFilePaths()) - files.emplace_back(path.toStdU32String()); + for (const QString &path : mFileDialog.selectedFilePaths()) { + files.emplace_back(Files::pathFromQString(path)); + } } else { @@ -248,7 +252,7 @@ void CS::Editor::createNewFile (const std::filesystem::path &savePath) std::vector files; for (const QString &path : mFileDialog.selectedFilePaths()) { - files.emplace_back(path.toStdU32String()); + files.emplace_back(Files::pathFromQString(path)); } files.push_back (savePath); @@ -320,12 +324,13 @@ bool CS::Editor::makeIPCServer() mServer->close(); fullPath.remove(QRegExp("dummy$")); fullPath += mIpcServerName; - if(std::filesystem::exists(fullPath.toUtf8().constData())) + const auto path = Files::pathFromQString(fullPath); + if(exists(path)) { // TODO: compare pid of the current process with that in the file Log(Debug::Info) << "Detected unclean shutdown."; // delete the stale file - if(remove(fullPath.toUtf8().constData())) + if(remove(path)) Log(Debug::Error) << "Error: can not remove stale connection file."; } } @@ -390,7 +395,7 @@ int CS::Editor::run() } discoveredFiles.push_back(mFileToLoad); - QString extension = QString::fromStdU32String(mFileToLoad.extension().u32string()).toLower(); + const auto extension = Files::pathToQString(mFileToLoad.extension()).toLower(); if (extension == ".esm") { mFileToLoad.replace_extension(".omwgame"); diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index dd99ede234..435a32d920 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -7,6 +7,9 @@ #include #include +#include +#include + #include "operationholder.hpp" CSMDoc::Runner::Runner (std::filesystem::path projectPath) @@ -80,22 +83,21 @@ void CSMDoc::Runner::start (bool delayed) else arguments << "--new-game=1"; - arguments << ("--script-run="+mStartup->fileName()); + arguments << ("--script-run=" + mStartup->fileName()); - arguments << - QString::fromStdU32String (U"--data=\""+mProjectPath.parent_path().u32string()+U"\""); + arguments << "--data=\"" + Files::pathToQString(mProjectPath.parent_path()) + "\""; arguments << "--replace=content"; - for (const auto & mContentFile : mContentFiles) + for (const auto& mContentFile : mContentFiles) { - arguments << QString::fromStdU32String (U"--content="+mContentFile.u32string()); + arguments << "--content=" + Files::pathToQString(mContentFile); } arguments - << QString::fromStdU32String (U"--content="+mProjectPath.filename().u32string()); + << "--content=" + Files::pathToQString(mProjectPath.filename()); - mProcess.start (path, arguments); + mProcess.start(path, arguments); } mRunning = true; diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 791a1c556d..6dfd6b9d3e 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -1,12 +1,14 @@ #include "adjusterwidget.hpp" #include -#include - #include #include #include +#include +#include +#include + CSVDoc::AdjusterWidget::AdjusterWidget (QWidget *parent) : QWidget (parent), mValid (false), mAction (ContentAction_Undefined) { @@ -68,7 +70,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) } else { - std::filesystem::path path (name.toStdU32String()); + auto path = Files::pathFromQString(name); const auto extension = Misc::StringUtils::lowerCase(path.extension().u8string()); @@ -85,7 +87,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) if (!isFilePathChanged && !isLegacyPath) { // path already points to the local data directory - message = QString::fromStdU32String (U"Will be saved as: " + path.u32string()); + message = "Will be saved as: " + Files::pathToQString(path); mResultPath = path; } //in all other cases, ensure the path points to data-local and do an existing file check @@ -95,7 +97,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) if (isFilePathChanged) path = mLocalData / path.filename(); - message = QString::fromStdU32String (U"Will be saved as: " + path.u32string()); + message = "Will be saved as: " + Files::pathToQString(path); mResultPath = path; if (std::filesystem::exists (path)) diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index 4e8eab0541..dd37176d76 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -8,6 +8,9 @@ #include #include +#include +#include + #include "../../model/doc/document.hpp" void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event) @@ -19,7 +22,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event) CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document) : mDocument (document), mTotalRecordsLabel (0), mRecordsLabel (0), mAborted (false), mMessages (nullptr), mRecords(0) { - setWindowTitle (QString::fromStdU32String(U"Opening " + document->getSavePath().filename().u32string())); + setWindowTitle ("Opening " + Files::pathToQString(document->getSavePath().filename())); setMinimumWidth (400); @@ -89,16 +92,16 @@ void CSVDoc::LoadingDocument::nextStage (const std::string& name, int fileRecord mRecords = fileRecords; } -void CSVDoc::LoadingDocument::nextRecord (int records) +void CSVDoc::LoadingDocument::nextRecord(int records) { if (records <= mRecords) { - mTotalProgress->setValue (mTotalRecords+records); + mTotalProgress->setValue(mTotalRecords + records); mRecordProgress->setValue(records); - mRecordsLabel->setText(QString::fromStdString( - "Records: "+std::to_string(records)+" of "+std::to_string(mRecords))); + mRecordsLabel->setText( + "Records: " + QString::number(records) + " of " + QString::number(mRecords)); } } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 358bc05e8b..0c4c6a6d56 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -7,8 +7,10 @@ #include #include -#include "../../model/doc/documentmanager.hpp" +#include + #include "../../model/doc/document.hpp" +#include "../../model/doc/documentmanager.hpp" #include "../../model/doc/state.hpp" #include "../../model/world/columns.hpp" @@ -261,7 +263,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view) QMessageBox messageBox(view); CSMDoc::Document *document = view->getDocument(); - messageBox.setWindowTitle (QString::fromStdU32String(document->getSavePath().filename().u32string())); + messageBox.setWindowTitle (Files::pathToQString(document->getSavePath().filename())); messageBox.setText ("The document has been modified."); messageBox.setInformativeText ("Do you want to save your changes?"); messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); diff --git a/apps/opencs/view/tools/merge.cpp b/apps/opencs/view/tools/merge.cpp index 8e78364cea..35f4b6c1d0 100644 --- a/apps/opencs/view/tools/merge.cpp +++ b/apps/opencs/view/tools/merge.cpp @@ -1,13 +1,16 @@ #include "merge.hpp" -#include #include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include + +#include +#include #include "../../model/doc/document.hpp" #include "../../model/doc/documentmanager.hpp" @@ -102,7 +105,7 @@ void CSVTools::Merge::configure (CSMDoc::Document *document) for (std::vector::const_iterator iter (files.begin()); iter!=files.end(); ++iter) - mFiles->addItem (QString::fromStdU32String(iter->filename().u32string())); + mFiles->addItem (Files::pathToQString(iter->filename())); } void CSVTools::Merge::setLocalData (const std::filesystem::path& localData) diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index aa25f1fd3e..39d0c4a90a 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -1,19 +1,22 @@ #include "mainwizard.hpp" -#include #include +#include +#include #include #include -#include -#include "intropage.hpp" -#include "methodselectionpage.hpp" -#include "languageselectionpage.hpp" -#include "existinginstallationpage.hpp" -#include "installationtargetpage.hpp" +#include +#include + #include "componentselectionpage.hpp" -#include "importpage.hpp" #include "conclusionpage.hpp" +#include "existinginstallationpage.hpp" +#include "importpage.hpp" +#include "installationtargetpage.hpp" +#include "intropage.hpp" +#include "languageselectionpage.hpp" +#include "methodselectionpage.hpp" #ifdef OPENMW_USE_UNSHIELD #include "installationpage.hpp" @@ -67,7 +70,7 @@ Wizard::MainWizard::MainWizard(QWidget *parent) : if (!installationPath.empty()) { const std::filesystem::path& dataPath = installationPath / "Data Files"; - addInstallation(toQString(dataPath)); + addInstallation(Files::pathToQString(dataPath)); } } @@ -78,7 +81,7 @@ Wizard::MainWizard::~MainWizard() void Wizard::MainWizard::setupLog() { - QString logPath(toQString(mCfgMgr.getLogPath())); + QString logPath(Files::pathToQString(mCfgMgr.getLogPath())); logPath.append(QLatin1String("wizard.log")); QFile file(logPath); @@ -101,7 +104,7 @@ void Wizard::MainWizard::setupLog() void Wizard::MainWizard::addLogText(const QString &text) { - QString logPath(toQString(mCfgMgr.getLogPath())); + QString logPath(Files::pathToQString(mCfgMgr.getLogPath())); logPath.append(QLatin1String("wizard.log")); QFile file(logPath); @@ -131,8 +134,8 @@ void Wizard::MainWizard::addLogText(const QString &text) void Wizard::MainWizard::setupGameSettings() { - QString userPath(toQString(mCfgMgr.getUserConfigPath())); - QString globalPath(toQString(mCfgMgr.getGlobalPath())); + QString userPath(Files::pathToQString(mCfgMgr.getUserConfigPath())); + QString globalPath(Files::pathToQString(mCfgMgr.getGlobalPath())); QString message(tr("

Could not open %1 for reading

\

Please make sure you have the right permissions \ and try again.

")); @@ -196,7 +199,7 @@ void Wizard::MainWizard::setupGameSettings() void Wizard::MainWizard::setupLauncherSettings() { - QString path(toQString(mCfgMgr.getUserConfigPath())); + QString path(Files::pathToQString(mCfgMgr.getUserConfigPath())); path.append(QLatin1String(Config::LauncherSettings::sLauncherConfigFileName)); QString message(tr("

Could not open %1 for reading

\ @@ -246,7 +249,7 @@ void Wizard::MainWizard::runSettingsImporter() QString path(field(QLatin1String("installation.path")).toString()); - QString userPath(toQString(mCfgMgr.getUserConfigPath())); + QString userPath(Files::pathToQString(mCfgMgr.getUserConfigPath())); QFile file(userPath + QLatin1String("openmw.cfg")); // Construct the arguments to run the importer @@ -392,7 +395,7 @@ void Wizard::MainWizard::writeSettings() mGameSettings.removeDataDir(path); mGameSettings.addDataDir(path); - QString userPath(toQString(mCfgMgr.getUserConfigPath())); + QString userPath(Files::pathToQString(mCfgMgr.getUserConfigPath())); QDir dir(userPath); if (!dir.exists()) { @@ -468,8 +471,3 @@ bool Wizard::MainWizard::findFiles(const QString &name, const QString &path) return (dir.entryList().contains(name + QLatin1String(".esm"), Qt::CaseInsensitive) && dir.entryList().contains(name + QLatin1String(".bsa"), Qt::CaseInsensitive)); } - -QString Wizard::MainWizard::toQString(const std::filesystem::path& path) -{ - return QString::fromStdU32String(path.u32string()); -} diff --git a/apps/wizard/mainwizard.hpp b/apps/wizard/mainwizard.hpp index 1316aa2ec0..cae446862b 100644 --- a/apps/wizard/mainwizard.hpp +++ b/apps/wizard/mainwizard.hpp @@ -58,9 +58,6 @@ namespace Wizard void addLogText(const QString &text); private: - /// convert std::filesystem::path to QString - QString toQString(const std::filesystem::path& path); - void setupLog(); void setupGameSettings(); void setupLauncherSettings(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9ddfc4eb5b..e9f5fdf6e4 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -379,6 +379,10 @@ if (USE_QT) helpviewer ) + add_component_qt_dir (files + qtconversion + ) + QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) endif() diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 36f0cdad08..3f844e01b5 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -4,9 +4,11 @@ #include #include #include -#include #include +#include +#include +#include const char Config::GameSettings::sArchiveKey[] = "fallback-archive"; const char Config::GameSettings::sContentKey[] = "content"; @@ -24,19 +26,16 @@ void Config::GameSettings::validatePaths() for (const QString &path : paths) { - dataDirs.emplace_back(path.toStdU32String()); + dataDirs.emplace_back(Files::pathFromQString(path)); } // Parse the data dirs to convert the tokenized paths mCfgMgr.processPaths(dataDirs, /*basePath=*/""); mDataDirs.clear(); - for (auto & dataDir : dataDirs) { - QString path = QString::fromStdU32String(dataDir.u32string()); - - QDir dir(path); - if (dir.exists()) - mDataDirs.append(path); + for (const auto & dataDir : dataDirs) { + if (is_directory(dataDir)) + mDataDirs.append(Files::pathToQString(dataDir)); } // Do the same for data-local @@ -51,16 +50,14 @@ void Config::GameSettings::validatePaths() return; dataDirs.clear(); - dataDirs.emplace_back(local.toStdU32String()); + dataDirs.emplace_back(Files::pathFromQString(local)); mCfgMgr.processPaths(dataDirs, /*basePath=*/""); if (!dataDirs.empty()) { - QString path = QString::fromStdU32String(dataDirs.front().u32string()); - - QDir dir(path); - if (dir.exists()) - mDataLocal = path; + const auto& path = dataDirs.front(); + if (is_directory(path)) + mDataLocal = Files::pathToQString(path); } } diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index b06203c2a2..f2f1275666 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -8,6 +8,8 @@ #include #include +#include +#include const char Config::LauncherSettings::sCurrentContentListKey[] = "Profiles/currentprofile"; const char Config::LauncherSettings::sLauncherConfigFileName[] = "launcher.cfg"; @@ -119,7 +121,7 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) } // global and local data directories are not part of any profile - const auto globalDataDir = QString::fromStdU32String(gameSettings.getGlobalDataDir().u32string()); + const auto globalDataDir = Files::pathToQString(gameSettings.getGlobalDataDir()); const auto dataLocal = gameSettings.getDataLocal(); dirs.removeAll(globalDataDir); dirs.removeAll(dataLocal); diff --git a/components/files/qtconversion.cpp b/components/files/qtconversion.cpp new file mode 100644 index 0000000000..d56832cb78 --- /dev/null +++ b/components/files/qtconversion.cpp @@ -0,0 +1,28 @@ + +#include "qtconversion.hpp" + +#include + +QString Files::pathToQString(const std::filesystem::path& path) +{ + const auto tmp = path.u8string(); + return QString::fromUtf8(Misc::StringUtils::u8StringToString(tmp.data()), tmp.size()); +} + +QString Files::pathToQString(std::filesystem::path&& path) +{ + const auto tmp = path.u8string(); + return QString::fromUtf8(Misc::StringUtils::u8StringToString(tmp.data()), tmp.size()); +} + +std::filesystem::path Files::pathFromQString(QStringView path) +{ + const auto tmp = path.toUtf8(); + return std::filesystem::path{ Misc::StringUtils::stringToU8String(tmp) }; +} + +std::filesystem::path Files::pathFromQString(QString&& path) +{ + const auto tmp = path.toUtf8(); + return std::filesystem::path{ Misc::StringUtils::stringToU8String(tmp) }; +} diff --git a/components/files/qtconversion.hpp b/components/files/qtconversion.hpp new file mode 100644 index 0000000000..0a4598073e --- /dev/null +++ b/components/files/qtconversion.hpp @@ -0,0 +1,18 @@ +#ifndef COMPONENTS_FILES_QTCONVERSION_HPP +#define COMPONENTS_FILES_QTCONVERSION_HPP + +#include +#include + +namespace Files +{ + QString pathToQString(const std::filesystem::path& path); + + QString pathToQString(std::filesystem::path&& path); + + std::filesystem::path pathFromQString(QStringView path); + + std::filesystem::path pathFromQString(QString&& path); +} + +#endif // COMPONENTS_FILES_QTCONVERSION_HPP From 1a79f098fa4855a1c5ae57bf99822c5dcb74a740 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 10 Sep 2022 02:31:22 +0200 Subject: [PATCH 33/36] Use std::filesystem::create_directories instead of std::filesystem::create_directory to recursively generate directories from the provided path. --- apps/launcher/maindialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index a8e7a89b54..d0f3ebf0bc 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -159,7 +159,7 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() // Dialog wizard and setup will fail if the config directory does not already exist const auto& userConfigDir = mCfgMgr.getUserConfigPath(); if ( ! exists(userConfigDir) ) { - if ( ! create_directory(userConfigDir) ) + if ( ! create_directories(userConfigDir) ) { cfgError(tr("Error opening OpenMW configuration file"), tr("
Could not create directory %0

\ @@ -484,7 +484,7 @@ bool Launcher::MainDialog::writeSettings() const auto& userPath = mCfgMgr.getUserConfigPath(); if (!exists(userPath)) { - if (!create_directory(userPath)) { + if (!create_directories(userPath)) { cfgError(tr("Error creating OpenMW configuration directory"), tr("
Could not create %0

\ Please make sure you have the right permissions \ From a60cebd0f933ba5b2d8eff419ba340e9261bdc55 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 10 Sep 2022 12:11:56 +0200 Subject: [PATCH 34/36] Use std::u8string_view in debug logger overloads parameters. --- components/debug/debuglog.cpp | 2 +- components/debug/debuglog.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/debug/debuglog.cpp b/components/debug/debuglog.cpp index bb67847f6e..255b0d5fc9 100644 --- a/components/debug/debuglog.cpp +++ b/components/debug/debuglog.cpp @@ -63,7 +63,7 @@ Log& Log::operator<<(std::u8string&& rhs) return *this; } -Log& Log::operator<<(const std::u8string& rhs) +Log& Log::operator<<(const std::u8string_view rhs) { if (mShouldLog) std::cout << Misc::StringUtils::u8StringToString(rhs); diff --git a/components/debug/debuglog.hpp b/components/debug/debuglog.hpp index 526763d9f6..f57ae96d12 100644 --- a/components/debug/debuglog.hpp +++ b/components/debug/debuglog.hpp @@ -43,7 +43,7 @@ public: Log& operator<<(std::u8string&& rhs); - Log& operator<<(const std::u8string& rhs); + Log& operator<<(std::u8string_view rhs); Log& operator<<(const char8_t* rhs); From 9ceafe770d55499674fccbcdf111b194968a72e8 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 10 Sep 2022 19:38:29 +0200 Subject: [PATCH 35/36] Hard fail on loading BSA with records using unicode paths. --- apps/openmw/mwstate/character.cpp | 2 +- components/bsa/bsa_file.cpp | 2 +- components/bsa/bsa_file.hpp | 2 +- components/bsa/compressedbsafile.cpp | 23 +++++++++++++++-------- components/bsa/compressedbsafile.hpp | 2 +- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index 136adfec89..8e21325c47 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -83,7 +83,7 @@ void MWState::Character::addSlot (const ESM::SavedGame& profile) } MWState::Character::Character (std::filesystem::path saves, const std::string& game) - : mPath (std::move(saves)) +: mPath (std::move(saves)) { if (!std::filesystem::is_directory (mPath)) { diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 4bd47a2c92..6a621d91a8 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -35,7 +35,7 @@ using namespace Bsa; /// Error handling -[[noreturn]] void BSAFile::fail(const std::string &msg) +[[noreturn]] void BSAFile::fail(const std::string &msg) const { throw std::runtime_error("BSA Error: " + msg + "\nArchive: " + Files::pathToUnicodeString(mFilepath)); } diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index 0d1bda6134..b7f3b107fb 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -90,7 +90,7 @@ protected: std::filesystem::path mFilepath; /// Error handling - [[noreturn]] void fail(const std::string &msg); + [[noreturn]] void fail(const std::string &msg) const; /// Read header information from the input source virtual void readHeader(); diff --git a/components/bsa/compressedbsafile.cpp b/components/bsa/compressedbsafile.cpp index ee7204bd9e..ac50ef0c22 100644 --- a/components/bsa/compressedbsafile.cpp +++ b/components/bsa/compressedbsafile.cpp @@ -300,6 +300,13 @@ void CompressedBSAFile::readHeader() CompressedBSAFile::FileRecord CompressedBSAFile::getFileRecord(const std::string& str) const { + for (const auto c : str) + { + if (((static_cast(c) >> 7U) & 1U) != 0U) { + fail("File record " + str + " contains unicode characters, refusing to load."); + } + } + #ifdef _WIN32 const auto& path = str; #else @@ -310,9 +317,9 @@ CompressedBSAFile::FileRecord CompressedBSAFile::getFileRecord(const std::string std::replace(path.begin(), path.end(), '\\', '/'); #endif - auto p = Files::pathFromUnicodeString(path); + const auto p = std::filesystem::path{ path }; // Purposefully damage Unicode strings. const auto stem = p.stem(); - const auto ext = p.extension().u8string(); + const auto ext = p.extension().string(); // Purposefully damage Unicode strings. std::uint64_t folderHash = generateHash(p.parent_path(), {}); @@ -471,13 +478,13 @@ void CompressedBSAFile::convertCompressedSizesToUncompressed() } } -std::uint64_t CompressedBSAFile::generateHash(const std::filesystem::path& stem, std::u8string extension) +std::uint64_t CompressedBSAFile::generateHash(const std::filesystem::path& stem, std::string extension) { auto str = stem.u8string(); size_t len = str.length(); if (len == 0) return 0; - std::replace(str.begin(), str.end(), u8'/', u8'\\'); + std::replace(str.begin(), str.end(), '/', '\\'); Misc::StringUtils::lowerCaseInPlace(str); uint64_t result = str[len-1] | (len >= 3 ? (str[len-2] << 8) : 0) | (len << 16) | (str[0] << 24); if (len >= 4) @@ -490,10 +497,10 @@ std::uint64_t CompressedBSAFile::generateHash(const std::filesystem::path& stem, if (extension.empty()) return result; Misc::StringUtils::lowerCaseInPlace(extension); - if (extension == u8".kf") result |= 0x80; - else if (extension == u8".nif") result |= 0x8000; - else if (extension == u8".dds") result |= 0x8080; - else if (extension == u8".wav") result |= 0x80000000; + if (extension == ".kf") result |= 0x80; + else if (extension == ".nif") result |= 0x8000; + else if (extension == ".dds") result |= 0x8080; + else if (extension == ".wav") result |= 0x80000000; uint32_t hash = 0; for (const auto &c : extension) hash = hash * 0x1003f + c; diff --git a/components/bsa/compressedbsafile.hpp b/components/bsa/compressedbsafile.hpp index 71727bfade..bad8551f09 100644 --- a/components/bsa/compressedbsafile.hpp +++ b/components/bsa/compressedbsafile.hpp @@ -83,7 +83,7 @@ namespace Bsa //mFiles used by OpenMW will contain uncompressed file sizes void convertCompressedSizesToUncompressed(); /// \brief Normalizes given filename or folder and generates format-compatible hash. See https://en.uesp.net/wiki/Tes4Mod:Hash_Calculation. - static std::uint64_t generateHash(const std::filesystem::path& stem, std::u8string extension) ; + static std::uint64_t generateHash(const std::filesystem::path& stem, std::string extension) ; Files::IStreamPtr getFile(const FileRecord& fileRecord); public: using BSAFile::open; From 886b8c7af2244a12600c939f906ac045b6720ec6 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sun, 11 Sep 2022 05:00:04 +0200 Subject: [PATCH 36/36] Fix build error with stdlibc++ due to includes shuffling. --- apps/openmw/mwworld/esmloader.hpp | 1 + components/esm4/reader.cpp | 1 - components/esm4/reader.hpp | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/esmloader.hpp b/apps/openmw/mwworld/esmloader.hpp index 4c7c095b4b..5f2fc94bf4 100644 --- a/apps/openmw/mwworld/esmloader.hpp +++ b/apps/openmw/mwworld/esmloader.hpp @@ -2,6 +2,7 @@ #define ESMLOADER_HPP #include +#include #include "contentloader.hpp" diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp index a5696c461b..450b86de0d 100644 --- a/components/esm4/reader.cpp +++ b/components/esm4/reader.cpp @@ -31,7 +31,6 @@ #include #include #include -#include #include // for debugging #include // for debugging #include // for debugging diff --git a/components/esm4/reader.hpp b/components/esm4/reader.hpp index dea7360e3c..a3f6efea39 100644 --- a/components/esm4/reader.hpp +++ b/components/esm4/reader.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "common.hpp" #include "loadtes4.hpp"