Compare commits

..

No commits in common. "master" and "openmw-49-rc5" have entirely different histories.

147 changed files with 1101 additions and 1866 deletions

View file

@ -1,15 +1,18 @@
Checks: >
-*,
boost-*,
portability-*,
clang-analyzer-*,
-clang-analyzer-optin.*,
-clang-analyzer-optin*,
-clang-analyzer-cplusplus.NewDeleteLeaks,
-clang-analyzer-cplusplus.NewDelete,
-clang-analyzer-core.CallAndMessage,
modernize-avoid-bind,
readability-identifier-naming
WarningsAsErrors: '*'
HeaderFilterRegex: '(apps|components)/'
CheckOptions:
- key: readability-identifier-naming.ConceptCase
value: CamelCase
-modernize-avoid-bind
WarningsAsErrors: >
-*,
boost-*,
portability-*,
clang-analyzer-*,
-clang-analyzer-optin*,
-clang-analyzer-cplusplus.NewDeleteLeaks,
-clang-analyzer-core.CallAndMessage
HeaderFilterRegex: '^(apps|components)'

View file

@ -632,16 +632,12 @@ macOS14_Xcode15_arm64:
- |
if (Get-ChildItem -Recurse *.pdb) {
7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt
if(!$?) { Exit $LASTEXITCODE }
if (Test-Path env:AWS_ACCESS_KEY_ID) {
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" s3://openmw-artifacts/${artifactDirectory}
if(!$?) { Exit $LASTEXITCODE }
}
Push-Location ..
..\CI\Store-Symbols.ps1 -SkipCompress
if(!$?) { Exit $LASTEXITCODE }
7z a -tzip "..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_sym_store.zip"))" '.\SymStore\*' $config\CI-ID.txt
if(!$?) { Exit $LASTEXITCODE }
Pop-Location
Get-ChildItem -Recurse *.pdb | Remove-Item
}
@ -649,20 +645,13 @@ macOS14_Xcode15_arm64:
- |
if (Test-Path env:AWS_ACCESS_KEY_ID) {
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" s3://openmw-artifacts/${artifactDirectory}
if(!$?) { Exit $LASTEXITCODE }
}
- |
if ($executables) {
foreach ($exe in $executables.Split(',')) {
& .\$exe
if(!$?) { Exit $LASTEXITCODE }
}
}
- if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } }
after_script:
- Get-Volume
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
cache:
key: ninja-2022-v12
key: ninja-2022-v11
paths:
- ccache
- deps
@ -790,16 +779,12 @@ macOS14_Xcode15_arm64:
- |
if (Get-ChildItem -Recurse *.pdb) {
7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt
if(!$?) { Exit $LASTEXITCODE }
if (Test-Path env:AWS_ACCESS_KEY_ID) {
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" s3://openmw-artifacts/${artifactDirectory}
if(!$?) { Exit $LASTEXITCODE }
}
Push-Location ..
..\CI\Store-Symbols.ps1 -SkipCompress
if(!$?) { Exit $LASTEXITCODE }
7z a -tzip "..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_sym_store.zip"))" '.\SymStore\*' $config\CI-ID.txt
if(!$?) { Exit $LASTEXITCODE }
Pop-Location
Get-ChildItem -Recurse *.pdb | Remove-Item
}
@ -807,20 +792,13 @@ macOS14_Xcode15_arm64:
- |
if (Test-Path env:AWS_ACCESS_KEY_ID) {
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" s3://openmw-artifacts/${artifactDirectory}
if(!$?) { Exit $LASTEXITCODE }
}
- |
if ($executables) {
foreach ($exe in $executables.Split(',')) {
& .\$exe
if(!$?) { Exit $LASTEXITCODE }
}
}
- if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } }
after_script:
- Get-Volume
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
cache:
key: msbuild-2022-v12
key: msbuild-2022-v11
paths:
- deps
- MSVC2022_64/deps/Qt

View file

@ -35,6 +35,7 @@
Bug #5977: Fatigueless NPCs' corpse underwater changes animation on game load
Bug #6025: Subrecords cannot overlap records
Bug #6027: Collisionshape becomes spiderweb-like when the mesh is too complex
Bug #6097: Level Progress Tooltip Sometimes Not Updated
Bug #6146: Lua command `actor:setEquipment` doesn't trigger mwscripts when equipping or unequipping a scripted item
Bug #6156: 1ft Charm or Sound magic effect vfx doesn't work properly
Bug #6190: Unintuitive sun specularity time of day dependence
@ -227,11 +228,6 @@
Bug #8252: Plugin dependencies are not required to be loaded
Bug #8295: Post-processing chain is case-sensitive
Bug #8299: Crash while smoothing landscape
Bug #8364: Crash when clicking scrollbar without handle (divide by zero)
Bug #8378: Korean bitmap fonts are unusable
Bug #8439: Creatures without models can crash the game
Bug #8441: Freeze when using video main menu replacers
Bug #8462: Crashes when resizing the window on macOS
Feature #1415: Infinite fall failsafe
Feature #2566: Handle NAM9 records for manual cell references
Feature #3501: OpenMW-CS: Instance Editing - Shortcuts for axial locking
@ -396,7 +392,6 @@
Bug #6066: Addtopic "return" does not work from within script. No errors thrown
Bug #6067: ESP loader fails for certain subrecord orders
Bug #6087: Bound items added directly to the inventory disappear if their corresponding spell effect ends
Bug #6097: Level Progress Tooltip Sometimes Not Updated
Bug #6101: Disarming trapped unlocked owned objects isn't considered a crime
Bug #6107: Fatigue is incorrectly recalculated when fortify effect is applied or removed
Bug #6109: Crash when playing a custom made menu_background file

View file

@ -38,7 +38,7 @@ fi
if [[ $CI_CLANG_TIDY ]]; then
CMAKE_CONF_OPTS+=(
-DCMAKE_CXX_CLANG_TIDY=clang-tidy
-DCMAKE_CXX_CLANG_TIDY="clang-tidy;--warnings-as-errors=*"
-DBUILD_COMPONENTS_TESTS=ON
-DBUILD_OPENMW_TESTS=ON
-DBUILD_OPENCS_TESTS=ON

View file

@ -95,7 +95,7 @@ declare -rA GROUPED_DEPS=(
[libasan6]="libasan6"
[android]="binutils build-essential cmake ccache curl unzip git pkg-config"
[openmw-clang-format]="
clang-format-14
git-core
@ -126,24 +126,10 @@ export APT_CACHE_DIR="${PWD}/apt-cache"
export DEBIAN_FRONTEND=noninteractive
set -x
mkdir -pv "$APT_CACHE_DIR"
while true; do
apt-get update -yqq && break
done
apt-get update -yqq
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y --no-install-recommends software-properties-common gnupg >/dev/null
while true; do
add-apt-repository -y ppa:openmw/openmw && break
done
while true; do
add-apt-repository -y ppa:openmw/openmw-daily && break
done
while true; do
add-apt-repository -y ppa:openmw/staging && break
done
add-apt-repository -y ppa:openmw/openmw
add-apt-repository -y ppa:openmw/openmw-daily
add-apt-repository -y ppa:openmw/staging
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y --no-install-recommends "${deps[@]}" >/dev/null
apt list --installed

View file

@ -9,7 +9,7 @@ git checkout FETCH_HEAD
cd ..
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24x60' \
scripts/integration_tests.py --verbose --omw build/install/bin/openmw --workdir integration_tests_output example-suite/
scripts/integration_tests.py --omw build/install/bin/openmw --workdir integration_tests_output example-suite/
ls integration_tests_output/*.osg_stats.log | while read v; do
scripts/osg_stats.py --stats '.*' --regexp_match < "${v}"

View file

@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 49)
set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_LUA_API_REVISION 72)
set(OPENMW_LUA_API_REVISION 70)
set(OPENMW_POSTPROCESSING_API_REVISION 2)
set(OPENMW_VERSION_COMMITHASH "")
@ -860,6 +860,7 @@ if (OPENMW_OSX_DEPLOYMENT AND APPLE)
set(BU_CHMOD_BUNDLE_ITEMS ON)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})
include(BundleUtilities)
cmake_minimum_required(VERSION 3.1)
" COMPONENT Runtime)
set(ABSOLUTE_PLUGINS "")

View file

@ -179,7 +179,7 @@ namespace
generateKeys(std::back_inserter(keys), keys.size() * (100 - hitPercentage) / 100, random);
std::size_t n = 0;
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
const auto& key = keys[n++ % keys.size()];
auto result = cache.get(key.mAgentBounds, key.mTilePosition, key.mRecastMesh);

View file

@ -104,7 +104,7 @@ namespace
std::minstd_rand random;
std::vector<ESM::RefId> refIds = generateStringRefIds(state.range(0), random);
std::size_t i = 0;
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(refIds[i].serialize());
if (++i >= refIds.size())
@ -118,7 +118,7 @@ namespace
std::vector<std::string> serializedRefIds
= generateSerializedStringRefIds(state.range(0), random, [](ESM::RefId v) { return v.serialize(); });
std::size_t i = 0;
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(ESM::RefId::deserialize(serializedRefIds[i]));
if (++i >= serializedRefIds.size())
@ -131,7 +131,7 @@ namespace
std::minstd_rand random;
std::vector<ESM::RefId> refIds = generateStringRefIds(state.range(0), random);
std::size_t i = 0;
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(refIds[i].serializeText());
if (++i >= refIds.size())
@ -145,7 +145,7 @@ namespace
std::vector<std::string> serializedRefIds
= generateSerializedStringRefIds(state.range(0), random, [](ESM::RefId v) { return v.serializeText(); });
std::size_t i = 0;
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(ESM::RefId::deserializeText(serializedRefIds[i]));
if (++i >= serializedRefIds.size())
@ -158,7 +158,7 @@ namespace
std::minstd_rand random;
std::vector<ESM::RefId> refIds = generateGeneratedRefIds(random);
std::size_t i = 0;
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(refIds[i].serializeText());
if (++i >= refIds.size())
@ -172,7 +172,7 @@ namespace
std::vector<std::string> serializedRefIds
= generateSerializedGeneratedRefIds(random, [](ESM::RefId v) { return v.serializeText(); });
std::size_t i = 0;
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(ESM::RefId::deserializeText(serializedRefIds[i]));
if (++i >= serializedRefIds.size())
@ -185,7 +185,7 @@ namespace
std::minstd_rand random;
std::vector<ESM::RefId> refIds = generateIndexRefIds(random);
std::size_t i = 0;
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(refIds[i].serializeText());
if (++i >= refIds.size())
@ -199,7 +199,7 @@ namespace
std::vector<std::string> serializedRefIds
= generateSerializedIndexRefIds(random, [](ESM::RefId v) { return v.serializeText(); });
std::size_t i = 0;
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(ESM::RefId::deserializeText(serializedRefIds[i]));
if (++i >= serializedRefIds.size())
@ -212,7 +212,7 @@ namespace
std::minstd_rand random;
std::vector<ESM::RefId> refIds = generateESM3ExteriorCellRefIds(random);
std::size_t i = 0;
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(refIds[i].serializeText());
if (++i >= refIds.size())
@ -226,7 +226,7 @@ namespace
std::vector<std::string> serializedRefIds
= generateSerializedESM3ExteriorCellRefIds(random, [](ESM::RefId v) { return v.serializeText(); });
std::size_t i = 0;
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(ESM::RefId::deserializeText(serializedRefIds[i]));
if (++i >= serializedRefIds.size())

View file

@ -9,7 +9,7 @@ namespace
{
void settingsManager(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(Settings::Manager::getFloat("sky blending start", "Fog"));
}
@ -17,7 +17,7 @@ namespace
void settingsManager2(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(Settings::Manager::getFloat("near clip", "Camera"));
benchmark::DoNotOptimize(Settings::Manager::getBool("transparent postpass", "Post Processing"));
@ -26,7 +26,7 @@ namespace
void settingsManager3(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(Settings::Manager::getFloat("near clip", "Camera"));
benchmark::DoNotOptimize(Settings::Manager::getBool("transparent postpass", "Post Processing"));
@ -36,7 +36,7 @@ namespace
void localStatic(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
static float v = Settings::Manager::getFloat("sky blending start", "Fog");
benchmark::DoNotOptimize(v);
@ -45,7 +45,7 @@ namespace
void localStatic2(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
static float v1 = Settings::Manager::getFloat("near clip", "Camera");
static bool v2 = Settings::Manager::getBool("transparent postpass", "Post Processing");
@ -56,7 +56,7 @@ namespace
void localStatic3(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
static float v1 = Settings::Manager::getFloat("near clip", "Camera");
static bool v2 = Settings::Manager::getBool("transparent postpass", "Post Processing");
@ -69,7 +69,7 @@ namespace
void settingsStorage(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
float v = Settings::fog().mSkyBlendingStart.get();
benchmark::DoNotOptimize(v);
@ -78,7 +78,7 @@ namespace
void settingsStorage2(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
bool v1 = Settings::postProcessing().mTransparentPostpass.get();
float v2 = Settings::camera().mNearClip.get();
@ -89,7 +89,7 @@ namespace
void settingsStorage3(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
bool v1 = Settings::postProcessing().mTransparentPostpass.get();
float v2 = Settings::camera().mNearClip.get();
@ -102,7 +102,7 @@ namespace
void settingsStorageGet(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(Settings::get<float>("Fog", "sky blending start"));
}
@ -110,7 +110,7 @@ namespace
void settingsStorageGet2(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(Settings::get<bool>("Post Processing", "transparent postpass"));
benchmark::DoNotOptimize(Settings::get<float>("Camera", "near clip"));
@ -119,7 +119,7 @@ namespace
void settingsStorageGet3(benchmark::State& state)
{
for ([[maybe_unused]] auto _ : state)
for (auto _ : state)
{
benchmark::DoNotOptimize(Settings::get<bool>("Post Processing", "transparent postpass"));
benchmark::DoNotOptimize(Settings::get<float>("Camera", "near clip"));

View file

@ -53,6 +53,8 @@ namespace
bpo::options_description makeOptionsDescription()
{
using Fallback::FallbackMap;
bpo::options_description result;
auto addOption = result.add_options();
addOption("help", "print help message");
@ -85,8 +87,7 @@ namespace
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
"\n\twin1252 - Western European (Latin) alphabet, used by default");
addOption("fallback",
bpo::value<Fallback::FallbackMap>()->default_value(Fallback::FallbackMap(), "")->multitoken()->composing(),
addOption("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")->multitoken()->composing(),
"fallback values");
Files::ConfigurationManager::addCommonOptions(result);

View file

@ -5,9 +5,7 @@
#include <components/detournavigator/makenavmesh.hpp>
#include <components/detournavigator/navmeshdbutils.hpp>
#include <components/detournavigator/serialization.hpp>
#include <components/files/conversion.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/testing/util.hpp>
#include <BulletCollision/CollisionShapes/btBoxShape.h>
@ -374,106 +372,6 @@ namespace
}
}
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, should_write_debug_recast_mesh)
{
mRecastMeshManager.setWorldspace(mWorldspace, nullptr);
addHeightFieldPlane(mRecastMeshManager);
mSettings.mEnableWriteRecastMeshToFile = true;
const std::filesystem::path dir = TestingOpenMW::outputDirPath("DetourNavigatorAsyncNavMeshUpdaterTest");
mSettings.mRecastMeshPathPrefix = Files::pathToUnicodeString(dir) + "/";
Log(Debug::Verbose) << mSettings.mRecastMeshPathPrefix;
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(1, mSettings);
const std::map<TilePosition, ChangeType> changedTiles{ { TilePosition{ 0, 0 }, ChangeType::add } };
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
updater.wait(WaitConditionType::allJobsDone, &mListener);
EXPECT_TRUE(std::filesystem::exists(dir / "0.0.recastmesh.obj"));
}
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, should_write_debug_recast_mesh_with_revision)
{
mRecastMeshManager.setWorldspace(mWorldspace, nullptr);
addHeightFieldPlane(mRecastMeshManager);
mSettings.mEnableWriteRecastMeshToFile = true;
mSettings.mEnableRecastMeshFileNameRevision = true;
const std::filesystem::path dir = TestingOpenMW::outputDirPath("DetourNavigatorAsyncNavMeshUpdaterTest");
mSettings.mRecastMeshPathPrefix = Files::pathToUnicodeString(dir) + "/";
Log(Debug::Verbose) << mSettings.mRecastMeshPathPrefix;
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(1, mSettings);
const std::map<TilePosition, ChangeType> changedTiles{ { TilePosition{ 0, 0 }, ChangeType::add } };
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
updater.wait(WaitConditionType::allJobsDone, &mListener);
EXPECT_TRUE(std::filesystem::exists(dir / "0.0.recastmesh.1.2.obj"));
}
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, writing_recast_mesh_to_absent_file_should_not_fail_tile_generation)
{
mRecastMeshManager.setWorldspace(mWorldspace, nullptr);
addHeightFieldPlane(mRecastMeshManager);
mSettings.mEnableWriteRecastMeshToFile = true;
const std::filesystem::path dir = TestingOpenMW::outputDir() / "absent";
mSettings.mRecastMeshPathPrefix = Files::pathToUnicodeString(dir) + "/";
Log(Debug::Verbose) << mSettings.mRecastMeshPathPrefix;
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(1, mSettings);
const std::map<TilePosition, ChangeType> changedTiles{ { TilePosition{ 0, 0 }, ChangeType::add } };
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
updater.wait(WaitConditionType::allJobsDone, &mListener);
EXPECT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0u);
EXPECT_FALSE(std::filesystem::exists(dir));
}
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, should_write_debug_navmesh)
{
mRecastMeshManager.setWorldspace(mWorldspace, nullptr);
addHeightFieldPlane(mRecastMeshManager);
mSettings.mEnableWriteNavMeshToFile = true;
const std::filesystem::path dir = TestingOpenMW::outputDirPath("DetourNavigatorAsyncNavMeshUpdaterTest");
mSettings.mNavMeshPathPrefix = Files::pathToUnicodeString(dir) + "/";
Log(Debug::Verbose) << mSettings.mRecastMeshPathPrefix;
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(1, mSettings);
const std::map<TilePosition, ChangeType> changedTiles{ { TilePosition{ 0, 0 }, ChangeType::add } };
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
updater.wait(WaitConditionType::allJobsDone, &mListener);
EXPECT_TRUE(std::filesystem::exists(dir / "all_tiles_navmesh.bin"));
}
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, should_write_debug_navmesh_with_revision)
{
mRecastMeshManager.setWorldspace(mWorldspace, nullptr);
addHeightFieldPlane(mRecastMeshManager);
mSettings.mEnableWriteNavMeshToFile = true;
mSettings.mEnableNavMeshFileNameRevision = true;
const std::filesystem::path dir = TestingOpenMW::outputDirPath("DetourNavigatorAsyncNavMeshUpdaterTest");
mSettings.mNavMeshPathPrefix = Files::pathToUnicodeString(dir) + "/";
Log(Debug::Verbose) << mSettings.mRecastMeshPathPrefix;
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(1, mSettings);
const std::map<TilePosition, ChangeType> changedTiles{ { TilePosition{ 0, 0 }, ChangeType::add } };
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
updater.wait(WaitConditionType::allJobsDone, &mListener);
EXPECT_TRUE(std::filesystem::exists(dir / "all_tiles_navmesh.1.1.bin"));
}
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, writing_navmesh_to_absent_file_should_not_fail_tile_generation)
{
mRecastMeshManager.setWorldspace(mWorldspace, nullptr);
addHeightFieldPlane(mRecastMeshManager);
mSettings.mEnableWriteNavMeshToFile = true;
const std::filesystem::path dir = TestingOpenMW::outputDir() / "absent";
mSettings.mNavMeshPathPrefix = Files::pathToUnicodeString(dir) + "/";
Log(Debug::Verbose) << mSettings.mRecastMeshPathPrefix;
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(1, mSettings);
const std::map<TilePosition, ChangeType> changedTiles{ { TilePosition{ 0, 0 }, ChangeType::add } };
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
updater.wait(WaitConditionType::allJobsDone, &mListener);
EXPECT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0u);
EXPECT_FALSE(std::filesystem::exists(dir));
}
struct DetourNavigatorSpatialJobQueueTest : Test
{
const AgentBounds mAgentBounds{ CollisionShapeType::Aabb, osg::Vec3f(1, 1, 1) };

View file

@ -88,31 +88,4 @@ namespace
EXPECT_EQ(reader->getFileOffset(), sInitialOffset);
}
}
TEST_F(ESM3ReadersCacheWithContentFile, CachedSizeAndName)
{
ESM::ReadersCache readers(2);
{
readers.get(0)->openRaw(std::make_unique<std::istringstream>("123"), "closed0.omwaddon");
readers.get(1)->openRaw(std::make_unique<std::istringstream>("12345"), "closed1.omwaddon");
readers.get(2)->openRaw(std::make_unique<std::istringstream>("1234567"), "free.omwaddon");
}
auto busy = readers.get(3);
busy->openRaw(std::make_unique<std::istringstream>("123456789"), "busy.omwaddon");
EXPECT_EQ(readers.getFileSize(0), 3);
EXPECT_EQ(readers.getName(0), "closed0.omwaddon");
EXPECT_EQ(readers.getFileSize(1), 5);
EXPECT_EQ(readers.getName(1), "closed1.omwaddon");
EXPECT_EQ(readers.getFileSize(2), 7);
EXPECT_EQ(readers.getName(2), "free.omwaddon");
EXPECT_EQ(readers.getFileSize(3), 9);
EXPECT_EQ(readers.getName(3), "busy.omwaddon");
// not-yet-seen indices give zero for their size
EXPECT_EQ(readers.getFileSize(4), 0);
}
}

View file

@ -30,7 +30,7 @@ namespace
TEST(FilesGetHash, shouldClearErrors)
{
const auto fileName = outputFilePath("fileName");
const auto fileName = temporaryFilePath("fileName");
std::string content;
std::fill_n(std::back_inserter(content), 1, 'a');
std::istringstream stream(content);
@ -41,7 +41,7 @@ namespace
TEST_P(FilesGetHash, shouldReturnHashForStringStream)
{
const auto fileName = outputFilePath("fileName");
const auto fileName = temporaryFilePath("fileName");
std::string content;
std::fill_n(std::back_inserter(content), GetParam().mSize, 'a');
std::istringstream stream(content);

View file

@ -38,10 +38,10 @@ namespace
sol::state lua;
LuaUtil::InputAction::Registry registry;
LuaUtil::InputAction::Info a({ "a", LuaUtil::InputAction::Type::Boolean, "test", "a_name", "a_description",
sol::make_object(lua, false), false });
sol::make_object(lua, false) });
registry.insert(a);
LuaUtil::InputAction::Info b({ "b", LuaUtil::InputAction::Type::Boolean, "test", "b_name", "b_description",
sol::make_object(lua, false), false });
sol::make_object(lua, false) });
registry.insert(b);
LuaUtil::Callback bindA({ lua.load("return function() return true end")(), sol::table(lua, sol::create) });
LuaUtil::Callback bindBToA(

View file

@ -2,7 +2,6 @@
#include <components/misc/strings/conversion.hpp>
#include <components/settings/parser.hpp>
#include <components/settings/values.hpp>
#include <components/testing/util.hpp>
#include <gtest/gtest.h>
@ -25,9 +24,5 @@ int main(int argc, char** argv)
Settings::StaticValues::init();
testing::InitGoogleTest(&argc, argv);
const int result = RUN_ALL_TESTS();
if (result == 0)
std::filesystem::remove_all(TestingOpenMW::outputDir());
return result;
return RUN_ALL_TESTS();
}

View file

@ -51,7 +51,7 @@ namespace Misc
const std::pair<osg::Quat, osg::Vec3f> eulerAnglesXZQuat[] = {
{
osg::Quat(1, 0, 0, 0),
osg::Vec3f(0, 0, osg::PIf),
osg::Vec3f(0, 0, osg::PI),
},
{
osg::Quat(0, 1, 0, 0),
@ -59,7 +59,7 @@ namespace Misc
},
{
osg::Quat(0, 0, 1, 0),
osg::Vec3f(0, 0, osg::PIf),
osg::Vec3f(0, 0, osg::PI),
},
{
osg::Quat(0, 0, 0, 1),
@ -128,15 +128,15 @@ namespace Misc
const std::pair<osg::Quat, osg::Vec3f> eulerAnglesZYXQuat[] = {
{
osg::Quat(1, 0, 0, 0),
osg::Vec3f(osg::PIf, 0, 0),
osg::Vec3f(osg::PI, 0, 0),
},
{
osg::Quat(0, 1, 0, 0),
osg::Vec3f(osg::PIf, 0, osg::PIf),
osg::Vec3f(osg::PI, 0, osg::PI),
},
{
osg::Quat(0, 0, 1, 0),
osg::Vec3f(0, 0, osg::PIf),
osg::Vec3f(0, 0, osg::PI),
},
{
osg::Quat(0, 0, 0, 1),

View file

@ -16,7 +16,7 @@ namespace
ShaderManager mManager;
ShaderManager::DefineMap mDefines;
ShaderManagerTest() { mManager.setShaderPath(TestingOpenMW::outputDir()); }
ShaderManagerTest() { mManager.setShaderPath("tests_output"); }
template <class F>
void withShaderFile(const std::string& content, F&& f)

View file

@ -8,7 +8,6 @@
#include <QList>
#include <QMessageBox>
#include <QPair>
#include <QProgressDialog>
#include <QPushButton>
#include <algorithm>
@ -352,17 +351,9 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
if (!resourcesVfs.isEmpty())
directories.insert(0, { resourcesVfs });
QIcon containsDataIcon(":/images/openmw-plugin.png");
QProgressDialog progressBar("Adding data directories", {}, 0, directories.count(), this);
progressBar.setWindowModality(Qt::WindowModal);
progressBar.setValue(0);
std::unordered_set<QString> visitedDirectories;
for (const Config::SettingValue& currentDir : directories)
{
progressBar.setValue(progressBar.value() + 1);
if (!visitedDirectories.insert(currentDir.value).second)
continue;
@ -411,7 +402,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
// Add a "data file" icon if the directory contains a content file
if (mSelector->containsDataFiles(currentDir.value))
{
item->setIcon(containsDataIcon);
item->setIcon(QIcon(":/images/openmw-plugin.png"));
tooltip << tr("Contains content file(s)");
}
@ -774,7 +765,7 @@ void Launcher::DataFilesPage::addSubdirectories(bool append)
return;
QString rootPath = QFileDialog::getExistingDirectory(
this, tr("Select Directory"), {}, QFileDialog::ShowDirsOnly | QFileDialog::Option::ReadOnly);
this, tr("Select Directory"), QDir::homePath(), QFileDialog::ShowDirsOnly | QFileDialog::Option::ReadOnly);
if (rootPath.isEmpty())
return;

View file

@ -1,16 +1,20 @@
set(NAVMESHTOOL_LIB
set(NAVMESHTOOL
worldspacedata.cpp
navmesh.cpp
main.cpp
)
source_group(apps\\navmeshtool FILES ${NAVMESHTOOL})
add_library(openmw-navmeshtool-lib STATIC
${NAVMESHTOOL}
)
source_group(apps\\navmeshtool FILES ${NAVMESHTOOL_LIB} main.cpp)
add_library(openmw-navmeshtool-lib STATIC ${NAVMESHTOOL_LIB})
if (ANDROID)
add_library(openmw-navmeshtool SHARED main.cpp)
add_library(openmw-navmeshtool SHARED
main.cpp
)
else()
openmw_add_executable(openmw-navmeshtool main.cpp)
openmw_add_executable(openmw-navmeshtool ${NAVMESHTOOL})
endif()
target_link_libraries(openmw-navmeshtool openmw-navmeshtool-lib)

View file

@ -62,6 +62,8 @@ namespace NavMeshTool
bpo::options_description makeOptionsDescription()
{
using Fallback::FallbackMap;
bpo::options_description result;
auto addOption = result.add_options();
addOption("help", "print help message");
@ -223,8 +225,7 @@ namespace NavMeshTool
Resource::SceneManager sceneManager(&vfs, &imageManager, &nifFileManager, &bgsmFileManager, expiryDelay);
Resource::BulletShapeManager bulletShapeManager(&vfs, &sceneManager, &nifFileManager, expiryDelay);
DetourNavigator::RecastGlobalAllocator::init();
DetourNavigator::Settings navigatorSettings
= DetourNavigator::makeSettingsFromSettingsManager(Debug::getRecastMaxLogLevel());
DetourNavigator::Settings navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager();
navigatorSettings.mRecast.mSwimHeightScale
= EsmLoader::getGameSetting(esmData.mGameSettings, "fSwimHeightScale").getFloat();

View file

@ -38,6 +38,8 @@
#include "view/doc/viewmanager.hpp"
using namespace Fallback;
CS::Editor::Editor(int argc, char** argv)
: mConfigVariables(readConfiguration())
, mSettingsState(mCfgMgr)
@ -122,10 +124,7 @@ boost::program_options::variables_map CS::Editor::readConfiguration()
->default_value(std::vector<std::string>(), "fallback-archive")
->multitoken());
addOption("fallback",
boost::program_options::value<Fallback::FallbackMap>()
->default_value(Fallback::FallbackMap(), "")
->multitoken()
->composing(),
boost::program_options::value<FallbackMap>()->default_value(FallbackMap(), "")->multitoken()->composing(),
"fallback values");
Files::ConfigurationManager::addCommonOptions(desc);
@ -142,7 +141,7 @@ std::pair<Files::PathContainer, std::vector<std::string>> CS::Editor::readConfig
{
boost::program_options::variables_map& variables = mConfigVariables;
Fallback::Map::init(variables["fallback"].as<Fallback::FallbackMap>().mMap);
Fallback::Map::init(variables["fallback"].as<FallbackMap>().mMap);
mEncodingName = variables["encoding"].as<std::string>();
mDocumentManager.setEncoding(ToUTF8::calculateEncoding(mEncodingName));

View file

@ -1,5 +1,4 @@
#include <components/debug/debugging.hpp>
#include <components/testing/util.hpp>
#include <gtest/gtest.h>
@ -8,9 +7,5 @@ int main(int argc, char* argv[])
Log::sMinDebugLevel = Debug::getDebugLevel();
testing::InitGoogleTest(&argc, argv);
const int result = RUN_ALL_TESTS();
if (result == 0)
std::filesystem::remove_all(TestingOpenMW::outputDir());
return result;
return RUN_ALL_TESTS();
}

View file

@ -373,15 +373,11 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
, mScriptConsoleMode(false)
, mActivationDistanceOverride(-1)
, mGrab(true)
, mExportFonts(false)
, mRandomSeed(0)
, mNewGame(false)
, mCfgMgr(configurationManager)
, mGlMaxTextureImageUnits(0)
{
#if SDL_VERSION_ATLEAST(2, 24, 0)
SDL_SetHint(SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH, "1");
#endif
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0"); // We use only gamepads
Uint32 flags
@ -811,7 +807,7 @@ void OMW::Engine::prepareEngine()
rootNode->addChild(guiRoot);
mWindowManager = std::make_unique<MWGui::WindowManager>(mWindow, mViewer, guiRoot, mResourceSystem.get(),
mWorkQueue.get(), mCfgMgr.getLogPath(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts,
mWorkQueue.get(), mCfgMgr.getLogPath(), mScriptConsoleMode, mTranslationDataStorage, mEncoding,
Version::getOpenmwVersionDescription(), shadersSupported, mCfgMgr);
mEnvironment.setWindowManager(*mWindowManager);
@ -851,7 +847,7 @@ void OMW::Engine::prepareEngine()
}
listener->loadingOff();
mWorld->init(mMaxRecastLogLevel, mViewer, std::move(rootNode), mWorkQueue.get(), *mUnrefQueue);
mWorld->init(mViewer, std::move(rootNode), mWorkQueue.get(), *mUnrefQueue);
mEnvironment.setWorldScene(mWorld->getWorldScene());
mWorld->setupPlayer();
mWorld->setRandomSeed(mRandomSeed);
@ -1113,11 +1109,6 @@ void OMW::Engine::setWarningsMode(int mode)
mWarningsMode = mode;
}
void OMW::Engine::enableFontExport(bool exportFonts)
{
mExportFonts = exportFonts;
}
void OMW::Engine::setSaveGameFile(const std::filesystem::path& savegame)
{
mSaveGameFile = savegame;

View file

@ -4,7 +4,6 @@
#include <filesystem>
#include <components/compiler/extensions.hpp>
#include <components/debug/debuglog.hpp>
#include <components/esm/refid.hpp>
#include <components/files/collections.hpp>
#include <components/settings/settings.hpp>
@ -172,9 +171,7 @@ namespace OMW
// Grab mouse?
bool mGrab;
bool mExportFonts;
unsigned int mRandomSeed;
Debug::Level mMaxRecastLogLevel = Debug::Error;
Compiler::Extensions mExtensions;
std::unique_ptr<Compiler::Context> mScriptContext;
@ -183,9 +180,6 @@ namespace OMW
Translation::Storage mTranslationDataStorage;
bool mNewGame;
Files::ConfigurationManager& mCfgMgr;
int mGlMaxTextureImageUnits;
// not implemented
Engine(const Engine&);
Engine& operator=(const Engine&);
@ -257,14 +251,14 @@ namespace OMW
void setWarningsMode(int mode);
void enableFontExport(bool exportFonts);
/// Set the save game file to load after initialising the engine.
void setSaveGameFile(const std::filesystem::path& savegame);
void setRandomSeed(unsigned int seed);
void setRecastMaxLogLevel(Debug::Level value) { mMaxRecastLogLevel = value; }
private:
Files::ConfigurationManager& mCfgMgr;
int mGlMaxTextureImageUnits;
};
}

View file

@ -28,6 +28,8 @@ extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x
#include <unistd.h>
#endif
using namespace Fallback;
/**
* \brief Parses application command line and calls \ref Cfg::ConfigurationManager
* to parse configuration files.
@ -150,10 +152,9 @@ bool parseOptions(int argc, char** argv, OMW::Engine& engine, Files::Configurati
engine.setSaveGameFile(variables["load-savegame"].as<Files::MaybeQuotedPath>().u8string());
// other settings
Fallback::Map::init(variables["fallback"].as<Fallback::FallbackMap>().mMap);
Fallback::Map::init(variables["fallback"].as<FallbackMap>().mMap);
engine.setSoundUsage(!variables["no-sound"].as<bool>());
engine.setActivationDistanceOverride(variables["activate-dist"].as<int>());
engine.enableFontExport(variables["export-fonts"].as<bool>());
engine.setRandomSeed(variables["random-seed"].as<unsigned int>());
return true;
@ -219,8 +220,6 @@ int runApplication(int argc, char* argv[])
Files::ConfigurationManager cfgMgr;
std::unique_ptr<OMW::Engine> engine = std::make_unique<OMW::Engine>(cfgMgr);
engine->setRecastMaxLogLevel(Debug::getRecastMaxLogLevel());
if (parseOptions(argc, argv, *engine, cfgMgr))
{
if (!Misc::checkRequiredOSGPluginsArePresent())

View file

@ -200,7 +200,7 @@ namespace MWBase
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
/// references that are currently not in the scene should be ignored.
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, std::string_view groupName) = 0;
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0;
virtual bool checkScriptedAnimationPlaying(const MWWorld::Ptr& ptr) const = 0;

View file

@ -363,7 +363,7 @@ namespace MWBase
void windowVisibilityChange(bool visible) override = 0;
void windowResized(int x, int y) override = 0;
void windowClosed() override = 0;
virtual bool isWindowVisible() const = 0;
virtual bool isWindowVisible() = 0;
virtual void watchActor(const MWWorld::Ptr& ptr) = 0;
virtual MWWorld::Ptr getWatchedActor() const = 0;

View file

@ -237,12 +237,7 @@ namespace MWClass
bool Container::hasToolTip(const MWWorld::ConstPtr& ptr) const
{
if (const MWWorld::CustomData* data = ptr.getRefData().getCustomData())
{
if (!canBeHarvested(ptr))
return true;
const MWWorld::ContainerStore& store = data->asContainerCustomData().mStore;
return !store.isResolved() || store.hasVisibleItems();
}
return !canBeHarvested(ptr) || data->asContainerCustomData().mStore.hasVisibleItems();
return true;
}

View file

@ -1343,13 +1343,12 @@ namespace MWGui
return codePoint == '\r';
}
// Normal no-break space (0x00A0) is ignored here
// because Morrowind compatibility requires us to render its glyph
static bool ucsSpace(int codePoint)
{
switch (codePoint)
{
case 0x0020: // SPACE
case 0x00A0: // NO-BREAK SPACE
case 0x1680: // OGHAM SPACE MARK
case 0x180E: // MONGOLIAN VOWEL SEPARATOR
case 0x2000: // EN QUAD
@ -1374,14 +1373,12 @@ namespace MWGui
}
}
// No-break spaces (0x00A0, 0x202F, 0xFEFF - normal, narrow, zero width)
// are ignored here for obvious reasons
// Figure space (0x2007) is not a breaking space either
static bool ucsBreakingSpace(int codePoint)
{
switch (codePoint)
{
case 0x0020: // SPACE
// case 0x00A0: // NO-BREAK SPACE
case 0x1680: // OGHAM SPACE MARK
case 0x180E: // MONGOLIAN VOWEL SEPARATOR
case 0x2000: // EN QUAD
@ -1391,12 +1388,15 @@ namespace MWGui
case 0x2004: // THREE-PER-EM SPACE
case 0x2005: // FOUR-PER-EM SPACE
case 0x2006: // SIX-PER-EM SPACE
case 0x2007: // FIGURE SPACE
case 0x2008: // PUNCTUATION SPACE
case 0x2009: // THIN SPACE
case 0x200A: // HAIR SPACE
case 0x200B: // ZERO WIDTH SPACE
case 0x202F: // NARROW NO-BREAK SPACE
case 0x205F: // MEDIUM MATHEMATICAL SPACE
case 0x3000: // IDEOGRAPHIC SPACE
// case 0xFEFF: // ZERO WIDTH NO-BREAK SPACE
return true;
default:
return false;

View file

@ -666,8 +666,7 @@ namespace MWGui
else if (scrollbar)
{
mHistory->setSize(MyGUI::IntSize(mHistory->getWidth(), book->getSize().second));
// Scroll range should be >= 2 to enable scrolling and prevent a crash
size_t range = std::max(book->getSize().second - viewHeight, size_t(2));
size_t range = book->getSize().second - viewHeight;
mScrollBar->setScrollRange(range);
mScrollBar->setScrollPosition(range - 1);
mScrollBar->setTrackSize(

View file

@ -29,26 +29,11 @@ namespace MWGui
{
Misc::FrameRateLimiter frameRateLimiter
= Misc::makeFrameRateLimiter(MWBase::Environment::get().getFrameRateLimit());
const MWBase::WindowManager& windowManager = *MWBase::Environment::get().getWindowManager();
bool paused = false;
while (mRunning)
{
if (windowManager.isWindowVisible())
{
if (paused)
{
mVideo->resume();
paused = false;
}
// If finished playing, start again
if (!mVideo->update())
mVideo->playVideo("video\\menu_background.bik");
}
else if (!paused)
{
paused = true;
mVideo->pause();
}
// If finished playing, start again
if (!mVideo->update())
mVideo->playVideo("video\\menu_background.bik");
frameRateLimiter.limit();
}
}

View file

@ -146,7 +146,7 @@ namespace MWGui
WindowManager::WindowManager(SDL_Window* window, osgViewer::Viewer* viewer, osg::Group* guiRoot,
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, const std::filesystem::path& logpath,
bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding,
bool exportFonts, const std::string& versionDescription, bool useShaders, Files::ConfigurationManager& cfgMgr)
const std::string& versionDescription, bool useShaders, Files::ConfigurationManager& cfgMgr)
: mOldUpdateMask(0)
, mOldCullMask(0)
, mStore(nullptr)
@ -215,8 +215,7 @@ namespace MWGui
MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag);
// Load fonts
mFontLoader
= std::make_unique<Gui::FontLoader>(encoding, resourceSystem->getVFS(), mScalingFactor, exportFonts);
mFontLoader = std::make_unique<Gui::FontLoader>(encoding, resourceSystem->getVFS(), mScalingFactor);
// Register own widgets with MyGUI
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSkill>("Widget");
@ -730,9 +729,6 @@ namespace MWGui
return;
}
if (mGuiModes.empty())
return;
GuiModeState& state = mGuiModeStates[mGuiModes.back()];
for (const auto& window : state.mWindows)
{
@ -1218,7 +1214,7 @@ namespace MWGui
// TODO: check if any windows are now off-screen and move them back if so
}
bool WindowManager::isWindowVisible() const
bool WindowManager::isWindowVisible()
{
return mWindowVisible;
}

View file

@ -128,7 +128,7 @@ namespace MWGui
WindowManager(SDL_Window* window, osgViewer::Viewer* viewer, osg::Group* guiRoot,
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
const std::filesystem::path& logpath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage,
ToUTF8::FromType encoding, bool exportFonts, const std::string& versionDescription, bool useShaders,
ToUTF8::FromType encoding, const std::string& versionDescription, bool useShaders,
Files::ConfigurationManager& cfgMgr);
virtual ~WindowManager();
@ -290,7 +290,7 @@ namespace MWGui
void windowVisibilityChange(bool visible) override;
void windowResized(int x, int y) override;
void windowClosed() override;
bool isWindowVisible() const override;
bool isWindowVisible() override;
void watchActor(const MWWorld::Ptr& ptr) override;
MWWorld::Ptr getWatchedActor() const override;

View file

@ -148,7 +148,7 @@ namespace MWLua
};
}
sol::table readOnlyApi = LuaUtil::makeReadOnly(api);
return context.setTypePackage(readOnlyApi, "openmw_core");
sol::table readOnly = LuaUtil::makeReadOnly(api);
return context.setTypePackage(readOnly, "openmw_core");
}
}

View file

@ -38,116 +38,94 @@ namespace MWLua
sol::table initInputPackage(const Context& context)
{
sol::object cached = context.getTypePackage("openmw_input");
if (cached != sol::nil)
return cached;
sol::state_view lua = context.sol();
{
if (lua["openmw_input"] != sol::nil)
return lua["openmw_input"];
}
context.cachePackage("openmw_input_keyevent", [&lua]() {
sol::usertype<SDL_Keysym> keyEvent = lua.new_usertype<SDL_Keysym>("KeyEvent");
keyEvent["symbol"] = sol::readonly_property([](const SDL_Keysym& e) {
if (e.sym > 0 && e.sym <= 255)
return std::string(1, static_cast<char>(e.sym));
else
return std::string();
});
keyEvent["code"] = sol::readonly_property([](const SDL_Keysym& e) -> int { return e.scancode; });
keyEvent["withShift"]
= sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_SHIFT; });
keyEvent["withCtrl"]
= sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_CTRL; });
keyEvent["withAlt"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_ALT; });
keyEvent["withSuper"]
= sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_GUI; });
return sol::table(lua, sol::create);
sol::usertype<SDL_Keysym> keyEvent = lua.new_usertype<SDL_Keysym>("KeyEvent");
keyEvent["symbol"] = sol::readonly_property([](const SDL_Keysym& e) {
if (e.sym > 0 && e.sym <= 255)
return std::string(1, static_cast<char>(e.sym));
else
return std::string();
});
keyEvent["code"] = sol::readonly_property([](const SDL_Keysym& e) -> int { return e.scancode; });
keyEvent["withShift"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_SHIFT; });
keyEvent["withCtrl"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_CTRL; });
keyEvent["withAlt"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_ALT; });
keyEvent["withSuper"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_GUI; });
context.cachePackage("openmw_input_touchpadevent", [&lua]() {
auto touchpadEvent = lua.new_usertype<SDLUtil::TouchEvent>("TouchpadEvent");
touchpadEvent["device"]
= sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mDevice; });
touchpadEvent["finger"]
= sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mFinger; });
touchpadEvent["position"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> osg::Vec2f {
return { e.mX, e.mY };
});
touchpadEvent["pressure"]
= sol::readonly_property([](const SDLUtil::TouchEvent& e) -> float { return e.mPressure; });
return sol::table(lua, sol::create);
auto touchpadEvent = lua.new_usertype<SDLUtil::TouchEvent>("TouchpadEvent");
touchpadEvent["device"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mDevice; });
touchpadEvent["finger"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> int { return e.mFinger; });
touchpadEvent["position"] = sol::readonly_property([](const SDLUtil::TouchEvent& e) -> osg::Vec2f {
return { e.mX, e.mY };
});
touchpadEvent["pressure"]
= sol::readonly_property([](const SDLUtil::TouchEvent& e) -> float { return e.mPressure; });
context.cachePackage("openmw_input_inputactions", [&lua]() {
auto inputActions = lua.new_usertype<LuaUtil::InputAction::Registry>("InputActions");
inputActions[sol::meta_function::index]
= [](LuaUtil::InputAction::Registry& registry, std::string_view key) { return registry[key]; };
{
auto pairs = [](LuaUtil::InputAction::Registry& registry) {
auto next = [](LuaUtil::InputAction::Registry& registry, std::string_view key)
-> sol::optional<std::tuple<std::string, LuaUtil::InputAction::Info>> {
std::optional<std::string> nextKey(registry.nextKey(key));
if (!nextKey.has_value())
return sol::nullopt;
else
return std::make_tuple(*nextKey, registry[*nextKey].value());
};
return std::make_tuple(next, registry, registry.firstKey());
auto inputActions = lua.new_usertype<LuaUtil::InputAction::Registry>("InputActions");
inputActions[sol::meta_function::index]
= [](LuaUtil::InputAction::Registry& registry, std::string_view key) { return registry[key]; };
{
auto pairs = [](LuaUtil::InputAction::Registry& registry) {
auto next
= [](LuaUtil::InputAction::Registry& registry,
std::string_view key) -> sol::optional<std::tuple<std::string, LuaUtil::InputAction::Info>> {
std::optional<std::string> nextKey(registry.nextKey(key));
if (!nextKey.has_value())
return sol::nullopt;
else
return std::make_tuple(*nextKey, registry[*nextKey].value());
};
inputActions[sol::meta_function::pairs] = pairs;
}
return sol::table(lua, sol::create);
});
return std::make_tuple(next, registry, registry.firstKey());
};
inputActions[sol::meta_function::pairs] = pairs;
}
context.cachePackage("openmw_input_actioninfo", [&lua]() {
auto actionInfo = lua.new_usertype<LuaUtil::InputAction::Info>("ActionInfo");
actionInfo["key"] = sol::readonly_property(
[](const LuaUtil::InputAction::Info& info) -> std::string_view { return info.mKey; });
actionInfo["name"] = sol::readonly_property(
[](const LuaUtil::InputAction::Info& info) -> std::string_view { return info.mName; });
actionInfo["description"] = sol::readonly_property(
[](const LuaUtil::InputAction::Info& info) -> std::string_view { return info.mDescription; });
actionInfo["l10n"] = sol::readonly_property(
[](const LuaUtil::InputAction::Info& info) -> std::string_view { return info.mL10n; });
actionInfo["type"]
= sol::readonly_property([](const LuaUtil::InputAction::Info& info) { return info.mType; });
actionInfo["defaultValue"]
= sol::readonly_property([](const LuaUtil::InputAction::Info& info) { return info.mDefaultValue; });
return sol::table(lua, sol::create);
});
auto actionInfo = lua.new_usertype<LuaUtil::InputAction::Info>("ActionInfo");
actionInfo["key"] = sol::readonly_property(
[](const LuaUtil::InputAction::Info& info) -> std::string_view { return info.mKey; });
actionInfo["name"] = sol::readonly_property(
[](const LuaUtil::InputAction::Info& info) -> std::string_view { return info.mName; });
actionInfo["description"] = sol::readonly_property(
[](const LuaUtil::InputAction::Info& info) -> std::string_view { return info.mDescription; });
actionInfo["l10n"] = sol::readonly_property(
[](const LuaUtil::InputAction::Info& info) -> std::string_view { return info.mL10n; });
actionInfo["type"] = sol::readonly_property([](const LuaUtil::InputAction::Info& info) { return info.mType; });
actionInfo["defaultValue"]
= sol::readonly_property([](const LuaUtil::InputAction::Info& info) { return info.mDefaultValue; });
context.cachePackage("openmw_input_inputtriggers", [&lua]() {
auto inputTriggers = lua.new_usertype<LuaUtil::InputTrigger::Registry>("InputTriggers");
inputTriggers[sol::meta_function::index]
= [](LuaUtil::InputTrigger::Registry& registry, std::string_view key) { return registry[key]; };
{
auto pairs = [](LuaUtil::InputTrigger::Registry& registry) {
auto next = [](LuaUtil::InputTrigger::Registry& registry, std::string_view key)
-> sol::optional<std::tuple<std::string, LuaUtil::InputTrigger::Info>> {
std::optional<std::string> nextKey(registry.nextKey(key));
if (!nextKey.has_value())
return sol::nullopt;
else
return std::make_tuple(*nextKey, registry[*nextKey].value());
};
return std::make_tuple(next, registry, registry.firstKey());
auto inputTriggers = lua.new_usertype<LuaUtil::InputTrigger::Registry>("InputTriggers");
inputTriggers[sol::meta_function::index]
= [](LuaUtil::InputTrigger::Registry& registry, std::string_view key) { return registry[key]; };
{
auto pairs = [](LuaUtil::InputTrigger::Registry& registry) {
auto next
= [](LuaUtil::InputTrigger::Registry& registry,
std::string_view key) -> sol::optional<std::tuple<std::string, LuaUtil::InputTrigger::Info>> {
std::optional<std::string> nextKey(registry.nextKey(key));
if (!nextKey.has_value())
return sol::nullopt;
else
return std::make_tuple(*nextKey, registry[*nextKey].value());
};
inputTriggers[sol::meta_function::pairs] = pairs;
}
return sol::table(lua, sol::create);
});
return std::make_tuple(next, registry, registry.firstKey());
};
inputTriggers[sol::meta_function::pairs] = pairs;
}
context.cachePackage("openmw_input_triggerinfo", [&lua]() {
auto triggerInfo = lua.new_usertype<LuaUtil::InputTrigger::Info>("TriggerInfo");
triggerInfo["key"] = sol::readonly_property(
[](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mKey; });
triggerInfo["name"] = sol::readonly_property(
[](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mName; });
triggerInfo["description"] = sol::readonly_property(
[](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mDescription; });
triggerInfo["l10n"] = sol::readonly_property(
[](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mL10n; });
return sol::table(lua, sol::create);
});
auto triggerInfo = lua.new_usertype<LuaUtil::InputTrigger::Info>("TriggerInfo");
triggerInfo["key"] = sol::readonly_property(
[](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mKey; });
triggerInfo["name"] = sol::readonly_property(
[](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mName; });
triggerInfo["description"] = sol::readonly_property(
[](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mDescription; });
triggerInfo["l10n"] = sol::readonly_property(
[](const LuaUtil::InputTrigger::Info& info) -> std::string_view { return info.mL10n; });
MWBase::InputManager* input = MWBase::Environment::get().getInputManager();
sol::table api(lua, sol::create);
@ -161,18 +139,16 @@ namespace MWLua
}));
api["actions"] = std::ref(context.mLuaManager->inputActions());
api["registerAction"]
= [manager = context.mLuaManager, persistent = context.mType == Context::Menu](sol::table options) {
LuaUtil::InputAction::Info parsedOptions;
parsedOptions.mKey = options["key"].get<std::string_view>();
parsedOptions.mType = options["type"].get<LuaUtil::InputAction::Type>();
parsedOptions.mL10n = options["l10n"].get<std::string_view>();
parsedOptions.mName = options["name"].get<std::string_view>();
parsedOptions.mDescription = options["description"].get<std::string_view>();
parsedOptions.mDefaultValue = options["defaultValue"].get<sol::main_object>();
parsedOptions.mPersistent = persistent;
manager->inputActions().insert(std::move(parsedOptions));
};
api["registerAction"] = [manager = context.mLuaManager](sol::table options) {
LuaUtil::InputAction::Info parsedOptions;
parsedOptions.mKey = options["key"].get<std::string_view>();
parsedOptions.mType = options["type"].get<LuaUtil::InputAction::Type>();
parsedOptions.mL10n = options["l10n"].get<std::string_view>();
parsedOptions.mName = options["name"].get<std::string_view>();
parsedOptions.mDescription = options["description"].get<std::string_view>();
parsedOptions.mDefaultValue = options["defaultValue"].get<sol::main_object>();
manager->inputActions().insert(std::move(parsedOptions));
};
api["bindAction"] = [manager = context.mLuaManager](
std::string_view key, const sol::table& callback, sol::table dependencies) {
std::vector<std::string_view> parsedDependencies;
@ -202,16 +178,14 @@ namespace MWLua
};
api["triggers"] = std::ref(context.mLuaManager->inputTriggers());
api["registerTrigger"]
= [manager = context.mLuaManager, persistent = context.mType == Context::Menu](sol::table options) {
LuaUtil::InputTrigger::Info parsedOptions;
parsedOptions.mKey = options["key"].get<std::string_view>();
parsedOptions.mL10n = options["l10n"].get<std::string_view>();
parsedOptions.mName = options["name"].get<std::string_view>();
parsedOptions.mDescription = options["description"].get<std::string_view>();
parsedOptions.mPersistent = persistent;
manager->inputTriggers().insert(std::move(parsedOptions));
};
api["registerTrigger"] = [manager = context.mLuaManager](sol::table options) {
LuaUtil::InputTrigger::Info parsedOptions;
parsedOptions.mKey = options["key"].get<std::string_view>();
parsedOptions.mL10n = options["l10n"].get<std::string_view>();
parsedOptions.mName = options["name"].get<std::string_view>();
parsedOptions.mDescription = options["description"].get<std::string_view>();
manager->inputTriggers().insert(std::move(parsedOptions));
};
api["registerTriggerHandler"]
= [manager = context.mLuaManager](std::string_view key, const sol::table& callback) {
manager->inputTriggers().registerHandler(key, LuaUtil::Callback::fromLua(callback));
@ -471,8 +445,8 @@ namespace MWLua
{ "Tab", SDL_SCANCODE_TAB },
}));
sol::table readOnlyApi = LuaUtil::makeReadOnly(api);
return context.setTypePackage(readOnlyApi, "openmw_input");
lua["openmw_input"] = LuaUtil::makeReadOnly(api);
return lua["openmw_input"];
}
}

View file

@ -71,8 +71,7 @@ namespace MWLua
{
SelfObject* obj = mObject.asSelfObject();
addStatUpdateAction(context.mLuaManager, *obj);
obj->mStatsCache[SelfObject::CachedStat{ &ItemData::setValue, std::monostate{}, prop }]
= sol::main_object(value);
obj->mStatsCache[SelfObject::CachedStat{ &ItemData::setValue, std::monostate{}, prop }] = value;
}
else
throw std::runtime_error("Only global or self scripts can set the value");

View file

@ -54,7 +54,7 @@ namespace MWLua
{
}
MWBase::LuaManager::ActorControls mControls;
std::map<CachedStat, sol::main_object> mStatsCache;
std::map<CachedStat, sol::object> mStatsCache;
bool mIsActive;
};

View file

@ -654,8 +654,8 @@ namespace MWLua
MWBase::Environment::get().getL10nManager()->dropCache();
mUiResourceManager.clear();
mLua.dropScriptCache();
mInputActions.clear(true);
mInputTriggers.clear(true);
mInputActions.clear();
mInputTriggers.clear();
initConfiguration();
ESM::LuaScripts globalData;

View file

@ -1061,7 +1061,7 @@ namespace MWLua
};
// types.Actor.activeEffects(o):removeEffect(id, ?arg)
activeEffectsT["remove"] = [getEffectKey, context](const ActorActiveEffects& effects, std::string_view idStr,
activeEffectsT["remove"] = [getEffectKey](const ActorActiveEffects& effects, std::string_view idStr,
sol::optional<std::string_view> argStr) {
if (!effects.isActor())
return;
@ -1071,14 +1071,12 @@ namespace MWLua
MWMechanics::EffectKey key = getEffectKey(idStr, argStr);
context.mLuaManager->addAction([key, effects]() {
// Note that, although this is member method of ActorActiveEffects and we are removing an effect (not a
// spell), we still need to use the active spells store to purge this effect from active spells.
const auto& ptr = effects.mActor.ptr();
// Note that, although this is member method of ActorActiveEffects and we are removing an effect (not a
// spell), we still need to use the active spells store to purge this effect from active spells.
const auto& ptr = effects.mActor.ptr();
auto& activeSpells = ptr.getClass().getCreatureStats(ptr).getActiveSpells();
activeSpells.purgeEffect(ptr, key.mId, key.mArg);
});
auto& activeSpells = ptr.getClass().getCreatureStats(ptr).getActiveSpells();
activeSpells.purgeEffect(ptr, key.mId, key.mArg);
};
// types.Actor.activeEffects(o):set(value, id, ?arg)

View file

@ -213,7 +213,6 @@ namespace MWLua
{ "NavMeshNotFound", DetourNavigator::Status::NavMeshNotFound },
{ "StartPolygonNotFound", DetourNavigator::Status::StartPolygonNotFound },
{ "EndPolygonNotFound", DetourNavigator::Status::EndPolygonNotFound },
{ "TargetPolygonNotFound", DetourNavigator::Status::TargetPolygonNotFound },
{ "MoveAlongSurfaceFailed", DetourNavigator::Status::MoveAlongSurfaceFailed },
{ "FindPathOverPolygonsFailed", DetourNavigator::Status::FindPathOverPolygonsFailed },
{ "InitNavMeshQueryFailed", DetourNavigator::Status::InitNavMeshQueryFailed },

View file

@ -123,8 +123,7 @@ namespace MWLua
SelfObject* obj = mObject.asSelfObject();
addStatUpdateAction(context.mLuaManager, *obj);
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, attributeId, "skillIncreasesForAttribute" }]
= sol::main_object(value);
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, attributeId, "skillIncreasesForAttribute" }] = value;
}
};
@ -160,7 +159,7 @@ namespace MWLua
SelfObject* obj = mObject.asSelfObject();
addStatUpdateAction(context.mLuaManager, *obj);
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, specialization, "skillIncreasesForSpecialization" }]
= sol::main_object(value);
= value;
}
};
@ -184,8 +183,7 @@ namespace MWLua
{
SelfObject* obj = mObject.asSelfObject();
addStatUpdateAction(context.mLuaManager, *obj);
obj->mStatsCache[SelfObject::CachedStat{ &setCreatureValue, std::monostate{}, "current" }]
= sol::main_object(value);
obj->mStatsCache[SelfObject::CachedStat{ &setCreatureValue, std::monostate{}, "current" }] = value;
}
sol::object getProgress(const Context& context) const
@ -206,8 +204,7 @@ namespace MWLua
SelfObject* obj = mObject.asSelfObject();
addStatUpdateAction(context.mLuaManager, *obj);
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, std::monostate{}, "progress" }]
= sol::main_object(value);
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, std::monostate{}, "progress" }] = value;
}
SkillIncreasesForAttributeStats getSkillIncreasesForAttributeStats() const
@ -261,7 +258,7 @@ namespace MWLua
{
SelfObject* obj = mObject.asSelfObject();
addStatUpdateAction(context.mLuaManager, *obj);
obj->mStatsCache[SelfObject::CachedStat{ &DynamicStat::setValue, mIndex, prop }] = sol::main_object(value);
obj->mStatsCache[SelfObject::CachedStat{ &DynamicStat::setValue, mIndex, prop }] = value;
}
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
@ -321,7 +318,7 @@ namespace MWLua
{
SelfObject* obj = mObject.asSelfObject();
addStatUpdateAction(context.mLuaManager, *obj);
obj->mStatsCache[SelfObject::CachedStat{ &AttributeStat::setValue, mId, prop }] = sol::main_object(value);
obj->mStatsCache[SelfObject::CachedStat{ &AttributeStat::setValue, mId, prop }] = value;
}
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
@ -405,7 +402,7 @@ namespace MWLua
{
SelfObject* obj = mObject.asSelfObject();
addStatUpdateAction(context.mLuaManager, *obj);
obj->mStatsCache[SelfObject::CachedStat{ &SkillStat::setValue, mId, prop }] = sol::main_object(value);
obj->mStatsCache[SelfObject::CachedStat{ &SkillStat::setValue, mId, prop }] = value;
}
static void setValue(Index index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
@ -468,8 +465,7 @@ namespace MWLua
{
SelfObject* obj = mObject.asSelfObject();
addStatUpdateAction(context.mLuaManager, *obj);
obj->mStatsCache[SelfObject::CachedStat{ &AIStat::setValue, static_cast<int>(mIndex), prop }]
= sol::main_object(value);
obj->mStatsCache[SelfObject::CachedStat{ &AIStat::setValue, static_cast<int>(mIndex), prop }] = value;
}
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)

View file

@ -168,8 +168,7 @@ namespace MWLua
if (index == LuaUi::Layer::count())
throw std::logic_error(std::string("Layer not found"));
index++;
context.mLuaManager->addAction(
[=, name = std::string(name)]() { LuaUi::Layer::insert(index, name, options); }, "Insert UI layer");
context.mLuaManager->addAction([=]() { LuaUi::Layer::insert(index, name, options); }, "Insert UI layer");
};
layersTable["insertBefore"] = [context](
std::string_view beforename, std::string_view name, const sol::object& opt) {
@ -178,8 +177,7 @@ namespace MWLua
size_t index = LuaUi::Layer::indexOf(beforename);
if (index == LuaUi::Layer::count())
throw std::logic_error(std::string("Layer not found"));
context.mLuaManager->addAction(
[=, name = std::string(name)]() { LuaUi::Layer::insert(index, name, options); }, "Insert UI layer");
context.mLuaManager->addAction([=]() { LuaUi::Layer::insert(index, name, options); }, "Insert UI layer");
};
sol::table layers = LuaUtil::makeReadOnly(layersTable);
sol::table layersMeta = layers[sol::metatable_key];
@ -287,9 +285,8 @@ namespace MWLua
return res;
};
api["_setWindowDisabled"]
= [windowManager, luaManager = context.mLuaManager](std::string window, bool disabled) {
luaManager->addAction(
[=, window = std::move(window)]() { windowManager->setDisabledByLua(window, disabled); });
= [windowManager, luaManager = context.mLuaManager](std::string_view window, bool disabled) {
luaManager->addAction([=]() { windowManager->setDisabledByLua(window, disabled); });
};
// TODO
@ -311,7 +308,7 @@ namespace MWLua
return res.str();
};
element["layout"] = sol::property([](const LuaUi::Element& element) { return element.mLayout; },
[](LuaUi::Element& element, const sol::main_table& layout) { element.mLayout = layout; });
[](LuaUi::Element& element, const sol::table& layout) { element.mLayout = layout; });
element["update"] = [luaManager = context.mLuaManager](const std::shared_ptr<LuaUi::Element>& element) {
if (element->mState != LuaUi::Element::Created)
return;

View file

@ -68,7 +68,7 @@ namespace MWLua
Log(Debug::Verbose) << "Read a large data chunk (" << size << " bytes) from '" << file.mFileName << "'.";
}
sol::object readFile(lua_State* lua, FileHandle& file)
sol::object readFile(sol::this_state lua, FileHandle& file)
{
std::ostringstream os;
if (file.mFilePtr && file.mFilePtr->peek() != EOF)
@ -79,7 +79,7 @@ namespace MWLua
return sol::make_object<std::string>(lua, std::move(result));
}
sol::object readLineFromFile(lua_State* lua, FileHandle& file)
sol::object readLineFromFile(sol::this_state lua, FileHandle& file)
{
std::string result;
if (file.mFilePtr && std::getline(*file.mFilePtr, result))
@ -91,7 +91,7 @@ namespace MWLua
return sol::nil;
}
sol::object readNumberFromFile(lua_State* lua, Files::IStreamPtr& file)
sol::object readNumberFromFile(sol::this_state lua, Files::IStreamPtr& file)
{
double number = 0;
if (file && *file >> number)
@ -100,7 +100,7 @@ namespace MWLua
return sol::nil;
}
sol::object readCharactersFromFile(lua_State* lua, FileHandle& file, size_t count)
sol::object readCharactersFromFile(sol::this_state lua, FileHandle& file, size_t count)
{
if (count <= 0 && file.mFilePtr->peek() != EOF)
return sol::make_object<std::string>(lua, std::string());
@ -189,7 +189,7 @@ namespace MWLua
return seek(lua, self, std::ios_base::cur, off);
});
handle["lines"] = [](sol::this_main_state lua, sol::main_object self) {
handle["lines"] = [](sol::this_state lua, sol::object self) {
if (!self.is<FileHandle*>())
throw std::runtime_error("self should be a file handle");
return sol::as_function([lua, self]() -> sol::object {
@ -199,7 +199,7 @@ namespace MWLua
});
};
api["lines"] = [vfs](sol::this_main_state lua, std::string_view fileName) {
api["lines"] = [vfs](sol::this_state lua, std::string_view fileName) {
auto normalizedName = VFS::Path::normalizeFilename(fileName);
return sol::as_function(
[lua, file = FileHandle(vfs->getNormalized(normalizedName), normalizedName)]() mutable {

View file

@ -289,9 +289,8 @@ namespace MWMechanics
const ESM::RefId& enchantmentId = slot->getClass().getEnchantment(*slot);
if (enchantmentId.empty())
continue;
const ESM::Enchantment* enchantment
= world->getStore().get<ESM::Enchantment>().search(enchantmentId);
if (enchantment == nullptr || enchantment->mData.mType != ESM::Enchantment::ConstantEffect)
const ESM::Enchantment* enchantment = world->getStore().get<ESM::Enchantment>().find(enchantmentId);
if (enchantment->mData.mType != ESM::Enchantment::ConstantEffect)
continue;
if (std::find_if(mSpells.begin(), mSpells.end(),
[&](const ActiveSpellParams& params) {

View file

@ -2028,7 +2028,7 @@ namespace MWMechanics
iter->second->getCharacterController().skipAnim();
}
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, std::string_view groupName) const
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) const
{
const auto iter = mIndex.find(ptr.mRef);
if (iter != mIndex.end())

View file

@ -119,7 +119,7 @@ namespace MWMechanics
std::string_view startKey, std::string_view stopKey, bool forceLoop);
void enableLuaAnimations(const MWWorld::Ptr& ptr, bool enable);
void skipAnimation(const MWWorld::Ptr& ptr) const;
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, std::string_view groupName) const;
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) const;
bool checkScriptedAnimationPlaying(const MWWorld::Ptr& ptr) const;
void persistAnimationStates() const;
void clearAnimationQueue(const MWWorld::Ptr& ptr, bool clearScripted);

View file

@ -40,15 +40,15 @@ namespace MWMechanics
static const std::size_t MAX_IDLE_SIZE = 8;
const std::string_view AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] = {
"idle2",
"idle3",
"idle4",
"idle5",
"idle6",
"idle7",
"idle8",
"idle9",
const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] = {
std::string("idle2"),
std::string("idle3"),
std::string("idle4"),
std::string("idle5"),
std::string("idle6"),
std::string("idle7"),
std::string("idle8"),
std::string("idle9"),
};
namespace
@ -680,7 +680,7 @@ namespace MWMechanics
{
if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle))
{
const std::string_view groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle];
const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle];
return MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1);
}
else
@ -695,7 +695,7 @@ namespace MWMechanics
{
if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle))
{
const std::string_view groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle];
const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle];
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, groupName);
}
else

View file

@ -3,7 +3,6 @@
#include "typedaipackage.hpp"
#include <string_view>
#include <vector>
#include "aitemporarybase.hpp"
@ -182,7 +181,9 @@ namespace MWMechanics
const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end, AiWanderStorage& storage);
/// lookup table for converting idleSelect value to groupName
static const std::string_view sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1];
static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1];
static int OffsetToPreventOvercrowding();
};
}

View file

@ -1104,10 +1104,10 @@ namespace MWMechanics
attackType = ESM::Weapon::AT_Thrust;
// We want to avoid hit keys that come out of nowhere (e.g. in the follow animation)
// and processing multiple hit keys for a single attack
if (mReadyToHit)
if (mAttackStrength != -1.f)
{
charClass.hit(mPtr, mAttackStrength, attackType, mAttackVictim, mAttackHitPos, mAttackSuccess);
mReadyToHit = false;
mAttackStrength = -1.f;
}
}
else if (isRandomAttackAnimation(groupname) && action == "start")
@ -1153,10 +1153,10 @@ namespace MWMechanics
else if (action == "shoot release")
{
// See notes for melee release above
if (mReadyToHit)
if (mAttackStrength != -1.f)
{
mAnimation->releaseArrow(mAttackStrength);
mReadyToHit = false;
mAttackStrength = -1.f;
}
}
else if (action == "shoot follow attach")
@ -1246,7 +1246,7 @@ namespace MWMechanics
void CharacterController::prepareHit()
{
if (mReadyToHit)
if (mAttackStrength != -1.f)
return;
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
@ -1261,8 +1261,6 @@ namespace MWMechanics
mAttackStrength = 0.f;
playSwishSound();
}
mReadyToHit = true;
}
bool CharacterController::updateWeaponState()
@ -1522,7 +1520,6 @@ namespace MWMechanics
&& (mHitState == CharState_None || mHitState == CharState_Block))
{
mAttackStrength = -1.f;
mReadyToHit = false;
// Randomize attacks for non-bipedal creatures
if (!cls.isBipedal(mPtr)
@ -1809,7 +1806,8 @@ namespace MWMechanics
stop = strength + ' ' + stop;
}
mReadyToHit = false;
// Reset attack strength to make extra sure hits that come out of nowhere aren't processed
mAttackStrength = -1.f;
if (animPlaying)
mAnimation->disable(mCurrentWeapon);

View file

@ -172,7 +172,6 @@ namespace MWMechanics
std::string mCurrentWeapon;
float mAttackStrength{ -1.f };
bool mReadyToHit{ false };
MWWorld::Ptr mAttackVictim;
osg::Vec3f mAttackHitPos;
bool mAttackSuccess{ false };

View file

@ -778,8 +778,7 @@ namespace MWMechanics
else
mObjects.skipAnimation(ptr);
}
bool MechanicsManager::checkAnimationPlaying(const MWWorld::Ptr& ptr, std::string_view groupName)
bool MechanicsManager::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
{
if (ptr.getClass().isActor())
return mActors.checkAnimationPlaying(ptr, groupName);

View file

@ -146,7 +146,7 @@ namespace MWMechanics
std::string_view startKey, std::string_view stopKey, bool forceLoop) override;
void enableLuaAnimations(const MWWorld::Ptr& ptr, bool enable) override;
void skipAnimation(const MWWorld::Ptr& ptr) override;
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, std::string_view groupName) override;
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) override;
bool checkScriptedAnimationPlaying(const MWWorld::Ptr& ptr) const override;
void persistAnimationStates() override;
void clearAnimationQueue(const MWWorld::Ptr& ptr, bool clearScripted) override;

View file

@ -161,7 +161,7 @@ namespace MWRender
bool ActorAnimation::updateCarriedLeftVisible(const int weaptype) const
{
if (Settings::game().mShieldSheathing && mObjectRoot)
if (Settings::game().mShieldSheathing)
{
const MWWorld::Class& cls = mPtr.getClass();
MWMechanics::CreatureStats& stats = cls.getCreatureStats(mPtr);

View file

@ -1695,7 +1695,7 @@ namespace MWRender
mGlowUpdater->setColor(color);
mGlowUpdater->setDuration(glowDuration);
}
else if (mObjectRoot)
else
mGlowUpdater = SceneUtil::addEnchantedGlow(mObjectRoot, mResourceSystem, color, glowDuration);
}
}
@ -1869,7 +1869,7 @@ namespace MWRender
void Animation::setAlpha(float alpha)
{
if (alpha == mAlpha || !mObjectRoot)
if (alpha == mAlpha)
return;
mAlpha = alpha;

View file

@ -259,8 +259,7 @@ namespace MWRender
void CreatureWeaponAnimation::addControllers()
{
Animation::addControllers();
if (mObjectRoot)
WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get());
WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get());
}
osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration)

View file

@ -49,6 +49,11 @@ namespace MWRender
&& exts.glslLanguageVersion >= minimumGLVersionRequiredForCompute;
#endif
if (mUseCompute)
Log(Debug::Info) << "Initialized compute shader pipeline for water ripples";
else
Log(Debug::Info) << "Initialized fallback fragment shader pipeline for water ripples";
for (size_t i = 0; i < mState.size(); ++i)
{
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
@ -86,18 +91,6 @@ namespace MWRender
else
setupFragmentPipeline();
if (mProgramBlobber != nullptr)
{
static bool pipelineLogged = [&] {
if (mUseCompute)
Log(Debug::Info) << "Initialized compute shader pipeline for water ripples";
else
Log(Debug::Info) << "Initialized fallback fragment shader pipeline for water ripples";
return true;
}();
(void)pipelineLogged;
}
setCullCallback(new osg::NodeCallback);
setUpdateCallback(new osg::NodeCallback);
}
@ -109,36 +102,21 @@ namespace MWRender
Shader::ShaderManager::DefineMap defineMap = { { "rippleMapSize", std::to_string(sRTTSize) + ".0" } };
osg::ref_ptr<osg::Shader> vertex = shaderManager.getShader("fullscreen_tri.vert", {}, osg::Shader::VERTEX);
osg::ref_ptr<osg::Shader> blobber
= shaderManager.getShader("ripples_blobber.frag", defineMap, osg::Shader::FRAGMENT);
osg::ref_ptr<osg::Shader> simulate
= shaderManager.getShader("ripples_simulate.frag", defineMap, osg::Shader::FRAGMENT);
if (vertex == nullptr || blobber == nullptr || simulate == nullptr)
{
Log(Debug::Error) << "Failed to load shaders required for fragment shader ripple pipeline";
return;
}
mProgramBlobber = shaderManager.getProgram(vertex, std::move(blobber));
mProgramSimulation = shaderManager.getProgram(std::move(vertex), std::move(simulate));
mProgramBlobber = shaderManager.getProgram(
vertex, shaderManager.getShader("ripples_blobber.frag", defineMap, osg::Shader::FRAGMENT));
mProgramSimulation = shaderManager.getProgram(
std::move(vertex), shaderManager.getShader("ripples_simulate.frag", defineMap, osg::Shader::FRAGMENT));
}
void RipplesSurface::setupComputePipeline()
{
auto& shaderManager = mResourceSystem->getSceneManager()->getShaderManager();
osg::ref_ptr<osg::Shader> blobber
= shaderManager.getShader("core/ripples_blobber.comp", {}, osg::Shader::COMPUTE);
osg::ref_ptr<osg::Shader> simulate
= shaderManager.getShader("core/ripples_simulate.comp", {}, osg::Shader::COMPUTE);
if (blobber == nullptr || simulate == nullptr)
{
Log(Debug::Error) << "Failed to load shaders required for compute shader ripple pipeline";
return;
}
mProgramBlobber = shaderManager.getProgram(nullptr, std::move(blobber));
mProgramSimulation = shaderManager.getProgram(nullptr, std::move(simulate));
mProgramBlobber = shaderManager.getProgram(
nullptr, shaderManager.getShader("core/ripples_blobber.comp", {}, osg::Shader::COMPUTE));
mProgramSimulation = shaderManager.getProgram(
nullptr, shaderManager.getShader("core/ripples_simulate.comp", {}, osg::Shader::COMPUTE));
}
void RipplesSurface::updateState(const osg::FrameStamp& frameStamp, State& state)
@ -206,9 +184,6 @@ namespace MWRender
void RipplesSurface::drawImplementation(osg::RenderInfo& renderInfo) const
{
if (mProgramBlobber == nullptr || mProgramSimulation == nullptr)
return;
osg::State& state = *renderInfo.getState();
const std::size_t currentFrame = state.getFrameStamp()->getFrameNumber() % 2;
const State& frameState = mState[currentFrame];

View file

@ -162,17 +162,11 @@ namespace MWScript
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime, false);
MWWorld::Ptr ptr = R()(runtime);
int index = runtime[0].mInteger;
runtime.pop();
if (ptr.isEmpty())
{
runtime.push(0);
return;
}
bool ret = MWBase::Environment::get().getSoundManager()->getSoundPlaying(
ptr, ESM::RefId::stringRefId(runtime.getStringLiteral(index)));

View file

@ -38,7 +38,7 @@ MWState::Character* MWState::CharacterManager::getCurrentCharacter()
return mCurrent;
}
void MWState::CharacterManager::deleteSlot(const MWState::Slot* slot, const MWState::Character*& character)
void MWState::CharacterManager::deleteSlot(const MWState::Character* character, const MWState::Slot* slot)
{
std::list<Character>::iterator it = findCharacter(character);
@ -51,7 +51,6 @@ void MWState::CharacterManager::deleteSlot(const MWState::Slot* slot, const MWSt
if (character == mCurrent)
mCurrent = nullptr;
mCharacters.erase(it);
character = nullptr;
}
}

View file

@ -33,7 +33,7 @@ namespace MWState
Character* getCurrentCharacter();
///< @note May return null
void deleteSlot(const MWState::Slot* slot, const Character*& character);
void deleteSlot(const MWState::Character* character, const MWState::Slot* slot);
Character* createCharacter(const std::string& name);
///< Create new character within saved game management

View file

@ -706,10 +706,10 @@ void MWState::StateManager::quickLoad()
void MWState::StateManager::deleteGame(const MWState::Character* character, const MWState::Slot* slot)
{
const std::filesystem::path savePath = slot->mPath;
mCharacterManager.deleteSlot(slot, character);
mCharacterManager.deleteSlot(character, slot);
if (mLastSavegame == savePath)
{
if (character != nullptr)
if (character->begin() != character->end())
mLastSavegame = character->begin()->mPath;
else
mLastSavegame.clear();
@ -757,14 +757,12 @@ void MWState::StateManager::update(float duration)
if (mNewGameRequest)
{
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_MainMenu);
newGame();
mNewGameRequest = false;
}
if (mLoadRequest)
{
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_MainMenu);
loadGame(*mLoadRequest);
mLoadRequest = std::nullopt;
}

View file

@ -337,13 +337,13 @@ namespace
// helper function for forEachInternal
template <class Visitor, class List>
bool forEachImp(Visitor& visitor, List& list, MWWorld::CellStore& cellStore, bool includeDeleted)
bool forEachImp(Visitor& visitor, List& list, MWWorld::CellStore* cellStore)
{
for (auto& v : list.mList)
for (typename List::List::iterator iter(list.mList.begin()); iter != list.mList.end(); ++iter)
{
if (!includeDeleted && !MWWorld::CellStore::isAccessible(v.mData, v.mRef))
if (!MWWorld::CellStore::isAccessible(iter->mData, iter->mRef))
continue;
if (!visitor(MWWorld::Ptr(&v, &cellStore)))
if (!visitor(MWWorld::Ptr(&*iter, cellStore)))
return false;
}
return true;
@ -399,12 +399,12 @@ namespace MWWorld
// listing only objects owned by this cell. Internal use only, you probably want to use forEach() so that moved
// objects are accounted for.
template <class Visitor>
static bool forEachInternal(Visitor& visitor, MWWorld::CellStore& cellStore, bool includeDeleted)
static bool forEachInternal(Visitor& visitor, MWWorld::CellStore& cellStore)
{
bool returnValue = true;
Misc::tupleForEach(cellStore.mCellStoreImp->mRefLists, [&](auto& store) {
returnValue = returnValue && forEachImp(visitor, store, cellStore, includeDeleted);
Misc::tupleForEach(cellStore.mCellStoreImp->mRefLists, [&visitor, &returnValue, &cellStore](auto& store) {
returnValue = returnValue && forEachImp(visitor, store, &cellStore);
});
return returnValue;
@ -583,11 +583,11 @@ namespace MWWorld
mMergedRefsNeedsUpdate = true;
}
void CellStore::updateMergedRefs(bool includeDeleted) const
void CellStore::updateMergedRefs() const
{
mMergedRefs.clear();
MergeVisitor visitor(mMergedRefs, mMovedHere, mMovedToAnotherCell);
CellStoreImp::forEachInternal(visitor, const_cast<CellStore&>(*this), includeDeleted);
CellStoreImp::forEachInternal(visitor, const_cast<CellStore&>(*this));
visitor.merge();
mMergedRefsNeedsUpdate = false;
}

View file

@ -219,7 +219,7 @@ namespace MWWorld
return false;
if (mMergedRefsNeedsUpdate)
updateMergedRefs(includeDeleted);
updateMergedRefs();
if (mMergedRefs.empty())
return true;
@ -248,7 +248,7 @@ namespace MWWorld
return false;
if (mMergedRefsNeedsUpdate)
updateMergedRefs(includeDeleted);
updateMergedRefs();
for (const LiveCellRefBase* mergedRef : mMergedRefs)
{
@ -273,7 +273,7 @@ namespace MWWorld
return false;
if (mMergedRefsNeedsUpdate)
updateMergedRefs(includeDeleted);
updateMergedRefs();
if (mMergedRefs.empty())
return true;
@ -403,7 +403,7 @@ namespace MWWorld
/// Repopulate mMergedRefs.
void requestMergedRefsUpdate();
void updateMergedRefs(bool includeDeleted = false) const;
void updateMergedRefs() const;
// (item, max charge)
typedef std::vector<std::pair<LiveCellRefBase*, float>> TRechargingItems;

View file

@ -406,7 +406,8 @@ namespace MWWorld
template <class T>
ContainerStoreIteratorBase(const ContainerStoreIteratorBase<T>& other)
{
static_assert(IsConvertible<T, PtrType, void>::value);
char CANNOT_CONVERT_CONST_ITERATOR_TO_ITERATOR[IsConvertible<T, PtrType, void>::value ? 1 : -1];
((void)CANNOT_CONVERT_CONST_ITERATOR_TO_ITERATOR);
copy(other);
}

View file

@ -290,14 +290,14 @@ namespace MWWorld
mSwimHeightScale = mStore.get<ESM::GameSetting>().find("fSwimHeightScale")->mValue.getFloat();
}
void World::init(Debug::Level maxRecastLogLevel, osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode,
SceneUtil::WorkQueue* workQueue, SceneUtil::UnrefQueue& unrefQueue)
void World::init(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, SceneUtil::WorkQueue* workQueue,
SceneUtil::UnrefQueue& unrefQueue)
{
mPhysics = std::make_unique<MWPhysics::PhysicsSystem>(mResourceSystem, rootNode);
if (Settings::navigator().mEnable)
{
auto navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager(maxRecastLogLevel);
auto navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager();
navigatorSettings.mRecast.mSwimHeightScale = mSwimHeightScale;
mNavigator = DetourNavigator::makeNavigator(navigatorSettings, mUserDataPath);
}

View file

@ -4,7 +4,6 @@
#include <osg/Timer>
#include <osg/ref_ptr>
#include <components/debug/debuglog.hpp>
#include <components/esm3/readerscache.hpp>
#include <components/misc/rng.hpp>
#include <components/settings/settings.hpp>
@ -202,8 +201,8 @@ namespace MWWorld
Loading::Listener* listener);
// Must be called after `loadData`.
void init(Debug::Level maxRecastLogLevel, osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode,
SceneUtil::WorkQueue* workQueue, SceneUtil::UnrefQueue& unrefQueue);
void init(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, SceneUtil::WorkQueue* workQueue,
SceneUtil::UnrefQueue& unrefQueue);
virtual ~World();

View file

@ -2,7 +2,6 @@
#include <components/misc/strings/conversion.hpp>
#include <components/settings/parser.hpp>
#include <components/settings/values.hpp>
#include <components/testing/util.hpp>
#include <gtest/gtest.h>
@ -25,9 +24,5 @@ int main(int argc, char* argv[])
Settings::StaticValues::init();
testing::InitGoogleTest(&argc, argv);
const int result = RUN_ALL_TESTS();
if (result == 0)
std::filesystem::remove_all(TestingOpenMW::outputDir());
return result;
return RUN_ALL_TESTS();
}

View file

@ -59,7 +59,7 @@ list(APPEND COMPONENT_FILES "${OpenMW_BINARY_DIR}/${OSG_PLUGIN_CHECKER_CPP_FILE}
add_component_dir (lua
luastate scriptscontainer asyncpackage utilpackage serialization configuration l10n storage utf8
shapes/box inputactions yamlloader scripttracker luastateptr
shapes/box inputactions yamlloader scripttracker
)
add_component_dir (l10n

View file

@ -1,7 +1,6 @@
#include "gamesettings.hpp"
#include <QDir>
#include <QProgressDialog>
#include <QRegularExpression>
#include <components/files/configurationmanager.hpp>
@ -38,13 +37,8 @@ void Config::GameSettings::validatePaths()
mDataDirs.clear();
QProgressDialog progressBar("Validating paths", {}, 0, paths.count() + 1);
progressBar.setWindowModality(Qt::WindowModal);
progressBar.setValue(0);
for (const auto& dataDir : paths)
{
progressBar.setValue(progressBar.value() + 1);
if (QDir(dataDir.value).exists())
{
SettingValue copy = dataDir;
@ -56,8 +50,6 @@ void Config::GameSettings::validatePaths()
// Do the same for data-local
const QString& local = mSettings.value(QString("data-local")).value;
progressBar.setValue(progressBar.value() + 1);
if (!local.isEmpty() && QDir(local).exists())
{
mDataLocal = QDir(local).canonicalPath();

View file

@ -10,7 +10,6 @@
#include <QDataStream>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QFont>
#include <QIODevice>
@ -79,10 +78,14 @@ ContentSelectorModel::EsmFile* ContentSelectorModel::ContentModel::item(int row)
}
const ContentSelectorModel::EsmFile* ContentSelectorModel::ContentModel::item(const QString& name) const
{
bool path = name.contains('/');
EsmFile::FileProperty fp = EsmFile::FileProperty_FileName;
if (name.contains('/'))
fp = EsmFile::FileProperty_FilePath;
for (const EsmFile* file : mFiles)
{
if (name.compare(path ? file->filePath() : file->fileName(), Qt::CaseInsensitive) == 0)
if (name.compare(file->fileProperty(fp).toString(), Qt::CaseInsensitive) == 0)
return file;
}
return nullptr;
@ -307,6 +310,7 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const
{
setCheckState(file->filePath(), success);
emit dataChanged(index, index);
checkForLoadOrderErrors();
}
else
return success;
@ -421,6 +425,7 @@ bool ContentSelectorModel::ContentModel::dropMimeData(
dataChanged(index(minRow, 0), index(maxRow, 0));
// at this point we know that drag and drop has finished.
checkForLoadOrderErrors();
return true;
}
@ -547,13 +552,15 @@ void ContentSelectorModel::ContentModel::addFiles(const QString& path, bool newf
bool ContentSelectorModel::ContentModel::containsDataFiles(const QString& path)
{
QDir dir(path);
QStringList filters;
filters << "*.esp"
<< "*.esm"
<< "*.omwgame"
<< "*.omwaddon";
QDirIterator it(path, filters, QDir::Files | QDir::NoDotAndDotDot);
return it.hasNext();
dir.setNameFilters(filters);
return dir.entryList().count() != 0;
}
void ContentSelectorModel::ContentModel::clearFiles()
@ -700,13 +707,12 @@ void ContentSelectorModel::ContentModel::setNonUserContent(const QStringList& fi
bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile* file) const
{
int index = indexFromItem(file).row();
auto errors = checkForLoadOrderErrors(file, index);
return !errors.empty();
return mPluginsWithLoadOrderError.contains(file->filePath());
}
void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileList)
{
mPluginsWithLoadOrderError.clear();
int previousPosition = -1;
for (const QString& filepath : fileList)
{
@ -719,6 +725,7 @@ void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileL
if (filePosition < previousPosition)
{
mFiles.move(filePosition, previousPosition);
emit dataChanged(index(filePosition, 0, QModelIndex()), index(previousPosition, 0, QModelIndex()));
}
else
{
@ -726,7 +733,24 @@ void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileL
}
}
}
emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
checkForLoadOrderErrors();
}
void ContentSelectorModel::ContentModel::checkForLoadOrderErrors()
{
for (int row = 0; row < mFiles.count(); ++row)
{
EsmFile* file = mFiles.at(row);
bool isRowInError = checkForLoadOrderErrors(file, row).count() != 0;
if (isRowInError)
{
mPluginsWithLoadOrderError.insert(file->filePath());
}
else
{
mPluginsWithLoadOrderError.remove(file->filePath());
}
}
}
QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::checkForLoadOrderErrors(
@ -767,12 +791,11 @@ QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::
QString ContentSelectorModel::ContentModel::toolTip(const EsmFile* file) const
{
int index = indexFromItem(file).row();
auto errors = checkForLoadOrderErrors(file, index);
if (!errors.empty())
if (isLoadOrderError(file))
{
QString text("<b>");
for (const LoadOrderError& error : errors)
int index = indexFromItem(item(file->filePath())).row();
for (const LoadOrderError& error : checkForLoadOrderErrors(file, index))
{
assert(error.errorCode() != LoadOrderError::ErrorCode::ErrorCode_None);
@ -877,6 +900,7 @@ ContentSelectorModel::ContentFileList ContentSelectorModel::ContentModel::checke
void ContentSelectorModel::ContentModel::uncheckAll()
{
emit layoutAboutToBeChanged();
mCheckedFiles.clear();
emit dataChanged(index(0, 0), index(rowCount(), columnCount()), { Qt::CheckStateRole, Qt::UserRole + 1 });
emit layoutChanged();
}

View file

@ -69,6 +69,9 @@ namespace ContentSelectorModel
void refreshModel();
/// Checks all plug-ins for load order errors and updates mPluginsWithLoadOrderError with plug-ins with issues
void checkForLoadOrderErrors();
private:
void addFile(EsmFile* file);
@ -86,6 +89,7 @@ namespace ContentSelectorModel
QStringList mNonUserContent;
std::set<const EsmFile*> mCheckedFiles;
QHash<QString, bool> mNewFiles;
QSet<QString> mPluginsWithLoadOrderError;
QString mEncoding;
QIcon mWarningIcon;
QIcon mErrorIcon;

View file

@ -48,18 +48,18 @@ namespace ContentSelectorModel
void addGameFile(const QString& name) { mGameFiles.append(name); }
QVariant fileProperty(const FileProperty prop) const;
const QString& fileName() const { return mFileName; }
const QString& author() const { return mAuthor; }
QString fileName() const { return mFileName; }
QString author() const { return mAuthor; }
QDateTime modified() const { return mModified; }
const QString& formatVersion() const { return mVersion; }
const QString& filePath() const { return mPath; }
QString formatVersion() const { return mVersion; }
QString filePath() const { return mPath; }
bool builtIn() const { return mBuiltIn; }
bool fromAnotherConfigFile() const { return mFromAnotherConfigFile; }
bool isMissing() const { return mPath.isEmpty(); }
/// @note Contains file names, not paths.
const QStringList& gameFiles() const { return mGameFiles; }
const QString& description() const { return mDescription; }
QString description() const { return mDescription; }
QString toolTip() const
{
if (isMissing())

View file

@ -211,6 +211,7 @@ void ContentSelectorView::ContentSelector::addFiles(const QString& path, bool ne
ui->gameFileView->setCurrentIndex(0);
mContentModel->uncheckAll();
mContentModel->checkForLoadOrderErrors();
}
void ContentSelectorView::ContentSelector::sortFiles()
@ -253,6 +254,7 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i
oldIndex = index;
setGameFileSelected(index, true);
mContentModel->checkForLoadOrderErrors();
}
emit signalCurrentGamefileIndexChanged(index);

View file

@ -237,7 +237,7 @@ namespace Crash
// must remain until monitor has finished
waitMonitor();
std::string message = "OpenMW has encountered a fatal error.\nCrash dump saved to '"
std::string message = "OpenMW has encountered a fatal error.\nCrash log saved to '"
+ Misc::StringUtils::u8StringToString(getCrashDumpPath(*mShm).u8string())
+ "'.\nPlease report this to https://gitlab.com/OpenMW/openmw/issues !";
SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), nullptr);

View file

@ -21,7 +21,6 @@ namespace Crash
// the main openmw process in task manager.
static constexpr const int CrashCatcherTimeout = 2500;
static constexpr const int CrashCatcherThawTimeout = 250;
struct CrashSHM;

View file

@ -87,10 +87,9 @@ namespace Crash
SetEvent(mSignalAppEvent);
}
bool CrashMonitor::waitApp(bool thawMode) const
bool CrashMonitor::waitApp() const
{
return WaitForSingleObject(mSignalMonitorEvent, thawMode ? CrashCatcherThawTimeout : CrashCatcherTimeout)
== WAIT_OBJECT_0;
return WaitForSingleObject(mSignalMonitorEvent, CrashCatcherTimeout) == WAIT_OBJECT_0;
}
bool CrashMonitor::isAppAlive() const
@ -186,7 +185,7 @@ namespace Crash
frozen = false;
}
if (!mFreezeAbort && waitApp(frozen))
if (!mFreezeAbort && waitApp())
{
shmLock();
@ -216,7 +215,7 @@ namespace Crash
{
handleCrash(true);
TerminateProcess(mAppProcessHandle, 0xDEAD);
std::string message = "OpenMW has frozen.\nCrash dump saved to '"
std::string message = "OpenMW appears to have frozen.\nCrash log saved to '"
+ Misc::StringUtils::u8StringToString(getFreezeDumpPath(*mShm).u8string())
+ "'.\nPlease report this to https://gitlab.com/OpenMW/openmw/issues !";
SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), nullptr);
@ -290,10 +289,10 @@ namespace Crash
{
std::thread messageBoxThread([&]() {
SDL_MessageBoxButtonData button = { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 0, "Abort" };
SDL_MessageBoxData messageBoxData = { SDL_MESSAGEBOX_ERROR, nullptr, "OpenMW has frozen",
"OpenMW has frozen. This should never happen. Press Abort to terminate it and generate a crash dump to "
"help diagnose the problem.\nOpenMW may unfreeze if you wait, and this message box will disappear "
"after it becomes responsive.",
SDL_MessageBoxData messageBoxData = { SDL_MESSAGEBOX_ERROR, nullptr, "OpenMW appears to have frozen",
"OpenMW appears to have frozen. Press Abort to terminate it and generate a crash dump.\nIf OpenMW "
"hasn't actually frozen, this message box will disappear a within a few seconds of it becoming "
"responsive.",
1, &button, nullptr };
int buttonId;

View file

@ -41,7 +41,7 @@ namespace Crash
void signalApp() const;
bool waitApp(bool thawMode) const;
bool waitApp() const;
bool isAppAlive() const;

View file

@ -106,96 +106,94 @@ namespace Debug
logListener = std::move(listener);
}
namespace
class DebugOutputBase : public boost::iostreams::sink
{
class DebugOutputBase : public boost::iostreams::sink
public:
virtual std::streamsize write(const char* str, std::streamsize size)
{
public:
virtual std::streamsize write(const char* str, std::streamsize size)
if (size <= 0)
return size;
std::string_view msg{ str, static_cast<size_t>(size) };
// Skip debug level marker
Level level = All;
if (Log::sWriteLevel)
{
if (size <= 0)
return size;
std::string_view msg{ str, static_cast<size_t>(size) };
level = getLevelMarker(msg[0]);
msg = msg.substr(1);
}
// Skip debug level marker
Level level = All;
if (Log::sWriteLevel)
{
level = getLevelMarker(msg[0]);
msg = msg.substr(1);
}
char prefix[32];
std::size_t prefixSize;
{
prefix[0] = '[';
const auto now = std::chrono::system_clock::now();
const auto time = std::chrono::system_clock::to_time_t(now);
tm time_info{};
char prefix[32];
std::size_t prefixSize;
{
prefix[0] = '[';
const auto now = std::chrono::system_clock::now();
const auto time = std::chrono::system_clock::to_time_t(now);
tm time_info{};
#ifdef _WIN32
(void)localtime_s(&time_info, &time);
(void)localtime_s(&time_info, &time);
#else
(void)localtime_r(&time, &time_info);
(void)localtime_r(&time, &time_info);
#endif
prefixSize = std::strftime(prefix + 1, sizeof(prefix) - 1, "%T", &time_info) + 1;
char levelLetter = " EWIVD*"[int(level)];
const auto ms
= std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
prefixSize += snprintf(prefix + prefixSize, sizeof(prefix) - prefixSize, ".%03u %c] ",
static_cast<unsigned>(ms % 1000), levelLetter);
}
while (!msg.empty())
{
if (msg[0] == 0)
break;
size_t lineSize = 1;
while (lineSize < msg.size() && msg[lineSize - 1] != '\n')
lineSize++;
writeImpl(prefix, prefixSize, level);
writeImpl(msg.data(), lineSize, level);
if (logListener)
logListener(
level, std::string_view(prefix, prefixSize), std::string_view(msg.data(), lineSize));
msg = msg.substr(lineSize);
}
return size;
prefixSize = std::strftime(prefix + 1, sizeof(prefix) - 1, "%T", &time_info) + 1;
char levelLetter = " EWIVD*"[int(level)];
const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
prefixSize += snprintf(prefix + prefixSize, sizeof(prefix) - prefixSize, ".%03u %c] ",
static_cast<unsigned>(ms % 1000), levelLetter);
}
virtual ~DebugOutputBase() = default;
protected:
static Level getLevelMarker(char marker)
while (!msg.empty())
{
if (0 <= marker && static_cast<unsigned>(marker) < static_cast<unsigned>(All))
return static_cast<Level>(marker);
return All;
if (msg[0] == 0)
break;
size_t lineSize = 1;
while (lineSize < msg.size() && msg[lineSize - 1] != '\n')
lineSize++;
writeImpl(prefix, prefixSize, level);
writeImpl(msg.data(), lineSize, level);
if (logListener)
logListener(level, std::string_view(prefix, prefixSize), std::string_view(msg.data(), lineSize));
msg = msg.substr(lineSize);
}
virtual std::streamsize writeImpl(const char* str, std::streamsize size, Level debugLevel)
{
return size;
}
};
return size;
}
virtual ~DebugOutputBase() = default;
protected:
static Level getLevelMarker(char marker)
{
if (0 <= marker && static_cast<unsigned>(marker) < static_cast<unsigned>(All))
return static_cast<Level>(marker);
return All;
}
virtual std::streamsize writeImpl(const char* str, std::streamsize size, Level debugLevel)
{
return size;
}
};
#if defined _WIN32 && defined _DEBUG
class DebugOutput : public DebugOutputBase
class DebugOutput : public DebugOutputBase
{
public:
std::streamsize writeImpl(const char* str, std::streamsize size, Level debugLevel)
{
public:
std::streamsize writeImpl(const char* str, std::streamsize size, Level debugLevel)
{
// Make a copy for null termination
std::string tmp(str, static_cast<unsigned int>(size));
// Write string to Visual Studio Debug output
OutputDebugString(tmp.c_str());
return size;
}
// Make a copy for null termination
std::string tmp(str, static_cast<unsigned int>(size));
// Write string to Visual Studio Debug output
OutputDebugString(tmp.c_str());
return size;
}
virtual ~DebugOutput() = default;
};
virtual ~DebugOutput() = default;
};
#else
namespace
{
struct Record
{
std::string mValue;
@ -326,38 +324,22 @@ namespace Debug
First mFirst;
Second mSecond;
};
}
#endif
Level toLevel(std::string_view value)
{
if (value == "ERROR")
return Error;
if (value == "WARNING")
return Warning;
if (value == "INFO")
return Info;
if (value == "VERBOSE")
return Verbose;
if (value == "DEBUG")
return Debug;
return Verbose;
}
static std::unique_ptr<std::ostream> rawStdout = nullptr;
static std::unique_ptr<std::ostream> rawStderr = nullptr;
static std::unique_ptr<std::mutex> rawStderrMutex = nullptr;
static std::ofstream logfile;
static std::unique_ptr<std::ostream> rawStdout = nullptr;
static std::unique_ptr<std::ostream> rawStderr = nullptr;
static std::unique_ptr<std::mutex> rawStderrMutex = nullptr;
static std::ofstream logfile;
#if defined(_WIN32) && defined(_DEBUG)
static boost::iostreams::stream_buffer<DebugOutput> sb;
static boost::iostreams::stream_buffer<DebugOutput> sb;
#else
static boost::iostreams::stream_buffer<Tee<Identity, Coloured>> standardOut;
static boost::iostreams::stream_buffer<Tee<Identity, Coloured>> standardErr;
static boost::iostreams::stream_buffer<Tee<Buffer, Coloured>> bufferedOut;
static boost::iostreams::stream_buffer<Tee<Buffer, Coloured>> bufferedErr;
static boost::iostreams::stream_buffer<Tee<Identity, Coloured>> standardOut;
static boost::iostreams::stream_buffer<Tee<Identity, Coloured>> standardErr;
static boost::iostreams::stream_buffer<Tee<Buffer, Coloured>> bufferedOut;
static boost::iostreams::stream_buffer<Tee<Buffer, Coloured>> bufferedErr;
#endif
}
std::ostream& getRawStdout()
{
@ -377,19 +359,23 @@ namespace Debug
Level getDebugLevel()
{
if (const char* env = getenv("OPENMW_DEBUG_LEVEL"))
return toLevel(env);
{
const std::string_view value(env);
if (value == "ERROR")
return Error;
if (value == "WARNING")
return Warning;
if (value == "INFO")
return Info;
if (value == "VERBOSE")
return Verbose;
if (value == "DEBUG")
return Debug;
}
return Verbose;
}
Level getRecastMaxLogLevel()
{
if (const char* env = getenv("OPENMW_RECAST_MAX_LOG_LEVEL"))
return toLevel(env);
return Error;
}
void setupLogging(const std::filesystem::path& logDir, std::string_view appName)
{
Log::sMinDebugLevel = getDebugLevel();

View file

@ -36,8 +36,6 @@ namespace Debug
Level getDebugLevel();
Level getRecastMaxLogLevel();
// Redirect cout and cerr to the log file
void setupLogging(const std::filesystem::path& logDir, std::string_view appName);

View file

@ -453,9 +453,9 @@ namespace DetourNavigator
Misc::setCurrentThreadIdlePriority();
while (!mShouldStop)
{
if (JobIt job = getNextJob(); job != mJobs.end())
try
{
try
if (JobIt job = getNextJob(); job != mJobs.end())
{
const JobStatus status = processJob(*job);
Log(Debug::Debug) << "Processed job " << job->mId << " with status=" << status
@ -480,20 +480,12 @@ namespace DetourNavigator
}
}
}
catch (const std::exception& e)
{
Log(Debug::Warning) << "Failed to process navmesh job " << job->mId
<< " for worldspace=" << job->mWorldspace << " agent=" << job->mAgentBounds
<< " changedTile=(" << job->mChangedTile << ")"
<< " changeType=" << job->mChangeType
<< " by thread=" << std::this_thread::get_id() << ": " << e.what();
unlockTile(job->mId, job->mAgentBounds, job->mChangedTile);
removeJob(job);
}
else
cleanupLastUpdates();
}
else
catch (const std::exception& e)
{
cleanupLastUpdates();
Log(Debug::Error) << "AsyncNavMeshUpdater::process exception: " << e.what();
}
}
Log(Debug::Debug) << "Stop navigator jobs processing by thread=" << std::this_thread::get_id();
@ -501,8 +493,7 @@ namespace DetourNavigator
JobStatus AsyncNavMeshUpdater::processJob(Job& job)
{
Log(Debug::Debug) << "Processing job " << job.mId << " for worldspace=" << job.mWorldspace
<< " agent=" << job.mAgentBounds << ""
Log(Debug::Debug) << "Processing job " << job.mId << " for agent=(" << job.mAgentBounds << ")"
<< " changedTile=(" << job.mChangedTile << ")"
<< " changeType=" << job.mChangeType << " by thread=" << std::this_thread::get_id();
@ -552,14 +543,7 @@ namespace DetourNavigator
return JobStatus::Done;
}
try
{
writeDebugRecastMesh(mSettings, job.mChangedTile, *recastMesh);
}
catch (const std::exception& e)
{
Log(Debug::Warning) << "Failed to write debug recast mesh: " << e.what();
}
writeDebugRecastMesh(mSettings, job.mChangedTile, *recastMesh);
NavMeshTilesCache::Value cachedNavMeshData
= mNavMeshTilesCache.get(job.mAgentBounds, job.mChangedTile, *recastMesh);
@ -682,19 +666,12 @@ namespace DetourNavigator
mPresentTiles.insert(std::make_tuple(job.mAgentBounds, job.mChangedTile));
}
try
{
writeDebugNavMesh(mSettings, navMeshCacheItem, navMeshVersion);
}
catch (const std::exception& e)
{
Log(Debug::Warning) << "Failed to write debug navmesh: " << e.what();
}
writeDebugNavMesh(mSettings, navMeshCacheItem, navMeshVersion);
return isSuccess(status) ? JobStatus::Done : JobStatus::Fail;
}
JobIt AsyncNavMeshUpdater::getNextJob() noexcept
JobIt AsyncNavMeshUpdater::getNextJob()
{
std::unique_lock<std::mutex> lock(mMutex);
@ -769,7 +746,7 @@ namespace DetourNavigator
return mJobs.size();
}
void AsyncNavMeshUpdater::cleanupLastUpdates() noexcept
void AsyncNavMeshUpdater::cleanupLastUpdates()
{
const auto now = std::chrono::steady_clock::now();

View file

@ -244,7 +244,7 @@ namespace DetourNavigator
inline JobStatus handleUpdateNavMeshStatus(UpdateNavMeshStatus status, const Job& job,
const GuardedNavMeshCacheItem& navMeshCacheItem, const RecastMesh& recastMesh);
inline JobIt getNextJob() noexcept;
JobIt getNextJob();
void postThreadJob(JobIt job, std::deque<JobIt>& queue);
@ -254,7 +254,7 @@ namespace DetourNavigator
inline std::size_t getTotalJobs() const;
inline void cleanupLastUpdates() noexcept;
void cleanupLastUpdates();
inline void waitUntilJobsDoneForNotPresentTiles(Loading::Listener* listener);

View file

@ -523,7 +523,7 @@ namespace DetourNavigator
std::unique_ptr<PreparedNavMeshData> prepareNavMeshTileData(const RecastMesh& recastMesh, ESM::RefId worldspace,
const TilePosition& tilePosition, const AgentBounds& agentBounds, const RecastSettings& settings)
{
RecastContext context(worldspace, tilePosition, agentBounds, recastMesh.getVersion(), settings.mMaxLogLevel);
RecastContext context(worldspace, tilePosition, agentBounds);
const auto [minZ, maxZ] = getBoundsByZ(recastMesh, agentBounds.mHalfExtents.z(), settings);

View file

@ -1,7 +1,7 @@
#include "recastcontext.hpp"
#include "debug.hpp"
#include <components/debug/debuglog.hpp>
#include "components/debug/debuglog.hpp"
#include <sstream>
@ -23,30 +23,25 @@ namespace DetourNavigator
return Debug::Debug;
}
std::string formatPrefix(ESM::RefId worldspace, const TilePosition& tilePosition,
const AgentBounds& agentBounds, const Version& version)
std::string formatPrefix(
ESM::RefId worldspace, const TilePosition& tilePosition, const AgentBounds& agentBounds)
{
std::ostringstream stream;
stream << "Worldspace: " << worldspace << "; tile position: " << tilePosition.x() << ", "
<< tilePosition.y() << "; agent bounds: " << agentBounds << "; version: " << version << "; ";
<< tilePosition.y() << "; agent bounds: " << agentBounds << "; ";
return stream.str();
}
}
RecastContext::RecastContext(ESM::RefId worldspace, const TilePosition& tilePosition,
const AgentBounds& agentBounds, const Version& version, Debug::Level maxLogLevel)
: mMaxLogLevel(maxLogLevel)
, mPrefix(formatPrefix(worldspace, tilePosition, agentBounds, version))
RecastContext::RecastContext(
ESM::RefId worldspace, const TilePosition& tilePosition, const AgentBounds& agentBounds)
: mPrefix(formatPrefix(worldspace, tilePosition, agentBounds))
{
}
void RecastContext::doLog(const rcLogCategory category, const char* msg, const int len)
{
if (msg == nullptr || len <= 0)
return;
const Debug::Level level = getLogLevel(category);
if (level > mMaxLogLevel)
return;
Log(level) << mPrefix << std::string_view(msg, static_cast<std::size_t>(len));
if (len > 0)
Log(getLogLevel(category)) << mPrefix << std::string_view(msg, static_cast<std::size_t>(len));
}
}

View file

@ -3,7 +3,6 @@
#include "tileposition.hpp"
#include <components/debug/debuglog.hpp>
#include <components/esm/refid.hpp>
#include <string>
@ -13,18 +12,15 @@
namespace DetourNavigator
{
struct AgentBounds;
struct Version;
class RecastContext final : public rcContext
{
public:
explicit RecastContext(ESM::RefId worldspace, const TilePosition& tilePosition, const AgentBounds& agentBounds,
const Version& version, Debug::Level maxLogLevel);
explicit RecastContext(ESM::RefId worldspace, const TilePosition& tilePosition, const AgentBounds& agentBounds);
const std::string& getPrefix() const { return mPrefix; }
private:
Debug::Level mMaxLogLevel;
std::string mPrefix;
void doLog(rcLogCategory category, const char* msg, int len) override;

View file

@ -44,7 +44,7 @@ namespace DetourNavigator
};
}
RecastSettings makeRecastSettingsFromSettingsManager(Debug::Level maxLogLevel)
RecastSettings makeRecastSettingsFromSettingsManager()
{
RecastSettings result;
@ -63,7 +63,6 @@ namespace DetourNavigator
result.mRegionMergeArea = ::Settings::navigator().mRegionMergeArea;
result.mRegionMinArea = ::Settings::navigator().mRegionMinArea;
result.mTileSize = ::Settings::navigator().mTileSize;
result.mMaxLogLevel = maxLogLevel;
return result;
}
@ -81,11 +80,11 @@ namespace DetourNavigator
}
}
Settings makeSettingsFromSettingsManager(Debug::Level maxLogLevel)
Settings makeSettingsFromSettingsManager()
{
Settings result;
result.mRecast = makeRecastSettingsFromSettingsManager(maxLogLevel);
result.mRecast = makeRecastSettingsFromSettingsManager();
result.mDetour = makeDetourSettingsFromSettingsManager();
const NavMeshLimits limits = getNavMeshTileLimits(result.mDetour);

View file

@ -1,8 +1,6 @@
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_SETTINGS_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_SETTINGS_H
#include <components/debug/debuglog.hpp>
#include <chrono>
#include <string>
@ -25,7 +23,6 @@ namespace DetourNavigator
int mRegionMergeArea = 0;
int mRegionMinArea = 0;
int mTileSize = 0;
Debug::Level mMaxLogLevel = Debug::Error;
};
struct DetourSettings
@ -58,7 +55,7 @@ namespace DetourNavigator
inline constexpr std::int64_t navMeshFormatVersion = 2;
Settings makeSettingsFromSettingsManager(Debug::Level maxLogLevel);
Settings makeSettingsFromSettingsManager();
}
#endif

View file

@ -1,9 +1,8 @@
#include "luascripts.hpp"
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include "components/esm3/esmreader.hpp"
#include "components/esm3/esmwriter.hpp"
#include <components/lua/luastateptr.hpp>
#include <components/lua/serialization.hpp>
// List of all records, that are related to Lua.
@ -103,16 +102,13 @@ void ESM::LuaScriptsCfg::adjustRefNums(const ESMReader& esm)
throw std::runtime_error("Incorrect contentFile index");
};
LuaUtil::LuaStatePtr state(luaL_newstate());
if (state == nullptr)
throw std::runtime_error("Failed to create Lua runtime");
lua_State* L = luaL_newstate();
LuaUtil::BasicSerializer serializer(adjustRefNumFn);
auto adjustLuaData = [&](std::string& data) {
if (data.empty())
return;
sol::object luaData = LuaUtil::deserialize(state.get(), data, &serializer);
sol::object luaData = LuaUtil::deserialize(L, data, &serializer);
data = LuaUtil::serialize(luaData, &serializer);
};
@ -127,6 +123,7 @@ void ESM::LuaScriptsCfg::adjustRefNums(const ESMReader& esm)
refCfg.mRefnumContentFile = adjustRefNumFn(refCfg.mRefnumContentFile);
}
}
lua_close(L);
}
void ESM::LuaScriptsCfg::save(ESMWriter& esm) const

View file

@ -32,7 +32,7 @@ namespace ESM
void EffectList::updateIndexes()
{
for (size_t i = 0; i < mList.size(); i++)
mList[i].mIndex = static_cast<uint32_t>(i);
mList[i].mIndex = i;
}
void EffectList::add(ESMReader& esm)

View file

@ -73,10 +73,10 @@ namespace ESM
int index = getIndex();
for (int i = 0; i < getIndex(); i++)
{
if (readers.getFileSize(static_cast<std::size_t>(i)) == 0)
const ESM::ReadersCache::BusyItem reader = readers.get(static_cast<std::size_t>(i));
if (reader->getFileSize() == 0)
continue; // Content file in non-ESM format
const auto fnamecandidate
= Files::pathToUnicodeString(readers.getName(static_cast<std::size_t>(i)).filename());
const auto fnamecandidate = Files::pathToUnicodeString(reader->getName().filename());
if (Misc::StringUtils::ciEqual(fname, fnamecandidate))
{
index = i;

View file

@ -47,7 +47,6 @@ namespace ESM
{
it->mReader.open(*it->mName);
it->mName.reset();
it->mFileSize.reset();
}
mBusyItems.splice(mBusyItems.end(), mClosedItems, it);
break;
@ -58,46 +57,6 @@ namespace ESM
return BusyItem(*this, it);
}
const std::filesystem::path& ReadersCache::getName(std::size_t index) const
{
const auto indexIt = mIndex.find(index);
if (indexIt == mIndex.end())
throw std::logic_error("ESMReader at index " + std::to_string(index) + " has not been created yet");
switch (indexIt->second->mState)
{
case State::Busy:
case State::Free:
return indexIt->second->mReader.getName();
case State::Closed:
if (indexIt->second->mName)
return *indexIt->second->mName;
throw std::logic_error("ESMReader at index " + std::to_string(index) + " has forgotten its filename");
default:
throw std::logic_error("ESMReader at index " + std::to_string(index) + " in unknown state");
}
}
std::size_t ReadersCache::getFileSize(std::size_t index)
{
const auto indexIt = mIndex.find(index);
if (indexIt == mIndex.end())
return 0;
switch (indexIt->second->mState)
{
case State::Busy:
case State::Free:
if (!indexIt->second->mReader.getName().empty())
return indexIt->second->mReader.getFileSize();
throw std::logic_error("ESMReader at index " + std::to_string(index) + " has not been opened yet");
case State::Closed:
if (indexIt->second->mFileSize)
return *indexIt->second->mFileSize;
throw std::logic_error("ESMReader at index " + std::to_string(index) + " has forgotten its file size");
default:
throw std::logic_error("ESMReader at index " + std::to_string(index) + " in unknown state");
}
}
void ReadersCache::closeExtraReaders()
{
while (!mFreeItems.empty() && mBusyItems.size() + mFreeItems.size() + 1 > mCapacity)
@ -106,7 +65,6 @@ namespace ESM
if (it->mReader.isOpen())
{
it->mName = it->mReader.getName();
it->mFileSize = it->mReader.getFileSize();
it->mReader.close();
}
mClosedItems.splice(mClosedItems.end(), mFreeItems, it);

View file

@ -26,7 +26,6 @@ namespace ESM
State mState = State::Busy;
ESMReader mReader;
std::optional<std::filesystem::path> mName;
std::optional<std::size_t> mFileSize;
Item() = default;
};
@ -56,10 +55,6 @@ namespace ESM
BusyItem get(std::size_t index);
const std::filesystem::path& getName(std::size_t index) const;
std::size_t getFileSize(std::size_t index);
void clear();
private:

View file

@ -114,9 +114,6 @@ void ESM4::Quest::load(ESM4::Reader& reader)
case ESM::fourCC("NNAM"): // FO3
case ESM::fourCC("QOBJ"): // FO3
case ESM::fourCC("NAM0"): // FO3
case ESM::fourCC("SLSD"): // FO3
case ESM::fourCC("SCVR"): // FO3
case ESM::fourCC("SCRV"): // FO3
case ESM::fourCC("ANAM"): // TES5
case ESM::fourCC("DNAM"): // TES5
case ESM::fourCC("ENAM"): // TES5

View file

@ -24,6 +24,8 @@ namespace Fallback
};
// Parses and validates a fallback map from boost program_options.
// Note: for boost to pick up the validate function, you need to pull in the namespace e.g.
// by using namespace Fallback;
void validate(boost::any& v, std::vector<std::string> const& tokens, FallbackMap*, int);
}

View file

@ -36,14 +36,12 @@ namespace Files
{
std::filesystem::path userPath = std::filesystem::current_path();
PWSTR cString;
HRESULT result = SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &cString);
if (SUCCEEDED(result))
userPath = std::filesystem::path(cString);
else
Log(Debug::Error) << "Error " << result << " when getting Documents path";
WCHAR path[MAX_PATH + 1] = {};
CoTaskMemFree(cString);
if (SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, nullptr, 0, path)))
{
userPath = std::filesystem::path(path);
}
return userPath / "My Games" / mName;
}
@ -56,19 +54,14 @@ namespace Files
std::filesystem::path WindowsPath::getGlobalConfigPath() const
{
// The concept of a global config path is absurd on Windows.
// Always use local config instead.
// The virtual base class requires that we provide this, though.
std::filesystem::path globalPath = std::filesystem::current_path();
PWSTR cString;
HRESULT result = SHGetKnownFolderPath(FOLDERID_ProgramFiles, 0, nullptr, &cString);
if (SUCCEEDED(result))
globalPath = std::filesystem::path(cString);
else
Log(Debug::Error) << "Error " << result << " when getting Program Files path";
WCHAR path[MAX_PATH + 1] = {};
CoTaskMemFree(cString);
if (SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_PROGRAM_FILES | CSIDL_FLAG_CREATE, nullptr, 0, path)))
{
globalPath = std::filesystem::path(path);
}
return globalPath / mName;
}

View file

@ -227,10 +227,9 @@ namespace
namespace Gui
{
FontLoader::FontLoader(ToUTF8::FromType encoding, const VFS::Manager* vfs, float scalingFactor, bool exportFonts)
FontLoader::FontLoader(ToUTF8::FromType encoding, const VFS::Manager* vfs, float scalingFactor)
: mVFS(vfs)
, mScalingFactor(scalingFactor)
, mExportFonts(exportFonts)
{
if (encoding == ToUTF8::WINDOWS_1252)
mEncoding = ToUTF8::CP437;
@ -364,8 +363,8 @@ namespace Gui
Point bottom_right;
float width;
float height;
float kerningLeft;
float kerningRight;
float u2; // appears unused, always 0
float kerning;
float ascent;
} GlyphInfo;
@ -408,8 +407,7 @@ namespace Gui
file.reset();
// Create the font texture
const std::string name(name_);
const std::string bitmapFilename = "fonts/" + name + ".tex";
std::string bitmapFilename = "fonts/" + std::string(name_) + ".tex";
Files::IStreamPtr bitmapFile = mVFS->get(bitmapFilename);
@ -427,23 +425,9 @@ namespace Gui
textureData.resize(width * height * 4);
bitmapFile->read(textureData.data(), width * height * 4);
if (!bitmapFile->good())
Log(Debug::Warning) << "Font bitmap " << bitmapFilename << " ended prematurely, using partial data ("
<< bitmapFile->gcount() << "/" << (width * height * 4) << " bytes)";
fail(*bitmapFile, bitmapFilename, "File too small to be a valid bitmap");
bitmapFile.reset();
if (mExportFonts)
{
osg::ref_ptr<osg::Image> image = new osg::Image;
image->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
assert(image->isDataContiguous());
memcpy(image->data(), textureData.data(), textureData.size());
// Convert to OpenGL origin for sensible output
image->flipVertical();
Log(Debug::Info) << "Writing " << name + ".png";
osgDB::writeImageFile(*image, name + ".png");
}
MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture(bitmapFilename);
tex->createManual(width, height, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8A8);
unsigned char* texData = reinterpret_cast<unsigned char*>(tex->lock(MyGUI::TextureUsage::Write));
@ -481,7 +465,7 @@ namespace Gui
// € (Euro Sign, 0x80/U+20AC) is replaced with underscore
// 0x81 (unused) is replaced with underscore
additional.emplace(44, 0x201A); // (Single Low-9 Quotation Mark, 0x82) => , (comma)
// ƒ (Latin Small Letter F with Hook, 0x83) is unavailable, not replaced
additional.emplace(102, 0x0192); // ƒ (Latin Small Letter F with Hook, 0x83) => f (latin small F) (custom)
additional.emplace(44, 0x201E); // „ (Double Low-9 Quotation Mark, 0x84) => , (comma)
additional.emplace(46, 0x2026); // … (Horizontal Ellipsis, 0x85) => . (period)
additional.emplace(43, 0x2020); // † (Dagger, 0x86) => + (plus sign)
@ -516,7 +500,7 @@ namespace Gui
// £ (Pound Sign, 0xA3) is available but its glyph looks like œ (small oe ligature)
omitted.push_back(0x00A4); // ¤ (Currency Sign)
// ¥ (Yen Sign, 0xA5) is unavailable, not replaced
additional.emplace(221, 0x00A6); // ¦ (Broken Bar, 0xA6) => ▌
// ¦ (Broken Bar, 0xA6) is unavailable, not replaced
omitted.push_back(0x00A7); // § (Section Sign)
additional.emplace(34, 0x00A8); // ¨ (Diaeresis) => " (double quote mark)
additional.emplace(99, 0x00A9); // © (Copyright Sign) => c (latin small C)
@ -528,7 +512,7 @@ namespace Gui
additional.emplace(95, 0x00AF); // ¯ (Macron) => _ (underscore)
// ° (Degree Sign, 0xB0) is unavailable, not replaced
// ± (Plus-Minus Sign, 0xB1) is unavailable, not replaced
// ² (Superscript Two, 0xB2) is unavailable, not replaced
additional.emplace(50, 0x00B2); // ² (Superscript Two) => 2 (two digit) (custom)
additional.emplace(51, 0x00B3); // ³ (Superscript Three) => 3 (three digit)
additional.emplace(39, 0x00B4); // ´ (Acute Accent) => ' (apostrophe)
// µ (Micro Sign, 0xB5) is unavailable, not replaced
@ -548,7 +532,7 @@ namespace Gui
additional.emplace(65, 0x00C3); // Ã (Latin Capital Letter A with Tilde) => A (latin capital A)
// Ä (Latin Capital Letter A with Diaeresis, 0xC4) is available
// Å (Latin Capital Letter A with Ring Above, 0xC5) is available
// Æ (Latin Capital Letter Ae, 0xC6) is unavailable, not replaced
additional.emplace(65, 0x00C6); // Æ (Latin Capital Letter Ae) => A (latin capital A) (custom)
// Ç (Latin Capital Letter C with Cedilla, 0xC7) is available
additional.emplace(69, 0x00C8); // È (Latin Capital Letter E with Grave) => E (latin capital E)
// É (Latin Capital Letter E with Acute, 0xC9) is available
@ -559,7 +543,7 @@ namespace Gui
additional.emplace(73, 0x00CE); // Î (Latin Capital Letter I with Circumflex) => I (latin capital I)
additional.emplace(73, 0x00CF); // Ï (Latin Capital Letter I with Diaeresis) => I (latin capital I)
additional.emplace(68, 0x00D0); // Ð (Latin Capital Letter Eth) => D (latin capital D)
// Ñ (Latin Capital Letter N with Tilde, 0xD1) is unavailable, not replaced
additional.emplace(78, 0x00D1); // Ñ (Latin Capital Letter N with Tilde) => N (latin capital N) (custom)
additional.emplace(79, 0x00D2); // Ò (Latin Capital Letter O with Grave) => O (latin capital O)
additional.emplace(79, 0x00D3); // Ó (Latin Capital Letter O with Acute) => O (latin capital O)
additional.emplace(79, 0x00D4); // Ô (Latin Capital Letter O with Circumflex) => O (latin capital O)
@ -572,12 +556,7 @@ namespace Gui
additional.emplace(85, 0x00DB); // Û (Latin Capital Letter U with Circumflex) => U (latin capital U)
// Ü (Latin Capital Letter U with Diaeresis, 0xDC) is available
additional.emplace(89, 0x00DD); // Ý (Latin Capital Letter Y with Acute) => Y (latin capital Y)
// 0xDE to 0xFF are generally not replaced with certain exceptions
additional.emplace(97, 0x00E3); // ã (Latin Small Letter A with Tilde) => a (latin small A)
additional.emplace(100, 0x00F0); // ð (Latin Small Letter Eth) => d (latin small D)
additional.emplace(111, 0x00F5); // õ (Latin Small Letter O with Tilde) => o (latin small O)
additional.emplace(111, 0x00F8); // ø (Latin Small Letter O with Stroke) => o (latin small O)
additional.emplace(121, 0x00FD); // ý (Latin Small Letter Y with Acute) => y (latin small Y)
// 0xDE to 0xFF are not replaced
// Russian Morrowind which uses Win-1251 encoding only does equivalent (often garbage) Win-1252 replacements
// However, we'll provide custom replacements for Cyrillic io letters
@ -585,12 +564,6 @@ namespace Gui
additional.emplace(69, 0x0401); // Ё (Cyrillic Capital Letter Io) => E (latin capital E)
additional.emplace(137, 0x0451); // ё (Cyrillic Small Letter Io) => ë (latin small E-diaeresis)
// ASCII vertical bar, use this as text input cursor
additional.emplace(124, MyGUI::FontCodeType::Cursor);
// Underscore, use for NotDefined marker (used for glyphs not existing in the font)
additional.emplace(95, MyGUI::FontCodeType::NotDefined);
for (int i = 0; i < 256; i++)
{
float x1 = data[i].top_left.x * width;
@ -600,31 +573,64 @@ namespace Gui
ToUTF8::Utf8Encoder encoder(mEncoding);
unsigned long unicodeVal = getUnicode(i, encoder, mEncoding);
const std::string coord = MyGUI::utility::toString(x1) + " " + MyGUI::utility::toString(y1) + " "
+ MyGUI::utility::toString(w) + " " + MyGUI::utility::toString(h);
float advance = data[i].width + data[i].kerningRight;
// Yes MyGUI, we really do want an advance of 0 sometimes, thank you.
if (advance == 0.f && data[i].width != 0.f)
advance = std::numeric_limits<float>::min();
const std::string bearing = MyGUI::utility::toString(data[i].kerningLeft) + ' '
+ MyGUI::utility::toString((fontSize - data[i].ascent));
const MyGUI::IntSize size(static_cast<int>(data[i].width), static_cast<int>(data[i].height));
MyGUI::xml::ElementPtr code = codes->createChild("Code");
code->addAttribute("index", unicodeVal);
code->addAttribute("coord", coord);
code->addAttribute("advance", advance);
code->addAttribute("bearing", bearing);
code->addAttribute("size", size);
code->addAttribute("coord",
MyGUI::utility::toString(x1) + " " + MyGUI::utility::toString(y1) + " " + MyGUI::utility::toString(w)
+ " " + MyGUI::utility::toString(h));
code->addAttribute("advance", data[i].width);
code->addAttribute("bearing",
MyGUI::utility::toString(data[i].kerning) + " "
+ MyGUI::utility::toString((fontSize - data[i].ascent)));
code->addAttribute(
"size", MyGUI::IntSize(static_cast<int>(data[i].width), static_cast<int>(data[i].height)));
for (auto [it, end] = additional.equal_range(i); it != end; ++it)
{
code = codes->createChild("Code");
code->addAttribute("index", it->second);
code->addAttribute("coord", coord);
code->addAttribute("advance", advance);
code->addAttribute("bearing", bearing);
code->addAttribute("size", size);
code->addAttribute("coord",
MyGUI::utility::toString(x1) + " " + MyGUI::utility::toString(y1) + " "
+ MyGUI::utility::toString(w) + " " + MyGUI::utility::toString(h));
code->addAttribute("advance", data[i].width);
code->addAttribute("bearing",
MyGUI::utility::toString(data[i].kerning) + " "
+ MyGUI::utility::toString((fontSize - data[i].ascent)));
code->addAttribute(
"size", MyGUI::IntSize(static_cast<int>(data[i].width), static_cast<int>(data[i].height)));
}
// ASCII vertical bar, use this as text input cursor
if (i == 124)
{
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
cursorCode->addAttribute("index", MyGUI::FontCodeType::Cursor);
cursorCode->addAttribute("coord",
MyGUI::utility::toString(x1) + " " + MyGUI::utility::toString(y1) + " "
+ MyGUI::utility::toString(w) + " " + MyGUI::utility::toString(h));
cursorCode->addAttribute("advance", data[i].width);
cursorCode->addAttribute("bearing",
MyGUI::utility::toString(data[i].kerning) + " "
+ MyGUI::utility::toString((fontSize - data[i].ascent)));
cursorCode->addAttribute(
"size", MyGUI::IntSize(static_cast<int>(data[i].width), static_cast<int>(data[i].height)));
}
// Underscore, use for NotDefined marker (used for glyphs not existing in the font)
if (i == 95)
{
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
cursorCode->addAttribute("index", MyGUI::FontCodeType::NotDefined);
cursorCode->addAttribute("coord",
MyGUI::utility::toString(x1) + " " + MyGUI::utility::toString(y1) + " "
+ MyGUI::utility::toString(w) + " " + MyGUI::utility::toString(h));
cursorCode->addAttribute("advance", data[i].width);
cursorCode->addAttribute("bearing",
MyGUI::utility::toString(data[i].kerning) + " "
+ MyGUI::utility::toString((fontSize - data[i].ascent)));
cursorCode->addAttribute(
"size", MyGUI::IntSize(static_cast<int>(data[i].width), static_cast<int>(data[i].height)));
}
}
@ -633,19 +639,12 @@ namespace Gui
omitted.push_back(MyGUI::FontCodeType::SelectedBack);
for (const UnicodeIndex index : omitted)
{
MyGUI::xml::ElementPtr code = codes->createChild("Code");
code->addAttribute("index", index);
code->addAttribute("coord", "0 0 0 0");
code->addAttribute("advance", "0");
code->addAttribute("bearing", "0 0");
code->addAttribute("size", "0 0");
}
if (mExportFonts)
{
Log(Debug::Info) << "Writing " << name + ".xml";
xmlDocument.createDeclaration();
xmlDocument.save(name + ".xml");
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
cursorCode->addAttribute("index", index);
cursorCode->addAttribute("coord", "0 0 0 0");
cursorCode->addAttribute("advance", "0");
cursorCode->addAttribute("bearing", "0 0");
cursorCode->addAttribute("size", "0 0");
}
// Register the font with MyGUI

View file

@ -25,8 +25,7 @@ namespace Gui
class FontLoader
{
public:
/// @param exportFonts export the converted fonts (Images and XML with glyph metrics) to files?
FontLoader(ToUTF8::FromType encoding, const VFS::Manager* vfs, float scalingFactor, bool exportFonts);
FontLoader(ToUTF8::FromType encoding, const VFS::Manager* vfs, float scalingFactor);
void overrideLineHeight(MyGUI::xml::ElementPtr _node, std::string_view _file, MyGUI::Version _version);
@ -36,7 +35,6 @@ namespace Gui
ToUTF8::FromType mEncoding;
const VFS::Manager* mVFS;
float mScalingFactor;
bool mExportFonts;
void loadFonts();
void loadFont(const std::string& fontName, const std::string& fontId);

View file

@ -239,29 +239,6 @@ namespace LuaUtil
}
});
}
void Registry::clear(bool force)
{
std::vector<Info> infoToKeep;
if (!force)
{
for (const Info& info : mInfo)
if (info.mPersistent)
infoToKeep.push_back(info);
}
mKeys.clear();
mIds.clear();
mInfo.clear();
mHandlers.clear();
mBindings.clear();
mValues.clear();
mBindingTree.clear();
if (!force)
{
for (const Info& i : infoToKeep)
insert(i);
}
}
}
namespace InputTrigger
@ -315,24 +292,5 @@ namespace LuaUtil
}),
handlers.end());
}
void Registry::clear(bool force)
{
std::vector<Info> infoToKeep;
if (!force)
{
for (const Info& info : mInfo)
if (info.mPersistent)
infoToKeep.push_back(info);
}
mInfo.clear();
mHandlers.clear();
mIds.clear();
if (!force)
{
for (const Info& i : infoToKeep)
insert(i);
}
}
}
}

View file

@ -29,7 +29,6 @@ namespace LuaUtil::InputAction
std::string mName;
std::string mDescription;
sol::main_object mDefaultValue;
bool mPersistent;
};
class MultiTree
@ -74,7 +73,16 @@ namespace LuaUtil::InputAction
{
mHandlers[safeIdByKey(key)].push_back(handler);
}
void clear(bool force = false);
void clear()
{
mKeys.clear();
mIds.clear();
mInfo.clear();
mHandlers.clear();
mBindings.clear();
mValues.clear();
mBindingTree.clear();
}
private:
using Id = MultiTree::Node;
@ -102,7 +110,6 @@ namespace LuaUtil::InputTrigger
std::string mL10n;
std::string mName;
std::string mDescription;
bool mPersistent;
};
class Registry
@ -123,7 +130,12 @@ namespace LuaUtil::InputTrigger
void insert(const Info& info);
void registerHandler(std::string_view key, const LuaUtil::Callback& callback);
void activate(std::string_view key);
void clear(bool force = false);
void clear()
{
mInfo.clear();
mHandlers.clear();
mIds.clear();
}
private:
using Id = size_t;

View file

@ -32,8 +32,7 @@ namespace
// Argument names
const auto str = LuaUtil::cast<std::string>(key);
argNames.push_back(
icu::UnicodeString::fromUTF8(icu::StringPiece(str.data(), static_cast<int32_t>(str.size()))));
argNames.push_back(icu::UnicodeString::fromUTF8(icu::StringPiece(str.data(), str.size())));
}
}
}

View file

@ -11,7 +11,6 @@
#include <components/files/conversion.hpp>
#include <components/vfs/manager.hpp>
#include "luastateptr.hpp"
#include "scriptscontainer.hpp"
#include "utf8.hpp"
@ -152,37 +151,37 @@ namespace LuaUtil
return newPtr;
}
LuaStatePtr LuaState::createLuaRuntime(LuaState* luaState)
lua_State* LuaState::createLuaRuntime(LuaState* luaState)
{
if (sProfilerEnabled)
{
Log(Debug::Info) << "Initializing LuaUtil::LuaState with profiler";
LuaStatePtr state(lua_newstate(&trackingAllocator, luaState));
if (state != nullptr)
return state;
sProfilerEnabled = false;
Log(Debug::Error) << "Failed to initialize LuaUtil::LuaState with custom allocator; disabling Lua profiler";
lua_State* L = lua_newstate(&trackingAllocator, luaState);
if (L)
return L;
else
{
sProfilerEnabled = false;
Log(Debug::Error)
<< "Failed to initialize LuaUtil::LuaState with custom allocator; disabling Lua profiler";
}
}
Log(Debug::Info) << "Initializing LuaUtil::LuaState without profiler";
LuaStatePtr state(luaL_newstate());
if (state == nullptr)
throw std::runtime_error("Failed to create Lua runtime");
return state;
lua_State* L = luaL_newstate();
if (!L)
throw std::runtime_error("Can't create Lua runtime");
return L;
}
LuaState::LuaState(const VFS::Manager* vfs, const ScriptsConfiguration* conf, const LuaStateSettings& settings)
: mSettings(settings)
, mLuaState([&] {
LuaStatePtr state = createLuaRuntime(this);
sol::set_default_state(state.get());
return state;
}())
, mSol(mLuaState.get())
, mLuaHolder(createLuaRuntime(this))
, mSol(mLuaHolder.get())
, mConf(conf)
, mVFS(vfs)
{
if (sProfilerEnabled)
lua_sethook(mLuaState.get(), &countHook, LUA_MASKCOUNT, countHookStep);
lua_sethook(mLuaHolder.get(), &countHook, LUA_MASKCOUNT, countHookStep);
protectedCall([&](LuaView& view) {
auto& sol = view.sol();
@ -344,8 +343,7 @@ namespace LuaUtil
}
sol::protected_function_result LuaState::runInNewSandbox(const VFS::Path::Normalized& path,
const std::string& envName, const std::map<std::string, sol::main_object>& packages,
const sol::main_object& hiddenData)
const std::string& envName, const std::map<std::string, sol::object>& packages, const sol::object& hiddenData)
{
// TODO
sol::protected_function script = loadScriptAndCache(path);

Some files were not shown because too many files have changed in this diff Show more