1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-10-16 17:46:37 +00:00

Merge branch 'OpenMW:master' into master

This commit is contained in:
Andy Lanzone 2025-06-01 22:57:37 -07:00 committed by GitHub
commit 51f9ce890e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 42 additions and 143 deletions

View file

@ -10,6 +10,7 @@
#include <QPair>
#include <QProgressDialog>
#include <QPushButton>
#include <QTimer>
#include <algorithm>
#include <mutex>
@ -202,8 +203,14 @@ Launcher::DataFilesPage::DataFilesPage(const Files::ConfigurationManager& cfg, C
// the addons and don't want to get signals of the system doing it during startup.
connect(mSelector, &ContentSelectorView::ContentSelector::signalAddonDataChanged, this,
&DataFilesPage::slotAddonDataChanged);
mReloadCellsTimer = new QTimer(this);
mReloadCellsTimer->setSingleShot(true);
mReloadCellsTimer->setInterval(200);
connect(mReloadCellsTimer, &QTimer::timeout, this, &DataFilesPage::onReloadCellsTimerTimeout);
// Call manually to indicate all changes to addon data during startup.
slotAddonDataChanged();
onReloadCellsTimerTimeout();
}
Launcher::DataFilesPage::~DataFilesPage()
@ -1001,6 +1008,11 @@ bool Launcher::DataFilesPage::showDeleteMessageBox(const QString& text)
}
void Launcher::DataFilesPage::slotAddonDataChanged()
{
mReloadCellsTimer->start();
}
void Launcher::DataFilesPage::onReloadCellsTimerTimeout()
{
const ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
QStringList selectedFiles;

View file

@ -17,6 +17,7 @@
class QSortFilterProxyModel;
class QAbstractItemModel;
class QMenu;
class QTimer;
namespace Files
{
@ -137,6 +138,7 @@ namespace Launcher
std::mutex mReloadCellsMutex;
std::condition_variable mStartReloadCells;
std::thread mReloadCellsThread;
QTimer* mReloadCellsTimer;
void addArchive(const QString& name, Qt::CheckState selected, int row = -1);
void addArchivesFromDir(const QString& dir);
@ -151,6 +153,7 @@ namespace Launcher
void addProfile(const QString& profile, bool setAsCurrent);
void checkForDefaultProfile();
void populateFileViews(const QString& contentModelName);
void onReloadCellsTimerTimeout();
void reloadCells();
void refreshDataFilesView();
void updateNavMeshProgress(int minDataSize);

View file

@ -193,15 +193,6 @@ namespace MWMechanics
mLevel = level;
}
void CreatureStats::modifyMagicEffects(const MagicEffects& effects)
{
bool recalc = effects.getOrDefault(ESM::MagicEffect::FortifyMaximumMagicka).getModifier()
!= mMagicEffects.getOrDefault(ESM::MagicEffect::FortifyMaximumMagicka).getModifier();
mMagicEffects.setModifiers(effects);
if (recalc)
recalculateMagicka();
}
void CreatureStats::setAiSetting(AiSetting index, Stat<int> value)
{
mAiSettings[static_cast<std::underlying_type_t<AiSetting>>(index)] = value;

View file

@ -155,9 +155,6 @@ namespace MWMechanics
void setDynamic(int index, const DynamicStat<float>& value);
/// Set Modifier for each magic effect according to \a effects. Does not touch Base values.
void modifyMagicEffects(const MagicEffects& effects);
void setAttackingOrSpell(bool attackingOrSpell) { mAttackingOrSpell = attackingOrSpell; }
void setAttackType(std::string_view attackType) { mAttackType = attackType; }

View file

@ -121,11 +121,6 @@ namespace MWMechanics
return *this;
}
void MagicEffects::remove(const EffectKey& key)
{
mCollection.erase(key);
}
void MagicEffects::add(const EffectKey& key, const EffectParam& param)
{
Collection::iterator iter = mCollection.find(key);
@ -145,19 +140,6 @@ namespace MWMechanics
mCollection[key].modifyBase(diff);
}
void MagicEffects::setModifiers(const MagicEffects& effects)
{
for (Collection::iterator it = mCollection.begin(); it != mCollection.end(); ++it)
{
it->second.setModifier(effects.getOrDefault(it->first).getModifier());
}
for (Collection::const_iterator it = effects.begin(); it != effects.end(); ++it)
{
mCollection[it->first].setModifier(it->second.getModifier());
}
}
EffectParam MagicEffects::getOrDefault(const EffectKey& key) const
{
return get(key).value_or(EffectParam());
@ -174,40 +156,6 @@ namespace MWMechanics
return std::nullopt;
}
MagicEffects MagicEffects::diff(const MagicEffects& prev, const MagicEffects& now)
{
MagicEffects result;
// adding/changing
for (Collection::const_iterator iter(now.begin()); iter != now.end(); ++iter)
{
Collection::const_iterator other = prev.mCollection.find(iter->first);
if (other == prev.end())
{
// adding
result.add(iter->first, iter->second);
}
else
{
// changing
result.add(iter->first, iter->second - other->second);
}
}
// removing
for (Collection::const_iterator iter(prev.begin()); iter != prev.end(); ++iter)
{
Collection::const_iterator other = now.mCollection.find(iter->first);
if (other == now.end())
{
result.add(iter->first, EffectParam() - iter->second);
}
}
return result;
}
void MagicEffects::writeState(ESM::MagicEffects& state) const
{
for (const auto& [key, params] : mCollection)

View file

@ -103,19 +103,12 @@ namespace MWMechanics
void writeState(ESM::MagicEffects& state) const;
void add(const EffectKey& key, const EffectParam& param);
void remove(const EffectKey& key);
void modifyBase(const EffectKey& key, int diff);
/// Copy Modifier values from \a effects, but keep original mBase values.
void setModifiers(const MagicEffects& effects);
EffectParam getOrDefault(const EffectKey& key) const;
std::optional<EffectParam> get(const EffectKey& key) const;
///< This function can safely be used for keys that are not present.
static MagicEffects diff(const MagicEffects& prev, const MagicEffects& now);
///< Return changes from \a prev to \a now.
};
std::string getMagicEffectString(

View file

@ -241,9 +241,6 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const
return false;
EsmFile* file = item(index.row());
QString fileName = file->fileName();
bool success = false;
switch (role)
{
case Qt::EditRole:
@ -257,65 +254,23 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const
file->setFileProperty(EsmFile::FileProperty_GameFile, list.at(i));
emit dataChanged(index, index);
success = true;
return true;
}
break;
case Qt::UserRole + 1:
{
success = (flags(index) & Qt::ItemIsEnabled);
if (success)
{
success = setCheckState(file, value.toBool());
emit dataChanged(index, index);
}
return isEnabled(index) && setCheckState(file, value.toBool());
}
break;
case Qt::CheckStateRole:
{
int checkValue = value.toInt();
bool setState = false;
if (file->builtIn() || file->fromAnotherConfigFile())
{
setState = false;
success = false;
}
else if (checkValue == Qt::Checked && !mCheckedFiles.contains(file))
{
setState = true;
success = true;
}
else if (checkValue == Qt::Checked && mCheckedFiles.contains(file))
setState = true;
else if (checkValue == Qt::Unchecked)
setState = true;
if (setState)
{
setCheckState(file, success);
emit dataChanged(index, index);
}
else
return success;
for (EsmFile* file2 : mFiles)
{
if (file2->gameFiles().contains(fileName, Qt::CaseInsensitive))
{
QModelIndex idx = indexFromItem(file2);
emit dataChanged(idx, idx);
}
}
success = true;
if (checkValue == Qt::Checked)
return mCheckedFiles.contains(file) || setCheckState(file, true);
if (checkValue == Qt::Unchecked)
return !mCheckedFiles.contains(file) || setCheckState(file, false);
}
break;
}
return success;
return false;
}
bool ContentSelectorModel::ContentModel::insertRows(int position, int rows, const QModelIndex& parent)
@ -709,6 +664,7 @@ void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileL
{
// setCheckState already gracefully handles builtIn and fromAnotherConfigFile
// as necessary, move plug-ins in visible list to match sequence of supplied filelist
// FIXME: setCheckState also does tons of other things which we don't want to happen
int filePosition = indexFromItem(file).row();
if (filePosition < previousPosition)
{
@ -802,38 +758,37 @@ bool ContentSelectorModel::ContentModel::setCheckState(const EsmFile* file, bool
else
mCheckedFiles.erase(file);
emit dataChanged(indexFromItem(file), indexFromItem(file));
QModelIndex fileIndex = indexFromItem(file);
emit dataChanged(fileIndex, fileIndex);
// FIXME: this should not happen per-file.
// Consider not hiding files if their game is disabled so that this is completely unnecessary.
if (file->isGameFile())
refreshModel();
// if we're checking an item, ensure all "upstream" files (dependencies) are checked as well.
// Check "upstream" files (dependencies) if the file is checked,
// uncheck downstream files if the file is unchecked.
// Update the data for downstream files unconditionally (load order warnings).
// FIXME: downstream files of toggled upstream/downstream files should be updated, but that would be slow.
if (checkState)
{
for (const QString& upstreamName : file->gameFiles())
{
const EsmFile* upstreamFile = item(upstreamName);
if (!upstreamFile)
if (upstreamFile == nullptr || !mCheckedFiles.insert(upstreamFile).second)
continue;
mCheckedFiles.insert(upstreamFile);
emit dataChanged(indexFromItem(upstreamFile), indexFromItem(upstreamFile));
QModelIndex upstreamIndex = indexFromItem(upstreamFile);
emit dataChanged(upstreamIndex, upstreamIndex);
}
}
// otherwise, if we're unchecking an item (or the file is a game file) ensure all downstream files are unchecked.
else
for (const EsmFile* otherFile : mFiles)
{
for (const EsmFile* downstreamFile : mFiles)
{
if (downstreamFile->gameFiles().contains(file->fileName(), Qt::CaseInsensitive))
{
mCheckedFiles.erase(downstreamFile);
emit dataChanged(indexFromItem(downstreamFile), indexFromItem(downstreamFile));
}
}
if (!otherFile->gameFiles().contains(file->fileName(), Qt::CaseInsensitive))
continue;
if (!checkState)
mCheckedFiles.erase(otherFile);
QModelIndex otherIndex = indexFromItem(otherFile);
emit dataChanged(otherIndex, otherIndex);
}
// Need to manually let Bloodmoon entry know if Tribunal is checked/unchecked