Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package openmw for openSUSE:Factory checked in at 2025-06-24 20:47:54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openmw (Old) and /work/SRC/openSUSE:Factory/.openmw.new.7067 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openmw" Tue Jun 24 20:47:54 2025 rev:20 rq:1287957 version:0.49rc9 Changes: -------- --- /work/SRC/openSUSE:Factory/openmw/openmw.changes 2025-06-10 09:07:57.154050473 +0200 +++ /work/SRC/openSUSE:Factory/.openmw.new.7067/openmw.changes 2025-06-24 20:49:09.948346317 +0200 @@ -1,0 +2,12 @@ +Mon Jun 23 11:45:41 UTC 2025 - Michael Pujos <pujos.mich...@gmail.com> + +- Compiled with Qt6 +- Update to version 0.49rc9 + * [#8039] Fixed movement accumulation for actors that use Collada models on some builds compiled under LLVM + * [#8558] OpenMW-Lua: Light record color is now exposed as util.color rather than as a number + * [#8559] ESSImporter: Fixed selected spell/enchanted item and stolen item counter conversion + * [#8563] Improved handling of content files that are defined in the non-user version of openmw.cfg + * [#8567] Token replacement and relative paths work properly when the paths are passed through CLI + * Improved application detection for default shortcuts + +------------------------------------------------------------------- Old: ---- openmw-49-rc8.tar.gz New: ---- openmw-49-rc9.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openmw.spec ++++++ --- /var/tmp/diff_new_pack.Xg5C0s/_old 2025-06-24 20:49:10.836383132 +0200 +++ /var/tmp/diff_new_pack.Xg5C0s/_new 2025-06-24 20:49:10.840383298 +0200 @@ -21,9 +21,9 @@ # are not compatible with it # 1.69 is the first boost version that is supposed to work with C++ 20: %define min_boost_version 1.69 -%define archive_version 49-rc8 +%define archive_version 49-rc9 Name: openmw -Version: 0.49rc8 +Version: 0.49rc9 Release: 0 Summary: Reimplementation of The Elder Scrolls III: Morrowind License: GPL-3.0-only AND MIT @@ -40,15 +40,14 @@ BuildRequires: libboost_program_options-devel >= %{min_boost_version} BuildRequires: libboost_regex-devel >= %{min_boost_version} BuildRequires: libboost_system-devel >= %{min_boost_version} -BuildRequires: libqt5-linguist-devel -BuildRequires: pkgconfig BuildRequires: tinyxml-devel BuildRequires: update-desktop-files -BuildRequires: pkgconfig(Qt5Core) -BuildRequires: pkgconfig(Qt5Network) -BuildRequires: pkgconfig(Qt5OpenGL) -BuildRequires: pkgconfig(Qt5Svg) -BuildRequires: pkgconfig(Qt5Widgets) +BuildRequires: pkgconfig(Qt6Core) +BuildRequires: pkgconfig(Qt6Linguist) +BuildRequires: pkgconfig(Qt6Network) +BuildRequires: pkgconfig(Qt6OpenGLWidgets) +BuildRequires: pkgconfig(Qt6Svg) +BuildRequires: pkgconfig(Qt6Widgets) BuildRequires: pkgconfig(bullet) >= 2.83.0 BuildRequires: pkgconfig(icu-i18n) BuildRequires: pkgconfig(icu-uc) ++++++ openmw-49-rc8.tar.gz -> openmw-49-rc9.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/.github/workflows/push.yml new/openmw-openmw-49-rc9/.github/workflows/push.yml --- old/openmw-openmw-49-rc8/.github/workflows/push.yml 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/.github/workflows/push.yml 2025-06-23 10:59:11.000000000 +0200 @@ -73,7 +73,7 @@ - uses: actions/checkout@v4 - name: Install Building Dependencies - run: CI/before_install.osx.sh + run: CI/before_install.macos.sh - name: Prime ccache uses: hendrikmuhs/ccache-action@v1 @@ -82,11 +82,9 @@ max-size: 1000M - name: Configure - run: CI/before_script.osx.sh + run: CI/before_script.macos.sh - name: Build - run: | - cd build - make -j $(sysctl -n hw.logicalcpu) package + run: CI/macos/build.sh Output-Envs: name: Read .env file and expose it as output diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/.gitlab-ci.yml new/openmw-openmw-49-rc9/.gitlab-ci.yml --- old/openmw-openmw-49-rc8/.gitlab-ci.yml 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/.gitlab-ci.yml 2025-06-23 10:59:11.000000000 +0200 @@ -507,14 +507,15 @@ paths: - ccache/ script: - - CI/before_install.osx.sh + - CI/before_install.macos.sh - export CCACHE_BASEDIR="$(pwd)" - export CCACHE_DIR="$(pwd)/ccache" - mkdir -pv "${CCACHE_DIR}" - - ccache -z -M "${CCACHE_SIZE}" - - CI/before_script.osx.sh - - cd build; make -j $(sysctl -n hw.logicalcpu) package - - for dmg in *.dmg; do mv "$dmg" "${dmg%.dmg}_${CI_COMMIT_REF_NAME##*/}.dmg"; done + - CI/macos/ccache_prep.sh + - CI/before_script.macos.sh + - CI/macos/build.sh + - cd build + - for dmg in *.dmg; do mv "$dmg" "${dmg%.dmg}_${DMG_IDENTIFIER}_${CI_COMMIT_REF_NAME##*/}.dmg"; done - | if [[ -n "${AWS_ACCESS_KEY_ID}" ]]; then echo "[default]" > ~/.s3cfg @@ -529,11 +530,23 @@ s3cmd put "${dmg}" s3://openmw-artifacts/${artifactDirectory} done fi - - ccache -s + - ../CI/macos/ccache_save.sh artifacts: paths: - build/OpenMW-*.dmg +macOS14_Xcode15_amd64: + extends: .MacOS + image: macos-14-xcode-15 + tags: + - saas-macos-medium-m1 + cache: + key: macOS14_Xcode15_amd64.v2 + variables: + CCACHE_SIZE: 3G + DMG_IDENTIFIER: amd64 + MACOS_AMD64: true + macOS14_Xcode15_arm64: extends: .MacOS image: macos-14-xcode-15 @@ -542,6 +555,7 @@ cache: key: macOS14_Xcode15_arm64.v1 variables: + DMG_IDENTIFIER: arm64 CCACHE_SIZE: 3G .Compress_And_Upload_Symbols_Base: @@ -968,7 +982,7 @@ - flatpak build-bundle ./repo openmw.flatpak org.openmw.OpenMW.devel cache: key: flatpak - paths: + paths: - ".flatpak-builder" artifacts: untracked: false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/CHANGELOG.md new/openmw-openmw-49-rc9/CHANGELOG.md --- old/openmw-openmw-49-rc8/CHANGELOG.md 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/CHANGELOG.md 2025-06-23 10:59:11.000000000 +0200 @@ -236,6 +236,7 @@ Bug #8465: Blue screen w/ antialiasing and post-processing on macOS Bug #8503: Camera does not handle NaN gracefully Bug #8541: Lua: util.color:asHex produces wrong output for some colors + Bug #8567: Token replacement does not work via CLI and relative paths passed via the command line are not relative to the CWD Feature #1415: Infinite fall failsafe Feature #2566: Handle NAM9 records for manual cell references Feature #3501: OpenMW-CS: Instance Editing - Shortcuts for axial locking diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/before_install.macos.sh new/openmw-openmw-49-rc9/CI/before_install.macos.sh --- old/openmw-openmw-49-rc8/CI/before_install.macos.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/openmw-openmw-49-rc9/CI/before_install.macos.sh 2025-06-23 10:59:11.000000000 +0200 @@ -0,0 +1,11 @@ +#!/bin/sh -ex + +export HOMEBREW_NO_EMOJI=1 +export HOMEBREW_NO_INSTALL_CLEANUP=1 +export HOMEBREW_AUTOREMOVE=1 + +if [[ "${MACOS_AMD64}" ]]; then + ./CI/macos/before_install.amd64.sh +else + ./CI/macos/before_install.arm64.sh +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/before_install.osx.sh new/openmw-openmw-49-rc9/CI/before_install.osx.sh --- old/openmw-openmw-49-rc8/CI/before_install.osx.sh 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/CI/before_install.osx.sh 1970-01-01 01:00:00.000000000 +0100 @@ -1,30 +0,0 @@ -#!/bin/sh -ex - -export HOMEBREW_NO_EMOJI=1 -export HOMEBREW_NO_INSTALL_CLEANUP=1 -export HOMEBREW_AUTOREMOVE=1 - -brew tap --repair -brew update --quiet - -brew install curl xquartz gd fontconfig freetype harfbuzz brotli s3cmd - -command -v ccache >/dev/null 2>&1 || brew install ccache -command -v cmake >/dev/null 2>&1 || brew install cmake -command -v qmake >/dev/null 2>&1 || brew install qt@5 -export PATH="/opt/homebrew/opt/qt@5/bin:$PATH" - -# Install deps -brew install openal-soft icu4c yaml-cpp sqlite - -ccache --version -cmake --version -qmake --version - -if [[ "${MACOS_AMD64}" ]]; then - curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240802.zip -o ~/openmw-deps.zip - unzip -o ~/openmw-deps.zip -d /tmp > /dev/null -else - curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240818-arm64.tar.xz -o ~/openmw-deps.tar.xz - tar xf ~/openmw-deps.tar.xz -C /tmp > /dev/null -fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/before_script.macos.sh new/openmw-openmw-49-rc9/CI/before_script.macos.sh --- old/openmw-openmw-49-rc8/CI/before_script.macos.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/openmw-openmw-49-rc9/CI/before_script.macos.sh 2025-06-23 10:59:11.000000000 +0200 @@ -0,0 +1,77 @@ +#!/bin/sh -e + +# Silence a git warning +git config --global advice.detachedHead false + +rm -fr build +mkdir build +cd build + +DEPENDENCIES_ROOT="/tmp/openmw-deps" + +if [[ "${MACOS_AMD64}" ]]; then + QT_PATH=$(arch -x86_64 /usr/local/bin/brew --prefix qt@6) + ICU_PATH=$(arch -x86_64 /usr/local/bin/brew --prefix icu4c) + OPENAL_PATH=$(arch -x86_64 /usr/local/bin/brew --prefix openal-soft) + CCACHE_EXECUTABLE=$(arch -x86_64 /usr/local/bin/brew --prefix ccache)/bin/ccache +else + QT_PATH=$(brew --prefix qt@6) + ICU_PATH=$(brew --prefix icu4c) + OPENAL_PATH=$(brew --prefix openal-soft) + CCACHE_EXECUTABLE=$(brew --prefix ccache)/bin/ccache +fi + +declare -a CMAKE_CONF_OPTS=( +-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH;$OPENAL_PATH" +-D CMAKE_C_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" +-D CMAKE_CXX_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" +-D CMAKE_CXX_FLAGS="-stdlib=libc++" +-D CMAKE_C_COMPILER="clang" +-D CMAKE_CXX_COMPILER="clang++" +-D CMAKE_OSX_DEPLOYMENT_TARGET="13.6" +-D OPENMW_USE_SYSTEM_RECASTNAVIGATION=TRUE +-D Boost_INCLUDE_DIR="$DEPENDENCIES_ROOT/include" +-D OSGPlugins_LIB_DIR="$DEPENDENCIES_ROOT/lib/osgPlugins-3.6.5" +-D ICU_ROOT="$ICU_PATH" +-D OPENMW_OSX_DEPLOYMENT=TRUE +) + +declare -a BUILD_OPTS=( +-D BUILD_OPENMW=TRUE +-D BUILD_OPENCS=TRUE +-D BUILD_ESMTOOL=TRUE +-D BUILD_BSATOOL=TRUE +-D BUILD_ESSIMPORTER=TRUE +-D BUILD_NIFTEST=TRUE +-D BUILD_NAVMESHTOOL=TRUE +-D BUILD_BULLETOBJECTTOOL=TRUE +-G"Unix Makefiles" +) + +if [[ "${MACOS_AMD64}" ]]; then + CMAKE_CONF_OPTS+=( + -D CMAKE_OSX_ARCHITECTURES="x86_64" + ) +fi + +if [[ "${CMAKE_BUILD_TYPE}" ]]; then + CMAKE_CONF_OPTS+=( + -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + ) +else + CMAKE_CONF_OPTS+=( + -D CMAKE_BUILD_TYPE=RelWithDebInfo + ) +fi + +if [[ "${MACOS_AMD64}" ]]; then + arch -x86_64 cmake \ + "${CMAKE_CONF_OPTS[@]}" \ + "${BUILD_OPTS[@]}" \ + .. +else + cmake \ + "${CMAKE_CONF_OPTS[@]}" \ + "${BUILD_OPTS[@]}" \ + .. +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/before_script.osx.sh new/openmw-openmw-49-rc9/CI/before_script.osx.sh --- old/openmw-openmw-49-rc8/CI/before_script.osx.sh 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/CI/before_script.osx.sh 1970-01-01 01:00:00.000000000 +0100 @@ -1,53 +0,0 @@ -#!/bin/sh -e - -# Silence a git warning -git config --global advice.detachedHead false - -rm -fr build -mkdir build -cd build - -DEPENDENCIES_ROOT="/tmp/openmw-deps" - -QT_PATH=$(brew --prefix qt@5) -ICU_PATH=$(brew --prefix icu4c) -OPENAL_PATH=$(brew --prefix openal-soft) -CCACHE_EXECUTABLE=$(brew --prefix ccache)/bin/ccache - -declare -a CMAKE_CONF_OPTS=( --D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH;$OPENAL_PATH" --D CMAKE_C_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" --D CMAKE_CXX_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" --D CMAKE_CXX_FLAGS="-stdlib=libc++" --D CMAKE_C_COMPILER="clang" --D CMAKE_CXX_COMPILER="clang++" --D CMAKE_OSX_DEPLOYMENT_TARGET="13.6" --D OPENMW_USE_SYSTEM_RECASTNAVIGATION=TRUE --D Boost_INCLUDE_DIR="$DEPENDENCIES_ROOT/include" --D OSGPlugins_LIB_DIR="$DEPENDENCIES_ROOT/lib/osgPlugins-3.6.5" --D ICU_ROOT="$ICU_PATH" --D OPENMW_OSX_DEPLOYMENT=TRUE -) - -if [[ "${CMAKE_BUILD_TYPE}" ]]; then - CMAKE_CONF_OPTS+=( - -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - ) -else - CMAKE_CONF_OPTS+=( - -D CMAKE_BUILD_TYPE=RelWithDebInfo - ) -fi - -cmake \ -"${CMAKE_CONF_OPTS[@]}" \ --D BUILD_OPENMW=TRUE \ --D BUILD_OPENCS=TRUE \ --D BUILD_ESMTOOL=TRUE \ --D BUILD_BSATOOL=TRUE \ --D BUILD_ESSIMPORTER=TRUE \ --D BUILD_NIFTEST=TRUE \ --D BUILD_NAVMESHTOOL=TRUE \ --D BUILD_BULLETOBJECTTOOL=TRUE \ --G"Unix Makefiles" \ -.. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/macos/before_install.amd64.sh new/openmw-openmw-49-rc9/CI/macos/before_install.amd64.sh --- old/openmw-openmw-49-rc8/CI/macos/before_install.amd64.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/openmw-openmw-49-rc9/CI/macos/before_install.amd64.sh 2025-06-23 10:59:11.000000000 +0200 @@ -0,0 +1,8 @@ +#!/bin/sh -ex + +arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + +arch -x86_64 /usr/local/bin/brew install curl xquartz gd fontconfig freetype harfbuzz brotli s3cmd ccache cmake qt@6 openal-soft icu4c yaml-cpp sqlite + +curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240802.zip -o ~/openmw-deps.zip +unzip -o ~/openmw-deps.zip -d /tmp > /dev/null diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/macos/before_install.arm64.sh new/openmw-openmw-49-rc9/CI/macos/before_install.arm64.sh --- old/openmw-openmw-49-rc8/CI/macos/before_install.arm64.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/openmw-openmw-49-rc9/CI/macos/before_install.arm64.sh 2025-06-23 10:59:11.000000000 +0200 @@ -0,0 +1,16 @@ +#!/bin/sh -ex + +brew tap --repair +brew update --quiet + +brew install curl xquartz gd fontconfig freetype harfbuzz brotli s3cmd + +command -v ccache >/dev/null 2>&1 || brew install ccache +command -v cmake >/dev/null 2>&1 || brew install cmake +command -v qmake >/dev/null 2>&1 || brew install qt@6 + +# Install deps +brew install openal-soft icu4c yaml-cpp sqlite + +curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240818-arm64.tar.xz -o ~/openmw-deps.tar.xz +tar xf ~/openmw-deps.tar.xz -C /tmp > /dev/null diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/macos/build.sh new/openmw-openmw-49-rc9/CI/macos/build.sh --- old/openmw-openmw-49-rc8/CI/macos/build.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/openmw-openmw-49-rc9/CI/macos/build.sh 2025-06-23 10:59:11.000000000 +0200 @@ -0,0 +1,9 @@ +#!/bin/sh -ex + +cd build + +if [[ "${MACOS_AMD64}" ]]; then + arch -x86_64 make -j $(sysctl -n hw.logicalcpu) package +else + make -j $(sysctl -n hw.logicalcpu) package +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/macos/ccache_prep.sh new/openmw-openmw-49-rc9/CI/macos/ccache_prep.sh --- old/openmw-openmw-49-rc8/CI/macos/ccache_prep.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/openmw-openmw-49-rc9/CI/macos/ccache_prep.sh 2025-06-23 10:59:11.000000000 +0200 @@ -0,0 +1,7 @@ +#!/bin/sh -ex + +if [[ "${MACOS_AMD64}" ]]; then + arch -x86_64 ccache -z -M "${CCACHE_SIZE}" +else + ccache -z -M "${CCACHE_SIZE}" +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/macos/ccache_save.sh new/openmw-openmw-49-rc9/CI/macos/ccache_save.sh --- old/openmw-openmw-49-rc8/CI/macos/ccache_save.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/openmw-openmw-49-rc9/CI/macos/ccache_save.sh 2025-06-23 10:59:11.000000000 +0200 @@ -0,0 +1,7 @@ +#!/bin/sh -ex + +if [[ "${MACOS_AMD64}" ]]; then + arch -x86_64 ccache -s +else + ccache -s +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/CMakeLists.txt new/openmw-openmw-49-rc9/CMakeLists.txt --- old/openmw-openmw-49-rc8/CMakeLists.txt 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/CMakeLists.txt 2025-06-23 10:59:11.000000000 +0200 @@ -82,7 +82,7 @@ set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 49) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 75) +set(OPENMW_LUA_API_REVISION 76) set(OPENMW_POSTPROCESSING_API_REVISION 2) set(OPENMW_VERSION_COMMITHASH "") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/bulletobjecttool/main.cpp new/openmw-openmw-49-rc9/apps/bulletobjecttool/main.cpp --- old/openmw-openmw-49-rc8/apps/bulletobjecttool/main.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/bulletobjecttool/main.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -125,6 +125,7 @@ } Files::ConfigurationManager config; + config.processPaths(variables, std::filesystem::current_path()); config.readConfiguration(variables, desc); Debug::setupLogging(config.getLogPath(), applicationName); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/converter.hpp new/openmw-openmw-49-rc9/apps/essimporter/converter.hpp --- old/openmw-openmw-49-rc8/apps/essimporter/converter.hpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/essimporter/converter.hpp 2025-06-23 10:59:11.000000000 +0200 @@ -252,7 +252,7 @@ for (size_t i = 0; i < invState.mItems.size(); ++i) { // FIXME: in case of conflict (multiple items with this refID) use the already equipped one? - if (invState.mItems[i].mRef.mRefID == ESM::RefId::stringRefId(refr.mActorData.mSelectedEnchantItem)) + if (invState.mItems[i].mRef.mRefID == refr.mActorData.mSelectedEnchantItem) invState.mSelectedEnchantItem = i; } } @@ -260,12 +260,12 @@ void write(ESM::ESMWriter& esm) override { esm.startRecord(ESM::REC_ASPL); - esm.writeHNString("ID__", mSelectedSpell); + esm.writeHNRefId("ID__", mSelectedSpell); esm.endRecord(ESM::REC_ASPL); } private: - std::string mSelectedSpell; + ESM::RefId mSelectedSpell; }; class ConvertPCDT : public Converter @@ -374,16 +374,16 @@ void write(ESM::ESMWriter& esm) override { esm.startRecord(ESM::REC_DCOU); - for (auto it = mKillCounter.begin(); it != mKillCounter.end(); ++it) + for (const auto& [id, count] : mKillCounter) { - esm.writeHNString("ID__", it->first); - esm.writeHNT("COUN", it->second); + esm.writeHNRefId("ID__", id); + esm.writeHNT("COUN", count); } esm.endRecord(ESM::REC_DCOU); } private: - std::map<std::string, int> mKillCounter; + std::map<ESM::RefId, int> mKillCounter; }; class ConvertFACT : public Converter diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/importacdt.hpp new/openmw-openmw-49-rc9/apps/essimporter/importacdt.hpp --- old/openmw-openmw-49-rc8/apps/essimporter/importacdt.hpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/essimporter/importacdt.hpp 2025-06-23 10:59:11.000000000 +0200 @@ -75,8 +75,8 @@ // to change them ingame int mCombatStats[3][2]; - std::string mSelectedSpell; - std::string mSelectedEnchantItem; + ESM::RefId mSelectedSpell; + ESM::RefId mSelectedEnchantItem; SCRI mSCRI; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/importcellref.cpp new/openmw-openmw-49-rc9/apps/essimporter/importcellref.cpp --- old/openmw-openmw-49-rc8/apps/essimporter/importcellref.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/essimporter/importcellref.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -107,12 +107,12 @@ if (esm.isNextSub("WNAM")) { - std::string id = esm.getHString(); + ESM::RefId spellRefId = esm.getRefId(); if (esm.isNextSub("XNAM")) - mActorData.mSelectedEnchantItem = esm.getHString(); + mActorData.mSelectedEnchantItem = esm.getRefId(); else - mActorData.mSelectedSpell = std::move(id); + mActorData.mSelectedSpell = std::move(spellRefId); if (esm.isNextSub("YNAM")) esm.skipHSub(); // 4 byte, 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/importinfo.cpp new/openmw-openmw-49-rc9/apps/essimporter/importinfo.cpp --- old/openmw-openmw-49-rc8/apps/essimporter/importinfo.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/essimporter/importinfo.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -7,7 +7,19 @@ void INFO::load(ESM::ESMReader& esm) { - mInfo = esm.getHNString("INAM"); + if (esm.peekNextSub("XNAM")) + { + // TODO: Support older saves by turning XNAM into a RefId. + // XNAM is probably the number of the topic response within the topic record's linked list. + // Resolving this value will likely require loading Morrowind.esm. + + esm.getSubName(); + esm.skipHSub(); + mInfo = ESM::RefId(); + } + else + mInfo = esm.getHNRefId("INAM"); + mActorRefId = esm.getHNString("ACDT"); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/importinfo.hpp new/openmw-openmw-49-rc9/apps/essimporter/importinfo.hpp --- old/openmw-openmw-49-rc8/apps/essimporter/importinfo.hpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/essimporter/importinfo.hpp 2025-06-23 10:59:11.000000000 +0200 @@ -3,6 +3,8 @@ #include <string> +#include <components/esm/refid.hpp> + namespace ESM { class ESMReader; @@ -13,7 +15,7 @@ struct INFO { - std::string mInfo; + ESM::RefId mInfo; std::string mActorRefId; void load(ESM::ESMReader& esm); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/importklst.cpp new/openmw-openmw-49-rc9/apps/essimporter/importklst.cpp --- old/openmw-openmw-49-rc8/apps/essimporter/importklst.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/essimporter/importklst.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -9,7 +9,7 @@ { while (esm.isNextSub("KNAM")) { - std::string refId = esm.getHString(); + ESM::RefId refId = esm.getRefId(); int32_t count; esm.getHNT(count, "CNAM"); mKillCounter[refId] = count; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/importklst.hpp new/openmw-openmw-49-rc9/apps/essimporter/importklst.hpp --- old/openmw-openmw-49-rc8/apps/essimporter/importklst.hpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/essimporter/importklst.hpp 2025-06-23 10:59:11.000000000 +0200 @@ -3,7 +3,8 @@ #include <cstdint> #include <map> -#include <string> + +#include <components/esm/refid.hpp> namespace ESM { @@ -18,8 +19,7 @@ { void load(ESM::ESMReader& esm); - /// RefId, kill count - std::map<std::string, int32_t> mKillCounter; + std::map<ESM::RefId, int32_t> mKillCounter; int32_t mWerewolfKills; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/main.cpp new/openmw-openmw-49-rc9/apps/essimporter/main.cpp --- old/openmw-openmw-49-rc8/apps/essimporter/main.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/essimporter/main.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -40,6 +40,7 @@ bpo::notify(variables); Files::ConfigurationManager cfgManager(true); + cfgManager.processPaths(variables, std::filesystem::current_path()); cfgManager.readConfiguration(variables, desc); const auto& essFile = variables["mwsave"].as<Files::MaybeQuotedPath>(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/navmeshtool/main.cpp new/openmw-openmw-49-rc9/apps/navmeshtool/main.cpp --- old/openmw-openmw-49-rc8/apps/navmeshtool/main.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/navmeshtool/main.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -143,6 +143,7 @@ } Files::ConfigurationManager config; + config.processPaths(variables, std::filesystem::current_path()); config.readConfiguration(variables, desc); Debug::setupLogging(config.getLogPath(), applicationName); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/opencs/model/doc/runner.cpp new/openmw-openmw-49-rc9/apps/opencs/model/doc/runner.cpp --- old/openmw-openmw-49-rc8/apps/opencs/model/doc/runner.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/opencs/model/doc/runner.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -2,11 +2,8 @@ #include <utility> -#if defined(Q_OS_MAC) #include <QCoreApplication> #include <QDir> -#endif - #include <QProcess> #include <QString> #include <QStringList> @@ -55,16 +52,17 @@ QString path = "openmw"; #ifdef Q_OS_WIN - path.append(QString(".exe")); -#elif defined(Q_OS_MAC) + path.append(QLatin1String(".exe")); +#endif QDir dir(QCoreApplication::applicationDirPath()); +#ifdef Q_OS_MAC + // the CS and engine are in separate .app directories dir.cdUp(); dir.cdUp(); dir.cdUp(); - path = dir.absoluteFilePath(path.prepend("OpenMW.app/Contents/MacOS/")); -#else - path.prepend(QString("./")); + path.prepend("OpenMW.app/Contents/MacOS/"); #endif + path = dir.absoluteFilePath(path); mStartup = new QTemporaryFile(this); mStartup->open(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/openmw/CMakeLists.txt new/openmw-openmw-49-rc9/apps/openmw/CMakeLists.txt --- old/openmw-openmw-49-rc8/apps/openmw/CMakeLists.txt 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/openmw/CMakeLists.txt 2025-06-23 10:59:11.000000000 +0200 @@ -138,6 +138,12 @@ endif() target_link_libraries(openmw openmw-lib) + + # Workaround necessary to ensure osgAnimation::MatrixLinearSampler dynamic casts work under Clang + # NOTE: it's unclear whether the broken behavior is spec-compliant + if (CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set_target_properties(openmw PROPERTIES ENABLE_EXPORTS ON) + endif() endif() # Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/openmw/main.cpp new/openmw-openmw-49-rc9/apps/openmw/main.cpp --- old/openmw-openmw-49-rc8/apps/openmw/main.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/openmw/main.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -61,6 +61,8 @@ return false; } + cfgMgr.processPaths(variables, std::filesystem::current_path()); + cfgMgr.readConfiguration(variables, desc); Debug::setupLogging(cfgMgr.getLogPath(), "OpenMW"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/openmw/mwlua/types/light.cpp new/openmw-openmw-49-rc9/apps/openmw/mwlua/types/light.cpp --- old/openmw-openmw-49-rc8/apps/openmw/mwlua/types/light.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/apps/openmw/mwlua/types/light.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -5,6 +5,7 @@ #include <components/esm3/loadligh.hpp> #include <components/lua/luastate.hpp> #include <components/lua/util.hpp> +#include <components/misc/color.hpp> #include <components/misc/resourcehelpers.hpp> #include <components/resource/resourcesystem.hpp> @@ -62,7 +63,13 @@ if (rec["radius"] != sol::nil) light.mData.mRadius = rec["radius"]; if (rec["color"] != sol::nil) - light.mData.mColor = rec["color"]; + { + sol::object color = rec["color"]; + if (color.is<Misc::Color>()) + light.mData.mColor = color.as<Misc::Color>().toRGBA(); + else + light.mData.mColor = color.as<uint32_t>(); + } setRecordFlag(rec, "isCarriable", ESM::Light::Carry, light); setRecordFlag(rec, "isDynamic", ESM::Light::Dynamic, light); setRecordFlag(rec, "isFire", ESM::Light::Fire, light); @@ -104,7 +111,8 @@ record["value"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mValue; }); record["duration"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mTime; }); record["radius"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mRadius; }); - record["color"] = sol::readonly_property([](const ESM::Light& rec) -> int { return rec.mData.mColor; }); + record["color"] = sol::readonly_property( + [](const ESM::Light& rec) -> Misc::Color { return Misc::Color::fromRGB(rec.mData.mColor); }); record["isCarriable"] = sol::readonly_property( [](const ESM::Light& rec) -> bool { return rec.mData.mFlags & ESM::Light::Carry; }); record["isDynamic"] = sol::readonly_property( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/config/gamesettings.cpp new/openmw-openmw-49-rc9/components/config/gamesettings.cpp --- old/openmw-openmw-49-rc8/components/config/gamesettings.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/config/gamesettings.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -189,19 +189,16 @@ if (ignoreContent && (key == QLatin1String("content") || key == QLatin1String("data"))) continue; - QList<SettingValue> values = cache.values(key); - values.append(settings.values(key)); - - bool exists = false; - for (const auto& existingValue : values) - { - if (existingValue.value == value.value) + auto containsValue = [&](const QMultiMap<QString, SettingValue>& map) { + for (auto [itr, end] = map.equal_range(key); itr != end; ++itr) { - exists = true; - break; + if (itr->value == value.value) + return true; } - } - if (!exists) + return false; + }; + + if (!containsValue(cache) && !containsValue(settings)) { cache.insert(key, value); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/contentselector/model/contentmodel.cpp new/openmw-openmw-49-rc9/components/contentselector/model/contentmodel.cpp --- old/openmw-openmw-49-rc8/components/contentselector/model/contentmodel.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/contentselector/model/contentmodel.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -129,7 +129,7 @@ { if (depFile->isGameFile() && file->gameFiles().contains(depFile->fileName(), Qt::CaseInsensitive)) { - if (!depFile->builtIn() && !depFile->fromAnotherConfigFile() && !mCheckedFiles.contains(depFile)) + if (!isChecked(depFile)) break; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; @@ -215,8 +215,7 @@ if (file == mGameFile) return QVariant(); - return (file->builtIn() || file->fromAnotherConfigFile() || mCheckedFiles.contains(file)) ? Qt::Checked - : Qt::Unchecked; + return isChecked(file) ? Qt::Checked : Qt::Unchecked; } case Qt::UserRole: @@ -230,7 +229,7 @@ } case Qt::UserRole + 1: - return mCheckedFiles.contains(file); + return isChecked(file); } return QVariant(); } @@ -264,9 +263,9 @@ { int checkValue = value.toInt(); if (checkValue == Qt::Checked) - return mCheckedFiles.contains(file) || setCheckState(file, true); + return isChecked(file) || setCheckState(file, true); if (checkValue == Qt::Unchecked) - return !mCheckedFiles.contains(file) || setCheckState(file, false); + return !isChecked(file) || setCheckState(file, false); } } @@ -606,6 +605,14 @@ emit layoutChanged(); } +bool ContentSelectorModel::ContentModel::isChecked(const EsmFile* file) const +{ + if (file == nullptr) + return false; + + return file->builtIn() || file->fromAnotherConfigFile() || mCheckedFiles.contains(file); +} + bool ContentSelectorModel::ContentModel::isEnabled(const QModelIndex& index) const { return (flags(index) & Qt::ItemIsEnabled); @@ -691,7 +698,7 @@ } else { - if (!mCheckedFiles.contains(dependentFile)) + if (!isChecked(dependentFile)) { errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName)); } @@ -706,7 +713,7 @@ { // Warn the user if Bloodmoon is loaded before Tribunal (Tribunal is not a hard dependency) const EsmFile* tribunalFile = item("Tribunal.esm"); - if (tribunalFile != nullptr && mCheckedFiles.contains(tribunalFile) && row < indexFromItem(tribunalFile).row()) + if (isChecked(tribunalFile) && row < indexFromItem(tribunalFile).row()) errors.append(LoadOrderError(LoadOrderError::ErrorCode_LoadOrder, "Tribunal.esm")); } @@ -770,8 +777,9 @@ for (const QString& upstreamName : file->gameFiles()) { const EsmFile* upstreamFile = item(upstreamName); - if (upstreamFile == nullptr || !mCheckedFiles.insert(upstreamFile).second) + if (upstreamFile == nullptr || isChecked(upstreamFile)) continue; + mCheckedFiles.insert(upstreamFile); QModelIndex upstreamIndex = indexFromItem(upstreamFile); emit dataChanged(upstreamIndex, upstreamIndex); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/contentselector/model/contentmodel.hpp new/openmw-openmw-49-rc9/components/contentselector/model/contentmodel.hpp --- old/openmw-openmw-49-rc8/components/contentselector/model/contentmodel.hpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/contentselector/model/contentmodel.hpp 2025-06-23 10:59:11.000000000 +0200 @@ -58,6 +58,7 @@ QStringList gameFiles() const; void setCurrentGameFile(const EsmFile* file); + bool isChecked(const EsmFile* file) const; bool isEnabled(const QModelIndex& index) const; bool setCheckState(const EsmFile* file, bool isChecked); bool isNew(const QString& filepath) const; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/contentselector/view/contentselector.cpp new/openmw-openmw-49-rc9/components/contentselector/view/contentselector.cpp --- old/openmw-openmw-49-rc8/components/contentselector/view/contentselector.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/contentselector/view/contentselector.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -157,7 +157,7 @@ index = ui->gameFileView->findText(file->fileName()); // verify that the current index is also checked in the model - if (!mContentModel->setCheckState(file, true)) + if (!mContentModel->isChecked(file) && !mContentModel->setCheckState(file, true)) { // throw error in case file not found? return; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashcatcher.cpp new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashcatcher.cpp --- old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashcatcher.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashcatcher.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -129,6 +129,8 @@ if (mShm == nullptr) throw std::runtime_error("Failed to map crash catcher shared memory"); + mShm->mMonitorStatus = CrashSHM::Status::Uninitialised; + mShmMutex = CreateMutexW(&attributes, FALSE, NULL); if (mShmMutex == nullptr) throw std::runtime_error("Failed to create crash catcher shared memory mutex"); @@ -147,10 +149,15 @@ void CrashCatcher::waitMonitor() { - if (WaitForSingleObject(mSignalAppEvent, CrashCatcherTimeout) != WAIT_OBJECT_0) + if (!waitMonitorNoThrow()) throw std::runtime_error("Waiting for monitor failed"); } + bool CrashCatcher::waitMonitorNoThrow() + { + return WaitForSingleObject(mSignalAppEvent, CrashCatcherTimeout) == WAIT_OBJECT_0; + } + void CrashCatcher::signalMonitor() { SetEvent(mSignalMonitorEvent); @@ -234,13 +241,23 @@ signalMonitor(); - // must remain until monitor has finished - waitMonitor(); + // give monitor a chance to start dumping + // as we're suspended, this might time out even if it's successful, so mMonitorStatus is the source of truth + waitMonitorNoThrow(); - std::string message = "OpenMW has encountered a fatal error.\nCrash dump saved to '" - + Misc::StringUtils::u8StringToString(getCrashDumpPath(*mShm).u8string()) - + "'.\nPlease report this to https://gitlab.com/OpenMW/openmw/issues !"; - SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), nullptr); + shmLock(); + CrashSHM::Status monitorStatus = mShm->mMonitorStatus; + shmUnlock(); + + if (monitorStatus == CrashSHM::Status::DumpedSuccessfully) + { + std::string message = "OpenMW has encountered a fatal error.\nCrash dump saved to '" + + Misc::StringUtils::u8StringToString(getCrashDumpPath(*mShm).u8string()) + + "'.\nPlease report this to https://gitlab.com/OpenMW/openmw/issues !"; + SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), nullptr); + } + else if (monitorStatus == CrashSHM::Status::Dumping) + SDL_ShowSimpleMessageBox(0, "Fatal Error", "Timed out while creating crash dump", nullptr); } } // namespace Crash diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashcatcher.hpp new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashcatcher.hpp --- old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashcatcher.hpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashcatcher.hpp 2025-06-23 10:59:11.000000000 +0200 @@ -66,6 +66,7 @@ const std::filesystem::path& freezeDumpName); void waitMonitor(); + bool waitMonitorNoThrow(); void signalMonitor(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashmonitor.cpp new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashmonitor.cpp --- old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashmonitor.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashmonitor.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -163,6 +163,7 @@ void CrashMonitor::run() { + mShm->mMonitorStatus = CrashSHM::Status::Monitoring; try { // app waits for monitor start up, let it continue @@ -231,6 +232,18 @@ void CrashMonitor::handleCrash(bool isFreeze) { + shmLock(); + mShm->mMonitorStatus = CrashSHM::Status::Dumping; + shmUnlock(); + + auto failedDumping = [this](const std::string& message) { + Log(Debug::Error) << "CrashMonitor: " << message; + shmLock(); + mShm->mMonitorStatus = CrashSHM::Status::FailedDumping; + shmUnlock(); + SDL_ShowSimpleMessageBox(0, "Failed to create crash dump", message.c_str(), nullptr); + }; + DWORD processId = GetProcessId(mAppProcessHandle); const char* env = getenv("OPENMW_FULL_MEMDUMP"); @@ -238,7 +251,10 @@ { HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); if (dbghelp == NULL) + { + failedDumping("Could not load dbghelp.dll"); return; + } using MiniDumpWirteDumpFn = BOOL(WINAPI*)(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, @@ -246,11 +262,17 @@ MiniDumpWirteDumpFn miniDumpWriteDump = (MiniDumpWirteDumpFn)GetProcAddress(dbghelp, "MiniDumpWriteDump"); if (miniDumpWriteDump == NULL) + { + failedDumping("Could not get MiniDumpWriteDump address"); return; + } std::wstring utf16Path = (isFreeze ? getFreezeDumpPath(*mShm) : getCrashDumpPath(*mShm)).native(); if (utf16Path.empty()) + { + failedDumping("Empty dump path"); return; + } if (utf16Path.length() > MAX_PATH) utf16Path = LR"(\\?\)" + utf16Path; @@ -258,9 +280,17 @@ HANDLE hCrashLog = CreateFileW(utf16Path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (hCrashLog == NULL || hCrashLog == INVALID_HANDLE_VALUE) + { + failedDumping("Bad dump file handle"); return; + } if (auto err = GetLastError(); err != ERROR_ALREADY_EXISTS && err != 0) + { + std::stringstream ss; + ss << "Error opening dump file: " << std::hex << err; + failedDumping(ss.str()); return; + } EXCEPTION_POINTERS exp; exp.ContextRecord = &mShm->mCrashed.mContext; @@ -274,15 +304,26 @@ if (env) type = static_cast<MINIDUMP_TYPE>(type | MiniDumpWithFullMemory); - miniDumpWriteDump(mAppProcessHandle, processId, hCrashLog, type, &infos, 0, 0); + if (!miniDumpWriteDump(mAppProcessHandle, processId, hCrashLog, type, &infos, 0, 0)) + { + auto err = GetLastError(); + std::stringstream ss; + ss << "Error while writing dump: " << std::hex << err; + failedDumping(ss.str()); + return; + } + + shmLock(); + mShm->mMonitorStatus = CrashSHM::Status::DumpedSuccessfully; + shmUnlock(); } catch (const std::exception& e) { - Log(Debug::Error) << "CrashMonitor: " << e.what(); + failedDumping(e.what()); } catch (...) { - Log(Debug::Error) << "CrashMonitor: unknown exception"; + failedDumping("Unknown exception"); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashshm.hpp new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashshm.hpp --- old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashshm.hpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashshm.hpp 2025-06-23 10:59:11.000000000 +0200 @@ -22,6 +22,17 @@ Event mEvent; + enum class Status + { + Uninitialised, + Monitoring, + Dumping, + DumpedSuccessfully, + FailedDumping + }; + + Status mMonitorStatus; + struct Startup { HANDLE mAppProcessHandle; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/files/linuxpath.cpp new/openmw-openmw-49-rc9/components/files/linuxpath.cpp --- old/openmw-openmw-49-rc8/components/files/linuxpath.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/files/linuxpath.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -7,7 +7,6 @@ #include <pwd.h> #include <unistd.h> -#include <components/debug/debuglog.hpp> #include <components/misc/strings/lower.hpp> namespace @@ -51,14 +50,6 @@ LinuxPath::LinuxPath(const std::string& application_name) : mName(application_name) { - std::error_code ec; - current_path(getLocalPath(), ec); - const auto err = ec.value(); - if (err != 0) - { - Log(Debug::Warning) << "Error " << err << " " << std::generic_category().message(errno) - << " when changing current directory"; - } } std::filesystem::path LinuxPath::getUserConfigPath() const diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/files/macospath.cpp new/openmw-openmw-49-rc9/components/files/macospath.cpp --- old/openmw-openmw-49-rc8/components/files/macospath.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/files/macospath.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -64,11 +64,6 @@ MacOsPath::MacOsPath(const std::string& application_name) : mName(application_name) { - std::filesystem::path binary_path = getBinaryPath(); - std::error_code ec; - std::filesystem::current_path(binary_path.parent_path(), ec); - if (ec.value() != 0) - Log(Debug::Warning) << "Error " << ec.message() << " when changing current directory"; } std::filesystem::path MacOsPath::getUserConfigPath() const @@ -102,7 +97,7 @@ std::filesystem::path MacOsPath::getLocalPath() const { - return std::filesystem::path("../Resources/"); + return getBinaryPath().parent_path().parent_path() / "Resources"; } std::filesystem::path MacOsPath::getGlobalDataPath() const diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/files/windowspath.cpp new/openmw-openmw-49-rc9/components/files/windowspath.cpp --- old/openmw-openmw-49-rc8/components/files/windowspath.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/files/windowspath.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -26,10 +26,6 @@ WindowsPath::WindowsPath(const std::string& application_name) : mName(application_name) { - 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/lua/utilpackage.cpp new/openmw-openmw-49-rc9/components/lua/utilpackage.cpp --- old/openmw-openmw-49-rc8/components/lua/utilpackage.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/lua/utilpackage.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -237,6 +237,7 @@ colorType["asRgba"] = [](const Misc::Color& c) { return Vec4(c.r(), c.g(), c.b(), c.a()); }; colorType["asRgb"] = [](const Misc::Color& c) { return Vec3(c.r(), c.g(), c.b()); }; colorType["asHex"] = [](const Misc::Color& c) { return c.toHex(); }; + colorType[sol::meta_function::equal_to] = [](const Misc::Color& a, const Misc::Color& b) { return a == b; }; sol::table color(lua, sol::create); color["rgba"] = [](float r, float g, float b, float a) { return Misc::Color(r, g, b, a); }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/misc/color.cpp new/openmw-openmw-49-rc9/components/misc/color.cpp --- old/openmw-openmw-49-rc8/components/misc/color.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/misc/color.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -6,13 +6,12 @@ #include <sstream> #include <system_error> +#include <components/sceneutil/util.hpp> + namespace Misc { Color::Color(float r, float g, float b, float a) - : mR(std::clamp(r, 0.f, 1.f)) - , mG(std::clamp(g, 0.f, 1.f)) - , mB(std::clamp(b, 0.f, 1.f)) - , mA(std::clamp(a, 0.f, 1.f)) + : mValue(std::clamp(r, 0.f, 1.f), std::clamp(g, 0.f, 1.f), std::clamp(b, 0.f, 1.f), std::clamp(a, 0.f, 1.f)) { } @@ -27,26 +26,31 @@ { if (hex.size() != 6) throw std::logic_error(std::string("Invalid hex color: ") += hex); - std::array<float, 3> rgb; - for (size_t i = 0; i < rgb.size(); i++) + Color col; + col.mValue.a() = 1; + for (size_t i = 0; i < 3; i++) { auto sub = hex.substr(i * 2, 2); int v = 0; auto [_, ec] = std::from_chars(sub.data(), sub.data() + sub.size(), v, 16); if (ec != std::errc()) throw std::logic_error(std::string("Invalid hex color: ") += hex); - rgb[i] = v / 255.0f; + col.mValue[i] = v / 255.0f; } - return Color(rgb[0], rgb[1], rgb[2], 1); + return col; + } + + Color Color::fromRGB(unsigned int value) + { + return Color(SceneUtil::colourFromRGB(value)); } std::string Color::toHex() const { std::string result(6, '0'); - std::array<float, 3> rgb = { mR, mG, mB }; - for (size_t i = 0; i < rgb.size(); i++) + for (size_t i = 0; i < 3; i++) { - int b = static_cast<int>(rgb[i] * 255.0f); + int b = static_cast<int>(mValue[i] * 255.0f); char* start = result.data() + i * 2; if (b < 16) start++; @@ -59,6 +63,6 @@ bool operator==(const Color& l, const Color& r) { - return l.mR == r.mR && l.mG == r.mG && l.mB == r.mB && l.mA == r.mA; + return l.mValue == r.mValue; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/misc/color.hpp new/openmw-openmw-49-rc9/components/misc/color.hpp --- old/openmw-openmw-49-rc8/components/misc/color.hpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/misc/color.hpp 2025-06-23 10:59:11.000000000 +0200 @@ -3,31 +3,38 @@ #include <string> +#include <osg/Vec4> + namespace Misc { class Color { + explicit Color(osg::Vec4&& value) + : mValue(value) + { + } + public: + Color() = default; Color(float r, float g, float b, float a); - float r() const { return mR; } - float g() const { return mG; } - float b() const { return mB; } - float a() const { return mA; } + float r() const { return mValue.r(); } + float g() const { return mValue.g(); } + float b() const { return mValue.b(); } + float a() const { return mValue.a(); } std::string toString() const; static Color fromHex(std::string_view hex); + static Color fromRGB(unsigned int value); std::string toHex() const; + unsigned int toRGBA() const { return mValue.asRGBA(); } friend bool operator==(const Color& l, const Color& r); private: - float mR; - float mG; - float mB; - float mA; + osg::Vec4 mValue; }; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/components/process/processinvoker.cpp new/openmw-openmw-49-rc9/components/process/processinvoker.cpp --- old/openmw-openmw-49-rc8/components/process/processinvoker.cpp 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/components/process/processinvoker.cpp 2025-06-23 10:59:11.000000000 +0200 @@ -1,14 +1,11 @@ #include "processinvoker.hpp" +#include <QCoreApplication> #include <QDir> #include <QMessageBox> #include <QString> #include <QStringList> -#if defined(Q_OS_MAC) -#include <QCoreApplication> -#endif - Process::ProcessInvoker::ProcessInvoker(QObject* parent) : QObject(parent) { @@ -60,12 +57,9 @@ QString path(name); #ifdef Q_OS_WIN path.append(QLatin1String(".exe")); -#elif defined(Q_OS_MAC) - QDir dir(QCoreApplication::applicationDirPath()); - path = dir.absoluteFilePath(name); -#else - path.prepend(QLatin1String("./")); #endif + QDir dir(QCoreApplication::applicationDirPath()); + path = dir.absoluteFilePath(path); QFileInfo info(path); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/docs/source/reference/modding/paths.rst new/openmw-openmw-49-rc9/docs/source/reference/modding/paths.rst --- old/openmw-openmw-49-rc8/docs/source/reference/modding/paths.rst 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/docs/source/reference/modding/paths.rst 2025-06-23 10:59:11.000000000 +0200 @@ -75,6 +75,7 @@ Configuration for OpenMW is composed from several sources. From lowest to highest priority, these are: + * The local or global ``openmw.cfg``. * Any ``openmw.cfg`` files in any other directories specified with the ``config`` option. * Options specified on the command line. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/files/lua_api/openmw/core.lua new/openmw-openmw-49-rc9/files/lua_api/openmw/core.lua --- old/openmw-openmw-49-rc8/files/lua_api/openmw/core.lua 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/files/lua_api/openmw/core.lua 2025-06-23 10:59:11.000000000 +0200 @@ -635,7 +635,7 @@ -- @usage local spell = core.magic.spells.records[1] -- get by index -- @usage -- Print all powers -- for _, spell in pairs(core.magic.spells.records) do --- if spell.types == core.magic.SPELL_TYPE.Power then +-- if spell.type == core.magic.SPELL_TYPE.Power then -- print(spell.name) -- end -- end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/files/lua_api/openmw/types.lua new/openmw-openmw-49-rc9/files/lua_api/openmw/types.lua --- old/openmw-openmw-49-rc8/files/lua_api/openmw/types.lua 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/files/lua_api/openmw/types.lua 2025-06-23 10:59:11.000000000 +0200 @@ -808,8 +808,8 @@ -- A read-only list of all @{#CreatureRecord}s in the world database, may be indexed by recordId. -- Implements [iterables#List](iterables.html#List) of #CreatureRecord. -- @field [parent=#Creature] #list<#CreatureRecord> records --- @usage local record = types.NPC.classes['example_recordid'] --- @usage local record = types.NPC.classes[1] +-- @usage local creature = types.Creature.records['creature id'] -- get by id +-- @usage local creature = types.Creature.records[1] -- get by index --- -- Whether the object is a creature. @@ -876,8 +876,8 @@ -- A read-only list of all @{#NpcRecord}s in the world database, may be indexed by recordId. -- Implements [iterables#List](iterables.html#List) of #NpcRecord. -- @field [parent=#NPC] #map<#NpcRecord> records --- @usage local record = types.NPC.classes['example_recordid'] --- @usage local record = types.NPC.classes[1] +-- @usage local npc = types.NPC.records['npc id'] -- get by id +-- @usage local npc = types.NPC.records[1] -- get by index --- -- Whether the object is an NPC or a Player. @@ -1048,8 +1048,8 @@ -- A read-only list of all @{#ClassRecord}s in the world database, may be indexed by recordId. -- Implements [iterables#List](iterables.html#List) of #ClassRecord. -- @field [parent=#Classes] #list<#ClassRecord> records --- @usage local record = types.NPC.classes['example_recordid'] --- @usage local record = types.NPC.classes[1] +-- @usage local class = types.NPC.classes.records['class id'] -- get by id +-- @usage local class = types.NPC.classes.records[1] -- get by index --- -- Returns a read-only @{#ClassRecord} @@ -1088,8 +1088,8 @@ -- A read-only list of all @{#RaceRecord}s in the world database. -- Implements [iterables#List](iterables.html#List) of #RaceRecord. -- @field [parent=#Races] #list<#RaceRecord> records --- @usage local record = types.NPC.classes['example_recordid'] --- @usage local record = types.NPC.classes[1] +-- @usage local race = types.NPC.races.records['race id'] -- get by id +-- @usage local race = types.NPC.races.records[1] -- get by index --- -- Returns a read-only @{#RaceRecord} @@ -1275,8 +1275,8 @@ -- A read-only list of all @{#BirthSignRecord}s in the world database. -- Implements [iterables#List](iterables.html#List) of #BirthSignRecord. -- @field [parent=#BirthSigns] #list<#BirthSignRecord> records --- @usage local record = types.NPC.classes['example_recordid'] --- @usage local record = types.NPC.classes[1] +-- @usage local birthSign = types.Player.birthSigns.records['birthsign id'] -- get by id +-- @usage local birthSign = types.Player.birthSigns.records[1] -- get by index --- -- Returns a read-only @{#BirthSignRecord} @@ -1673,7 +1673,7 @@ -- @field #number value -- @field #number duration -- @field #number radius --- @field #number color +-- @field openmw.util#Color color -- @field #boolean isCarriable True if the light can be carried by actors and appears up in their inventory. -- @field #boolean isDynamic If true, the light will apply to actors and other moving objects -- @field #boolean isFire True if the light acts like a fire. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/files/org.openmw.cs.desktop new/openmw-openmw-49-rc9/files/org.openmw.cs.desktop --- old/openmw-openmw-49-rc8/files/org.openmw.cs.desktop 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/files/org.openmw.cs.desktop 2025-06-23 10:59:11.000000000 +0200 @@ -8,3 +8,4 @@ Exec=openmw-cs Icon=openmw-cs Categories=Game;RolePlaying; +StartupWMClass=openmw-cs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/files/org.openmw.launcher.desktop new/openmw-openmw-49-rc9/files/org.openmw.launcher.desktop --- old/openmw-openmw-49-rc8/files/org.openmw.launcher.desktop 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/files/org.openmw.launcher.desktop 2025-06-23 10:59:11.000000000 +0200 @@ -8,3 +8,4 @@ Exec=openmw-launcher Icon=openmw Categories=Game;RolePlaying; +StartupWMClass=openmw-launcher diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openmw-openmw-49-rc8/scripts/data/integration_tests/test_lua_api/global.lua new/openmw-openmw-49-rc9/scripts/data/integration_tests/test_lua_api/global.lua --- old/openmw-openmw-49-rc8/scripts/data/integration_tests/test_lua_api/global.lua 2025-06-07 00:14:32.000000000 +0200 +++ new/openmw-openmw-49-rc9/scripts/data/integration_tests/test_lua_api/global.lua 2025-06-23 10:59:11.000000000 +0200 @@ -157,7 +157,7 @@ value = 10, duration = 12, radius = 30, - color = 5, + color = util.color.hex('123456'), name = "TestLight", model = "meshes/marker_door.dae" }