mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-09-23 03:47:34 -04:00
Merge branch 'fargoths_lost_weather_ring' into 'master'
Make most weather bindings read/write See merge request OpenMW/openmw!4866
This commit is contained in:
commit
15b9d70cbe
@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...")
|
||||
set(OPENMW_VERSION_MAJOR 0)
|
||||
set(OPENMW_VERSION_MINOR 50)
|
||||
set(OPENMW_VERSION_RELEASE 0)
|
||||
set(OPENMW_LUA_API_REVISION 94)
|
||||
set(OPENMW_LUA_API_REVISION 95)
|
||||
set(OPENMW_POSTPROCESSING_API_REVISION 3)
|
||||
|
||||
set(OPENMW_VERSION_COMMITHASH "")
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "animationbindings.hpp"
|
||||
|
||||
#include <components/lua/luastate.hpp>
|
||||
#include <components/misc/finitenumbers.hpp>
|
||||
#include <components/misc/finitevalues.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include <components/lua/luastate.hpp>
|
||||
#include <components/lua/utilpackage.hpp>
|
||||
#include <components/misc/finitenumbers.hpp>
|
||||
#include <components/misc/finitevalues.hpp>
|
||||
#include <components/settings/values.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <components/esm3/loadregn.hpp>
|
||||
#include <components/lua/util.hpp>
|
||||
#include <components/misc/color.hpp>
|
||||
#include <components/misc/finitevalues.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
|
||||
@ -20,6 +21,18 @@
|
||||
#include "context.hpp"
|
||||
#include "object.hpp"
|
||||
|
||||
namespace sol
|
||||
{
|
||||
template <>
|
||||
struct is_automagical<MWWorld::TimeOfDayInterpolator<float>> : std::false_type
|
||||
{
|
||||
};
|
||||
template <>
|
||||
struct is_automagical<MWWorld::TimeOfDayInterpolator<osg::Vec4f>> : std::false_type
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class WeatherStore
|
||||
@ -36,11 +49,6 @@ namespace
|
||||
size_t size() const { return MWBase::Environment::get().getWorld()->getAllWeather().size(); }
|
||||
};
|
||||
|
||||
Misc::Color color(const osg::Vec4f& color)
|
||||
{
|
||||
return Misc::Color(color.r(), color.g(), color.b(), color.a());
|
||||
}
|
||||
|
||||
template <class Cell>
|
||||
bool hasWeather(const Cell& cell, bool requireExterior)
|
||||
{
|
||||
@ -77,110 +85,146 @@ namespace
|
||||
return (world.*getter)();
|
||||
});
|
||||
}
|
||||
|
||||
void createFloatInterpolator(sol::state_view lua)
|
||||
{
|
||||
using Misc::FiniteFloat;
|
||||
using T = MWWorld::TimeOfDayInterpolator<float>;
|
||||
|
||||
auto interT = lua.new_usertype<T>("TimeOfDayInterpolatorFloat");
|
||||
|
||||
interT["sunrise"] = sol::property([](const T& inter) { return inter.getSunriseValue(); },
|
||||
[](T& inter, FiniteFloat value) { inter.setSunriseValue(value); });
|
||||
interT["sunset"] = sol::property([](const T& inter) { return inter.getSunsetValue(); },
|
||||
[](T& inter, FiniteFloat value) { inter.setSunsetValue(value); });
|
||||
interT["day"] = sol::property([](const T& inter) { return inter.getDayValue(); },
|
||||
[](T& inter, FiniteFloat value) { inter.setDayValue(value); });
|
||||
interT["night"] = sol::property([](const T& inter) { return inter.getNightValue(); },
|
||||
[](T& inter, FiniteFloat value) { inter.setNightValue(value); });
|
||||
}
|
||||
|
||||
void createColorInterpolator(sol::state_view lua)
|
||||
{
|
||||
using Misc::Color;
|
||||
using T = MWWorld::TimeOfDayInterpolator<osg::Vec4f>;
|
||||
|
||||
auto interT = lua.new_usertype<T>("TimeOfDayInterpolatorColor");
|
||||
|
||||
interT["sunrise"] = sol::property([](const T& inter) { return Color::fromVec(inter.getSunriseValue()); },
|
||||
[](T& inter, const Color& value) { inter.setSunriseValue(value.toVec()); });
|
||||
interT["sunset"] = sol::property([](const T& inter) { return Color::fromVec(inter.getSunsetValue()); },
|
||||
[](T& inter, const Color& value) { inter.setSunsetValue(value.toVec()); });
|
||||
interT["day"] = sol::property([](const T& inter) { return Color::fromVec(inter.getDayValue()); },
|
||||
[](T& inter, const Color& value) { inter.setDayValue(value.toVec()); });
|
||||
interT["night"] = sol::property([](const T& inter) { return Color::fromVec(inter.getNightValue()); },
|
||||
[](T& inter, const Color& value) { inter.setNightValue(value.toVec()); });
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
sol::table initCoreWeatherBindings(const Context& context)
|
||||
{
|
||||
using Misc::FiniteFloat;
|
||||
using Misc::FiniteVec3f;
|
||||
|
||||
sol::state_view lua = context.sol();
|
||||
sol::table api(lua, sol::create);
|
||||
|
||||
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
auto weatherT = lua.new_usertype<MWWorld::Weather>("Weather");
|
||||
createFloatInterpolator(lua);
|
||||
createColorInterpolator(lua);
|
||||
|
||||
weatherT[sol::meta_function::to_string]
|
||||
= [](const MWWorld::Weather& w) -> std::string { return "Weather[" + w.mName + "]"; };
|
||||
weatherT["name"]
|
||||
= sol::readonly_property([](const MWWorld::Weather& w) -> std::string_view { return w.mName; });
|
||||
weatherT["windSpeed"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mWindSpeed; });
|
||||
weatherT["cloudSpeed"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mCloudSpeed; });
|
||||
weatherT["cloudTexture"] = sol::readonly_property([vfs](const MWWorld::Weather& w) {
|
||||
return Misc::ResourceHelpers::correctTexturePath(w.mCloudTexture, vfs);
|
||||
});
|
||||
weatherT["cloudsMaximumPercent"]
|
||||
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mCloudsMaximumPercent; });
|
||||
weatherT["isStorm"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mIsStorm; });
|
||||
weatherT["stormDirection"]
|
||||
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mStormDirection; });
|
||||
weatherT["glareView"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mGlareView; });
|
||||
weatherT["rainSpeed"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainSpeed; });
|
||||
weatherT["rainEntranceSpeed"]
|
||||
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainEntranceSpeed; });
|
||||
weatherT["rainEffect"] = sol::readonly_property([](const MWWorld::Weather& w) -> sol::optional<std::string> {
|
||||
if (w.mRainEffect.empty())
|
||||
return sol::nullopt;
|
||||
return w.mRainEffect;
|
||||
});
|
||||
weatherT["rainMaxRaindrops"]
|
||||
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainMaxRaindrops; });
|
||||
weatherT["rainDiameter"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainDiameter; });
|
||||
weatherT["rainThreshold"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainThreshold; });
|
||||
weatherT["rainMaxHeight"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainMaxHeight; });
|
||||
weatherT["rainMinHeight"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainMinHeight; });
|
||||
weatherT["rainLoopSoundID"]
|
||||
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainLoopSoundID.serializeText(); });
|
||||
weatherT["scriptId"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mScriptId; });
|
||||
weatherT["recordId"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mId.serializeText(); });
|
||||
weatherT["thunderSoundID"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
|
||||
sol::table result(lua, sol::create);
|
||||
for (const auto& soundId : w.mThunderSoundID)
|
||||
result.add(soundId.serializeText());
|
||||
return result;
|
||||
});
|
||||
|
||||
weatherT["windSpeed"] = sol::property([](const MWWorld::Weather& w) { return w.mWindSpeed; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat windSpeed) { w.mWindSpeed = windSpeed; });
|
||||
weatherT["cloudSpeed"] = sol::property([](const MWWorld::Weather& w) { return w.mCloudSpeed; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat cloudSpeed) { w.mCloudSpeed = cloudSpeed; });
|
||||
weatherT["cloudTexture"] = sol::property(
|
||||
[vfs](
|
||||
const MWWorld::Weather& w) { return Misc::ResourceHelpers::correctTexturePath(w.mCloudTexture, vfs); },
|
||||
[](MWWorld::Weather& w, std::string_view cloudTexture) { w.mCloudTexture = cloudTexture; });
|
||||
weatherT["cloudsMaximumPercent"]
|
||||
= sol::property([](const MWWorld::Weather& w) { return w.mCloudsMaximumPercent; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat cloudsMaximumPercent) {
|
||||
w.mCloudsMaximumPercent = cloudsMaximumPercent;
|
||||
});
|
||||
weatherT["isStorm"] = sol::property([](const MWWorld::Weather& w) { return w.mIsStorm; },
|
||||
[](MWWorld::Weather& w, bool isStorm) { w.mIsStorm = isStorm; });
|
||||
weatherT["stormDirection"] = sol::property([](const MWWorld::Weather& w) { return w.mStormDirection; },
|
||||
[](MWWorld::Weather& w, const FiniteVec3f& stormDirection) { w.mStormDirection = stormDirection; });
|
||||
weatherT["glareView"] = sol::property([](const MWWorld::Weather& w) { return w.mGlareView; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat glareView) { w.mGlareView = glareView; });
|
||||
weatherT["rainSpeed"] = sol::property([](const MWWorld::Weather& w) { return w.mRainSpeed; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat rainSpeed) { w.mRainSpeed = rainSpeed; });
|
||||
weatherT["rainEntranceSpeed"] = sol::property([](const MWWorld::Weather& w) { return w.mRainEntranceSpeed; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat rainEntranceSpeed) { w.mRainEntranceSpeed = rainEntranceSpeed; });
|
||||
weatherT["rainEffect"] = sol::property(
|
||||
[](const MWWorld::Weather& w) -> sol::optional<std::string> {
|
||||
if (w.mRainEffect.empty())
|
||||
return sol::nullopt;
|
||||
return w.mRainEffect;
|
||||
},
|
||||
[](MWWorld::Weather& w, sol::optional<std::string_view> rainEffect) {
|
||||
w.mRainEffect = rainEffect.value_or("");
|
||||
});
|
||||
weatherT["rainMaxRaindrops"] = sol::property([](const MWWorld::Weather& w) { return w.mRainMaxRaindrops; },
|
||||
[](MWWorld::Weather& w, int rainMaxRaindrops) { w.mRainMaxRaindrops = rainMaxRaindrops; });
|
||||
weatherT["rainDiameter"] = sol::property([](const MWWorld::Weather& w) { return w.mRainDiameter; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat rainDiameter) { w.mRainDiameter = rainDiameter; });
|
||||
weatherT["rainThreshold"] = sol::property([](const MWWorld::Weather& w) { return w.mRainThreshold; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat rainThreshold) { w.mRainThreshold = rainThreshold; });
|
||||
weatherT["rainMaxHeight"] = sol::property([](const MWWorld::Weather& w) { return w.mRainMaxHeight; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat rainMaxHeight) { w.mRainMaxHeight = rainMaxHeight; });
|
||||
weatherT["rainMinHeight"] = sol::property([](const MWWorld::Weather& w) { return w.mRainMinHeight; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat rainMinHeight) { w.mRainMinHeight = rainMinHeight; });
|
||||
weatherT["rainLoopSoundID"]
|
||||
= sol::property([](const MWWorld::Weather& w) { return LuaUtil::serializeRefId(w.mRainLoopSoundID); },
|
||||
[](MWWorld::Weather& w, sol::optional<std::string_view> rainLoopSoundID) {
|
||||
w.mRainLoopSoundID = ESM::RefId::deserializeText(rainLoopSoundID.value_or(""));
|
||||
});
|
||||
weatherT["sunDiscSunsetColor"]
|
||||
= sol::readonly_property([](const MWWorld::Weather& w) { return color(w.mSunDiscSunsetColor); });
|
||||
= sol::property([](const MWWorld::Weather& w) { return Misc::Color::fromVec(w.mSunDiscSunsetColor); },
|
||||
[](MWWorld::Weather& w, const Misc::Color& sunDiscSunsetColor) {
|
||||
w.mSunDiscSunsetColor = sunDiscSunsetColor.toVec();
|
||||
});
|
||||
weatherT["ambientLoopSoundID"]
|
||||
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mAmbientLoopSoundID.serializeText(); });
|
||||
weatherT["ambientColor"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
|
||||
sol::table result(lua, sol::create);
|
||||
result["sunrise"] = color(w.mAmbientColor.getSunriseValue());
|
||||
result["day"] = color(w.mAmbientColor.getDayValue());
|
||||
result["sunset"] = color(w.mAmbientColor.getSunsetValue());
|
||||
result["night"] = color(w.mAmbientColor.getNightValue());
|
||||
return result;
|
||||
});
|
||||
weatherT["fogColor"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
|
||||
sol::table result(lua, sol::create);
|
||||
result["sunrise"] = color(w.mFogColor.getSunriseValue());
|
||||
result["day"] = color(w.mFogColor.getDayValue());
|
||||
result["sunset"] = color(w.mFogColor.getSunsetValue());
|
||||
result["night"] = color(w.mFogColor.getNightValue());
|
||||
return result;
|
||||
});
|
||||
weatherT["skyColor"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
|
||||
sol::table result(lua, sol::create);
|
||||
result["sunrise"] = color(w.mSkyColor.getSunriseValue());
|
||||
result["day"] = color(w.mSkyColor.getDayValue());
|
||||
result["sunset"] = color(w.mSkyColor.getSunsetValue());
|
||||
result["night"] = color(w.mSkyColor.getNightValue());
|
||||
return result;
|
||||
});
|
||||
weatherT["sunColor"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
|
||||
sol::table result(lua, sol::create);
|
||||
result["sunrise"] = color(w.mSunColor.getSunriseValue());
|
||||
result["day"] = color(w.mSunColor.getDayValue());
|
||||
result["sunset"] = color(w.mSunColor.getSunsetValue());
|
||||
result["night"] = color(w.mSunColor.getNightValue());
|
||||
return result;
|
||||
});
|
||||
weatherT["landFogDepth"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
|
||||
sol::table result(lua, sol::create);
|
||||
result["sunrise"] = w.mLandFogDepth.getSunriseValue();
|
||||
result["day"] = w.mLandFogDepth.getDayValue();
|
||||
result["sunset"] = w.mLandFogDepth.getSunsetValue();
|
||||
result["night"] = w.mLandFogDepth.getNightValue();
|
||||
return result;
|
||||
});
|
||||
weatherT["particleEffect"]
|
||||
= sol::readonly_property([](const MWWorld::Weather& w) -> sol::optional<std::string> {
|
||||
if (w.mParticleEffect.empty())
|
||||
return sol::nullopt;
|
||||
return w.mParticleEffect;
|
||||
});
|
||||
weatherT["distantLandFogFactor"]
|
||||
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mDL.FogFactor; });
|
||||
weatherT["distantLandFogOffset"]
|
||||
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mDL.FogOffset; });
|
||||
weatherT["scriptId"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mScriptId; });
|
||||
weatherT["recordId"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mId.serializeText(); });
|
||||
= sol::property([](const MWWorld::Weather& w) { return LuaUtil::serializeRefId(w.mAmbientLoopSoundID); },
|
||||
[](MWWorld::Weather& w, sol::optional<std::string_view> ambientLoopSoundId) {
|
||||
w.mAmbientLoopSoundID = ESM::RefId::deserializeText(ambientLoopSoundId.value_or(""));
|
||||
});
|
||||
weatherT["ambientColor"] = sol::readonly_property([](const MWWorld::Weather& w) { return &w.mAmbientColor; });
|
||||
weatherT["fogColor"] = sol::readonly_property([](const MWWorld::Weather& w) { return &w.mFogColor; });
|
||||
weatherT["skyColor"] = sol::readonly_property([](const MWWorld::Weather& w) { return &w.mSkyColor; });
|
||||
weatherT["sunColor"] = sol::readonly_property([](const MWWorld::Weather& w) { return &w.mSunColor; });
|
||||
weatherT["landFogDepth"] = sol::readonly_property([](const MWWorld::Weather& w) { return &w.mLandFogDepth; });
|
||||
weatherT["particleEffect"] = sol::property(
|
||||
[](const MWWorld::Weather& w) -> sol::optional<std::string> {
|
||||
if (w.mParticleEffect.empty())
|
||||
return sol::nullopt;
|
||||
return w.mParticleEffect;
|
||||
},
|
||||
[](MWWorld::Weather& w, sol::optional<std::string_view> particleEffect) {
|
||||
w.mParticleEffect = particleEffect.value_or("");
|
||||
});
|
||||
weatherT["distantLandFogFactor"] = sol::property([](const MWWorld::Weather& w) { return w.mDL.FogFactor; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat fogFactor) { w.mDL.FogFactor = fogFactor; });
|
||||
weatherT["distantLandFogOffset"] = sol::property([](const MWWorld::Weather& w) { return w.mDL.FogOffset; },
|
||||
[](MWWorld::Weather& w, const FiniteFloat fogOffset) { w.mDL.FogOffset = fogOffset; });
|
||||
|
||||
api["changeWeather"] = [](std::string_view regionId, const MWWorld::Weather& weather) {
|
||||
ESM::RefId region = ESM::RefId::deserializeText(regionId);
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <components/esm3/loadnpc.hpp>
|
||||
#include <components/esm3/loadweap.hpp>
|
||||
#include <components/lua/luastate.hpp>
|
||||
#include <components/misc/finitenumbers.hpp>
|
||||
#include <components/misc/finitevalues.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
@ -114,6 +114,11 @@ namespace MWWorld
|
||||
const T& getSunsetValue() const { return mSunsetValue; }
|
||||
const T& getNightValue() const { return mNightValue; }
|
||||
|
||||
void setSunriseValue(const T& sunriseValue) { mSunriseValue = sunriseValue; }
|
||||
void setDayValue(const T& dayValue) { mDayValue = dayValue; }
|
||||
void setSunsetValue(const T& sunsetValue) { mSunsetValue = sunsetValue; }
|
||||
void setNightValue(const T& nightValue) { mNightValue = nightValue; }
|
||||
|
||||
private:
|
||||
T mSunriseValue, mDayValue, mSunsetValue, mNightValue;
|
||||
};
|
||||
|
@ -45,6 +45,11 @@ namespace Misc
|
||||
return Color(SceneUtil::colourFromRGB(value));
|
||||
}
|
||||
|
||||
Color Color::fromVec(osg::Vec4f value)
|
||||
{
|
||||
return Color(std::move(value));
|
||||
}
|
||||
|
||||
std::string Color::toHex() const
|
||||
{
|
||||
std::string result(6, '0');
|
||||
|
@ -27,9 +27,11 @@ namespace Misc
|
||||
|
||||
static Color fromHex(std::string_view hex);
|
||||
static Color fromRGB(unsigned int value);
|
||||
static Color fromVec(osg::Vec4f value);
|
||||
|
||||
std::string toHex() const;
|
||||
unsigned int toRGBA() const { return mValue.asRGBA(); }
|
||||
osg::Vec4f toVec() const { return mValue; }
|
||||
|
||||
friend bool operator==(const Color& l, const Color& r);
|
||||
|
||||
|
@ -1,53 +0,0 @@
|
||||
#ifndef OPENMW_COMPONENTS_MISC_FINITENUMBERS_HPP
|
||||
#define OPENMW_COMPONENTS_MISC_FINITENUMBERS_HPP
|
||||
|
||||
#include <components/lua/luastate.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
template <class T>
|
||||
struct FiniteNumber
|
||||
{
|
||||
T mValue;
|
||||
|
||||
FiniteNumber(T v)
|
||||
{
|
||||
if (!std::isfinite(v))
|
||||
throw std::invalid_argument("Value must be a finite number");
|
||||
mValue = v;
|
||||
}
|
||||
|
||||
operator T() const { return mValue; }
|
||||
};
|
||||
|
||||
using FiniteDouble = FiniteNumber<double>;
|
||||
|
||||
using FiniteFloat = FiniteNumber<float>;
|
||||
}
|
||||
|
||||
namespace sol
|
||||
{
|
||||
template <class Handler, class T>
|
||||
bool sol_lua_check(
|
||||
types<Misc::FiniteNumber<T>>, lua_State* state, int index, Handler&& handler, stack::record& tracking)
|
||||
{
|
||||
bool success = stack::check<T>(state, lua_absindex(state, index), std::forward<Handler>(handler));
|
||||
tracking.use(1);
|
||||
return success;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static Misc::FiniteNumber<T> sol_lua_get(
|
||||
types<Misc::FiniteNumber<T>>, lua_State* state, int index, stack::record& tracking)
|
||||
{
|
||||
T value = stack::get<T>(state, lua_absindex(state, index));
|
||||
tracking.use(1);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
76
components/misc/finitevalues.hpp
Normal file
76
components/misc/finitevalues.hpp
Normal file
@ -0,0 +1,76 @@
|
||||
#ifndef OPENMW_COMPONENTS_MISC_FINITEVALUES_HPP
|
||||
#define OPENMW_COMPONENTS_MISC_FINITEVALUES_HPP
|
||||
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/Vec4f>
|
||||
|
||||
#include <components/lua/luastate.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
template <class T>
|
||||
struct FiniteValue
|
||||
{
|
||||
T mValue;
|
||||
|
||||
FiniteValue(T v)
|
||||
{
|
||||
constexpr bool isVecType
|
||||
= std::is_same_v<osg::Vec2f, T> || std::is_same_v<osg::Vec3f, T> || std::is_same_v<osg::Vec4f, T>;
|
||||
|
||||
if constexpr (isVecType)
|
||||
{
|
||||
for (int i = 0; i < T::num_components; ++i)
|
||||
if (!std::isfinite(v[i]))
|
||||
throw std::invalid_argument("Vector must contain finite numbers");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!std::isfinite(v))
|
||||
throw std::invalid_argument("Value must be a finite number");
|
||||
}
|
||||
mValue = v;
|
||||
}
|
||||
|
||||
operator T() const { return mValue; }
|
||||
};
|
||||
|
||||
using FiniteDouble = FiniteValue<double>;
|
||||
|
||||
using FiniteFloat = FiniteValue<float>;
|
||||
|
||||
using FiniteVec2f = FiniteValue<osg::Vec2f>;
|
||||
|
||||
using FiniteVec3f = FiniteValue<osg::Vec3f>;
|
||||
|
||||
using FiniteVec4f = FiniteValue<osg::Vec4f>;
|
||||
}
|
||||
|
||||
namespace sol
|
||||
{
|
||||
template <class Handler, class T>
|
||||
bool sol_lua_check(
|
||||
types<Misc::FiniteValue<T>>, lua_State* state, int index, Handler&& handler, stack::record& tracking)
|
||||
{
|
||||
bool success = stack::check<T>(state, lua_absindex(state, index), std::forward<Handler>(handler));
|
||||
tracking.use(1);
|
||||
return success;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static Misc::FiniteValue<T> sol_lua_get(
|
||||
types<Misc::FiniteValue<T>>, lua_State* state, int index, stack::record& tracking)
|
||||
{
|
||||
T value = stack::get<T>(state, lua_absindex(state, index));
|
||||
tracking.use(1);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1304,7 +1304,6 @@
|
||||
---
|
||||
-- Weather data
|
||||
-- @type WeatherRecord
|
||||
-- @extends #userdata
|
||||
-- @field #string recordId
|
||||
-- @field #number scriptId
|
||||
-- @field #string name
|
||||
@ -1329,10 +1328,26 @@
|
||||
-- @field #number distantLandFogFactor
|
||||
-- @field #number distantLandFogOffset
|
||||
-- @field openmw.util#Color sunDiscSunsetColor
|
||||
-- @field #table landFogDepth A table with the keys "sunrise", "day", "sunset" and "night"
|
||||
-- @field #table skyColor A table with the keys "sunrise", "day", "sunset" and "night". Each is a @{openmw.util#Color}.
|
||||
-- @field #table ambientColor A table with the keys "sunrise", "day", "sunset" and "night". Each is a @{openmw.util#Color}.
|
||||
-- @field #table fogColor A table with the keys "sunrise", "day", "sunset" and "night". Each is a @{openmw.util#Color}.
|
||||
-- @field #table sunColor A table with the keys "sunrise", "day", "sunset" and "night". Each is a @{openmw.util#Color}.
|
||||
-- @field #TimeOfDayInterpolatorFloat landFogDepth
|
||||
-- @field #TimeOfDayInterpolatorColor skyColor
|
||||
-- @field #TimeOfDayInterpolatorColor ambientColor
|
||||
-- @field #TimeOfDayInterpolatorColor fogColor
|
||||
-- @field #TimeOfDayInterpolatorColor sunColor
|
||||
|
||||
---
|
||||
-- Interpolates numbers for weathers based on time of day
|
||||
-- @type TimeOfDayInterpolatorFloat
|
||||
-- @field #number sunrise
|
||||
-- @field #number sunset
|
||||
-- @field #number day
|
||||
-- @field #number night
|
||||
|
||||
---
|
||||
-- Interpolates colors for weathers based on time of day
|
||||
-- @type TimeOfDayInterpolatorColor
|
||||
-- @field openmw.util#Color sunrise
|
||||
-- @field openmw.util#Color sunset
|
||||
-- @field openmw.util#Color day
|
||||
-- @field openmw.util#Color night
|
||||
|
||||
return nil
|
||||
|
@ -351,13 +351,20 @@ testing.registerGlobalTest('load while teleporting - teleport', function()
|
||||
landracer:teleport(player.cell, player.position)
|
||||
end)
|
||||
|
||||
testing.registerGlobalTest('nan', function()
|
||||
testing.registerGlobalTest('nan float', function()
|
||||
local nan = 0.0 / 0.0
|
||||
local ok, err = pcall(function() world.setGameTimeScale(nan) end)
|
||||
testing.expectEqual(ok, false)
|
||||
testing.expectEqual(err, 'Value must be a finite number')
|
||||
end)
|
||||
|
||||
testing.registerGlobalTest('nan vector', function()
|
||||
local nan = 0.0 / 0.0
|
||||
local ok, err = pcall(function() core.weather.records[1].stormDirection = util.vector3(nan, nan, nan) end)
|
||||
testing.expectEqual(ok, false)
|
||||
testing.expectEqual(err, 'Vector must contain finite numbers')
|
||||
end)
|
||||
|
||||
testing.registerGlobalTest('mwscript magic interactions', function()
|
||||
local player = world.players[1]
|
||||
local script = world.mwscript.getGlobalScript('OpenMW_Tests', player)
|
||||
|
@ -73,7 +73,8 @@ registerGlobalTest('memory limit')
|
||||
registerGlobalTest('vfs')
|
||||
registerGlobalTest('commit crime')
|
||||
registerGlobalTest('record model property')
|
||||
registerGlobalTest('nan', 'world.setGameTimeScale should not accept nan')
|
||||
registerGlobalTest('nan float', 'world.setGameTimeScale should not accept nan')
|
||||
registerGlobalTest('nan vector', 'weather.stormDirection should not accept a vector with a nan component')
|
||||
|
||||
registerGlobalTest('player yaw rotation', 'rotating player with controls.yawChange should change rotation')
|
||||
registerGlobalTest('player pitch rotation', 'rotating player with controls.pitchChange should change rotation')
|
||||
|
@ -12,6 +12,7 @@ require('global_issues')
|
||||
require('global_dialogues')
|
||||
require('global_mwscript')
|
||||
require('global_regions')
|
||||
require('global_weather')
|
||||
|
||||
return {
|
||||
engineHandlers = {
|
||||
|
10
scripts/data/morrowind_tests/global_weather.lua
Normal file
10
scripts/data/morrowind_tests/global_weather.lua
Normal file
@ -0,0 +1,10 @@
|
||||
local testing = require('testing_util')
|
||||
local core = require('openmw.core')
|
||||
local util = require('openmw.util')
|
||||
|
||||
testing.registerGlobalTest('[weather] Should be able to change weather records', function()
|
||||
local record = core.weather.records['clear']
|
||||
testing.expect(record ~= nil, 'Clear weather to exist')
|
||||
record.skyColor.sunrise = util.color.hex('2227FF')
|
||||
testing.expectEqual(record.skyColor.sunrise, util.color.hex('2227FF'))
|
||||
end)
|
Loading…
x
Reference in New Issue
Block a user