In the olden days, we passed it a vector of open ESMReader instances, as they knew the filenames and sizes, so were a convenient source of this knowledge.
When the ReadersCache was introduced as a pool of readers to limit the maximum number of simultaneously open file handles (to avoid going over the OS' limit) it was a poor substitute.
* We iterate over all the earlier readers in order in a double loop, which is the worst case scenario for an LRU pool as once we're past the size limit, we're guaranteed maximum thrashing - the least recently used item is the most likely to be used next, so the worst to evict.
* We didn't want to read any ESM files, just know whether they'd been read and what their sizes were, so didn't want to open a file handle, which the ReadersCache forced us to do.
Obviously, opening lots of file handles isn't fast, and as this was an operation done for each content file which iterated over the file's masters and within that loop iterated over every loaded file, that's O(n^3) complexity in the worst case, and for things like delta plugin merged plugins, they hit the worst case in long load orders.
This resolves the freeze reported as https://gitlab.com/OpenMW/openmw/-/issues/8425, but there may be other freezes on launch.
I tested this with a USB3 external hard drive.
These two places were the only ones where we're IO-bound and block the main thread, so they're the only ones that need progress bars.
If trying to replicate this test, then it's important to unplug the hard drive between each repeat.
Apparently Windows is excellent at disk caching these days as it takes a minute and a half to start the launcher with Total Overhaul on this drive when it's just been plugged in, but less time than the first launch after a reboot on an NVME drive once the cache has been warmed up.
It's much slower than doing it on demand as it only takes a microsecond, but for a really big load order, there are hundreds of thousands of intermediate calls before everything's set up and we can draw the GUI.
Unchecking files only changes whether they're checked, and doesn't completely rearrange the table and change the number of elements it has, so we only need to change the check state, not the whole layout.
It's way faster to just query all the data once after setting a content list than it is to query the data for all files between the old and new location of a file when we change any file's location in the load order.
SHGetFolderPathW was deprecated in Windows Vista nearly two decades ago. ShGetKnownFolderPath is the replacement.
Also log if there was an error. Someone seemed to be getting an error on Discord, despite other apps being able to get the path just fine with these functions.
Also don't pass the flags to create the folders if they don't exist. We probably don't have the right permissions and if they don't exist, then there are bigger problems. Maybe this will fix the issue the user was having.
Also add a comment about global config on Windows being fundamentally wrong.
* Do not fail tile generation if debug mesh writing fails.
* Mark some functions as noexcept to better crash than have a deadlock.
* Unlock tile and remove job if there on exception while processing it.
/usr/bin/../include/c++/v1/string_view:300:42: error: implicit instantiation of undefined template 'std::char_traits<signed char>'
300 | static_assert(is_same<_CharT, typename traits_type::char_type>::value,
| ^
/home/elsid/dev/openmw/components/to_utf8/to_utf8.cpp:55:41: note: in instantiation of template class 'std::basic_string_view<signed char>' requested here
55 | std::basic_string_view<signed char> getTranslationArray(FromType sourceEncoding)
| ^
/usr/bin/../include/c++/v1/__fwd/string.h:23:29: note: template is declared here
23 | struct _LIBCPP_TEMPLATE_VIS char_traits;
| ^
std::char_traits support for non char types was removed from libc++19:
https://reviews.llvm.org/D157058.
components\lua\configuration.cpp(133): warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data
components\esm3\effectlist.cpp(35): warning C4267: '=': conversion from 'size_t' to 'uint32_t', possible loss of data
components_tests\misc\testmathutil.cpp(54): warning C4305: 'argument': truncation from 'const double' to 'osg::Vec3f::value_type'
components_tests\misc\testmathutil.cpp(62): warning C4305: 'argument': truncation from 'const double' to 'osg::Vec3f::value_type'
components_tests\misc\testmathutil.cpp(131): warning C4305: 'argument': truncation from 'const double' to 'osg::Vec3f::value_type'
components_tests\misc\testmathutil.cpp(135): warning C4305: 'argument': truncation from 'const double' to 'osg::Vec3f::value_type'
components_tests\misc\testmathutil.cpp(135): warning C4305: 'argument': truncation from 'const double' to 'osg::Vec3f::value_type'
components_tests\misc\testmathutil.cpp(139): warning C4305: 'argument': truncation from 'const double' to 'osg::Vec3f::value_type'
Previously, comments would be associated with the openmw.cfg line that followed them, but only up to the first comma.
This meant that if you had fallback=thing,otherthing and fallback=thing,thirdthing, comments above the thirdthing line would be moved above the otherthing line, even though both lines would be kept when the file was written out.
This seemed to be an attempt at a feature when cc9cii first implemented the comment preservation system, but it only seems to cause confusion.
Store original representation of paths in content lists. Also compare against existing content lists in a more forgiving way.
See merge request OpenMW/openmw!4424
Also compare against existing content lists in a more forgiving way.
The first improvement makes it possible to use relative paths in openmw.cfg without the launcher canonicalising them.
This was really annoying if you used a relative path on purpose.
It also stops the launcher converting all paths to Qt's convention, where forward slashes are used on Windows even though they're not native.
The engine doesn't care, so you could always put either in the config file, but the launcher wouldn't stand for that, and would make them match.
To make this work, we need to store a path's originalRepresentation in the content list, compare paths loaded from openmw.cfg based on their originalRepresentation, and convert paths from originalRepresentation to absolute value when loading them from a content list.
The second improvement means that paths that are equivalent, but expressed differently (e.g. mismatched case on Windows, mismatched separators on Windows, or mild differences like unnecessary `./`es and doubled separators) don't trigger the creation of a new effectively-identical content list.
To make this work, we had to switch the comparison to lexicaly normalise the path first.
It could only be lexical normalisation as originalRepresentation might be absolute, relative, or absolute-but-based-on-a-path-slug, and we didn't want slugs to break things or relative paths to count as equivalent to absolute ones that refer to the same file.
The comparison is case-insensitive on Windows, and case-sensitive elsewhere.
This isn't strictly right, as you can have case-sensitive things mounted on Windows or tell a Linux directory to be case-insensitive, but we can't tell when that might happen based on a lexical path as it depends on real directory properties (and might differ for different parts of the path, which is too much hassle to support).
Static variables should be initalized once instead of initializing them with
nullptr and then doing actual initialization behind if condition. Otherwise a
race condition may happen leading to undefined behaviour.
Boost::zlib is basically part of Boost::iostreams, and depending on how you configure Boost, it can either be a separate library or get embedded into iostreams.
With the third-party-but-linked-on-Boost's-website package we've been using for years, it's a separate library.
Before https://gitlab.com/OpenMW/openmw/-/merge_requests/4307, we needed to explicitly link with it as CMake wasn't handling transitive dependencies for us.
With vcpkg, it's embedded, and doesn't have its own CMake config, so we couldn't explicitly link with it even if we wanted to.
Now CMake *is* handling transitive dependencies for us, we don't even need to think about this library.
It's all automatic.
Boost::locale, on the other hand, used to be something we used directly (I think for doing UTF-16/UTF-8 conversions when dealing with Windows paths).
However, it isn't anymore, and we just didn't purge it from our CMake when we should have.
It can go.
Resolves https://gitlab.com/OpenMW/openmw/-/issues/8100
Also removes some old crud.
Hopefully the old crud is all:
* Handled automatically by CMake now we're using the modern approach.
* A hack-fix for a problem caused by not using the modern approach.
* Massively outdated so no longer necessary.
If it turns out this makes CI fail, I'll tweak things as necessary.
Changes that might not be wanted include:
* Getting rid of our BOOST_STATIC CMake option. In cases where the CMake config doesn't make the one correct choice from the build environment (i.e. because there's a choice) the CMake config exposes the option already.
However, we were forcing this on for Windows, so that might matter.
It seems to default to static on my machine even though I thought I read something suggesting otherwise, so we'll see how things go with that.
If we eventually put CMake in charge of installing dependency DLLs this will be a moot point as we won't need to care.
* Bumping the minimum version of Boost to 1.70.0, as that's the first with working CMake config.
It's from 2019, so plausibly there are distros too scared to use a library from five years ago as it can't legally drink in the US (although it could in limited quantities with parental supervision in the UK, as long as it's just something inconsequential like a single sip of beer).
I tried to fix https://gitlab.com/OpenMW/openmw/-/issues/8080 by making it so that instead of crashing, we showed an error.
In doing so, I discovered some problems with plugin sorting and the refresh button, like:
* it forgetting the non-user content files somewhere
* nothing guaranteeing that built-in content files stay at the top of the list and them only being there because the first data directory that provides them is usually the first data directory
* it forgetting the non-user content files somewhere else
* it looking like it'd forget any kind of non-user setting under certain circumstances
I fixed those problems too
To avoid implicit conversion via Normalized which creates NormalizedView from a
temporary Normalized. Mark constructors explicit on purpose so there is no
ambiguity on implicit conversion when there is an overloaded function like:
void f(const Normalized&);
void f(NormalizedView);