mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-09-11 05:20:14 -04:00
Merge branch 'OpenMW:master' into master
This commit is contained in:
commit
6185683ca3
@ -234,6 +234,7 @@
|
|||||||
Bug #8445: Launcher crashes on exit when cell name loading thread is still running
|
Bug #8445: Launcher crashes on exit when cell name loading thread is still running
|
||||||
Bug #8462: Crashes when resizing the window on macOS
|
Bug #8462: Crashes when resizing the window on macOS
|
||||||
Bug #8465: Blue screen w/ antialiasing and post-processing on macOS
|
Bug #8465: Blue screen w/ antialiasing and post-processing on macOS
|
||||||
|
Bug #8503: Camera does not handle NaN gracefully
|
||||||
Feature #1415: Infinite fall failsafe
|
Feature #1415: Infinite fall failsafe
|
||||||
Feature #2566: Handle NAM9 records for manual cell references
|
Feature #2566: Handle NAM9 records for manual cell references
|
||||||
Feature #3501: OpenMW-CS: Instance Editing - Shortcuts for axial locking
|
Feature #3501: OpenMW-CS: Instance Editing - Shortcuts for axial locking
|
||||||
|
@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...")
|
|||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 49)
|
set(OPENMW_VERSION_MINOR 49)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
set(OPENMW_LUA_API_REVISION 73)
|
set(OPENMW_LUA_API_REVISION 75)
|
||||||
set(OPENMW_POSTPROCESSING_API_REVISION 2)
|
set(OPENMW_POSTPROCESSING_API_REVISION 2)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
|
@ -365,15 +365,15 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
|||||||
|
|
||||||
QIcon containsDataIcon(":/images/openmw-plugin.png");
|
QIcon containsDataIcon(":/images/openmw-plugin.png");
|
||||||
|
|
||||||
QProgressDialog progressBar("Adding data directories", {}, 0, directories.count(), this);
|
QProgressDialog progressBar("Adding data directories", {}, 0, static_cast<int>(directories.size()), this);
|
||||||
progressBar.setWindowModality(Qt::WindowModal);
|
progressBar.setWindowModality(Qt::WindowModal);
|
||||||
progressBar.setValue(0);
|
|
||||||
|
|
||||||
std::unordered_set<QString> visitedDirectories;
|
std::unordered_set<QString> visitedDirectories;
|
||||||
for (const Config::SettingValue& currentDir : directories)
|
for (qsizetype i = 0; i < directories.size(); ++i)
|
||||||
{
|
{
|
||||||
progressBar.setValue(progressBar.value() + 1);
|
progressBar.setValue(static_cast<int>(i));
|
||||||
|
|
||||||
|
const Config::SettingValue& currentDir = directories.at(i);
|
||||||
if (!visitedDirectories.insert(currentDir.value).second)
|
if (!visitedDirectories.insert(currentDir.value).second)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -436,6 +436,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
|||||||
}
|
}
|
||||||
item->setToolTip(tooltip.join('\n'));
|
item->setToolTip(tooltip.join('\n'));
|
||||||
}
|
}
|
||||||
|
progressBar.setValue(progressBar.maximum());
|
||||||
mSelector->sortFiles();
|
mSelector->sortFiles();
|
||||||
|
|
||||||
QList<Config::SettingValue> selectedArchives = mGameSettings.getArchiveList();
|
QList<Config::SettingValue> selectedArchives = mGameSettings.getArchiveList();
|
||||||
@ -1001,7 +1002,11 @@ bool Launcher::DataFilesPage::showDeleteMessageBox(const QString& text)
|
|||||||
|
|
||||||
void Launcher::DataFilesPage::slotAddonDataChanged()
|
void Launcher::DataFilesPage::slotAddonDataChanged()
|
||||||
{
|
{
|
||||||
QStringList selectedFiles = selectedFilePaths();
|
const ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
|
||||||
|
QStringList selectedFiles;
|
||||||
|
for (const ContentSelectorModel::EsmFile* item : items)
|
||||||
|
selectedFiles.append(item->filePath());
|
||||||
|
|
||||||
if (mSelectedFiles != selectedFiles)
|
if (mSelectedFiles != selectedFiles)
|
||||||
{
|
{
|
||||||
const std::lock_guard lock(mReloadCellsMutex);
|
const std::lock_guard lock(mReloadCellsMutex);
|
||||||
@ -1013,6 +1018,7 @@ void Launcher::DataFilesPage::slotAddonDataChanged()
|
|||||||
|
|
||||||
void Launcher::DataFilesPage::reloadCells()
|
void Launcher::DataFilesPage::reloadCells()
|
||||||
{
|
{
|
||||||
|
QStringList selectedFiles;
|
||||||
std::unique_lock lock(mReloadCellsMutex);
|
std::unique_lock lock(mReloadCellsMutex);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
@ -1025,16 +1031,26 @@ void Launcher::DataFilesPage::reloadCells()
|
|||||||
if (!std::exchange(mReloadCells, false))
|
if (!std::exchange(mReloadCells, false))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
QStringList selectedFiles = mSelectedFiles;
|
const QStringList newSelectedFiles = mSelectedFiles;
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
|
QStringList filteredFiles;
|
||||||
|
for (const QString& v : newSelectedFiles)
|
||||||
|
if (QFile::exists(v))
|
||||||
|
filteredFiles.append(v);
|
||||||
|
|
||||||
|
if (selectedFiles != filteredFiles)
|
||||||
|
{
|
||||||
|
selectedFiles = std::move(filteredFiles);
|
||||||
|
|
||||||
CellNameLoader cellNameLoader;
|
CellNameLoader cellNameLoader;
|
||||||
QSet<QString> set = cellNameLoader.getCellNames(selectedFiles);
|
QSet<QString> set = cellNameLoader.getCellNames(selectedFiles);
|
||||||
QStringList cellNamesList(set.begin(), set.end());
|
QStringList cellNamesList(set.begin(), set.end());
|
||||||
std::sort(cellNamesList.begin(), cellNamesList.end());
|
std::sort(cellNamesList.begin(), cellNamesList.end());
|
||||||
|
|
||||||
emit signalLoadedCellsChanged(std::move(cellNamesList));
|
emit signalLoadedCellsChanged(std::move(cellNamesList));
|
||||||
|
}
|
||||||
|
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|
||||||
|
@ -465,7 +465,6 @@ namespace MWGui
|
|||||||
|
|
||||||
void Console::findOccurrence(const SearchDirection direction)
|
void Console::findOccurrence(const SearchDirection direction)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (mCurrentSearchTerm.empty())
|
if (mCurrentSearchTerm.empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -478,17 +477,16 @@ namespace MWGui
|
|||||||
size_t firstIndex{ 0 };
|
size_t firstIndex{ 0 };
|
||||||
size_t lastIndex{ historyText.length() };
|
size_t lastIndex{ historyText.length() };
|
||||||
|
|
||||||
// If search is not the first adjust the range based on the direction and previous occurrence.
|
// If this isn't the first search, adjust the range based on the previous occurrence.
|
||||||
if (mCurrentOccurrenceIndex != std::string::npos)
|
if (mCurrentOccurrenceIndex != std::string::npos)
|
||||||
{
|
{
|
||||||
if (direction == SearchDirection::Forward && mCurrentOccurrenceIndex > 1)
|
if (direction == SearchDirection::Forward)
|
||||||
{
|
{
|
||||||
firstIndex = mCurrentOccurrenceIndex + mCurrentOccurrenceLength;
|
firstIndex = mCurrentOccurrenceIndex + mCurrentOccurrenceLength;
|
||||||
}
|
}
|
||||||
else if (direction == SearchDirection::Reverse
|
else if (direction == SearchDirection::Reverse)
|
||||||
&& (historyText.length() - mCurrentOccurrenceIndex) > mCurrentOccurrenceLength)
|
|
||||||
{
|
{
|
||||||
lastIndex = mCurrentOccurrenceIndex - 1;
|
lastIndex = mCurrentOccurrenceIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,6 +521,13 @@ namespace MWGui
|
|||||||
void Console::findInHistoryText(const std::string& historyText, const SearchDirection direction,
|
void Console::findInHistoryText(const std::string& historyText, const SearchDirection direction,
|
||||||
const size_t firstIndex, const size_t lastIndex)
|
const size_t firstIndex, const size_t lastIndex)
|
||||||
{
|
{
|
||||||
|
if (lastIndex <= firstIndex)
|
||||||
|
{
|
||||||
|
mCurrentOccurrenceIndex = std::string::npos;
|
||||||
|
mCurrentOccurrenceLength = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mRegExSearch)
|
if (mRegExSearch)
|
||||||
{
|
{
|
||||||
findWithRegex(historyText, direction, firstIndex, lastIndex);
|
findWithRegex(historyText, direction, firstIndex, lastIndex);
|
||||||
@ -570,7 +575,7 @@ namespace MWGui
|
|||||||
const size_t firstIndex, const size_t lastIndex)
|
const size_t firstIndex, const size_t lastIndex)
|
||||||
{
|
{
|
||||||
// Search in given text interval for search term
|
// Search in given text interval for search term
|
||||||
const size_t substringLength{ (lastIndex - firstIndex) + 1 };
|
const size_t substringLength = lastIndex - firstIndex;
|
||||||
const std::string_view historyTextView((historyText.c_str() + firstIndex), substringLength);
|
const std::string_view historyTextView((historyText.c_str() + firstIndex), substringLength);
|
||||||
if (direction == SearchDirection::Forward)
|
if (direction == SearchDirection::Forward)
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <components/lua/luastate.hpp>
|
#include <components/lua/luastate.hpp>
|
||||||
#include <components/lua/utilpackage.hpp>
|
#include <components/lua/utilpackage.hpp>
|
||||||
|
#include <components/misc/finitenumbers.hpp>
|
||||||
#include <components/settings/values.hpp>
|
#include <components/settings/values.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
@ -11,11 +12,12 @@
|
|||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
|
|
||||||
using CameraMode = MWRender::Camera::Mode;
|
using CameraMode = MWRender::Camera::Mode;
|
||||||
|
|
||||||
sol::table initCameraPackage(sol::state_view lua)
|
sol::table initCameraPackage(sol::state_view lua)
|
||||||
{
|
{
|
||||||
|
using FiniteFloat = Misc::FiniteFloat;
|
||||||
|
|
||||||
MWRender::Camera* camera = MWBase::Environment::get().getWorld()->getCamera();
|
MWRender::Camera* camera = MWBase::Environment::get().getWorld()->getCamera();
|
||||||
MWRender::RenderingManager* renderingManager = MWBase::Environment::get().getWorld()->getRenderingManager();
|
MWRender::RenderingManager* renderingManager = MWBase::Environment::get().getWorld()->getRenderingManager();
|
||||||
|
|
||||||
@ -49,26 +51,27 @@ namespace MWLua
|
|||||||
api["getRoll"] = [camera]() { return -camera->getRoll(); };
|
api["getRoll"] = [camera]() { return -camera->getRoll(); };
|
||||||
|
|
||||||
api["setStaticPosition"] = [camera](const osg::Vec3f& pos) { camera->setStaticPosition(pos); };
|
api["setStaticPosition"] = [camera](const osg::Vec3f& pos) { camera->setStaticPosition(pos); };
|
||||||
api["setPitch"] = [camera](float v) {
|
api["setPitch"] = [camera](const FiniteFloat v) {
|
||||||
camera->setPitch(-v, true);
|
camera->setPitch(-v, true);
|
||||||
if (camera->getMode() == CameraMode::ThirdPerson)
|
if (camera->getMode() == CameraMode::ThirdPerson)
|
||||||
camera->calculateDeferredRotation();
|
camera->calculateDeferredRotation();
|
||||||
};
|
};
|
||||||
api["setYaw"] = [camera](float v) {
|
api["setYaw"] = [camera](const FiniteFloat v) {
|
||||||
camera->setYaw(-v, true);
|
camera->setYaw(-v, true);
|
||||||
if (camera->getMode() == CameraMode::ThirdPerson)
|
if (camera->getMode() == CameraMode::ThirdPerson)
|
||||||
camera->calculateDeferredRotation();
|
camera->calculateDeferredRotation();
|
||||||
};
|
};
|
||||||
api["setRoll"] = [camera](float v) { camera->setRoll(-v); };
|
api["setRoll"] = [camera](const FiniteFloat v) { camera->setRoll(-v); };
|
||||||
api["setExtraPitch"] = [camera](float v) { camera->setExtraPitch(-v); };
|
api["setExtraPitch"] = [camera](const FiniteFloat v) { camera->setExtraPitch(-v); };
|
||||||
api["setExtraYaw"] = [camera](float v) { camera->setExtraYaw(-v); };
|
api["setExtraYaw"] = [camera](const FiniteFloat v) { camera->setExtraYaw(-v); };
|
||||||
api["setExtraRoll"] = [camera](float v) { camera->setExtraRoll(-v); };
|
api["setExtraRoll"] = [camera](const FiniteFloat v) { camera->setExtraRoll(-v); };
|
||||||
api["getExtraPitch"] = [camera]() { return -camera->getExtraPitch(); };
|
api["getExtraPitch"] = [camera]() { return -camera->getExtraPitch(); };
|
||||||
api["getExtraYaw"] = [camera]() { return -camera->getExtraYaw(); };
|
api["getExtraYaw"] = [camera]() { return -camera->getExtraYaw(); };
|
||||||
api["getExtraRoll"] = [camera]() { return -camera->getExtraRoll(); };
|
api["getExtraRoll"] = [camera]() { return -camera->getExtraRoll(); };
|
||||||
|
|
||||||
api["getThirdPersonDistance"] = [camera]() { return camera->getCameraDistance(); };
|
api["getThirdPersonDistance"] = [camera]() { return camera->getCameraDistance(); };
|
||||||
api["setPreferredThirdPersonDistance"] = [camera](float v) { camera->setPreferredCameraDistance(v); };
|
api["setPreferredThirdPersonDistance"]
|
||||||
|
= [camera](const FiniteFloat v) { camera->setPreferredCameraDistance(v); };
|
||||||
|
|
||||||
api["getFirstPersonOffset"] = [camera]() { return camera->getFirstPersonOffset(); };
|
api["getFirstPersonOffset"] = [camera]() { return camera->getFirstPersonOffset(); };
|
||||||
api["setFirstPersonOffset"] = [camera](const osg::Vec3f& v) { camera->setFirstPersonOffset(v); };
|
api["setFirstPersonOffset"] = [camera](const osg::Vec3f& v) { camera->setFirstPersonOffset(v); };
|
||||||
@ -76,7 +79,7 @@ namespace MWLua
|
|||||||
api["getFocalPreferredOffset"] = [camera]() -> osg::Vec2f { return camera->getFocalPointTargetOffset(); };
|
api["getFocalPreferredOffset"] = [camera]() -> osg::Vec2f { return camera->getFocalPointTargetOffset(); };
|
||||||
api["setFocalPreferredOffset"] = [camera](const osg::Vec2f& v) { camera->setFocalPointTargetOffset(v); };
|
api["setFocalPreferredOffset"] = [camera](const osg::Vec2f& v) { camera->setFocalPointTargetOffset(v); };
|
||||||
api["getFocalTransitionSpeed"] = [camera]() { return camera->getFocalPointTransitionSpeed(); };
|
api["getFocalTransitionSpeed"] = [camera]() { return camera->getFocalPointTransitionSpeed(); };
|
||||||
api["setFocalTransitionSpeed"] = [camera](float v) { camera->setFocalPointTransitionSpeed(v); };
|
api["setFocalTransitionSpeed"] = [camera](const FiniteFloat v) { camera->setFocalPointTransitionSpeed(v); };
|
||||||
api["instantTransition"] = [camera]() { camera->instantTransition(); };
|
api["instantTransition"] = [camera]() { camera->instantTransition(); };
|
||||||
|
|
||||||
api["getCollisionType"] = [camera]() { return camera->getCollisionType(); };
|
api["getCollisionType"] = [camera]() { return camera->getCollisionType(); };
|
||||||
@ -86,11 +89,12 @@ namespace MWLua
|
|||||||
api["getFieldOfView"]
|
api["getFieldOfView"]
|
||||||
= [renderingManager]() { return osg::DegreesToRadians(renderingManager->getFieldOfView()); };
|
= [renderingManager]() { return osg::DegreesToRadians(renderingManager->getFieldOfView()); };
|
||||||
api["setFieldOfView"]
|
api["setFieldOfView"]
|
||||||
= [renderingManager](float v) { renderingManager->setFieldOfView(osg::RadiansToDegrees(v)); };
|
= [renderingManager](const FiniteFloat v) { renderingManager->setFieldOfView(osg::RadiansToDegrees(v)); };
|
||||||
|
|
||||||
api["getBaseViewDistance"] = [] { return Settings::camera().mViewingDistance.get(); };
|
api["getBaseViewDistance"] = [] { return Settings::camera().mViewingDistance.get(); };
|
||||||
api["getViewDistance"] = [renderingManager]() { return renderingManager->getViewDistance(); };
|
api["getViewDistance"] = [renderingManager]() { return renderingManager->getViewDistance(); };
|
||||||
api["setViewDistance"] = [renderingManager](float d) { renderingManager->setViewDistance(d, true); };
|
api["setViewDistance"]
|
||||||
|
= [renderingManager](const FiniteFloat d) { renderingManager->setViewDistance(d, true); };
|
||||||
|
|
||||||
api["getViewTransform"] = [camera]() { return LuaUtil::TransformM{ camera->getViewMatrix() }; };
|
api["getViewTransform"] = [camera]() { return LuaUtil::TransformM{ camera->getViewMatrix() }; };
|
||||||
|
|
||||||
|
@ -100,7 +100,8 @@ namespace MWLua
|
|||||||
stats.land(true);
|
stats.land(true);
|
||||||
stats.setTeleported(true);
|
stats.setTeleported(true);
|
||||||
world->getPlayer().setTeleported(true);
|
world->getPlayer().setTeleported(true);
|
||||||
world->changeToCell(destCell->getCell()->getId(), toPos(pos, rot), false);
|
bool differentCell = ptr.getCell() != destCell;
|
||||||
|
world->changeToCell(destCell->getCell()->getId(), toPos(pos, rot), false, differentCell);
|
||||||
MWWorld::Ptr newPtr = world->getPlayerPtr();
|
MWWorld::Ptr newPtr = world->getPlayerPtr();
|
||||||
world->moveObject(newPtr, pos);
|
world->moveObject(newPtr, pos);
|
||||||
world->rotateObject(newPtr, rot);
|
world->rotateObject(newPtr, rot);
|
||||||
@ -350,7 +351,7 @@ namespace MWLua
|
|||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"The argument of `activateBy` must be an actor who activates the object. Got: "
|
"The argument of `activateBy` must be an actor who activates the object. Got: "
|
||||||
+ actor.toString());
|
+ actor.toString());
|
||||||
if (objPtr.getRefData().activate())
|
|
||||||
MWBase::Environment::get().getLuaManager()->objectActivated(objPtr, actorPtr);
|
MWBase::Environment::get().getLuaManager()->objectActivated(objPtr, actorPtr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -160,26 +160,31 @@ namespace MWLua
|
|||||||
else
|
else
|
||||||
return LuaUtil::toLuaIndex(index);
|
return LuaUtil::toLuaIndex(index);
|
||||||
};
|
};
|
||||||
layersTable["insertAfter"] = [context](
|
layersTable["insertAfter"] = [context](std::string afterName, std::string_view name, const sol::object& opt) {
|
||||||
std::string_view afterName, std::string_view name, const sol::object& opt) {
|
|
||||||
LuaUi::Layer::Options options;
|
LuaUi::Layer::Options options;
|
||||||
options.mInteractive = LuaUtil::getValueOrDefault(LuaUtil::getFieldOrNil(opt, "interactive"), true);
|
options.mInteractive = LuaUtil::getValueOrDefault(LuaUtil::getFieldOrNil(opt, "interactive"), true);
|
||||||
|
context.mLuaManager->addAction(
|
||||||
|
[=]() {
|
||||||
size_t index = LuaUi::Layer::indexOf(afterName);
|
size_t index = LuaUi::Layer::indexOf(afterName);
|
||||||
if (index == LuaUi::Layer::count())
|
if (index == LuaUi::Layer::count())
|
||||||
throw std::logic_error(std::string("Layer not found"));
|
throw std::logic_error(
|
||||||
index++;
|
Misc::StringUtils::format("Couldn't insert after non-existent layer %s", afterName));
|
||||||
context.mLuaManager->addAction(
|
LuaUi::Layer::insert(index + 1, name, options);
|
||||||
[=, name = std::string(name)]() { LuaUi::Layer::insert(index, name, options); }, "Insert UI layer");
|
},
|
||||||
|
"Insert after UI layer");
|
||||||
};
|
};
|
||||||
layersTable["insertBefore"] = [context](
|
layersTable["insertBefore"] = [context](std::string beforeName, std::string_view name, const sol::object& opt) {
|
||||||
std::string_view beforename, std::string_view name, const sol::object& opt) {
|
|
||||||
LuaUi::Layer::Options options;
|
LuaUi::Layer::Options options;
|
||||||
options.mInteractive = LuaUtil::getValueOrDefault(LuaUtil::getFieldOrNil(opt, "interactive"), true);
|
options.mInteractive = LuaUtil::getValueOrDefault(LuaUtil::getFieldOrNil(opt, "interactive"), true);
|
||||||
size_t index = LuaUi::Layer::indexOf(beforename);
|
|
||||||
if (index == LuaUi::Layer::count())
|
|
||||||
throw std::logic_error(std::string("Layer not found"));
|
|
||||||
context.mLuaManager->addAction(
|
context.mLuaManager->addAction(
|
||||||
[=, name = std::string(name)]() { LuaUi::Layer::insert(index, name, options); }, "Insert UI layer");
|
[=]() {
|
||||||
|
size_t index = LuaUi::Layer::indexOf(beforeName);
|
||||||
|
if (index == LuaUi::Layer::count())
|
||||||
|
throw std::logic_error(
|
||||||
|
Misc::StringUtils::format("Couldn't insert before non-existent layer %s", beforeName));
|
||||||
|
LuaUi::Layer::insert(index, name, options);
|
||||||
|
},
|
||||||
|
"Insert before UI layer");
|
||||||
};
|
};
|
||||||
sol::table layers = LuaUtil::makeReadOnly(layersTable);
|
sol::table layers = LuaUtil::makeReadOnly(layersTable);
|
||||||
sol::table layersMeta = layers[sol::metatable_key];
|
sol::table layersMeta = layers[sol::metatable_key];
|
||||||
|
@ -1388,6 +1388,7 @@ namespace MWMechanics
|
|||||||
// Note: we do not disable unequipping animation automatically to avoid body desync
|
// Note: we do not disable unequipping animation automatically to avoid body desync
|
||||||
weapgroup = getWeaponAnimation(mWeaponType);
|
weapgroup = getWeaponAnimation(mWeaponType);
|
||||||
int unequipMask = MWRender::BlendMask_All;
|
int unequipMask = MWRender::BlendMask_All;
|
||||||
|
mUpperBodyState = UpperBodyState::Unequipping;
|
||||||
bool useShieldAnims = mAnimation->useShieldAnimations();
|
bool useShieldAnims = mAnimation->useShieldAnimations();
|
||||||
if (useShieldAnims && mWeaponType != ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell
|
if (useShieldAnims && mWeaponType != ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell
|
||||||
&& !(mWeaponType == ESM::Weapon::None && weaptype == ESM::Weapon::Spell))
|
&& !(mWeaponType == ESM::Weapon::None && weaptype == ESM::Weapon::Spell))
|
||||||
@ -1402,7 +1403,6 @@ namespace MWMechanics
|
|||||||
mAnimation->disable(weapgroup);
|
mAnimation->disable(weapgroup);
|
||||||
playBlendedAnimation(
|
playBlendedAnimation(
|
||||||
weapgroup, priorityWeapon, unequipMask, false, 1.0f, "unequip start", "unequip stop", 0.0f, 0);
|
weapgroup, priorityWeapon, unequipMask, false, 1.0f, "unequip start", "unequip stop", 0.0f, 0);
|
||||||
mUpperBodyState = UpperBodyState::Unequipping;
|
|
||||||
|
|
||||||
mAnimation->detachArrow();
|
mAnimation->detachArrow();
|
||||||
|
|
||||||
@ -1447,6 +1447,7 @@ namespace MWMechanics
|
|||||||
{
|
{
|
||||||
mAnimation->showWeapons(false);
|
mAnimation->showWeapons(false);
|
||||||
int equipMask = MWRender::BlendMask_All;
|
int equipMask = MWRender::BlendMask_All;
|
||||||
|
mUpperBodyState = UpperBodyState::Equipping;
|
||||||
if (useShieldAnims && weaptype != ESM::Weapon::Spell)
|
if (useShieldAnims && weaptype != ESM::Weapon::Spell)
|
||||||
{
|
{
|
||||||
equipMask = equipMask | ~MWRender::BlendMask_LeftArm;
|
equipMask = equipMask | ~MWRender::BlendMask_LeftArm;
|
||||||
@ -1459,7 +1460,6 @@ namespace MWMechanics
|
|||||||
playBlendedAnimation(weapgroup, priorityWeapon, equipMask, true, 1.0f, "equip start",
|
playBlendedAnimation(weapgroup, priorityWeapon, equipMask, true, 1.0f, "equip start",
|
||||||
"equip stop", 0.0f, 0);
|
"equip stop", 0.0f, 0);
|
||||||
}
|
}
|
||||||
mUpperBodyState = UpperBodyState::Equipping;
|
|
||||||
|
|
||||||
// If we do not have the "equip attach" key, show weapon manually.
|
// If we do not have the "equip attach" key, show weapon manually.
|
||||||
if (weaptype != ESM::Weapon::Spell
|
if (weaptype != ESM::Weapon::Spell
|
||||||
|
@ -38,19 +38,19 @@ void Config::GameSettings::validatePaths()
|
|||||||
|
|
||||||
mDataDirs.clear();
|
mDataDirs.clear();
|
||||||
|
|
||||||
QProgressDialog progressBar("Validating paths", {}, 0, paths.count() + 1);
|
QProgressDialog progressBar("Validating paths", {}, 0, static_cast<int>(paths.size() + 1));
|
||||||
progressBar.setWindowModality(Qt::WindowModal);
|
progressBar.setWindowModality(Qt::WindowModal);
|
||||||
progressBar.setValue(0);
|
progressBar.setValue(0);
|
||||||
|
|
||||||
for (const auto& dataDir : paths)
|
for (const auto& dataDir : paths)
|
||||||
{
|
{
|
||||||
progressBar.setValue(progressBar.value() + 1);
|
|
||||||
if (QDir(dataDir.value).exists())
|
if (QDir(dataDir.value).exists())
|
||||||
{
|
{
|
||||||
SettingValue copy = dataDir;
|
SettingValue copy = dataDir;
|
||||||
copy.value = QDir(dataDir.value).canonicalPath();
|
copy.value = QDir(dataDir.value).canonicalPath();
|
||||||
mDataDirs.append(copy);
|
mDataDirs.append(copy);
|
||||||
}
|
}
|
||||||
|
progressBar.setValue(progressBar.value() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do the same for data-local
|
// Do the same for data-local
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
|
#include <QProgressDialog>
|
||||||
|
|
||||||
#include <components/esm/format.hpp>
|
#include <components/esm/format.hpp>
|
||||||
#include <components/esm3/esmreader.hpp>
|
#include <components/esm3/esmreader.hpp>
|
||||||
@ -116,37 +117,26 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex& index
|
|||||||
if (file == mGameFile)
|
if (file == mGameFile)
|
||||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
|
||||||
|
|
||||||
Qt::ItemFlags returnFlags;
|
// files with no dependencies can always be checked
|
||||||
|
if (file->gameFiles().empty())
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
|
||||||
|
|
||||||
// addon can be checked if its gamefile is
|
// Show the file if the game it is for is enabled.
|
||||||
// ... special case, addon with no dependency can be used with any gamefile.
|
// NB: The file may theoretically depend on multiple games.
|
||||||
bool gamefileChecked = false;
|
// Early exit means that a file is visible only if its earliest found game dependency is enabled.
|
||||||
bool noGameFiles = true;
|
// This can be counterintuitive, but it is okay for non-bizarre content setups. And also faster.
|
||||||
for (const QString& fileName : file->gameFiles())
|
for (const EsmFile* depFile : mFiles)
|
||||||
{
|
{
|
||||||
for (QListIterator<EsmFile*> dependencyIter(mFiles); dependencyIter.hasNext(); dependencyIter.next())
|
if (depFile->isGameFile() && file->gameFiles().contains(depFile->fileName(), Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
// compare filenames only. Multiple instances
|
if (!depFile->builtIn() && !depFile->fromAnotherConfigFile() && !mCheckedFiles.contains(depFile))
|
||||||
// of the filename (with different paths) is not relevant here.
|
|
||||||
EsmFile* depFile = dependencyIter.peekNext();
|
|
||||||
if (!depFile->isGameFile() || depFile->fileName().compare(fileName, Qt::CaseInsensitive) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
noGameFiles = false;
|
|
||||||
if (depFile->builtIn() || depFile->fromAnotherConfigFile() || mCheckedFiles.contains(depFile))
|
|
||||||
{
|
|
||||||
gamefileChecked = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gamefileChecked || noGameFiles)
|
return Qt::NoItemFlags;
|
||||||
{
|
|
||||||
returnFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnFlags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int role) const
|
QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int role) const
|
||||||
@ -278,7 +268,7 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const
|
|||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
success = setCheckState(file->filePath(), value.toBool());
|
success = setCheckState(file, value.toBool());
|
||||||
emit dataChanged(index, index);
|
emit dataChanged(index, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,7 +295,7 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const
|
|||||||
|
|
||||||
if (setState)
|
if (setState)
|
||||||
{
|
{
|
||||||
setCheckState(file->filePath(), success);
|
setCheckState(file, success);
|
||||||
emit dataChanged(index, index);
|
emit dataChanged(index, index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -707,14 +697,18 @@ bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile* file) c
|
|||||||
|
|
||||||
void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileList)
|
void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileList)
|
||||||
{
|
{
|
||||||
|
QProgressDialog progressDialog("Setting content list", {}, 0, static_cast<int>(fileList.size()));
|
||||||
|
progressDialog.setWindowModality(Qt::WindowModal);
|
||||||
|
progressDialog.setValue(0);
|
||||||
|
|
||||||
int previousPosition = -1;
|
int previousPosition = -1;
|
||||||
for (const QString& filepath : fileList)
|
for (qsizetype i = 0, n = fileList.size(); i < n; ++i)
|
||||||
{
|
{
|
||||||
if (setCheckState(filepath, true))
|
const EsmFile* file = item(fileList[i]);
|
||||||
|
if (setCheckState(file, true))
|
||||||
{
|
{
|
||||||
// setCheckState already gracefully handles builtIn and fromAnotherConfigFile
|
// setCheckState already gracefully handles builtIn and fromAnotherConfigFile
|
||||||
// as necessary, move plug-ins in visible list to match sequence of supplied filelist
|
// as necessary, move plug-ins in visible list to match sequence of supplied filelist
|
||||||
const EsmFile* file = item(filepath);
|
|
||||||
int filePosition = indexFromItem(file).row();
|
int filePosition = indexFromItem(file).row();
|
||||||
if (filePosition < previousPosition)
|
if (filePosition < previousPosition)
|
||||||
{
|
{
|
||||||
@ -725,8 +719,11 @@ void ContentSelectorModel::ContentModel::setContentList(const QStringList& fileL
|
|||||||
previousPosition = filePosition;
|
previousPosition = filePosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progressDialog.setValue(static_cast<int>(i + 1));
|
||||||
}
|
}
|
||||||
emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
|
|
||||||
|
refreshModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::checkForLoadOrderErrors(
|
QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::checkForLoadOrderErrors(
|
||||||
@ -790,18 +787,13 @@ QString ContentSelectorModel::ContentModel::toolTip(const EsmFile* file) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorModel::ContentModel::refreshModel()
|
void ContentSelectorModel::ContentModel::refreshModel(std::initializer_list<int> roles)
|
||||||
{
|
{
|
||||||
emit dataChanged(index(0, 0), index(rowCount() - 1, 0));
|
emit dataChanged(index(0, 0), index(rowCount() - 1, 0), roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContentSelectorModel::ContentModel::setCheckState(const QString& filepath, bool checkState)
|
bool ContentSelectorModel::ContentModel::setCheckState(const EsmFile* file, bool checkState)
|
||||||
{
|
{
|
||||||
if (filepath.isEmpty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const EsmFile* file = item(filepath);
|
|
||||||
|
|
||||||
if (!file || file->builtIn() || file->fromAnotherConfigFile())
|
if (!file || file->builtIn() || file->fromAnotherConfigFile())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -810,7 +802,7 @@ bool ContentSelectorModel::ContentModel::setCheckState(const QString& filepath,
|
|||||||
else
|
else
|
||||||
mCheckedFiles.erase(file);
|
mCheckedFiles.erase(file);
|
||||||
|
|
||||||
emit dataChanged(indexFromItem(item(filepath)), indexFromItem(item(filepath)));
|
emit dataChanged(indexFromItem(file), indexFromItem(file));
|
||||||
|
|
||||||
if (file->isGameFile())
|
if (file->isGameFile())
|
||||||
refreshModel();
|
refreshModel();
|
||||||
@ -835,10 +827,7 @@ bool ContentSelectorModel::ContentModel::setCheckState(const QString& filepath,
|
|||||||
{
|
{
|
||||||
for (const EsmFile* downstreamFile : mFiles)
|
for (const EsmFile* downstreamFile : mFiles)
|
||||||
{
|
{
|
||||||
QFileInfo fileInfo(filepath);
|
if (downstreamFile->gameFiles().contains(file->fileName(), Qt::CaseInsensitive))
|
||||||
QString filename = fileInfo.fileName();
|
|
||||||
|
|
||||||
if (downstreamFile->gameFiles().contains(filename, Qt::CaseInsensitive))
|
|
||||||
{
|
{
|
||||||
mCheckedFiles.erase(downstreamFile);
|
mCheckedFiles.erase(downstreamFile);
|
||||||
|
|
||||||
@ -878,5 +867,5 @@ ContentSelectorModel::ContentFileList ContentSelectorModel::ContentModel::checke
|
|||||||
void ContentSelectorModel::ContentModel::uncheckAll()
|
void ContentSelectorModel::ContentModel::uncheckAll()
|
||||||
{
|
{
|
||||||
mCheckedFiles.clear();
|
mCheckedFiles.clear();
|
||||||
emit dataChanged(index(0, 0), index(rowCount(), columnCount()), { Qt::CheckStateRole, Qt::UserRole + 1 });
|
refreshModel({ Qt::CheckStateRole, Qt::UserRole + 1 });
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ namespace ContentSelectorModel
|
|||||||
void setCurrentGameFile(const EsmFile* file);
|
void setCurrentGameFile(const EsmFile* file);
|
||||||
|
|
||||||
bool isEnabled(const QModelIndex& index) const;
|
bool isEnabled(const QModelIndex& index) const;
|
||||||
bool setCheckState(const QString& filepath, bool isChecked);
|
bool setCheckState(const EsmFile* file, bool isChecked);
|
||||||
bool isNew(const QString& filepath) const;
|
bool isNew(const QString& filepath) const;
|
||||||
void setNew(const QString& filepath, bool isChecked);
|
void setNew(const QString& filepath, bool isChecked);
|
||||||
void setNonUserContent(const QStringList& fileList);
|
void setNonUserContent(const QStringList& fileList);
|
||||||
@ -67,7 +67,7 @@ namespace ContentSelectorModel
|
|||||||
ContentFileList checkedItems() const;
|
ContentFileList checkedItems() const;
|
||||||
void uncheckAll();
|
void uncheckAll();
|
||||||
|
|
||||||
void refreshModel();
|
void refreshModel(std::initializer_list<int> roles = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addFile(EsmFile* file);
|
void addFile(EsmFile* file);
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
|
|
||||||
ContentSelectorModel::EsmFile::EsmFile(const QString& fileName, ModelItem* parent)
|
ContentSelectorModel::EsmFile::EsmFile(const QString& fileName, ModelItem* parent)
|
||||||
: ModelItem(parent)
|
: ModelItem(parent)
|
||||||
, mFileName(fileName)
|
|
||||||
{
|
{
|
||||||
|
setFileName(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorModel::EsmFile::setFileName(const QString& fileName)
|
void ContentSelectorModel::EsmFile::setFileName(const QString& fileName)
|
||||||
{
|
{
|
||||||
mFileName = fileName;
|
mFileName = fileName;
|
||||||
|
mHasGameExtension = (mFileName.endsWith(QLatin1String(".esm"), Qt::CaseInsensitive)
|
||||||
|
|| mFileName.endsWith(QLatin1String(".omwgame"), Qt::CaseInsensitive));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorModel::EsmFile::setAuthor(const QString& author)
|
void ContentSelectorModel::EsmFile::setAuthor(const QString& author)
|
||||||
@ -53,9 +55,7 @@ void ContentSelectorModel::EsmFile::setFromAnotherConfigFile(bool fromAnotherCon
|
|||||||
|
|
||||||
bool ContentSelectorModel::EsmFile::isGameFile() const
|
bool ContentSelectorModel::EsmFile::isGameFile() const
|
||||||
{
|
{
|
||||||
return (mGameFiles.size() == 0)
|
return mHasGameExtension && mGameFiles.empty();
|
||||||
&& (mFileName.endsWith(QLatin1String(".esm"), Qt::CaseInsensitive)
|
|
||||||
|| mFileName.endsWith(QLatin1String(".omwgame"), Qt::CaseInsensitive));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant ContentSelectorModel::EsmFile::fileProperty(const FileProperty prop) const
|
QVariant ContentSelectorModel::EsmFile::fileProperty(const FileProperty prop) const
|
||||||
@ -108,7 +108,7 @@ void ContentSelectorModel::EsmFile::setFileProperty(const FileProperty prop, con
|
|||||||
switch (prop)
|
switch (prop)
|
||||||
{
|
{
|
||||||
case FileProperty_FileName:
|
case FileProperty_FileName:
|
||||||
mFileName = value;
|
setFileName(value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FileProperty_Author:
|
case FileProperty_Author:
|
||||||
|
@ -102,6 +102,7 @@ namespace ContentSelectorModel
|
|||||||
QString mToolTip;
|
QString mToolTip;
|
||||||
bool mBuiltIn = false;
|
bool mBuiltIn = false;
|
||||||
bool mFromAnotherConfigFile = false;
|
bool mFromAnotherConfigFile = false;
|
||||||
|
bool mHasGameExtension = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QModelIndex>
|
#include <QModelIndex>
|
||||||
|
#include <QProgressDialog>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
ContentSelectorView::ContentSelector::ContentSelector(QWidget* parent, bool showOMWScripts)
|
ContentSelectorView::ContentSelector::ContentSelector(QWidget* parent, bool showOMWScripts)
|
||||||
@ -156,7 +157,7 @@ void ContentSelectorView::ContentSelector::setGameFile(const QString& filename)
|
|||||||
index = ui->gameFileView->findText(file->fileName());
|
index = ui->gameFileView->findText(file->fileName());
|
||||||
|
|
||||||
// verify that the current index is also checked in the model
|
// verify that the current index is also checked in the model
|
||||||
if (!mContentModel->setCheckState(filename, true))
|
if (!mContentModel->setCheckState(file, true))
|
||||||
{
|
{
|
||||||
// throw error in case file not found?
|
// throw error in case file not found?
|
||||||
return;
|
return;
|
||||||
@ -292,27 +293,33 @@ void ContentSelectorView::ContentSelector::slotShowContextMenu(const QPoint& pos
|
|||||||
mContextMenu->exec(globalPos);
|
mContextMenu->exec(globalPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorView::ContentSelector::setCheckStateForMultiSelectedItems(bool checked)
|
void ContentSelectorView::ContentSelector::setCheckStateForMultiSelectedItems(Qt::CheckState checkState)
|
||||||
{
|
{
|
||||||
Qt::CheckState checkState = checked ? Qt::Checked : Qt::Unchecked;
|
const QModelIndexList selectedIndexes = ui->addonView->selectionModel()->selectedIndexes();
|
||||||
for (const QModelIndex& index : ui->addonView->selectionModel()->selectedIndexes())
|
|
||||||
|
QProgressDialog progressDialog("Updating content selection", {}, 0, static_cast<int>(selectedIndexes.size()));
|
||||||
|
progressDialog.setWindowModality(Qt::WindowModal);
|
||||||
|
progressDialog.setValue(0);
|
||||||
|
|
||||||
|
for (qsizetype i = 0, n = selectedIndexes.size(); i < n; ++i)
|
||||||
{
|
{
|
||||||
QModelIndex sourceIndex = mAddonProxyModel->mapToSource(index);
|
const QModelIndex sourceIndex = mAddonProxyModel->mapToSource(selectedIndexes[i]);
|
||||||
|
|
||||||
if (mContentModel->data(sourceIndex, Qt::CheckStateRole).toInt() != checkState)
|
if (mContentModel->data(sourceIndex, Qt::CheckStateRole).toInt() != checkState)
|
||||||
{
|
|
||||||
mContentModel->setData(sourceIndex, checkState, Qt::CheckStateRole);
|
mContentModel->setData(sourceIndex, checkState, Qt::CheckStateRole);
|
||||||
}
|
|
||||||
|
progressDialog.setValue(static_cast<int>(i + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorView::ContentSelector::slotUncheckMultiSelectedItems()
|
void ContentSelectorView::ContentSelector::slotUncheckMultiSelectedItems()
|
||||||
{
|
{
|
||||||
setCheckStateForMultiSelectedItems(false);
|
setCheckStateForMultiSelectedItems(Qt::Unchecked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorView::ContentSelector::slotCheckMultiSelectedItems()
|
void ContentSelectorView::ContentSelector::slotCheckMultiSelectedItems()
|
||||||
{
|
{
|
||||||
setCheckStateForMultiSelectedItems(true);
|
setCheckStateForMultiSelectedItems(Qt::Checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorView::ContentSelector::slotCopySelectedItemsPaths()
|
void ContentSelectorView::ContentSelector::slotCopySelectedItemsPaths()
|
||||||
|
@ -69,7 +69,7 @@ namespace ContentSelectorView
|
|||||||
void buildAddonView();
|
void buildAddonView();
|
||||||
void buildContextMenu();
|
void buildContextMenu();
|
||||||
void setGameFileSelected(int index, bool selected);
|
void setGameFileSelected(int index, bool selected);
|
||||||
void setCheckStateForMultiSelectedItems(bool checked);
|
void setCheckStateForMultiSelectedItems(Qt::CheckState checkState);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void signalCurrentGamefileIndexChanged(int);
|
void signalCurrentGamefileIndexChanged(int);
|
||||||
|
45
components/misc/finitenumbers.hpp
Normal file
45
components/misc/finitenumbers.hpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef OPENMW_COMPONENTS_MISC_FINITENUMBERS_HPP
|
||||||
|
#define OPENMW_COMPONENTS_MISC_FINITENUMBERS_HPP
|
||||||
|
|
||||||
|
#include <components/lua/luastate.hpp>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace Misc
|
||||||
|
{
|
||||||
|
struct FiniteFloat
|
||||||
|
{
|
||||||
|
float mValue;
|
||||||
|
FiniteFloat(float v)
|
||||||
|
{
|
||||||
|
if (!std::isfinite(v))
|
||||||
|
throw std::invalid_argument("Value must be a finite number");
|
||||||
|
mValue = v;
|
||||||
|
}
|
||||||
|
operator float() const { return mValue; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sol
|
||||||
|
{
|
||||||
|
using FiniteFloat = Misc::FiniteFloat;
|
||||||
|
|
||||||
|
template <typename Handler>
|
||||||
|
bool sol_lua_check(
|
||||||
|
sol::types<FiniteFloat>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking)
|
||||||
|
{
|
||||||
|
bool success = sol::stack::check<float>(L, lua_absindex(L, index), handler);
|
||||||
|
tracking.use(1);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FiniteFloat sol_lua_get(sol::types<FiniteFloat>, lua_State* L, int index, sol::stack::record& tracking)
|
||||||
|
{
|
||||||
|
float val = sol::stack::get<float>(L, lua_absindex(L, index));
|
||||||
|
tracking.use(1);
|
||||||
|
return FiniteFloat(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -104,6 +104,8 @@ namespace SceneUtil
|
|||||||
("shadowTexture" + std::to_string(i - mShadowSettings->getBaseShadowTextureUnit())).c_str(),
|
("shadowTexture" + std::to_string(i - mShadowSettings->getBaseShadowTextureUnit())).c_str(),
|
||||||
static_cast<int>(i)));
|
static_cast<int>(i)));
|
||||||
}
|
}
|
||||||
|
stateset.addUniform(new osg::Uniform("maximumShadowMapDistance", 0.00001f));
|
||||||
|
stateset.addUniform(new osg::Uniform("shadowFadeStart", 0.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
ShadowManager::ShadowManager(osg::ref_ptr<osg::Group> sceneRoot, osg::ref_ptr<osg::Group> rootNode,
|
ShadowManager::ShadowManager(osg::ref_ptr<osg::Group> sceneRoot, osg::ref_ptr<osg::Group> rootNode,
|
||||||
|
@ -95,7 +95,7 @@ namespace Terrain
|
|||||||
if (!terrainNode)
|
if (!terrainNode)
|
||||||
return; // no terrain defined
|
return; // no terrain defined
|
||||||
|
|
||||||
TerrainGrid::World::loadCell(x, y);
|
Terrain::World::loadCell(x, y);
|
||||||
|
|
||||||
mTerrainRoot->addChild(terrainNode);
|
mTerrainRoot->addChild(terrainNode);
|
||||||
|
|
||||||
|
@ -7,5 +7,6 @@
|
|||||||
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw_aux.time <Package openmw_aux.time>` | everywhere | | Timers and game time utils |
|
|:ref:`openmw_aux.time <Package openmw_aux.time>` | everywhere | | Timers and game time utils |
|
||||||
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw_aux.ui <Package openmw_aux.ui>` | by player scripts | | User interface utils |
|
|:ref:`openmw_aux.ui <Package openmw_aux.ui>` | by player and menu | | User interface utils |
|
||||||
|
| | scripts | |
|
||||||
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+---------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
@ -34,10 +34,10 @@
|
|||||||
- | Control, extend, and override skill progression of the
|
- | Control, extend, and override skill progression of the
|
||||||
| player.
|
| player.
|
||||||
* - :ref:`Settings <Interface Settings>`
|
* - :ref:`Settings <Interface Settings>`
|
||||||
- by player and global scripts
|
- by player, menu, and global scripts
|
||||||
- Save, display and track changes of setting values.
|
- Save, display and track changes of setting values.
|
||||||
* - :ref:`MWUI <Interface MWUI>`
|
* - :ref:`MWUI <Interface MWUI>`
|
||||||
- by player scripts
|
- by player and menu scripts
|
||||||
- Morrowind-style UI templates.
|
- Morrowind-style UI templates.
|
||||||
* - :ref:`UI <Interface UI>`
|
* - :ref:`UI <Interface UI>`
|
||||||
- by player scripts
|
- by player scripts
|
||||||
|
@ -1,43 +1,48 @@
|
|||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
| Package | Can be used | Description |
|
| Package | Can be used | Description |
|
||||||
+============================================================+====================+===============================================================+
|
+============================================================+====================+===============================================================+
|
||||||
|:ref:`openmw.interfaces <Script interfaces>` | everywhere | | Public interfaces of other scripts. |
|
|:ref:`openmw.ambient <Package openmw.ambient>` | by player and menu | | Controls background sounds for given player. |
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
| | scripts | |
|
||||||
|:ref:`openmw.util <Package openmw.util>` | everywhere | | Defines utility functions and classes like 3D vectors, |
|
|
||||||
| | | | that don't depend on the game world. |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.storage <Package openmw.storage>` | everywhere | | Storage API. In particular can be used to store data |
|
|
||||||
| | | | between game sessions. |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.core <Package openmw.core>` | everywhere | | Functions that are common for both global and local scripts |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.types <Package openmw.types>` | everywhere | | Functions for specific types of game objects. |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw.animation <Package openmw.animation>` | everywhere | | Animation controls |
|
|:ref:`openmw.animation <Package openmw.animation>` | everywhere | | Animation controls |
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw.async <Package openmw.async>` | everywhere | | Timers and callbacks. |
|
|:ref:`openmw.async <Package openmw.async>` | everywhere | | Timers and callbacks. |
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw.vfs <Package openmw.vfs>` | everywhere | | Read-only access to data directories via VFS. |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.markup <Package openmw.markup>` | everywhere | | API to work with markup languages. |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.world <Package openmw.world>` | by global scripts | | Read-write access to the game world. |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.self <Package openmw.self>` | by local scripts | | Full access to the object the script is attached to. |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.nearby <Package openmw.nearby>` | by local scripts | | Read-only access to the nearest area of the game world. |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.ambient <Package openmw.ambient>` | by player scripts | | Controls background sounds for given player. |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.input <Package openmw.input>` | by player scripts | | User input. |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.ui <Package openmw.ui>` | by player scripts | | Controls :ref:`user interface <User interface reference>`. |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.menu <Package openmw.menu>` | by menu scripts | | Main menu functionality, such as managing game saves |
|
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
|
||||||
|:ref:`openmw.camera <Package openmw.camera>` | by player scripts | | Controls camera. |
|
|:ref:`openmw.camera <Package openmw.camera>` | by player scripts | | Controls camera. |
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw.postprocessing <Package openmw.postprocessing>`| by player scripts | | Controls post-process shaders. |
|
|:ref:`openmw.core <Package openmw.core>` | everywhere | | Functions that are common for both global and local scripts |
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|:ref:`openmw.debug <Package openmw.debug>` | by player scripts | | Collection of debug utils. |
|
|:ref:`openmw.debug <Package openmw.debug>` | by player scripts | | Collection of debug utils. |
|
||||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.input <Package openmw.input>` | by player and menu | | User input. |
|
||||||
|
| | scripts | |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.interfaces <Script interfaces>` | everywhere | | Public interfaces of other scripts. |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.markup <Package openmw.markup>` | everywhere | | API to work with markup languages. |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.menu <Package openmw.menu>` | by menu scripts | | Main menu functionality, such as managing game saves |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.nearby <Package openmw.nearby>` | by local and | | Read-only access to the nearest area of the game world. |
|
||||||
|
| | player scripts | |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.postprocessing <Package openmw.postprocessing>`| by player scripts | | Controls post-process shaders. |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.self <Package openmw.self>` | by local and | | Full access to the object the script is attached to. |
|
||||||
|
| | player scripts | |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.storage <Package openmw.storage>` | everywhere | | Storage API. In particular can be used to store data |
|
||||||
|
| | | | between game sessions. |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.types <Package openmw.types>` | everywhere | | Functions for specific types of game objects. |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.ui <Package openmw.ui>` | by player and menu | | Controls :ref:`user interface <User interface reference>`. |
|
||||||
|
| | scripts | |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.util <Package openmw.util>` | everywhere | | Defines utility functions and classes like 3D vectors, |
|
||||||
|
| | | | that don't depend on the game world. |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.vfs <Package openmw.vfs>` | everywhere | | Read-only access to data directories via VFS. |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
|:ref:`openmw.world <Package openmw.world>` | by global scripts | | Read-write access to the game world. |
|
||||||
|
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||||
|
Loading…
x
Reference in New Issue
Block a user