1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-10-15 21:46:37 +00:00
This commit is contained in:
Andrew Lanzone 2025-08-04 16:44:12 -07:00
commit 8e76a0ab06
146 changed files with 928 additions and 499 deletions

View file

@ -108,8 +108,8 @@ Coverity:
- ccache/ - ccache/
variables: variables:
CCACHE_SIZE: 2G CCACHE_SIZE: 2G
CC: clang-12 CC: clang
CXX: clang++-12 CXX: clang++
CMAKE_BUILD_TYPE: Debug CMAKE_BUILD_TYPE: Debug
CMAKE_CXX_FLAGS_DEBUG: -O0 CMAKE_CXX_FLAGS_DEBUG: -O0
before_script: before_script:
@ -125,18 +125,34 @@ Coverity:
- ccache -z -M "${CCACHE_SIZE}" - ccache -z -M "${CCACHE_SIZE}"
- CI/before_script.linux.sh - CI/before_script.linux.sh
- cov-analysis-linux64-*/bin/cov-configure --template --comptype prefix --compiler ccache - cov-analysis-linux64-*/bin/cov-configure --template --comptype prefix --compiler ccache
# Remove the specific targets and build everything once we can do it under 3h
- cov-analysis-linux64-*/bin/cov-build --dir cov-int cmake --build build -- -j $(nproc) - cov-analysis-linux64-*/bin/cov-build --dir cov-int cmake --build build -- -j $(nproc)
- ccache -svv - ccache -svv
after_script:
- tar cfz cov-int.tar.gz cov-int - tar cfz cov-int.tar.gz cov-int
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME - echo "OPENMW_JOB_ID=$CI_JOB_ID" >> build.env
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
--form file=@cov-int.tar.gz --form version="$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA"
--form description="CI_COMMIT_SHORT_SHA / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
artifacts: artifacts:
expire_in: 1 day
paths: paths:
- /builds/OpenMW/openmw/cov-int/build-log.txt - /builds/OpenMW/openmw/cov-int/build-log.txt
- /builds/OpenMW/openmw/cov-int.tar.gz
reports:
dotenv: build.env
Coverity_Upload:
image: ubuntu:24.04
stage: build
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
before_script:
- CI/install_debian_deps.sh coverity_upload
script:
- echo "$CI_API_V4_URL/projects/$CI_PROJECT_ID/jobs/$OPENMW_JOB_ID/artifacts/cov-int.tar.gz"
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
--form version="$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA"
--form description="CI_COMMIT_SHORT_SHA / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
--form url="$CI_API_V4_URL/projects/$CI_PROJECT_ID/jobs/$OPENMW_JOB_ID/artifacts/cov-int.tar.gz"
needs:
- Coverity
Ubuntu_GCC: Ubuntu_GCC:
extends: .Ubuntu extends: .Ubuntu

View file

@ -11,7 +11,8 @@ print_help() {
declare -rA GROUPED_DEPS=( declare -rA GROUPED_DEPS=(
[gcc]="binutils gcc build-essential cmake ccache curl unzip git pkg-config mold" [gcc]="binutils gcc build-essential cmake ccache curl unzip git pkg-config mold"
[clang]="binutils clang make cmake ccache curl unzip git pkg-config mold" [clang]="binutils clang make cmake ccache curl unzip git pkg-config mold"
[coverity]="binutils clang-12 make cmake ccache curl unzip git pkg-config" [coverity]="binutils clang make cmake ccache curl unzip git pkg-config file"
[coverity_upload]="curl"
[gcc_preprocess]=" [gcc_preprocess]="
binutils binutils
build-essential build-essential

View file

@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 50) set(OPENMW_VERSION_MINOR 50)
set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_LUA_API_REVISION 85) set(OPENMW_LUA_API_REVISION 87)
set(OPENMW_POSTPROCESSING_API_REVISION 3) set(OPENMW_POSTPROCESSING_API_REVISION 3)
set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_COMMITHASH "")

View file

@ -638,8 +638,9 @@ CUSTOM: customdata.lua
sol::object deserialized = LuaUtil::deserialize(lua.sol(), data2.mScripts[0].mData, &serializer1); sol::object deserialized = LuaUtil::deserialize(lua.sol(), data2.mScripts[0].mData, &serializer1);
EXPECT_TRUE(deserialized.is<sol::table>()); EXPECT_TRUE(deserialized.is<sol::table>());
sol::table table = deserialized; sol::table table = deserialized;
for (const auto& [key, value] : table) if (!table.empty())
{ {
const auto [key, value] = *table.cbegin();
EXPECT_TRUE(key.is<ESM::RefNum>()); EXPECT_TRUE(key.is<ESM::RefNum>());
EXPECT_TRUE(value.is<ESM::RefNum>()); EXPECT_TRUE(value.is<ESM::RefNum>());
EXPECT_EQ(key.as<ESM::RefNum>(), (ESM::RefNum{ 42, 34 })); EXPECT_EQ(key.as<ESM::RefNum>(), (ESM::RefNum{ 42, 34 }));

View file

@ -215,8 +215,6 @@ int main(int argc, char** argv)
std::cerr << "ERROR: " << e.what() << std::endl; std::cerr << "ERROR: " << e.what() << std::endl;
return 1; return 1;
} }
return 0;
} }
namespace namespace

View file

@ -291,6 +291,7 @@ bool Launcher::SettingsPage::loadSettings()
} }
} }
loadSettingBool(Settings::sound().mCameraListener, *cameraListenerCheckBox); loadSettingBool(Settings::sound().mCameraListener, *cameraListenerCheckBox);
dopplerSpinBox->setValue(Settings::sound().mDopplerFactor);
} }
// Interface Changes // Interface Changes
@ -485,6 +486,8 @@ void Launcher::SettingsPage::saveSettings()
const bool cCameraListener = cameraListenerCheckBox->checkState() != Qt::Unchecked; const bool cCameraListener = cameraListenerCheckBox->checkState() != Qt::Unchecked;
Settings::sound().mCameraListener.set(cCameraListener); Settings::sound().mCameraListener.set(cCameraListener);
Settings::sound().mDopplerFactor.set(dopplerSpinBox->value());
} }
// Interface Changes // Interface Changes

View file

@ -1224,6 +1224,51 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="dopplerLabel">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Controls the strength of the Doppler effect. Zero means it is completely disabled.&lt;/p&gt;&lt;p&gt;The Doppler effect increases or decreases the pitch of sounds relative to the velocity of the sound source and the listener.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Doppler Factor</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="dopplerSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>283</width>
<height>0</height>
</size>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.250000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<spacer> <spacer>
<property name="orientation"> <property name="orientation">

View file

@ -59,14 +59,13 @@ namespace CSMWorld
const Record<ESM::LandTexture>* IdCollection<ESM::LandTexture>::searchRecord(std::uint16_t index, int plugin) const const Record<ESM::LandTexture>* IdCollection<ESM::LandTexture>::searchRecord(std::uint16_t index, int plugin) const
{ {
auto found = mIndices.find({ plugin, index }); const auto it = mIndices.find({ plugin, index });
if (found != mIndices.end()) if (it == mIndices.end())
{ return nullptr;
int index = searchId(found->second); const int recordIndex = searchId(it->second);
if (index != -1) if (recordIndex == -1)
return &getRecord(index); return nullptr;
} return &getRecord(recordIndex);
return nullptr;
} }
const std::string* IdCollection<ESM::LandTexture>::getLandTexture(std::uint16_t index, int plugin) const const std::string* IdCollection<ESM::LandTexture>::getLandTexture(std::uint16_t index, int plugin) const

View file

@ -5,7 +5,8 @@
#include <future> #include <future>
#include <system_error> #include <system_error>
#include <osgDB/WriteFile> #include <osgDB/ReaderWriter>
#include <osgDB/Registry>
#include <osgViewer/ViewerEventHandlers> #include <osgViewer/ViewerEventHandlers>
#include <SDL.h> #include <SDL.h>
@ -28,7 +29,6 @@
#include <components/compiler/extensions0.hpp> #include <components/compiler/extensions0.hpp>
#include <components/stereo/multiview.hpp>
#include <components/stereo/stereomanager.hpp> #include <components/stereo/stereomanager.hpp>
#include <components/sceneutil/glextensions.hpp> #include <components/sceneutil/glextensions.hpp>

View file

@ -75,6 +75,7 @@ namespace MWBase
const MWRender::AnimPriority& priority, int blendMask, bool autodisable, float speedmult, const MWRender::AnimPriority& priority, int blendMask, bool autodisable, float speedmult,
std::string_view start, std::string_view stop, float startpoint, uint32_t loops, bool loopfallback) std::string_view start, std::string_view stop, float startpoint, uint32_t loops, bool loopfallback)
= 0; = 0;
virtual void jailTimeServed(const MWWorld::Ptr& actor, int days) = 0;
virtual void skillLevelUp(const MWWorld::Ptr& actor, ESM::RefId skillId, std::string_view source) = 0; virtual void skillLevelUp(const MWWorld::Ptr& actor, ESM::RefId skillId, std::string_view source) = 0;
virtual void skillUse(const MWWorld::Ptr& actor, ESM::RefId skillId, int useType, float scale) = 0; virtual void skillUse(const MWWorld::Ptr& actor, ESM::RefId skillId, int useType, float scale) = 0;
virtual void onHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& weapon, virtual void onHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& weapon,

View file

@ -234,6 +234,8 @@ namespace MWBase
const osg::Vec3f& pos, const osg::Vec3f& dir, const osg::Vec3f& up, bool underwater) const osg::Vec3f& pos, const osg::Vec3f& dir, const osg::Vec3f& up, bool underwater)
= 0; = 0;
virtual void setListenerVel(const osg::Vec3f& vel) = 0;
virtual void updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated) = 0; virtual void updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated) = 0;
void setSimulationTimeScale(float scale) { mSimulationTimeScale = scale; } void setSimulationTimeScale(float scale) { mSimulationTimeScale = scale; }

View file

@ -496,6 +496,8 @@ namespace MWBase
virtual float getSunVisibility() const = 0; virtual float getSunVisibility() const = 0;
virtual float getSunPercentage() const = 0; virtual float getSunPercentage() const = 0;
virtual float getPhysicsFrameRateDt() const = 0;
virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) = 0; virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) = 0;
/// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker)

View file

@ -4,6 +4,7 @@
#include <components/misc/strings/format.hpp> #include <components/misc/strings/format.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/luamanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -86,46 +87,6 @@ namespace MWGui
// We should not worsen corprus when in prison // We should not worsen corprus when in prison
player.getClass().getCreatureStats(player).getActiveSpells().skipWorsenings(mDays * 24); player.getClass().getCreatureStats(player).getActiveSpells().skipWorsenings(mDays * 24);
MWBase::Environment::get().getLuaManager()->jailTimeServed(player, mDays);
const auto& skillStore = MWBase::Environment::get().getESMStore()->get<ESM::Skill>();
std::set<const ESM::Skill*> skills;
for (int day = 0; day < mDays; ++day)
{
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
const ESM::Skill* skill = skillStore.searchRandom({}, prng);
skills.insert(skill);
MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill->mId);
if (skill->mId == ESM::Skill::Security || skill->mId == ESM::Skill::Sneak)
value.setBase(std::min(100.f, value.getBase() + 1));
else
value.setBase(std::max(0.f, value.getBase() - 1));
}
const MWWorld::Store<ESM::GameSetting>& gmst
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
std::string message;
if (mDays == 1)
message = gmst.find("sNotifyMessage42")->mValue.getString();
else
message = gmst.find("sNotifyMessage43")->mValue.getString();
message = Misc::StringUtils::format(message, mDays);
for (const ESM::Skill* skill : skills)
{
int skillValue = player.getClass().getNpcStats(player).getSkill(skill->mId).getBase();
std::string skillMsg = gmst.find("sNotifyMessage44")->mValue.getString();
if (skill->mId == ESM::Skill::Sneak || skill->mId == ESM::Skill::Security)
skillMsg = gmst.find("sNotifyMessage39")->mValue.getString();
skillMsg = Misc::StringUtils::format(skillMsg, skill->mName, skillValue);
message += "\n" + skillMsg;
}
std::vector<std::string> buttons;
buttons.emplace_back("#{Interface:OK}");
MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons);
} }
} }

View file

@ -775,12 +775,10 @@ namespace MWGui
, mGlobalMapRender(std::make_unique<MWRender::GlobalMap>(localMapRender->getRoot(), workQueue)) , mGlobalMapRender(std::make_unique<MWRender::GlobalMap>(localMapRender->getRoot(), workQueue))
, mEditNoteDialog() , mEditNoteDialog()
{ {
static bool registered = false; [[maybe_unused]] static const bool registered = [] {
if (!registered)
{
MyGUI::FactoryManager::getInstance().registerFactory<MarkerWidget>("Widget"); MyGUI::FactoryManager::getInstance().registerFactory<MarkerWidget>("Widget");
registered = true; return true;
} }();
mEditNoteDialog.setVisible(false); mEditNoteDialog.setVisible(false);
mEditNoteDialog.eventOkClicked += MyGUI::newDelegate(this, &MapWindow::onNoteEditOk); mEditNoteDialog.eventOkClicked += MyGUI::newDelegate(this, &MapWindow::onNoteEditOk);

View file

@ -587,6 +587,7 @@ namespace MWGui
getWidget(mAvailableEffectsList, "AvailableEffects"); getWidget(mAvailableEffectsList, "AvailableEffects");
getWidget(mUsedEffectsView, "UsedEffects"); getWidget(mUsedEffectsView, "UsedEffects");
getWidget(mPriceLabel, "PriceLabel"); getWidget(mPriceLabel, "PriceLabel");
getWidget(mPlayerGold, "PlayerGold");
getWidget(mBuyButton, "BuyButton"); getWidget(mBuyButton, "BuyButton");
getWidget(mCancelButton, "CancelButton"); getWidget(mCancelButton, "CancelButton");
@ -613,6 +614,10 @@ namespace MWGui
mPtr = actor; mPtr = actor;
mNameEdit->setCaption({}); mNameEdit->setCaption({});
MWWorld::Ptr player = MWMechanics::getPlayer();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
mPlayerGold->setCaptionWithReplacing(MyGUI::utility::toString(playerGold));
startEditing(); startEditing();
} }

View file

@ -190,6 +190,7 @@ namespace MWGui
MyGUI::Button* mBuyButton; MyGUI::Button* mBuyButton;
MyGUI::Button* mCancelButton; MyGUI::Button* mCancelButton;
MyGUI::TextBox* mPriceLabel; MyGUI::TextBox* mPriceLabel;
MyGUI::TextBox* mPlayerGold;
ESM::Spell mSpell; ESM::Spell mSpell;
}; };

View file

@ -29,7 +29,7 @@ namespace MWGui
: WindowBase("openmw_trainingwindow.layout") : WindowBase("openmw_trainingwindow.layout")
{ {
getWidget(mTrainingOptions, "TrainingOptions"); getWidget(mTrainingOptions, "TrainingOptions");
getWidget(mCancelButton, "CancelButton"); getWidget(mCancelButton, "OkButton");
getWidget(mPlayerGold, "PlayerGold"); getWidget(mPlayerGold, "PlayerGold");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onCancelButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onCancelButtonClicked);
@ -123,14 +123,14 @@ namespace MWGui
MyGUI::Button* button = mTrainingOptions->createWidget<MyGUI::Button>(price <= playerGold MyGUI::Button* button = mTrainingOptions->createWidget<MyGUI::Button>(price <= playerGold
? "SandTextButton" ? "SandTextButton"
: "SandTextButtonDisabled", // can't use setEnabled since that removes tooltip : "SandTextButtonDisabled", // can't use setEnabled since that removes tooltip
MyGUI::IntCoord(5, 5 + i * lineHeight, mTrainingOptions->getWidth() - 10, lineHeight), MyGUI::IntCoord(4, 3 + i * lineHeight, mTrainingOptions->getWidth() - 10, lineHeight),
MyGUI::Align::Default); MyGUI::Align::Default);
button->setUserData(skills[i].first); button->setUserData(skills[i].first);
button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected); button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected);
button->setCaptionWithReplacing( button->setCaptionWithReplacing(
MyGUI::TextIterator::toTagsString(skill->mName) + " - " + MyGUI::utility::toString(price)); MyGUI::TextIterator::toTagsString(skill->mName) + " - " + MyGUI::utility::toString(price) + "#{sgp}");
button->setSize(button->getTextSize().width + 12, button->getSize().height); button->setSize(button->getTextSize().width + 12, button->getSize().height);

View file

@ -1,13 +1,7 @@
#include "animationbindings.hpp" #include "animationbindings.hpp"
#include <components/esm3/loadmgef.hpp>
#include <components/esm3/loadstat.hpp>
#include <components/lua/asyncpackage.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/utilpackage.hpp>
#include <components/misc/finitenumbers.hpp> #include <components/misc/finitenumbers.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/settings/values.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
@ -15,11 +9,8 @@
#include "../mwmechanics/character.hpp" #include "../mwmechanics/character.hpp"
#include "../mwworld/esmstore.hpp"
#include "context.hpp" #include "context.hpp"
#include "luamanagerimp.hpp" #include "luamanagerimp.hpp"
#include "objectvariant.hpp"
namespace MWLua namespace MWLua
{ {

View file

@ -8,7 +8,7 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "idcollectionbindings.hpp" #include "idcollectionbindings.hpp"
#include "types/types.hpp" #include "recordstore.hpp"
namespace sol namespace sol
{ {

View file

@ -3,10 +3,10 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
struct Context;
sol::table initBirthSignRecordBindings(const Context& context); sol::table initBirthSignRecordBindings(const Context& context);
} }

View file

@ -1,7 +1,5 @@
#include "cellbindings.hpp" #include "cellbindings.hpp"
#include <components/esm/esmbridge.hpp>
#include <components/esm3/loadacti.hpp> #include <components/esm3/loadacti.hpp>
#include <components/esm3/loadalch.hpp> #include <components/esm3/loadalch.hpp>
#include <components/esm3/loadappa.hpp> #include <components/esm3/loadappa.hpp>
@ -27,7 +25,6 @@
#include <components/esm4/loadammo.hpp> #include <components/esm4/loadammo.hpp>
#include <components/esm4/loadarmo.hpp> #include <components/esm4/loadarmo.hpp>
#include <components/esm4/loadbook.hpp> #include <components/esm4/loadbook.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/esm4/loadclot.hpp> #include <components/esm4/loadclot.hpp>
#include <components/esm4/loadcont.hpp> #include <components/esm4/loadcont.hpp>
#include <components/esm4/loaddoor.hpp> #include <components/esm4/loaddoor.hpp>
@ -38,7 +35,6 @@
#include <components/esm4/loadligh.hpp> #include <components/esm4/loadligh.hpp>
#include <components/esm4/loadmisc.hpp> #include <components/esm4/loadmisc.hpp>
#include <components/esm4/loadmstt.hpp> #include <components/esm4/loadmstt.hpp>
#include <components/esm4/loadrefr.hpp>
#include <components/esm4/loadscol.hpp> #include <components/esm4/loadscol.hpp>
#include <components/esm4/loadstat.hpp> #include <components/esm4/loadstat.hpp>
#include <components/esm4/loadtree.hpp> #include <components/esm4/loadtree.hpp>

View file

@ -1,12 +1,12 @@
#ifndef MWLUA_CELLBINDINGS_H #ifndef MWLUA_CELLBINDINGS_H
#define MWLUA_CELLBINDINGS_H #define MWLUA_CELLBINDINGS_H
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
void initCellBindingsForLocalScripts(const Context&); struct Context;
void initCellBindingsForGlobalScripts(const Context&);
void initCellBindingsForLocalScripts(const Context& context);
void initCellBindingsForGlobalScripts(const Context& context);
} }
#endif // MWLUA_CELLBINDINGS_H #endif // MWLUA_CELLBINDINGS_H

View file

@ -4,7 +4,7 @@
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include "idcollectionbindings.hpp" #include "idcollectionbindings.hpp"
#include "types/types.hpp" #include "recordstore.hpp"
namespace sol namespace sol
{ {

View file

@ -3,10 +3,10 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
struct Context;
sol::table initClassRecordBindings(const Context& context); sol::table initClassRecordBindings(const Context& context);
} }

View file

@ -4,7 +4,6 @@
#include <stdexcept> #include <stdexcept>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/esm3/loadfact.hpp>
#include <components/lua/l10n.hpp> #include <components/lua/l10n.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/serialization.hpp> #include <components/lua/serialization.hpp>
@ -20,6 +19,7 @@
#include "../mwworld/datetimemanager.hpp" #include "../mwworld/datetimemanager.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "context.hpp"
#include "coremwscriptbindings.hpp" #include "coremwscriptbindings.hpp"
#include "dialoguebindings.hpp" #include "dialoguebindings.hpp"
#include "factionbindings.hpp" #include "factionbindings.hpp"

View file

@ -3,13 +3,13 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
struct Context;
void addCoreTimeBindings(sol::table& api, const Context& context); void addCoreTimeBindings(sol::table& api, const Context& context);
sol::table initCorePackage(const Context&); sol::table initCorePackage(const Context& context);
} }
#endif // MWLUA_COREBINDINGS_H #endif // MWLUA_COREBINDINGS_H

View file

@ -1,7 +1,7 @@
#ifndef OPENMW_MWLUA_DEBUGBINDINGS_H #ifndef OPENMW_MWLUA_DEBUGBINDINGS_H
#define OPENMW_MWLUA_DEBUGBINDINGS_H #define OPENMW_MWLUA_DEBUGBINDINGS_H
#include <sol/sol.hpp> #include <sol/forward.hpp>
namespace MWLua namespace MWLua
{ {

View file

@ -113,6 +113,15 @@ namespace MWLua
scripts->onSkillLevelUp(event.mSkill, event.mSource); scripts->onSkillLevelUp(event.mSkill, event.mSource);
} }
void operator()(const OnJailTimeServed& event) const
{
MWWorld::Ptr actor = getPtr(event.mActor);
if (actor.isEmpty())
return;
if (auto* scripts = getLocalScripts(actor))
scripts->onJailTimeServed(event.mDays);
}
private: private:
MWWorld::Ptr getPtr(ESM::RefNum id) const MWWorld::Ptr getPtr(ESM::RefNum id) const
{ {

View file

@ -70,8 +70,13 @@ namespace MWLua
std::string mSkill; std::string mSkill;
std::string mSource; std::string mSource;
}; };
struct OnJailTimeServed
{
ESM::RefNum mActor;
int mDays;
};
using Event = std::variant<OnActive, OnInactive, OnConsume, OnActivate, OnUseItem, OnNewExterior, OnTeleported, using Event = std::variant<OnActive, OnInactive, OnConsume, OnActivate, OnUseItem, OnNewExterior, OnTeleported,
OnAnimationTextKey, OnSkillUse, OnSkillLevelUp>; OnAnimationTextKey, OnSkillUse, OnSkillLevelUp, OnJailTimeServed>;
void clear() { mQueue.clear(); } void clear() { mQueue.clear(); }
void addToQueue(Event e) { mQueue.push_back(std::move(e)); } void addToQueue(Event e) { mQueue.push_back(std::move(e)); }

View file

@ -3,10 +3,10 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
struct Context;
sol::table initCoreFactionBindings(const Context& context); sol::table initCoreFactionBindings(const Context& context);
} }

View file

@ -14,6 +14,7 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwinput/actions.hpp" #include "../mwinput/actions.hpp"
#include "context.hpp"
#include "luamanagerimp.hpp" #include "luamanagerimp.hpp"
namespace sol namespace sol

View file

@ -3,11 +3,11 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
sol::table initInputPackage(const Context&); struct Context;
sol::table initInputPackage(const Context& context);
} }
#endif // MWLUA_INPUTBINDINGS_H #endif // MWLUA_INPUTBINDINGS_H

View file

@ -1,14 +1,24 @@
#include "landbindings.hpp" #include "landbindings.hpp"
#include <span>
#include <string>
#include <sol/object.hpp>
#include <sol/table.hpp>
#include <sol/variadic_results.hpp>
#include <components/esm/refid.hpp> #include <components/esm/refid.hpp>
#include <components/esm/util.hpp> #include <components/esm/util.hpp>
#include <components/esmterrain/storage.hpp> #include <components/esmterrain/storage.hpp>
#include <components/lua/luastate.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/worldmodel.hpp" #include "../mwworld/worldmodel.hpp"
#include "context.hpp"
#include "object.hpp" #include "object.hpp"
namespace namespace

View file

@ -1,10 +1,12 @@
#ifndef MWLUA_LANDBINDINGS_H #ifndef MWLUA_LANDBINDINGS_H
#define MWLUA_LANDBINDINGS_H #define MWLUA_LANDBINDINGS_H
#include "context.hpp" #include <sol/forward.hpp>
namespace MWLua namespace MWLua
{ {
struct Context;
sol::table initCoreLandBindings(const Context& context); sol::table initCoreLandBindings(const Context& context);
} }

View file

@ -1,9 +1,5 @@
#include "localscripts.hpp" #include "localscripts.hpp"
#include <components/esm3/loadcell.hpp>
#include <components/esm3/loadweap.hpp>
#include <components/misc/strings/lower.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwmechanics/aicombat.hpp" #include "../mwmechanics/aicombat.hpp"
@ -232,7 +228,7 @@ namespace MWLua
[&](LuaUtil::LuaView& view) { addPackage("openmw.self", sol::make_object(view.sol(), &mData)); }); [&](LuaUtil::LuaView& view) { addPackage("openmw.self", sol::make_object(view.sol(), &mData)); });
registerEngineHandlers({ &mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers, &mOnActivatedHandlers, registerEngineHandlers({ &mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers, &mOnActivatedHandlers,
&mOnTeleportedHandlers, &mOnAnimationTextKeyHandlers, &mOnPlayAnimationHandlers, &mOnSkillUse, &mOnTeleportedHandlers, &mOnAnimationTextKeyHandlers, &mOnPlayAnimationHandlers, &mOnSkillUse,
&mOnSkillLevelUp }); &mOnSkillLevelUp, &mOnJailTimeServed });
} }
void LocalScripts::setActive(bool active, bool callHandlers) void LocalScripts::setActive(bool active, bool callHandlers)

View file

@ -1,9 +1,7 @@
#ifndef MWLUA_LOCALSCRIPTS_H #ifndef MWLUA_LOCALSCRIPTS_H
#define MWLUA_LOCALSCRIPTS_H #define MWLUA_LOCALSCRIPTS_H
#include <memory> #include <string_view>
#include <set>
#include <string>
#include <utility> #include <utility>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
@ -89,6 +87,7 @@ namespace MWLua
{ {
callEngineHandlers(mOnSkillLevelUp, skillId, source); callEngineHandlers(mOnSkillLevelUp, skillId, source);
} }
void onJailTimeServed(int days) { callEngineHandlers(mOnJailTimeServed, days); }
void applyStatsCache(); void applyStatsCache();
@ -118,6 +117,7 @@ namespace MWLua
EngineHandlerList mOnPlayAnimationHandlers{ "_onPlayAnimation" }; EngineHandlerList mOnPlayAnimationHandlers{ "_onPlayAnimation" };
EngineHandlerList mOnSkillUse{ "_onSkillUse" }; EngineHandlerList mOnSkillUse{ "_onSkillUse" };
EngineHandlerList mOnSkillLevelUp{ "_onSkillLevelUp" }; EngineHandlerList mOnSkillLevelUp{ "_onSkillLevelUp" };
EngineHandlerList mOnJailTimeServed{ "_onJailTimeServed" };
}; };
} }

View file

@ -1,29 +1,30 @@
#ifndef MWLUA_LUABINDINGS_H #ifndef MWLUA_LUABINDINGS_H
#define MWLUA_LUABINDINGS_H #define MWLUA_LUABINDINGS_H
#include <map>
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include <string>
#include "context.hpp" #include <map>
#include <string>
namespace MWLua namespace MWLua
{ {
struct Context;
// Initialize Lua packages that are available for all scripts. // Initialize Lua packages that are available for all scripts.
std::map<std::string, sol::object> initCommonPackages(const Context&); std::map<std::string, sol::object> initCommonPackages(const Context& context);
// Initialize Lua packages that are available for global scripts (additionally to common packages). // Initialize Lua packages that are available for global scripts (additionally to common packages).
std::map<std::string, sol::object> initGlobalPackages(const Context&); std::map<std::string, sol::object> initGlobalPackages(const Context& context);
// Initialize Lua packages that are available for local scripts (additionally to common packages). // Initialize Lua packages that are available for local scripts (additionally to common packages).
std::map<std::string, sol::object> initLocalPackages(const Context&); std::map<std::string, sol::object> initLocalPackages(const Context& context);
// Initialize Lua packages that are available only for local scripts on the player (additionally to common and local // Initialize Lua packages that are available only for local scripts on the player (additionally to common and local
// packages). // packages).
std::map<std::string, sol::object> initPlayerPackages(const Context&); std::map<std::string, sol::object> initPlayerPackages(const Context& context);
// Initialize Lua packages that are available only for menu scripts (additionally to common packages). // Initialize Lua packages that are available only for menu scripts (additionally to common packages).
std::map<std::string, sol::object> initMenuPackages(const Context&); std::map<std::string, sol::object> initMenuPackages(const Context& context);
} }
#endif // MWLUA_LUABINDINGS_H #endif // MWLUA_LUABINDINGS_H

View file

@ -5,6 +5,10 @@
#include <MyGUI_InputManager.h> #include <MyGUI_InputManager.h>
#include <osg/Stats> #include <osg/Stats>
#include <sol/object.hpp>
#include <sol/table.hpp>
#include <sol/types.hpp>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/esm/luascripts.hpp> #include <components/esm/luascripts.hpp>
@ -15,7 +19,6 @@
#include <components/l10n/manager.hpp> #include <components/l10n/manager.hpp>
#include <components/lua_ui/content.hpp>
#include <components/lua_ui/registerscriptsettings.hpp> #include <components/lua_ui/registerscriptsettings.hpp>
#include <components/lua_ui/util.hpp> #include <components/lua_ui/util.hpp>
@ -212,13 +215,12 @@ namespace MWLua
// Run engine handlers // Run engine handlers
mEngineEvents.callEngineHandlers(); mEngineEvents.callEngineHandlers();
if (!timeManager.isPaused()) bool isPaused = timeManager.isPaused();
{
float frameDuration = MWBase::Environment::get().getFrameDuration(); float frameDuration = MWBase::Environment::get().getFrameDuration();
for (LocalScripts* scripts : mActiveLocalScripts) for (LocalScripts* scripts : mActiveLocalScripts)
scripts->update(frameDuration); scripts->update(isPaused ? 0 : frameDuration);
mGlobalScripts.update(frameDuration); mGlobalScripts.update(isPaused ? 0 : frameDuration);
}
mLua.protectedCall([&](LuaUtil::LuaView& lua) { mScriptTracker.unloadInactiveScripts(lua); }); mLua.protectedCall([&](LuaUtil::LuaView& lua) { mScriptTracker.unloadInactiveScripts(lua); });
} }
@ -491,6 +493,11 @@ namespace MWLua
EngineEvents::OnSkillLevelUp{ getId(actor), skillId.serializeText(), std::string(source) }); EngineEvents::OnSkillLevelUp{ getId(actor), skillId.serializeText(), std::string(source) });
} }
void LuaManager::jailTimeServed(const MWWorld::Ptr& actor, int days)
{
mEngineEvents.addToQueue(EngineEvents::OnJailTimeServed{ getId(actor), days });
}
void LuaManager::onHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& weapon, void LuaManager::onHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& weapon,
const MWWorld::Ptr& ammo, int attackType, float attackStrength, float damage, bool isHealth, const MWWorld::Ptr& ammo, int attackType, float attackStrength, float damage, bool isHealth,
const osg::Vec3f& hitPos, bool successful, MWMechanics::DamageSourceType sourceType) const osg::Vec3f& hitPos, bool successful, MWMechanics::DamageSourceType sourceType)

View file

@ -3,9 +3,10 @@
#include <filesystem> #include <filesystem>
#include <map> #include <map>
#include <osg/Stats>
#include <set> #include <set>
#include <osg/Stats>
#include <components/lua/inputactions.hpp> #include <components/lua/inputactions.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/lua/scripttracker.hpp> #include <components/lua/scripttracker.hpp>
@ -92,6 +93,7 @@ namespace MWLua
bool loopfallback) override; bool loopfallback) override;
void skillUse(const MWWorld::Ptr& actor, ESM::RefId skillId, int useType, float scale) override; void skillUse(const MWWorld::Ptr& actor, ESM::RefId skillId, int useType, float scale) override;
void skillLevelUp(const MWWorld::Ptr& actor, ESM::RefId skillId, std::string_view source) override; void skillLevelUp(const MWWorld::Ptr& actor, ESM::RefId skillId, std::string_view source) override;
void jailTimeServed(const MWWorld::Ptr& actor, int days) override;
void onHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& weapon, void onHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& weapon,
const MWWorld::Ptr& ammo, int attackType, float attackStrength, float damage, bool isHealth, const MWWorld::Ptr& ammo, int attackType, float attackStrength, float damage, bool isHealth,
const osg::Vec3f& hitPos, bool successful, MWMechanics::DamageSourceType sourceType) override; const osg::Vec3f& hitPos, bool successful, MWMechanics::DamageSourceType sourceType) override;

View file

@ -3,10 +3,10 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
struct Context;
sol::table initCoreMagicBindings(const Context& context); sol::table initCoreMagicBindings(const Context& context);
void addActorMagicBindings(sol::table& actor, const Context& context); void addActorMagicBindings(sol::table& actor, const Context& context);
} }

View file

@ -3,11 +3,11 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
sol::table initMarkupPackage(const Context&); struct Context;
sol::table initMarkupPackage(const Context& context);
} }
#endif // MWLUA_MARKUPBINDINGS_H #endif // MWLUA_MARKUPBINDINGS_H

View file

@ -7,6 +7,8 @@
#include "../mwbase/statemanager.hpp" #include "../mwbase/statemanager.hpp"
#include "../mwstate/character.hpp" #include "../mwstate/character.hpp"
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
static const MWState::Character* findCharacter(std::string_view characterDir) static const MWState::Character* findCharacter(std::string_view characterDir)

View file

@ -9,11 +9,11 @@
#include "../mwbase/luamanager.hpp" #include "../mwbase/luamanager.hpp"
#include "context.hpp"
#include "inputprocessor.hpp" #include "inputprocessor.hpp"
namespace MWLua namespace MWLua
{ {
struct Context;
sol::table initMenuPackage(const Context& context); sol::table initMenuPackage(const Context& context);

View file

@ -12,6 +12,7 @@
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/worldimp.hpp" #include "../mwworld/worldimp.hpp"
#include "context.hpp"
#include "object.hpp" #include "object.hpp"
#include <stdexcept> #include <stdexcept>

View file

@ -3,13 +3,11 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
struct Context;
sol::table initMWScriptBindings(const Context&); sol::table initMWScriptBindings(const Context& context);
} }
#endif // MWLUA_MWSCRIPTBINDINGS_H #endif // MWLUA_MWSCRIPTBINDINGS_H

View file

@ -13,9 +13,12 @@
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/scene.hpp" #include "../mwworld/scene.hpp"
#include "context.hpp"
#include "luamanagerimp.hpp" #include "luamanagerimp.hpp"
#include "objectlists.hpp" #include "objectlists.hpp"
#include <vector>
namespace namespace
{ {
template <class T = MWWorld::Ptr> template <class T = MWWorld::Ptr>

View file

@ -3,11 +3,11 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
sol::table initNearbyPackage(const Context&); struct Context;
sol::table initNearbyPackage(const Context& context);
} }
#endif // MWLUA_NEARBYBINDINGS_H #endif // MWLUA_NEARBYBINDINGS_H

View file

@ -1,9 +1,7 @@
#ifndef MWLUA_OBJECT_H #ifndef MWLUA_OBJECT_H
#define MWLUA_OBJECT_H #define MWLUA_OBJECT_H
#include <map>
#include <stdexcept> #include <stdexcept>
#include <typeindex>
#include <sol/sol.hpp> #include <sol/sol.hpp>

View file

@ -1,12 +1,12 @@
#ifndef MWLUA_OBJECTBINDINGS_H #ifndef MWLUA_OBJECTBINDINGS_H
#define MWLUA_OBJECTBINDINGS_H #define MWLUA_OBJECTBINDINGS_H
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
void initObjectBindingsForLocalScripts(const Context&); struct Context;
void initObjectBindingsForGlobalScripts(const Context&);
void initObjectBindingsForLocalScripts(const Context& context);
void initObjectBindingsForGlobalScripts(const Context& context);
} }
#endif // MWLUA_OBJECTBINDINGS_H #endif // MWLUA_OBJECTBINDINGS_H

View file

@ -1,9 +1,5 @@
#include "objectlists.hpp" #include "objectlists.hpp"
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/esm3/loadcell.hpp>
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"

View file

@ -8,6 +8,7 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwrender/postprocessor.hpp" #include "../mwrender/postprocessor.hpp"
#include "context.hpp"
#include "luamanagerimp.hpp" #include "luamanagerimp.hpp"
namespace namespace

View file

@ -3,11 +3,11 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
sol::table initPostprocessingPackage(const Context&); struct Context;
sol::table initPostprocessingPackage(const Context& context);
} }
#endif // MWLUA_POSTPROCESSINGBINDINGS_H #endif // MWLUA_POSTPROCESSINGBINDINGS_H

View file

@ -8,7 +8,7 @@
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "idcollectionbindings.hpp" #include "idcollectionbindings.hpp"
#include "types/types.hpp" #include "recordstore.hpp"
namespace namespace
{ {

View file

@ -3,10 +3,10 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
struct Context;
sol::table initRaceRecordBindings(const Context& context); sol::table initRaceRecordBindings(const Context& context);
} }

View file

@ -1,10 +1,16 @@
#ifndef MWLUA_RECORDSTORE_H #ifndef MWLUA_RECORDSTORE_H
#define MWLUA_RECORDSTORE_H #define MWLUA_RECORDSTORE_H
#include <sol/sol.hpp> #include <type_traits>
#include <sol/forward.hpp>
#include <sol/overload.hpp>
#include <sol/state_view.hpp>
#include <sol/table.hpp>
#include <sol/types.hpp>
#include <sol/unsafe_function.hpp>
#include <sol/usertype.hpp>
#include <components/esm/defs.hpp>
#include <components/lua/luastate.hpp>
#include <components/lua/util.hpp> #include <components/lua/util.hpp>
#include "apps/openmw/mwbase/environment.hpp" #include "apps/openmw/mwbase/environment.hpp"

View file

@ -3,11 +3,11 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
sol::table initCoreSoundBindings(const Context&); struct Context;
sol::table initCoreSoundBindings(const Context& context);
sol::table initAmbientPackage(const Context& context); sol::table initAmbientPackage(const Context& context);
} }

View file

@ -1,9 +1,11 @@
#include "stats.hpp" #include "stats.hpp"
#include <algorithm> #include <algorithm>
#include <memory>
#include <optional> #include <optional>
#include <string>
#include <string_view> #include <string_view>
#include <type_traits>
#include <utility>
#include <variant> #include <variant>
#include <components/esm3/loadclas.hpp> #include <components/esm3/loadclas.hpp>

View file

@ -108,6 +108,10 @@ namespace MWLua
} }
luaManager->addUIMessage(message, mode); luaManager->addUIMessage(message, mode);
}; };
api["_showInteractiveMessage"] = [windowManager](std::string_view message, sol::optional<sol::table>) {
windowManager->interactiveMessageBox(message, { "#{Interface:OK}" });
};
api["CONSOLE_COLOR"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string, Misc::Color>(lua, api["CONSOLE_COLOR"] = LuaUtil::makeStrictReadOnly(LuaUtil::tableFromPairs<std::string, Misc::Color>(lua,
{ {
{ "Default", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Default.substr(1)) }, { "Default", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Default.substr(1)) },

View file

@ -3,11 +3,11 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
sol::table initUserInterfacePackage(const Context&); struct Context;
sol::table initUserInterfacePackage(const Context& context);
} }
#endif // MWLUA_UIBINDINGS_H #endif // MWLUA_UIBINDINGS_H

View file

@ -1,7 +1,8 @@
#ifndef MWLUA_USERDATASERIALIZER_H #ifndef MWLUA_USERDATASERIALIZER_H
#define MWLUA_USERDATASERIALIZER_H #define MWLUA_USERDATASERIALIZER_H
#include "object.hpp" #include <map>
#include <memory>
namespace LuaUtil namespace LuaUtil
{ {

View file

@ -3,11 +3,11 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
sol::table initVFSPackage(const Context&); struct Context;
sol::table initVFSPackage(const Context& context);
} }
#endif // MWLUA_VFSBINDINGS_H #endif // MWLUA_VFSBINDINGS_H

View file

@ -7,7 +7,6 @@
#include <components/esm3/loadclot.hpp> #include <components/esm3/loadclot.hpp>
#include <components/esm3/loadligh.hpp> #include <components/esm3/loadligh.hpp>
#include <components/esm3/loadmisc.hpp> #include <components/esm3/loadmisc.hpp>
#include <components/esm3/loadskil.hpp>
#include <components/esm3/loadweap.hpp> #include <components/esm3/loadweap.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/misc/finitenumbers.hpp> #include <components/misc/finitenumbers.hpp>
@ -27,6 +26,7 @@
#include "luamanagerimp.hpp" #include "luamanagerimp.hpp"
#include "animationbindings.hpp" #include "animationbindings.hpp"
#include "context.hpp"
#include "corebindings.hpp" #include "corebindings.hpp"
#include "mwscriptbindings.hpp" #include "mwscriptbindings.hpp"

View file

@ -3,11 +3,11 @@
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include "context.hpp"
namespace MWLua namespace MWLua
{ {
sol::table initWorldPackage(const Context&); struct Context;
sol::table initWorldPackage(const Context& context);
} }
#endif // MWLUA_WORLDBINDINGS_H #endif // MWLUA_WORLDBINDINGS_H

View file

@ -93,9 +93,10 @@ namespace
namespace MWPhysics namespace MWPhysics
{ {
PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode) PhysicsSystem::PhysicsSystem(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> parentNode)
: mShapeManager( : mPhysicsDt(1.f / 60.f)
std::make_unique<Resource::BulletShapeManager>(resourceSystem->getVFS(), resourceSystem->getSceneManager(), , mShapeManager(std::make_unique<Resource::BulletShapeManager>(resourceSystem->getVFS(),
resourceSystem->getNifFileManager(), Settings::cells().mCacheExpiryDelay)) resourceSystem->getSceneManager(), resourceSystem->getNifFileManager(),
Settings::cells().mCacheExpiryDelay))
, mResourceSystem(resourceSystem) , mResourceSystem(resourceSystem)
, mDebugDrawEnabled(false) , mDebugDrawEnabled(false)
, mTimeAccum(0.0f) , mTimeAccum(0.0f)
@ -103,7 +104,6 @@ namespace MWPhysics
, mWaterHeight(0) , mWaterHeight(0)
, mWaterEnabled(false) , mWaterEnabled(false)
, mParentNode(std::move(parentNode)) , mParentNode(std::move(parentNode))
, mPhysicsDt(1.f / 60.f)
{ {
mResourceSystem->addResourceManager(mShapeManager.get()); mResourceSystem->addResourceManager(mShapeManager.get());

View file

@ -287,6 +287,8 @@ namespace MWPhysics
void reportStats(unsigned int frameNumber, osg::Stats& stats) const; void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
void reportCollision(const btVector3& position, const btVector3& normal); void reportCollision(const btVector3& position, const btVector3& normal);
float mPhysicsDt;
private: private:
void updateWater(); void updateWater();
@ -330,8 +332,6 @@ namespace MWPhysics
osg::ref_ptr<osg::Group> mParentNode; osg::ref_ptr<osg::Group> mParentNode;
float mPhysicsDt;
std::size_t mSimulationsCounter = 0; std::size_t mSimulationsCounter = 0;
std::array<std::vector<Simulation>, 2> mSimulations; std::array<std::vector<Simulation>, 2> mSimulations;
std::vector<std::pair<MWWorld::Ptr, osg::Vec3f>> mActorsPositions; std::vector<std::pair<MWWorld::Ptr, osg::Vec3f>> mActorsPositions;

View file

@ -1117,8 +1117,8 @@ namespace MWRender
return keyframeController->getAsCallback(); return keyframeController->getAsCallback();
} }
else
return asCallback; return asCallback;
} }
void Animation::resetActiveGroups() void Animation::resetActiveGroups()

View file

@ -401,14 +401,12 @@ namespace MWRender
{ {
if (mViewMode == VM_FirstPerson) if (mViewMode == VM_FirstPerson)
{ {
static bool prototypeAdded = false; [[maybe_unused]] static const bool prototypeAdded = [&] {
if (!prototypeAdded)
{
osg::ref_ptr<osgUtil::RenderBin> depthClearBin(new osgUtil::RenderBin); osg::ref_ptr<osgUtil::RenderBin> depthClearBin(new osgUtil::RenderBin);
depthClearBin->setDrawCallback(new DepthClearCallback()); depthClearBin->setDrawCallback(new DepthClearCallback());
osgUtil::RenderBin::addRenderBinPrototype("DepthClear", depthClearBin); osgUtil::RenderBin::addRenderBinPrototype("DepthClear", depthClearBin);
prototypeAdded = true; return true;
} }();
mObjectRoot->getOrCreateStateSet()->setRenderBinDetails( mObjectRoot->getOrCreateStateSet()->setRenderBinDetails(
RenderBin_FirstPerson, "DepthClear", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); RenderBin_FirstPerson, "DepthClear", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS);
} }

View file

@ -88,14 +88,13 @@ namespace MWRender
if (mProgramBlobber != nullptr) if (mProgramBlobber != nullptr)
{ {
static bool pipelineLogged = [&] { [[maybe_unused]] static const bool pipelineLogged = [&] {
if (mUseCompute) if (mUseCompute)
Log(Debug::Info) << "Initialized compute shader pipeline for water ripples"; Log(Debug::Info) << "Initialized compute shader pipeline for water ripples";
else else
Log(Debug::Info) << "Initialized fallback fragment shader pipeline for water ripples"; Log(Debug::Info) << "Initialized fallback fragment shader pipeline for water ripples";
return true; return true;
}(); }();
(void)pipelineLogged;
} }
setCullCallback(new osg::NodeCallback); setCullCallback(new osg::NodeCallback);

View file

@ -1,6 +1,8 @@
#include "terrainstorage.hpp" #include "terrainstorage.hpp"
#include <components/esm3/loadland.hpp> #include <components/esm3/loadland.hpp>
#include <components/esm4/loadltex.hpp>
#include <components/esm4/loadtxst.hpp>
#include <components/esm4/loadwrld.hpp> #include <components/esm4/loadwrld.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -111,4 +113,15 @@ namespace MWRender
return esmStore.get<ESM::LandTexture>().search(index, plugin); return esmStore.get<ESM::LandTexture>().search(index, plugin);
} }
const ESM4::LandTexture* TerrainStorage::getEsm4LandTexture(ESM::RefId ltexId) const
{
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
return esmStore.get<ESM4::LandTexture>().search(ltexId);
}
const ESM4::TextureSet* TerrainStorage::getEsm4TextureSet(ESM::RefId txstId) const
{
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
return esmStore.get<ESM4::TextureSet>().search(txstId);
}
} }

View file

@ -24,6 +24,9 @@ namespace MWRender
osg::ref_ptr<const ESMTerrain::LandObject> getLand(ESM::ExteriorCellLocation cellLocation) override; osg::ref_ptr<const ESMTerrain::LandObject> getLand(ESM::ExteriorCellLocation cellLocation) override;
const std::string* getLandTexture(std::uint16_t index, int plugin) override; const std::string* getLandTexture(std::uint16_t index, int plugin) override;
const ESM4::LandTexture* getEsm4LandTexture(ESM::RefId ltexId) const override;
const ESM4::TextureSet* getEsm4TextureSet(ESM::RefId txstId) const override;
bool hasData(ESM::ExteriorCellLocation cellLocation) override; bool hasData(ESM::ExteriorCellLocation cellLocation) override;
/// Get bounds of the whole terrain in cell units /// Get bounds of the whole terrain in cell units

View file

@ -604,7 +604,7 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
std::string_view effect = runtime.getStringLiteral(runtime[0].mInteger); const std::string_view effectName = runtime.getStringLiteral(runtime[0].mInteger);
runtime.pop(); runtime.pop();
if (!ptr.getClass().isActor()) if (!ptr.getClass().isActor())
@ -615,11 +615,11 @@ namespace MWScript
long key; long key;
if (const auto k = ::Misc::StringUtils::toNumeric<long>(effect.data()); if (const auto k = ::Misc::StringUtils::toNumeric<long>(effectName);
k.has_value() && *k >= 0 && *k <= 32767) k.has_value() && *k >= 0 && *k <= 32767)
key = *k; key = *k;
else else
key = ESM::MagicEffect::effectGmstIdToIndex(effect); key = ESM::MagicEffect::effectGmstIdToIndex(effectName);
const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
for (const auto& spell : stats.getActiveSpells()) for (const auto& spell : stats.getActiveSpells())

View file

@ -522,16 +522,14 @@ namespace MWSound
/* We need to make sure ffmpeg is initialized. Optionally silence warning /* We need to make sure ffmpeg is initialized. Optionally silence warning
* output from the lib */ * output from the lib */
static bool done_init = false; [[maybe_unused]] static const bool doneInit = [] {
if (!done_init)
{
// This is not needed anymore above FFMpeg version 4.0 // This is not needed anymore above FFMpeg version 4.0
#if LIBAVCODEC_VERSION_INT < 3805796 #if LIBAVCODEC_VERSION_INT < 3805796
av_register_all(); av_register_all();
#endif #endif
av_log_set_level(AV_LOG_ERROR); av_log_set_level(AV_LOG_ERROR);
done_init = true; return true;
} }();
} }
FFmpegDecoder::~FFmpegDecoder() FFmpegDecoder::~FFmpegDecoder()

View file

@ -15,6 +15,7 @@
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/misc/thread.hpp> #include <components/misc/thread.hpp>
#include <components/settings/values.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include "efxpresets.h" #include "efxpresets.h"
@ -963,6 +964,7 @@ namespace MWSound
// Speed of sound is in units per second. Take the sound speed in air (assumed // Speed of sound is in units per second. Take the sound speed in air (assumed
// meters per second), multiply by the units per meter to get the speed in u/s. // meters per second), multiply by the units per meter to get the speed in u/s.
alSpeedOfSound(Constants::SoundSpeedInAir * Constants::UnitsPerMeter); alSpeedOfSound(Constants::SoundSpeedInAir * Constants::UnitsPerMeter);
alDopplerFactor(Settings::sound().mDopplerFactor);
alGetError(); alGetError();
mInitialized = true; mInitialized = true;
@ -1142,8 +1144,8 @@ namespace MWSound
alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
} }
void OpenALOutput::initCommon3D(ALuint source, const osg::Vec3f& pos, ALfloat mindist, ALfloat maxdist, void OpenALOutput::initCommon3D(ALuint source, const osg::Vec3f& pos, const osg::Vec3f& vel, ALfloat mindist,
ALfloat gain, ALfloat pitch, bool loop, bool useenv) ALfloat maxdist, ALfloat gain, ALfloat pitch, bool loop, bool useenv)
{ {
alSourcef(source, AL_REFERENCE_DISTANCE, mindist); alSourcef(source, AL_REFERENCE_DISTANCE, mindist);
alSourcef(source, AL_MAX_DISTANCE, maxdist); alSourcef(source, AL_MAX_DISTANCE, maxdist);
@ -1179,11 +1181,11 @@ namespace MWSound
alSourcef(source, AL_PITCH, pitch); alSourcef(source, AL_PITCH, pitch);
alSourcefv(source, AL_POSITION, pos.ptr()); alSourcefv(source, AL_POSITION, pos.ptr());
alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSourcefv(source, AL_VELOCITY, vel.ptr());
} }
void OpenALOutput::updateCommon( void OpenALOutput::updateCommon(ALuint source, const osg::Vec3f& pos, const osg::Vec3f& vel, ALfloat maxdist,
ALuint source, const osg::Vec3f& pos, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool useenv) ALfloat gain, ALfloat pitch, bool useenv)
{ {
if (useenv && mListenerEnv == Env_Underwater && !mWaterFilter) if (useenv && mListenerEnv == Env_Underwater && !mWaterFilter)
{ {
@ -1195,7 +1197,7 @@ namespace MWSound
alSourcef(source, AL_PITCH, pitch); alSourcef(source, AL_PITCH, pitch);
alSourcefv(source, AL_POSITION, pos.ptr()); alSourcefv(source, AL_POSITION, pos.ptr());
alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSourcefv(source, AL_VELOCITY, vel.ptr());
} }
bool OpenALOutput::playSound(Sound* sound, Sound_Handle data, float offset) bool OpenALOutput::playSound(Sound* sound, Sound_Handle data, float offset)
@ -1248,8 +1250,9 @@ namespace MWSound
} }
source = mFreeSources.front(); source = mFreeSources.front();
initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), initCommon3D(source, sound->getPosition(), sound->getVelocity(), sound->getMinDistance(),
sound->getRealVolume(), getTimeScaledPitch(sound), sound->getIsLooping(), sound->getUseEnv()); sound->getMaxDistance(), sound->getRealVolume(), getTimeScaledPitch(sound), sound->getIsLooping(),
sound->getUseEnv());
alSourcei(source, AL_BUFFER, GET_PTRID(data)); alSourcei(source, AL_BUFFER, GET_PTRID(data));
alSourcef(source, AL_SEC_OFFSET, offset); alSourcef(source, AL_SEC_OFFSET, offset);
if (getALError() != AL_NO_ERROR) if (getALError() != AL_NO_ERROR)
@ -1312,8 +1315,8 @@ namespace MWSound
return; return;
ALuint source = GET_PTRID(sound->mHandle); ALuint source = GET_PTRID(sound->mHandle);
updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(), updateCommon(source, sound->getPosition(), sound->getVelocity(), sound->getMaxDistance(),
getTimeScaledPitch(sound), sound->getUseEnv()); sound->getRealVolume(), getTimeScaledPitch(sound), sound->getUseEnv());
getALError(); getALError();
} }
@ -1360,8 +1363,8 @@ namespace MWSound
if (sound->getIsLooping()) if (sound->getIsLooping())
Log(Debug::Warning) << "Warning: cannot loop stream \"" << decoder->getName() << "\""; Log(Debug::Warning) << "Warning: cannot loop stream \"" << decoder->getName() << "\"";
initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), initCommon3D(source, sound->getPosition(), sound->getVelocity(), sound->getMinDistance(),
sound->getRealVolume(), getTimeScaledPitch(sound), false, sound->getUseEnv()); sound->getMaxDistance(), sound->getRealVolume(), getTimeScaledPitch(sound), false, sound->getUseEnv());
if (getALError() != AL_NO_ERROR) if (getALError() != AL_NO_ERROR)
return false; return false;
@ -1443,8 +1446,8 @@ namespace MWSound
OpenAL_SoundStream* stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle); OpenAL_SoundStream* stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
ALuint source = stream->mSource; ALuint source = stream->mSource;
updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(), updateCommon(source, sound->getPosition(), sound->getVelocity(), sound->getMaxDistance(),
getTimeScaledPitch(sound), sound->getUseEnv()); sound->getRealVolume(), getTimeScaledPitch(sound), sound->getUseEnv());
getALError(); getALError();
} }
@ -1459,12 +1462,13 @@ namespace MWSound
} }
void OpenALOutput::updateListener( void OpenALOutput::updateListener(
const osg::Vec3f& pos, const osg::Vec3f& atdir, const osg::Vec3f& updir, Environment env) const osg::Vec3f& pos, const osg::Vec3f& atdir, const osg::Vec3f& updir, const osg::Vec3f& vel, Environment env)
{ {
if (mContext) if (mContext)
{ {
ALfloat orient[6] = { atdir.x(), atdir.y(), atdir.z(), updir.x(), updir.y(), updir.z() }; ALfloat orient[6] = { atdir.x(), atdir.y(), atdir.z(), updir.x(), updir.y(), updir.z() };
alListenerfv(AL_POSITION, pos.ptr()); alListenerfv(AL_POSITION, pos.ptr());
alListenerfv(AL_VELOCITY, vel.ptr());
alListenerfv(AL_ORIENTATION, orient); alListenerfv(AL_ORIENTATION, orient);
if (env != mListenerEnv) if (env != mListenerEnv)
@ -1497,6 +1501,7 @@ namespace MWSound
} }
mListenerPos = pos; mListenerPos = pos;
mListenerVel = vel;
mListenerEnv = env; mListenerEnv = env;
} }
@ -1582,7 +1587,6 @@ namespace MWSound
: SoundOutput(mgr) : SoundOutput(mgr)
, mDevice(nullptr) , mDevice(nullptr)
, mContext(nullptr) , mContext(nullptr)
, mListenerPos(0.0f, 0.0f, 0.0f)
, mListenerEnv(Env_Normal) , mListenerEnv(Env_Normal)
, mWaterFilter(0) , mWaterFilter(0)
, mWaterEffect(0) , mWaterEffect(0)

View file

@ -46,6 +46,7 @@ namespace MWSound
StreamVec mActiveStreams; StreamVec mActiveStreams;
osg::Vec3f mListenerPos; osg::Vec3f mListenerPos;
osg::Vec3f mListenerVel;
Environment mListenerEnv; Environment mListenerEnv;
ALuint mWaterFilter; ALuint mWaterFilter;
@ -64,11 +65,11 @@ namespace MWSound
std::unique_ptr<DefaultDeviceThread> mDefaultDeviceThread; std::unique_ptr<DefaultDeviceThread> mDefaultDeviceThread;
void initCommon2D(ALuint source, const osg::Vec3f& pos, ALfloat gain, ALfloat pitch, bool loop, bool useenv); void initCommon2D(ALuint source, const osg::Vec3f& pos, ALfloat gain, ALfloat pitch, bool loop, bool useenv);
void initCommon3D(ALuint source, const osg::Vec3f& pos, ALfloat mindist, ALfloat maxdist, ALfloat gain, void initCommon3D(ALuint source, const osg::Vec3f& pos, const osg::Vec3f& vel, ALfloat mindist, ALfloat maxdist,
ALfloat pitch, bool loop, bool useenv); ALfloat gain, ALfloat pitch, bool loop, bool useenv);
void updateCommon( void updateCommon(ALuint source, const osg::Vec3f& pos, const osg::Vec3f& vel, ALfloat maxdist, ALfloat gain,
ALuint source, const osg::Vec3f& pos, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool useenv); ALfloat pitch, bool useenv);
float getTimeScaledPitch(SoundBase* sound); float getTimeScaledPitch(SoundBase* sound);
@ -108,8 +109,8 @@ namespace MWSound
void startUpdate() override; void startUpdate() override;
void finishUpdate() override; void finishUpdate() override;
void updateListener( void updateListener(const osg::Vec3f& pos, const osg::Vec3f& atdir, const osg::Vec3f& updir,
const osg::Vec3f& pos, const osg::Vec3f& atdir, const osg::Vec3f& updir, Environment env) override; const osg::Vec3f& vel, Environment env) override;
void pauseSounds(int types) override; void pauseSounds(int types) override;
void resumeSounds(int types) override; void resumeSounds(int types) override;

View file

@ -31,6 +31,8 @@ namespace MWSound
struct SoundParams struct SoundParams
{ {
osg::Vec3f mPos; osg::Vec3f mPos;
osg::Vec3f mLastPos;
osg::Vec3f mVel;
float mVolume = 1.0f; float mVolume = 1.0f;
float mBaseVolume = 1.0f; float mBaseVolume = 1.0f;
float mPitch = 1.0f; float mPitch = 1.0f;
@ -57,6 +59,8 @@ namespace MWSound
public: public:
void setPosition(const osg::Vec3f& pos) { mParams.mPos = pos; } void setPosition(const osg::Vec3f& pos) { mParams.mPos = pos; }
void setLastPosition(const osg::Vec3f& lastpos) { mParams.mLastPos = lastpos; }
void setVelocity(const osg::Vec3f& vel) { mParams.mVel = vel; }
void setVolume(float volume) { mParams.mVolume = volume; } void setVolume(float volume) { mParams.mVolume = volume; }
void setBaseVolume(float volume) { mParams.mBaseVolume = volume; } void setBaseVolume(float volume) { mParams.mBaseVolume = volume; }
void setFadeout(float duration) { setFade(duration, 0.0, Play_StopAtFadeEnd); } void setFadeout(float duration) { setFade(duration, 0.0, Play_StopAtFadeEnd); }
@ -150,6 +154,8 @@ namespace MWSound
} }
const osg::Vec3f& getPosition() const { return mParams.mPos; } const osg::Vec3f& getPosition() const { return mParams.mPos; }
const osg::Vec3f& getLastPosition() const { return mParams.mLastPos; }
const osg::Vec3f& getVelocity() const { return mParams.mVel; }
float getRealVolume() const { return mParams.mVolume * mParams.mBaseVolume * mParams.mFadeVolume; } float getRealVolume() const { return mParams.mVolume * mParams.mBaseVolume * mParams.mFadeVolume; }
float getPitch() const { return mParams.mPitch; } float getPitch() const { return mParams.mPitch; }
float getMinDistance() const { return mParams.mMinDistance; } float getMinDistance() const { return mParams.mMinDistance; }

View file

@ -119,6 +119,7 @@ namespace MWSound
, mListenerPos(0, 0, 0) , mListenerPos(0, 0, 0)
, mListenerDir(1, 0, 0) , mListenerDir(1, 0, 0)
, mListenerUp(0, 0, 1) , mListenerUp(0, 0, 1)
, mListenerVel(0, 0, 0)
, mUnderwaterSound(nullptr) , mUnderwaterSound(nullptr)
, mNearWaterSound(nullptr) , mNearWaterSound(nullptr)
, mPlaybackPaused(false) , mPlaybackPaused(false)
@ -960,7 +961,7 @@ namespace MWSound
} }
mOutput->startUpdate(); mOutput->startUpdate();
mOutput->updateListener(mListenerPos, mListenerDir, mListenerUp, env); mOutput->updateListener(mListenerPos, mListenerDir, mListenerUp, mListenerVel, env);
updateMusic(duration); updateMusic(duration);
@ -977,7 +978,13 @@ namespace MWSound
if (sound->getIs3D()) if (sound->getIs3D())
{ {
if (!ptr.isEmpty()) if (!ptr.isEmpty())
{
sound->setLastPosition(sound->getPosition());
sound->setPosition(ptr.getRefData().getPosition().asVec3()); sound->setPosition(ptr.getRefData().getPosition().asVec3());
MWBase::World* world = MWBase::Environment::get().getWorld();
sound->setVelocity(
(sound->getPosition() - sound->getLastPosition()) / world->getPhysicsFrameRateDt());
}
cull3DSound(sound); cull3DSound(sound);
} }
@ -1013,8 +1020,11 @@ namespace MWSound
{ {
if (!ptr.isEmpty()) if (!ptr.isEmpty())
{ {
sound->setLastPosition(sound->getPosition());
MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
sound->setPosition(world->getActorHeadTransform(ptr).getTrans()); sound->setPosition(world->getActorHeadTransform(ptr).getTrans());
sound->setVelocity(
(sound->getPosition() - sound->getLastPosition()) / world->getPhysicsFrameRateDt());
} }
cull3DSound(sound); cull3DSound(sound);
@ -1153,6 +1163,11 @@ namespace MWSound
mWaterSoundUpdater.setUnderwater(underwater); mWaterSoundUpdater.setUnderwater(underwater);
} }
void SoundManager::setListenerVel(const osg::Vec3f& vel)
{
mListenerVel = vel;
}
void SoundManager::updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated) void SoundManager::updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated)
{ {
SoundMap::iterator snditer = mActiveSounds.find(old.mRef); SoundMap::iterator snditer = mActiveSounds.find(old.mRef);

View file

@ -92,6 +92,7 @@ namespace MWSound
osg::Vec3f mListenerPos; osg::Vec3f mListenerPos;
osg::Vec3f mListenerDir; osg::Vec3f mListenerDir;
osg::Vec3f mListenerUp; osg::Vec3f mListenerUp;
osg::Vec3f mListenerVel;
int mPausedSoundTypes[BlockerType::MaxCount] = {}; int mPausedSoundTypes[BlockerType::MaxCount] = {};
@ -283,6 +284,8 @@ namespace MWSound
void setListenerPosDir( void setListenerPosDir(
const osg::Vec3f& pos, const osg::Vec3f& dir, const osg::Vec3f& up, bool underwater) override; const osg::Vec3f& pos, const osg::Vec3f& dir, const osg::Vec3f& up, bool underwater) override;
void setListenerVel(const osg::Vec3f& vel) override;
void updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated) override; void updatePtr(const MWWorld::ConstPtr& old, const MWWorld::ConstPtr& updated) override;
void clear() override; void clear() override;

View file

@ -61,8 +61,8 @@ namespace MWSound
virtual void startUpdate() = 0; virtual void startUpdate() = 0;
virtual void finishUpdate() = 0; virtual void finishUpdate() = 0;
virtual void updateListener( virtual void updateListener(const osg::Vec3f& pos, const osg::Vec3f& atdir, const osg::Vec3f& updir,
const osg::Vec3f& pos, const osg::Vec3f& atdir, const osg::Vec3f& updir, Environment env) const osg::Vec3f& vel, Environment env)
= 0; = 0;
virtual void pauseSounds(int types) = 0; virtual void pauseSounds(int types) = 0;

View file

@ -110,6 +110,7 @@ namespace ESM4
struct Static; struct Static;
struct StaticCollection; struct StaticCollection;
struct Terminal; struct Terminal;
struct TextureSet;
struct Tree; struct Tree;
struct Weapon; struct Weapon;
struct World; struct World;
@ -149,7 +150,7 @@ namespace MWWorld
Store<ESM4::LevelledNpc>, Store<ESM4::Light>, Store<ESM4::MiscItem>, Store<ESM4::MovableStatic>, Store<ESM4::LevelledNpc>, Store<ESM4::Light>, Store<ESM4::MiscItem>, Store<ESM4::MovableStatic>,
Store<ESM4::Npc>, Store<ESM4::Outfit>, Store<ESM4::Potion>, Store<ESM4::Race>, Store<ESM4::Reference>, Store<ESM4::Npc>, Store<ESM4::Outfit>, Store<ESM4::Potion>, Store<ESM4::Race>, Store<ESM4::Reference>,
Store<ESM4::Sound>, Store<ESM4::SoundReference>, Store<ESM4::Static>, Store<ESM4::StaticCollection>, Store<ESM4::Sound>, Store<ESM4::SoundReference>, Store<ESM4::Static>, Store<ESM4::StaticCollection>,
Store<ESM4::Terminal>, Store<ESM4::Tree>, Store<ESM4::Weapon>, Store<ESM4::World>>; Store<ESM4::Terminal>, Store<ESM4::TextureSet>, Store<ESM4::Tree>, Store<ESM4::Weapon>, Store<ESM4::World>>;
private: private:
template <typename T> template <typename T>

View file

@ -461,6 +461,11 @@ namespace MWWorld
update(magicBoltState, duration); update(magicBoltState, duration);
for (const auto& sound : magicBoltState.mSounds)
{
sound->setVelocity(direction * speed);
}
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit // For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit
// result. // result.
std::vector<MWWorld::Ptr> targetActors; std::vector<MWWorld::Ptr> targetActors;

View file

@ -1273,13 +1273,12 @@ namespace MWWorld
const std::size_t leftCapacity = mPreloader->getMaxCacheSize() - mPreloader->getCacheSize(); const std::size_t leftCapacity = mPreloader->getMaxCacheSize() - mPreloader->getCacheSize();
if (cells.size() > leftCapacity) if (cells.size() > leftCapacity)
{ {
static bool logged = [&] { [[maybe_unused]] static const bool logged = [&] {
Log(Debug::Warning) << "Not enough cell preloader cache capacity to preload exterior cells, consider " Log(Debug::Warning) << "Not enough cell preloader cache capacity to preload exterior cells, consider "
"increasing \"preload cell cache max\" up to " "increasing \"preload cell cache max\" up to "
<< (mPreloader->getCacheSize() + cells.size()); << (mPreloader->getCacheSize() + cells.size());
return true; return true;
}(); }();
(void)logged;
cells.resize(leftCapacity); cells.resize(leftCapacity);
} }

View file

@ -1354,6 +1354,7 @@ template class MWWorld::TypedDynamicStore<ESM4::SoundReference>;
template class MWWorld::TypedDynamicStore<ESM4::Static>; template class MWWorld::TypedDynamicStore<ESM4::Static>;
template class MWWorld::TypedDynamicStore<ESM4::StaticCollection>; template class MWWorld::TypedDynamicStore<ESM4::StaticCollection>;
template class MWWorld::TypedDynamicStore<ESM4::Terminal>; template class MWWorld::TypedDynamicStore<ESM4::Terminal>;
template class MWWorld::TypedDynamicStore<ESM4::TextureSet>;
template class MWWorld::TypedDynamicStore<ESM4::Tree>; template class MWWorld::TypedDynamicStore<ESM4::Tree>;
template class MWWorld::TypedDynamicStore<ESM4::Weapon>; template class MWWorld::TypedDynamicStore<ESM4::Weapon>;
template class MWWorld::TypedDynamicStore<ESM4::World>; template class MWWorld::TypedDynamicStore<ESM4::World>;

View file

@ -1460,6 +1460,8 @@ namespace MWWorld
void World::queueMovement(const Ptr& ptr, const osg::Vec3f& velocity) void World::queueMovement(const Ptr& ptr, const osg::Vec3f& velocity)
{ {
mPhysics->queueObjectMovement(ptr, velocity); mPhysics->queueObjectMovement(ptr, velocity);
if (ptr == MWMechanics::getPlayer())
MWBase::Environment::get().getSoundManager()->setListenerVel(velocity);
} }
void World::updateAnimatedCollisionShape(const Ptr& ptr) void World::updateAnimatedCollisionShape(const Ptr& ptr)
@ -3182,6 +3184,11 @@ namespace MWWorld
return mWeatherManager->getSunPercentage(getTimeStamp().getHour()); return mWeatherManager->getSunPercentage(getTimeStamp().getHour());
} }
float World::getPhysicsFrameRateDt() const
{
return mPhysics->mPhysicsDt;
}
bool World::findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) bool World::findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result)
{ {
if (cell->isExterior()) if (cell->isExterior())

View file

@ -584,6 +584,8 @@ namespace MWWorld
float getSunVisibility() const override; float getSunVisibility() const override;
float getSunPercentage() const override; float getSunPercentage() const override;
float getPhysicsFrameRateDt() const override;
bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override;
/// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker)

View file

@ -407,6 +407,7 @@ add_component_dir(detournavigator
areatype areatype
asyncnavmeshupdater asyncnavmeshupdater
bounds bounds
cellgridbounds
changetype changetype
collisionshapetype collisionshapetype
commulativeaabb commulativeaabb

View file

@ -8,7 +8,6 @@
#include <algorithm> #include <algorithm>
#include <cstdint> #include <cstdint>
#include <optional>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <variant> #include <variant>

View file

@ -10,10 +10,8 @@
#include <osg/io_utils> #include <osg/io_utils>
#include <functional>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <stdexcept>
#include <vector> #include <vector>
namespace DetourNavigator namespace DetourNavigator
@ -79,7 +77,7 @@ namespace DetourNavigator
return; return;
} }
const auto data const std::unique_ptr<PreparedNavMeshData> data
= prepareNavMeshTileData(*recastMesh, mWorldspace, mTilePosition, mAgentBounds, mSettings.mRecast); = prepareNavMeshTileData(*recastMesh, mWorldspace, mTilePosition, mAgentBounds, mSettings.mRecast);
if (data == nullptr) if (data == nullptr)

View file

@ -3,8 +3,6 @@
#include "exceptions.hpp" #include "exceptions.hpp"
#include "flags.hpp" #include "flags.hpp"
#include "navmeshdata.hpp" #include "navmeshdata.hpp"
#include "navmeshdb.hpp"
#include "navmeshtilescache.hpp"
#include "offmeshconnection.hpp" #include "offmeshconnection.hpp"
#include "preparednavmeshdata.hpp" #include "preparednavmeshdata.hpp"
#include "recastcontext.hpp" #include "recastcontext.hpp"
@ -22,8 +20,6 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <iomanip>
#include <limits>
namespace DetourNavigator namespace DetourNavigator
{ {

View file

@ -4,7 +4,6 @@
#include <DetourCommon.h> #include <DetourCommon.h>
#include <DetourNavMesh.h> #include <DetourNavMesh.h>
#include <algorithm>
#include <cassert> #include <cassert>
#include <stdexcept> #include <stdexcept>
#include <tuple> #include <tuple>

View file

@ -6,7 +6,6 @@
#include <osg/Vec3f> #include <osg/Vec3f>
#include <tuple> #include <tuple>
#include <vector>
namespace DetourNavigator namespace DetourNavigator
{ {

View file

@ -4,8 +4,6 @@
#include <Recast.h> #include <Recast.h>
#include <cstring>
namespace namespace
{ {
void initPolyMeshDetail(rcPolyMeshDetail& value) noexcept void initPolyMeshDetail(rcPolyMeshDetail& value) noexcept

View file

@ -3,9 +3,10 @@
#include "flags.hpp" #include "flags.hpp"
#include <optional>
#include <osg/Vec3f> #include <osg/Vec3f>
#include <optional>
class dtNavMeshQuery; class dtNavMeshQuery;
namespace DetourNavigator namespace DetourNavigator

View file

@ -11,9 +11,7 @@
#include <osg/Vec3f> #include <osg/Vec3f>
#include <cstdint> #include <cstdint>
#include <memory>
#include <numeric> #include <numeric>
#include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>

View file

@ -31,6 +31,7 @@ namespace ESM
VER_134 = 0x3fab851f, // FONV, GunRunnersArsenal, LonesomeRoad, OldWorldBlues VER_134 = 0x3fab851f, // FONV, GunRunnersArsenal, LonesomeRoad, OldWorldBlues
VER_094 = 0x3f70a3d7, // TES5/FO3 VER_094 = 0x3f70a3d7, // TES5/FO3
VER_170 = 0x3fd9999a, // TES5 VER_170 = 0x3fd9999a, // TES5
VER_171 = 0x3fdae148, // TES5
VER_095 = 0x3f733333, // FO4 VER_095 = 0x3f733333, // FO4
}; };

View file

@ -33,6 +33,7 @@ ESM::LandData::LandData(const ESM::Land& land, int loadFlags)
, mNormals(mData->mNormals) , mNormals(mData->mNormals)
, mColors(mData->mColours) , mColors(mData->mColours)
, mTextures(mData->mTextures) , mTextures(mData->mTextures)
, mIsEsm4(false)
{ {
} }
@ -43,9 +44,11 @@ ESM::LandData::LandData(const ESM4::Land& land, int /*loadFlags*/)
, mMaxHeight(std::numeric_limits<float>::lowest()) , mMaxHeight(std::numeric_limits<float>::lowest())
, mSize(Constants::ESM4CellSizeInUnits) , mSize(Constants::ESM4CellSizeInUnits)
, mLandSize(ESM4::Land::sVertsPerSide) , mLandSize(ESM4::Land::sVertsPerSide)
, mPlugin(land.mId.mContentFile)
, mNormals(land.mVertNorm) , mNormals(land.mVertNorm)
, mColors(land.mVertColr) , mColors(land.mVertColr)
, mTextures(textures) , mTextures(textures)
, mIsEsm4(true)
{ {
float rowOffset = land.mHeightMap.heightOffset; float rowOffset = land.mHeightMap.heightOffset;
for (int y = 0; y < mLandSize; y++) for (int y = 0; y < mLandSize; y++)
@ -69,6 +72,9 @@ ESM::LandData::LandData(const ESM4::Land& land, int /*loadFlags*/)
} }
mHeights = mHeightsData; mHeights = mHeightsData;
for (int i = 0; i < 4; ++i)
mEsm4Textures[i] = land.mTextures[i];
} }
namespace ESM namespace ESM

View file

@ -1,15 +1,13 @@
#ifndef COMPONENTS_ESM_ESMTERRAIN #ifndef COMPONENTS_ESM_ESMTERRAIN
#define COMPONENTS_ESM_ESMTERRAIN #define COMPONENTS_ESM_ESMTERRAIN
#include <array>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <span> #include <span>
#include <vector> #include <vector>
namespace ESM4 #include <components/esm4/loadland.hpp>
{
struct Land;
}
namespace ESM namespace ESM
{ {
@ -28,7 +26,6 @@ namespace ESM
std::span<const float> getHeights() const { return mHeights; } std::span<const float> getHeights() const { return mHeights; }
std::span<const std::int8_t> getNormals() const { return mNormals; } std::span<const std::int8_t> getNormals() const { return mNormals; }
std::span<const std::uint8_t> getColors() const { return mColors; } std::span<const std::uint8_t> getColors() const { return mColors; }
std::span<const std::uint16_t> getTextures() const { return mTextures; }
float getSize() const { return mSize; } float getSize() const { return mSize; }
float getMinHeight() const { return mMinHeight; } float getMinHeight() const { return mMinHeight; }
float getMaxHeight() const { return mMaxHeight; } float getMaxHeight() const { return mMaxHeight; }
@ -36,6 +33,22 @@ namespace ESM
int getLoadFlags() const { return mLoadFlags; } int getLoadFlags() const { return mLoadFlags; }
int getPlugin() const { return mPlugin; } int getPlugin() const { return mPlugin; }
bool isEsm4() const { return mIsEsm4; }
std::span<const std::uint16_t> getTextures() const
{
if (mIsEsm4)
throw std::logic_error("ESM3 textures requested from ESM4 LandData");
return mTextures;
}
const ESM4::Land::Texture& getEsm4Texture(std::size_t quad) const
{
if (!mIsEsm4)
throw std::logic_error("ESM4 texture requested from ESM3 LandData");
return mEsm4Textures[quad];
}
private: private:
std::unique_ptr<const ESM::LandRecordData> mData; std::unique_ptr<const ESM::LandRecordData> mData;
int mLoadFlags = 0; int mLoadFlags = 0;
@ -49,6 +62,8 @@ namespace ESM
std::span<const std::int8_t> mNormals; std::span<const std::int8_t> mNormals;
std::span<const std::uint8_t> mColors; std::span<const std::uint8_t> mColors;
std::span<const std::uint16_t> mTextures; std::span<const std::uint16_t> mTextures;
std::array<ESM4::Land::Texture, 4> mEsm4Textures;
bool mIsEsm4;
}; };
} }

View file

@ -51,10 +51,10 @@ namespace std
{ {
size_t operator()(const ESM::FormId& formId) const size_t operator()(const ESM::FormId& formId) const
{ {
static_assert(sizeof(ESM::FormId) == sizeof(size_t)); static_assert(sizeof(ESM::FormId) == sizeof(uint64_t));
size_t s; uint64_t s;
memcpy(&s, &formId, sizeof(size_t)); memcpy(&s, &formId, sizeof(ESM::FormId));
return hash<size_t>()(s); return hash<uint64_t>()(s);
} }
}; };

View file

@ -79,6 +79,7 @@
#include <components/esm4/loadstat.hpp> #include <components/esm4/loadstat.hpp>
#include <components/esm4/loadterm.hpp> #include <components/esm4/loadterm.hpp>
#include <components/esm4/loadtree.hpp> #include <components/esm4/loadtree.hpp>
#include <components/esm4/loadtxst.hpp>
#include <components/esm4/loadweap.hpp> #include <components/esm4/loadweap.hpp>
#include <components/esm4/loadwrld.hpp> #include <components/esm4/loadwrld.hpp>

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2015-2016, 2018, 2020-2021 cc9cii Copyright (C) 2015 - 2024 cc9cii
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
@ -17,7 +17,7 @@
misrepresented as being the original software. misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
cc9cii cc9c@iinet.net.au cc9cii cc9cii@hotmail.com
Much of the information on the data structures are based on the information Much of the information on the data structures are based on the information
from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by from Tes4Mod:Mod_File_Format and Tes5Mod:File_Formats but also refined by
@ -26,13 +26,51 @@
*/ */
#include "loadland.hpp" #include "loadland.hpp"
#include <cassert>
#include <cstdint> #include <cstdint>
#include <stdexcept> #include <stdexcept>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include "reader.hpp" #include "reader.hpp"
// #include "writer.hpp"
namespace
{
void assignDefaultTextures(ESM4::Land& land, ESM4::Reader& reader)
{
std::uint32_t esmVer = reader.esmVersion();
// Note: in games after TES4 it can be configured in ini file (sDefaultLandDiffuseTexture)
if (!reader.hasFormVersion() && (esmVer == ESM::VER_080 || esmVer == ESM::VER_100)) // TES4
{
land.mDefaultDiffuseMap = VFS::Path::NormalizedView("textures/landscape/terrainhddirt01.dds");
land.mDefaultNormalMap = VFS::Path::NormalizedView("textures/landscape/terrainhddirt01_n.dds");
}
else if (reader.hasFormVersion() && reader.formVersion() >= 16
&& (esmVer == ESM::VER_094 || esmVer == ESM::VER_170 || esmVer == ESM::VER_171)) // TES5
{
land.mDefaultDiffuseMap = VFS::Path::NormalizedView("textures/landscape/dirt02.dds");
land.mDefaultNormalMap = VFS::Path::NormalizedView("textures/landscape/dirt02_n.dds");
}
else if (esmVer == ESM::VER_095 || esmVer == ESM::VER_100) // FO4
{
land.mDefaultDiffuseMap
= VFS::Path::NormalizedView("textures/landscape/ground/commonwealthdefault01_d.dds");
land.mDefaultNormalMap = VFS::Path::NormalizedView("textures/landscape/ground/commonwealthdefault01_n.dds");
}
else if (esmVer == ESM::VER_094 || esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134)
{ // FO3, FONV
land.mDefaultDiffuseMap = VFS::Path::NormalizedView("textures/landscape/dirtwasteland01.dds");
land.mDefaultNormalMap = VFS::Path::NormalizedView("textures/landscape/dirtwasteland01_n.dds");
}
else
{
// Nothing especially bad happens if default texture is not set (except of the missing texture of course),
// but we throw an error because this case is unexpected and detection logic needs to be updated.
throw std::runtime_error("ESM4::Land unknown ESM version");
}
}
}
// overlap north // overlap north
// //
@ -53,12 +91,16 @@ void ESM4::Land::load(ESM4::Reader& reader)
{ {
mId = reader.getFormIdFromHeader(); mId = reader.getFormIdFromHeader();
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
mDataTypes = 0; mDataTypes = 0;
mCell = reader.currCell(); mCell = reader.currCell();
TxtLayer layer; TxtLayer layer;
std::int8_t currentAddQuad = -1; // for VTXT following ATXT std::int8_t currentAddQuad = -1; // for VTXT following ATXT
assignDefaultTextures(*this, reader);
// std::map<FormId, int> uniqueTextures; // FIXME: for temp testing only layer.texture.formId = 0;
for (int i = 0; i < 4; ++i)
mTextures[i].base.formId = 0;
while (reader.getSubRecordHeader()) while (reader.getSubRecordHeader())
{ {
@ -78,12 +120,6 @@ void ESM4::Land::load(ESM4::Reader& reader)
} }
case ESM::fourCC("VHGT"): // vertex height gradient, 4+33x33+3 = 4+1089+3 = 1096 case ESM::fourCC("VHGT"): // vertex height gradient, 4+33x33+3 = 4+1089+3 = 1096
{ {
#if 0
reader.get(mHeightMap.heightOffset);
reader.get(mHeightMap.gradientData);
reader.get(mHeightMap.unknown1);
reader.get(mHeightMap.unknown2);
#endif
reader.get(mHeightMap); reader.get(mHeightMap);
mDataTypes |= LAND_VHGT; mDataTypes |= LAND_VHGT;
break; break;
@ -102,13 +138,9 @@ void ESM4::Land::load(ESM4::Reader& reader)
if (base.quadrant >= 4) if (base.quadrant >= 4)
throw std::runtime_error("base texture quadrant index error"); throw std::runtime_error("base texture quadrant index error");
reader.adjustFormId(base.formId); if (base.formId != 0)
mTextures[base.quadrant].base = std::move(base); reader.adjustFormId(base.formId);
#if 0 mTextures[base.quadrant].base = base;
std::cout << "Base Texture formid: 0x"
<< std::hex << mTextures[base.quadrant].base.formId
<< ", quad " << std::dec << (int)base.quadrant << std::endl;
#endif
} }
break; break;
} }
@ -116,31 +148,23 @@ void ESM4::Land::load(ESM4::Reader& reader)
{ {
if (currentAddQuad != -1) if (currentAddQuad != -1)
{ {
// FIXME: sometimes there are no VTXT following an ATXT? Just add a dummy one for now // NOTE: sometimes there are no VTXT following an ATXT
Log(Debug::Verbose) << "ESM4::Land VTXT empty layer " << layer.texture.layerIndex; layer.data.resize(1); // just one spot
layer.data.back().position = 0; // this corner
layer.data.back().opacity = 0.f; // transparent
if (layer.texture.layerIndex != mTextures[currentAddQuad].layers.size())
throw std::runtime_error("ESM4::LAND additional texture skipping layer");
mTextures[currentAddQuad].layers.push_back(layer); mTextures[currentAddQuad].layers.push_back(layer);
} }
reader.get(layer.texture); reader.get(layer.texture);
reader.adjustFormId(layer.texture.formId); if (layer.texture.formId != 0)
reader.adjustFormId(layer.texture.formId);
if (layer.texture.quadrant >= 4) if (layer.texture.quadrant >= 4)
throw std::runtime_error("additional texture quadrant index error"); throw std::runtime_error("ESM4::LAND additional texture quadrant index error");
#if 0
FormId txt = layer.texture.formId;
std::map<FormId, int>::iterator lb = uniqueTextures.lower_bound(txt);
if (lb != uniqueTextures.end() && !(uniqueTextures.key_comp()(txt, lb->first)))
{
lb->second += 1;
}
else
uniqueTextures.insert(lb, std::make_pair(txt, 1));
#endif
#if 0
std::cout << "Additional Texture formId: 0x"
<< std::hex << layer.texture.formId
<< ", quad " << std::dec << (int)layer.texture.quadrant << std::endl;
std::cout << "Additional Texture layer: "
<< std::dec << (int)layer.texture.layerIndex << std::endl;
#endif
currentAddQuad = layer.texture.quadrant; currentAddQuad = layer.texture.quadrant;
break; break;
} }
@ -156,25 +180,17 @@ void ESM4::Land::load(ESM4::Reader& reader)
if (count) if (count)
{ {
layer.data.resize(count); layer.data.resize(count);
std::vector<ESM4::Land::VTXT>::iterator it = layer.data.begin(); for (ESM4::Land::VTXT& vtxt : layer.data)
for (; it != layer.data.end(); ++it) reader.get(vtxt);
{
reader.get(*it);
// FIXME: debug only
// std::cout << "pos: " << std::dec << (int)(*it).position << std::endl;
}
} }
mTextures[currentAddQuad].layers.push_back(layer);
// Assumed that the layers are added in the correct sequence if (layer.texture.layerIndex != mTextures[currentAddQuad].layers.size())
// FIXME: Knights.esp doesn't seem to observe this - investigate more throw std::runtime_error("ESM4::LAND additional texture skipping layer");
// assert(layer.texture.layerIndex == mTextures[currentAddQuad].layers.size()-1
//&& "additional texture layer index error"); mTextures[currentAddQuad].layers.push_back(layer);
currentAddQuad = -1; currentAddQuad = -1;
layer.data.clear(); layer.data.clear();
// FIXME: debug only
// std::cout << "VTXT: count " << std::dec << count << std::endl;
break; break;
} }
case ESM::fourCC("VTEX"): // only in Oblivion? case ESM::fourCC("VTEX"): // only in Oblivion?
@ -195,44 +211,14 @@ void ESM4::Land::load(ESM4::Reader& reader)
reader.skipSubRecordData(); reader.skipSubRecordData();
break; break;
default: default:
throw std::runtime_error("ESM4::LAND::load - Unknown subrecord " + ESM::printName(subHdr.typeId)); throw std::runtime_error("ESM4::LAND - Unknown subrecord " + ESM::printName(subHdr.typeId));
} }
} }
if (currentAddQuad != -1) if (currentAddQuad != -1)
{ {
// FIXME: not sure if it happens here as well // not sure if it happens here as well, if so just ignore
Log(Debug::Verbose) << "ESM4::Land VTXT empty layer " << layer.texture.layerIndex << " quad " Log(Debug::Verbose) << "ESM4::Land VTXT empty layer " << layer.texture.layerIndex << " quad "
<< static_cast<unsigned>(layer.texture.quadrant); << static_cast<unsigned>(layer.texture.quadrant);
mTextures[currentAddQuad].layers.push_back(layer);
} }
bool missing = false;
for (int i = 0; i < 4; ++i)
{
if (mTextures[i].base.formId == 0)
{
// std::cout << "ESM4::LAND " << ESM4::formIdToString(mFormId) << " missing base, quad " << i << std::endl;
// std::cout << "layers " << mTextures[i].layers.size() << std::endl;
// NOTE: can't set the default here since FO3/FONV may have different defaults
// mTextures[i].base.formId = 0x000008C0; // TerrainHDDirt01.dds
missing = true;
}
// else
//{
// std::cout << "ESM4::LAND " << ESM4::formIdToString(mFormId) << " base, quad " << i << std::endl;
// std::cout << "layers " << mTextures[i].layers.size() << std::endl;
// }
}
// at least one of the quadrants do not have a base texture, return without setting the flag
if (!missing)
mDataTypes |= LAND_VTEX;
} }
// void ESM4::Land::save(ESM4::Writer& writer) const
//{
// }
// void ESM4::Land::blank()
//{
// }

View file

@ -32,6 +32,7 @@
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include <components/esm/formid.hpp> #include <components/esm/formid.hpp>
#include <components/vfs/pathutil.hpp>
namespace ESM4 namespace ESM4
{ {
@ -124,6 +125,8 @@ namespace ESM4
Texture mTextures[4]; // 0 = bottom left, 1 = bottom right, 2 = top left, 3 = top right Texture mTextures[4]; // 0 = bottom left, 1 = bottom right, 2 = top left, 3 = top right
std::vector<ESM::FormId> mIds; // land texture (LTEX) formids std::vector<ESM::FormId> mIds; // land texture (LTEX) formids
ESM::FormId mCell; ESM::FormId mCell;
VFS::Path::NormalizedView mDefaultDiffuseMap;
VFS::Path::NormalizedView mDefaultNormalMap;
void load(Reader& reader); void load(Reader& reader);

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