From 9a43ca2d0047ff62136318b4f7a0c563665116f4 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 24 Nov 2023 22:33:43 +0300 Subject: [PATCH 1/6] Move NiGeometry triangulation to NiGeometry --- components/nif/node.cpp | 96 ++++++++++++++++ components/nif/node.hpp | 13 ++- components/nifbullet/bulletnifloader.cpp | 138 ++--------------------- components/nifbullet/bulletnifloader.hpp | 2 +- 4 files changed, 121 insertions(+), 128 deletions(-) diff --git a/components/nif/node.cpp b/components/nif/node.cpp index 28cd2cdbfe..01c0e1597d 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -2,13 +2,33 @@ #include +#include + +#include #include +#include #include "data.hpp" #include "exception.hpp" #include "physics.hpp" #include "property.hpp" +namespace +{ + + void triBasedGeomToBtTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriBasedGeomData& data) + { + // FIXME: copying vertices/indices individually is unreasonable + const std::vector& vertices = data.mVertices; + mesh.preallocateVertices(static_cast(vertices.size())); + for (const osg::Vec3f& vertex : vertices) + mesh.findOrAddVertex(Misc::Convert::toBullet(vertex), false); + + mesh.preallocateIndices(static_cast(data.mNumTriangles) * 3); + } + +} + namespace Nif { @@ -218,6 +238,82 @@ namespace Nif } } + std::unique_ptr NiTriShape::getCollisionShape() const + { + if (mData.empty() || mData->mVertices.empty()) + return nullptr; + + auto data = static_cast(mData.getPtr()); + if (data->mNumTriangles == 0 || data->mTriangles.empty()) + return nullptr; + + auto mesh = std::make_unique(); + triBasedGeomToBtTriangleMesh(*mesh, *data); + const std::vector& triangles = data->mTriangles; + for (std::size_t i = 0; i < triangles.size(); i += 3) + mesh->addTriangleIndices(triangles[i + 0], triangles[i + 1], triangles[i + 2]); + + if (mesh->getNumTriangles() == 0) + return nullptr; + + auto shape = std::make_unique(mesh.get(), true); + std::ignore = mesh.release(); + + return shape; + } + + std::unique_ptr NiTriStrips::getCollisionShape() const + { + if (mData.empty() || mData->mVertices.empty()) + return nullptr; + + auto data = static_cast(mData.getPtr()); + if (data->mNumTriangles == 0 || data->mStrips.empty()) + return nullptr; + + auto mesh = std::make_unique(); + triBasedGeomToBtTriangleMesh(*mesh, *data); + for (const std::vector& strip : data->mStrips) + { + if (strip.size() < 3) + continue; + + unsigned short a; + unsigned short b = strip[0]; + unsigned short c = strip[1]; + for (size_t i = 2; i < strip.size(); i++) + { + a = b; + b = c; + c = strip[i]; + if (a == b || b == c || a == c) + continue; + if (i % 2 == 0) + mesh->addTriangleIndices(a, b, c); + else + mesh->addTriangleIndices(a, c, b); + } + } + + if (mesh->getNumTriangles() == 0) + return nullptr; + + auto shape = std::make_unique(mesh.get(), true); + std::ignore = mesh.release(); + + return shape; + } + + std::unique_ptr NiLines::getCollisionShape() const + { + return nullptr; + } + + std::unique_ptr NiParticles::getCollisionShape() const + { + return nullptr; + } + void BSSegmentedTriShape::SegmentData::read(NIFStream* nif) { nif->read(mFlags); diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 0aaad40ed4..32746f7a9f 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -8,6 +8,8 @@ #include "base.hpp" +class btCollisionShape; + namespace Nif { @@ -146,6 +148,11 @@ namespace Nif void read(NIFStream* nif) override; void post(Reader& nif) override; + + virtual std::unique_ptr getCollisionShape() const + { + throw std::runtime_error("NiGeometry::getCollisionShape() called on base class"); + } }; // Abstract triangle-based geometry @@ -155,6 +162,7 @@ namespace Nif struct NiTriShape : NiTriBasedGeom { + std::unique_ptr getCollisionShape() const override; }; struct BSSegmentedTriShape : NiTriShape @@ -175,17 +183,20 @@ namespace Nif struct NiTriStrips : NiTriBasedGeom { + std::unique_ptr getCollisionShape() const override; }; struct NiLines : NiTriBasedGeom { + std::unique_ptr getCollisionShape() const override; }; struct NiParticles : NiGeometry { + std::unique_ptr getCollisionShape() const override; }; - struct BSLODTriShape : NiTriBasedGeom + struct BSLODTriShape : NiTriShape { std::array mLOD; void read(NIFStream* nif) override; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index ec46afec41..96dff80004 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -6,22 +6,15 @@ #include #include -#include - #include - +#include #include - #include - -#include #include #include #include #include -#include - namespace { @@ -32,111 +25,6 @@ namespace return letterPos < path.size() && (path[letterPos] == 'x' || path[letterPos] == 'X'); } - bool isTypeNiGeometry(int type) - { - switch (type) - { - case Nif::RC_NiTriShape: - case Nif::RC_NiTriStrips: - case Nif::RC_BSLODTriShape: - case Nif::RC_BSSegmentedTriShape: - return true; - } - return false; - } - - bool isTypeTriShape(int type) - { - switch (type) - { - case Nif::RC_NiTriShape: - case Nif::RC_BSLODTriShape: - case Nif::RC_BSSegmentedTriShape: - return true; - } - - return false; - } - - void prepareTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriBasedGeomData& data) - { - // FIXME: copying vertices/indices individually is unreasonable - const std::vector& vertices = data.mVertices; - mesh.preallocateVertices(static_cast(vertices.size())); - for (const osg::Vec3f& vertex : vertices) - mesh.findOrAddVertex(Misc::Convert::toBullet(vertex), false); - - mesh.preallocateIndices(static_cast(data.mNumTriangles) * 3); - } - - void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriShapeData& data) - { - prepareTriangleMesh(mesh, data); - const std::vector& triangles = data.mTriangles; - for (std::size_t i = 0; i < triangles.size(); i += 3) - mesh.addTriangleIndices(triangles[i + 0], triangles[i + 1], triangles[i + 2]); - } - - void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriStripsData& data) - { - prepareTriangleMesh(mesh, data); - for (const std::vector& strip : data.mStrips) - { - if (strip.size() < 3) - continue; - - unsigned short a; - unsigned short b = strip[0]; - unsigned short c = strip[1]; - for (size_t i = 2; i < strip.size(); i++) - { - a = b; - b = c; - c = strip[i]; - if (a == b || b == c || a == c) - continue; - if (i % 2 == 0) - mesh.addTriangleIndices(a, b, c); - else - mesh.addTriangleIndices(a, c, b); - } - } - } - - template - auto handleNiGeometry(const Nif::NiGeometry& geometry, Function&& function) - -> decltype(function(static_cast(geometry.mData.get()))) - { - if (isTypeTriShape(geometry.recType)) - { - auto data = static_cast(geometry.mData.getPtr()); - if (data->mTriangles.empty()) - return {}; - - return function(static_cast(*data)); - } - - if (geometry.recType == Nif::RC_NiTriStrips) - { - auto data = static_cast(geometry.mData.getPtr()); - if (data->mStrips.empty()) - return {}; - - return function(static_cast(*data)); - } - - return {}; - } - - std::unique_ptr makeChildMesh(const Nif::NiGeometry& geometry) - { - return handleNiGeometry(geometry, [&](const auto& data) { - auto mesh = std::make_unique(); - fillTriangleMesh(*mesh, data); - return mesh; - }); - } - } namespace NifBullet @@ -336,8 +224,8 @@ namespace NifBullet return; // Otherwise we'll want to notify the user. - Log(Debug::Info) << "RootCollisionNode is not attached to the root node in " << mShape->mFileName - << ". Treating it as a common NiTriShape."; + Log(Debug::Info) << "BulletNifLoader: RootCollisionNode is not attached to the root node in " + << mShape->mFileName << ". Treating it as a NiNode."; } else { @@ -349,8 +237,12 @@ namespace NifBullet if (node.recType == Nif::RC_AvoidNode) args.mAvoid = true; - if ((args.mAutogenerated || args.mIsCollisionNode) && isTypeNiGeometry(node.recType)) - handleNiTriShape(static_cast(node), parent, args); + if (args.mAutogenerated || args.mIsCollisionNode) + { + auto geometry = dynamic_cast(&node); + if (geometry) + handleGeometry(*geometry, parent, args); + } // For NiNodes, loop through children if (const Nif::NiNode* ninode = dynamic_cast(&node)) @@ -367,7 +259,7 @@ namespace NifBullet } } - void BulletNifLoader::handleNiTriShape( + void BulletNifLoader::handleGeometry( const Nif::NiGeometry& niGeometry, const Nif::Parent* nodeParent, HandleNodeArgs args) { // This flag comes from BSXFlags @@ -378,20 +270,14 @@ namespace NifBullet if (args.mHasTriMarkers && Misc::StringUtils::ciStartsWith(niGeometry.mName, "Tri EditorMarker")) return; - if (niGeometry.mData.empty() || niGeometry.mData->mVertices.empty()) - return; - if (!niGeometry.mSkin.empty()) args.mAnimated = false; // TODO: handle NiSkinPartition - std::unique_ptr childMesh = makeChildMesh(niGeometry); - if (childMesh == nullptr || childMesh->getNumTriangles() == 0) + std::unique_ptr childShape = niGeometry.getCollisionShape(); + if (childShape == nullptr) return; - auto childShape = std::make_unique(childMesh.get(), true); - std::ignore = childMesh.release(); - osg::Matrixf transform = niGeometry.mTransform.toMatrix(); for (const Nif::Parent* parent = nodeParent; parent != nullptr; parent = parent->mParent) transform *= parent->mNiNode.mTransform.toMatrix(); diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index c87c1242de..a80e6fdc3d 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -62,7 +62,7 @@ namespace NifBullet void handleRoot(Nif::FileView nif, const Nif::NiAVObject& node, HandleNodeArgs args); void handleNode(const Nif::NiAVObject& node, const Nif::Parent* parent, HandleNodeArgs args); - void handleNiTriShape(const Nif::NiGeometry& nifNode, const Nif::Parent* parent, HandleNodeArgs args); + void handleGeometry(const Nif::NiGeometry& nifNode, const Nif::Parent* parent, HandleNodeArgs args); std::unique_ptr mCompoundShape; std::unique_ptr mAvoidCompoundShape; From 1841341da2a1880e4d50241b00a6df941fbaf9cf Mon Sep 17 00:00:00 2001 From: uramer Date: Sat, 25 Nov 2023 17:39:00 +0100 Subject: [PATCH 2/6] Fix Lua remove interacting with restocking items --- apps/openmw/mwlua/objectbindings.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 2f3a020971..e938d90e5e 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -417,20 +417,23 @@ namespace MWLua using DelayedRemovalFn = std::function; auto removeFn = [](const MWWorld::Ptr ptr, int countToRemove) -> std::optional { - int currentCount = ptr.getRefData().getCount(); + int rawCount = ptr.getRefData().getCount(false); + int currentCount = std::abs(rawCount); + int signedCountToRemove = (rawCount < 0 ? -1 : 1) * countToRemove; + if (countToRemove <= 0 || countToRemove > currentCount) throw std::runtime_error("Can't remove " + std::to_string(countToRemove) + " of " + std::to_string(currentCount) + " items"); - ptr.getRefData().setCount(currentCount - countToRemove); // Immediately change count + ptr.getRefData().setCount(rawCount - signedCountToRemove); // Immediately change count if (!ptr.getContainerStore() && currentCount > countToRemove) return std::nullopt; // Delayed action to trigger side effects - return [countToRemove](MWWorld::Ptr ptr) { + return [signedCountToRemove](MWWorld::Ptr ptr) { // Restore the original count - ptr.getRefData().setCount(ptr.getRefData().getCount() + countToRemove); + ptr.getRefData().setCount(ptr.getRefData().getCount(false) + signedCountToRemove); // And now remove properly if (ptr.getContainerStore()) - ptr.getContainerStore()->remove(ptr, countToRemove, false); + ptr.getContainerStore()->remove(ptr, std::abs(signedCountToRemove), false); else { MWBase::Environment::get().getWorld()->disable(ptr); From 81a6a7cd2f51ea3c64809e844fb0df6f02f736e2 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Nov 2023 18:03:04 +0400 Subject: [PATCH 3/6] Rework resolution selection (feature 7709) --- CHANGELOG.md | 1 + apps/launcher/graphicspage.cpp | 32 +---------- apps/openmw/mwgui/settingswindow.cpp | 22 +------- components/CMakeLists.txt | 2 +- components/misc/display.cpp | 82 ++++++++++++++++++++++++++++ components/misc/display.hpp | 11 ++++ files/ui/graphicspage.ui | 2 +- 7 files changed, 101 insertions(+), 51 deletions(-) create mode 100644 components/misc/display.cpp create mode 100644 components/misc/display.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ab1c0213a..30ad2bae6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -133,6 +133,7 @@ Feature #7625: Add some missing console error outputs Feature #7634: Support NiParticleBomb Feature #7652: Sort inactive post processing shaders list properly + Feature #7709: Improve resolution selection in Launcher Task #5896: Do not use deprecated MyGUI properties Task #7113: Move from std::atoi to std::from_char Task #7117: Replace boost::scoped_array with std::vector diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index cf2f00fca4..832cb0ef8f 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -2,6 +2,7 @@ #include "sdlinit.hpp" +#include #include #include @@ -16,22 +17,6 @@ #include #include -#include - -QString getAspect(int x, int y) -{ - int gcd = std::gcd(x, y); - if (gcd == 0) - return QString(); - - int xaspect = x / gcd; - int yaspect = y / gcd; - // special case: 8 : 5 is usually referred to as 16:10 - if (xaspect == 8 && yaspect == 5) - return QString("16:10"); - - return QString(QString::number(xaspect) + ":" + QString::number(yaspect)); -} Launcher::GraphicsPage::GraphicsPage(QWidget* parent) : QWidget(parent) @@ -304,19 +289,8 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) return result; } - QString resolution = QString::number(mode.w) + QString(" x ") + QString::number(mode.h); - - QString aspect = getAspect(mode.w, mode.h); - if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) - { - resolution.append(tr(" (Wide ") + aspect + ")"); - } - else if (aspect == QLatin1String("4:3")) - { - resolution.append(tr(" (Standard 4:3)")); - } - - result.append(resolution); + auto str = Misc::getResolutionText(mode.w, mode.h); + result.append(QString(str.c_str())); } result.removeDuplicates(); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 696596a46f..2d9a9d8292 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -21,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -93,20 +93,6 @@ namespace return left.first > right.first; } - std::string getAspect(int x, int y) - { - int gcd = std::gcd(x, y); - if (gcd == 0) - return std::string(); - - int xaspect = x / gcd; - int yaspect = y / gcd; - // special case: 8 : 5 is usually referred to as 16:10 - if (xaspect == 8 && yaspect == 5) - return "16 : 10"; - return MyGUI::utility::toString(xaspect) + " : " + MyGUI::utility::toString(yaspect); - } - const std::string_view checkButtonType = "CheckButton"; const std::string_view sliderType = "Slider"; @@ -366,11 +352,7 @@ namespace MWGui std::sort(resolutions.begin(), resolutions.end(), sortResolutions); for (std::pair& resolution : resolutions) { - std::string str - = MyGUI::utility::toString(resolution.first) + " x " + MyGUI::utility::toString(resolution.second); - std::string aspect = getAspect(resolution.first, resolution.second); - if (!aspect.empty()) - str = str + " (" + aspect + ")"; + std::string str = Misc::getResolutionText(resolution.first, resolution.second); if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE) mResolutionList->addItem(str); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index c9c74957ec..7e3c7aea23 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -273,7 +273,7 @@ add_component_dir (esm4 ) add_component_dir (misc - barrier budgetmeasurement color compression constants convert coordinateconverter endianness float16 frameratelimiter + barrier budgetmeasurement color compression constants convert coordinateconverter display endianness float16 frameratelimiter guarded math mathutil messageformatparser notnullptr objectpool osguservalues progressreporter resourcehelpers rng strongtypedef thread timeconvert timer tuplehelpers tuplemeta utf8stream weakcache windows ) diff --git a/components/misc/display.cpp b/components/misc/display.cpp new file mode 100644 index 0000000000..7570914483 --- /dev/null +++ b/components/misc/display.cpp @@ -0,0 +1,82 @@ +#include "display.hpp" + +#include +#include + +#include + +namespace Misc +{ + std::string getResolutionText(int x, int y) + { + int gcd = std::gcd(x, y); + if (gcd == 0) + return std::string(); + + int xaspect = x / gcd; + int yaspect = y / gcd; + + // It is unclear how to handle 90-degree screen rotation properly. + // So far only swap aspects, apply custom formatting logic and then swap back. + // As result, 1920 x 1200 is displayed as "1200 x 1920 (10:16)" + bool flipped = false; + if (yaspect > xaspect) + { + flipped = true; + std::swap(xaspect, yaspect); + } + + // 683:384 (used in 1366 x 768) is usually referred as 16:9 + if (xaspect == 683 && yaspect == 384) + { + xaspect = 16; + yaspect = 9; + } + // 85:48 (used in 1360 x 768) is usually referred as 16:9 + else if (xaspect == 85 && yaspect == 48) + { + xaspect = 16; + yaspect = 9; + } + // 49:36 (used in 1176 x 864) is usually referred as 4:3 + else if (xaspect == 49 && yaspect == 36) + { + xaspect = 4; + yaspect = 3; + } + // 39:29 (used in 624 x 484) is usually referred as 4:3 + else if (xaspect == 39 && yaspect == 29) + { + xaspect = 4; + yaspect = 3; + } + // 8:5 (used in 1440 x 900) is usually referred as 16:10 + else if (xaspect == 8 && yaspect == 5) + { + xaspect = 16; + yaspect = 10; + } + // 5:3 (used in 1280 x 768) is usually referred as 15:9 + else if (xaspect == 5 && yaspect == 3) + { + xaspect = 15; + yaspect = 9; + } + else + { + // everything between 21:9 and 22:9 + // is usually referred as 21:9 + float ratio = static_cast(xaspect) / yaspect; + if (ratio >= 21 / 9.f && ratio < 22 / 9.f) + { + xaspect = 21; + yaspect = 9; + } + } + + if (flipped) + std::swap(xaspect, yaspect); + + return Misc::StringUtils::format("%i x %i (%i:%i)", x, y, xaspect, yaspect); + } +} diff --git a/components/misc/display.hpp b/components/misc/display.hpp new file mode 100644 index 0000000000..6f60a48cda --- /dev/null +++ b/components/misc/display.hpp @@ -0,0 +1,11 @@ +#ifndef OPENMW_COMPONENTS_MISC_DISPLAY_H +#define OPENMW_COMPONENTS_MISC_DISPLAY_H + +#include + +namespace Misc +{ + std::string getResolutionText(int x, int y); +} + +#endif diff --git a/files/ui/graphicspage.ui b/files/ui/graphicspage.ui index bb900ccb2d..70ab1f0728 100644 --- a/files/ui/graphicspage.ui +++ b/files/ui/graphicspage.ui @@ -22,7 +22,7 @@ - + From 623510c073e5f2034b32f200d5752a1549288030 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 28 Nov 2023 22:47:27 +0400 Subject: [PATCH 4/6] Use multiplication character in the launcher instead of 'x' --- apps/launcher/graphicspage.cpp | 6 +++--- apps/openmw/mwgui/settingswindow.cpp | 2 +- components/misc/display.cpp | 4 ++-- components/misc/display.hpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 832cb0ef8f..84d5049d6c 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -102,7 +102,7 @@ bool Launcher::GraphicsPage::loadSettings() const int width = Settings::video().mResolutionX; const int height = Settings::video().mResolutionY; - QString resolution = QString::number(width) + QString(" x ") + QString::number(height); + QString resolution = QString::number(width) + QString(" × ") + QString::number(height); screenComboBox->setCurrentIndex(Settings::video().mScreen); int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith); @@ -189,7 +189,7 @@ void Launcher::GraphicsPage::saveSettings() int cHeight = 0; if (standardRadioButton->isChecked()) { - QRegularExpression resolutionRe("^(\\d+) x (\\d+)"); + QRegularExpression resolutionRe("^(\\d+) × (\\d+)"); QRegularExpressionMatch match = resolutionRe.match(resolutionComboBox->currentText().simplified()); if (match.hasMatch()) { @@ -289,7 +289,7 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) return result; } - auto str = Misc::getResolutionText(mode.w, mode.h); + auto str = Misc::getResolutionText(mode.w, mode.h, "%i × %i (%i:%i)"); result.append(QString(str.c_str())); } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 2d9a9d8292..1060b3a20f 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -352,7 +352,7 @@ namespace MWGui std::sort(resolutions.begin(), resolutions.end(), sortResolutions); for (std::pair& resolution : resolutions) { - std::string str = Misc::getResolutionText(resolution.first, resolution.second); + std::string str = Misc::getResolutionText(resolution.first, resolution.second, "%i x %i (%i:%i)"); if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE) mResolutionList->addItem(str); diff --git a/components/misc/display.cpp b/components/misc/display.cpp index 7570914483..ee78b2a0c9 100644 --- a/components/misc/display.cpp +++ b/components/misc/display.cpp @@ -7,7 +7,7 @@ namespace Misc { - std::string getResolutionText(int x, int y) + std::string getResolutionText(int x, int y, const std::string& format) { int gcd = std::gcd(x, y); if (gcd == 0) @@ -77,6 +77,6 @@ namespace Misc if (flipped) std::swap(xaspect, yaspect); - return Misc::StringUtils::format("%i x %i (%i:%i)", x, y, xaspect, yaspect); + return Misc::StringUtils::format(format, x, y, xaspect, yaspect); } } diff --git a/components/misc/display.hpp b/components/misc/display.hpp index 6f60a48cda..82037661c8 100644 --- a/components/misc/display.hpp +++ b/components/misc/display.hpp @@ -5,7 +5,7 @@ namespace Misc { - std::string getResolutionText(int x, int y); + std::string getResolutionText(int x, int y, const std::string& format); } #endif From 67421d67e2ced5139b6da59c799ec13e51049c16 Mon Sep 17 00:00:00 2001 From: Zackhasacat Date: Wed, 29 Nov 2023 15:42:34 +0000 Subject: [PATCH 5/6] Allow not passing force in ItemUsage events --- files/data/scripts/omw/usehandlers.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/data/scripts/omw/usehandlers.lua b/files/data/scripts/omw/usehandlers.lua index 01203b225c..563e31b3b7 100644 --- a/files/data/scripts/omw/usehandlers.lua +++ b/files/data/scripts/omw/usehandlers.lua @@ -22,7 +22,7 @@ local function useItem(obj, actor, force) end end end - world._runStandardUseAction(obj, actor, force) + world._runStandardUseAction(obj, actor, options.force) end return { From f52e8f76c6157600a2d485e37e8e9028769f5841 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 29 Nov 2023 16:59:01 +0100 Subject: [PATCH 6/6] Use std::erase instead of using std::remove without erasing --- components/lua_ui/element.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/lua_ui/element.cpp b/components/lua_ui/element.cpp index 71f2ba9c96..baa3438982 100644 --- a/components/lua_ui/element.cpp +++ b/components/lua_ui/element.cpp @@ -99,7 +99,7 @@ namespace LuaUi if (parent) { auto children = parent->children(); - std::remove(children.begin(), children.end(), root); + std::erase(children, root); parent->setChildren(children); root->widget()->detachFromWidget(); }