From 40cba7962cb8466dc876ac4330d6e368f14df618 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 6 Jan 2025 16:43:54 +0100 Subject: [PATCH 01/98] Bump us up to 0.50.0 --- CHANGELOG.md | 4 ++++ CMakeLists.txt | 2 +- README.md | 2 +- apps/openmw/mwstate/statemanagerimp.cpp | 6 ++++-- components/esm3/formatversion.hpp | 3 ++- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fab893258f..8115cc875c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +0.50.0 +------ + + 0.49.0 ------ diff --git a/CMakeLists.txt b/CMakeLists.txt index bcb27f7649..26b1df7075 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,7 +80,7 @@ endif() message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 49) +set(OPENMW_VERSION_MINOR 50) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_LUA_API_REVISION 69) set(OPENMW_POSTPROCESSING_API_REVISION 2) diff --git a/README.md b/README.md index bca5851c7b..f65f74e9d8 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ OpenMW is an open-source open-world RPG game engine that supports playing Morrow OpenMW also comes with OpenMW-CS, a replacement for Bethesda's Construction Set. -* Version: 0.49.0 +* Version: 0.50.0 * License: GPLv3 (see [LICENSE](https://gitlab.com/OpenMW/openmw/-/raw/master/LICENSE) for more information) * Website: https://www.openmw.org * IRC: #openmw on irc.libera.chat diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 9e292a3eee..dac9776514 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -660,11 +660,13 @@ void MWState::StateManager::loadGame(const Character* character, const std::file // Report the last version still capable of reading this save if (e.getFormatVersion() <= ESM::OpenMW0_48SaveGameFormatVersion) release = "OpenMW 0.48.0"; + else if (e.getFormatVersion() <= ESM::OpenMW0_49SaveGameFormatVersion) + release = "OpenMW 0.49.0"; else { // Insert additional else if statements above to cover future releases - static_assert(ESM::MinSupportedSaveGameFormatVersion <= ESM::OpenMW0_49SaveGameFormatVersion); - release = "OpenMW 0.49.0"; + static_assert(ESM::MinSupportedSaveGameFormatVersion <= ESM::OpenMW0_50SaveGameFormatVersion); + release = "OpenMW 0.50.0"; } auto l10n = MWBase::Environment::get().getL10nManager()->getContext("OMWEngine"); std::string error = l10n->formatMessage("LoadingRequiresOldVersionError", { "version" }, { release }); diff --git a/components/esm3/formatversion.hpp b/components/esm3/formatversion.hpp index 32e245d7d1..c205f2fbb7 100644 --- a/components/esm3/formatversion.hpp +++ b/components/esm3/formatversion.hpp @@ -32,7 +32,8 @@ namespace ESM inline constexpr FormatVersion MinSupportedSaveGameFormatVersion = 5; inline constexpr FormatVersion OpenMW0_48SaveGameFormatVersion = 21; - inline constexpr FormatVersion OpenMW0_49SaveGameFormatVersion = CurrentSaveGameFormatVersion; + inline constexpr FormatVersion OpenMW0_49SaveGameFormatVersion = 34; + inline constexpr FormatVersion OpenMW0_50SaveGameFormatVersion = CurrentSaveGameFormatVersion; } #endif From 3b50bcfb3a668db7529596370b49bf8d85771e71 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 19 Jan 2025 20:07:53 +0100 Subject: [PATCH 02/98] Allow GetSpellEffects to detect enchantments by id --- apps/openmw/mwscript/miscextensions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index ed2ef756e6..95238d4299 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -884,8 +884,8 @@ namespace MWScript return; } - const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); - runtime.push(stats.getActiveSpells().isSpellActive(id)); + const auto& activeSpells = ptr.getClass().getCreatureStats(ptr).getActiveSpells(); + runtime.push(activeSpells.isSpellActive(id) || activeSpells.isEnchantmentActive(id)); } }; From a645ec0910579c15fbba3c8872dabcdf7ea043b1 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Tue, 21 Jan 2025 20:25:13 +0100 Subject: [PATCH 03/98] Allow filters to apply to creatures --- apps/openmw/mwdialogue/filter.cpp | 19 +++++++++---------- apps/openmw/mwdialogue/selectwrapper.cpp | 23 ----------------------- apps/openmw/mwdialogue/selectwrapper.hpp | 3 --- 3 files changed, 9 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 295d690ce5..e21a57aad9 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -265,10 +265,6 @@ bool MWDialogue::Filter::testFunctionLocal(const MWDialogue::SelectWrapper& sele bool MWDialogue::Filter::testSelectStruct(const SelectWrapper& select) const { - if (select.isNpcOnly() && (mActor.getType() != ESM::NPC::sRecordId)) - // If the actor is a creature, we pass all conditions only applicable to NPCs. - return true; - if (select.getFunction() == ESM::DialogueCondition::Function_Choice && mChoice == -1) // If not currently in a choice, we reject all conditions that test against choices. return false; @@ -504,7 +500,8 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons return MWBase::Environment::get().getWorld()->getCurrentWeather(); case ESM::DialogueCondition::Function_Reputation: - + if (!mActor.getClass().isNpc()) + return 0; return mActor.getClass().getNpcStats(mActor).getReputation(); case ESM::DialogueCondition::Function_FactionRankDifference: @@ -586,11 +583,11 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con case ESM::DialogueCondition::Function_NotClass: - return mActor.get()->mBase->mClass != select.getId(); + return !mActor.getClass().isNpc() || mActor.get()->mBase->mClass != select.getId(); case ESM::DialogueCondition::Function_NotRace: - return mActor.get()->mBase->mRace != select.getId(); + return !mActor.getClass().isNpc() || mActor.get()->mBase->mRace != select.getId(); case ESM::DialogueCondition::Function_NotCell: { @@ -598,12 +595,14 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con return !Misc::StringUtils::ciStartsWith(actorCell, select.getCellName()); } case ESM::DialogueCondition::Function_SameSex: - + if (!mActor.getClass().isNpc()) + return false; return (player.get()->mBase->mFlags & ESM::NPC::Female) == (mActor.get()->mBase->mFlags & ESM::NPC::Female); case ESM::DialogueCondition::Function_SameRace: - + if (!mActor.getClass().isNpc()) + return false; return mActor.get()->mBase->mRace == player.get()->mBase->mRace; case ESM::DialogueCondition::Function_SameFaction: @@ -668,7 +667,7 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con case ESM::DialogueCondition::Function_Werewolf: - return mActor.getClass().getNpcStats(mActor).isWerewolf(); + return mActor.getClass().isNpc() && mActor.getClass().getNpcStats(mActor).isWerewolf(); default: diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 02c9d29b59..f9469bf9a9 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -247,29 +247,6 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const }; } -bool MWDialogue::SelectWrapper::isNpcOnly() const -{ - switch (mSelect.mFunction) - { - case ESM::DialogueCondition::Function_NotFaction: - case ESM::DialogueCondition::Function_NotClass: - case ESM::DialogueCondition::Function_NotRace: - case ESM::DialogueCondition::Function_SameSex: - case ESM::DialogueCondition::Function_SameRace: - case ESM::DialogueCondition::Function_SameFaction: - case ESM::DialogueCondition::Function_RankRequirement: - case ESM::DialogueCondition::Function_Reputation: - case ESM::DialogueCondition::Function_FactionRankDifference: - case ESM::DialogueCondition::Function_Werewolf: - case ESM::DialogueCondition::Function_PcWerewolfKills: - case ESM::DialogueCondition::Function_FacReactionLowest: - case ESM::DialogueCondition::Function_FacReactionHighest: - return true; - default: - return false; - } -} - bool MWDialogue::SelectWrapper::selectCompare(int value) const { return selectCompareImp(mSelect, value); diff --git a/apps/openmw/mwdialogue/selectwrapper.hpp b/apps/openmw/mwdialogue/selectwrapper.hpp index d831b6cea0..d15334cbe1 100644 --- a/apps/openmw/mwdialogue/selectwrapper.hpp +++ b/apps/openmw/mwdialogue/selectwrapper.hpp @@ -28,9 +28,6 @@ namespace MWDialogue Type getType() const; - bool isNpcOnly() const; - ///< \attention Do not call any of the select functions for this select struct! - bool selectCompare(int value) const; bool selectCompare(float value) const; From 7d2dd3422dc552564321c3267267f705cb18798a Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Tue, 21 Jan 2025 20:31:12 +0100 Subject: [PATCH 04/98] Ignore missing global variables when filtering dialogue --- apps/openmw/mwdialogue/filter.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index e21a57aad9..b7d4a1361c 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -301,9 +301,13 @@ bool MWDialogue::Filter::testSelectStructNumeric(const SelectWrapper& select) co switch (select.getFunction()) { case ESM::DialogueCondition::Function_Global: - + { + const auto& world = MWBase::Environment::get().getWorld(); + if (world->getGlobalVariableType(select.getName()) == ' ') + return true; // ignore this filter if the global doesn't exist // internally all globals are float :( - return select.selectCompare(MWBase::Environment::get().getWorld()->getGlobalFloat(select.getName())); + return select.selectCompare(world->getGlobalFloat(select.getName())); + } case ESM::DialogueCondition::Function_Local: { From 0f9be64904734c217792002c1b2636ff42aec0ea Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 4 Feb 2025 09:17:31 +0300 Subject: [PATCH 05/98] Use the final effect cost to calculate enchantment price (#8340) --- apps/openmw/mwmechanics/enchanting.cpp | 27 ++++++++++++++++++++------ apps/openmw/mwmechanics/enchanting.hpp | 2 ++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 7d0007f9e3..66bef89e2c 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -185,18 +185,18 @@ namespace MWMechanics * * Formula on UESPWiki is not entirely correct. */ - float Enchanting::getEnchantPoints(bool precise) const + std::vector Enchanting::getEffectCosts() const { + std::vector costs; if (mEffectList.mList.empty()) - // No effects added, cost = 0 - return 0; + return costs; + costs.reserve(mEffectList.mList.size()); const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); const float fEffectCostMult = store.get().find("fEffectCostMult")->mValue.getFloat(); const float fEnchantmentConstantDurationMult = store.get().find("fEnchantmentConstantDurationMult")->mValue.getFloat(); - float enchantmentCost = 0.f; float cost = 0.f; for (const ESM::IndexedENAMstruct& effect : mEffectList.mList) { @@ -215,9 +215,18 @@ namespace MWMechanics if (effect.mData.mRange == ESM::RT_Target) cost *= 1.5f; - enchantmentCost += precise ? cost : std::floor(cost); + costs.push_back(cost); } + return costs; + } + + float Enchanting::getEnchantPoints(bool precise) const + { + float enchantmentCost = 0.f; + for (float cost : getEffectCosts()) + enchantmentCost += precise ? cost : std::floor(cost); + return enchantmentCost; } @@ -278,13 +287,19 @@ namespace MWMechanics if (mEnchanter.isEmpty()) return 0; + // Use the final effect's accumulated cost + float finalEffectCost = 0.f; + std::vector effectCosts = getEffectCosts(); + if (!effectCosts.empty()) + finalEffectCost = effectCosts.back(); + float priceMultipler = MWBase::Environment::get() .getESMStore() ->get() .find("fEnchantmentValueMult") ->mValue.getFloat(); int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer( - mEnchanter, static_cast(getEnchantPoints() * priceMultipler), true); + mEnchanter, static_cast(finalEffectCost * priceMultipler), true); price *= count * getTypeMultiplier(); return std::max(1, price); } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 5db02b8cba..98e0982f7c 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -2,6 +2,7 @@ #define GAME_MWMECHANICS_ENCHANTING_H #include +#include #include #include @@ -32,6 +33,7 @@ namespace MWMechanics float getTypeMultiplier() const; void payForEnchantment(int count) const; int getEnchantPrice(int count) const; + std::vector getEffectCosts() const; public: Enchanting(); From 1a9e29844b663dfde8b93f19e6adf25cd0da1c4f Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Wed, 12 Feb 2025 23:12:07 +0300 Subject: [PATCH 06/98] Implement TCB interpolation for vectors and scalars (#2379) --- components/nif/nifkey.hpp | 94 ++++++++++++++++++++++++-------- components/nifosg/controller.hpp | 2 +- 2 files changed, 72 insertions(+), 24 deletions(-) diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index 604cf92c33..bd362101c6 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -3,7 +3,9 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP #define OPENMW_COMPONENTS_NIF_NIFKEY_HPP +#include #include +#include #include "exception.hpp" #include "niffile.hpp" @@ -17,7 +19,7 @@ namespace Nif InterpolationType_Unknown = 0, InterpolationType_Linear = 1, InterpolationType_Quadratic = 2, - InterpolationType_TBC = 3, + InterpolationType_TCB = 3, InterpolationType_XYZ = 4, InterpolationType_Constant = 5 }; @@ -28,18 +30,19 @@ namespace Nif T mValue; T mInTan; // Only for Quadratic interpolation, and never for QuaternionKeyList T mOutTan; // Only for Quadratic interpolation, and never for QuaternionKeyList - - // FIXME: Implement TBC interpolation - /* - float mTension; // Only for TBC interpolation - float mBias; // Only for TBC interpolation - float mContinuity; // Only for TBC interpolation - */ }; - using FloatKey = KeyT; - using Vector3Key = KeyT; - using Vector4Key = KeyT; - using QuaternionKey = KeyT; + + template + struct TCBKey + { + float mTime; + T mValue{}; + T mInTan{}; + T mOutTan{}; + float mTension; + float mContinuity; + float mBias; + }; template struct KeyMapT @@ -101,15 +104,20 @@ namespace Nif mKeys[time] = key; } } - else if (mInterpolationType == InterpolationType_TBC) + else if (mInterpolationType == InterpolationType_TCB) { - for (size_t i = 0; i < count; i++) + std::vector> tcbKeys(count); + for (TCBKey& key : tcbKeys) { - float time; - nif->read(time); - readTBC(*nif, key); - mKeys[time] = key; + nif->read(key.mTime); + key.mValue = ((*nif).*getValue)(); + nif->read(key.mTension); + nif->read(key.mContinuity); + nif->read(key.mBias); } + generateTCBTangents(tcbKeys); + for (TCBKey& key : tcbKeys) + mKeys[key.mTime] = KeyType{ std::move(key.mValue), std::move(key.mInTan), std::move(key.mOutTan) }; } else if (mInterpolationType == InterpolationType_XYZ) { @@ -140,12 +148,52 @@ namespace Nif static void readQuadratic(NIFStream& nif, KeyT& key) { readValue(nif, key); } - static void readTBC(NIFStream& nif, KeyT& key) + template + static void generateTCBTangents(std::vector>& keys) { - readValue(nif, key); - /*key.mTension = */ nif.get(); - /*key.mBias = */ nif.get(); - /*key.mContinuity = */ nif.get(); + if (keys.size() <= 1) + return; + + std::sort(keys.begin(), keys.end(), [](const auto& a, const auto& b) { return a.mTime < b.mTime; }); + for (size_t i = 0; i < keys.size(); ++i) + { + TCBKey& curr = keys[i]; + const TCBKey& prev = (i == 0) ? curr : keys[i - 1]; + const TCBKey& next = (i == keys.size() - 1) ? curr : keys[i + 1]; + const float prevLen = curr.mTime - prev.mTime; + const float nextLen = next.mTime - curr.mTime; + if (prevLen + nextLen <= 0.f) + continue; + + const U prevDelta = curr.mValue - prev.mValue; + const U nextDelta = next.mValue - curr.mValue; + const float t = curr.mTension; + const float c = curr.mContinuity; + const float b = curr.mBias; + + U x{}, y{}, z{}, w{}; + if (prevLen > 0.f) + x = prevDelta / prevLen * (1 - t) * (1 - c) * (1 + b); + if (nextLen > 0.f) + y = nextDelta / nextLen * (1 - t) * (1 + c) * (1 - b); + if (prevLen > 0.f) + z = prevDelta / prevLen * (1 - t) * (1 + c) * (1 + b); + if (nextLen > 0.f) + w = nextDelta / nextLen * (1 - t) * (1 - c) * (1 - b); + + curr.mInTan = (x + y) * prevLen / (prevLen + nextLen); + curr.mOutTan = (z + w) * nextLen / (prevLen + nextLen); + } + } + + static void generateTCBTangents(std::vector>& keys) + { + // TODO: is this even legal? + } + + static void generateTCBTangents(std::vector>& keys) + { + // TODO: implement TCB interpolation for quaternions } }; using FloatKeyMap = KeyMapT>; diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 99d3df9545..468668ce76 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -131,6 +131,7 @@ namespace NifOsg case Nif::InterpolationType_Constant: return fraction > 0.5f ? b.mValue : a.mValue; case Nif::InterpolationType_Quadratic: + case Nif::InterpolationType_TCB: { // Using a cubic Hermite spline. // b1(t) = 2t^3 - 3t^2 + 1 @@ -147,7 +148,6 @@ namespace NifOsg const float b4 = t3 - t2; return a.mValue * b1 + b.mValue * b2 + a.mOutTan * b3 + b.mInTan * b4; } - // TODO: Implement TBC interpolation default: return a.mValue + ((b.mValue - a.mValue) * fraction); } From 0254feefe381227709f5a0ace05fb1f704d3e3fe Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 20:32:49 +0300 Subject: [PATCH 07/98] Rename bsa_file.cpp/hpp to follow naming conventions --- CI/file_name_exceptions.txt | 2 -- components/CMakeLists.txt | 2 +- components/bsa/ba2dx10file.hpp | 2 +- components/bsa/ba2gnrlfile.hpp | 2 +- components/bsa/{bsa_file.cpp => bsafile.cpp} | 4 ++-- components/bsa/{bsa_file.hpp => bsafile.hpp} | 2 +- components/bsa/compressedbsafile.hpp | 4 ++-- components/vfs/bsaarchive.hpp | 2 +- 8 files changed, 9 insertions(+), 11 deletions(-) rename components/bsa/{bsa_file.cpp => bsafile.cpp} (99%) rename components/bsa/{bsa_file.hpp => bsafile.hpp} (98%) diff --git a/CI/file_name_exceptions.txt b/CI/file_name_exceptions.txt index 14d106169b..f1dcf0f38f 100644 --- a/CI/file_name_exceptions.txt +++ b/CI/file_name_exceptions.txt @@ -28,8 +28,6 @@ apps/openmw_tests/mwdialogue/test_keywordsearch.cpp apps/openmw_tests/mwscript/test_scripts.cpp apps/openmw_tests/mwscript/test_utils.hpp apps/openmw_tests/mwworld/test_store.cpp -components/bsa/bsa_file.cpp -components/bsa/bsa_file.hpp components/crashcatcher/windows_crashcatcher.cpp components/crashcatcher/windows_crashcatcher.hpp components/crashcatcher/windows_crashmonitor.cpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b6734e6fc6..83270f3c6f 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -111,7 +111,7 @@ add_component_dir (bgsm ) add_component_dir (bsa - bsa_file compressedbsafile ba2gnrlfile ba2dx10file ba2file memorystream + bsafile compressedbsafile ba2gnrlfile ba2dx10file ba2file memorystream ) add_component_dir (bullethelpers diff --git a/components/bsa/ba2dx10file.hpp b/components/bsa/ba2dx10file.hpp index 59db10745b..5d4249365b 100644 --- a/components/bsa/ba2dx10file.hpp +++ b/components/bsa/ba2dx10file.hpp @@ -7,7 +7,7 @@ #include #include -#include +#include "bsafile.hpp" namespace Bsa { diff --git a/components/bsa/ba2gnrlfile.hpp b/components/bsa/ba2gnrlfile.hpp index 6a212c5e81..5f1f21dec9 100644 --- a/components/bsa/ba2gnrlfile.hpp +++ b/components/bsa/ba2gnrlfile.hpp @@ -6,7 +6,7 @@ #include #include -#include +#include "bsafile.hpp" namespace Bsa { diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsafile.cpp similarity index 99% rename from components/bsa/bsa_file.cpp rename to components/bsa/bsafile.cpp index 46639a729e..03ee185e9e 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsafile.cpp @@ -4,7 +4,7 @@ Email: < korslund@gmail.com > WWW: https://openmw.org/ - This file (bsa_file.cpp) is part of the OpenMW package. + This file (bsafile.cpp) is part of the OpenMW package. OpenMW is distributed as free software: you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -21,7 +21,7 @@ */ -#include "bsa_file.hpp" +#include "bsafile.hpp" #include #include diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsafile.hpp similarity index 98% rename from components/bsa/bsa_file.hpp rename to components/bsa/bsafile.hpp index 03a0703885..9e79df85a1 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsafile.hpp @@ -4,7 +4,7 @@ Email: < korslund@gmail.com > WWW: https://openmw.org/ - This file (bsa_file.h) is part of the OpenMW package. + This file (bsafile.hpp) is part of the OpenMW package. OpenMW is distributed as free software: you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/components/bsa/compressedbsafile.hpp b/components/bsa/compressedbsafile.hpp index 8fa5c9a62a..1179dcc00b 100644 --- a/components/bsa/compressedbsafile.hpp +++ b/components/bsa/compressedbsafile.hpp @@ -26,11 +26,11 @@ #ifndef BSA_COMPRESSED_BSA_FILE_H #define BSA_COMPRESSED_BSA_FILE_H +#include #include #include -#include -#include +#include "bsafile.hpp" namespace Bsa { diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index 664466fa40..2e6fac6558 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include From 8b911ce3eb29002f7b4c3eaf921066cccad32a26 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 21:00:40 +0300 Subject: [PATCH 08/98] Rename components/fx files to follow naming conventions --- CI/file_name_exceptions.txt | 2 -- components/CMakeLists.txt | 2 +- components/fx/lexer.cpp | 1 - components/fx/lexer.hpp | 2 +- components/fx/{lexer_types.hpp => lexertypes.hpp} | 6 +++--- components/fx/{parse_constants.hpp => parseconstants.hpp} | 4 ++-- components/fx/technique.cpp | 2 +- 7 files changed, 8 insertions(+), 11 deletions(-) rename components/fx/{lexer_types.hpp => lexertypes.hpp} (98%) rename components/fx/{parse_constants.hpp => parseconstants.hpp} (98%) diff --git a/CI/file_name_exceptions.txt b/CI/file_name_exceptions.txt index f1dcf0f38f..0923a70567 100644 --- a/CI/file_name_exceptions.txt +++ b/CI/file_name_exceptions.txt @@ -33,8 +33,6 @@ components/crashcatcher/windows_crashcatcher.hpp components/crashcatcher/windows_crashmonitor.cpp components/crashcatcher/windows_crashmonitor.hpp components/crashcatcher/windows_crashshm.hpp -components/fx/lexer_types.hpp -components/fx/parse_constants.hpp components/platform/file.posix.cpp components/platform/file.stdio.cpp components/platform/file.win32.cpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 83270f3c6f..ccf3a329b3 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -173,7 +173,7 @@ add_component_dir(esm attr common defs esmcommon records util luascripts format exteriorcelllocation ) -add_component_dir(fx pass technique lexer lexer_types parse_constants widgets stateupdater) +add_component_dir(fx pass technique lexer lexertypes parseconstants widgets stateupdater) add_component_dir(std140 ubo) diff --git a/components/fx/lexer.cpp b/components/fx/lexer.cpp index 6140c7375c..2fc25e44f1 100644 --- a/components/fx/lexer.cpp +++ b/components/fx/lexer.cpp @@ -6,7 +6,6 @@ #include #include -#include #include namespace fx diff --git a/components/fx/lexer.hpp b/components/fx/lexer.hpp index fc7d4ec9d7..adc8974904 100644 --- a/components/fx/lexer.hpp +++ b/components/fx/lexer.hpp @@ -7,7 +7,7 @@ #include #include -#include "lexer_types.hpp" +#include "lexertypes.hpp" namespace fx { diff --git a/components/fx/lexer_types.hpp b/components/fx/lexertypes.hpp similarity index 98% rename from components/fx/lexer_types.hpp rename to components/fx/lexertypes.hpp index 9fe13ac827..c0df1a9da8 100644 --- a/components/fx/lexer_types.hpp +++ b/components/fx/lexertypes.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_COMPONENTS_FX_LEXER_TYPES_H -#define OPENMW_COMPONENTS_FX_LEXER_TYPES_H +#ifndef OPENMW_COMPONENTS_FX_LEXERTYPES_H +#define OPENMW_COMPONENTS_FX_LEXERTYPES_H #include #include @@ -165,4 +165,4 @@ namespace fx } } -#endif \ No newline at end of file +#endif diff --git a/components/fx/parse_constants.hpp b/components/fx/parseconstants.hpp similarity index 98% rename from components/fx/parse_constants.hpp rename to components/fx/parseconstants.hpp index 2057476f3e..412a19980b 100644 --- a/components/fx/parse_constants.hpp +++ b/components/fx/parseconstants.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_COMPONENTS_FX_PARSE_CONSTANTS_H -#define OPENMW_COMPONENTS_FX_PARSE_CONSTANTS_H +#ifndef OPENMW_COMPONENTS_FX_PARSECONSTANTS_H +#define OPENMW_COMPONENTS_FX_PARSECONSTANTS_H #include #include diff --git a/components/fx/technique.cpp b/components/fx/technique.cpp index 5963e274ec..b0b7f282aa 100644 --- a/components/fx/technique.cpp +++ b/components/fx/technique.cpp @@ -17,7 +17,7 @@ #include #include -#include "parse_constants.hpp" +#include "parseconstants.hpp" namespace { From 5d5595cc5ba130b9c8326b6e7ec776ce01d667f0 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 21:12:28 +0300 Subject: [PATCH 09/98] Standardize components/bsa file include guards and order --- components/bsa/ba2dx10file.cpp | 6 ++++-- components/bsa/ba2dx10file.hpp | 4 ++-- components/bsa/ba2file.hpp | 4 ++-- components/bsa/ba2gnrlfile.cpp | 6 ++++-- components/bsa/ba2gnrlfile.hpp | 4 ++-- components/bsa/bsafile.cpp | 6 +++--- components/bsa/bsafile.hpp | 4 ++-- components/bsa/compressedbsafile.cpp | 4 +++- components/bsa/compressedbsafile.hpp | 4 ++-- components/bsa/memorystream.hpp | 7 ++++--- 10 files changed, 28 insertions(+), 21 deletions(-) diff --git a/components/bsa/ba2dx10file.cpp b/components/bsa/ba2dx10file.cpp index 502ca043ab..a438121d5b 100644 --- a/components/bsa/ba2dx10file.cpp +++ b/components/bsa/ba2dx10file.cpp @@ -24,13 +24,15 @@ #endif #include -#include -#include + #include #include #include #include +#include "ba2file.hpp" +#include "memorystream.hpp" + namespace Bsa { BA2DX10File::BA2DX10File() {} diff --git a/components/bsa/ba2dx10file.hpp b/components/bsa/ba2dx10file.hpp index 5d4249365b..cd1f822179 100644 --- a/components/bsa/ba2dx10file.hpp +++ b/components/bsa/ba2dx10file.hpp @@ -1,5 +1,5 @@ -#ifndef BSA_BA2_DX10_FILE_H -#define BSA_BA2_DX10_FILE_H +#ifndef OPENMW_COMPONENTS_BSA_BA2DX10FILE_HPP +#define OPENMW_COMPONENTS_BSA_BA2DX10FILE_HPP #include #include diff --git a/components/bsa/ba2file.hpp b/components/bsa/ba2file.hpp index 9a68d3afd0..0d51be4c0e 100644 --- a/components/bsa/ba2file.hpp +++ b/components/bsa/ba2file.hpp @@ -1,5 +1,5 @@ -#ifndef BSA_BA2_FILE_H -#define BSA_BA2_FILE_H +#ifndef OPENMW_COMPONENTS_BSA_BA2FILE_HPP +#define OPENMW_COMPONENTS_BSA_BA2FILE_HPP #include #include diff --git a/components/bsa/ba2gnrlfile.cpp b/components/bsa/ba2gnrlfile.cpp index 63dd3d1d50..75e7305245 100644 --- a/components/bsa/ba2gnrlfile.cpp +++ b/components/bsa/ba2gnrlfile.cpp @@ -22,13 +22,15 @@ #endif #include -#include -#include + #include #include #include #include +#include "ba2file.hpp" +#include "memorystream.hpp" + namespace Bsa { // special marker for invalid records, diff --git a/components/bsa/ba2gnrlfile.hpp b/components/bsa/ba2gnrlfile.hpp index 5f1f21dec9..0bc94eae0e 100644 --- a/components/bsa/ba2gnrlfile.hpp +++ b/components/bsa/ba2gnrlfile.hpp @@ -1,5 +1,5 @@ -#ifndef BSA_BA2_GNRL_FILE_H -#define BSA_BA2_GNRL_FILE_H +#ifndef OPENMW_COMPONENTS_BSA_BA2GNRLFILE_HPP +#define OPENMW_COMPONENTS_BSA_BA2GNRLFILE_HPP #include #include diff --git a/components/bsa/bsafile.cpp b/components/bsa/bsafile.cpp index 03ee185e9e..948b9dac8d 100644 --- a/components/bsa/bsafile.cpp +++ b/components/bsa/bsafile.cpp @@ -23,15 +23,15 @@ #include "bsafile.hpp" -#include -#include - #include #include #include #include #include +#include +#include + using namespace Bsa; /// Error handling diff --git a/components/bsa/bsafile.hpp b/components/bsa/bsafile.hpp index 9e79df85a1..ad7acdad17 100644 --- a/components/bsa/bsafile.hpp +++ b/components/bsa/bsafile.hpp @@ -21,8 +21,8 @@ */ -#ifndef BSA_BSA_FILE_H -#define BSA_BSA_FILE_H +#ifndef OPENMW_COMPONENTS_BSA_BSAFILE_HPP +#define OPENMW_COMPONENTS_BSA_BSAFILE_HPP #include #include diff --git a/components/bsa/compressedbsafile.cpp b/components/bsa/compressedbsafile.cpp index 14d90f5d91..8426c5965c 100644 --- a/components/bsa/compressedbsafile.cpp +++ b/components/bsa/compressedbsafile.cpp @@ -45,11 +45,13 @@ #endif #include -#include + #include #include #include +#include "memorystream.hpp" + namespace Bsa { /// Read header information from the input source diff --git a/components/bsa/compressedbsafile.hpp b/components/bsa/compressedbsafile.hpp index 1179dcc00b..83620f11bc 100644 --- a/components/bsa/compressedbsafile.hpp +++ b/components/bsa/compressedbsafile.hpp @@ -23,8 +23,8 @@ */ -#ifndef BSA_COMPRESSED_BSA_FILE_H -#define BSA_COMPRESSED_BSA_FILE_H +#ifndef OPENMW_COMPONENTS_BSA_COMPRESSEDBSAFILE_HPP +#define OPENMW_COMPONENTS_BSA_COMPRESSEDBSAFILE_HPP #include #include diff --git a/components/bsa/memorystream.hpp b/components/bsa/memorystream.hpp index 5662dde8ff..945d0b33d9 100644 --- a/components/bsa/memorystream.hpp +++ b/components/bsa/memorystream.hpp @@ -23,13 +23,14 @@ */ -#ifndef BSA_MEMORY_STREAM_H -#define BSA_MEMORY_STREAM_H +#ifndef OPENMW_COMPONENTS_BSA_MEMORYSTREAM_HPP +#define OPENMW_COMPONENTS_BSA_MEMORYSTREAM_HPP -#include #include #include +#include + namespace Bsa { /** From 3793ff8be882da974e654789c4f6808faafab62d Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 21:14:58 +0300 Subject: [PATCH 10/98] Standardize components/fx file include guards --- components/fx/lexer.hpp | 4 ++-- components/fx/lexertypes.hpp | 4 ++-- components/fx/parseconstants.hpp | 4 ++-- components/fx/pass.hpp | 4 ++-- components/fx/technique.hpp | 4 ++-- components/fx/types.hpp | 4 ++-- components/fx/widgets.hpp | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/components/fx/lexer.hpp b/components/fx/lexer.hpp index adc8974904..dda6b3a0f6 100644 --- a/components/fx/lexer.hpp +++ b/components/fx/lexer.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_COMPONENTS_FX_LEXER_H -#define OPENMW_COMPONENTS_FX_LEXER_H +#ifndef OPENMW_COMPONENTS_FX_LEXER_HPP +#define OPENMW_COMPONENTS_FX_LEXER_HPP #include #include diff --git a/components/fx/lexertypes.hpp b/components/fx/lexertypes.hpp index c0df1a9da8..2a56a84a1a 100644 --- a/components/fx/lexertypes.hpp +++ b/components/fx/lexertypes.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_COMPONENTS_FX_LEXERTYPES_H -#define OPENMW_COMPONENTS_FX_LEXERTYPES_H +#ifndef OPENMW_COMPONENTS_FX_LEXERTYPES_HPP +#define OPENMW_COMPONENTS_FX_LEXERTYPES_HPP #include #include diff --git a/components/fx/parseconstants.hpp b/components/fx/parseconstants.hpp index 412a19980b..3ad9abd959 100644 --- a/components/fx/parseconstants.hpp +++ b/components/fx/parseconstants.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_COMPONENTS_FX_PARSECONSTANTS_H -#define OPENMW_COMPONENTS_FX_PARSECONSTANTS_H +#ifndef OPENMW_COMPONENTS_FX_PARSECONSTANTS_HPP +#define OPENMW_COMPONENTS_FX_PARSECONSTANTS_HPP #include #include diff --git a/components/fx/pass.hpp b/components/fx/pass.hpp index e176afc699..1c417ac8cf 100644 --- a/components/fx/pass.hpp +++ b/components/fx/pass.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_COMPONENTS_FX_PASS_H -#define OPENMW_COMPONENTS_FX_PASS_H +#ifndef OPENMW_COMPONENTS_FX_PASS_HPP +#define OPENMW_COMPONENTS_FX_PASS_HPP #include #include diff --git a/components/fx/technique.hpp b/components/fx/technique.hpp index 2778763a9a..ad5e876faa 100644 --- a/components/fx/technique.hpp +++ b/components/fx/technique.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_COMPONENTS_FX_TECHNIQUE_H -#define OPENMW_COMPONENTS_FX_TECHNIQUE_H +#ifndef OPENMW_COMPONENTS_FX_TECHNIQUE_HPP +#define OPENMW_COMPONENTS_FX_TECHNIQUE_HPP #include #include diff --git a/components/fx/types.hpp b/components/fx/types.hpp index 596b54c217..1536cda115 100644 --- a/components/fx/types.hpp +++ b/components/fx/types.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_COMPONENTS_FX_TYPES_H -#define OPENMW_COMPONENTS_FX_TYPES_H +#ifndef OPENMW_COMPONENTS_FX_TYPES_HPP +#define OPENMW_COMPONENTS_FX_TYPES_HPP #include #include diff --git a/components/fx/widgets.hpp b/components/fx/widgets.hpp index 6217af7fee..59787ed9aa 100644 --- a/components/fx/widgets.hpp +++ b/components/fx/widgets.hpp @@ -1,5 +1,5 @@ -#ifndef OPENMW_COMPONENTS_FX_WIDGETS_H -#define OPENMW_COMPONENTS_FX_WIDGETS_H +#ifndef OPENMW_COMPONENTS_FX_WIDGETS_HPP +#define OPENMW_COMPONENTS_FX_WIDGETS_HPP #include #include From 7df74664e43cca949e1c57230e34f1bbc2747030 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 21:44:58 +0300 Subject: [PATCH 11/98] Rename gl4es-init.cpp/h to follow naming conventions --- CI/file_name_exceptions.txt | 2 -- components/CMakeLists.txt | 2 +- components/sdlutil/{gl4es_init.cpp => gl4esinit.cpp} | 2 +- components/sdlutil/{gl4es_init.h => gl4esinit.h} | 6 +++--- components/sdlutil/sdlgraphicswindow.cpp | 2 +- 5 files changed, 6 insertions(+), 8 deletions(-) rename components/sdlutil/{gl4es_init.cpp => gl4esinit.cpp} (97%) rename components/sdlutil/{gl4es_init.h => gl4esinit.h} (67%) diff --git a/CI/file_name_exceptions.txt b/CI/file_name_exceptions.txt index 0923a70567..6ae56912dd 100644 --- a/CI/file_name_exceptions.txt +++ b/CI/file_name_exceptions.txt @@ -36,8 +36,6 @@ components/crashcatcher/windows_crashshm.hpp components/platform/file.posix.cpp components/platform/file.stdio.cpp components/platform/file.win32.cpp -components/sdlutil/gl4es_init.cpp -components/sdlutil/gl4es_init.h components/to_utf8/gen_iconv.cpp components/to_utf8/tables_gen.hpp components/to_utf8/to_utf8.cpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index ccf3a329b3..da91cec7ef 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -362,7 +362,7 @@ add_component_dir (fontloader add_component_dir (sdlutil events - gl4es_init + gl4esinit imagetosurface sdlcursormanager sdlgraphicswindow diff --git a/components/sdlutil/gl4es_init.cpp b/components/sdlutil/gl4esinit.cpp similarity index 97% rename from components/sdlutil/gl4es_init.cpp rename to components/sdlutil/gl4esinit.cpp index 044b54ce02..13015dee82 100644 --- a/components/sdlutil/gl4es_init.cpp +++ b/components/sdlutil/gl4esinit.cpp @@ -1,7 +1,7 @@ // EGL does not work reliably for feature detection. // Instead, we initialize gl4es manually. #ifdef OPENMW_GL4ES_MANUAL_INIT -#include "gl4es_init.h" +#include "gl4esinit.h" // For glHint #include diff --git a/components/sdlutil/gl4es_init.h b/components/sdlutil/gl4esinit.h similarity index 67% rename from components/sdlutil/gl4es_init.h rename to components/sdlutil/gl4esinit.h index 6a19d3dfe5..8916d50a7e 100644 --- a/components/sdlutil/gl4es_init.h +++ b/components/sdlutil/gl4esinit.h @@ -1,5 +1,5 @@ -#ifndef OPENMW_COMPONENTS_SDLUTIL_GL4ES_INIT_H -#define OPENMW_COMPONENTS_SDLUTIL_GL4ES_INIT_H +#ifndef OPENMW_COMPONENTS_SDLUTIL_GL4ESINIT_H +#define OPENMW_COMPONENTS_SDLUTIL_GL4ESINIT_H #ifdef OPENMW_GL4ES_MANUAL_INIT #include @@ -10,4 +10,4 @@ extern "C" void openmw_gl4es_init(SDL_Window* window); #endif // OPENMW_GL4ES_MANUAL_INIT -#endif // OPENMW_COMPONENTS_SDLUTIL_GL4ES_INIT_H +#endif // OPENMW_COMPONENTS_SDLUTIL_GL4ESINIT_H diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index 36947460df..9ff0545930 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -3,7 +3,7 @@ #include #ifdef OPENMW_GL4ES_MANUAL_INIT -#include "gl4es_init.h" +#include "gl4esinit.h" #endif namespace SDLUtil From b997386cd3865c181ba14e41da15565f7af97cd5 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 21:53:24 +0300 Subject: [PATCH 12/98] Rename android-main.cpp to follow naming conventions --- CI/file_name_exceptions.txt | 1 - apps/openmw/CMakeLists.txt | 4 ++-- apps/openmw/{android_main.cpp => androidmain.cpp} | 0 3 files changed, 2 insertions(+), 3 deletions(-) rename apps/openmw/{android_main.cpp => androidmain.cpp} (100%) diff --git a/CI/file_name_exceptions.txt b/CI/file_name_exceptions.txt index 6ae56912dd..f4c12f19a3 100644 --- a/CI/file_name_exceptions.txt +++ b/CI/file_name_exceptions.txt @@ -1,4 +1,3 @@ -apps/openmw/android_main.cpp apps/openmw/mwsound/efx-presets.h apps/openmw/mwsound/ffmpeg_decoder.cpp apps/openmw/mwsound/ffmpeg_decoder.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 37de0abeab..37e9b39a01 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -15,7 +15,7 @@ set(OPENMW_HEADERS profile.hpp ) -source_group(apps/openmw FILES main.cpp android_main.cpp ${OPENMW_SOURCES} ${OPENMW_HEADERS} ${OPENMW_RESOURCES}) +source_group(apps/openmw FILES main.cpp androidmain.cpp ${OPENMW_SOURCES} ${OPENMW_HEADERS} ${OPENMW_RESOURCES}) add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky skyutil npcanimation esm4npcanimation vismask @@ -127,7 +127,7 @@ if(BUILD_OPENMW) if (ANDROID) add_library(openmw SHARED main.cpp - android_main.cpp + androidmain.cpp ) else() openmw_add_executable(openmw diff --git a/apps/openmw/android_main.cpp b/apps/openmw/androidmain.cpp similarity index 100% rename from apps/openmw/android_main.cpp rename to apps/openmw/androidmain.cpp From dd16c870808997867d757538d91ca47c654c6bd2 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 21:59:55 +0300 Subject: [PATCH 13/98] Rename components/platform files to follow naming conventions --- CI/file_name_exceptions.txt | 3 --- components/CMakeLists.txt | 6 +++--- components/platform/{file.posix.cpp => fileposix.cpp} | 0 components/platform/{file.stdio.cpp => filestdio.cpp} | 0 components/platform/{file.win32.cpp => filewin32.cpp} | 0 5 files changed, 3 insertions(+), 6 deletions(-) rename components/platform/{file.posix.cpp => fileposix.cpp} (100%) rename components/platform/{file.stdio.cpp => filestdio.cpp} (100%) rename components/platform/{file.win32.cpp => filewin32.cpp} (100%) diff --git a/CI/file_name_exceptions.txt b/CI/file_name_exceptions.txt index f4c12f19a3..185b4ba995 100644 --- a/CI/file_name_exceptions.txt +++ b/CI/file_name_exceptions.txt @@ -32,9 +32,6 @@ components/crashcatcher/windows_crashcatcher.hpp components/crashcatcher/windows_crashmonitor.cpp components/crashcatcher/windows_crashmonitor.hpp components/crashcatcher/windows_crashshm.hpp -components/platform/file.posix.cpp -components/platform/file.stdio.cpp -components/platform/file.win32.cpp components/to_utf8/gen_iconv.cpp components/to_utf8/tables_gen.hpp components/to_utf8/to_utf8.cpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index da91cec7ef..d57b0ed823 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -500,15 +500,15 @@ add_component_dir(platform if (WIN32) add_component_dir(platform - file.win32 + filewin32 ) elseif (UNIX) add_component_dir(platform - file.posix + fileposix ) else () add_component_dir(platform - file.stdio + filestdio ) endif() diff --git a/components/platform/file.posix.cpp b/components/platform/fileposix.cpp similarity index 100% rename from components/platform/file.posix.cpp rename to components/platform/fileposix.cpp diff --git a/components/platform/file.stdio.cpp b/components/platform/filestdio.cpp similarity index 100% rename from components/platform/file.stdio.cpp rename to components/platform/filestdio.cpp diff --git a/components/platform/file.win32.cpp b/components/platform/filewin32.cpp similarity index 100% rename from components/platform/file.win32.cpp rename to components/platform/filewin32.cpp From a3e19f9bb7a8192704fe5297c2f98d99f068746b Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 22:04:27 +0300 Subject: [PATCH 14/98] Rename apps/openmw_tests files to follow naming conventions --- CI/file_name_exceptions.txt | 4 ---- apps/openmw_tests/CMakeLists.txt | 6 +++--- .../{test_keywordsearch.cpp => testkeywordsearch.cpp} | 0 .../mwscript/{test_scripts.cpp => testscripts.cpp} | 4 ++-- .../openmw_tests/mwscript/{test_utils.hpp => testutils.hpp} | 0 apps/openmw_tests/mwworld/{test_store.cpp => teststore.cpp} | 0 6 files changed, 5 insertions(+), 9 deletions(-) rename apps/openmw_tests/mwdialogue/{test_keywordsearch.cpp => testkeywordsearch.cpp} (100%) rename apps/openmw_tests/mwscript/{test_scripts.cpp => testscripts.cpp} (99%) rename apps/openmw_tests/mwscript/{test_utils.hpp => testutils.hpp} (100%) rename apps/openmw_tests/mwworld/{test_store.cpp => teststore.cpp} (100%) diff --git a/CI/file_name_exceptions.txt b/CI/file_name_exceptions.txt index 185b4ba995..424dc3f691 100644 --- a/CI/file_name_exceptions.txt +++ b/CI/file_name_exceptions.txt @@ -23,10 +23,6 @@ apps/components_tests/lua/test_yaml.cpp apps/components_tests/misc/test_endianness.cpp apps/components_tests/misc/test_resourcehelpers.cpp apps/components_tests/misc/test_stringops.cpp -apps/openmw_tests/mwdialogue/test_keywordsearch.cpp -apps/openmw_tests/mwscript/test_scripts.cpp -apps/openmw_tests/mwscript/test_utils.hpp -apps/openmw_tests/mwworld/test_store.cpp components/crashcatcher/windows_crashcatcher.cpp components/crashcatcher/windows_crashcatcher.hpp components/crashcatcher/windows_crashmonitor.cpp diff --git a/apps/openmw_tests/CMakeLists.txt b/apps/openmw_tests/CMakeLists.txt index 9b57113110..4e57d610a3 100644 --- a/apps/openmw_tests/CMakeLists.txt +++ b/apps/openmw_tests/CMakeLists.txt @@ -6,14 +6,14 @@ file(GLOB UNITTEST_SRC_FILES options.cpp - mwworld/test_store.cpp + mwworld/teststore.cpp mwworld/testduration.cpp mwworld/testtimestamp.cpp mwworld/testptr.cpp - mwdialogue/test_keywordsearch.cpp + mwdialogue/testkeywordsearch.cpp - mwscript/test_scripts.cpp + mwscript/testscripts.cpp ) source_group(apps\\openmw-tests FILES ${UNITTEST_SRC_FILES}) diff --git a/apps/openmw_tests/mwdialogue/test_keywordsearch.cpp b/apps/openmw_tests/mwdialogue/testkeywordsearch.cpp similarity index 100% rename from apps/openmw_tests/mwdialogue/test_keywordsearch.cpp rename to apps/openmw_tests/mwdialogue/testkeywordsearch.cpp diff --git a/apps/openmw_tests/mwscript/test_scripts.cpp b/apps/openmw_tests/mwscript/testscripts.cpp similarity index 99% rename from apps/openmw_tests/mwscript/test_scripts.cpp rename to apps/openmw_tests/mwscript/testscripts.cpp index 0de542bdc6..b9e422daed 100644 --- a/apps/openmw_tests/mwscript/test_scripts.cpp +++ b/apps/openmw_tests/mwscript/testscripts.cpp @@ -1,7 +1,7 @@ #include #include -#include "test_utils.hpp" +#include "testutils.hpp" namespace { @@ -935,4 +935,4 @@ End)mwscript"; registerExtensions(); EXPECT_FALSE(!compile(sIssue6807)); } -} \ No newline at end of file +} diff --git a/apps/openmw_tests/mwscript/test_utils.hpp b/apps/openmw_tests/mwscript/testutils.hpp similarity index 100% rename from apps/openmw_tests/mwscript/test_utils.hpp rename to apps/openmw_tests/mwscript/testutils.hpp diff --git a/apps/openmw_tests/mwworld/test_store.cpp b/apps/openmw_tests/mwworld/teststore.cpp similarity index 100% rename from apps/openmw_tests/mwworld/test_store.cpp rename to apps/openmw_tests/mwworld/teststore.cpp From 89426af94a6467225bf15197dd3901e631fd228a Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 22:16:47 +0300 Subject: [PATCH 15/98] Rename apps/components_tests files to follow naming conventions --- CI/file_name_exceptions.txt | 16 --------- apps/components_tests/CMakeLists.txt | 35 +++++++++---------- ...t_fixed_string.cpp => testfixedstring.cpp} | 0 ...nversion_tests.cpp => conversiontests.cpp} | 0 .../lua/{test_async.cpp => testasync.cpp} | 0 ...onfiguration.cpp => testconfiguration.cpp} | 0 ..._inputactions.cpp => testinputactions.cpp} | 0 .../lua/{test_l10n.cpp => testl10n.cpp} | 0 .../lua/{test_lua.cpp => testlua.cpp} | 0 ...container.cpp => testscriptscontainer.cpp} | 0 ...erialization.cpp => testserialization.cpp} | 0 .../lua/{test_storage.cpp => teststorage.cpp} | 0 ...{test_ui_content.cpp => testuicontent.cpp} | 0 ...st_utilpackage.cpp => testutilpackage.cpp} | 0 .../lua/{test_yaml.cpp => testyaml.cpp} | 0 ...test_endianness.cpp => testendianness.cpp} | 0 ...rcehelpers.cpp => testresourcehelpers.cpp} | 0 .../{test_stringops.cpp => teststringops.cpp} | 0 18 files changed, 17 insertions(+), 34 deletions(-) rename apps/components_tests/esm/{test_fixed_string.cpp => testfixedstring.cpp} (100%) rename apps/components_tests/files/{conversion_tests.cpp => conversiontests.cpp} (100%) rename apps/components_tests/lua/{test_async.cpp => testasync.cpp} (100%) rename apps/components_tests/lua/{test_configuration.cpp => testconfiguration.cpp} (100%) rename apps/components_tests/lua/{test_inputactions.cpp => testinputactions.cpp} (100%) rename apps/components_tests/lua/{test_l10n.cpp => testl10n.cpp} (100%) rename apps/components_tests/lua/{test_lua.cpp => testlua.cpp} (100%) rename apps/components_tests/lua/{test_scriptscontainer.cpp => testscriptscontainer.cpp} (100%) rename apps/components_tests/lua/{test_serialization.cpp => testserialization.cpp} (100%) rename apps/components_tests/lua/{test_storage.cpp => teststorage.cpp} (100%) rename apps/components_tests/lua/{test_ui_content.cpp => testuicontent.cpp} (100%) rename apps/components_tests/lua/{test_utilpackage.cpp => testutilpackage.cpp} (100%) rename apps/components_tests/lua/{test_yaml.cpp => testyaml.cpp} (100%) rename apps/components_tests/misc/{test_endianness.cpp => testendianness.cpp} (100%) rename apps/components_tests/misc/{test_resourcehelpers.cpp => testresourcehelpers.cpp} (100%) rename apps/components_tests/misc/{test_stringops.cpp => teststringops.cpp} (100%) diff --git a/CI/file_name_exceptions.txt b/CI/file_name_exceptions.txt index 424dc3f691..92fca5c11f 100644 --- a/CI/file_name_exceptions.txt +++ b/CI/file_name_exceptions.txt @@ -7,22 +7,6 @@ apps/openmw/mwsound/sound_buffer.cpp apps/openmw/mwsound/sound_buffer.hpp apps/openmw/mwsound/sound_decoder.hpp apps/openmw/mwsound/sound_output.hpp -apps/components_tests/esm/test_fixed_string.cpp -apps/components_tests/files/conversion_tests.cpp -apps/components_tests/lua/test_async.cpp -apps/components_tests/lua/test_configuration.cpp -apps/components_tests/lua/test_l10n.cpp -apps/components_tests/lua/test_lua.cpp -apps/components_tests/lua/test_scriptscontainer.cpp -apps/components_tests/lua/test_serialization.cpp -apps/components_tests/lua/test_storage.cpp -apps/components_tests/lua/test_ui_content.cpp -apps/components_tests/lua/test_utilpackage.cpp -apps/components_tests/lua/test_inputactions.cpp -apps/components_tests/lua/test_yaml.cpp -apps/components_tests/misc/test_endianness.cpp -apps/components_tests/misc/test_resourcehelpers.cpp -apps/components_tests/misc/test_stringops.cpp components/crashcatcher/windows_crashcatcher.cpp components/crashcatcher/windows_crashcatcher.hpp components/crashcatcher/windows_crashmonitor.cpp diff --git a/apps/components_tests/CMakeLists.txt b/apps/components_tests/CMakeLists.txt index 22bb542538..7595681313 100644 --- a/apps/components_tests/CMakeLists.txt +++ b/apps/components_tests/CMakeLists.txt @@ -4,29 +4,28 @@ include_directories(SYSTEM ${GMOCK_INCLUDE_DIRS}) file(GLOB UNITTEST_SRC_FILES main.cpp - esm/test_fixed_string.cpp - esm/variant.cpp + esm/testfixedstring.cpp esm/testrefid.cpp + esm/variant.cpp - lua/test_lua.cpp - lua/test_scriptscontainer.cpp - lua/test_utilpackage.cpp - lua/test_serialization.cpp - lua/test_configuration.cpp - lua/test_l10n.cpp - lua/test_storage.cpp - lua/test_async.cpp - lua/test_inputactions.cpp - lua/test_yaml.cpp - - lua/test_ui_content.cpp + lua/testasync.cpp + lua/testconfiguration.cpp + lua/testinputactions.cpp + lua/testl10n.cpp + lua/testlua.cpp + lua/testscriptscontainer.cpp + lua/testserialization.cpp + lua/teststorage.cpp + lua/testuicontent.cpp + lua/testutilpackage.cpp + lua/testyaml.cpp misc/compression.cpp misc/progressreporter.cpp - misc/test_endianness.cpp - misc/test_resourcehelpers.cpp - misc/test_stringops.cpp + misc/testendianness.cpp misc/testmathutil.cpp + misc/testresourcehelpers.cpp + misc/teststringops.cpp nifloader/testbulletnifloader.cpp @@ -64,8 +63,8 @@ file(GLOB UNITTEST_SRC_FILES esmloader/esmdata.cpp esmloader/record.cpp + files/conversiontests.cpp files/hash.cpp - files/conversion_tests.cpp toutf8/toutf8.cpp diff --git a/apps/components_tests/esm/test_fixed_string.cpp b/apps/components_tests/esm/testfixedstring.cpp similarity index 100% rename from apps/components_tests/esm/test_fixed_string.cpp rename to apps/components_tests/esm/testfixedstring.cpp diff --git a/apps/components_tests/files/conversion_tests.cpp b/apps/components_tests/files/conversiontests.cpp similarity index 100% rename from apps/components_tests/files/conversion_tests.cpp rename to apps/components_tests/files/conversiontests.cpp diff --git a/apps/components_tests/lua/test_async.cpp b/apps/components_tests/lua/testasync.cpp similarity index 100% rename from apps/components_tests/lua/test_async.cpp rename to apps/components_tests/lua/testasync.cpp diff --git a/apps/components_tests/lua/test_configuration.cpp b/apps/components_tests/lua/testconfiguration.cpp similarity index 100% rename from apps/components_tests/lua/test_configuration.cpp rename to apps/components_tests/lua/testconfiguration.cpp diff --git a/apps/components_tests/lua/test_inputactions.cpp b/apps/components_tests/lua/testinputactions.cpp similarity index 100% rename from apps/components_tests/lua/test_inputactions.cpp rename to apps/components_tests/lua/testinputactions.cpp diff --git a/apps/components_tests/lua/test_l10n.cpp b/apps/components_tests/lua/testl10n.cpp similarity index 100% rename from apps/components_tests/lua/test_l10n.cpp rename to apps/components_tests/lua/testl10n.cpp diff --git a/apps/components_tests/lua/test_lua.cpp b/apps/components_tests/lua/testlua.cpp similarity index 100% rename from apps/components_tests/lua/test_lua.cpp rename to apps/components_tests/lua/testlua.cpp diff --git a/apps/components_tests/lua/test_scriptscontainer.cpp b/apps/components_tests/lua/testscriptscontainer.cpp similarity index 100% rename from apps/components_tests/lua/test_scriptscontainer.cpp rename to apps/components_tests/lua/testscriptscontainer.cpp diff --git a/apps/components_tests/lua/test_serialization.cpp b/apps/components_tests/lua/testserialization.cpp similarity index 100% rename from apps/components_tests/lua/test_serialization.cpp rename to apps/components_tests/lua/testserialization.cpp diff --git a/apps/components_tests/lua/test_storage.cpp b/apps/components_tests/lua/teststorage.cpp similarity index 100% rename from apps/components_tests/lua/test_storage.cpp rename to apps/components_tests/lua/teststorage.cpp diff --git a/apps/components_tests/lua/test_ui_content.cpp b/apps/components_tests/lua/testuicontent.cpp similarity index 100% rename from apps/components_tests/lua/test_ui_content.cpp rename to apps/components_tests/lua/testuicontent.cpp diff --git a/apps/components_tests/lua/test_utilpackage.cpp b/apps/components_tests/lua/testutilpackage.cpp similarity index 100% rename from apps/components_tests/lua/test_utilpackage.cpp rename to apps/components_tests/lua/testutilpackage.cpp diff --git a/apps/components_tests/lua/test_yaml.cpp b/apps/components_tests/lua/testyaml.cpp similarity index 100% rename from apps/components_tests/lua/test_yaml.cpp rename to apps/components_tests/lua/testyaml.cpp diff --git a/apps/components_tests/misc/test_endianness.cpp b/apps/components_tests/misc/testendianness.cpp similarity index 100% rename from apps/components_tests/misc/test_endianness.cpp rename to apps/components_tests/misc/testendianness.cpp diff --git a/apps/components_tests/misc/test_resourcehelpers.cpp b/apps/components_tests/misc/testresourcehelpers.cpp similarity index 100% rename from apps/components_tests/misc/test_resourcehelpers.cpp rename to apps/components_tests/misc/testresourcehelpers.cpp diff --git a/apps/components_tests/misc/test_stringops.cpp b/apps/components_tests/misc/teststringops.cpp similarity index 100% rename from apps/components_tests/misc/test_stringops.cpp rename to apps/components_tests/misc/teststringops.cpp From ac9505b53672f4097b471a955353be351821c49a Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 22:35:33 +0300 Subject: [PATCH 16/98] Rename components/to_utf8 directory and files to follow naming conventions --- CI/file_name_exceptions.txt | 4 ---- apps/bulletobjecttool/main.cpp | 2 +- apps/components_tests/esmloader/load.cpp | 2 +- apps/components_tests/toutf8/toutf8.cpp | 2 +- apps/esmtool/tes4.cpp | 2 +- apps/essimporter/importer.cpp | 2 +- apps/mwiniimporter/importer.hpp | 2 +- apps/navmeshtool/main.cpp | 2 +- apps/opencs/editor.cpp | 2 +- apps/opencs/model/doc/document.hpp | 2 +- apps/opencs/model/doc/documentmanager.hpp | 2 +- apps/opencs/model/doc/saving.hpp | 2 +- apps/opencs/model/doc/savingstate.hpp | 2 +- apps/opencs/model/tools/mergeoperation.hpp | 2 +- apps/opencs/model/tools/mergestages.hpp | 2 +- apps/opencs/model/tools/tools.hpp | 2 +- apps/opencs/model/world/data.hpp | 2 +- apps/openmw/mwgui/journalbooks.hpp | 2 +- apps/openmw/mwgui/journalwindow.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/wizard/inisettings.hpp | 2 +- components/CMakeLists.txt | 6 +++--- components/esm3/esmreader.hpp | 2 +- components/esm3/esmwriter.cpp | 2 +- components/esm4/reader.cpp | 2 +- components/fontloader/fontloader.hpp | 2 +- components/nif/nifstream.cpp | 4 ++-- components/to_utf8/.gitignore | 1 - components/to_utf8/Makefile | 8 -------- components/toutf8/.gitignore | 1 + components/toutf8/Makefile | 8 ++++++++ components/{to_utf8/gen_iconv.cpp => toutf8/geniconv.cpp} | 4 ++-- .../{to_utf8/tables_gen.hpp => toutf8/tablesgen.hpp} | 4 ++-- components/{to_utf8/to_utf8.cpp => toutf8/toutf8.cpp} | 4 ++-- components/{to_utf8/to_utf8.hpp => toutf8/toutf8.hpp} | 4 ++-- components/translation/translation.hpp | 2 +- 36 files changed, 47 insertions(+), 51 deletions(-) delete mode 100644 components/to_utf8/.gitignore delete mode 100644 components/to_utf8/Makefile create mode 100644 components/toutf8/.gitignore create mode 100644 components/toutf8/Makefile rename components/{to_utf8/gen_iconv.cpp => toutf8/geniconv.cpp} (95%) rename components/{to_utf8/tables_gen.hpp => toutf8/tablesgen.hpp} (99%) rename components/{to_utf8/to_utf8.cpp => toutf8/toutf8.cpp} (99%) rename components/{to_utf8/to_utf8.hpp => toutf8/toutf8.hpp} (97%) diff --git a/CI/file_name_exceptions.txt b/CI/file_name_exceptions.txt index 92fca5c11f..95ecafa856 100644 --- a/CI/file_name_exceptions.txt +++ b/CI/file_name_exceptions.txt @@ -12,7 +12,3 @@ components/crashcatcher/windows_crashcatcher.hpp components/crashcatcher/windows_crashmonitor.cpp components/crashcatcher/windows_crashmonitor.hpp components/crashcatcher/windows_crashshm.hpp -components/to_utf8/gen_iconv.cpp -components/to_utf8/tables_gen.hpp -components/to_utf8/to_utf8.cpp -components/to_utf8/to_utf8.hpp diff --git a/apps/bulletobjecttool/main.cpp b/apps/bulletobjecttool/main.cpp index 190eb3364d..857eb357aa 100644 --- a/apps/bulletobjecttool/main.cpp +++ b/apps/bulletobjecttool/main.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/apps/components_tests/esmloader/load.cpp b/apps/components_tests/esmloader/load.cpp index 20e06507d1..e5e1b15876 100644 --- a/apps/components_tests/esmloader/load.cpp +++ b/apps/components_tests/esmloader/load.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include diff --git a/apps/components_tests/toutf8/toutf8.cpp b/apps/components_tests/toutf8/toutf8.cpp index 704ee6742d..3c84da65ee 100644 --- a/apps/components_tests/toutf8/toutf8.cpp +++ b/apps/components_tests/toutf8/toutf8.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/apps/esmtool/tes4.cpp b/apps/esmtool/tes4.cpp index 5b657da573..4ff632a217 100644 --- a/apps/esmtool/tes4.cpp +++ b/apps/esmtool/tes4.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include namespace EsmTool { diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 5cc9a8259b..cf04fee163 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -25,7 +25,7 @@ #include -#include +#include #include "importercontext.hpp" diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index 4c42caf5a3..342670713c 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -8,7 +8,7 @@ #include #include -#include +#include class MwIniImporter { diff --git a/apps/navmeshtool/main.cpp b/apps/navmeshtool/main.cpp index 27f84104ac..5c7fe53126 100644 --- a/apps/navmeshtool/main.cpp +++ b/apps/navmeshtool/main.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 4cab88e5f2..0072a18d0d 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include "view/doc/viewmanager.hpp" diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 60516cdc8c..ac8f06712c 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include "../world/data.hpp" #include "../world/idcompletionmanager.hpp" diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 2c9ee1e98e..53caf04a0a 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include "loader.hpp" diff --git a/apps/opencs/model/doc/saving.hpp b/apps/opencs/model/doc/saving.hpp index 5dcdbb6803..6197798fdf 100644 --- a/apps/opencs/model/doc/saving.hpp +++ b/apps/opencs/model/doc/saving.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include "operation.hpp" #include "savingstate.hpp" diff --git a/apps/opencs/model/doc/savingstate.hpp b/apps/opencs/model/doc/savingstate.hpp index c42dff0366..af8caa2c4d 100644 --- a/apps/opencs/model/doc/savingstate.hpp +++ b/apps/opencs/model/doc/savingstate.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include namespace CSMDoc { diff --git a/apps/opencs/model/tools/mergeoperation.hpp b/apps/opencs/model/tools/mergeoperation.hpp index 2cce2bec0d..c50a7eefb0 100644 --- a/apps/opencs/model/tools/mergeoperation.hpp +++ b/apps/opencs/model/tools/mergeoperation.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include "../doc/operation.hpp" diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 42f06858b1..40cc799c81 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include "../doc/stage.hpp" diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index c9e8937c90..939dea9bb8 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -6,7 +6,7 @@ #include -#include +#include #include diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 237b746746..c119541381 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include "cell.hpp" #include "idcollection.hpp" diff --git a/apps/openmw/mwgui/journalbooks.hpp b/apps/openmw/mwgui/journalbooks.hpp index 1970830eab..792edcc070 100644 --- a/apps/openmw/mwgui/journalbooks.hpp +++ b/apps/openmw/mwgui/journalbooks.hpp @@ -4,7 +4,7 @@ #include "bookpage.hpp" #include "journalviewmodel.hpp" -#include +#include namespace MWGui { diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 22e7048acf..f0f394156c 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -3,7 +3,7 @@ #include "windowbase.hpp" -#include +#include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 052a269188..3b85b74a8d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include "charactercreation.hpp" #include "draganddrop.hpp" diff --git a/apps/wizard/inisettings.hpp b/apps/wizard/inisettings.hpp index c8cd30c3c1..6ea8fc4adb 100644 --- a/apps/wizard/inisettings.hpp +++ b/apps/wizard/inisettings.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace Wizard { diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d57b0ed823..217839ce61 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -155,9 +155,9 @@ add_component_dir (nifbullet bulletnifloader ) -add_component_dir (to_utf8 - tables_gen - to_utf8 +add_component_dir (toutf8 + tablesgen + toutf8 ) add_component_dir(esm attr common defs esmcommon records util luascripts format refid esmbridge esmterrain diff --git a/components/esm3/esmreader.hpp b/components/esm3/esmreader.hpp index 5af5e75573..9bae5f217e 100644 --- a/components/esm3/esmreader.hpp +++ b/components/esm3/esmreader.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include "components/esm/decompose.hpp" #include "components/esm/esmcommon.hpp" diff --git a/components/esm3/esmwriter.cpp b/components/esm3/esmwriter.cpp index 47c861e3ca..8bae844585 100644 --- a/components/esm3/esmwriter.cpp +++ b/components/esm3/esmwriter.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "formatversion.hpp" diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp index 505922601d..43a9e26418 100644 --- a/components/esm4/reader.cpp +++ b/components/esm4/reader.cpp @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include "grouptype.hpp" diff --git a/components/fontloader/fontloader.hpp b/components/fontloader/fontloader.hpp index 7e9220d58d..e5705f6af1 100644 --- a/components/fontloader/fontloader.hpp +++ b/components/fontloader/fontloader.hpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace VFS { diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index ef63bae937..6c361401e8 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -2,9 +2,9 @@ #include -#include "niffile.hpp" +#include -#include "../to_utf8/to_utf8.hpp" +#include "niffile.hpp" namespace { diff --git a/components/to_utf8/.gitignore b/components/to_utf8/.gitignore deleted file mode 100644 index 4e0357749e..0000000000 --- a/components/to_utf8/.gitignore +++ /dev/null @@ -1 +0,0 @@ -gen_iconv diff --git a/components/to_utf8/Makefile b/components/to_utf8/Makefile deleted file mode 100644 index 5234d455ae..0000000000 --- a/components/to_utf8/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -tables_gen.hpp: gen_iconv - ./gen_iconv > tables_gen.hpp - -gen_iconv: gen_iconv.cpp - g++ -Wall $^ -o $@ - -clean: - rm -f ./gen_iconv \ No newline at end of file diff --git a/components/toutf8/.gitignore b/components/toutf8/.gitignore new file mode 100644 index 0000000000..f1f54f5aea --- /dev/null +++ b/components/toutf8/.gitignore @@ -0,0 +1 @@ +geniconv diff --git a/components/toutf8/Makefile b/components/toutf8/Makefile new file mode 100644 index 0000000000..e46176d3ed --- /dev/null +++ b/components/toutf8/Makefile @@ -0,0 +1,8 @@ +tablesgen.hpp: geniconv + ./geniconv > tablesgen.hpp + +geniconv: geniconv.cpp + g++ -Wall $^ -o $@ + +clean: + rm -f ./geniconv diff --git a/components/to_utf8/gen_iconv.cpp b/components/toutf8/geniconv.cpp similarity index 95% rename from components/to_utf8/gen_iconv.cpp rename to components/toutf8/geniconv.cpp index 062b1173fc..48a7fb4627 100644 --- a/components/to_utf8/gen_iconv.cpp +++ b/components/toutf8/geniconv.cpp @@ -1,4 +1,4 @@ -// This program generates the file tables_gen.hpp +// This program generates the file tablesgen.hpp #include @@ -88,7 +88,7 @@ int write_table(const std::string& charset, const std::string& tableName) int main() { // Write header guard - std::cout << "#ifndef COMPONENTS_TOUTF8_TABLE_GEN_H\n#define COMPONENTS_TOUTF8_TABLE_GEN_H\n\n"; + std::cout << "#ifndef OPENMW_COMPONENTS_TOUTF8_TABLESGEN_HPP\n#define OPENMW_COMPONENTS_TOUTF8_TABLESGEN_HPP\n\n"; // Write namespace std::cout << "namespace ToUTF8\n{\n\n"; diff --git a/components/to_utf8/tables_gen.hpp b/components/toutf8/tablesgen.hpp similarity index 99% rename from components/to_utf8/tables_gen.hpp rename to components/toutf8/tablesgen.hpp index b25bb54bab..9ef5097ece 100644 --- a/components/to_utf8/tables_gen.hpp +++ b/components/toutf8/tablesgen.hpp @@ -1,5 +1,5 @@ -#ifndef COMPONENTS_TOUTF8_TABLE_GEN_H -#define COMPONENTS_TOUTF8_TABLE_GEN_H +#ifndef OPENMW_COMPONENTS_TOUTF8_TABLESGEN_HPP +#define OPENMW_COMPONENTS_TOUTF8_TABLESGEN_HPP namespace ToUTF8 { diff --git a/components/to_utf8/to_utf8.cpp b/components/toutf8/toutf8.cpp similarity index 99% rename from components/to_utf8/to_utf8.cpp rename to components/toutf8/toutf8.cpp index 15fb8b26c0..e9b2a7fe2f 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/toutf8/toutf8.cpp @@ -1,4 +1,4 @@ -#include "to_utf8.hpp" +#include "toutf8.hpp" #include #include @@ -41,7 +41,7 @@ */ // Generated tables -#include "tables_gen.hpp" +#include "tablesgen.hpp" using namespace ToUTF8; diff --git a/components/to_utf8/to_utf8.hpp b/components/toutf8/toutf8.hpp similarity index 97% rename from components/to_utf8/to_utf8.hpp rename to components/toutf8/toutf8.hpp index 80af6586c9..1da4ebffbb 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/toutf8/toutf8.hpp @@ -1,5 +1,5 @@ -#ifndef COMPONENTS_TOUTF8_H -#define COMPONENTS_TOUTF8_H +#ifndef OPENMW_COMPONENTS_TOUTF8_TOUTF8_HPP +#define OPENMW_COMPONENTS_TOUTF8_TOUTF8_HPP #include #include diff --git a/components/translation/translation.hpp b/components/translation/translation.hpp index a7b6087ac7..18e40713e5 100644 --- a/components/translation/translation.hpp +++ b/components/translation/translation.hpp @@ -2,7 +2,7 @@ #define COMPONENTS_TRANSLATION_DATA_H #include -#include +#include namespace Translation { From fc850cfe69c75482d0434255a9f38ecf91fbf3ee Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 22:56:21 +0300 Subject: [PATCH 17/98] Rename components/crashcatcher files to follow naming conventions --- CI/file_name_exceptions.txt | 5 ----- components/CMakeLists.txt | 6 +++--- components/crashcatcher/crashcatcher.hpp | 4 ++-- ...{windows_crashcatcher.cpp => windowscrashcatcher.cpp} | 9 +++++---- ...{windows_crashcatcher.hpp => windowscrashcatcher.hpp} | 9 +++++---- components/crashcatcher/windowscrashdumppathhelpers.hpp | 6 ++++-- ...{windows_crashmonitor.cpp => windowscrashmonitor.cpp} | 9 +++++---- ...{windows_crashmonitor.hpp => windowscrashmonitor.hpp} | 6 +++--- .../{windows_crashshm.hpp => windowscrashshm.hpp} | 6 +++--- components/debug/debugging.cpp | 2 +- 10 files changed, 31 insertions(+), 31 deletions(-) rename components/crashcatcher/{windows_crashcatcher.cpp => windowscrashcatcher.cpp} (98%) rename components/crashcatcher/{windows_crashcatcher.hpp => windowscrashcatcher.hpp} (94%) rename components/crashcatcher/{windows_crashmonitor.cpp => windowscrashmonitor.cpp} (99%) rename components/crashcatcher/{windows_crashmonitor.hpp => windowscrashmonitor.hpp} (90%) rename components/crashcatcher/{windows_crashshm.hpp => windowscrashshm.hpp} (89%) diff --git a/CI/file_name_exceptions.txt b/CI/file_name_exceptions.txt index 95ecafa856..a388ebf630 100644 --- a/CI/file_name_exceptions.txt +++ b/CI/file_name_exceptions.txt @@ -7,8 +7,3 @@ apps/openmw/mwsound/sound_buffer.cpp apps/openmw/mwsound/sound_buffer.hpp apps/openmw/mwsound/sound_decoder.hpp apps/openmw/mwsound/sound_output.hpp -components/crashcatcher/windows_crashcatcher.cpp -components/crashcatcher/windows_crashcatcher.hpp -components/crashcatcher/windows_crashmonitor.cpp -components/crashcatcher/windows_crashmonitor.hpp -components/crashcatcher/windows_crashshm.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 217839ce61..2385b4ca83 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -390,10 +390,10 @@ copy_resource_file("lua_ui/content.lua" "${OPENMW_RESOURCES_ROOT}" "resources/lu if(WIN32) add_component_dir (crashcatcher - windows_crashcatcher - windows_crashmonitor - windows_crashshm + windowscrashcatcher windowscrashdumppathhelpers + windowscrashmonitor + windowscrashshm ) elseif(NOT ANDROID) add_component_dir (crashcatcher diff --git a/components/crashcatcher/crashcatcher.hpp b/components/crashcatcher/crashcatcher.hpp index 16b416cf98..60f749e57a 100644 --- a/components/crashcatcher/crashcatcher.hpp +++ b/components/crashcatcher/crashcatcher.hpp @@ -1,5 +1,5 @@ -#ifndef CRASHCATCHER_H -#define CRASHCATCHER_H +#ifndef OPENMW_COMPONENTS_CRASHCATCHER_CRASHCATCHER_HPP +#define OPENMW_COMPONENTS_CRASHCATCHER_CRASHCATCHER_HPP #include diff --git a/components/crashcatcher/windows_crashcatcher.cpp b/components/crashcatcher/windowscrashcatcher.cpp similarity index 98% rename from components/crashcatcher/windows_crashcatcher.cpp rename to components/crashcatcher/windowscrashcatcher.cpp index 23dfac549c..40c54834ac 100644 --- a/components/crashcatcher/windows_crashcatcher.cpp +++ b/components/crashcatcher/windowscrashcatcher.cpp @@ -1,17 +1,18 @@ -#include "windows_crashcatcher.hpp" +#include "windowscrashcatcher.hpp" #include #include #include #include -#include "windows_crashmonitor.hpp" -#include "windows_crashshm.hpp" -#include "windowscrashdumppathhelpers.hpp" #include #include +#include "windowscrashdumppathhelpers.hpp" +#include "windowscrashmonitor.hpp" +#include "windowscrashshm.hpp" + namespace Crash { namespace diff --git a/components/crashcatcher/windows_crashcatcher.hpp b/components/crashcatcher/windowscrashcatcher.hpp similarity index 94% rename from components/crashcatcher/windows_crashcatcher.hpp rename to components/crashcatcher/windowscrashcatcher.hpp index 89678c9ada..ea53fcb520 100644 --- a/components/crashcatcher/windows_crashcatcher.hpp +++ b/components/crashcatcher/windowscrashcatcher.hpp @@ -1,11 +1,12 @@ -#ifndef WINDOWS_CRASHCATCHER_HPP -#define WINDOWS_CRASHCATCHER_HPP +#ifndef OPENMW_COMPONENTS_CRASHCATCHER_WINDOWSCRASHCATCHER_HPP +#define OPENMW_COMPONENTS_CRASHCATCHER_WINDOWSCRASHCATCHER_HPP #include -#include #include +#include "crashcatcher.hpp" + namespace Crash { @@ -78,4 +79,4 @@ namespace Crash } // namespace Crash -#endif // WINDOWS_CRASHCATCHER_HPP +#endif diff --git a/components/crashcatcher/windowscrashdumppathhelpers.hpp b/components/crashcatcher/windowscrashdumppathhelpers.hpp index fa64969301..9e11c57834 100644 --- a/components/crashcatcher/windowscrashdumppathhelpers.hpp +++ b/components/crashcatcher/windowscrashdumppathhelpers.hpp @@ -1,8 +1,10 @@ -#ifndef COMPONENTS_CRASH_WINDOWSCRASHDUMPPATHHELPERS_H -#include "windows_crashshm.hpp" +#ifndef OPENMW_COMPONENTS_CRASHCATCHER_WINDOWSCRASHDUMPPATHHELPERS_HPP +#define OPENMW_COMPONENTS_CRASHCATCHER_WINDOWSCRASHDUMPPATHHELPERS_HPP #include +#include "windowscrashshm.hpp" + namespace Crash { std::filesystem::path getCrashDumpPath(const CrashSHM& crashShm); diff --git a/components/crashcatcher/windows_crashmonitor.cpp b/components/crashcatcher/windowscrashmonitor.cpp similarity index 99% rename from components/crashcatcher/windows_crashmonitor.cpp rename to components/crashcatcher/windowscrashmonitor.cpp index 3708283efa..a92c310f63 100644 --- a/components/crashcatcher/windows_crashmonitor.cpp +++ b/components/crashcatcher/windowscrashmonitor.cpp @@ -1,4 +1,4 @@ -#include "windows_crashmonitor.hpp" +#include "windowscrashmonitor.hpp" #include #include @@ -10,12 +10,13 @@ #include -#include "windows_crashcatcher.hpp" -#include "windows_crashshm.hpp" -#include "windowscrashdumppathhelpers.hpp" #include #include +#include "windowscrashcatcher.hpp" +#include "windowscrashdumppathhelpers.hpp" +#include "windowscrashshm.hpp" + namespace Crash { std::unordered_map CrashMonitor::smEventHookOwners{}; diff --git a/components/crashcatcher/windows_crashmonitor.hpp b/components/crashcatcher/windowscrashmonitor.hpp similarity index 90% rename from components/crashcatcher/windows_crashmonitor.hpp rename to components/crashcatcher/windowscrashmonitor.hpp index 16e173169e..cb650df6dd 100644 --- a/components/crashcatcher/windows_crashmonitor.hpp +++ b/components/crashcatcher/windowscrashmonitor.hpp @@ -1,5 +1,5 @@ -#ifndef WINDOWS_CRASHMONITOR_HPP -#define WINDOWS_CRASHMONITOR_HPP +#ifndef OPENMW_COMPONENTS_CRASHCATCHER_WINDOWSCRASHMONITOR_HPP +#define OPENMW_COMPONENTS_CRASHCATCHER_WINDOWSCRASHMONITOR_HPP #include @@ -60,4 +60,4 @@ namespace Crash } // namespace Crash -#endif // WINDOWS_CRASHMONITOR_HPP +#endif diff --git a/components/crashcatcher/windows_crashshm.hpp b/components/crashcatcher/windowscrashshm.hpp similarity index 89% rename from components/crashcatcher/windows_crashshm.hpp rename to components/crashcatcher/windowscrashshm.hpp index b919757890..a9357710ca 100644 --- a/components/crashcatcher/windows_crashshm.hpp +++ b/components/crashcatcher/windowscrashshm.hpp @@ -1,5 +1,5 @@ -#ifndef WINDOWS_CRASHSHM_HPP -#define WINDOWS_CRASHSHM_HPP +#ifndef OPENMW_COMPONENTS_CRASHCATCHER_WINDOWSCRASHSHM_HPP +#define OPENMW_COMPONENTS_CRASHCATCHER_WINDOWSCRASHSHM_HPP #include @@ -44,4 +44,4 @@ namespace Crash } // namespace Crash -#endif // WINDOWS_CRASHSHM_HPP +#endif diff --git a/components/debug/debugging.cpp b/components/debug/debugging.cpp index 32aec8f0fc..11d74be606 100644 --- a/components/debug/debugging.cpp +++ b/components/debug/debugging.cpp @@ -22,7 +22,7 @@ #include #ifdef _WIN32 -#include +#include #include #include From 72cbf61b4351e6be9ec24581b96b5471c3b6f34c Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 23:45:51 +0300 Subject: [PATCH 18/98] Rename apps/openmw/mwsound files and classes to follow naming conventions --- CI/file_name_exceptions.txt | 9 -- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwbase/soundmanager.hpp | 4 +- .../mwsound/{efx-presets.h => efxpresets.h} | 6 +- .../{ffmpeg_decoder.cpp => ffmpegdecoder.cpp} | 40 ++++---- .../{ffmpeg_decoder.hpp => ffmpegdecoder.hpp} | 16 ++-- apps/openmw/mwsound/loudness.hpp | 2 +- apps/openmw/mwsound/movieaudiofactory.cpp | 6 +- .../{openal_output.cpp => openaloutput.cpp} | 93 +++++++++---------- .../{openal_output.hpp => openaloutput.hpp} | 16 ++-- apps/openmw/mwsound/sound.hpp | 4 +- .../{sound_buffer.cpp => soundbuffer.cpp} | 32 +++---- .../{sound_buffer.hpp => soundbuffer.hpp} | 43 ++++----- .../{sound_decoder.hpp => sounddecoder.hpp} | 14 +-- apps/openmw/mwsound/soundmanagerimp.cpp | 50 +++++----- apps/openmw/mwsound/soundmanagerimp.hpp | 22 ++--- .../{sound_output.hpp => soundoutput.hpp} | 18 ++-- 17 files changed, 185 insertions(+), 194 deletions(-) rename apps/openmw/mwsound/{efx-presets.h => efxpresets.h} (99%) rename apps/openmw/mwsound/{ffmpeg_decoder.cpp => ffmpegdecoder.cpp} (93%) rename apps/openmw/mwsound/{ffmpeg_decoder.hpp => ffmpegdecoder.hpp} (89%) rename apps/openmw/mwsound/{openal_output.cpp => openaloutput.cpp} (95%) rename apps/openmw/mwsound/{openal_output.hpp => openaloutput.hpp} (91%) rename apps/openmw/mwsound/{sound_buffer.cpp => soundbuffer.cpp} (85%) rename apps/openmw/mwsound/{sound_buffer.hpp => soundbuffer.hpp} (68%) rename apps/openmw/mwsound/{sound_decoder.hpp => sounddecoder.hpp} (80%) rename apps/openmw/mwsound/{sound_output.hpp => soundoutput.hpp} (88%) diff --git a/CI/file_name_exceptions.txt b/CI/file_name_exceptions.txt index a388ebf630..e69de29bb2 100644 --- a/CI/file_name_exceptions.txt +++ b/CI/file_name_exceptions.txt @@ -1,9 +0,0 @@ -apps/openmw/mwsound/efx-presets.h -apps/openmw/mwsound/ffmpeg_decoder.cpp -apps/openmw/mwsound/ffmpeg_decoder.hpp -apps/openmw/mwsound/openal_output.cpp -apps/openmw/mwsound/openal_output.hpp -apps/openmw/mwsound/sound_buffer.cpp -apps/openmw/mwsound/sound_buffer.hpp -apps/openmw/mwsound/sound_decoder.hpp -apps/openmw/mwsound/sound_output.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 37e9b39a01..7319791d87 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -71,8 +71,8 @@ add_openmw_dir (mwlua ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output - loudness movieaudiofactory alext efx efx-presets regionsoundselector watersoundupdater + soundmanagerimp openaloutput ffmpegdecoder sound soundbuffer sounddecoder soundoutput + loudness movieaudiofactory alext efx efxpresets regionsoundselector watersoundupdater ) add_openmw_dir (mwworld diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 5f96a4e095..532bc771ba 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -39,8 +39,8 @@ namespace MWSound class Sound; class Stream; - struct Sound_Decoder; - typedef std::shared_ptr DecoderPtr; + struct SoundDecoder; + typedef std::shared_ptr DecoderPtr; /* These must all fit together */ enum class PlayMode diff --git a/apps/openmw/mwsound/efx-presets.h b/apps/openmw/mwsound/efxpresets.h similarity index 99% rename from apps/openmw/mwsound/efx-presets.h rename to apps/openmw/mwsound/efxpresets.h index a9662936d5..a36c41db03 100644 --- a/apps/openmw/mwsound/efx-presets.h +++ b/apps/openmw/mwsound/efxpresets.h @@ -1,7 +1,7 @@ /* Reverb presets for EFX */ -#ifndef EFX_PRESETS_H -#define EFX_PRESETS_H +#ifndef GAME_SOUND_EFXPRESETS_H +#define GAME_SOUND_EFXPRESETS_H #ifndef EFXEAXREVERBPROPERTIES_DEFINED #define EFXEAXREVERBPROPERTIES_DEFINED @@ -852,4 +852,4 @@ typedef struct 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 \ } -#endif /* EFX_PRESETS_H */ +#endif diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpegdecoder.cpp similarity index 93% rename from apps/openmw/mwsound/ffmpeg_decoder.cpp rename to apps/openmw/mwsound/ffmpegdecoder.cpp index 54fd126c41..5a0f336a93 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpegdecoder.cpp @@ -1,4 +1,4 @@ -#include "ffmpeg_decoder.hpp" +#include "ffmpegdecoder.hpp" #include #include @@ -44,11 +44,11 @@ namespace MWSound av_frame_free(&ptr); } - int FFmpeg_Decoder::readPacket(void* user_data, uint8_t* buf, int buf_size) + int FFmpegDecoder::readPacket(void* user_data, uint8_t* buf, int buf_size) { try { - std::istream& stream = *static_cast(user_data)->mDataStream; + std::istream& stream = *static_cast(user_data)->mDataStream; stream.clear(); stream.read((char*)buf, buf_size); std::streamsize count = stream.gcount(); @@ -65,18 +65,18 @@ namespace MWSound } #if OPENMW_FFMPEG_CONST_WRITEPACKET - int FFmpeg_Decoder::writePacket(void*, const uint8_t*, int) + int FFmpegDecoder::writePacket(void*, const uint8_t*, int) #else - int FFmpeg_Decoder::writePacket(void*, uint8_t*, int) + int FFmpegDecoder::writePacket(void*, uint8_t*, int) #endif { Log(Debug::Error) << "can't write to read-only stream"; return -1; } - int64_t FFmpeg_Decoder::seek(void* user_data, int64_t offset, int whence) + int64_t FFmpegDecoder::seek(void* user_data, int64_t offset, int whence) { - std::istream& stream = *static_cast(user_data)->mDataStream; + std::istream& stream = *static_cast(user_data)->mDataStream; whence &= ~AVSEEK_FORCE; @@ -106,7 +106,7 @@ namespace MWSound /* Used by getAV*Data to search for more compressed data, and buffer it in the * correct stream. It won't buffer data for streams that the app doesn't have a * handle for. */ - bool FFmpeg_Decoder::getNextPacket() + bool FFmpegDecoder::getNextPacket() { if (!mStream) return false; @@ -129,7 +129,7 @@ namespace MWSound return false; } - bool FFmpeg_Decoder::getAVAudioData() + bool FFmpegDecoder::getAVAudioData() { bool got_frame = false; @@ -192,7 +192,7 @@ namespace MWSound return true; } - size_t FFmpeg_Decoder::readAVAudioData(void* data, size_t length) + size_t FFmpegDecoder::readAVAudioData(void* data, size_t length) { size_t dec = 0; @@ -227,7 +227,7 @@ namespace MWSound return dec; } - void FFmpeg_Decoder::open(VFS::Path::NormalizedView fname) + void FFmpegDecoder::open(VFS::Path::NormalizedView fname) { close(); mDataStream = mResourceMgr->get(fname); @@ -317,7 +317,7 @@ namespace MWSound mStream = stream; } - void FFmpeg_Decoder::close() + void FFmpegDecoder::close() { mStream = nullptr; mCodecCtx.reset(); @@ -332,7 +332,7 @@ namespace MWSound mDataStream.reset(); } - std::string FFmpeg_Decoder::getName() + std::string FFmpegDecoder::getName() { // In the FFMpeg 4.0 a "filename" field was replaced by "url" #if LIBAVCODEC_VERSION_INT < 3805796 @@ -342,7 +342,7 @@ namespace MWSound #endif } - void FFmpeg_Decoder::getInfo(int* samplerate, ChannelConfig* chans, SampleType* type) + void FFmpegDecoder::getInfo(int* samplerate, ChannelConfig* chans, SampleType* type) { if (!mStream) throw std::runtime_error("No audio stream info"); @@ -459,7 +459,7 @@ namespace MWSound } } - size_t FFmpeg_Decoder::read(char* buffer, size_t bytes) + size_t FFmpegDecoder::read(char* buffer, size_t bytes) { if (!mStream) { @@ -469,7 +469,7 @@ namespace MWSound return readAVAudioData(buffer, bytes); } - void FFmpeg_Decoder::readAll(std::vector& output) + void FFmpegDecoder::readAll(std::vector& output) { if (!mStream) { @@ -490,7 +490,7 @@ namespace MWSound } } - size_t FFmpeg_Decoder::getSampleOffset() + size_t FFmpegDecoder::getSampleOffset() { #if OPENMW_FFMPEG_5_OR_GREATER std::size_t delay = (mFrameSize - mFramePos) / mOutputChannelLayout.nb_channels @@ -501,8 +501,8 @@ namespace MWSound return static_cast(mNextPts * mCodecCtx->sample_rate) - delay; } - FFmpeg_Decoder::FFmpeg_Decoder(const VFS::Manager* vfs) - : Sound_Decoder(vfs) + FFmpegDecoder::FFmpegDecoder(const VFS::Manager* vfs) + : SoundDecoder(vfs) , mStream(nullptr) , mFrameSize(0) , mFramePos(0) @@ -534,7 +534,7 @@ namespace MWSound } } - FFmpeg_Decoder::~FFmpeg_Decoder() + FFmpegDecoder::~FFmpegDecoder() { close(); } diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpegdecoder.hpp similarity index 89% rename from apps/openmw/mwsound/ffmpeg_decoder.hpp rename to apps/openmw/mwsound/ffmpegdecoder.hpp index e67b8efbf3..c71b935bc4 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpegdecoder.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_SOUND_FFMPEG_DECODER_H -#define GAME_SOUND_FFMPEG_DECODER_H +#ifndef GAME_SOUND_FFMPEGDECODER_H +#define GAME_SOUND_FFMPEGDECODER_H #include @@ -31,7 +31,7 @@ extern "C" #include -#include "sound_decoder.hpp" +#include "sounddecoder.hpp" namespace MWSound { @@ -63,7 +63,7 @@ namespace MWSound using AVFramePtr = std::unique_ptr; - class FFmpeg_Decoder final : public Sound_Decoder + class FFmpegDecoder final : public SoundDecoder { AVIOContextPtr mIoCtx; AVFormatContextPtr mFormatCtx; @@ -114,13 +114,13 @@ namespace MWSound void readAll(std::vector& output) override; size_t getSampleOffset() override; - FFmpeg_Decoder& operator=(const FFmpeg_Decoder& rhs); - FFmpeg_Decoder(const FFmpeg_Decoder& rhs); + FFmpegDecoder& operator=(const FFmpegDecoder& rhs); + FFmpegDecoder(const FFmpegDecoder& rhs); public: - explicit FFmpeg_Decoder(const VFS::Manager* vfs); + explicit FFmpegDecoder(const VFS::Manager* vfs); - virtual ~FFmpeg_Decoder(); + virtual ~FFmpegDecoder(); friend class SoundManager; }; diff --git a/apps/openmw/mwsound/loudness.hpp b/apps/openmw/mwsound/loudness.hpp index 1800ec246f..edc201f38a 100644 --- a/apps/openmw/mwsound/loudness.hpp +++ b/apps/openmw/mwsound/loudness.hpp @@ -4,7 +4,7 @@ #include #include -#include "sound_decoder.hpp" +#include "sounddecoder.hpp" namespace MWSound { diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 962086701a..61992bc0d5 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -7,17 +7,17 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" -#include "sound_decoder.hpp" +#include "sounddecoder.hpp" namespace MWSound { class MovieAudioDecoder; - class MWSoundDecoderBridge final : public Sound_Decoder + class MWSoundDecoderBridge final : public SoundDecoder { public: MWSoundDecoderBridge(MWSound::MovieAudioDecoder* decoder) - : Sound_Decoder(nullptr) + : SoundDecoder(nullptr) , mDecoder(decoder) { } diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openaloutput.cpp similarity index 95% rename from apps/openmw/mwsound/openal_output.cpp rename to apps/openmw/mwsound/openaloutput.cpp index f829ea458a..0f27524912 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openaloutput.cpp @@ -17,14 +17,13 @@ #include #include +#include "efxpresets.h" #include "loudness.hpp" -#include "openal_output.hpp" +#include "openaloutput.hpp" #include "sound.hpp" -#include "sound_decoder.hpp" +#include "sounddecoder.hpp" #include "soundmanagerimp.hpp" -#include "efx-presets.h" - #ifndef ALC_ALL_DEVICES_SPECIFIER #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif @@ -301,7 +300,7 @@ namespace MWSound OpenAL_SoundStream(const OpenAL_SoundStream& rhs); OpenAL_SoundStream& operator=(const OpenAL_SoundStream& rhs); - friend class OpenAL_Output; + friend class OpenALOutput; public: OpenAL_SoundStream(ALuint src, DecoderPtr decoder); @@ -323,7 +322,7 @@ namespace MWSound // // A background streaming thread (keeps active streams processed) // - struct OpenAL_Output::StreamThread + struct OpenALOutput::StreamThread { std::vector mStreams; @@ -393,13 +392,13 @@ namespace MWSound StreamThread& operator=(const StreamThread& rhs) = delete; }; - class OpenAL_Output::DefaultDeviceThread + class OpenALOutput::DefaultDeviceThread { public: std::basic_string mCurrentName; private: - OpenAL_Output& mOutput; + OpenALOutput& mOutput; std::atomic mQuitNow; std::mutex mMutex; @@ -433,7 +432,7 @@ namespace MWSound } public: - DefaultDeviceThread(OpenAL_Output& output, std::basic_string_view name = {}) + DefaultDeviceThread(OpenALOutput& output, std::basic_string_view name = {}) : mCurrentName(name) , mOutput(output) , mQuitNow(false) @@ -655,7 +654,7 @@ namespace MWSound // // An OpenAL output device // - std::vector OpenAL_Output::enumerate() + std::vector OpenALOutput::enumerate() { std::vector devlist; const ALCchar* devnames; @@ -672,14 +671,14 @@ namespace MWSound return devlist; } - void OpenAL_Output::eventCallback( + void OpenALOutput::eventCallback( ALenum eventType, ALuint object, ALuint param, ALsizei length, const ALchar* message, void* userParam) { if (eventType == AL_EVENT_TYPE_DISCONNECTED_SOFT) - static_cast(userParam)->onDisconnect(); + static_cast(userParam)->onDisconnect(); } - void OpenAL_Output::onDisconnect() + void OpenALOutput::onDisconnect() { if (!mInitialized || !alcReopenDeviceSOFT) return; @@ -702,7 +701,7 @@ namespace MWSound } } - bool OpenAL_Output::init(const std::string& devname, const std::string& hrtfname, HrtfMode hrtfmode) + bool OpenALOutput::init(const std::string& devname, const std::string& hrtfname, HrtfMode hrtfmode) { deinit(); std::lock_guard lock(mReopenMutex); @@ -802,7 +801,7 @@ namespace MWSound { static const std::array events{ { AL_EVENT_TYPE_DISCONNECTED_SOFT } }; alEventControlSOFT(events.size(), events.data(), AL_TRUE); - alEventCallbackSOFT(&OpenAL_Output::eventCallback, this); + alEventCallbackSOFT(&OpenALOutput::eventCallback, this); } else Log(Debug::Warning) << "Cannot detect audio device changes"; @@ -970,7 +969,7 @@ namespace MWSound return true; } - void OpenAL_Output::deinit() + void OpenALOutput::deinit() { mStreamThread->removeAll(); mDefaultDeviceThread.reset(); @@ -1006,7 +1005,7 @@ namespace MWSound mInitialized = false; } - std::vector OpenAL_Output::enumerateHrtf() + std::vector OpenALOutput::enumerateHrtf() { std::vector ret; @@ -1028,7 +1027,7 @@ namespace MWSound return ret; } - std::pair OpenAL_Output::loadSound(VFS::Path::NormalizedView fname) + std::pair OpenALOutput::loadSound(VFS::Path::NormalizedView fname) { getALError(); @@ -1076,7 +1075,7 @@ namespace MWSound return std::make_pair(MAKE_PTRID(buf), size); } - size_t OpenAL_Output::unloadSound(Sound_Handle data) + size_t OpenALOutput::unloadSound(Sound_Handle data) { ALuint buffer = GET_PTRID(data); if (!buffer) @@ -1105,7 +1104,7 @@ namespace MWSound return size; } - void OpenAL_Output::initCommon2D( + void OpenALOutput::initCommon2D( ALuint source, const osg::Vec3f& pos, ALfloat gain, ALfloat pitch, bool loop, bool useenv) { alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); @@ -1143,7 +1142,7 @@ namespace MWSound alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); } - void OpenAL_Output::initCommon3D(ALuint source, const osg::Vec3f& pos, ALfloat mindist, ALfloat maxdist, + void OpenALOutput::initCommon3D(ALuint source, const osg::Vec3f& pos, ALfloat mindist, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool loop, bool useenv) { alSourcef(source, AL_REFERENCE_DISTANCE, mindist); @@ -1183,7 +1182,7 @@ namespace MWSound alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); } - void OpenAL_Output::updateCommon( + void OpenALOutput::updateCommon( ALuint source, const osg::Vec3f& pos, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool useenv) { if (useenv && mListenerEnv == Env_Underwater && !mWaterFilter) @@ -1199,7 +1198,7 @@ namespace MWSound alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); } - bool OpenAL_Output::playSound(Sound* sound, Sound_Handle data, float offset) + bool OpenALOutput::playSound(Sound* sound, Sound_Handle data, float offset) { ALuint source; @@ -1238,7 +1237,7 @@ namespace MWSound return true; } - bool OpenAL_Output::playSound3D(Sound* sound, Sound_Handle data, float offset) + bool OpenALOutput::playSound3D(Sound* sound, Sound_Handle data, float offset) { ALuint source; @@ -1277,7 +1276,7 @@ namespace MWSound return true; } - void OpenAL_Output::finishSound(Sound* sound) + void OpenALOutput::finishSound(Sound* sound) { if (!sound->mHandle) return; @@ -1294,7 +1293,7 @@ namespace MWSound mActiveSounds.erase(std::find(mActiveSounds.begin(), mActiveSounds.end(), sound)); } - bool OpenAL_Output::isSoundPlaying(Sound* sound) + bool OpenALOutput::isSoundPlaying(Sound* sound) { if (!sound->mHandle) return false; @@ -1307,7 +1306,7 @@ namespace MWSound return state == AL_PLAYING || state == AL_PAUSED; } - void OpenAL_Output::updateSound(Sound* sound) + void OpenALOutput::updateSound(Sound* sound) { if (!sound->mHandle) return; @@ -1318,7 +1317,7 @@ namespace MWSound getALError(); } - bool OpenAL_Output::streamSound(DecoderPtr decoder, Stream* sound, bool getLoudnessData) + bool OpenALOutput::streamSound(DecoderPtr decoder, Stream* sound, bool getLoudnessData) { if (mFreeSources.empty()) { @@ -1349,7 +1348,7 @@ namespace MWSound return true; } - bool OpenAL_Output::streamSound3D(DecoderPtr decoder, Stream* sound, bool getLoudnessData) + bool OpenALOutput::streamSound3D(DecoderPtr decoder, Stream* sound, bool getLoudnessData) { if (mFreeSources.empty()) { @@ -1380,7 +1379,7 @@ namespace MWSound return true; } - void OpenAL_Output::finishStream(Stream* sound) + void OpenALOutput::finishStream(Stream* sound) { if (!sound->mHandle) return; @@ -1402,7 +1401,7 @@ namespace MWSound delete stream; } - double OpenAL_Output::getStreamDelay(Stream* sound) + double OpenALOutput::getStreamDelay(Stream* sound) { if (!sound->mHandle) return 0.0; @@ -1410,7 +1409,7 @@ namespace MWSound return stream->getStreamDelay(); } - double OpenAL_Output::getStreamOffset(Stream* sound) + double OpenALOutput::getStreamOffset(Stream* sound) { if (!sound->mHandle) return 0.0; @@ -1419,7 +1418,7 @@ namespace MWSound return stream->getStreamOffset(); } - float OpenAL_Output::getStreamLoudness(Stream* sound) + float OpenALOutput::getStreamLoudness(Stream* sound) { if (!sound->mHandle) return 0.0; @@ -1428,7 +1427,7 @@ namespace MWSound return stream->getCurrentLoudness(); } - bool OpenAL_Output::isStreamPlaying(Stream* sound) + bool OpenALOutput::isStreamPlaying(Stream* sound) { if (!sound->mHandle) return false; @@ -1437,7 +1436,7 @@ namespace MWSound return stream->isPlaying(); } - void OpenAL_Output::updateStream(Stream* sound) + void OpenALOutput::updateStream(Stream* sound) { if (!sound->mHandle) return; @@ -1449,17 +1448,17 @@ namespace MWSound getALError(); } - void OpenAL_Output::startUpdate() + void OpenALOutput::startUpdate() { alcSuspendContext(alcGetCurrentContext()); } - void OpenAL_Output::finishUpdate() + void OpenALOutput::finishUpdate() { alcProcessContext(alcGetCurrentContext()); } - void OpenAL_Output::updateListener( + void OpenALOutput::updateListener( const osg::Vec3f& pos, const osg::Vec3f& atdir, const osg::Vec3f& updir, Environment env) { if (mContext) @@ -1501,7 +1500,7 @@ namespace MWSound mListenerEnv = env; } - void OpenAL_Output::pauseSounds(int types) + void OpenALOutput::pauseSounds(int types) { std::vector sources; for (Sound* sound : mActiveSounds) @@ -1524,7 +1523,7 @@ namespace MWSound } } - void OpenAL_Output::pauseActiveDevice() + void OpenALOutput::pauseActiveDevice() { if (mDevice == nullptr) return; @@ -1540,7 +1539,7 @@ namespace MWSound alListenerf(AL_GAIN, 0.0f); } - void OpenAL_Output::resumeActiveDevice() + void OpenALOutput::resumeActiveDevice() { if (mDevice == nullptr) return; @@ -1556,7 +1555,7 @@ namespace MWSound alListenerf(AL_GAIN, 1.0f); } - void OpenAL_Output::resumeSounds(int types) + void OpenALOutput::resumeSounds(int types) { std::vector sources; for (Sound* sound : mActiveSounds) @@ -1579,8 +1578,8 @@ namespace MWSound } } - OpenAL_Output::OpenAL_Output(SoundManager& mgr) - : Sound_Output(mgr) + OpenALOutput::OpenALOutput(SoundManager& mgr) + : SoundOutput(mgr) , mDevice(nullptr) , mContext(nullptr) , mListenerPos(0.0f, 0.0f, 0.0f) @@ -1593,12 +1592,12 @@ namespace MWSound { } - OpenAL_Output::~OpenAL_Output() + OpenALOutput::~OpenALOutput() { - OpenAL_Output::deinit(); + OpenALOutput::deinit(); } - float OpenAL_Output::getTimeScaledPitch(SoundBase* sound) + float OpenALOutput::getTimeScaledPitch(SoundBase* sound) { const bool shouldScale = !(sound->mParams.mFlags & PlayMode::NoScaling); return shouldScale ? sound->getPitch() * mManager.getSimulationTimeScale() : sound->getPitch(); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openaloutput.hpp similarity index 91% rename from apps/openmw/mwsound/openal_output.hpp rename to apps/openmw/mwsound/openaloutput.hpp index b419038eab..4e96dd1627 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openaloutput.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_SOUND_OPENAL_OUTPUT_H -#define GAME_SOUND_OPENAL_OUTPUT_H +#ifndef GAME_SOUND_OPENALOUTPUT_H +#define GAME_SOUND_OPENALOUTPUT_H #include #include @@ -13,7 +13,7 @@ #include "alc.h" #include "alext.h" -#include "sound_output.hpp" +#include "soundoutput.hpp" namespace MWSound { @@ -22,7 +22,7 @@ namespace MWSound class Sound; class Stream; - class OpenAL_Output : public Sound_Output + class OpenALOutput : public SoundOutput { ALCdevice* mDevice; ALCcontext* mContext; @@ -72,8 +72,8 @@ namespace MWSound float getTimeScaledPitch(SoundBase* sound); - OpenAL_Output& operator=(const OpenAL_Output& rhs); - OpenAL_Output(const OpenAL_Output& rhs); + OpenALOutput& operator=(const OpenALOutput& rhs); + OpenALOutput(const OpenALOutput& rhs); static void eventCallback( ALenum eventType, ALuint object, ALuint param, ALsizei length, const ALchar* message, void* userParam); @@ -117,8 +117,8 @@ namespace MWSound void pauseActiveDevice() override; void resumeActiveDevice() override; - OpenAL_Output(SoundManager& mgr); - virtual ~OpenAL_Output(); + OpenALOutput(SoundManager& mgr); + virtual ~OpenALOutput(); }; } diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 48e8975340..5160b2934f 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -3,7 +3,7 @@ #include -#include "sound_output.hpp" +#include "soundoutput.hpp" namespace MWSound { @@ -53,7 +53,7 @@ namespace MWSound protected: Sound_Instance mHandle = nullptr; - friend class OpenAL_Output; + friend class OpenALOutput; public: void setPosition(const osg::Vec3f& pos) { mParams.mPos = pos; } diff --git a/apps/openmw/mwsound/sound_buffer.cpp b/apps/openmw/mwsound/soundbuffer.cpp similarity index 85% rename from apps/openmw/mwsound/sound_buffer.cpp rename to apps/openmw/mwsound/soundbuffer.cpp index f28b268df2..722d89f0eb 100644 --- a/apps/openmw/mwsound/sound_buffer.cpp +++ b/apps/openmw/mwsound/soundbuffer.cpp @@ -1,4 +1,4 @@ -#include "sound_buffer.hpp" +#include "soundbuffer.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/esmstore.hpp" @@ -35,7 +35,7 @@ namespace MWSound } } - SoundBufferPool::SoundBufferPool(Sound_Output& output) + SoundBufferPool::SoundBufferPool(SoundOutput& output) : mOutput(&output) , mBufferCacheMax(Settings::sound().mBufferCacheMax * 1024 * 1024) , mBufferCacheMin( @@ -48,31 +48,31 @@ namespace MWSound clear(); } - Sound_Buffer* SoundBufferPool::lookup(const ESM::RefId& soundId) const + SoundBuffer* SoundBufferPool::lookup(const ESM::RefId& soundId) const { const auto it = mBufferNameMap.find(soundId); if (it != mBufferNameMap.end()) { - Sound_Buffer* sfx = it->second; + SoundBuffer* sfx = it->second; if (sfx->getHandle() != nullptr) return sfx; } return nullptr; } - Sound_Buffer* SoundBufferPool::lookup(std::string_view fileName) const + SoundBuffer* SoundBufferPool::lookup(std::string_view fileName) const { const auto it = mBufferFileNameMap.find(std::string(fileName)); if (it != mBufferFileNameMap.end()) { - Sound_Buffer* sfx = it->second; + SoundBuffer* sfx = it->second; if (sfx->getHandle() != nullptr) return sfx; } return nullptr; } - Sound_Buffer* SoundBufferPool::loadSfx(Sound_Buffer* sfx) + SoundBuffer* SoundBufferPool::loadSfx(SoundBuffer* sfx) { if (sfx->getHandle() != nullptr) return sfx; @@ -95,7 +95,7 @@ namespace MWSound return sfx; } - Sound_Buffer* SoundBufferPool::load(const ESM::RefId& soundId) + SoundBuffer* SoundBufferPool::load(const ESM::RefId& soundId) { if (mBufferNameMap.empty()) { @@ -103,7 +103,7 @@ namespace MWSound insertSound(sound.mId, sound); } - Sound_Buffer* sfx; + SoundBuffer* sfx; const auto it = mBufferNameMap.find(soundId); if (it != mBufferNameMap.end()) sfx = it->second; @@ -118,9 +118,9 @@ namespace MWSound return loadSfx(sfx); } - Sound_Buffer* SoundBufferPool::load(std::string_view fileName) + SoundBuffer* SoundBufferPool::load(std::string_view fileName) { - Sound_Buffer* sfx; + SoundBuffer* sfx; const auto it = mBufferFileNameMap.find(std::string(fileName)); if (it != mBufferFileNameMap.end()) sfx = it->second; @@ -146,7 +146,7 @@ namespace MWSound mUnusedBuffers.clear(); } - Sound_Buffer* SoundBufferPool::insertSound(std::string_view fileName) + SoundBuffer* SoundBufferPool::insertSound(std::string_view fileName) { static const AudioParams audioParams = makeAudioParams(MWBase::Environment::get().getESMStore()->get()); @@ -158,13 +158,13 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - Sound_Buffer& sfx = mSoundBuffers.emplace_back(fileName, volume, min, max); + SoundBuffer& sfx = mSoundBuffers.emplace_back(fileName, volume, min, max); mBufferFileNameMap.emplace(fileName, &sfx); return &sfx; } - Sound_Buffer* SoundBufferPool::insertSound(const ESM::RefId& soundId, const ESM::Sound& sound) + SoundBuffer* SoundBufferPool::insertSound(const ESM::RefId& soundId, const ESM::Sound& sound) { static const AudioParams audioParams = makeAudioParams(MWBase::Environment::get().getESMStore()->get()); @@ -183,7 +183,7 @@ namespace MWSound min = std::max(min, 1.0f); max = std::max(min, max); - Sound_Buffer& sfx = mSoundBuffers.emplace_back( + SoundBuffer& sfx = mSoundBuffers.emplace_back( Misc::ResourceHelpers::correctSoundPath(VFS::Path::Normalized(sound.mSound)), volume, min, max); mBufferNameMap.emplace(soundId, &sfx); @@ -194,7 +194,7 @@ namespace MWSound { while (!mUnusedBuffers.empty() && mBufferCacheSize > mBufferCacheMin) { - Sound_Buffer* const unused = mUnusedBuffers.back(); + SoundBuffer* const unused = mUnusedBuffers.back(); mBufferCacheSize -= mOutput->unloadSound(unused->getHandle()); unused->mHandle = nullptr; diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/soundbuffer.hpp similarity index 68% rename from apps/openmw/mwsound/sound_buffer.hpp rename to apps/openmw/mwsound/soundbuffer.hpp index 7de6dab9ae..f7e7639b2d 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/soundbuffer.hpp @@ -1,14 +1,15 @@ -#ifndef GAME_SOUND_SOUND_BUFFER_H -#define GAME_SOUND_SOUND_BUFFER_H +#ifndef GAME_SOUND_SOUNDBUFFER_H +#define GAME_SOUND_SOUNDBUFFER_H #include #include #include #include -#include "sound_output.hpp" #include +#include "soundoutput.hpp" + namespace ESM { struct Sound; @@ -23,11 +24,11 @@ namespace MWSound { class SoundBufferPool; - class Sound_Buffer + class SoundBuffer { public: template - Sound_Buffer(T&& resname, float volume, float mindist, float maxdist) + SoundBuffer(T&& resname, float volume, float mindist, float maxdist) : mResourceName(std::forward(resname)) , mVolume(volume) , mMinDist(mindist) @@ -59,7 +60,7 @@ namespace MWSound class SoundBufferPool { public: - SoundBufferPool(Sound_Output& output); + SoundBufferPool(SoundOutput& output); SoundBufferPool(const SoundBufferPool&) = delete; @@ -67,20 +68,20 @@ namespace MWSound /// Lookup a soundId for its sound data (resource name, local volume, /// minRange, and maxRange) - Sound_Buffer* lookup(const ESM::RefId& soundId) const; + SoundBuffer* lookup(const ESM::RefId& soundId) const; /// Lookup a sound by file name for its sound data (resource name, local volume, /// minRange, and maxRange) - Sound_Buffer* lookup(std::string_view fileName) const; + SoundBuffer* lookup(std::string_view fileName) const; /// Lookup a soundId for its sound data (resource name, local volume, /// minRange, and maxRange), and ensure it's ready for use. - Sound_Buffer* load(const ESM::RefId& soundId); + SoundBuffer* load(const ESM::RefId& soundId); // Lookup for a sound by file name, and ensure it's ready for use. - Sound_Buffer* load(std::string_view fileName); + SoundBuffer* load(std::string_view fileName); - void use(Sound_Buffer& sfx) + void use(SoundBuffer& sfx) { if (sfx.mUses++ == 0) { @@ -90,7 +91,7 @@ namespace MWSound } } - void release(Sound_Buffer& sfx) + void release(SoundBuffer& sfx) { if (--sfx.mUses == 0) mUnusedBuffers.push_front(&sfx); @@ -99,23 +100,23 @@ namespace MWSound void clear(); private: - Sound_Buffer* loadSfx(Sound_Buffer* sfx); + SoundBuffer* loadSfx(SoundBuffer* sfx); - Sound_Output* mOutput; - std::deque mSoundBuffers; - std::unordered_map mBufferNameMap; - std::unordered_map mBufferFileNameMap; + SoundOutput* mOutput; + std::deque mSoundBuffers; + std::unordered_map mBufferNameMap; + std::unordered_map mBufferFileNameMap; std::size_t mBufferCacheMax; std::size_t mBufferCacheMin; std::size_t mBufferCacheSize = 0; // NOTE: unused buffers are stored in front-newest order. - std::deque mUnusedBuffers; + std::deque mUnusedBuffers; - inline Sound_Buffer* insertSound(const ESM::RefId& soundId, const ESM::Sound& sound); - inline Sound_Buffer* insertSound(std::string_view fileName); + inline SoundBuffer* insertSound(const ESM::RefId& soundId, const ESM::Sound& sound); + inline SoundBuffer* insertSound(std::string_view fileName); inline void unloadUnused(); }; } -#endif /* GAME_SOUND_SOUND_BUFFER_H */ +#endif /* GAME_SOUND_SOUNDBUFFER_H */ diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sounddecoder.hpp similarity index 80% rename from apps/openmw/mwsound/sound_decoder.hpp rename to apps/openmw/mwsound/sounddecoder.hpp index 17f9d28909..675fad4197 100644 --- a/apps/openmw/mwsound/sound_decoder.hpp +++ b/apps/openmw/mwsound/sounddecoder.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_SOUND_SOUND_DECODER_H -#define GAME_SOUND_SOUND_DECODER_H +#ifndef GAME_SOUND_SOUNDDECODER_H +#define GAME_SOUND_SOUNDDECODER_H #include @@ -34,7 +34,7 @@ namespace MWSound size_t framesToBytes(size_t frames, ChannelConfig config, SampleType type); size_t bytesToFrames(size_t bytes, ChannelConfig config, SampleType type); - struct Sound_Decoder + struct SoundDecoder { const VFS::Manager* mResourceMgr; @@ -48,15 +48,15 @@ namespace MWSound virtual void readAll(std::vector& output); virtual size_t getSampleOffset() = 0; - Sound_Decoder(const VFS::Manager* resourceMgr) + SoundDecoder(const VFS::Manager* resourceMgr) : mResourceMgr(resourceMgr) { } - virtual ~Sound_Decoder() {} + virtual ~SoundDecoder() {} private: - Sound_Decoder(const Sound_Decoder& rhs); - Sound_Decoder& operator=(const Sound_Decoder& rhs); + SoundDecoder(const SoundDecoder& rhs); + SoundDecoder& operator=(const SoundDecoder& rhs); }; } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1d9a6d457c..66bdfbdbfa 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -26,12 +26,12 @@ #include "../mwmechanics/actorutil.hpp" #include "constants.hpp" -#include "ffmpeg_decoder.hpp" -#include "openal_output.hpp" +#include "ffmpegdecoder.hpp" +#include "openaloutput.hpp" #include "sound.hpp" -#include "sound_buffer.hpp" -#include "sound_decoder.hpp" -#include "sound_output.hpp" +#include "soundbuffer.hpp" +#include "sounddecoder.hpp" +#include "soundoutput.hpp" namespace MWSound { @@ -57,7 +57,7 @@ namespace MWSound return settings; } - float initialFadeVolume(float squaredDist, Sound_Buffer* sfx, Type type, PlayMode mode) + float initialFadeVolume(float squaredDist, SoundBuffer* sfx, Type type, PlayMode mode) { // If a sound is farther away than its maximum distance, start playing it with a zero fade volume. // It can still become audible once the player moves closer. @@ -111,7 +111,7 @@ namespace MWSound SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) : mVFS(vfs) - , mOutput(std::make_unique(*this)) + , mOutput(std::make_unique(*this)) , mWaterSoundUpdater(makeWaterSoundUpdaterSettings()) , mSoundBuffers(*mOutput) , mMusicType(MWSound::MusicType::Normal) @@ -169,7 +169,7 @@ namespace MWSound // Return a new decoder instance, used as needed by the output implementations DecoderPtr SoundManager::getDecoder() { - return std::make_shared(mVFS); + return std::make_shared(mVFS); } DecoderPtr SoundManager::loadVoice(VFS::Path::NormalizedView voicefile) @@ -459,7 +459,7 @@ namespace MWSound return false; } - Sound* SoundManager::playSound(Sound_Buffer* sfx, float volume, float pitch, Type type, PlayMode mode, float offset) + Sound* SoundManager::playSound(SoundBuffer* sfx, float volume, float pitch, Type type, PlayMode mode, float offset) { if (!mOutput->isInitialized()) return nullptr; @@ -495,7 +495,7 @@ namespace MWSound if (!mVFS->exists(normalizedName)) return nullptr; - Sound_Buffer* sfx = mSoundBuffers.load(normalizedName); + SoundBuffer* sfx = mSoundBuffers.load(normalizedName); if (!sfx) return nullptr; @@ -508,14 +508,14 @@ namespace MWSound if (!mOutput->isInitialized()) return nullptr; - Sound_Buffer* sfx = mSoundBuffers.load(soundId); + SoundBuffer* sfx = mSoundBuffers.load(soundId); if (!sfx) return nullptr; return playSound(sfx, volume, pitch, type, mode, offset); } - Sound* SoundManager::playSound3D(const MWWorld::ConstPtr& ptr, Sound_Buffer* sfx, float volume, float pitch, + Sound* SoundManager::playSound3D(const MWWorld::ConstPtr& ptr, SoundBuffer* sfx, float volume, float pitch, Type type, PlayMode mode, float offset) { if (!mOutput->isInitialized()) @@ -576,7 +576,7 @@ namespace MWSound return nullptr; // Look up the sound in the ESM data - Sound_Buffer* sfx = mSoundBuffers.load(soundId); + SoundBuffer* sfx = mSoundBuffers.load(soundId); if (!sfx) return nullptr; @@ -594,7 +594,7 @@ namespace MWSound if (!mVFS->exists(normalizedName)) return nullptr; - Sound_Buffer* sfx = mSoundBuffers.load(normalizedName); + SoundBuffer* sfx = mSoundBuffers.load(normalizedName); if (!sfx) return nullptr; @@ -608,7 +608,7 @@ namespace MWSound return nullptr; // Look up the sound in the ESM data - Sound_Buffer* sfx = mSoundBuffers.load(soundId); + SoundBuffer* sfx = mSoundBuffers.load(soundId); if (!sfx) return nullptr; @@ -642,7 +642,7 @@ namespace MWSound mOutput->finishSound(sound); } - void SoundManager::stopSound(Sound_Buffer* sfx, const MWWorld::ConstPtr& ptr) + void SoundManager::stopSound(SoundBuffer* sfx, const MWWorld::ConstPtr& ptr) { SoundMap::iterator snditer = mActiveSounds.find(ptr.mRef); if (snditer != mActiveSounds.end()) @@ -660,7 +660,7 @@ namespace MWSound if (!mOutput->isInitialized()) return; - Sound_Buffer* sfx = mSoundBuffers.lookup(soundId); + SoundBuffer* sfx = mSoundBuffers.lookup(soundId); if (!sfx) return; @@ -673,7 +673,7 @@ namespace MWSound return; std::string normalizedName = VFS::Path::normalizeFilename(fileName); - Sound_Buffer* sfx = mSoundBuffers.lookup(normalizedName); + SoundBuffer* sfx = mSoundBuffers.lookup(normalizedName); if (!sfx) return; @@ -725,7 +725,7 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr.mRef); if (snditer != mActiveSounds.end()) { - Sound_Buffer* sfx = mSoundBuffers.lookup(soundId); + SoundBuffer* sfx = mSoundBuffers.lookup(soundId); if (sfx == nullptr) return; for (SoundBufferRefPair& sndbuf : snditer->second.mList) @@ -743,7 +743,7 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.find(ptr.mRef); if (snditer != mActiveSounds.end()) { - Sound_Buffer* sfx = mSoundBuffers.lookup(normalizedName); + SoundBuffer* sfx = mSoundBuffers.lookup(normalizedName); if (!sfx) return false; @@ -761,7 +761,7 @@ namespace MWSound SoundMap::const_iterator snditer = mActiveSounds.find(ptr.mRef); if (snditer != mActiveSounds.end()) { - Sound_Buffer* sfx = mSoundBuffers.lookup(soundId); + SoundBuffer* sfx = mSoundBuffers.lookup(soundId); if (!sfx) return false; @@ -846,7 +846,7 @@ namespace MWSound const auto update = mWaterSoundUpdater.update(player, *world); WaterSoundAction action; - Sound_Buffer* sfx; + SoundBuffer* sfx; std::tie(action, sfx) = getWaterSoundAction(update, curcell); switch (action) @@ -870,7 +870,7 @@ namespace MWSound mLastCell = curcell; } - std::pair SoundManager::getWaterSoundAction( + std::pair SoundManager::getWaterSoundAction( const WaterSoundUpdate& update, const MWWorld::Cell* cell) const { if (mNearWaterSound) @@ -880,7 +880,7 @@ namespace MWSound bool soundIdChanged = false; - Sound_Buffer* sfx = mSoundBuffers.lookup(update.mId); + SoundBuffer* sfx = mSoundBuffers.lookup(update.mId); if (mLastCell != cell) { const auto snditer = mActiveSounds.find(nullptr); @@ -1168,7 +1168,7 @@ namespace MWSound // Default readAll implementation, for decoders that can't do anything // better - void Sound_Decoder::readAll(std::vector& output) + void SoundDecoder::readAll(std::vector& output) { size_t total = output.size(); size_t got; diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index a5e5b2c45f..8fc7e6701f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -15,7 +15,7 @@ #include "../mwbase/soundmanager.hpp" #include "regionsoundselector.hpp" -#include "sound_buffer.hpp" +#include "soundbuffer.hpp" #include "type.hpp" #include "watersoundupdater.hpp" @@ -37,8 +37,8 @@ namespace MWWorld namespace MWSound { - class Sound_Output; - struct Sound_Decoder; + class SoundOutput; + struct SoundDecoder; class SoundBase; class Sound; class Stream; @@ -50,7 +50,7 @@ namespace MWSound { const VFS::Manager* mVFS; - std::unique_ptr mOutput; + std::unique_ptr mOutput; WaterSoundUpdater mWaterSoundUpdater; @@ -60,7 +60,7 @@ namespace MWSound Misc::ObjectPool mStreams; - typedef std::pair SoundBufferRefPair; + typedef std::pair SoundBufferRefPair; typedef std::vector SoundBufferRefPairList; struct ActiveSound @@ -109,7 +109,7 @@ namespace MWSound Sound* mCurrentRegionSound; - Sound_Buffer* insertSound(const std::string& soundId, const ESM::Sound* sound); + SoundBuffer* insertSound(const std::string& soundId, const ESM::Sound* sound); // returns a decoder to start streaming, or nullptr if the sound was not found DecoderPtr loadVoice(VFS::Path::NormalizedView voicefile); @@ -126,9 +126,9 @@ namespace MWSound bool remove3DSoundAtDistance(PlayMode mode, const MWWorld::ConstPtr& ptr) const; - Sound* playSound(Sound_Buffer* sfx, float volume, float pitch, Type type = Type::Sfx, + Sound* playSound(SoundBuffer* sfx, float volume, float pitch, Type type = Type::Sfx, PlayMode mode = PlayMode::Normal, float offset = 0); - Sound* playSound3D(const MWWorld::ConstPtr& ptr, Sound_Buffer* sfx, float volume, float pitch, Type type, + Sound* playSound3D(const MWWorld::ConstPtr& ptr, SoundBuffer* sfx, float volume, float pitch, Type type, PlayMode mode, float offset); void updateSounds(float duration); @@ -144,7 +144,7 @@ namespace MWSound PlaySound, }; - std::pair getWaterSoundAction( + std::pair getWaterSoundAction( const WaterSoundUpdate& update, const MWWorld::Cell* cell) const; SoundManager(const SoundManager& rhs); @@ -152,9 +152,9 @@ namespace MWSound protected: DecoderPtr getDecoder(); - friend class OpenAL_Output; + friend class OpenALOutput; - void stopSound(Sound_Buffer* sfx, const MWWorld::ConstPtr& ptr); + void stopSound(SoundBuffer* sfx, const MWWorld::ConstPtr& ptr); ///< Stop the given object from playing given sound buffer. public: diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/soundoutput.hpp similarity index 88% rename from apps/openmw/mwsound/sound_output.hpp rename to apps/openmw/mwsound/soundoutput.hpp index 5a77124985..e5c266b204 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/soundoutput.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_SOUND_SOUND_OUTPUT_H -#define GAME_SOUND_SOUND_OUTPUT_H +#ifndef GAME_SOUND_SOUNDOUTPUT_H +#define GAME_SOUND_SOUNDOUTPUT_H #include #include @@ -13,7 +13,7 @@ namespace MWSound { class SoundManager; - struct Sound_Decoder; + struct SoundDecoder; class Sound; class Stream; @@ -30,7 +30,7 @@ namespace MWSound using HrtfMode = Settings::HrtfMode; - class Sound_Output + class SoundOutput { SoundManager& mManager; @@ -71,24 +71,24 @@ namespace MWSound virtual void pauseActiveDevice() = 0; virtual void resumeActiveDevice() = 0; - Sound_Output& operator=(const Sound_Output& rhs); - Sound_Output(const Sound_Output& rhs); + SoundOutput& operator=(const SoundOutput& rhs); + SoundOutput(const SoundOutput& rhs); protected: bool mInitialized; - Sound_Output(SoundManager& mgr) + SoundOutput(SoundManager& mgr) : mManager(mgr) , mInitialized(false) { } public: - virtual ~Sound_Output() {} + virtual ~SoundOutput() {} bool isInitialized() const { return mInitialized; } - friend class OpenAL_Output; + friend class OpenALOutput; friend class SoundManager; friend class SoundBufferPool; }; From cf7e276a6ae066464720ca2f00a1d573ec28c2b2 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 22 Feb 2025 23:52:17 +0300 Subject: [PATCH 19/98] Remove file name exceptions (#7249) --- CI/check_file_names.sh | 3 +-- CI/file_name_exceptions.txt | 0 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 CI/file_name_exceptions.txt diff --git a/CI/check_file_names.sh b/CI/check_file_names.sh index b04416659e..2a0f421cc9 100755 --- a/CI/check_file_names.sh +++ b/CI/check_file_names.sh @@ -1,7 +1,6 @@ #!/bin/bash -ex git ls-files -- ':(exclude)extern/' '*.cpp' '*.hpp' '*.h' | - grep -vP '/[a-z0-9]+\.(cpp|hpp|h)$' | - grep -vFf CI/file_name_exceptions.txt && + grep -vP '/[a-z0-9]+\.(cpp|hpp|h)$' && ( echo 'File names do not follow the naming convention, see https://wiki.openmw.org/index.php?title=Naming_Conventions#Files'; exit -1 ) exit 0 diff --git a/CI/file_name_exceptions.txt b/CI/file_name_exceptions.txt deleted file mode 100644 index e69de29bb2..0000000000 From 61e2117e9d15e08a4e18be1ce34df2e991d8cca6 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 4 Mar 2025 03:41:27 +0300 Subject: [PATCH 20/98] Remove excessive spacing between travel destination and price --- apps/openmw/mwgui/travelwindow.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 6ba3a55286..8c4999a13d 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -93,8 +93,7 @@ namespace MWGui const std::string& nameString = name.getRefIdString(); toAdd->setUserString("price", std::to_string(price)); - toAdd->setCaptionWithReplacing( - "#{sCell=" + nameString + "} - " + MyGUI::utility::toString(price) + "#{sgp}"); + toAdd->setCaptionWithReplacing("#{sCell=" + nameString + "} - " + MyGUI::utility::toString(price) + "#{sgp}"); toAdd->setSize(mDestinationsView->getWidth(), lineHeight); toAdd->eventMouseWheel += MyGUI::newDelegate(this, &TravelWindow::onMouseWheel); toAdd->setUserString("Destination", nameString); From 59edf4750bd6e00fa311c4cce97c67320ced9951 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 4 Mar 2025 05:23:40 +0300 Subject: [PATCH 21/98] Fix Travel window header alignment --- apps/openmw/mwgui/travelwindow.cpp | 6 ------ apps/openmw/mwgui/travelwindow.hpp | 2 -- files/data/mygui/openmw_travel_window.layout | 13 ++++++------- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 6ba3a55286..d1b578ff9a 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -33,15 +33,9 @@ namespace MWGui { getWidget(mCancelButton, "CancelButton"); getWidget(mPlayerGold, "PlayerGold"); - getWidget(mSelect, "Select"); - getWidget(mDestinations, "Travel"); getWidget(mDestinationsView, "DestinationsView"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TravelWindow::onCancelButtonClicked); - - mDestinations->setCoord(450 / 2 - mDestinations->getTextSize().width / 2, mDestinations->getTop(), - mDestinations->getTextSize().width, mDestinations->getHeight()); - mSelect->setCoord(8, mSelect->getTop(), mSelect->getTextSize().width, mSelect->getHeight()); } void TravelWindow::addDestination(const ESM::RefId& name, const ESM::Position& pos, bool interior) diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 6d7c1c7376..630e27518a 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -24,8 +24,6 @@ namespace MWGui protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; - MyGUI::TextBox* mDestinations; - MyGUI::TextBox* mSelect; MyGUI::ScrollView* mDestinationsView; diff --git a/files/data/mygui/openmw_travel_window.layout b/files/data/mygui/openmw_travel_window.layout index 96de2fc08d..03c2e713e5 100644 --- a/files/data/mygui/openmw_travel_window.layout +++ b/files/data/mygui/openmw_travel_window.layout @@ -4,18 +4,17 @@ - - - - - + - + + + + - + From 71ef86078cc7ca755aee3f58a88527e40110a45d Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Tue, 11 Mar 2025 22:21:42 +0300 Subject: [PATCH 22/98] Clip HUD item widgets to not overlap the borders (#7740) --- files/data/mygui/openmw_hud.layout | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/files/data/mygui/openmw_hud.layout b/files/data/mygui/openmw_hud.layout index a189075f44..0650df1f43 100644 --- a/files/data/mygui/openmw_hud.layout +++ b/files/data/mygui/openmw_hud.layout @@ -44,8 +44,8 @@ - - + + @@ -56,7 +56,9 @@ - + + + @@ -131,4 +133,4 @@ - \ No newline at end of file + From 34a5eb7512f2dae1efe3e818875fc51ef1f5a32a Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 13 Mar 2025 18:42:55 +0300 Subject: [PATCH 23/98] Editor: Account for pixel ratio in instance mode mouse coordinates conversion (#6573) --- apps/opencs/view/render/instancemode.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index fb085f075a..03872a3d6c 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -171,16 +171,18 @@ osg::Vec3f CSVRender::InstanceMode::getProjectionSpaceCoords(const osg::Vec3f& p osg::Vec3f CSVRender::InstanceMode::getMousePlaneCoords(const QPoint& point, const osg::Vec3d& dragStart) { - osg::Matrix viewMatrix; - viewMatrix.invert(getWorldspaceWidget().getCamera()->getViewMatrix()); - osg::Matrix projMatrix; - projMatrix.invert(getWorldspaceWidget().getCamera()->getProjectionMatrix()); - osg::Matrix combined = projMatrix * viewMatrix; + const osg::Matrix viewMatrix = getWorldspaceWidget().getCamera()->getViewMatrix(); + const osg::Matrix projMatrix = getWorldspaceWidget().getCamera()->getProjectionMatrix(); + const osg::Matrix combined = osg::Matrix::inverse(viewMatrix * projMatrix); /* calculate viewport normalized coordinates note: is there a reason to use getCamera()->getViewport()->computeWindowMatrix() instead? */ - float x = (point.x() * 2) / getWorldspaceWidget().getCamera()->getViewport()->width() - 1.0f; - float y = 1.0f - (point.y() * 2) / getWorldspaceWidget().getCamera()->getViewport()->height(); + const float scale = getWorldspaceWidget().devicePixelRatioF(); + const osg::Viewport* viewport = getWorldspaceWidget().getCamera()->getViewport(); + float x = point.x() * scale / viewport->width(); + float y = point.y() * scale / viewport->height(); + x = x * 2.0f - 1.0f; + y = 1.0f - y * 2.0f; osg::Vec3f mousePlanePoint = osg::Vec3f(x, y, dragStart.z()) * combined; From 4db41c21116f26924177215ac8493e1818ee96b6 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 15 Mar 2025 14:29:13 +0300 Subject: [PATCH 24/98] Merchant repair menu layout tweaks --- apps/openmw/mwgui/merchantrepair.cpp | 2 +- files/data/mygui/openmw_merchantrepair.layout | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index a59f225e9e..54f9ae4187 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -75,7 +75,7 @@ namespace MWGui int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mActor, x, true); std::string name{ iter->getClass().getName(*iter) }; - name += " - " + MyGUI::utility::toString(price) + name += " - " + MyGUI::utility::toString(price) + MWBase::Environment::get().getESMStore()->get().find("sgp")->mValue.getString(); items.emplace_back(name, price, *iter); diff --git a/files/data/mygui/openmw_merchantrepair.layout b/files/data/mygui/openmw_merchantrepair.layout index 60f5e05096..940bf10f15 100644 --- a/files/data/mygui/openmw_merchantrepair.layout +++ b/files/data/mygui/openmw_merchantrepair.layout @@ -1,28 +1,28 @@ - + - - - - - + + + + + - - + + - + - + From 887e1c04ef49f3604c7f8dd07a970b930767d634 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Wed, 5 Mar 2025 05:52:26 +0300 Subject: [PATCH 25/98] Spell buying window layout tweaks --- apps/openmw/mwgui/spellbuyingwindow.cpp | 2 +- .../mygui/openmw_spell_buying_window.layout | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 9fca86caba..a66b21ba2b 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -62,7 +62,7 @@ namespace MWGui mCurrentY += lineHeight; toAdd->setUserData(price); - toAdd->setCaptionWithReplacing(spell.mName + " - " + MyGUI::utility::toString(price) + "#{sgp}"); + toAdd->setCaptionWithReplacing(spell.mName + " - " + MyGUI::utility::toString(price) + "#{sgp}"); toAdd->setSize(mSpellsView->getWidth(), lineHeight); toAdd->eventMouseWheel += MyGUI::newDelegate(this, &SpellBuyingWindow::onMouseWheel); toAdd->setUserString("ToolTipType", "Spell"); diff --git a/files/data/mygui/openmw_spell_buying_window.layout b/files/data/mygui/openmw_spell_buying_window.layout index 25a02945ee..d3ec75ef45 100644 --- a/files/data/mygui/openmw_spell_buying_window.layout +++ b/files/data/mygui/openmw_spell_buying_window.layout @@ -1,28 +1,28 @@ - + - - - - - + + + + + - - + + - + - + From 8634b6c3acb29af8bf542f89211a30a2014e2c1f Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 20 Feb 2025 22:25:12 +0300 Subject: [PATCH 26/98] Revise saved game dialog save info layout (#8313) --- apps/openmw/mwgui/savegamedialog.cpp | 25 +++++++++++-------- apps/openmw/mwgui/savegamedialog.hpp | 1 + .../data/mygui/openmw_savegame_dialog.layout | 10 ++++++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 94f25e118b..4ce6abfcd7 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -43,6 +43,7 @@ namespace MWGui { getWidget(mScreenshot, "Screenshot"); getWidget(mCharacterSelection, "SelectCharacter"); + getWidget(mCellName, "CellName"); getWidget(mInfoText, "InfoText"); getWidget(mOkButton, "OkButton"); getWidget(mCancelButton, "CancelButton"); @@ -390,6 +391,7 @@ namespace MWGui if (pos == MyGUI::ITEM_NONE || !mCurrentCharacter) { mCurrentSlot = nullptr; + mCellName->setCaption({}); mInfoText->setCaption({}); mScreenshot->setImageTexture({}); return; @@ -411,15 +413,19 @@ namespace MWGui std::stringstream text; - text << Misc::fileTimeToString(mCurrentSlot->mTimeStamp, "%Y.%m.%d %T") << "\n"; + const std::string& playerName = mCurrentSlot->mProfile.mPlayerName; + if (!playerName.empty()) + text << playerName << "\n"; + + text << "#{OMWEngine:Level} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; + + if (mCurrentSlot->mProfile.mCurrentDay > 0) + text << "#{Calendar:day} " << mCurrentSlot->mProfile.mCurrentDay << "\n"; if (mCurrentSlot->mProfile.mMaximumHealth > 0) text << "#{OMWEngine:Health} " << static_cast(mCurrentSlot->mProfile.mCurrentHealth) << "/" << static_cast(mCurrentSlot->mProfile.mMaximumHealth) << "\n"; - text << "#{OMWEngine:Level} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; - text << "#{sCell=" << mCurrentSlot->mProfile.mPlayerCellName << "}\n"; - int hour = int(mCurrentSlot->mProfile.mInGameTime.mGameHour); bool pm = hour >= 12; if (hour >= 13) @@ -427,20 +433,19 @@ namespace MWGui if (hour == 0) hour = 12; - if (mCurrentSlot->mProfile.mCurrentDay > 0) - text << "#{Calendar:day} " << mCurrentSlot->mProfile.mCurrentDay << "\n"; - text << mCurrentSlot->mProfile.mInGameTime.mDay << " " << MWBase::Environment::get().getWorld()->getTimeManager()->getMonthName( mCurrentSlot->mProfile.mInGameTime.mMonth) - << " " << hour << " " << (pm ? "#{Calendar:pm}" : "#{Calendar:am}"); + << " " << hour << " " << (pm ? "#{Calendar:pm}" : "#{Calendar:am}") << "\n"; if (mCurrentSlot->mProfile.mTimePlayed > 0) { - text << "\n" - << "#{OMWEngine:TimePlayed}: " << formatTimeplayed(mCurrentSlot->mProfile.mTimePlayed); + text << "#{OMWEngine:TimePlayed}: " << formatTimeplayed(mCurrentSlot->mProfile.mTimePlayed) << "\n"; } + text << Misc::fileTimeToString(mCurrentSlot->mTimeStamp, "%Y.%m.%d %T") << "\n"; + + mCellName->setCaptionWithReplacing("#{sCell=" + mCurrentSlot->mProfile.mPlayerCellName + "}"); mInfoText->setCaptionWithReplacing(text.str()); // Reset the image for the case we're unable to recover a screenshot diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 35e65fbed0..af831f066e 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -57,6 +57,7 @@ namespace MWGui bool mSaving; MyGUI::ComboBox* mCharacterSelection; + MyGUI::EditBox* mCellName; MyGUI::EditBox* mInfoText; MyGUI::Button* mOkButton; MyGUI::Button* mCancelButton; diff --git a/files/data/mygui/openmw_savegame_dialog.layout b/files/data/mygui/openmw_savegame_dialog.layout index 1e40b5dd34..8bb6a64401 100644 --- a/files/data/mygui/openmw_savegame_dialog.layout +++ b/files/data/mygui/openmw_savegame_dialog.layout @@ -37,14 +37,20 @@ + + + + + + + + - - From d6916c35bcde30710fb9391ad6f1d03c5832bf95 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 21 Mar 2025 03:18:22 +0300 Subject: [PATCH 27/98] Only print the player name if it doesn't match the profile --- apps/openmw/mwgui/savegamedialog.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 4ce6abfcd7..967bb23919 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -197,7 +197,8 @@ namespace MWGui title << " (#{OMWEngine:Level} " << signature.mPlayerLevel << " " << MyGUI::TextIterator::toTagsString(MyGUI::UString(className)) << ")"; - mCharacterSelection->addItem(MyGUI::LanguageManager::getInstance().replaceTags(title.str())); + const MyGUI::UString playerDesc = MyGUI::LanguageManager::getInstance().replaceTags(title.str()); + mCharacterSelection->addItem(playerDesc, signature.mPlayerName); if (mCurrentCharacter == &*it || (!mCurrentCharacter && !mSaving @@ -413,9 +414,11 @@ namespace MWGui std::stringstream text; - const std::string& playerName = mCurrentSlot->mProfile.mPlayerName; - if (!playerName.empty()) - text << playerName << "\n"; + const size_t profileIndex = mCharacterSelection->getIndexSelected(); + const std::string& slotPlayerName = mCurrentSlot->mProfile.mPlayerName; + const std::string& profilePlayerName = *mCharacterSelection->getItemDataAt(profileIndex); + if (slotPlayerName != profilePlayerName) + text << slotPlayerName << "\n"; text << "#{OMWEngine:Level} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; From 88cac9b0fa2e634034bc8bde3ffbecfc5cf54fa5 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 23 Mar 2025 18:25:20 +0100 Subject: [PATCH 28/98] Reset initial wander position when commanding actors and don't create return packages when stacking actual ai packages --- apps/openmw/mwmechanics/aipackage.hpp | 1 + apps/openmw/mwmechanics/aisequence.cpp | 25 +++++++++++++++++-------- apps/openmw/mwmechanics/aistate.hpp | 7 +------ apps/openmw/mwmechanics/aiwander.cpp | 9 ++++++++- apps/openmw/mwmechanics/aiwander.hpp | 2 ++ 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index ca33f5dc90..edb62c97c4 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -119,6 +119,7 @@ namespace MWMechanics /// Reset pathfinding state void reset(); + virtual void resetInitialPosition() {} /// Return if actor's rotation speed is sufficient to rotate to the destination pathpoint on the run. Otherwise /// actor should rotate while standing. diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 019aaf7c0a..4d1e5a0502 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -400,7 +400,7 @@ namespace MWMechanics const auto newTypeId = package.getTypeId(); if (currentTypeId <= MWMechanics::AiPackageTypeId::Wander && !hasPackage(MWMechanics::AiPackageTypeId::InternalTravel) - && (newTypeId <= MWMechanics::AiPackageTypeId::Combat || newTypeId == MWMechanics::AiPackageTypeId::Pursue + && (newTypeId == MWMechanics::AiPackageTypeId::Combat || newTypeId == MWMechanics::AiPackageTypeId::Pursue || newTypeId == MWMechanics::AiPackageTypeId::Cast)) { osg::Vec3f dest; @@ -432,8 +432,14 @@ namespace MWMechanics } // insert new package in correct place depending on priority + bool resetInitialPositions = false; for (auto it = mPackages.begin(); it != mPackages.end(); ++it) { + if (resetInitialPositions) + { + (*it)->resetInitialPosition(); + continue; + } // We should override current AiCast package, if we try to add a new one. if ((*it)->getTypeId() == MWMechanics::AiPackageTypeId::Cast && package.getTypeId() == MWMechanics::AiPackageTypeId::Cast) @@ -444,22 +450,25 @@ namespace MWMechanics if ((*it)->getPriority() <= package.getPriority()) { + if (cancelOther && isActualAiPackage((*it)->getTypeId())) + mAiState.reset(); onPackageAdded(package); - mPackages.insert(it, package.clone()); - return; + it = mPackages.insert(it, package.clone()); + if (newTypeId == MWMechanics::AiPackageTypeId::Follow) + resetInitialPositions = true; + else + return; } } + if (resetInitialPositions) + return; onPackageAdded(package); mPackages.push_back(package.clone()); // Make sure that temporary storage is empty if (cancelOther) - { - mAiState.moveIn(std::make_unique()); - mAiState.moveIn(std::make_unique()); - mAiState.moveIn(std::make_unique()); - } + mAiState.reset(); } bool MWMechanics::AiSequence::isEmpty() const diff --git a/apps/openmw/mwmechanics/aistate.hpp b/apps/openmw/mwmechanics/aistate.hpp index f2ce17fd9c..bb88557b6d 100644 --- a/apps/openmw/mwmechanics/aistate.hpp +++ b/apps/openmw/mwmechanics/aistate.hpp @@ -59,12 +59,7 @@ namespace MWMechanics mStorage = std::make_unique(payload); } - /// \brief takes ownership of the passed object - template - void moveIn(std::unique_ptr&& storage) - { - mStorage = std::move(storage); - } + void reset() { mStorage.reset(); } }; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3c299c1490..dd0c65a2f2 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -676,6 +676,13 @@ namespace MWMechanics stopMovement(actor); } + void AiWander::resetInitialPosition() + { + mStoredInitialActorPosition = false; + mPathFinder.clearPath(); + mHasDestination = false; + } + bool AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) { if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle)) @@ -804,7 +811,7 @@ namespace MWMechanics converter.toWorld(dest); - state.moveIn(std::make_unique()); + state.reset(); osg::Vec3f pos(static_cast(dest.mX), static_cast(dest.mY), static_cast(dest.mZ)); MWBase::Environment::get().getWorld()->moveObject(actor, pos); diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index aed7214f4d..39525e6e65 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -121,6 +121,8 @@ namespace MWMechanics static std::string_view getIdleGroupName(size_t index) { return sIdleSelectToGroupName[index]; } + void resetInitialPosition() override; + private: void stopWalking(const MWWorld::Ptr& actor); From 73811b45b193b02ddd2ee0e0cf935ebba26f6034 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 23 Mar 2025 21:44:04 +0100 Subject: [PATCH 29/98] Clarify the resetInitialPosition loop --- apps/openmw/mwmechanics/aisequence.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 4d1e5a0502..70b94b1eba 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -432,14 +432,8 @@ namespace MWMechanics } // insert new package in correct place depending on priority - bool resetInitialPositions = false; for (auto it = mPackages.begin(); it != mPackages.end(); ++it) { - if (resetInitialPositions) - { - (*it)->resetInitialPosition(); - continue; - } // We should override current AiCast package, if we try to add a new one. if ((*it)->getTypeId() == MWMechanics::AiPackageTypeId::Cast && package.getTypeId() == MWMechanics::AiPackageTypeId::Cast) @@ -455,13 +449,13 @@ namespace MWMechanics onPackageAdded(package); it = mPackages.insert(it, package.clone()); if (newTypeId == MWMechanics::AiPackageTypeId::Follow) - resetInitialPositions = true; - else - return; + { + for (++it; it != mPackages.end(); ++it) + (*it)->resetInitialPosition(); + } + return; } } - if (resetInitialPositions) - return; onPackageAdded(package); mPackages.push_back(package.clone()); From 0eb2ced0723bdc271aa7c814eda22254a3e3a148 Mon Sep 17 00:00:00 2001 From: Kindi Date: Fri, 4 Apr 2025 12:58:07 +0800 Subject: [PATCH 30/98] update spell windows after selecting spell using quickkey --- apps/openmw/mwgui/quickkeysmenu.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 93b0ef071f..c8932c97b6 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -421,6 +421,9 @@ namespace MWGui } store.setSelectedEnchantItem(it); + // to reset WindowManager::mSelectedSpell immediately + MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(*it); + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState::Spell); } } @@ -448,6 +451,9 @@ namespace MWGui store.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight); MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState::Weapon); } + + // Updates the state of equipped/not equipped (skin) in spellwindow + MWBase::Environment::get().getWindowManager()->updateSpellWindow(); } // --------------------------------------------------------------------------------------------------------- From 115fc089045513c30ee8913b46df3bde9505c2cd Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 20 Apr 2025 00:12:53 +0100 Subject: [PATCH 31/98] Don't forget parallax when reapplying shader visitor Fixes https://gitlab.com/OpenMW/openmw/-/issues/8341 I don't think this should go into 0.49 because there may be implications beyond what I've thought of and I'd rather we had a full dev cycle to notice any regressions. The fix is a little janky, but makes use of some dead code we've had since the introduction of normal-height maps nearly a decade ago, so it's a safe bet that it was never intended to be dead code. The main effect of the jankiness is that we'll add some pointless @defines for normalHeightMap that none of our shaders use and which will always be zero. --- components/shader/shadervisitor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index d97276576f..a60716f0a6 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -287,7 +287,7 @@ namespace Shader addedState->setName("addedState"); } - const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", + const char* defaultTextures[] = { "diffuseMap", "normalMap", "normalHeightMap", "emissiveMap", "darkMap", "detailMap", "envMap", "specularMap", "decalMap", "bumpMap", "glossMap" }; bool isTextureNameRecognized(std::string_view name) { @@ -440,7 +440,7 @@ namespace Shader writableStateSet = getWritableStateSet(node); writableStateSet->setTextureAttributeAndModes(unit, normalMapTex, osg::StateAttribute::ON); writableStateSet->setTextureAttributeAndModes( - unit, new SceneUtil::TextureType("normalMap"), osg::StateAttribute::ON); + unit, new SceneUtil::TextureType(normalHeight ? "normalHeightMap" : "normalMap"), osg::StateAttribute::ON); mRequirements.back().mTextures[unit] = "normalMap"; mRequirements.back().mTexStageRequiringTangents = unit; mRequirements.back().mShaderRequired = true; From 4707c7e2fc2d3f2fbe4364ae378d79c7248564a7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 20 Apr 2025 00:17:03 +0100 Subject: [PATCH 32/98] Format --- components/shader/shadervisitor.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index a60716f0a6..092ff47dca 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -287,8 +287,8 @@ namespace Shader addedState->setName("addedState"); } - const char* defaultTextures[] = { "diffuseMap", "normalMap", "normalHeightMap", "emissiveMap", "darkMap", "detailMap", "envMap", - "specularMap", "decalMap", "bumpMap", "glossMap" }; + const char* defaultTextures[] = { "diffuseMap", "normalMap", "normalHeightMap", "emissiveMap", "darkMap", + "detailMap", "envMap", "specularMap", "decalMap", "bumpMap", "glossMap" }; bool isTextureNameRecognized(std::string_view name) { return std::find(std::begin(defaultTextures), std::end(defaultTextures), name) != std::end(defaultTextures); @@ -439,8 +439,9 @@ namespace Shader if (!writableStateSet) writableStateSet = getWritableStateSet(node); writableStateSet->setTextureAttributeAndModes(unit, normalMapTex, osg::StateAttribute::ON); - writableStateSet->setTextureAttributeAndModes( - unit, new SceneUtil::TextureType(normalHeight ? "normalHeightMap" : "normalMap"), osg::StateAttribute::ON); + writableStateSet->setTextureAttributeAndModes(unit, + new SceneUtil::TextureType(normalHeight ? "normalHeightMap" : "normalMap"), + osg::StateAttribute::ON); mRequirements.back().mTextures[unit] = "normalMap"; mRequirements.back().mTexStageRequiringTangents = unit; mRequirements.back().mShaderRequired = true; From 085e5d198872e4f770716cd02bc15a5e6b863d8c Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sat, 19 Apr 2025 22:31:58 -0600 Subject: [PATCH 33/98] Calculate spell cost when building buying window --- apps/openmw/mwgui/spellbuyingwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 9fca86caba..778949d906 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -19,6 +19,7 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spells.hpp" +#include "../mwmechanics/spellutil.hpp" namespace MWGui { @@ -44,7 +45,7 @@ namespace MWGui int price = std::max(1, static_cast( - spell.mData.mCost * store.get().find("fSpellValueMult")->mValue.getFloat())); + MWMechanics::calcSpellCost(spell) * store.get().find("fSpellValueMult")->mValue.getFloat())); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true); MWWorld::Ptr player = MWMechanics::getPlayer(); From 22c01b22c1482b8a7fd10950d1f58e9d59c8b636 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sat, 19 Apr 2025 23:06:30 -0600 Subject: [PATCH 34/98] Clang format --- apps/openmw/mwgui/spellbuyingwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 778949d906..d77fff88d2 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -44,8 +44,8 @@ namespace MWGui const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); int price = std::max(1, - static_cast( - MWMechanics::calcSpellCost(spell) * store.get().find("fSpellValueMult")->mValue.getFloat())); + static_cast(MWMechanics::calcSpellCost(spell) + * store.get().find("fSpellValueMult")->mValue.getFloat())); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true); MWWorld::Ptr player = MWMechanics::getPlayer(); From e2e7b58b3a8fb4fabe148e3696ba48e25ad4856e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 20 Apr 2025 23:55:38 +0100 Subject: [PATCH 35/98] Handle normalHeightMap as special case --- components/shader/shadervisitor.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 092ff47dca..0e6b5e79c6 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -287,11 +287,17 @@ namespace Shader addedState->setName("addedState"); } - const char* defaultTextures[] = { "diffuseMap", "normalMap", "normalHeightMap", "emissiveMap", "darkMap", - "detailMap", "envMap", "specularMap", "decalMap", "bumpMap", "glossMap" }; + // This list is used both for detecting known texture types (including added normal maps etc.) and setting the + // shader defines. Normal maps and normal height maps both get sent to the shader as a normal map, so the latter + // must be detected separately. + const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", + "specularMap", "decalMap", "bumpMap", "glossMap" }; bool isTextureNameRecognized(std::string_view name) { - return std::find(std::begin(defaultTextures), std::end(defaultTextures), name) != std::end(defaultTextures); + if (std::find(std::begin(defaultTextures), std::end(defaultTextures), name) != std::end(defaultTextures)) + return true; + else + return name == "normalHeightMap"; } void ShaderVisitor::applyStateSet(osg::ref_ptr stateset, osg::Node& node) From 58fcc8f66d36abe6a4bd9031bad78d5da5e075ab Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Fri, 25 Apr 2025 21:24:27 +0300 Subject: [PATCH 36/98] Require a non-empty argument in ShowMap (#8466) --- apps/openmw/mwscript/guiextensions.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 07855f18ef..3f84362c34 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -115,6 +115,11 @@ namespace MWScript std::string_view cell = runtime.getStringLiteral(runtime[0].mInteger); runtime.pop(); + // In Morrowind, using an empty string either errors out (e.g. console) or kills the game + // so it should be reasonable to interrupt the script + if (cell.empty()) + throw std::runtime_error("ShowMap substring must not be empty"); + // "Will match complete or partial cells, so ShowMap, "Vivec" will show cells Vivec and Vivec, Fred's // House as well." http://www.uesp.net/wiki/Tes3Mod:ShowMap From 87014016a259cf56ad00b991ed7fbe6e077c41e8 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 3 May 2025 17:25:27 +0200 Subject: [PATCH 37/98] Stop postponing physics for objects that _don't_ have physics --- apps/openmw/mwworld/scene.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index fb3aee958c..478bdb5bb8 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -375,7 +375,6 @@ namespace MWWorld if (object->getShapeInstance()->mVisualCollisionType == Resource::VisualCollisionType::None) mNavigator.removeObject(DetourNavigator::ObjectId(object), navigatorUpdateGuard); mPhysics->remove(ptr); - ptr.mRef->mData.mPhysicsPostponed = false; } else if (mPhysics->getActor(ptr)) { @@ -383,6 +382,8 @@ namespace MWWorld mRendering.removeActorPath(ptr); mPhysics->remove(ptr); } + else + ptr.mRef->mData.mPhysicsPostponed = false; MWBase::Environment::get().getLuaManager()->objectRemovedFromScene(ptr); } From d1196ea66756e8975e49668abc3c6823ad116a14 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Tue, 6 May 2025 20:09:48 +0200 Subject: [PATCH 38/98] Ignore resistances for base diseases --- apps/openmw/mwmechanics/activespells.cpp | 6 +++--- apps/openmw/mwmechanics/activespells.hpp | 4 ++-- apps/openmw/mwmechanics/disease.hpp | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 9e64996e46..0f361f7ffc 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -267,7 +267,7 @@ namespace MWMechanics if (spell->mData.mType != ESM::Spell::ST_Spell && spell->mData.mType != ESM::Spell::ST_Power && !isSpellActive(spell->mId)) { - mSpells.emplace_back(ActiveSpellParams{ spell, ptr }); + mSpells.emplace_back(ActiveSpellParams{ spell, ptr, true }); mSpells.back().setActiveSpellId(MWBase::Environment::get().getESMStore()->generateId()); } } @@ -506,9 +506,9 @@ namespace MWMechanics mQueue.emplace_back(params); } - void ActiveSpells::addSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor) + void ActiveSpells::addSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, bool ignoreResistances) { - mQueue.emplace_back(ActiveSpellParams{ spell, actor, true }); + mQueue.emplace_back(ActiveSpellParams{ spell, actor, ignoreResistances }); } void ActiveSpells::purge(ParamsPredicate predicate, const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index e4fa60ddb6..3e4dafdb26 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -137,8 +137,8 @@ namespace MWMechanics /// void addSpell(const ActiveSpellParams& params); - /// Bypasses resistances - void addSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor); + /// Force resistances + void addSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, bool ignoreResistances = true); /// Removes the active effects from this spell/potion/.. with \a id void removeEffectsBySourceSpellId(const MWWorld::Ptr& ptr, const ESM::RefId& id); diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index c793d5d540..262f813916 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -66,7 +66,9 @@ namespace MWMechanics if (Misc::Rng::rollDice(10000, prng) < x) { // Contracted disease! - actor.getClass().getCreatureStats(actor).getSpells().add(spell); + MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); + creatureStats.getSpells().add(spell); + creatureStats.getActiveSpells().addSpell(spell, actor, false); MWBase::Environment::get().getWorld()->applyLoopingParticles(actor); std::string msg = MWBase::Environment::get() From b5aaf4ca30357e5a08c968dc3fd019a6313b365f Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 22 May 2025 16:03:52 -0600 Subject: [PATCH 39/98] Fix mPickpocketDetected flag being set after use --- apps/openmw/mwgui/pickpocketitemmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index fa7bce449b..437a21fb23 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -129,8 +129,8 @@ namespace MWGui { MWBase::Environment::get().getMechanicsManager()->commitCrime( player, mActor, MWBase::MechanicsManager::OT_Pickpocket, ESM::RefId(), 0, true); - MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); mPickpocketDetected = true; + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); return false; } else From 192cf1535b9743f7ff2a1f97cae9df1d10d24f4b Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 22 May 2025 16:10:05 -0600 Subject: [PATCH 40/98] Fix second instance of mPickpocketDetected set after use --- apps/openmw/mwgui/pickpocketitemmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index 437a21fb23..8756427589 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -101,8 +101,8 @@ namespace MWGui { MWBase::Environment::get().getMechanicsManager()->commitCrime( player, mActor, MWBase::MechanicsManager::OT_Pickpocket, ESM::RefId(), 0, true); - MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); mPickpocketDetected = true; + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); } } From 2ce4571c3a194c2296ab5577c1388c231dc9be70 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 17 Jun 2025 00:24:42 +0100 Subject: [PATCH 41/98] Handle paths passed on the command line properly Fixes https://gitlab.com/OpenMW/openmw/-/issues/8567. Also maybe horribly breaks lots of things because it removes some insanity from https://gitlab.com/OpenMW/openmw/-/merge_requests/86, which would set the CWD to the local directory just in case any local-relative paths were expressed relatively without the explicit base being the local path. --- apps/bulletobjecttool/main.cpp | 1 + apps/essimporter/main.cpp | 1 + apps/navmeshtool/main.cpp | 1 + apps/openmw/main.cpp | 2 ++ components/files/linuxpath.cpp | 8 -------- components/files/macospath.cpp | 5 ----- components/files/windowspath.cpp | 4 ---- 7 files changed, 5 insertions(+), 17 deletions(-) diff --git a/apps/bulletobjecttool/main.cpp b/apps/bulletobjecttool/main.cpp index 5cb275a53d..66f710df72 100644 --- a/apps/bulletobjecttool/main.cpp +++ b/apps/bulletobjecttool/main.cpp @@ -125,6 +125,7 @@ namespace } Files::ConfigurationManager config; + config.processPaths(variables, std::filesystem::current_path()); config.readConfiguration(variables, desc); Debug::setupLogging(config.getLogPath(), applicationName); diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp index f0833e9d81..50e11e2c5a 100644 --- a/apps/essimporter/main.cpp +++ b/apps/essimporter/main.cpp @@ -40,6 +40,7 @@ Allowed options)"); bpo::notify(variables); Files::ConfigurationManager cfgManager(true); + cfgManager.processPaths(variables, std::filesystem::current_path()); cfgManager.readConfiguration(variables, desc); const auto& essFile = variables["mwsave"].as(); diff --git a/apps/navmeshtool/main.cpp b/apps/navmeshtool/main.cpp index e148e60d54..65ee6df6b1 100644 --- a/apps/navmeshtool/main.cpp +++ b/apps/navmeshtool/main.cpp @@ -143,6 +143,7 @@ namespace NavMeshTool } Files::ConfigurationManager config; + config.processPaths(variables, std::filesystem::current_path()); config.readConfiguration(variables, desc); Debug::setupLogging(config.getLogPath(), applicationName); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 812a6ffd85..12b327c222 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -61,6 +61,8 @@ bool parseOptions(int argc, char** argv, OMW::Engine& engine, Files::Configurati return false; } + cfgMgr.processPaths(variables, std::filesystem::current_path()); + cfgMgr.readConfiguration(variables, desc); Debug::setupLogging(cfgMgr.getLogPath(), "OpenMW"); diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index 4dbe119917..aa8c410748 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -51,14 +51,6 @@ namespace Files 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 --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 4b37c2fb26..f98bb72a8f 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -64,11 +64,6 @@ namespace Files 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 diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index 6fb9845976..77faa23131 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -26,10 +26,6 @@ namespace Files 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 From acbc0a9b8f00289c5f3459a9e6d7eeffe057a35e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Jun 2025 00:19:14 +0100 Subject: [PATCH 42/98] Fix launching other binaries when the CWD is not the binary directory --- apps/opencs/model/doc/runner.cpp | 22 ++++++++++------------ components/process/processinvoker.cpp | 11 +++-------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index d647d6b498..a9274ee5dc 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -2,11 +2,8 @@ #include -#if defined(Q_OS_MAC) #include #include -#endif - #include #include #include @@ -55,16 +52,17 @@ void CSMDoc::Runner::start(bool delayed) QString path = "openmw"; #ifdef Q_OS_WIN - path.append(QString(".exe")); -#elif defined(Q_OS_MAC) - QDir dir(QCoreApplication::applicationDirPath()); - dir.cdUp(); - dir.cdUp(); - dir.cdUp(); - path = dir.absoluteFilePath(path.prepend("OpenMW.app/Contents/MacOS/")); -#else - path.prepend(QString("./")); + 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.prepend("OpenMW.app/Contents/MacOS/") +#endif + path = dir.absoluteFilePath(path); mStartup = new QTemporaryFile(this); mStartup->open(); diff --git a/components/process/processinvoker.cpp b/components/process/processinvoker.cpp index 9489076acb..04058c492d 100644 --- a/components/process/processinvoker.cpp +++ b/components/process/processinvoker.cpp @@ -1,13 +1,11 @@ #include "processinvoker.hpp" +#include #include #include #include #include -#if defined(Q_OS_MAC) -#include -#endif Process::ProcessInvoker::ProcessInvoker(QObject* parent) : QObject(parent) @@ -60,12 +58,9 @@ bool Process::ProcessInvoker::startProcess(const QString& name, const QStringLis 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); From 9a28216cda34950b045281af1d2fa25fe87b1dff Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Jun 2025 00:19:22 +0100 Subject: [PATCH 43/98] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa0c43be25..479a19d905 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 From 276e0e67650fd836768bacf2a6d93403c6aba281 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Jun 2025 00:22:58 +0100 Subject: [PATCH 44/98] Remove vestigial include --- components/files/linuxpath.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index aa8c410748..2e74948fff 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -7,7 +7,6 @@ #include #include -#include #include namespace From f7b8091117569e263b59c35efa7162a2f5327a08 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Jun 2025 00:23:52 +0100 Subject: [PATCH 45/98] Add missing semicolon --- apps/opencs/model/doc/runner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index a9274ee5dc..4019fbfe57 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -60,7 +60,7 @@ void CSMDoc::Runner::start(bool delayed) dir.cdUp(); dir.cdUp(); dir.cdUp(); - path.prepend("OpenMW.app/Contents/MacOS/") + path.prepend("OpenMW.app/Contents/MacOS/"); #endif path = dir.absoluteFilePath(path); From 323ee5f79d7c29961e33f1e55af4cd00ac8424f3 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Jun 2025 00:27:08 +0100 Subject: [PATCH 46/98] Remove a line break that clang-format was fussing about --- components/process/processinvoker.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/process/processinvoker.cpp b/components/process/processinvoker.cpp index 04058c492d..f1af67d20d 100644 --- a/components/process/processinvoker.cpp +++ b/components/process/processinvoker.cpp @@ -6,7 +6,6 @@ #include #include - Process::ProcessInvoker::ProcessInvoker(QObject* parent) : QObject(parent) { From 5938ba528fea407d82b53500c230d4daa923522e Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Thu, 19 Jun 2025 13:50:15 +0300 Subject: [PATCH 47/98] Export symbols for openmw binary under Clang (#8039) --- apps/openmw/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 37de0abeab..2dc2d2e24d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -138,6 +138,12 @@ if(BUILD_OPENMW) 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 From bee9716262321f6f2067718d63e41797f153d65e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Jun 2025 16:32:21 +0100 Subject: [PATCH 48/98] Fix getLocalPath for MacOS --- components/files/macospath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index f98bb72a8f..8a18ed144a 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -97,7 +97,7 @@ namespace Files std::filesystem::path MacOsPath::getLocalPath() const { - return std::filesystem::path("../Resources/"); + return getBinaryPath() / "../Resources"; } std::filesystem::path MacOsPath::getGlobalDataPath() const From 71d334fe7903a1920a75c86d38c528b87a975860 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Jun 2025 19:55:26 +0100 Subject: [PATCH 49/98] Fix MacOS even more --- components/files/macospath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 8a18ed144a..191f3b15a6 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -97,7 +97,7 @@ namespace Files std::filesystem::path MacOsPath::getLocalPath() const { - return getBinaryPath() / "../Resources"; + return getBinaryPath().parent_path().parent_path() / "Resources"; } std::filesystem::path MacOsPath::getGlobalDataPath() const From 910690c7e5885c2e86f0830c064024a532728806 Mon Sep 17 00:00:00 2001 From: Calandiel Date: Sun, 18 Aug 2024 03:17:57 +0200 Subject: [PATCH 50/98] expose a terrain height getter --- apps/openmw/mwlua/corebindings.cpp | 43 ++++++++++++++++++++++++++++++ components/esmterrain/storage.cpp | 39 ++++++++++++++++----------- components/esmterrain/storage.hpp | 12 +++++++-- 3 files changed, 77 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index 9df435c00d..eb0c8c4175 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -1,5 +1,8 @@ #include "corebindings.hpp" +#include +#include +#include #include #include @@ -25,6 +28,9 @@ #include "magicbindings.hpp" #include "soundbindings.hpp" #include "stats.hpp" +#include +#include +#include namespace MWLua { @@ -147,6 +153,43 @@ namespace MWLua { std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) }); }; } + api["getHeightAt"] = [](float x, float y, sol::object cellOrName) { + ESM::RefId worldspace; + if (cellOrName.is()) + worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); + else if (cellOrName.is() && !cellOrName.as().empty()) + worldspace = MWBase::Environment::get() + .getWorldModel() + ->getCell(cellOrName.as()) + .getCell() + ->getWorldSpace(); + else + worldspace = ESM::Cell::sDefaultWorldspaceId; + + const float cellSize = ESM::getCellSize(worldspace); + int cellX = static_cast(std::floor(x / cellSize)); + int cellY = static_cast(std::floor(y / cellSize)); + + auto store = MWBase::Environment::get().getESMStore(); + auto landStore = store->get(); + auto land = landStore.search(cellX, cellY); + const ESM::Land::LandData* landData = nullptr; + if (land != nullptr) + { + landData = land->getLandData(ESM::Land::DATA_VHGT); + if (landData != nullptr) + { + // Ensure data is loaded if necessary + land->loadData(ESM::Land::DATA_VHGT); + } + } + if (landData == nullptr) + { + // If we failed to load data, return the default height + return static_cast(ESM::Land::DEFAULT_HEIGHT); + } + return ESMTerrain::Storage::getHeightAt(landData->mHeights, landData->sLandSize, { x, y, 0 }, cellSize); + }; sol::table readOnlyApi = LuaUtil::makeReadOnly(api); return context.setTypePackage(readOnlyApi, "openmw_core"); diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 35ec814aa2..330fa0440b 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -465,21 +465,14 @@ namespace ESMTerrain blendmaps.clear(); // If a single texture fills the whole terrain, there is no need to blend } - float Storage::getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace) + float Storage::getHeightAt( + const std::span data, const int landSize, const osg::Vec3f& worldPos, const float cellSize) { - const float cellSize = ESM::getCellSize(worldspace); + // if (!data) + // return defaultHeight; int cellX = static_cast(std::floor(worldPos.x() / cellSize)); int cellY = static_cast(std::floor(worldPos.y() / cellSize)); - osg::ref_ptr land = getLand(ESM::ExteriorCellLocation(cellX, cellY, worldspace)); - if (!land) - return ESM::isEsm4Ext(worldspace) ? std::numeric_limits::lowest() : defaultHeight; - - const ESM::LandData* data = land->getData(ESM::Land::DATA_VHGT); - if (!data) - return defaultHeight; - const int landSize = data->getLandSize(); - // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition // Normalized position in the cell @@ -516,10 +509,10 @@ namespace ESMTerrain */ // Build all 4 positions in normalized cell space, using point-sampled height - osg::Vec3f v0(startXTS, startYTS, getVertexHeight(data, startX, startY) / cellSize); - osg::Vec3f v1(endXTS, startYTS, getVertexHeight(data, endX, startY) / cellSize); - osg::Vec3f v2(endXTS, endYTS, getVertexHeight(data, endX, endY) / cellSize); - osg::Vec3f v3(startXTS, endYTS, getVertexHeight(data, startX, endY) / cellSize); + osg::Vec3f v0(startXTS, startYTS, Storage::getVertexHeight(data, landSize, startX, startY) / cellSize); + osg::Vec3f v1(endXTS, startYTS, Storage::getVertexHeight(data, landSize, endX, startY) / cellSize); + osg::Vec3f v2(endXTS, endYTS, Storage::getVertexHeight(data, landSize, endX, endY) / cellSize); + osg::Vec3f v3(startXTS, endYTS, Storage::getVertexHeight(data, landSize, startX, endY) / cellSize); // define this plane in terrain space osg::Plane plane; // FIXME: deal with differing triangle alignment @@ -548,6 +541,22 @@ namespace ESMTerrain return (-plane.getNormal().x() * nX - plane.getNormal().y() * nY - plane[3]) / plane.getNormal().z() * cellSize; } + float Storage::getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace) + { + const float cellSize = ESM::getCellSize(worldspace); + int cellX = static_cast(std::floor(worldPos.x() / cellSize)); + int cellY = static_cast(std::floor(worldPos.y() / cellSize)); + + osg::ref_ptr land = getLand(ESM::ExteriorCellLocation(cellX, cellY, worldspace)); + if (!land) + return ESM::isEsm4Ext(worldspace) ? std::numeric_limits::lowest() : defaultHeight; + + const ESM::LandData* data = land->getData(ESM::Land::DATA_VHGT); + if (!data) + return defaultHeight; + return Storage::getHeightAt(data->getHeights(), data->getLandSize(), worldPos, cellSize); + } + const LandObject* Storage::getLand(ESM::ExteriorCellLocation cellLocation, LandCache& cache) { if (const auto land = cache.find(cellLocation.mX, cellLocation.mY)) diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 402f2147ab..c88a15fa30 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -114,6 +114,9 @@ namespace ESMTerrain float getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace) override; + static float getHeightAt( + const std::span data, const int landSize, const osg::Vec3f& worldPos, const float cellSize); + /// Get the transformation factor for mapping cell units to world units. float getCellWorldSize(ESM::RefId worldspace) override; @@ -122,12 +125,17 @@ namespace ESMTerrain int getBlendmapScale(float chunkSize) override; - float getVertexHeight(const ESM::LandData* data, int x, int y) + static float getVertexHeight(const ESM::LandData* data, int x, int y) { const int landSize = data->getLandSize(); + return getVertexHeight(data->getHeights(), landSize, x, y); + } + + static float getVertexHeight(const std::span data, const int landSize, int x, int y) + { assert(x < landSize); assert(y < landSize); - return data->getHeights()[y * landSize + x]; + return data[y * landSize + x]; } private: From 283be9f4f061c1cff821eeb2ed7b145f8ba22899 Mon Sep 17 00:00:00 2001 From: Calandiel Date: Sun, 18 Aug 2024 03:26:52 +0200 Subject: [PATCH 51/98] add docs for the new binding --- apps/openmw/mwlua/corebindings.cpp | 9 +++++---- files/lua_api/openmw/core.lua | 7 +++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index eb0c8c4175..9574564ada 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -153,7 +153,8 @@ namespace MWLua { std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) }); }; } - api["getHeightAt"] = [](float x, float y, sol::object cellOrName) { + + api["getHeightAt"] = [](const osg::Vec3f& pos, sol::object cellOrName) { ESM::RefId worldspace; if (cellOrName.is()) worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); @@ -167,8 +168,8 @@ namespace MWLua worldspace = ESM::Cell::sDefaultWorldspaceId; const float cellSize = ESM::getCellSize(worldspace); - int cellX = static_cast(std::floor(x / cellSize)); - int cellY = static_cast(std::floor(y / cellSize)); + int cellX = static_cast(std::floor(pos.x() / cellSize)); + int cellY = static_cast(std::floor(pos.y() / cellSize)); auto store = MWBase::Environment::get().getESMStore(); auto landStore = store->get(); @@ -188,7 +189,7 @@ namespace MWLua // If we failed to load data, return the default height return static_cast(ESM::Land::DEFAULT_HEIGHT); } - return ESMTerrain::Storage::getHeightAt(landData->mHeights, landData->sLandSize, { x, y, 0 }, cellSize); + return ESMTerrain::Storage::getHeightAt(landData->mHeights, landData->sLandSize, pos, cellSize); }; sol::table readOnlyApi = LuaUtil::makeReadOnly(api); diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 8a78a52441..5813b32b27 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -62,6 +62,13 @@ -- @param #string setting Setting name -- @return #any +--- +-- Get the terrain height at a given location. +-- @function [parent=#core] getHeightAt +-- @param openmw.util#Vector3 position +-- @param #any cellOrName (optional) cell or cell name in their exterior world space to query +-- @return #number + --- -- Return l10n formatting function for the given context. -- Localisation files (containing the message names and translations) should be stored in From 1521d5195a02da1354a3979506a5e956c39191d1 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Tue, 29 Apr 2025 01:19:02 +0200 Subject: [PATCH 52/98] add bindings for land textures --- apps/openmw/mwlua/corebindings.cpp | 89 ++++++++++++++++++++++++++++++ components/esmterrain/storage.cpp | 87 +++++++++++++++++++++++++++-- components/esmterrain/storage.hpp | 6 ++ files/lua_api/openmw/core.lua | 9 +++ 4 files changed, 186 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index 9574564ada..865e670011 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -31,6 +33,7 @@ #include #include #include +#include namespace MWLua { @@ -182,6 +185,7 @@ namespace MWLua { // Ensure data is loaded if necessary land->loadData(ESM::Land::DATA_VHGT); + landData = land->getLandData(ESM::Land::DATA_VHGT); } } if (landData == nullptr) @@ -192,6 +196,91 @@ namespace MWLua return ESMTerrain::Storage::getHeightAt(landData->mHeights, landData->sLandSize, pos, cellSize); }; + api["getLandTextureAt"] = [lua = context.mLua](const osg::Vec3f& pos, sol::object cellOrName) { + sol::variadic_results values; + ESM::RefId worldspace; + if (cellOrName.is()) + worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); + else if (cellOrName.is() && !cellOrName.as().empty()) + worldspace = MWBase::Environment::get() + .getWorldModel() + ->getCell(cellOrName.as()) + .getCell() + ->getWorldSpace(); + else + worldspace = ESM::Cell::sDefaultWorldspaceId; + + const float cellSize = ESM::getCellSize(worldspace); + + int cellX = static_cast(std::floor(pos.x() / cellSize)); + int cellY = static_cast(std::floor(pos.y() / cellSize)); + + auto store = MWBase::Environment::get().getESMStore(); + // We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time + // to get the actual data + auto landStore = store->get(); + auto land = landStore.search(cellX, cellY); + const ESM::Land::LandData* landData = nullptr; + if (land != nullptr) + { + landData = land->getLandData(ESM::Land::DATA_VTEX); + if (landData != nullptr) + { + // Ensure data is loaded if necessary + land->loadData(ESM::Land::DATA_VTEX); + landData = land->getLandData(ESM::Land::DATA_VTEX); + } + } + if (landData == nullptr) + { + // If we fail to preload land data, return, we need to be able to get *any* land to know how to correct + // the position used to sample terrain + return values; + } + + const osg::Vec3f correctedPos + = ESMTerrain::Storage::getTextureCorrectedWorldPos(pos, landData->sLandTextureSize, cellSize); + int correctedCellX = static_cast(std::floor(correctedPos.x() / cellSize)); + int correctedCellY = static_cast(std::floor(correctedPos.y() / cellSize)); + auto correctedLand = landStore.search(correctedCellX, correctedCellY); + const ESM::Land::LandData* correctedLandData = nullptr; + if (correctedLand != nullptr) + { + correctedLandData = correctedLand->getLandData(ESM::Land::DATA_VTEX); + if (correctedLandData != nullptr) + { + // Ensure data is loaded if necessary + land->loadData(ESM::Land::DATA_VTEX); + correctedLandData = correctedLand->getLandData(ESM::Land::DATA_VTEX); + } + } + if (correctedLandData == nullptr) + { + return values; + } + + // We're passing in sLandTextureSize, NOT sLandSize like with getHeightAt + const ESMTerrain::UniqueTextureId textureId + = ESMTerrain::Storage::getLandTextureAt(correctedLandData->mTextures, correctedLand->getPlugin(), + correctedLandData->sLandTextureSize, correctedPos, cellSize); + + // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId + if (textureId.first != 0) + { + values.push_back(sol::make_object(lua->sol(), textureId.first - 1)); + values.push_back(sol::make_object(lua->sol(), textureId.second)); + + auto textureStore = store->get(); + const std::string* textureString = textureStore.search(textureId.first - 1, textureId.second); + if (textureString) + { + values.push_back(sol::make_object(lua->sol(), *textureString)); + } + } + + return values; + }; + sol::table readOnlyApi = LuaUtil::makeReadOnly(api); return context.setTypePackage(readOnlyApi, "openmw_core"); } diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 330fa0440b..903ec11c29 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -22,6 +23,19 @@ namespace ESMTerrain { namespace { + UniqueTextureId getTextureIdAt( + const std::span data, const int plugin, const std::size_t x, const std::size_t y) + { + assert(x < ESM::Land::LAND_TEXTURE_SIZE); + assert(y < ESM::Land::LAND_TEXTURE_SIZE); + + const std::uint16_t tex = data[y * ESM::Land::LAND_TEXTURE_SIZE + x]; + if (tex == 0) + return { 0, 0 }; // vtex 0 is always the base texture, regardless of plugin + + return { tex, plugin }; + } + UniqueTextureId getTextureIdAt(const LandObject* land, std::size_t x, std::size_t y) { assert(x < ESM::Land::LAND_TEXTURE_SIZE); @@ -34,11 +48,7 @@ namespace ESMTerrain if (data == nullptr) return { 0, 0 }; - const std::uint16_t tex = data->getTextures()[y * ESM::Land::LAND_TEXTURE_SIZE + x]; - if (tex == 0) - return { 0, 0 }; // vtex 0 is always the base texture, regardless of plugin - - return { tex, land->getPlugin() }; + return getTextureIdAt(data->getTextures(), land->getPlugin(), x, y); } } @@ -465,6 +475,73 @@ namespace ESMTerrain blendmaps.clear(); // If a single texture fills the whole terrain, there is no need to blend } + osg::Vec3f Storage::getTextureCorrectedWorldPos( + const osg::Vec3f& uncorrectedWorldPos, const int textureSize, const float cellSize) + { + // the offset is [-0.25, +0.25] of a single texture's size + // TODO: verify whether or not this works in TES4 and beyond + float offset = (cellSize / textureSize) * 0.25; + return uncorrectedWorldPos + osg::Vec3f{ -offset, +offset, 0.0f }; + } + + // Takes in a corrected world pos to match the visuals. + UniqueTextureId Storage::getLandTextureAt(const std::span landData, const int plugin, + const int textureSize, const osg::Vec3f& correctedWorldPos, const float cellSize) + { + int cellX = static_cast(std::floor(correctedWorldPos.x() / cellSize)); + int cellY = static_cast(std::floor(correctedWorldPos.y() / cellSize)); + + // Normalized position in the cell + float nX = (correctedWorldPos.x() - (cellX * cellSize)) / cellSize; + float nY = (correctedWorldPos.y() - (cellY * cellSize)) / cellSize; + + int startX = static_cast(nX * textureSize); + int startY = static_cast(nY * textureSize); + + int endX = startX + 1; + int endY = startY + 1; + endX = std::min(endX, textureSize - 1); + endY = std::min(endY, textureSize - 1); + + float fractionX = std::clamp(nX * textureSize - startX, 0.0f, 1.0f); + float fractionY = std::clamp(nY * textureSize - startY, 0.0f, 1.0f); + + /* For even / odd tri strip rows, triangles are this shape: + even odd + 3---2 3---2 + | / | | \ | + 0---1 0---1 + */ + return getTextureIdAt(landData, plugin, startX, startY); + + if (fractionX <= 0.5f) + { + if (fractionY <= 0.5) + { + // 0 + return getTextureIdAt(landData, plugin, startX, startY); + } + else + { + // 3 + return getTextureIdAt(landData, plugin, startX, endY); + } + } + else + { + if (fractionY <= 0.5) + { + // 1 + return getTextureIdAt(landData, plugin, endX, startY); + } + else + { + // 2 + return getTextureIdAt(landData, plugin, endX, endY); + } + } + } + float Storage::getHeightAt( const std::span data, const int landSize, const osg::Vec3f& worldPos, const float cellSize) { diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index c88a15fa30..7b4e9f8694 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -117,6 +117,12 @@ namespace ESMTerrain static float getHeightAt( const std::span data, const int landSize, const osg::Vec3f& worldPos, const float cellSize); + static osg::Vec3f getTextureCorrectedWorldPos( + const osg::Vec3f& uncorrectedWorldPos, const int textureSize, const float cellSize); + + static UniqueTextureId getLandTextureAt(const std::span landData, const int plugin, + const int textureSize, const osg::Vec3f& worldPos, const float cellSize); + /// Get the transformation factor for mapping cell units to world units. float getCellWorldSize(ESM::RefId worldspace) override; diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 5813b32b27..1ffc60f6d5 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -69,6 +69,15 @@ -- @param #any cellOrName (optional) cell or cell name in their exterior world space to query -- @return #number +--- +-- Get the terrain texture at a given location. +-- @function [parent=#core] getLandTextureAt +-- @param openmw.util#Vector3 position +-- @param #any cellOrName (optional) cell or cell name in their exterior world space to query +-- @return #nil, #number Land texture index or nil if failed to retrieve the texture +-- @return #nil, #number Plugin id or nil if failed to retrieve the texture +-- @return #nil, #string Texture path or nil if one isn't defined + --- -- Return l10n formatting function for the given context. -- Localisation files (containing the message names and translations) should be stored in From fe68a098ea0238b40fabb245d3f1151c1b7ff875 Mon Sep 17 00:00:00 2001 From: Calandiel Date: Mon, 19 Aug 2024 00:40:09 +0200 Subject: [PATCH 53/98] reorder includes --- apps/openmw/mwlua/corebindings.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index 865e670011..a8db2d25fb 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -1,15 +1,17 @@ #include "corebindings.hpp" -#include -#include -#include -#include -#include #include + +#include #include +#include #include +#include #include +#include +#include +#include #include #include #include @@ -30,10 +32,9 @@ #include "magicbindings.hpp" #include "soundbindings.hpp" #include "stats.hpp" -#include -#include -#include -#include +#include +#include +#include namespace MWLua { From 22a0dce4a610a9d905d0577bbb25e8afee6e6271 Mon Sep 17 00:00:00 2001 From: Calandiel Date: Mon, 19 Aug 2024 00:40:27 +0200 Subject: [PATCH 54/98] reorder includes --- apps/openmw/mwlua/corebindings.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index a8db2d25fb..e5db05235d 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -6,6 +6,9 @@ #include #include +#include +#include +#include #include #include #include @@ -32,10 +35,6 @@ #include "magicbindings.hpp" #include "soundbindings.hpp" #include "stats.hpp" -#include -#include -#include - namespace MWLua { static sol::table initContentFilesBindings(sol::state_view& lua) From 3b962e3fd4ee1054523b69d9640228bdd8b7a968 Mon Sep 17 00:00:00 2001 From: Calandiel Date: Mon, 19 Aug 2024 00:41:01 +0200 Subject: [PATCH 55/98] reorder includes --- apps/openmw/mwlua/corebindings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index e5db05235d..24a1b08919 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -35,6 +35,7 @@ #include "magicbindings.hpp" #include "soundbindings.hpp" #include "stats.hpp" + namespace MWLua { static sol::table initContentFilesBindings(sol::state_view& lua) From 336275292e005763c6553d2628faf4ad86ce2967 Mon Sep 17 00:00:00 2001 From: Calandiel Date: Mon, 19 Aug 2024 00:42:23 +0200 Subject: [PATCH 56/98] reorder includes --- apps/openmw/mwlua/corebindings.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index 24a1b08919..aa0b321f6c 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -1,14 +1,15 @@ #include "corebindings.hpp" -#include - #include #include #include +#include + #include #include #include + #include #include #include From 8917103bf36172f2f7e4583cfed840702d4ec80b Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Tue, 29 Apr 2025 01:20:13 +0200 Subject: [PATCH 57/98] put land bindings in a table in openmw.core --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwlua/corebindings.cpp | 13 +-- apps/openmw/mwlua/landbindings.cpp | 153 +++++++++++++++++++++++++++++ apps/openmw/mwlua/landbindings.hpp | 11 +++ 4 files changed, 168 insertions(+), 11 deletions(-) create mode 100644 apps/openmw/mwlua/landbindings.cpp create mode 100644 apps/openmw/mwlua/landbindings.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 37de0abeab..48dcf41aae 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -62,7 +62,7 @@ add_openmw_dir (mwlua luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant context menuscripts globalscripts localscripts playerscripts luabindings objectbindings cellbindings mwscriptbindings camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings dialoguebindings - postprocessingbindings stats recordstore debugbindings corebindings worldbindings worker magicbindings factionbindings + postprocessingbindings stats recordstore debugbindings corebindings worldbindings worker landbindings magicbindings factionbindings classbindings itemdata inputprocessor animationbindings birthsignbindings racebindings markupbindings types/types types/door types/item types/actor types/container types/lockable types/weapon types/npc types/creature types/player types/activator types/book types/lockpick types/probe types/apparatus diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index aa0b321f6c..8bef77f4ae 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -2,20 +2,10 @@ #include #include -#include - -#include - -#include -#include -#include #include -#include #include -#include #include -#include #include #include #include @@ -32,6 +22,7 @@ #include "dialoguebindings.hpp" #include "factionbindings.hpp" +#include "landbindings.hpp" #include "luaevents.hpp" #include "magicbindings.hpp" #include "soundbindings.hpp" @@ -108,6 +99,8 @@ namespace MWLua api["stats"] = context.cachePackage("openmw_core_stats", [context]() { return initCoreStatsBindings(context); }); + api["land"] = context.cachePackage("openmw_core_land", [context]() { return initCoreLandBindings(context); }); + api["factions"] = context.cachePackage("openmw_core_factions", [context]() { return initCoreFactionBindings(context); }); api["dialogue"] diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp new file mode 100644 index 0000000000..37e95183ca --- /dev/null +++ b/apps/openmw/mwlua/landbindings.cpp @@ -0,0 +1,153 @@ +#include "landbindings.hpp" + +#include +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwworld/esmstore.hpp" + +namespace MWLua +{ + sol::table initCoreLandBindings(const Context& context) + { + sol::state_view& lua = context.mLua->sol(); + sol::table landApi(lua, sol::create); + + // Constants + landApi["RANGE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ + { "Self", ESM::RT_Self }, + { "Touch", ESM::RT_Touch }, + { "Target", ESM::RT_Target }, + })); + + landApi["getHeightAt"] = [](const osg::Vec3f& pos, sol::object cellOrName) { + ESM::RefId worldspace; + if (cellOrName.is()) + worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); + else if (cellOrName.is() && !cellOrName.as().empty()) + worldspace = MWBase::Environment::get() + .getWorldModel() + ->getCell(cellOrName.as()) + .getCell() + ->getWorldSpace(); + else + worldspace = ESM::Cell::sDefaultWorldspaceId; + + const float cellSize = ESM::getCellSize(worldspace); + int cellX = static_cast(std::floor(pos.x() / cellSize)); + int cellY = static_cast(std::floor(pos.y() / cellSize)); + + auto store = MWBase::Environment::get().getESMStore(); + auto landStore = store->get(); + auto land = landStore.search(cellX, cellY); + const ESM::Land::LandData* landData = nullptr; + if (land != nullptr) + { + landData = land->getLandData(ESM::Land::DATA_VHGT); + if (landData != nullptr) + { + // Ensure data is loaded if necessary + land->loadData(ESM::Land::DATA_VHGT); + landData = land->getLandData(ESM::Land::DATA_VHGT); + } + } + if (landData == nullptr) + { + // If we failed to load data, return the default height + return static_cast(ESM::Land::DEFAULT_HEIGHT); + } + return ESMTerrain::Storage::getHeightAt(landData->mHeights, landData->sLandSize, pos, cellSize); + }; + + landApi["getLandTextureAt"] = [lua = context.mLua](const osg::Vec3f& pos, sol::object cellOrName) { + sol::variadic_results values; + ESM::RefId worldspace; + if (cellOrName.is()) + worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); + else if (cellOrName.is() && !cellOrName.as().empty()) + worldspace = MWBase::Environment::get() + .getWorldModel() + ->getCell(cellOrName.as()) + .getCell() + ->getWorldSpace(); + else + worldspace = ESM::Cell::sDefaultWorldspaceId; + + const float cellSize = ESM::getCellSize(worldspace); + + int cellX = static_cast(std::floor(pos.x() / cellSize)); + int cellY = static_cast(std::floor(pos.y() / cellSize)); + + auto store = MWBase::Environment::get().getESMStore(); + // We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time + // to get the actual data + auto landStore = store->get(); + auto land = landStore.search(cellX, cellY); + const ESM::Land::LandData* landData = nullptr; + if (land != nullptr) + { + landData = land->getLandData(ESM::Land::DATA_VTEX); + if (landData != nullptr) + { + // Ensure data is loaded if necessary + land->loadData(ESM::Land::DATA_VTEX); + landData = land->getLandData(ESM::Land::DATA_VTEX); + } + } + if (landData == nullptr) + { + // If we fail to preload land data, return, we need to be able to get *any* land to know how to correct + // the position used to sample terrain + return values; + } + + const osg::Vec3f correctedPos + = ESMTerrain::Storage::getTextureCorrectedWorldPos(pos, landData->sLandTextureSize, cellSize); + int correctedCellX = static_cast(std::floor(correctedPos.x() / cellSize)); + int correctedCellY = static_cast(std::floor(correctedPos.y() / cellSize)); + auto correctedLand = landStore.search(correctedCellX, correctedCellY); + const ESM::Land::LandData* correctedLandData = nullptr; + if (correctedLand != nullptr) + { + correctedLandData = correctedLand->getLandData(ESM::Land::DATA_VTEX); + if (correctedLandData != nullptr) + { + // Ensure data is loaded if necessary + land->loadData(ESM::Land::DATA_VTEX); + correctedLandData = correctedLand->getLandData(ESM::Land::DATA_VTEX); + } + } + if (correctedLandData == nullptr) + { + return values; + } + + // We're passing in sLandTextureSize, NOT sLandSize like with getHeightAt + const ESMTerrain::UniqueTextureId textureId + = ESMTerrain::Storage::getLandTextureAt(correctedLandData->mTextures, correctedLand->getPlugin(), + correctedLandData->sLandTextureSize, correctedPos, cellSize); + + // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId + if (textureId.first != 0) + { + values.push_back(sol::make_object(lua->sol(), textureId.first - 1)); + values.push_back(sol::make_object(lua->sol(), textureId.second)); + + auto textureStore = store->get(); + const std::string* textureString = textureStore.search(textureId.first - 1, textureId.second); + if (textureString) + { + values.push_back(sol::make_object(lua->sol(), *textureString)); + } + } + + return values; + }; + + return LuaUtil::makeReadOnly(landApi); + } +} diff --git a/apps/openmw/mwlua/landbindings.hpp b/apps/openmw/mwlua/landbindings.hpp new file mode 100644 index 0000000000..8cdf30046b --- /dev/null +++ b/apps/openmw/mwlua/landbindings.hpp @@ -0,0 +1,11 @@ +#ifndef MWLUA_LANDBINDINGS_H +#define MWLUA_LANDBINDINGS_H + +#include "context.hpp" + +namespace MWLua +{ + sol::table initCoreLandBindings(const Context& context); +} + +#endif // MWLUA_LANDBINDINGS_H From 378093791bcc5e4974ebe7cd24a3ede791099cb2 Mon Sep 17 00:00:00 2001 From: Calandiel Date: Tue, 20 Aug 2024 00:01:02 +0200 Subject: [PATCH 58/98] update the docs for land functions --- files/lua_api/openmw/core.lua | 36 +++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 1ffc60f6d5..30db9b6791 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -62,22 +62,6 @@ -- @param #string setting Setting name -- @return #any ---- --- Get the terrain height at a given location. --- @function [parent=#core] getHeightAt --- @param openmw.util#Vector3 position --- @param #any cellOrName (optional) cell or cell name in their exterior world space to query --- @return #number - ---- --- Get the terrain texture at a given location. --- @function [parent=#core] getLandTextureAt --- @param openmw.util#Vector3 position --- @param #any cellOrName (optional) cell or cell name in their exterior world space to query --- @return #nil, #number Land texture index or nil if failed to retrieve the texture --- @return #nil, #number Plugin id or nil if failed to retrieve the texture --- @return #nil, #string Texture path or nil if one isn't defined - --- -- Return l10n formatting function for the given context. -- Localisation files (containing the message names and translations) should be stored in @@ -466,10 +450,30 @@ -- @usage for _, item in ipairs(inventory:findAll('common_shirt_01')) do ... end +--- @{#Land}: Functions for interacting with land data +-- @field [parent=#core] #Land land + + --- @{#Magic}: spells and spell effects -- @field [parent=#core] #Magic magic +--- +-- Get the terrain height at a given location. +-- @function [parent=#Land] getHeightAt +-- @param openmw.util#Vector3 position +-- @param #any cellOrName (optional) cell or cell name in their exterior world space to query +-- @return #number + +--- +-- Get the terrain texture at a given location. +-- @function [parent=#Land] getLandTextureAt +-- @param openmw.util#Vector3 position +-- @param #any cellOrName (optional) cell or cell name in their exterior world space to query +-- @return #nil, #number Land texture index or nil if failed to retrieve the texture +-- @return #nil, #number Plugin id or nil if failed to retrieve the texture +-- @return #nil, #string Texture path or nil if one isn't defined + --- Possible @{#SpellRange} values -- @field [parent=#Magic] #SpellRange RANGE From c711179b8f8e5f045d6a0018e07ceb6879e3f055 Mon Sep 17 00:00:00 2001 From: Calandiel Date: Tue, 20 Aug 2024 22:52:55 +0200 Subject: [PATCH 59/98] apply changes requested in the code review --- apps/openmw/mwlua/landbindings.cpp | 18 +++++++++--------- components/esmterrain/storage.cpp | 5 +++-- components/esmterrain/storage.hpp | 2 +- files/lua_api/openmw/core.lua | 4 ++-- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 37e95183ca..3f5c0f2e40 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -17,13 +17,6 @@ namespace MWLua sol::state_view& lua = context.mLua->sol(); sol::table landApi(lua, sol::create); - // Constants - landApi["RANGE"] = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs({ - { "Self", ESM::RT_Self }, - { "Touch", ESM::RT_Touch }, - { "Target", ESM::RT_Target }, - })); - landApi["getHeightAt"] = [](const osg::Vec3f& pos, sol::object cellOrName) { ESM::RefId worldspace; if (cellOrName.is()) @@ -63,7 +56,7 @@ namespace MWLua return ESMTerrain::Storage::getHeightAt(landData->mHeights, landData->sLandSize, pos, cellSize); }; - landApi["getLandTextureAt"] = [lua = context.mLua](const osg::Vec3f& pos, sol::object cellOrName) { + landApi["getTextureAt"] = [lua = context.mLua](const osg::Vec3f& pos, sol::object cellOrName) { sol::variadic_results values; ESM::RefId worldspace; if (cellOrName.is()) @@ -85,6 +78,11 @@ namespace MWLua auto store = MWBase::Environment::get().getESMStore(); // We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time // to get the actual data + // This is because the visual land textures are offset with regards to quads that are rendered for terrain. + // To properly calculate that offset, we need to know how many texture samples exist per cell edge, + // as it differs between tes3 and tes4. It's equal - + // Once we know the value, we will calculate the offset and retrieve a sample again, this time + // with the offset taken into account. auto landStore = store->get(); auto land = landStore.search(cellX, cellY); const ESM::Land::LandData* landData = nullptr; @@ -105,6 +103,8 @@ namespace MWLua return values; } + // Use landData to get amount of sampler per cell edge (sLandTextureSize) + // and then get the corrected position that will map to the rendered texture const osg::Vec3f correctedPos = ESMTerrain::Storage::getTextureCorrectedWorldPos(pos, landData->sLandTextureSize, cellSize); int correctedCellX = static_cast(std::floor(correctedPos.x() / cellSize)); @@ -128,7 +128,7 @@ namespace MWLua // We're passing in sLandTextureSize, NOT sLandSize like with getHeightAt const ESMTerrain::UniqueTextureId textureId - = ESMTerrain::Storage::getLandTextureAt(correctedLandData->mTextures, correctedLand->getPlugin(), + = ESMTerrain::Storage::getTextureAt(correctedLandData->mTextures, correctedLand->getPlugin(), correctedLandData->sLandTextureSize, correctedPos, cellSize); // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 903ec11c29..aa9ef3e362 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -2,11 +2,11 @@ #include #include -#include #include #include #include +#include #include #include @@ -475,6 +475,7 @@ namespace ESMTerrain blendmaps.clear(); // If a single texture fills the whole terrain, there is no need to blend } + // Returns a position that can be used to look up a land texture, while taking their offset into account osg::Vec3f Storage::getTextureCorrectedWorldPos( const osg::Vec3f& uncorrectedWorldPos, const int textureSize, const float cellSize) { @@ -485,7 +486,7 @@ namespace ESMTerrain } // Takes in a corrected world pos to match the visuals. - UniqueTextureId Storage::getLandTextureAt(const std::span landData, const int plugin, + UniqueTextureId Storage::getTextureAt(const std::span landData, const int plugin, const int textureSize, const osg::Vec3f& correctedWorldPos, const float cellSize) { int cellX = static_cast(std::floor(correctedWorldPos.x() / cellSize)); diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 7b4e9f8694..6ca33b18bf 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -120,7 +120,7 @@ namespace ESMTerrain static osg::Vec3f getTextureCorrectedWorldPos( const osg::Vec3f& uncorrectedWorldPos, const int textureSize, const float cellSize); - static UniqueTextureId getLandTextureAt(const std::span landData, const int plugin, + static UniqueTextureId getTextureAt(const std::span landData, const int plugin, const int textureSize, const osg::Vec3f& worldPos, const float cellSize); /// Get the transformation factor for mapping cell units to world units. diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 30db9b6791..0636682669 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -467,10 +467,10 @@ --- -- Get the terrain texture at a given location. --- @function [parent=#Land] getLandTextureAt +-- @function [parent=#Land] getTextureAt -- @param openmw.util#Vector3 position -- @param #any cellOrName (optional) cell or cell name in their exterior world space to query --- @return #nil, #number Land texture index or nil if failed to retrieve the texture +-- @return #nil, #number Land texture index or nil if failed to retrieve the texture. Landscape textures created through editors such as openmw-cs can be assigned an id to differentiate them, that is also used for terrain rendering. The value returned here corresponds to that value. See also LTEX records (https://en.uesp.net/wiki/Morrowind_Mod:Mod_File_Format/LTEX) -- @return #nil, #number Plugin id or nil if failed to retrieve the texture -- @return #nil, #string Texture path or nil if one isn't defined From 901c6b94a607f03521264684f368e6a830a162cd Mon Sep 17 00:00:00 2001 From: Calandiel Date: Thu, 22 Aug 2024 22:38:38 +0200 Subject: [PATCH 60/98] remove unnecessary land loading --- apps/openmw/mwlua/landbindings.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 3f5c0f2e40..3b07e119be 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -41,12 +41,6 @@ namespace MWLua if (land != nullptr) { landData = land->getLandData(ESM::Land::DATA_VHGT); - if (landData != nullptr) - { - // Ensure data is loaded if necessary - land->loadData(ESM::Land::DATA_VHGT); - landData = land->getLandData(ESM::Land::DATA_VHGT); - } } if (landData == nullptr) { @@ -89,12 +83,6 @@ namespace MWLua if (land != nullptr) { landData = land->getLandData(ESM::Land::DATA_VTEX); - if (landData != nullptr) - { - // Ensure data is loaded if necessary - land->loadData(ESM::Land::DATA_VTEX); - landData = land->getLandData(ESM::Land::DATA_VTEX); - } } if (landData == nullptr) { @@ -114,12 +102,6 @@ namespace MWLua if (correctedLand != nullptr) { correctedLandData = correctedLand->getLandData(ESM::Land::DATA_VTEX); - if (correctedLandData != nullptr) - { - // Ensure data is loaded if necessary - land->loadData(ESM::Land::DATA_VTEX); - correctedLandData = correctedLand->getLandData(ESM::Land::DATA_VTEX); - } } if (correctedLandData == nullptr) { From dcf0c6e314306ede78f7cee43376af75801f7967 Mon Sep 17 00:00:00 2001 From: Calandiel Date: Sat, 31 Aug 2024 13:14:44 +0200 Subject: [PATCH 61/98] simplify texture retrieval for land bindings --- components/esmterrain/storage.cpp | 41 ------------------------------- 1 file changed, 41 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index aa9ef3e362..360e2b6822 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -499,48 +499,7 @@ namespace ESMTerrain int startX = static_cast(nX * textureSize); int startY = static_cast(nY * textureSize); - int endX = startX + 1; - int endY = startY + 1; - endX = std::min(endX, textureSize - 1); - endY = std::min(endY, textureSize - 1); - - float fractionX = std::clamp(nX * textureSize - startX, 0.0f, 1.0f); - float fractionY = std::clamp(nY * textureSize - startY, 0.0f, 1.0f); - - /* For even / odd tri strip rows, triangles are this shape: - even odd - 3---2 3---2 - | / | | \ | - 0---1 0---1 - */ return getTextureIdAt(landData, plugin, startX, startY); - - if (fractionX <= 0.5f) - { - if (fractionY <= 0.5) - { - // 0 - return getTextureIdAt(landData, plugin, startX, startY); - } - else - { - // 3 - return getTextureIdAt(landData, plugin, startX, endY); - } - } - else - { - if (fractionY <= 0.5) - { - // 1 - return getTextureIdAt(landData, plugin, endX, startY); - } - else - { - // 2 - return getTextureIdAt(landData, plugin, endX, endY); - } - } } float Storage::getHeightAt( From 4182279f7254966084459df4a4c64a2d6896c537 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 22 Dec 2024 22:47:31 +0100 Subject: [PATCH 62/98] deduplication for landbindings.cpp + slight api changes - remove textureId from return - return plugin name instead of plugin id --- apps/openmw/mwlua/landbindings.cpp | 135 +++++++++++++---------------- files/lua_api/openmw/core.lua | 3 +- 2 files changed, 60 insertions(+), 78 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 3b07e119be..cfa8fd58d3 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -4,72 +4,67 @@ #include #include +#include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" +static const ESM::RefId worldspaceAt(const osg::Vec3f& pos, sol::object cellOrName) +{ + ESM::RefId worldspace; + if (cellOrName.is()) + worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); + else if (cellOrName.is() && !cellOrName.as().empty()) + worldspace = MWBase::Environment::get() + .getWorldModel() + ->getCell(cellOrName.as()) + .getCell() + ->getWorldSpace(); + else + worldspace = ESM::Cell::sDefaultWorldspaceId; + + return worldspace; +} + +static bool fillLandData(const MWWorld::Store* landStore, const osg::Vec3f& pos, const float cellSize, + const ESM::Land** land, const ESM::Land::LandData** landData) +{ + int cellX = static_cast(std::floor(pos.x() / cellSize)); + int cellY = static_cast(std::floor(pos.y() / cellSize)); + + *land = landStore->search(cellX, cellY); + + if (*land != nullptr) + *landData = (*land)->getLandData(ESM::Land::DATA_VTEX); + + // If we fail to preload land data, return, we need to be able to get *any* land to know how to correct + // the position used to sample terrain + if (*landData == nullptr) + return false; + + return true; +} + namespace MWLua { sol::table initCoreLandBindings(const Context& context) { - sol::state_view& lua = context.mLua->sol(); + auto lua = context.sol(); sol::table landApi(lua, sol::create); landApi["getHeightAt"] = [](const osg::Vec3f& pos, sol::object cellOrName) { - ESM::RefId worldspace; - if (cellOrName.is()) - worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); - else if (cellOrName.is() && !cellOrName.as().empty()) - worldspace = MWBase::Environment::get() - .getWorldModel() - ->getCell(cellOrName.as()) - .getCell() - ->getWorldSpace(); - else - worldspace = ESM::Cell::sDefaultWorldspaceId; - - const float cellSize = ESM::getCellSize(worldspace); - int cellX = static_cast(std::floor(pos.x() / cellSize)); - int cellY = static_cast(std::floor(pos.y() / cellSize)); - - auto store = MWBase::Environment::get().getESMStore(); - auto landStore = store->get(); - auto land = landStore.search(cellX, cellY); - const ESM::Land::LandData* landData = nullptr; - if (land != nullptr) - { - landData = land->getLandData(ESM::Land::DATA_VHGT); - } - if (landData == nullptr) - { - // If we failed to load data, return the default height - return static_cast(ESM::Land::DEFAULT_HEIGHT); - } - return ESMTerrain::Storage::getHeightAt(landData->mHeights, landData->sLandSize, pos, cellSize); + auto worldspace = worldspaceAt(pos, cellOrName); + return MWBase::Environment::get().getWorld()->getTerrainHeightAt(pos, worldspace); }; - landApi["getTextureAt"] = [lua = context.mLua](const osg::Vec3f& pos, sol::object cellOrName) { + landApi["getTextureAt"] = [lua = lua](const osg::Vec3f& pos, sol::object cellOrName) { sol::variadic_results values; - ESM::RefId worldspace; - if (cellOrName.is()) - worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); - else if (cellOrName.is() && !cellOrName.as().empty()) - worldspace = MWBase::Environment::get() - .getWorldModel() - ->getCell(cellOrName.as()) - .getCell() - ->getWorldSpace(); - else - worldspace = ESM::Cell::sDefaultWorldspaceId; - - const float cellSize = ESM::getCellSize(worldspace); - - int cellX = static_cast(std::floor(pos.x() / cellSize)); - int cellY = static_cast(std::floor(pos.y() / cellSize)); - auto store = MWBase::Environment::get().getESMStore(); + auto landStore = store->get(); + + const float cellSize = ESM::getCellSize(worldspaceAt(pos, cellOrName)); // We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time // to get the actual data // This is because the visual land textures are offset with regards to quads that are rendered for terrain. @@ -77,36 +72,22 @@ namespace MWLua // as it differs between tes3 and tes4. It's equal - // Once we know the value, we will calculate the offset and retrieve a sample again, this time // with the offset taken into account. - auto landStore = store->get(); - auto land = landStore.search(cellX, cellY); + const ESM::Land* land = nullptr; const ESM::Land::LandData* landData = nullptr; - if (land != nullptr) - { - landData = land->getLandData(ESM::Land::DATA_VTEX); - } - if (landData == nullptr) - { - // If we fail to preload land data, return, we need to be able to get *any* land to know how to correct - // the position used to sample terrain + + if (!fillLandData(&landStore, pos, cellSize, &land, &landData)) return values; - } // Use landData to get amount of sampler per cell edge (sLandTextureSize) // and then get the corrected position that will map to the rendered texture const osg::Vec3f correctedPos = ESMTerrain::Storage::getTextureCorrectedWorldPos(pos, landData->sLandTextureSize, cellSize); - int correctedCellX = static_cast(std::floor(correctedPos.x() / cellSize)); - int correctedCellY = static_cast(std::floor(correctedPos.y() / cellSize)); - auto correctedLand = landStore.search(correctedCellX, correctedCellY); + + const ESM::Land* correctedLand = nullptr; const ESM::Land::LandData* correctedLandData = nullptr; - if (correctedLand != nullptr) - { - correctedLandData = correctedLand->getLandData(ESM::Land::DATA_VTEX); - } - if (correctedLandData == nullptr) - { + + if (!fillLandData(&landStore, correctedPos, cellSize, &correctedLand, &correctedLandData)) return values; - } // We're passing in sLandTextureSize, NOT sLandSize like with getHeightAt const ESMTerrain::UniqueTextureId textureId @@ -116,15 +97,17 @@ namespace MWLua // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId if (textureId.first != 0) { - values.push_back(sol::make_object(lua->sol(), textureId.first - 1)); - values.push_back(sol::make_object(lua->sol(), textureId.second)); - + auto store = MWBase::Environment::get().getESMStore(); auto textureStore = store->get(); const std::string* textureString = textureStore.search(textureId.first - 1, textureId.second); if (textureString) - { - values.push_back(sol::make_object(lua->sol(), *textureString)); - } + values.push_back(sol::make_object(lua, *textureString)); + else + return values; + + const std::vector& contentList = MWBase::Environment::get().getWorld()->getContentFiles(); + if (textureId.second > 0 && textureId.second < contentList.size()) + values.push_back(sol::make_object(lua, contentList[textureId.second])); } return values; diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 0636682669..8ad7a973da 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -470,9 +470,8 @@ -- @function [parent=#Land] getTextureAt -- @param openmw.util#Vector3 position -- @param #any cellOrName (optional) cell or cell name in their exterior world space to query --- @return #nil, #number Land texture index or nil if failed to retrieve the texture. Landscape textures created through editors such as openmw-cs can be assigned an id to differentiate them, that is also used for terrain rendering. The value returned here corresponds to that value. See also LTEX records (https://en.uesp.net/wiki/Morrowind_Mod:Mod_File_Format/LTEX) --- @return #nil, #number Plugin id or nil if failed to retrieve the texture -- @return #nil, #string Texture path or nil if one isn't defined +-- @return #nil, #string Plugin name or nil if failed to retrieve the texture --- Possible @{#SpellRange} values -- @field [parent=#Magic] #SpellRange RANGE From ea02c6918612f97268a2355eef2bb4ce929a14d3 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Mon, 6 Jan 2025 21:47:09 +0100 Subject: [PATCH 63/98] fix index check + cast to size_t --- apps/openmw/mwlua/landbindings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index cfa8fd58d3..5176c7909c 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -106,7 +106,7 @@ namespace MWLua return values; const std::vector& contentList = MWBase::Environment::get().getWorld()->getContentFiles(); - if (textureId.second > 0 && textureId.second < contentList.size()) + if (textureId.second >= 0 && static_cast(textureId.second) < contentList.size()) values.push_back(sol::make_object(lua, contentList[textureId.second])); } From 940e73a35672277a93732d14c804d9e442aa71b8 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Wed, 8 Jan 2025 21:05:08 +0100 Subject: [PATCH 64/98] landbindings - static to anonymous namespace + use references --- apps/openmw/mwlua/landbindings.cpp | 62 +++++++++++++++--------------- components/esmterrain/storage.cpp | 2 - 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 5176c7909c..aef7ab47c6 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -11,40 +11,43 @@ #include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" -static const ESM::RefId worldspaceAt(const osg::Vec3f& pos, sol::object cellOrName) +namespace { - ESM::RefId worldspace; - if (cellOrName.is()) - worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); - else if (cellOrName.is() && !cellOrName.as().empty()) - worldspace = MWBase::Environment::get() - .getWorldModel() - ->getCell(cellOrName.as()) - .getCell() - ->getWorldSpace(); - else - worldspace = ESM::Cell::sDefaultWorldspaceId; + const ESM::RefId worldspaceAt(const osg::Vec3f& pos, sol::object cellOrName) + { + ESM::RefId worldspace; + if (cellOrName.is()) + worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); + else if (cellOrName.is() && !cellOrName.as().empty()) + worldspace = MWBase::Environment::get() + .getWorldModel() + ->getCell(cellOrName.as()) + .getCell() + ->getWorldSpace(); + else + worldspace = ESM::Cell::sDefaultWorldspaceId; - return worldspace; -} + return worldspace; + } -static bool fillLandData(const MWWorld::Store* landStore, const osg::Vec3f& pos, const float cellSize, - const ESM::Land** land, const ESM::Land::LandData** landData) -{ - int cellX = static_cast(std::floor(pos.x() / cellSize)); - int cellY = static_cast(std::floor(pos.y() / cellSize)); + bool fillLandData(const MWWorld::Store& landStore, const osg::Vec3f& pos, const float cellSize, + const ESM::Land::LandData*& landData) + { + int cellX = static_cast(std::floor(pos.x() / cellSize)); + int cellY = static_cast(std::floor(pos.y() / cellSize)); - *land = landStore->search(cellX, cellY); + const ESM::Land* land = landStore.search(cellX, cellY); - if (*land != nullptr) - *landData = (*land)->getLandData(ESM::Land::DATA_VTEX); + if (land != nullptr) + landData = land->getLandData(ESM::Land::DATA_VTEX); - // If we fail to preload land data, return, we need to be able to get *any* land to know how to correct - // the position used to sample terrain - if (*landData == nullptr) - return false; + // If we fail to preload land data, return, we need to be able to get *any* land to know how to correct + // the position used to sample terrain + if (landData == nullptr) + return false; - return true; + return true; + } } namespace MWLua @@ -72,10 +75,9 @@ namespace MWLua // as it differs between tes3 and tes4. It's equal - // Once we know the value, we will calculate the offset and retrieve a sample again, this time // with the offset taken into account. - const ESM::Land* land = nullptr; const ESM::Land::LandData* landData = nullptr; - if (!fillLandData(&landStore, pos, cellSize, &land, &landData)) + if (!fillLandData(landStore, pos, cellSize, landData)) return values; // Use landData to get amount of sampler per cell edge (sLandTextureSize) @@ -86,7 +88,7 @@ namespace MWLua const ESM::Land* correctedLand = nullptr; const ESM::Land::LandData* correctedLandData = nullptr; - if (!fillLandData(&landStore, correctedPos, cellSize, &correctedLand, &correctedLandData)) + if (!fillLandData(landStore, correctedPos, cellSize, correctedLandData)) return values; // We're passing in sLandTextureSize, NOT sLandSize like with getHeightAt diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 360e2b6822..c4adda54a1 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -505,8 +505,6 @@ namespace ESMTerrain float Storage::getHeightAt( const std::span data, const int landSize, const osg::Vec3f& worldPos, const float cellSize) { - // if (!data) - // return defaultHeight; int cellX = static_cast(std::floor(worldPos.x() / cellSize)); int cellY = static_cast(std::floor(worldPos.y() / cellSize)); From 3d07b63ad87ab03c1f80637ceea95e2a10cc663c Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Wed, 8 Jan 2025 21:10:34 +0100 Subject: [PATCH 65/98] don't copy store --- apps/openmw/mwlua/landbindings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index aef7ab47c6..1e49db5c5e 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -65,7 +65,7 @@ namespace MWLua landApi["getTextureAt"] = [lua = lua](const osg::Vec3f& pos, sol::object cellOrName) { sol::variadic_results values; auto store = MWBase::Environment::get().getESMStore(); - auto landStore = store->get(); + const auto &landStore = store->get(); const float cellSize = ESM::getCellSize(worldspaceAt(pos, cellOrName)); // We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time @@ -100,7 +100,7 @@ namespace MWLua if (textureId.first != 0) { auto store = MWBase::Environment::get().getESMStore(); - auto textureStore = store->get(); + const auto& textureStore = store->get(); const std::string* textureString = textureStore.search(textureId.first - 1, textureId.second); if (textureString) values.push_back(sol::make_object(lua, *textureString)); From fc772744d2086065ad3e12efd5622e125de1ccde Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Wed, 8 Jan 2025 21:51:01 +0100 Subject: [PATCH 66/98] don't touch ESMTerrain::Storage --- apps/openmw/mwlua/landbindings.cpp | 40 ++++++++++++-- components/esmterrain/storage.cpp | 84 +++++++----------------------- components/esmterrain/storage.hpp | 18 +------ 3 files changed, 58 insertions(+), 84 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 1e49db5c5e..de039cf750 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -13,6 +13,39 @@ namespace { + osg::Vec3f getTextureCorrectedWorldPos( + const osg::Vec3f& uncorrectedWorldPos, const int textureSize, const float cellSize) + { + // the offset is [-0.25, +0.25] of a single texture's size + // TODO: verify whether or not this works in TES4 and beyond + float offset = (cellSize / textureSize) * 0.25; + return uncorrectedWorldPos + osg::Vec3f{ -offset, +offset, 0.0f }; + } + + // Takes in a corrected world pos to match the visuals. + ESMTerrain::UniqueTextureId getTextureAt(const std::span landData, const int plugin, + const int textureSize, const osg::Vec3f& correctedWorldPos, const float cellSize) + { + int cellX = static_cast(std::floor(correctedWorldPos.x() / cellSize)); + int cellY = static_cast(std::floor(correctedWorldPos.y() / cellSize)); + + // Normalized position in the cell + float nX = (correctedWorldPos.x() - (cellX * cellSize)) / cellSize; + float nY = (correctedWorldPos.y() - (cellY * cellSize)) / cellSize; + + int startX = static_cast(nX * textureSize); + int startY = static_cast(nY * textureSize); + + assert(startX < ESM::Land::LAND_TEXTURE_SIZE); + assert(startY < ESM::Land::LAND_TEXTURE_SIZE); + + const std::uint16_t tex = landData[startY * ESM::Land::LAND_TEXTURE_SIZE + startX]; + if (tex == 0) + return { 0, 0 }; // vtex 0 is always the base texture, regardless of plugin + + return { tex, plugin }; + } + const ESM::RefId worldspaceAt(const osg::Vec3f& pos, sol::object cellOrName) { ESM::RefId worldspace; @@ -65,7 +98,7 @@ namespace MWLua landApi["getTextureAt"] = [lua = lua](const osg::Vec3f& pos, sol::object cellOrName) { sol::variadic_results values; auto store = MWBase::Environment::get().getESMStore(); - const auto &landStore = store->get(); + const auto& landStore = store->get(); const float cellSize = ESM::getCellSize(worldspaceAt(pos, cellOrName)); // We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time @@ -82,8 +115,7 @@ namespace MWLua // Use landData to get amount of sampler per cell edge (sLandTextureSize) // and then get the corrected position that will map to the rendered texture - const osg::Vec3f correctedPos - = ESMTerrain::Storage::getTextureCorrectedWorldPos(pos, landData->sLandTextureSize, cellSize); + const osg::Vec3f correctedPos = getTextureCorrectedWorldPos(pos, landData->sLandTextureSize, cellSize); const ESM::Land* correctedLand = nullptr; const ESM::Land::LandData* correctedLandData = nullptr; @@ -93,7 +125,7 @@ namespace MWLua // We're passing in sLandTextureSize, NOT sLandSize like with getHeightAt const ESMTerrain::UniqueTextureId textureId - = ESMTerrain::Storage::getTextureAt(correctedLandData->mTextures, correctedLand->getPlugin(), + = getTextureAt(correctedLandData->mTextures, correctedLand->getPlugin(), correctedLandData->sLandTextureSize, correctedPos, cellSize); // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index c4adda54a1..35ec814aa2 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -23,19 +22,6 @@ namespace ESMTerrain { namespace { - UniqueTextureId getTextureIdAt( - const std::span data, const int plugin, const std::size_t x, const std::size_t y) - { - assert(x < ESM::Land::LAND_TEXTURE_SIZE); - assert(y < ESM::Land::LAND_TEXTURE_SIZE); - - const std::uint16_t tex = data[y * ESM::Land::LAND_TEXTURE_SIZE + x]; - if (tex == 0) - return { 0, 0 }; // vtex 0 is always the base texture, regardless of plugin - - return { tex, plugin }; - } - UniqueTextureId getTextureIdAt(const LandObject* land, std::size_t x, std::size_t y) { assert(x < ESM::Land::LAND_TEXTURE_SIZE); @@ -48,7 +34,11 @@ namespace ESMTerrain if (data == nullptr) return { 0, 0 }; - return getTextureIdAt(data->getTextures(), land->getPlugin(), x, y); + const std::uint16_t tex = data->getTextures()[y * ESM::Land::LAND_TEXTURE_SIZE + x]; + if (tex == 0) + return { 0, 0 }; // vtex 0 is always the base texture, regardless of plugin + + return { tex, land->getPlugin() }; } } @@ -475,39 +465,21 @@ namespace ESMTerrain blendmaps.clear(); // If a single texture fills the whole terrain, there is no need to blend } - // Returns a position that can be used to look up a land texture, while taking their offset into account - osg::Vec3f Storage::getTextureCorrectedWorldPos( - const osg::Vec3f& uncorrectedWorldPos, const int textureSize, const float cellSize) - { - // the offset is [-0.25, +0.25] of a single texture's size - // TODO: verify whether or not this works in TES4 and beyond - float offset = (cellSize / textureSize) * 0.25; - return uncorrectedWorldPos + osg::Vec3f{ -offset, +offset, 0.0f }; - } - - // Takes in a corrected world pos to match the visuals. - UniqueTextureId Storage::getTextureAt(const std::span landData, const int plugin, - const int textureSize, const osg::Vec3f& correctedWorldPos, const float cellSize) - { - int cellX = static_cast(std::floor(correctedWorldPos.x() / cellSize)); - int cellY = static_cast(std::floor(correctedWorldPos.y() / cellSize)); - - // Normalized position in the cell - float nX = (correctedWorldPos.x() - (cellX * cellSize)) / cellSize; - float nY = (correctedWorldPos.y() - (cellY * cellSize)) / cellSize; - - int startX = static_cast(nX * textureSize); - int startY = static_cast(nY * textureSize); - - return getTextureIdAt(landData, plugin, startX, startY); - } - - float Storage::getHeightAt( - const std::span data, const int landSize, const osg::Vec3f& worldPos, const float cellSize) + float Storage::getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace) { + const float cellSize = ESM::getCellSize(worldspace); int cellX = static_cast(std::floor(worldPos.x() / cellSize)); int cellY = static_cast(std::floor(worldPos.y() / cellSize)); + osg::ref_ptr land = getLand(ESM::ExteriorCellLocation(cellX, cellY, worldspace)); + if (!land) + return ESM::isEsm4Ext(worldspace) ? std::numeric_limits::lowest() : defaultHeight; + + const ESM::LandData* data = land->getData(ESM::Land::DATA_VHGT); + if (!data) + return defaultHeight; + const int landSize = data->getLandSize(); + // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition // Normalized position in the cell @@ -544,10 +516,10 @@ namespace ESMTerrain */ // Build all 4 positions in normalized cell space, using point-sampled height - osg::Vec3f v0(startXTS, startYTS, Storage::getVertexHeight(data, landSize, startX, startY) / cellSize); - osg::Vec3f v1(endXTS, startYTS, Storage::getVertexHeight(data, landSize, endX, startY) / cellSize); - osg::Vec3f v2(endXTS, endYTS, Storage::getVertexHeight(data, landSize, endX, endY) / cellSize); - osg::Vec3f v3(startXTS, endYTS, Storage::getVertexHeight(data, landSize, startX, endY) / cellSize); + osg::Vec3f v0(startXTS, startYTS, getVertexHeight(data, startX, startY) / cellSize); + osg::Vec3f v1(endXTS, startYTS, getVertexHeight(data, endX, startY) / cellSize); + osg::Vec3f v2(endXTS, endYTS, getVertexHeight(data, endX, endY) / cellSize); + osg::Vec3f v3(startXTS, endYTS, getVertexHeight(data, startX, endY) / cellSize); // define this plane in terrain space osg::Plane plane; // FIXME: deal with differing triangle alignment @@ -576,22 +548,6 @@ namespace ESMTerrain return (-plane.getNormal().x() * nX - plane.getNormal().y() * nY - plane[3]) / plane.getNormal().z() * cellSize; } - float Storage::getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace) - { - const float cellSize = ESM::getCellSize(worldspace); - int cellX = static_cast(std::floor(worldPos.x() / cellSize)); - int cellY = static_cast(std::floor(worldPos.y() / cellSize)); - - osg::ref_ptr land = getLand(ESM::ExteriorCellLocation(cellX, cellY, worldspace)); - if (!land) - return ESM::isEsm4Ext(worldspace) ? std::numeric_limits::lowest() : defaultHeight; - - const ESM::LandData* data = land->getData(ESM::Land::DATA_VHGT); - if (!data) - return defaultHeight; - return Storage::getHeightAt(data->getHeights(), data->getLandSize(), worldPos, cellSize); - } - const LandObject* Storage::getLand(ESM::ExteriorCellLocation cellLocation, LandCache& cache) { if (const auto land = cache.find(cellLocation.mX, cellLocation.mY)) diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 6ca33b18bf..402f2147ab 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -114,15 +114,6 @@ namespace ESMTerrain float getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace) override; - static float getHeightAt( - const std::span data, const int landSize, const osg::Vec3f& worldPos, const float cellSize); - - static osg::Vec3f getTextureCorrectedWorldPos( - const osg::Vec3f& uncorrectedWorldPos, const int textureSize, const float cellSize); - - static UniqueTextureId getTextureAt(const std::span landData, const int plugin, - const int textureSize, const osg::Vec3f& worldPos, const float cellSize); - /// Get the transformation factor for mapping cell units to world units. float getCellWorldSize(ESM::RefId worldspace) override; @@ -131,17 +122,12 @@ namespace ESMTerrain int getBlendmapScale(float chunkSize) override; - static float getVertexHeight(const ESM::LandData* data, int x, int y) + float getVertexHeight(const ESM::LandData* data, int x, int y) { const int landSize = data->getLandSize(); - return getVertexHeight(data->getHeights(), landSize, x, y); - } - - static float getVertexHeight(const std::span data, const int landSize, int x, int y) - { assert(x < landSize); assert(y < landSize); - return data[y * landSize + x]; + return data->getHeights()[y * landSize + x]; } private: From 8954f458676e5103f37da67f4fc640ef652c9545 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Wed, 8 Jan 2025 22:03:32 +0100 Subject: [PATCH 67/98] fixes for landbindings.cpp --- apps/openmw/mwlua/landbindings.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index de039cf750..e865c8997d 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -64,12 +64,12 @@ namespace } bool fillLandData(const MWWorld::Store& landStore, const osg::Vec3f& pos, const float cellSize, - const ESM::Land::LandData*& landData) + const ESM::Land*& land, const ESM::Land::LandData*& landData) { int cellX = static_cast(std::floor(pos.x() / cellSize)); int cellY = static_cast(std::floor(pos.y() / cellSize)); - const ESM::Land* land = landStore.search(cellX, cellY); + land = landStore.search(cellX, cellY); if (land != nullptr) landData = land->getLandData(ESM::Land::DATA_VTEX); @@ -108,9 +108,10 @@ namespace MWLua // as it differs between tes3 and tes4. It's equal - // Once we know the value, we will calculate the offset and retrieve a sample again, this time // with the offset taken into account. + const ESM::Land* land = nullptr; const ESM::Land::LandData* landData = nullptr; - if (!fillLandData(landStore, pos, cellSize, landData)) + if (!fillLandData(landStore, pos, cellSize, land, landData)) return values; // Use landData to get amount of sampler per cell edge (sLandTextureSize) @@ -120,13 +121,12 @@ namespace MWLua const ESM::Land* correctedLand = nullptr; const ESM::Land::LandData* correctedLandData = nullptr; - if (!fillLandData(landStore, correctedPos, cellSize, correctedLandData)) + if (!fillLandData(landStore, correctedPos, cellSize, correctedLand, correctedLandData)) return values; // We're passing in sLandTextureSize, NOT sLandSize like with getHeightAt - const ESMTerrain::UniqueTextureId textureId - = getTextureAt(correctedLandData->mTextures, correctedLand->getPlugin(), - correctedLandData->sLandTextureSize, correctedPos, cellSize); + const ESMTerrain::UniqueTextureId textureId = getTextureAt(correctedLandData->mTextures, + correctedLand->getPlugin(), correctedLandData->sLandTextureSize, correctedPos, cellSize); // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId if (textureId.first != 0) From f3128f9c7be389cfa7bde609c38da9d8d9008fce Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 12 Jan 2025 15:00:28 +0100 Subject: [PATCH 68/98] remove unused include --- apps/openmw/mwlua/corebindings.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index 8bef77f4ae..ff1496fd40 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include #include From 47453b307a81d675b905c435b881b08246688dc3 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 12 Jan 2025 15:07:44 +0100 Subject: [PATCH 69/98] no auto in landbindings.cpp --- apps/openmw/mwlua/landbindings.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index e865c8997d..4384f0aa66 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -87,18 +87,18 @@ namespace MWLua { sol::table initCoreLandBindings(const Context& context) { - auto lua = context.sol(); + sol::state_view lua = context.sol(); sol::table landApi(lua, sol::create); landApi["getHeightAt"] = [](const osg::Vec3f& pos, sol::object cellOrName) { - auto worldspace = worldspaceAt(pos, cellOrName); + ESM::RefId worldspace = worldspaceAt(pos, cellOrName); return MWBase::Environment::get().getWorld()->getTerrainHeightAt(pos, worldspace); }; landApi["getTextureAt"] = [lua = lua](const osg::Vec3f& pos, sol::object cellOrName) { sol::variadic_results values; - auto store = MWBase::Environment::get().getESMStore(); - const auto& landStore = store->get(); + Misc::NotNullPtr store = MWBase::Environment::get().getESMStore(); + const MWWorld::Store& landStore = store->get(); const float cellSize = ESM::getCellSize(worldspaceAt(pos, cellOrName)); // We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time @@ -131,14 +131,13 @@ namespace MWLua // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId if (textureId.first != 0) { - auto store = MWBase::Environment::get().getESMStore(); - const auto& textureStore = store->get(); + Misc::NotNullPtr store = MWBase::Environment::get().getESMStore(); + const MWWorld::Store& textureStore = store->get(); const std::string* textureString = textureStore.search(textureId.first - 1, textureId.second); - if (textureString) - values.push_back(sol::make_object(lua, *textureString)); - else + if (!textureString) return values; + values.push_back(sol::make_object(lua, *textureString)); const std::vector& contentList = MWBase::Environment::get().getWorld()->getContentFiles(); if (textureId.second >= 0 && static_cast(textureId.second) < contentList.size()) values.push_back(sol::make_object(lua, contentList[textureId.second])); From 6671c12ad2609ba4036298805b7f7365fd3a9674 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 12 Jan 2025 15:09:22 +0100 Subject: [PATCH 70/98] reorder of documentation for landbindings in core.lua --- files/lua_api/openmw/core.lua | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 8ad7a973da..3c00f49354 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -453,11 +453,6 @@ --- @{#Land}: Functions for interacting with land data -- @field [parent=#core] #Land land - ---- @{#Magic}: spells and spell effects --- @field [parent=#core] #Magic magic - - --- -- Get the terrain height at a given location. -- @function [parent=#Land] getHeightAt @@ -473,6 +468,10 @@ -- @return #nil, #string Texture path or nil if one isn't defined -- @return #nil, #string Plugin name or nil if failed to retrieve the texture + +--- @{#Magic}: spells and spell effects +-- @field [parent=#core] #Magic magic + --- Possible @{#SpellRange} values -- @field [parent=#Magic] #SpellRange RANGE From 5d0986e8123fce4bca4ab8c09768e5753b8dd0c9 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 12 Jan 2025 15:22:07 +0100 Subject: [PATCH 71/98] Misc::NotNullPtr to MWWorld::ESMStore& store --- apps/openmw/mwlua/landbindings.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 4384f0aa66..cd3a68fbb4 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -97,8 +97,8 @@ namespace MWLua landApi["getTextureAt"] = [lua = lua](const osg::Vec3f& pos, sol::object cellOrName) { sol::variadic_results values; - Misc::NotNullPtr store = MWBase::Environment::get().getESMStore(); - const MWWorld::Store& landStore = store->get(); + MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); + const MWWorld::Store& landStore = store.get(); const float cellSize = ESM::getCellSize(worldspaceAt(pos, cellOrName)); // We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time @@ -131,8 +131,8 @@ namespace MWLua // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId if (textureId.first != 0) { - Misc::NotNullPtr store = MWBase::Environment::get().getESMStore(); - const MWWorld::Store& textureStore = store->get(); + MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); + const MWWorld::Store& textureStore = store.get(); const std::string* textureString = textureStore.search(textureId.first - 1, textureId.second); if (!textureString) return values; From 7c76387ffe062b6ae41ef0f5ff3a17d63e2d1756 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 12 Jan 2025 17:26:20 +0100 Subject: [PATCH 72/98] no interior cell + make cellOrName mandatory --- apps/openmw/mwlua/landbindings.cpp | 24 +++++++++++------------- files/lua_api/openmw/core.lua | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index cd3a68fbb4..72af17776a 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -46,21 +46,19 @@ namespace return { tex, plugin }; } - const ESM::RefId worldspaceAt(const osg::Vec3f& pos, sol::object cellOrName) + const ESM::RefId worldspaceAt(sol::object cellOrName) { - ESM::RefId worldspace; + const MWWorld::Cell* cell = nullptr; if (cellOrName.is()) - worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); + cell = cellOrName.as().mStore->getCell(); else if (cellOrName.is() && !cellOrName.as().empty()) - worldspace = MWBase::Environment::get() - .getWorldModel() - ->getCell(cellOrName.as()) - .getCell() - ->getWorldSpace(); - else - worldspace = ESM::Cell::sDefaultWorldspaceId; + cell = MWBase::Environment::get().getWorldModel()->getCell(cellOrName.as()).getCell(); + if (cell = nullptr) + throw std::runtime_error("Invalid cell"); + else if (!cell->isExterior()) + throw std::runtime_error("Cell cannot be interior"); - return worldspace; + return cell->getWorldSpace(); } bool fillLandData(const MWWorld::Store& landStore, const osg::Vec3f& pos, const float cellSize, @@ -91,7 +89,7 @@ namespace MWLua sol::table landApi(lua, sol::create); landApi["getHeightAt"] = [](const osg::Vec3f& pos, sol::object cellOrName) { - ESM::RefId worldspace = worldspaceAt(pos, cellOrName); + ESM::RefId worldspace = worldspaceAt(cellOrName); return MWBase::Environment::get().getWorld()->getTerrainHeightAt(pos, worldspace); }; @@ -100,7 +98,7 @@ namespace MWLua MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); const MWWorld::Store& landStore = store.get(); - const float cellSize = ESM::getCellSize(worldspaceAt(pos, cellOrName)); + const float cellSize = ESM::getCellSize(worldspaceAt(cellOrName)); // We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time // to get the actual data // This is because the visual land textures are offset with regards to quads that are rendered for terrain. diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 3c00f49354..b2bd58d23c 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -464,7 +464,7 @@ -- Get the terrain texture at a given location. -- @function [parent=#Land] getTextureAt -- @param openmw.util#Vector3 position --- @param #any cellOrName (optional) cell or cell name in their exterior world space to query +-- @param #any cellOrName cell or cell name in their exterior world space to query -- @return #nil, #string Texture path or nil if one isn't defined -- @return #nil, #string Plugin name or nil if failed to retrieve the texture From 8de0ccc82c95fd0823527f3c22dece821c38cd5c Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 12 Jan 2025 17:36:31 +0100 Subject: [PATCH 73/98] remove redundant code --- apps/openmw/mwlua/landbindings.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 72af17776a..996d749c3b 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -129,7 +129,6 @@ namespace MWLua // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId if (textureId.first != 0) { - MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); const MWWorld::Store& textureStore = store.get(); const std::string* textureString = textureStore.search(textureId.first - 1, textureId.second); if (!textureString) From 4ede868ed2c5380fb5ec7991162a509ca4ed4d8a Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 12 Jan 2025 17:42:03 +0100 Subject: [PATCH 74/98] fix typo --- apps/openmw/mwlua/landbindings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 996d749c3b..2f99efcc85 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -53,7 +53,7 @@ namespace cell = cellOrName.as().mStore->getCell(); else if (cellOrName.is() && !cellOrName.as().empty()) cell = MWBase::Environment::get().getWorldModel()->getCell(cellOrName.as()).getCell(); - if (cell = nullptr) + if (cell == nullptr) throw std::runtime_error("Invalid cell"); else if (!cell->isExterior()) throw std::runtime_error("Cell cannot be interior"); From 76e2c77517a75bd0fe1fcb7ae46ef245853ece8c Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 12 Jan 2025 17:50:36 +0100 Subject: [PATCH 75/98] check for lcell also --- apps/openmw/mwlua/landbindings.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 2f99efcc85..bd5e72eacd 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -51,6 +51,8 @@ namespace const MWWorld::Cell* cell = nullptr; if (cellOrName.is()) cell = cellOrName.as().mStore->getCell(); + else if (cellOrName.is()) + cell = cellOrName.as().mStore->getCell(); else if (cellOrName.is() && !cellOrName.as().empty()) cell = MWBase::Environment::get().getWorldModel()->getCell(cellOrName.as()).getCell(); if (cell == nullptr) From effb3de2a703cbe4443cb18082dff02a6ad28467 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 12 Jan 2025 19:47:04 +0100 Subject: [PATCH 76/98] const --- apps/openmw/mwlua/landbindings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index bd5e72eacd..9da50a667b 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -97,7 +97,7 @@ namespace MWLua landApi["getTextureAt"] = [lua = lua](const osg::Vec3f& pos, sol::object cellOrName) { sol::variadic_results values; - MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); + const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); const MWWorld::Store& landStore = store.get(); const float cellSize = ESM::getCellSize(worldspaceAt(cellOrName)); From 3e0685e4a6f4fad19db6b56926a6c07c26c86c03 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sat, 18 Jan 2025 21:48:31 +0100 Subject: [PATCH 77/98] don't double sample + only allow default worldspace --- apps/openmw/mwlua/landbindings.cpp | 39 +++++++----------------------- 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 9da50a667b..509eff3a15 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "../mwbase/environment.hpp" @@ -13,15 +14,6 @@ namespace { - osg::Vec3f getTextureCorrectedWorldPos( - const osg::Vec3f& uncorrectedWorldPos, const int textureSize, const float cellSize) - { - // the offset is [-0.25, +0.25] of a single texture's size - // TODO: verify whether or not this works in TES4 and beyond - float offset = (cellSize / textureSize) * 0.25; - return uncorrectedWorldPos + osg::Vec3f{ -offset, +offset, 0.0f }; - } - // Takes in a corrected world pos to match the visuals. ESMTerrain::UniqueTextureId getTextureAt(const std::span landData, const int plugin, const int textureSize, const osg::Vec3f& correctedWorldPos, const float cellSize) @@ -59,6 +51,8 @@ namespace throw std::runtime_error("Invalid cell"); else if (!cell->isExterior()) throw std::runtime_error("Cell cannot be interior"); + else if (cell->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId) + throw std::runtime_error("Only default exterior worldspace is supported"); return cell->getWorldSpace(); } @@ -101,32 +95,17 @@ namespace MWLua const MWWorld::Store& landStore = store.get(); const float cellSize = ESM::getCellSize(worldspaceAt(cellOrName)); - // We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time - // to get the actual data - // This is because the visual land textures are offset with regards to quads that are rendered for terrain. - // To properly calculate that offset, we need to know how many texture samples exist per cell edge, - // as it differs between tes3 and tes4. It's equal - - // Once we know the value, we will calculate the offset and retrieve a sample again, this time - // with the offset taken into account. + const float offset = (cellSize / ESM::LandRecordData::sLandTextureSize) * 0.25; + const osg::Vec3f correctedPos = pos + osg::Vec3f{ -offset, +offset, 0.0f }; + const ESM::Land* land = nullptr; const ESM::Land::LandData* landData = nullptr; - if (!fillLandData(landStore, pos, cellSize, land, landData)) + if (!fillLandData(landStore, correctedPos, cellSize, land, landData)) return values; - // Use landData to get amount of sampler per cell edge (sLandTextureSize) - // and then get the corrected position that will map to the rendered texture - const osg::Vec3f correctedPos = getTextureCorrectedWorldPos(pos, landData->sLandTextureSize, cellSize); - - const ESM::Land* correctedLand = nullptr; - const ESM::Land::LandData* correctedLandData = nullptr; - - if (!fillLandData(landStore, correctedPos, cellSize, correctedLand, correctedLandData)) - return values; - - // We're passing in sLandTextureSize, NOT sLandSize like with getHeightAt - const ESMTerrain::UniqueTextureId textureId = getTextureAt(correctedLandData->mTextures, - correctedLand->getPlugin(), correctedLandData->sLandTextureSize, correctedPos, cellSize); + const ESMTerrain::UniqueTextureId textureId = getTextureAt( + landData->mTextures, land->getPlugin(), ESM::LandRecordData::sLandTextureSize, correctedPos, cellSize); // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId if (textureId.first != 0) From 03e4735b1985bc0402d4aa943c94ce2a70c3e066 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sat, 18 Jan 2025 21:56:25 +0100 Subject: [PATCH 78/98] add #8112 to changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa0c43be25..725d26ce4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +0.50.0 +------ + + Feature #8112: Expose landscape record data to Lua + 0.49.0 ------ From 732fb4affe22f35d92ff55b3fb551c205d007dc6 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sat, 18 Jan 2025 23:09:51 +0100 Subject: [PATCH 79/98] inline fillLandData and return empty table instead of throwing --- apps/openmw/mwlua/landbindings.cpp | 48 +++++++++++++----------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 509eff3a15..05cc4f3773 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include "../mwbase/environment.hpp" @@ -16,7 +15,7 @@ namespace { // Takes in a corrected world pos to match the visuals. ESMTerrain::UniqueTextureId getTextureAt(const std::span landData, const int plugin, - const int textureSize, const osg::Vec3f& correctedWorldPos, const float cellSize) + const osg::Vec3f& correctedWorldPos, const float cellSize) { int cellX = static_cast(std::floor(correctedWorldPos.x() / cellSize)); int cellY = static_cast(std::floor(correctedWorldPos.y() / cellSize)); @@ -25,8 +24,8 @@ namespace float nX = (correctedWorldPos.x() - (cellX * cellSize)) / cellSize; float nY = (correctedWorldPos.y() - (cellY * cellSize)) / cellSize; - int startX = static_cast(nX * textureSize); - int startY = static_cast(nY * textureSize); + int startX = static_cast(nX * ESM::Land::LAND_TEXTURE_SIZE); + int startY = static_cast(nY * ESM::Land::LAND_TEXTURE_SIZE); assert(startX < ESM::Land::LAND_TEXTURE_SIZE); assert(startY < ESM::Land::LAND_TEXTURE_SIZE); @@ -51,30 +50,9 @@ namespace throw std::runtime_error("Invalid cell"); else if (!cell->isExterior()) throw std::runtime_error("Cell cannot be interior"); - else if (cell->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId) - throw std::runtime_error("Only default exterior worldspace is supported"); return cell->getWorldSpace(); } - - bool fillLandData(const MWWorld::Store& landStore, const osg::Vec3f& pos, const float cellSize, - const ESM::Land*& land, const ESM::Land::LandData*& landData) - { - int cellX = static_cast(std::floor(pos.x() / cellSize)); - int cellY = static_cast(std::floor(pos.y() / cellSize)); - - land = landStore.search(cellX, cellY); - - if (land != nullptr) - landData = land->getLandData(ESM::Land::DATA_VTEX); - - // If we fail to preload land data, return, we need to be able to get *any* land to know how to correct - // the position used to sample terrain - if (landData == nullptr) - return false; - - return true; - } } namespace MWLua @@ -93,19 +71,33 @@ namespace MWLua sol::variadic_results values; const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); const MWWorld::Store& landStore = store.get(); + ESM::RefId worldspace = worldspaceAt(cellOrName); - const float cellSize = ESM::getCellSize(worldspaceAt(cellOrName)); + if (worldspace != ESM::Cell::sDefaultWorldspaceId) + return values; + + const float cellSize = ESM::getCellSize(worldspace); const float offset = (cellSize / ESM::LandRecordData::sLandTextureSize) * 0.25; const osg::Vec3f correctedPos = pos + osg::Vec3f{ -offset, +offset, 0.0f }; const ESM::Land* land = nullptr; const ESM::Land::LandData* landData = nullptr; - if (!fillLandData(landStore, correctedPos, cellSize, land, landData)) + int cellX = static_cast(std::floor(correctedPos.x() / cellSize)); + int cellY = static_cast(std::floor(correctedPos.y() / cellSize)); + + land = landStore.search(cellX, cellY); + + if (land != nullptr) + landData = land->getLandData(ESM::Land::DATA_VTEX); + + // If we fail to preload land data, return, we need to be able to get *any* land to know how to correct + // the position used to sample terrain + if (landData == nullptr) return values; const ESMTerrain::UniqueTextureId textureId = getTextureAt( - landData->mTextures, land->getPlugin(), ESM::LandRecordData::sLandTextureSize, correctedPos, cellSize); + landData->mTextures, land->getPlugin(), correctedPos, cellSize); // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId if (textureId.first != 0) From 3207f3a387267da1971a49771764f17689ef3703 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 19 Jan 2025 00:06:10 +0100 Subject: [PATCH 80/98] clang-format --- apps/openmw/mwlua/landbindings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp index 05cc4f3773..a4ebc0a841 100644 --- a/apps/openmw/mwlua/landbindings.cpp +++ b/apps/openmw/mwlua/landbindings.cpp @@ -96,8 +96,8 @@ namespace MWLua if (landData == nullptr) return values; - const ESMTerrain::UniqueTextureId textureId = getTextureAt( - landData->mTextures, land->getPlugin(), correctedPos, cellSize); + const ESMTerrain::UniqueTextureId textureId + = getTextureAt(landData->mTextures, land->getPlugin(), correctedPos, cellSize); // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId if (textureId.first != 0) From 0e68e36aa71f65a352db804b82c3f535e037a567 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Sun, 19 Jan 2025 00:10:37 +0100 Subject: [PATCH 81/98] that shouldn't have been touched --- files/lua_api/openmw/core.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index b2bd58d23c..74738a7c4d 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -472,6 +472,7 @@ --- @{#Magic}: spells and spell effects -- @field [parent=#core] #Magic magic + --- Possible @{#SpellRange} values -- @field [parent=#Magic] #SpellRange RANGE From 1ac407f32b2abdc4998a0bc0bb40eb79a648baf7 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Tue, 29 Apr 2025 01:42:38 +0200 Subject: [PATCH 82/98] fix rebase error --- apps/openmw/mwlua/corebindings.cpp | 124 ----------------------------- 1 file changed, 124 deletions(-) diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index ff1496fd40..2c3b0475ba 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -151,130 +151,6 @@ namespace MWLua }; } - api["getHeightAt"] = [](const osg::Vec3f& pos, sol::object cellOrName) { - ESM::RefId worldspace; - if (cellOrName.is()) - worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); - else if (cellOrName.is() && !cellOrName.as().empty()) - worldspace = MWBase::Environment::get() - .getWorldModel() - ->getCell(cellOrName.as()) - .getCell() - ->getWorldSpace(); - else - worldspace = ESM::Cell::sDefaultWorldspaceId; - - const float cellSize = ESM::getCellSize(worldspace); - int cellX = static_cast(std::floor(pos.x() / cellSize)); - int cellY = static_cast(std::floor(pos.y() / cellSize)); - - auto store = MWBase::Environment::get().getESMStore(); - auto landStore = store->get(); - auto land = landStore.search(cellX, cellY); - const ESM::Land::LandData* landData = nullptr; - if (land != nullptr) - { - landData = land->getLandData(ESM::Land::DATA_VHGT); - if (landData != nullptr) - { - // Ensure data is loaded if necessary - land->loadData(ESM::Land::DATA_VHGT); - landData = land->getLandData(ESM::Land::DATA_VHGT); - } - } - if (landData == nullptr) - { - // If we failed to load data, return the default height - return static_cast(ESM::Land::DEFAULT_HEIGHT); - } - return ESMTerrain::Storage::getHeightAt(landData->mHeights, landData->sLandSize, pos, cellSize); - }; - - api["getLandTextureAt"] = [lua = context.mLua](const osg::Vec3f& pos, sol::object cellOrName) { - sol::variadic_results values; - ESM::RefId worldspace; - if (cellOrName.is()) - worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); - else if (cellOrName.is() && !cellOrName.as().empty()) - worldspace = MWBase::Environment::get() - .getWorldModel() - ->getCell(cellOrName.as()) - .getCell() - ->getWorldSpace(); - else - worldspace = ESM::Cell::sDefaultWorldspaceId; - - const float cellSize = ESM::getCellSize(worldspace); - - int cellX = static_cast(std::floor(pos.x() / cellSize)); - int cellY = static_cast(std::floor(pos.y() / cellSize)); - - auto store = MWBase::Environment::get().getESMStore(); - // We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time - // to get the actual data - auto landStore = store->get(); - auto land = landStore.search(cellX, cellY); - const ESM::Land::LandData* landData = nullptr; - if (land != nullptr) - { - landData = land->getLandData(ESM::Land::DATA_VTEX); - if (landData != nullptr) - { - // Ensure data is loaded if necessary - land->loadData(ESM::Land::DATA_VTEX); - landData = land->getLandData(ESM::Land::DATA_VTEX); - } - } - if (landData == nullptr) - { - // If we fail to preload land data, return, we need to be able to get *any* land to know how to correct - // the position used to sample terrain - return values; - } - - const osg::Vec3f correctedPos - = ESMTerrain::Storage::getTextureCorrectedWorldPos(pos, landData->sLandTextureSize, cellSize); - int correctedCellX = static_cast(std::floor(correctedPos.x() / cellSize)); - int correctedCellY = static_cast(std::floor(correctedPos.y() / cellSize)); - auto correctedLand = landStore.search(correctedCellX, correctedCellY); - const ESM::Land::LandData* correctedLandData = nullptr; - if (correctedLand != nullptr) - { - correctedLandData = correctedLand->getLandData(ESM::Land::DATA_VTEX); - if (correctedLandData != nullptr) - { - // Ensure data is loaded if necessary - land->loadData(ESM::Land::DATA_VTEX); - correctedLandData = correctedLand->getLandData(ESM::Land::DATA_VTEX); - } - } - if (correctedLandData == nullptr) - { - return values; - } - - // We're passing in sLandTextureSize, NOT sLandSize like with getHeightAt - const ESMTerrain::UniqueTextureId textureId - = ESMTerrain::Storage::getLandTextureAt(correctedLandData->mTextures, correctedLand->getPlugin(), - correctedLandData->sLandTextureSize, correctedPos, cellSize); - - // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId - if (textureId.first != 0) - { - values.push_back(sol::make_object(lua->sol(), textureId.first - 1)); - values.push_back(sol::make_object(lua->sol(), textureId.second)); - - auto textureStore = store->get(); - const std::string* textureString = textureStore.search(textureId.first - 1, textureId.second); - if (textureString) - { - values.push_back(sol::make_object(lua->sol(), *textureString)); - } - } - - return values; - }; - sol::table readOnlyApi = LuaUtil::makeReadOnly(api); return context.setTypePackage(readOnlyApi, "openmw_core"); } From b1326e45549ba9c9e2d22295bb8eb88db4ea4db5 Mon Sep 17 00:00:00 2001 From: Sebastian Fieber Date: Fri, 20 Jun 2025 22:00:02 +0200 Subject: [PATCH 83/98] update doc for getTextureAt --- files/lua_api/openmw/core.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 74738a7c4d..7a212a10ea 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -461,7 +461,10 @@ -- @return #number --- --- Get the terrain texture at a given location. +-- Get the terrain texture at a given location. As textures are blended and +-- multiple textures can be at one specific position the texture whose center is +-- closest to the position will be returned. +-- -- @function [parent=#Land] getTextureAt -- @param openmw.util#Vector3 position -- @param #any cellOrName cell or cell name in their exterior world space to query From 3ff7dedfd1b6c312310af01abb33ab9ae0aa53c0 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 21 Jun 2025 19:03:11 +0300 Subject: [PATCH 84/98] Revert "Merge branch 'landscape-data-bindings' into 'master'" This reverts merge request !4500 --- CHANGELOG.md | 5 -- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwlua/corebindings.cpp | 3 - apps/openmw/mwlua/landbindings.cpp | 121 ----------------------------- apps/openmw/mwlua/landbindings.hpp | 11 --- files/lua_api/openmw/core.lua | 22 ------ 6 files changed, 1 insertion(+), 163 deletions(-) delete mode 100644 apps/openmw/mwlua/landbindings.cpp delete mode 100644 apps/openmw/mwlua/landbindings.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 6310b9dbb8..479a19d905 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,3 @@ -0.50.0 ------- - - Feature #8112: Expose landscape record data to Lua - 0.49.0 ------ diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 48dcf41aae..37de0abeab 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -62,7 +62,7 @@ add_openmw_dir (mwlua luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant context menuscripts globalscripts localscripts playerscripts luabindings objectbindings cellbindings mwscriptbindings camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings dialoguebindings - postprocessingbindings stats recordstore debugbindings corebindings worldbindings worker landbindings magicbindings factionbindings + postprocessingbindings stats recordstore debugbindings corebindings worldbindings worker magicbindings factionbindings classbindings itemdata inputprocessor animationbindings birthsignbindings racebindings markupbindings types/types types/door types/item types/actor types/container types/lockable types/weapon types/npc types/creature types/player types/activator types/book types/lockpick types/probe types/apparatus diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index 2c3b0475ba..9df435c00d 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -21,7 +21,6 @@ #include "dialoguebindings.hpp" #include "factionbindings.hpp" -#include "landbindings.hpp" #include "luaevents.hpp" #include "magicbindings.hpp" #include "soundbindings.hpp" @@ -98,8 +97,6 @@ namespace MWLua api["stats"] = context.cachePackage("openmw_core_stats", [context]() { return initCoreStatsBindings(context); }); - api["land"] = context.cachePackage("openmw_core_land", [context]() { return initCoreLandBindings(context); }); - api["factions"] = context.cachePackage("openmw_core_factions", [context]() { return initCoreFactionBindings(context); }); api["dialogue"] diff --git a/apps/openmw/mwlua/landbindings.cpp b/apps/openmw/mwlua/landbindings.cpp deleted file mode 100644 index a4ebc0a841..0000000000 --- a/apps/openmw/mwlua/landbindings.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "landbindings.hpp" - -#include -#include -#include - -#include -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" -#include "../mwworld/esmstore.hpp" - -namespace -{ - // Takes in a corrected world pos to match the visuals. - ESMTerrain::UniqueTextureId getTextureAt(const std::span landData, const int plugin, - const osg::Vec3f& correctedWorldPos, const float cellSize) - { - int cellX = static_cast(std::floor(correctedWorldPos.x() / cellSize)); - int cellY = static_cast(std::floor(correctedWorldPos.y() / cellSize)); - - // Normalized position in the cell - float nX = (correctedWorldPos.x() - (cellX * cellSize)) / cellSize; - float nY = (correctedWorldPos.y() - (cellY * cellSize)) / cellSize; - - int startX = static_cast(nX * ESM::Land::LAND_TEXTURE_SIZE); - int startY = static_cast(nY * ESM::Land::LAND_TEXTURE_SIZE); - - assert(startX < ESM::Land::LAND_TEXTURE_SIZE); - assert(startY < ESM::Land::LAND_TEXTURE_SIZE); - - const std::uint16_t tex = landData[startY * ESM::Land::LAND_TEXTURE_SIZE + startX]; - if (tex == 0) - return { 0, 0 }; // vtex 0 is always the base texture, regardless of plugin - - return { tex, plugin }; - } - - const ESM::RefId worldspaceAt(sol::object cellOrName) - { - const MWWorld::Cell* cell = nullptr; - if (cellOrName.is()) - cell = cellOrName.as().mStore->getCell(); - else if (cellOrName.is()) - cell = cellOrName.as().mStore->getCell(); - else if (cellOrName.is() && !cellOrName.as().empty()) - cell = MWBase::Environment::get().getWorldModel()->getCell(cellOrName.as()).getCell(); - if (cell == nullptr) - throw std::runtime_error("Invalid cell"); - else if (!cell->isExterior()) - throw std::runtime_error("Cell cannot be interior"); - - return cell->getWorldSpace(); - } -} - -namespace MWLua -{ - sol::table initCoreLandBindings(const Context& context) - { - sol::state_view lua = context.sol(); - sol::table landApi(lua, sol::create); - - landApi["getHeightAt"] = [](const osg::Vec3f& pos, sol::object cellOrName) { - ESM::RefId worldspace = worldspaceAt(cellOrName); - return MWBase::Environment::get().getWorld()->getTerrainHeightAt(pos, worldspace); - }; - - landApi["getTextureAt"] = [lua = lua](const osg::Vec3f& pos, sol::object cellOrName) { - sol::variadic_results values; - const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); - const MWWorld::Store& landStore = store.get(); - ESM::RefId worldspace = worldspaceAt(cellOrName); - - if (worldspace != ESM::Cell::sDefaultWorldspaceId) - return values; - - const float cellSize = ESM::getCellSize(worldspace); - const float offset = (cellSize / ESM::LandRecordData::sLandTextureSize) * 0.25; - const osg::Vec3f correctedPos = pos + osg::Vec3f{ -offset, +offset, 0.0f }; - - const ESM::Land* land = nullptr; - const ESM::Land::LandData* landData = nullptr; - - int cellX = static_cast(std::floor(correctedPos.x() / cellSize)); - int cellY = static_cast(std::floor(correctedPos.y() / cellSize)); - - land = landStore.search(cellX, cellY); - - if (land != nullptr) - landData = land->getLandData(ESM::Land::DATA_VTEX); - - // If we fail to preload land data, return, we need to be able to get *any* land to know how to correct - // the position used to sample terrain - if (landData == nullptr) - return values; - - const ESMTerrain::UniqueTextureId textureId - = getTextureAt(landData->mTextures, land->getPlugin(), correctedPos, cellSize); - - // Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId - if (textureId.first != 0) - { - const MWWorld::Store& textureStore = store.get(); - const std::string* textureString = textureStore.search(textureId.first - 1, textureId.second); - if (!textureString) - return values; - - values.push_back(sol::make_object(lua, *textureString)); - const std::vector& contentList = MWBase::Environment::get().getWorld()->getContentFiles(); - if (textureId.second >= 0 && static_cast(textureId.second) < contentList.size()) - values.push_back(sol::make_object(lua, contentList[textureId.second])); - } - - return values; - }; - - return LuaUtil::makeReadOnly(landApi); - } -} diff --git a/apps/openmw/mwlua/landbindings.hpp b/apps/openmw/mwlua/landbindings.hpp deleted file mode 100644 index 8cdf30046b..0000000000 --- a/apps/openmw/mwlua/landbindings.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef MWLUA_LANDBINDINGS_H -#define MWLUA_LANDBINDINGS_H - -#include "context.hpp" - -namespace MWLua -{ - sol::table initCoreLandBindings(const Context& context); -} - -#endif // MWLUA_LANDBINDINGS_H diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 7a212a10ea..8a78a52441 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -450,28 +450,6 @@ -- @usage for _, item in ipairs(inventory:findAll('common_shirt_01')) do ... end ---- @{#Land}: Functions for interacting with land data --- @field [parent=#core] #Land land - ---- --- Get the terrain height at a given location. --- @function [parent=#Land] getHeightAt --- @param openmw.util#Vector3 position --- @param #any cellOrName (optional) cell or cell name in their exterior world space to query --- @return #number - ---- --- Get the terrain texture at a given location. As textures are blended and --- multiple textures can be at one specific position the texture whose center is --- closest to the position will be returned. --- --- @function [parent=#Land] getTextureAt --- @param openmw.util#Vector3 position --- @param #any cellOrName cell or cell name in their exterior world space to query --- @return #nil, #string Texture path or nil if one isn't defined --- @return #nil, #string Plugin name or nil if failed to retrieve the texture - - --- @{#Magic}: spells and spell effects -- @field [parent=#core] #Magic magic From 608831265c92c23f1347b51fd904a151c1a79cd8 Mon Sep 17 00:00:00 2001 From: Sarah Sunday <1644563-ssunday@users.noreply.gitlab.com> Date: Sat, 14 Jun 2025 14:10:28 -0500 Subject: [PATCH 85/98] [CI] Attempt to add intel mac builds with separate build step --- .gitlab-ci.yml | 11 +++++++++++ CI/before_install.osx.sh | 2 +- CI/before_script.osx.sh | 6 ++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d55e554905..d715956a25 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -534,6 +534,17 @@ Ubuntu_GCC_integration_tests_asan: paths: - build/OpenMW-*.dmg +macOS14_Xcode15_x86-64: + extends: .MacOS + image: macos-14-xcode-15 + tags: + - saas-macos-medium-m1 + cache: + key: macOS14_Xcode15_x86-64.v1 + variables: + CCACHE_SIZE: 3G + MACOS_X86_64: true + macOS14_Xcode15_arm64: extends: .MacOS image: macos-14-xcode-15 diff --git a/CI/before_install.osx.sh b/CI/before_install.osx.sh index 30822f5d00..b1666690ef 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -20,7 +20,7 @@ ccache --version cmake --version qmake --version -if [[ "${MACOS_AMD64}" ]]; then +if [[ "${MACOS_X86_64}" ]]; 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 diff --git a/CI/before_script.osx.sh b/CI/before_script.osx.sh index 9be91f1632..7957514e88 100755 --- a/CI/before_script.osx.sh +++ b/CI/before_script.osx.sh @@ -29,6 +29,12 @@ declare -a CMAKE_CONF_OPTS=( -D OPENMW_OSX_DEPLOYMENT=TRUE ) +if [[ "${MACOS_X86_64}" ]]; 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} From 0f551c823374ca5f14b8cac7631953ee30ff86eb Mon Sep 17 00:00:00 2001 From: Sarah Sunday <1644563-ssunday@users.noreply.gitlab.com> Date: Sat, 14 Jun 2025 15:38:05 -0500 Subject: [PATCH 86/98] [CI] Always use arm deps --- CI/before_install.osx.sh | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/CI/before_install.osx.sh b/CI/before_install.osx.sh index b1666690ef..e5f63a89a6 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -20,10 +20,5 @@ ccache --version cmake --version qmake --version -if [[ "${MACOS_X86_64}" ]]; 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 +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 From 139bde6420c1833893925976aa0425cd168f9c24 Mon Sep 17 00:00:00 2001 From: Sarah Sunday <1644563-ssunday@users.noreply.gitlab.com> Date: Sat, 21 Jun 2025 13:53:40 -0500 Subject: [PATCH 87/98] [CI] Fork before install mac arm/intel steps, prefix with arch command --- CI/before_install.osx.sh | 23 ++++---------- CI/before_script.osx.sh | 50 +++++++++++++++++++++---------- CI/macos/before_install.arm.sh | 20 +++++++++++++ CI/macos/before_install.x86_64.sh | 8 +++++ 4 files changed, 67 insertions(+), 34 deletions(-) create mode 100755 CI/macos/before_install.arm.sh create mode 100755 CI/macos/before_install.x86_64.sh diff --git a/CI/before_install.osx.sh b/CI/before_install.osx.sh index e5f63a89a6..2e333261ab 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -4,21 +4,8 @@ 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@6 - -# Install deps -brew install openal-soft icu4c yaml-cpp sqlite - -ccache --version -cmake --version -qmake --version - -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 +if [[ "${MACOS_X86_64}" ]]; then + ./CI/macos/before_install.x86_64.sh +else + ./CI/macos/before_install.arm.sh +fi diff --git a/CI/before_script.osx.sh b/CI/before_script.osx.sh index 7957514e88..ceabaef280 100755 --- a/CI/before_script.osx.sh +++ b/CI/before_script.osx.sh @@ -9,10 +9,17 @@ cd build DEPENDENCIES_ROOT="/tmp/openmw-deps" -QT_PATH=$(brew --prefix qt@6) -ICU_PATH=$(brew --prefix icu4c) -OPENAL_PATH=$(brew --prefix openal-soft) -CCACHE_EXECUTABLE=$(brew --prefix ccache)/bin/ccache +if [[ "${MACOS_X86_64}" ]]; then + QT_PATH=$(arch -x86_64 brew --prefix qt@6) + ICU_PATH=$(arch -x86_64 brew --prefix icu4c) + OPENAL_PATH=$(arch -x86_64 brew --prefix openal-soft) + CCACHE_EXECUTABLE=$(arch -x86_64 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" @@ -29,6 +36,18 @@ declare -a CMAKE_CONF_OPTS=( -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=TRU +-D BUILD_NIFTEST=TRUE +-D BUILD_NAVMESHTOOL=TRUE +-D BUILD_BULLETOBJECTTOOL=TRUE +-G"Unix Makefiles" +) + if [[ "${MACOS_X86_64}" ]]; then CMAKE_CONF_OPTS+=( -D CMAKE_OSX_ARCHITECTURES="x86_64" @@ -45,15 +64,14 @@ else ) 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" \ -.. +if [[ "${MACOS_X86_64}" ]]; then + arch -x86_64 cmake \ + "${CMAKE_CONF_OPTS[@]}" \ + "${BUILD_OPTS[@]}" \ + .. +else + cmake \ + "${CMAKE_CONF_OPTS[@]}" \ + "${BUILD_OPTS[@]}" \ + .. +fi diff --git a/CI/macos/before_install.arm.sh b/CI/macos/before_install.arm.sh new file mode 100755 index 0000000000..1be5f7b740 --- /dev/null +++ b/CI/macos/before_install.arm.sh @@ -0,0 +1,20 @@ +#!/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 + +ccache --version +cmake --version +qmake --version + +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 --git a/CI/macos/before_install.x86_64.sh b/CI/macos/before_install.x86_64.sh new file mode 100755 index 0000000000..6e5664c3b0 --- /dev/null +++ b/CI/macos/before_install.x86_64.sh @@ -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 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 From 12f359622057ba735cc45bd615dea579768d4f18 Mon Sep 17 00:00:00 2001 From: Sarah Sunday <1644563-ssunday@users.noreply.gitlab.com> Date: Sat, 21 Jun 2025 14:19:43 -0500 Subject: [PATCH 88/98] [CI] Specify intel brew location --- CI/before_script.osx.sh | 8 ++++---- CI/macos/before_install.x86_64.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CI/before_script.osx.sh b/CI/before_script.osx.sh index ceabaef280..9281089c43 100755 --- a/CI/before_script.osx.sh +++ b/CI/before_script.osx.sh @@ -10,10 +10,10 @@ cd build DEPENDENCIES_ROOT="/tmp/openmw-deps" if [[ "${MACOS_X86_64}" ]]; then - QT_PATH=$(arch -x86_64 brew --prefix qt@6) - ICU_PATH=$(arch -x86_64 brew --prefix icu4c) - OPENAL_PATH=$(arch -x86_64 brew --prefix openal-soft) - CCACHE_EXECUTABLE=$(arch -x86_64 brew --prefix ccache)/bin/ccache + 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) diff --git a/CI/macos/before_install.x86_64.sh b/CI/macos/before_install.x86_64.sh index 6e5664c3b0..642f2c2c62 100755 --- a/CI/macos/before_install.x86_64.sh +++ b/CI/macos/before_install.x86_64.sh @@ -2,7 +2,7 @@ arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -arch -x86_64 brew install curl xquartz gd fontconfig freetype harfbuzz brotli s3cmd ccache cmake qt@6 openal-soft icu4c yaml-cpp sqlite +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 From faa9af4428f87db9d0844eace8d0875ef8472e9f Mon Sep 17 00:00:00 2001 From: Sarah Sunday <1644563-ssunday@users.noreply.gitlab.com> Date: Sat, 21 Jun 2025 19:53:02 -0500 Subject: [PATCH 89/98] [CI] Overhaul mac CI flow --- .github/workflows/push.yml | 8 +++--- .gitlab-ci.yml | 25 +++++++++---------- ...install.osx.sh => before_install.macos.sh} | 6 ++--- ...e_script.osx.sh => before_script.macos.sh} | 6 ++--- ...tall.x86_64.sh => before_install.amd64.sh} | 0 ...install.arm.sh => before_install.arm64.sh} | 0 CI/macos/build.sh | 9 +++++++ CI/macos/ccache_prep.sh | 12 +++++++++ CI/macos/ccache_save.sh | 7 ++++++ 9 files changed, 49 insertions(+), 24 deletions(-) rename CI/{before_install.osx.sh => before_install.macos.sh} (51%) rename CI/{before_script.osx.sh => before_script.macos.sh} (95%) rename CI/macos/{before_install.x86_64.sh => before_install.amd64.sh} (100%) rename CI/macos/{before_install.arm.sh => before_install.arm64.sh} (100%) create mode 100755 CI/macos/build.sh create mode 100755 CI/macos/ccache_prep.sh create mode 100755 CI/macos/ccache_save.sh diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 41fa39b78d..3c4f4c45a7 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -73,7 +73,7 @@ jobs: - 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 @@ jobs: 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 --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d715956a25..ab8aa3d76d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -507,14 +507,11 @@ Ubuntu_GCC_integration_tests_asan: paths: - ccache/ script: - - CI/before_install.osx.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/before_install.macos.sh + - CI/macos/ccache_prep.sh + - CI/before_script.macos.sh + - CI/macos/build.sh + - for dmg in *.dmg; do mv "$dmg" "${dmg%.dmg}_${CI_COMMIT_REF_NAME##*/}_${DMG_IDENTIFIER}.dmg"; done - | if [[ -n "${AWS_ACCESS_KEY_ID}" ]]; then echo "[default]" > ~/.s3cfg @@ -529,21 +526,22 @@ Ubuntu_GCC_integration_tests_asan: s3cmd put "${dmg}" s3://openmw-artifacts/${artifactDirectory} done fi - - ccache -s + - CI/macos/ccache_save.sh artifacts: paths: - build/OpenMW-*.dmg -macOS14_Xcode15_x86-64: +macOS14_Xcode15_amd64: extends: .MacOS image: macos-14-xcode-15 tags: - saas-macos-medium-m1 cache: - key: macOS14_Xcode15_x86-64.v1 + key: macOS14_Xcode15_amd64.v1 variables: CCACHE_SIZE: 3G - MACOS_X86_64: true + DMG_IDENTIFIER: amd64 + MACOS_AMD64: true macOS14_Xcode15_arm64: extends: .MacOS @@ -553,6 +551,7 @@ macOS14_Xcode15_arm64: cache: key: macOS14_Xcode15_arm64.v1 variables: + DMG_IDENTIFIER: arm64 CCACHE_SIZE: 3G .Compress_And_Upload_Symbols_Base: @@ -979,7 +978,7 @@ Windows_MSBuild_CacheInit: - flatpak build-bundle ./repo openmw.flatpak org.openmw.OpenMW.devel cache: key: flatpak - paths: + paths: - ".flatpak-builder" artifacts: untracked: false diff --git a/CI/before_install.osx.sh b/CI/before_install.macos.sh similarity index 51% rename from CI/before_install.osx.sh rename to CI/before_install.macos.sh index 2e333261ab..f466dd06a7 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.macos.sh @@ -4,8 +4,8 @@ export HOMEBREW_NO_EMOJI=1 export HOMEBREW_NO_INSTALL_CLEANUP=1 export HOMEBREW_AUTOREMOVE=1 -if [[ "${MACOS_X86_64}" ]]; then - ./CI/macos/before_install.x86_64.sh +if [[ "${MACOS_AMD64}" ]]; then + ./CI/macos/before_install.amd64.sh else - ./CI/macos/before_install.arm.sh + ./CI/macos/before_install.arm64.sh fi diff --git a/CI/before_script.osx.sh b/CI/before_script.macos.sh similarity index 95% rename from CI/before_script.osx.sh rename to CI/before_script.macos.sh index 9281089c43..1d4b02e380 100755 --- a/CI/before_script.osx.sh +++ b/CI/before_script.macos.sh @@ -41,14 +41,14 @@ declare -a BUILD_OPTS=( -D BUILD_OPENCS=TRUE -D BUILD_ESMTOOL=TRUE -D BUILD_BSATOOL=TRUE --D BUILD_ESSIMPORTER=TRU +-D BUILD_ESSIMPORTER=TRUE -D BUILD_NIFTEST=TRUE -D BUILD_NAVMESHTOOL=TRUE -D BUILD_BULLETOBJECTTOOL=TRUE -G"Unix Makefiles" ) -if [[ "${MACOS_X86_64}" ]]; then +if [[ "${MACOS_AMD64}" ]]; then CMAKE_CONF_OPTS+=( -D CMAKE_OSX_ARCHITECTURES="x86_64" ) @@ -64,7 +64,7 @@ else ) fi -if [[ "${MACOS_X86_64}" ]]; then +if [[ "${MACOS_AMD64}" ]]; then arch -x86_64 cmake \ "${CMAKE_CONF_OPTS[@]}" \ "${BUILD_OPTS[@]}" \ diff --git a/CI/macos/before_install.x86_64.sh b/CI/macos/before_install.amd64.sh similarity index 100% rename from CI/macos/before_install.x86_64.sh rename to CI/macos/before_install.amd64.sh diff --git a/CI/macos/before_install.arm.sh b/CI/macos/before_install.arm64.sh similarity index 100% rename from CI/macos/before_install.arm.sh rename to CI/macos/before_install.arm64.sh diff --git a/CI/macos/build.sh b/CI/macos/build.sh new file mode 100755 index 0000000000..64986717ce --- /dev/null +++ b/CI/macos/build.sh @@ -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 --git a/CI/macos/ccache_prep.sh b/CI/macos/ccache_prep.sh new file mode 100755 index 0000000000..17af2f9b55 --- /dev/null +++ b/CI/macos/ccache_prep.sh @@ -0,0 +1,12 @@ +#!/bin/sh -ex + +export CCACHE_BASEDIR="$(pwd)" +export CCACHE_DIR="$(pwd)/ccache" +mkdir -pv "${CCACHE_DIR}" +ccache -z -M "${CCACHE_SIZE}" + +if [[ "${MACOS_AMD64}" ]]; then + arch -x86_64 ccache -z -M "${CCACHE_SIZE}" +else + ccache -z -M "${CCACHE_SIZE}" +fi diff --git a/CI/macos/ccache_save.sh b/CI/macos/ccache_save.sh new file mode 100755 index 0000000000..d06d16fb0c --- /dev/null +++ b/CI/macos/ccache_save.sh @@ -0,0 +1,7 @@ +#!/bin/sh -ex + +if [[ "${MACOS_AMD64}" ]]; then + arch -x86_64 ccache -s +else + ccache -s +fi From adc4698c4460763eccb8e0c42f10bea2c74610a0 Mon Sep 17 00:00:00 2001 From: Sarah Sunday <1644563-ssunday@users.noreply.gitlab.com> Date: Sat, 21 Jun 2025 21:14:44 -0500 Subject: [PATCH 90/98] [CI] Revert ccache script forking, rename try, cleanup --- .gitlab-ci.yml | 4 ++-- CI/macos/before_install.arm64.sh | 4 ---- CI/macos/ccache_prep.sh | 7 +------ CI/macos/ccache_save.sh | 7 ------- 4 files changed, 3 insertions(+), 19 deletions(-) delete mode 100755 CI/macos/ccache_save.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ab8aa3d76d..30654a8471 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -511,7 +511,7 @@ Ubuntu_GCC_integration_tests_asan: - CI/macos/ccache_prep.sh - CI/before_script.macos.sh - CI/macos/build.sh - - for dmg in *.dmg; do mv "$dmg" "${dmg%.dmg}_${CI_COMMIT_REF_NAME##*/}_${DMG_IDENTIFIER}.dmg"; done + - 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 @@ -526,7 +526,7 @@ Ubuntu_GCC_integration_tests_asan: s3cmd put "${dmg}" s3://openmw-artifacts/${artifactDirectory} done fi - - CI/macos/ccache_save.sh + - ccache -s artifacts: paths: - build/OpenMW-*.dmg diff --git a/CI/macos/before_install.arm64.sh b/CI/macos/before_install.arm64.sh index 1be5f7b740..84120dfba2 100755 --- a/CI/macos/before_install.arm64.sh +++ b/CI/macos/before_install.arm64.sh @@ -12,9 +12,5 @@ command -v qmake >/dev/null 2>&1 || brew install qt@6 # Install deps brew install openal-soft icu4c yaml-cpp sqlite -ccache --version -cmake --version -qmake --version - 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 --git a/CI/macos/ccache_prep.sh b/CI/macos/ccache_prep.sh index 17af2f9b55..06dd5c8479 100755 --- a/CI/macos/ccache_prep.sh +++ b/CI/macos/ccache_prep.sh @@ -3,10 +3,5 @@ export CCACHE_BASEDIR="$(pwd)" export CCACHE_DIR="$(pwd)/ccache" mkdir -pv "${CCACHE_DIR}" -ccache -z -M "${CCACHE_SIZE}" -if [[ "${MACOS_AMD64}" ]]; then - arch -x86_64 ccache -z -M "${CCACHE_SIZE}" -else - ccache -z -M "${CCACHE_SIZE}" -fi +ccache -z -M "${CCACHE_SIZE}" diff --git a/CI/macos/ccache_save.sh b/CI/macos/ccache_save.sh deleted file mode 100755 index d06d16fb0c..0000000000 --- a/CI/macos/ccache_save.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -ex - -if [[ "${MACOS_AMD64}" ]]; then - arch -x86_64 ccache -s -else - ccache -s -fi From 4bbc5710fb840273a674d0f3a372b1f54521cf14 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 22 Jun 2025 14:24:44 +0400 Subject: [PATCH 91/98] Fix some errors in Lua docs --- files/lua_api/openmw/core.lua | 2 +- files/lua_api/openmw/types.lua | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 8a78a52441..3275d2eb82 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -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 --git a/files/lua_api/openmw/types.lua b/files/lua_api/openmw/types.lua index 5aef5fac94..3802ad1492 100644 --- a/files/lua_api/openmw/types.lua +++ b/files/lua_api/openmw/types.lua @@ -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} From 50e3c9d50079917ddd8224dfbfef10994034e62d Mon Sep 17 00:00:00 2001 From: Sarah Sunday <1644563-ssunday@users.noreply.gitlab.com> Date: Sun, 22 Jun 2025 10:35:16 -0500 Subject: [PATCH 92/98] [CI] Ccache flow tweak, use forked commands, cd build --- .gitlab-ci.yml | 8 ++++++-- CI/macos/ccache_prep.sh | 10 +++++----- CI/macos/ccache_save.sh | 7 +++++++ 3 files changed, 18 insertions(+), 7 deletions(-) create mode 100755 CI/macos/ccache_save.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 30654a8471..f275702d2c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -508,9 +508,13 @@ Ubuntu_GCC_integration_tests_asan: - ccache/ script: - CI/before_install.macos.sh + - export CCACHE_BASEDIR="$(pwd)" + - export CCACHE_DIR="$(pwd)/ccache" + - mkdir -pv "${CCACHE_DIR}" - 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 @@ -526,7 +530,7 @@ Ubuntu_GCC_integration_tests_asan: s3cmd put "${dmg}" s3://openmw-artifacts/${artifactDirectory} done fi - - ccache -s + - CI/macos/ccache_save.sh artifacts: paths: - build/OpenMW-*.dmg @@ -537,7 +541,7 @@ macOS14_Xcode15_amd64: tags: - saas-macos-medium-m1 cache: - key: macOS14_Xcode15_amd64.v1 + key: macOS14_Xcode15_amd64.v2 variables: CCACHE_SIZE: 3G DMG_IDENTIFIER: amd64 diff --git a/CI/macos/ccache_prep.sh b/CI/macos/ccache_prep.sh index 06dd5c8479..abd0103be0 100755 --- a/CI/macos/ccache_prep.sh +++ b/CI/macos/ccache_prep.sh @@ -1,7 +1,7 @@ #!/bin/sh -ex -export CCACHE_BASEDIR="$(pwd)" -export CCACHE_DIR="$(pwd)/ccache" -mkdir -pv "${CCACHE_DIR}" - -ccache -z -M "${CCACHE_SIZE}" +if [[ "${MACOS_AMD64}" ]]; then + arch -x86_64 ccache -z -M "${CCACHE_SIZE}" +else + ccache -z -M "${CCACHE_SIZE}" +fi diff --git a/CI/macos/ccache_save.sh b/CI/macos/ccache_save.sh new file mode 100755 index 0000000000..d06d16fb0c --- /dev/null +++ b/CI/macos/ccache_save.sh @@ -0,0 +1,7 @@ +#!/bin/sh -ex + +if [[ "${MACOS_AMD64}" ]]; then + arch -x86_64 ccache -s +else + ccache -s +fi From 493827285b7292bf9446b38fff1b29e095776a8e Mon Sep 17 00:00:00 2001 From: Sarah Sunday <1644563-ssunday@users.noreply.gitlab.com> Date: Sun, 22 Jun 2025 13:35:23 -0500 Subject: [PATCH 93/98] [CI] Fix path and big env goof --- .gitlab-ci.yml | 2 +- CI/before_script.macos.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f275702d2c..52fa51d299 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -530,7 +530,7 @@ Ubuntu_GCC_integration_tests_asan: s3cmd put "${dmg}" s3://openmw-artifacts/${artifactDirectory} done fi - - CI/macos/ccache_save.sh + - ../CI/macos/ccache_save.sh artifacts: paths: - build/OpenMW-*.dmg diff --git a/CI/before_script.macos.sh b/CI/before_script.macos.sh index 1d4b02e380..50adab234d 100755 --- a/CI/before_script.macos.sh +++ b/CI/before_script.macos.sh @@ -9,7 +9,7 @@ cd build DEPENDENCIES_ROOT="/tmp/openmw-deps" -if [[ "${MACOS_X86_64}" ]]; then +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) From cbb50c001b9f13c962ac5f99a09cb626f0f4272e Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 28 Jun 2025 11:25:19 +0200 Subject: [PATCH 94/98] Destroy the script manager after the window manager --- CHANGELOG.md | 1 + apps/openmw/engine.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 479a19d905..67a7970983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -237,6 +237,7 @@ 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 + Bug #8576: Crash on exit when unresolving containers with scripted items 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 --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7dc372f269..0f82e953c1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -404,8 +404,8 @@ OMW::Engine::~Engine() mMechanicsManager = nullptr; mDialogueManager = nullptr; mJournal = nullptr; - mScriptManager = nullptr; mWindowManager = nullptr; + mScriptManager = nullptr; mWorld = nullptr; mStereoManager = nullptr; mSoundManager = nullptr; From 2ff497c3e5509b9cb601cfe6d71d5058e58acc16 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 29 Jun 2025 12:49:22 +0200 Subject: [PATCH 95/98] Use string_view in CSMPrefs::ShortcutManager --- apps/opencs/model/prefs/shortcutmanager.cpp | 14 +++++++------- apps/opencs/model/prefs/shortcutmanager.hpp | 10 +++++----- apps/opencs/model/prefs/state.cpp | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index d6686d31d9..ac032efffb 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -78,7 +78,7 @@ namespace CSMPrefs } } - bool ShortcutManager::getModifier(const std::string& name, int& modifier) const + bool ShortcutManager::getModifier(std::string_view name, int& modifier) const { ModifierMap::const_iterator item = mModifiers.find(name); if (item != mModifiers.end()) @@ -175,14 +175,14 @@ namespace CSMPrefs return concat; } - void ShortcutManager::convertFromString(const std::string& data, QKeySequence& sequence) const + void ShortcutManager::convertFromString(std::string_view data, QKeySequence& sequence) const { const int MaxKeys = 4; // A limitation of QKeySequence size_t end = data.find(';'); size_t size = std::min(end, data.size()); - std::string value = data.substr(0, size); + std::string_view value = data.substr(0, size); size_t start = 0; int keyPos = 0; @@ -195,7 +195,7 @@ namespace CSMPrefs end = data.find('+', start); end = std::min(end, value.size()); - std::string name = value.substr(start, end - start); + std::string_view name = value.substr(start, end - start); if (name == "Ctrl") { @@ -242,12 +242,12 @@ namespace CSMPrefs sequence = QKeySequence(keys[0], keys[1], keys[2], keys[3]); } - void ShortcutManager::convertFromString(const std::string& data, int& modifier) const + void ShortcutManager::convertFromString(std::string_view data, int& modifier) const { size_t start = data.find(';') + 1; start = std::min(start, data.size()); - std::string name = data.substr(start); + std::string_view name = data.substr(start); KeyMap::const_iterator searchResult = mKeys.find(name); if (searchResult != mKeys.end()) { @@ -259,7 +259,7 @@ namespace CSMPrefs } } - void ShortcutManager::convertFromString(const std::string& data, QKeySequence& sequence, int& modifier) const + void ShortcutManager::convertFromString(std::string_view data, QKeySequence& sequence, int& modifier) const { convertFromString(data, sequence); convertFromString(data, modifier); diff --git a/apps/opencs/model/prefs/shortcutmanager.hpp b/apps/opencs/model/prefs/shortcutmanager.hpp index 0cfe3ad86a..fa25876660 100644 --- a/apps/opencs/model/prefs/shortcutmanager.hpp +++ b/apps/opencs/model/prefs/shortcutmanager.hpp @@ -31,7 +31,7 @@ namespace CSMPrefs bool getSequence(std::string_view name, QKeySequence& sequence) const; void setSequence(std::string_view name, const QKeySequence& sequence); - bool getModifier(const std::string& name, int& modifier) const; + bool getModifier(std::string_view name, int& modifier) const; void setModifier(std::string_view name, int modifier); std::string convertToString(const QKeySequence& sequence) const; @@ -39,10 +39,10 @@ namespace CSMPrefs std::string convertToString(const QKeySequence& sequence, int modifier) const; - void convertFromString(const std::string& data, QKeySequence& sequence) const; - void convertFromString(const std::string& data, int& modifier) const; + void convertFromString(std::string_view data, QKeySequence& sequence) const; + void convertFromString(std::string_view data, int& modifier) const; - void convertFromString(const std::string& data, QKeySequence& sequence, int& modifier) const; + void convertFromString(std::string_view data, QKeySequence& sequence, int& modifier) const; /// Replaces "{sequence-name}" or "{modifier-name}" with the appropriate text QString processToolTip(const QString& toolTip) const; @@ -53,7 +53,7 @@ namespace CSMPrefs typedef std::map> SequenceMap; typedef std::map> ModifierMap; typedef std::map NameMap; - typedef std::map KeyMap; + typedef std::map> KeyMap; ShortcutMap mShortcuts; SequenceMap mSequences; diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index f0af163bf2..5c32ddb68b 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -498,7 +498,7 @@ CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut( // Setup with actual data QKeySequence sequence; - getShortcutManager().convertFromString(value, sequence); + getShortcutManager().convertFromString(value.get(), sequence); getShortcutManager().setSequence(value.mName, sequence); CSMPrefs::ShortcutSetting* setting From 5ef947e14fb6894b70f9e0d6d0865fc9e025e374 Mon Sep 17 00:00:00 2001 From: Aussiemon <1407091-Aussiemon@users.noreply.gitlab.com> Date: Tue, 1 Jul 2025 15:25:36 -0600 Subject: [PATCH 96/98] Match vanilla moon phases and visibility times --- apps/openmw/mwworld/weather.cpp | 119 +++- apps/openmw/mwworld/weather.hpp | 9 +- apps/openmw_tests/CMakeLists.txt | 1 + apps/openmw_tests/mwworld/testweather.cpp | 732 ++++++++++++++++++++++ 4 files changed, 836 insertions(+), 25 deletions(-) create mode 100644 apps/openmw_tests/mwworld/testweather.cpp diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 4f6f52a81a..2ee77458d4 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -352,6 +352,30 @@ namespace MWWorld mWeather = 0; } + MoonModel::MoonModel(float fadeInStart, float fadeInFinish, float fadeOutStart, float fadeOutFinish, + float axisOffset, float speed, float dailyIncrement, float fadeStartAngle, float fadeEndAngle, + float moonShadowEarlyFadeAngle) + { + mFadeInStart = fadeInStart; + mFadeInFinish = fadeInFinish; + mFadeOutStart = fadeOutStart; + mFadeOutFinish = fadeOutFinish; + mAxisOffset = axisOffset; + mDailyIncrement = dailyIncrement; + mFadeStartAngle = fadeStartAngle; + mFadeEndAngle = fadeEndAngle; + mMoonShadowEarlyFadeAngle = moonShadowEarlyFadeAngle; + + // Morrowind appears to have a minimum speed to avoid situations where the moon can't + // complete a full rotation in a single 24-hour period. The reverse-engineered formula is + // 180 degrees (full hemisphere) / 23 hours / 15 degrees (1 hour travel at speed 1.0). + mSpeed = std::max(speed, (180.0f / 23.0f / 15.0f)); + + // Morrowind appears to reduce mDailyIncrement with modulo 24.0f to avoid situations where + // the moon would increment more than an entire rotation in a single day. + mDailyIncrement = std::fmod(mDailyIncrement, 24.0f); + } + MoonModel::MoonModel(const std::string& name) : mFadeInStart(Fallback::Map::getFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(Fallback::Map::getFloat("Moons_" + name + "_Fade_In_Finish")) @@ -364,14 +388,19 @@ namespace MWWorld , mFadeEndAngle(Fallback::Map::getFloat("Moons_" + name + "_Fade_End_Angle")) , mMoonShadowEarlyFadeAngle(Fallback::Map::getFloat("Moons_" + name + "_Moon_Shadow_Early_Fade_Angle")) { - // Morrowind appears to have a minimum speed in order to avoid situations where the moon couldn't conceivably - // complete a rotation in a single 24 hour period. The value of 180/23 was deduced from reverse engineering. - mSpeed = std::min(mSpeed, 180.0f / 23.0f); + // Morrowind appears to have a minimum speed to avoid situations where the moon can't + // complete a full rotation in a single 24-hour period. The reverse-engineered formula is + // 180 degrees (full hemisphere) / 23 hours / 15 degrees (1 hour travel at speed 1.0). + mSpeed = std::max(mSpeed, (180.0f / 23.0f / 15.0f)); + + // Morrowind appears to reduce mDailyIncrement with modulo 24.0f to avoid situations where + // the moon would increment more than an entire rotation in a single day. + mDailyIncrement = std::fmod(mDailyIncrement, 24.0f); } MWRender::MoonState MoonModel::calculateState(const TimeStamp& gameTime) const { - float rotationFromHorizon = angle(gameTime); + float rotationFromHorizon = angle(gameTime.getDay(), gameTime.getHour()); MWRender::MoonState state = { rotationFromHorizon, mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. phase(gameTime), shadowBlend(rotationFromHorizon), @@ -380,7 +409,7 @@ namespace MWWorld return state; } - inline float MoonModel::angle(const TimeStamp& gameTime) const + inline float MoonModel::angle(int gameDay, float gameHour) const { // Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to // the opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon @@ -390,49 +419,83 @@ namespace MWWorld // 1. Moon rises and then sets in one day. // 2. Moon sets and doesn't rise in one day (occurs when the moon rise hour is >= 24). // 3. Moon sets and then rises in one day. - float moonRiseHourToday = moonRiseHour(gameTime.getDay()); - float moonRiseAngleToday = 0; + float moonRiseHourToday = moonRiseHour(gameDay); + float moonRiseAngleToday = 0.0f; - if (gameTime.getHour() < moonRiseHourToday) + if (gameHour < moonRiseHourToday) { - float moonRiseHourYesterday = moonRiseHour(gameTime.getDay() - 1); - if (moonRiseHourYesterday < 24) + // Rise hour increases by mDailyIncrement each day, so yesterday's is easy to calculate + float moonRiseHourYesterday = moonRiseHourToday - mDailyIncrement; + if (moonRiseHourYesterday < 24.0f) { - float moonRiseAngleYesterday = rotation(24 - moonRiseHourYesterday); - if (moonRiseAngleYesterday < 180) + // Morrowind offsets the increment by -1 when the previous day's visible point crosses into the next + // day. The offset lasts from this point until the next 24-day loop starts. To find this point we add + // mDailyIncrement to the previous visible point and check the result. + float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; + float timeToVisible = moonShadowEarlyFadeAngle1 / rotation(1.0f); + float cycleOffset = moonRiseHourYesterday + timeToVisible > 24.0f ? mDailyIncrement : 0.0f; + + float moonRiseAngleYesterday = rotation(24.0f - (moonRiseHourYesterday + cycleOffset)); + if (moonRiseAngleYesterday < 180.0f) { // The moon rose but did not set yesterday, so accumulate yesterday's angle with how much we've // travelled today. - moonRiseAngleToday = rotation(gameTime.getHour()) + moonRiseAngleYesterday; + moonRiseAngleToday = rotation(gameHour) + moonRiseAngleYesterday; } } } else { - moonRiseAngleToday = rotation(gameTime.getHour() - moonRiseHourToday); + moonRiseAngleToday = rotation(gameHour - moonRiseHourToday); } - if (moonRiseAngleToday >= 180) + if (moonRiseAngleToday >= 180.0f) { // The moon set today, reset the angle to the horizon. - moonRiseAngleToday = 0; + moonRiseAngleToday = 0.0f; } return moonRiseAngleToday; } - inline float MoonModel::moonRiseHour(unsigned int daysPassed) const + inline float MoonModel::moonPhaseHour(int gameDay) const { + // Morrowind delays moon phase changes until one of these is true: + // * The moon is invisible at midnight. + // * The moon reached moonShadowEarlyFadeAngle2 one daily increment ago (therefore invisible). + if (!isVisible(gameDay, 0.0f)) + return 0.0f; + else + { + // Calculate the angle at which the moon becomes transparent and the starting angle. + float moonShadowEarlyFadeAngle2 = (180.0f - mFadeEndAngle) + mMoonShadowEarlyFadeAngle; + float midnightAngle = angle(gameDay, 0.0f); + + // We can assume that moonShadowEarlyFadeAngle2 > midnightAngle, because the opposite + // case would make the moon invisible at midnight, which is checked above. + return ((moonShadowEarlyFadeAngle2 - midnightAngle) / rotation(1.0f)) + std::max(mDailyIncrement, 0.0f); + } + } + + inline float MoonModel::moonRiseHour(int gameDay) const + { + if (mDailyIncrement == 0.0f) + return 0.0f; + // This arises from the start date of 16 Last Seed, 427 // TODO: Find an alternate formula that doesn't rely on this day being fixed. - static const unsigned int startDay = 16; + constexpr int startDay = 16; + + // This formula finds the number of missed increments necessary to make the rise hour a 24-day loop. + // The offset increases on the first day of the loop and is multiplied by the number of completed loops. + float incrementOffset = (24.0f - std::abs(24.0f / mDailyIncrement)) * std::floor((gameDay + startDay) / 24.0f); // This odd formula arises from the fact that on 16 Last Seed, 17 increments have occurred, meaning // that upon starting a new game, it must only calculate the moon phase as far back as 1 Last Seed. // Note that we don't modulo after adding the latest daily increment because other calculations need to // know if doing so would cause the moon rise to be postponed until the next day (which happens when // the moon rise hour is >= 24 in Morrowind). - return mDailyIncrement + std::fmod((daysPassed - 1 + startDay) * mDailyIncrement, 24.0f); + return mDailyIncrement + std::fmod((gameDay - 1 + startDay - incrementOffset) * mDailyIncrement, 24.0f); } inline float MoonModel::rotation(float hours) const @@ -449,12 +512,18 @@ namespace MWWorld // phase cycle. // If the moon didn't rise yet today, use yesterday's moon phase. - if (gameTime.getHour() < moonRiseHour(gameTime.getDay())) + if (gameTime.getHour() < moonPhaseHour(gameTime.getDay())) return static_cast((gameTime.getDay() / 3) % 8); else return static_cast(((gameTime.getDay() + 1) / 3) % 8); } + inline bool MoonModel::isVisible(int gameDay, float gameHour) const + { + // Moons are "visible" when their alpha value is non-zero. + return hourlyAlpha(gameHour) > 0.f && earlyMoonShadowAlpha(angle(gameDay, gameHour)) > 0.f; + } + inline float MoonModel::shadowBlend(float angle) const { // The Fade End Angle and Fade Start Angle describe a region where the moon transitions from a solid disk @@ -480,6 +549,10 @@ namespace MWWorld inline float MoonModel::hourlyAlpha(float gameHour) const { + // Morrowind culls the moon one minute before mFadeOutFinish + constexpr float oneMinute = 0.0167f; + float adjustedFadeOutFinish = mFadeOutFinish - oneMinute; + // The Fade Out Start / Finish and Fade In Start / Finish describe the hours at which the moon // appears and disappears. // Depending on the current hour, the following values describe how transparent the moon is. @@ -487,9 +560,9 @@ namespace MWWorld // 2. From Fade Out Finish to Fade In Start: 0 (transparent) // 3. From Fade In Start to Fade In Finish: 0..1 // 4. From Fade In Finish to Fade Out Start: 1 (solid) - if ((gameHour >= mFadeOutStart) && (gameHour < mFadeOutFinish)) - return (mFadeOutFinish - gameHour) / (mFadeOutFinish - mFadeOutStart); - else if ((gameHour >= mFadeOutFinish) && (gameHour < mFadeInStart)) + if ((gameHour >= mFadeOutStart) && (gameHour < adjustedFadeOutFinish)) + return (adjustedFadeOutFinish - gameHour) / (adjustedFadeOutFinish - mFadeOutStart); + else if ((gameHour >= adjustedFadeOutFinish) && (gameHour < mFadeInStart)) return 0.0f; else if ((gameHour >= mFadeInStart) && (gameHour < mFadeInFinish)) return (gameHour - mFadeInStart) / (mFadeInFinish - mFadeInStart); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 0643240dcd..7c27a10316 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -251,6 +251,9 @@ namespace MWWorld { public: MoonModel(const std::string& name); + MoonModel(float fadeInStart, float fadeInFinish, float fadeOutStart, float fadeOutFinish, float axisOffset, + float speed, float dailyIncrement, float fadeStartAngle, float fadeEndAngle, + float moonShadowEarlyFadeAngle); MWRender::MoonState calculateState(const TimeStamp& gameTime) const; @@ -266,10 +269,12 @@ namespace MWWorld float mFadeEndAngle; float mMoonShadowEarlyFadeAngle; - float angle(const TimeStamp& gameTime) const; - float moonRiseHour(unsigned int daysPassed) const; + float angle(int gameDay, float gameHour) const; + float moonPhaseHour(int gameDay) const; + float moonRiseHour(int gameDay) const; float rotation(float hours) const; MWRender::MoonState::Phase phase(const TimeStamp& gameTime) const; + bool isVisible(int gameDay, float gameHour) const; float shadowBlend(float angle) const; float hourlyAlpha(float gameHour) const; float earlyMoonShadowAlpha(float angle) const; diff --git a/apps/openmw_tests/CMakeLists.txt b/apps/openmw_tests/CMakeLists.txt index 9b57113110..5cfee9ce4b 100644 --- a/apps/openmw_tests/CMakeLists.txt +++ b/apps/openmw_tests/CMakeLists.txt @@ -10,6 +10,7 @@ file(GLOB UNITTEST_SRC_FILES mwworld/testduration.cpp mwworld/testtimestamp.cpp mwworld/testptr.cpp + mwworld/testweather.cpp mwdialogue/test_keywordsearch.cpp diff --git a/apps/openmw_tests/mwworld/testweather.cpp b/apps/openmw_tests/mwworld/testweather.cpp new file mode 100644 index 0000000000..4b7fd8f9e2 --- /dev/null +++ b/apps/openmw_tests/mwworld/testweather.cpp @@ -0,0 +1,732 @@ +#include + +#include + +#include "apps/openmw/mwworld/timestamp.hpp" +#include "apps/openmw/mwworld/weather.hpp" + +namespace MWWorld +{ + namespace + { + // MASSER PHASES + + TEST(MWWorldWeatherTest, masserPhasesFullToWaningGibbousAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 2 and 26, 11:57 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 2 + 11.0f + 56.0f / 60.0f); + timeStampAfter += (24.0f * 2 + 11.0f + 58.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 26 + 11.0f + 56.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 26 + 11.0f + 58.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(0)); + EXPECT_EQ(afterState.mPhase, static_cast(1)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(0)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(1)); + } + + TEST(MWWorldWeatherTest, masserPhasesWaningGibbousToThirdQuarterAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 5 and 29, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 4 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 5 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 28 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 29 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(1)); + EXPECT_EQ(afterState.mPhase, static_cast(2)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(1)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(2)); + } + + TEST(MWWorldWeatherTest, masserPhasesThirdQuarterToWaningCrescentAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 8 and 32, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 7 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 8 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 31 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 32 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(2)); + EXPECT_EQ(afterState.mPhase, static_cast(3)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(2)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(3)); + } + + TEST(MWWorldWeatherTest, masserPhasesWaningCrescentToNewAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 11 and 35, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 10 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 11 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 34 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 35 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(3)); + EXPECT_EQ(afterState.mPhase, static_cast(4)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(3)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(4)); + } + + TEST(MWWorldWeatherTest, masserPhasesNewToWaxingCrescentAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 14 and 38, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 13 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 14 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 37 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 38 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(4)); + EXPECT_EQ(afterState.mPhase, static_cast(5)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(4)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(5)); + } + + TEST(MWWorldWeatherTest, masserPhasesWaxingCrescentToFirstQuarterAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 17 and 41, 2:57 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 17 + 2.0f + 56.0f / 60.0f); + timeStampAfter += (24.0f * 17 + 2.0f + 58.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 41 + 2.0f + 56.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 41 + 2.0f + 58.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(5)); + EXPECT_EQ(afterState.mPhase, static_cast(6)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(5)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(6)); + } + + TEST(MWWorldWeatherTest, masserPhasesFirstQuarterToWaxingGibbousAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 20 and 44, 5:57 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 20 + 5.0f + 56.0f / 60.0f); + timeStampAfter += (24.0f * 20 + 5.0f + 58.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 44 + 5.0f + 56.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 44 + 5.0f + 58.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(6)); + EXPECT_EQ(afterState.mPhase, static_cast(7)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(6)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(7)); + } + + TEST(MWWorldWeatherTest, masserPhasesWaxingGibbousToFullAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 23 and 47, 8:57 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 23 + 8.0f + 56.0f / 60.0f); + timeStampAfter += (24.0f * 23 + 8.0f + 58.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 47 + 8.0f + 56.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 47 + 8.0f + 58.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(7)); + EXPECT_EQ(afterState.mPhase, static_cast(0)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(7)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(0)); + } + + // SECUNDA PHASES + + TEST(MWWorldWeatherTest, secundaPhasesFullToWaningGibbousAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 2 and 26, 14:19 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 2 + 14.0f + 18.0f / 60.0f); + timeStampAfter += (24.0f * 2 + 14.0f + 20.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 26 + 14.0f + 18.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 26 + 14.0f + 20.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(0)); + EXPECT_EQ(afterState.mPhase, static_cast(1)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(0)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(1)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaningGibbousToThirdQuarterAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 5 and 29, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 4 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 5 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 28 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 29 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(1)); + EXPECT_EQ(afterState.mPhase, static_cast(2)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(1)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(2)); + } + + TEST(MWWorldWeatherTest, secundaPhasesThirdQuarterToWaningCrescentAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 8 and 32, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 7 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 8 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 31 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 32 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(2)); + EXPECT_EQ(afterState.mPhase, static_cast(3)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(2)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(3)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaningCrescentToNewAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 11 and 35, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 10 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 11 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 34 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 35 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(3)); + EXPECT_EQ(afterState.mPhase, static_cast(4)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(3)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(4)); + } + + TEST(MWWorldWeatherTest, secundaPhasesNewToWaxingCrescentAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 14 and 38, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 13 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 14 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 37 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 38 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(4)); + EXPECT_EQ(afterState.mPhase, static_cast(5)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(4)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(5)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaxingCrescentToFirstQuarterAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 17 and 41, 3:31 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 17 + 3.0f + 30.0f / 60.0f); + timeStampAfter += (24.0f * 17 + 3.0f + 32.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 41 + 3.0f + 30.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 41 + 3.0f + 32.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(5)); + EXPECT_EQ(afterState.mPhase, static_cast(6)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(5)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(6)); + } + + TEST(MWWorldWeatherTest, secundaPhasesFirstQuarterToWaxingGibbousAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 20 and 44, 7:07 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 20 + 7.0f + 6.0f / 60.0f); + timeStampAfter += (24.0f * 20 + 7.0f + 8.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 44 + 7.0f + 6.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 44 + 7.0f + 8.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(6)); + EXPECT_EQ(afterState.mPhase, static_cast(7)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(6)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(7)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaxingGibbousToFullAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 23 and 47, 10:43 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 23 + 10.0f + 42.0f / 60.0f); + timeStampAfter += (24.0f * 23 + 10.0f + 44.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 47 + 10.0f + 42.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 47 + 10.0f + 44.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(7)); + EXPECT_EQ(afterState.mPhase, static_cast(0)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(7)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(0)); + } + + // OFFSETS + + TEST(MWWorldWeatherTest, secundaShouldApplyIncrementOffsetAfterFirstLoop) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 8 and 32, 3:16 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 8 + 3.0f + 15.0f / 60.0f); + timeStampAfter += (24.0f * 8 + 3.0f + 17.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 32 + 3.0f + 15.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 32 + 3.0f + 17.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, moonWithLowIncrementShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 0.9f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 35.0f; + + // Days 7 and 31, 1:44 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 7 + 1.0f + 43.0f / 60.0f); + timeStampAfter += (24.0f * 7 + 1.0f + 45.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 31 + 1.0f + 43.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 31 + 1.0f + 45.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, masserShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 35.0f; + + // Days 4 and 28, 1:02 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 4 + 1.0f + 1.0f / 60.0f); + timeStampAfter += (24.0f * 4 + 1.0f + 3.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 28 + 1.0f + 1.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 28 + 1.0f + 3.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, secundaShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 50.0f; + + // Days 3 and 27, 2:04 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 3 + 2.0f + 3.0f / 60.0f); + timeStampAfter += (24.0f * 3 + 2.0f + 5.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 27 + 2.0f + 3.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 27 + 2.0f + 5.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, moonWithIncreasedSpeedShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 1.2f; + float speed = 1.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 50.0f; + + // Days 4 and 28, 1:13 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 4 + 1.0f + 12.0f / 60.0f); + timeStampAfter += (24.0f * 4 + 1.0f + 14.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 28 + 1.0f + 12.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 28 + 1.0f + 14.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + } +} From 0a9c3ce96f3cfb56d0974f84d91912c9e350fca9 Mon Sep 17 00:00:00 2001 From: Aussiemon <1407091-Aussiemon@users.noreply.gitlab.com> Date: Tue, 1 Jul 2025 15:32:20 -0600 Subject: [PATCH 97/98] Skip duplicate enchantments on Spell Cycle action --- apps/openmw/mwgui/spellwindow.cpp | 55 +++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d183a00273..566b7f4ccd 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -242,21 +242,50 @@ namespace MWGui return; mSpellView->setModel(new SpellModel(MWMechanics::getPlayer())); - - SpellModel::ModelIndex selected = mSpellView->getModel()->getSelectedIndex(); - if (selected < 0) - selected = 0; - - selected += next ? 1 : -1; - int itemcount = mSpellView->getModel()->getItemCount(); - if (itemcount == 0) + int itemCount = mSpellView->getModel()->getItemCount(); + if (itemCount == 0) return; - selected = (selected + itemcount) % itemcount; - const Spell& spell = mSpellView->getModel()->getItem(selected); - if (spell.mType == Spell::Type_EnchantedItem) - onEnchantedItemSelected(spell.mItem, spell.mActive); + SpellModel::ModelIndex nextIndex; + SpellModel::ModelIndex currentIndex = mSpellView->getModel()->getSelectedIndex(); + + // If we have a selected index, search for a valid selection in the target direction + if (currentIndex >= 0) + { + MWWorld::ContainerStore store; + const Spell& currentSpell = mSpellView->getModel()->getItem(currentIndex); + + nextIndex = currentIndex; + for (int i = 0; i < itemCount; i++) + { + nextIndex += next ? 1 : -1; + nextIndex = (nextIndex + itemCount) % itemCount; + + // We can keep this selection if: + // * we're not switching off of an enchanted item + // * we're not switching to an enchanted item + // * the next item wouldn't stack with the current item + if (currentSpell.mType != Spell::Type_EnchantedItem) + break; + + const Spell& nextSpell = mSpellView->getModel()->getItem(nextIndex); + if (nextSpell.mType != Spell::Type_EnchantedItem || !store.stacks(currentSpell.mItem, nextSpell.mItem)) + break; + } + } + // Otherwise, the first selection is always index 0 else - onSpellSelected(spell.mId); + nextIndex = 0; + + // Only trigger the selection event if the selection is actually changing. + // The itemCount check earlier ensures we have at least one spell to select. + if (nextIndex != currentIndex) + { + const Spell& selectedSpell = mSpellView->getModel()->getItem(nextIndex); + if (selectedSpell.mType == Spell::Type_EnchantedItem) + onEnchantedItemSelected(selectedSpell.mItem, selectedSpell.mActive); + else + onSpellSelected(selectedSpell.mId); + } } } From 5ba0b3ab5204ec75bc5b6ceef73c7cd4accf48c3 Mon Sep 17 00:00:00 2001 From: Aussiemon <1407091-Aussiemon@users.noreply.gitlab.com> Date: Tue, 1 Jul 2025 15:37:27 -0600 Subject: [PATCH 98/98] Make item value affect theft observer's fight willingness --- .../mwmechanics/mechanicsmanagerimp.cpp | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 47c49a8861..384c25953b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1232,33 +1232,39 @@ namespace MWMechanics victim.getClass().getCreatureStats(victim).notifyMurder(); // Bounty and disposition penalty for each type of crime - float disp = 0.f, dispVictim = 0.f; + int bounty; + float disp, dispVictim; if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) { - arg = store.find("iCrimeTresspass")->mValue.getInteger(); + bounty = store.find("iCrimeTresspass")->mValue.getInteger(); disp = dispVictim = store.find("iDispTresspass")->mValue.getFloat(); } else if (type == OT_Pickpocket) { - arg = store.find("iCrimePickPocket")->mValue.getInteger(); + bounty = store.find("iCrimePickPocket")->mValue.getInteger(); disp = dispVictim = store.find("fDispPickPocketMod")->mValue.getFloat(); } else if (type == OT_Assault) { - arg = store.find("iCrimeAttack")->mValue.getInteger(); + bounty = store.find("iCrimeAttack")->mValue.getInteger(); disp = store.find("iDispAttackMod")->mValue.getFloat(); dispVictim = store.find("fDispAttacking")->mValue.getFloat(); } else if (type == OT_Murder) { - arg = store.find("iCrimeKilling")->mValue.getInteger(); + bounty = store.find("iCrimeKilling")->mValue.getInteger(); disp = dispVictim = store.find("iDispKilling")->mValue.getFloat(); } else if (type == OT_Theft) { + bounty = static_cast(arg * store.find("fCrimeStealing")->mValue.getFloat()); + bounty = std::max(1, bounty); // Minimum bounty of 1, in case items with zero value are stolen disp = dispVictim = store.find("fDispStealing")->mValue.getFloat() * arg; - arg = static_cast(arg * store.find("fCrimeStealing")->mValue.getFloat()); - arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen + } + else + { + bounty = arg; + disp = dispVictim = 0.f; } // Make surrounding actors within alarm distance respond to the crime @@ -1296,7 +1302,7 @@ namespace MWMechanics else if (type == OT_Murder) fight = fightVictim = esmStore.get().find("iFightKilling")->mValue.getInteger(); else if (type == OT_Theft) - fight = fightVictim = esmStore.get().find("fFightStealing")->mValue.getInteger(); + fight = fightVictim = esmStore.get().find("fFightStealing")->mValue.getInteger() * arg; bool reported = false; @@ -1457,7 +1463,7 @@ namespace MWMechanics if (reported) { player.getClass().getNpcStats(player).setBounty( - std::max(0, player.getClass().getNpcStats(player).getBounty() + arg)); + std::max(0, player.getClass().getNpcStats(player).getBounty() + bounty)); // If committing a crime against a faction member, expell from the faction if (!victim.isEmpty() && victim.getClass().isNpc())