diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index 3fbe9082..dd9d0c57 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -209,11 +209,10 @@ void LevelScreen::update(float delta) { playerController->postUpdate(delta, !inputLocked, hud->isPause()); hud->update(hudVisible); + + const auto& weather = level->getWorld()->getInfo().weather; decorator->update( - hud->isPause() ? 0.0f : delta, - *camera, - worldRenderer->weather.a, - worldRenderer->weather.b + hud->isPause() ? 0.0f : delta, *camera, weather.a, weather.b ); } diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 3d3a6ef5..602ad158 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -111,6 +111,7 @@ void WorldRenderer::setupWorldShader( const EngineSettings& settings, float fogFactor ) { + const auto& weather = level.getWorld()->getInfo().weather; shader.use(); shader.uniformMatrix("u_model", glm::mat4(1.0f)); shader.uniformMatrix("u_proj", camera.getProjection()); @@ -152,7 +153,7 @@ void WorldRenderer::renderLevel( bool pause, bool hudVisible ) { - weather.update(delta); + const auto& weather = level.getWorld()->getInfo().weather; texts->render(ctx, camera, settings, hudVisible, false); @@ -200,7 +201,7 @@ void WorldRenderer::renderLevel( setupWorldShader(entityShader, camera, settings, fogFactor); - std::array weatherInstances {&weather.a, &weather.b}; + std::array weatherInstances {&weather.a, &weather.b}; for (const auto& weather : weatherInstances) { float zero = weather->fall.minOpacity; float one = weather->fall.maxOpacity; @@ -335,6 +336,7 @@ void WorldRenderer::draw( ) { timer += delta * !pause; auto world = level.getWorld(); + const auto& weather = world->getInfo().weather; const Viewport& vp = pctx.getViewport(); camera.aspect = vp.getWidth() / static_cast(vp.getHeight()); diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index d5f4d23c..da3a0349 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -11,6 +11,7 @@ #include "typedefs.hpp" #include "presets/WeatherPreset.hpp" +#include "world/Weather.hpp" class Level; class Player; @@ -34,44 +35,6 @@ class ModelBatch; class Assets; struct EngineSettings; -struct Weather { - WeatherPreset a {}; - WeatherPreset b {}; - std::string nameA; - std::string nameB; - float t = 1.0f; - float speed = 0.0f; - - void update(float delta) { - t += delta * speed; - t = std::min(t, 1.0f); - b.intensity = t; - a.intensity = 1.0f - t; - } - - void change(WeatherPreset preset, float time, std::string name="") { - std::swap(a, b); - std::swap(nameA, nameB); - b = std::move(preset); - t = 0.0f; - speed = 1.0f / glm::max(time, 1.e-5f); - nameB = std::move(name); - update(0.0f); - } - - float fogOpacity() const { - return b.fogOpacity * t + a.fogOpacity * (1.0f - t); - } - - float fogDencity() const { - return b.fogDencity * t + a.fogDencity * (1.0f - t); - } - - float fogCurve() const { - return b.fogCurve * t + a.fogCurve * (1.0f - t); - } -}; - class WorldRenderer { Engine& engine; const Level& level; @@ -113,7 +76,6 @@ public: std::unique_ptr particles; std::unique_ptr blockWraps; std::unique_ptr precipitation; - Weather weather {}; static bool showChunkBorders; static bool showEntitiesDebug; diff --git a/src/interfaces/Serializable.hpp b/src/interfaces/Serializable.hpp index 24457d44..46228f4a 100644 --- a/src/interfaces/Serializable.hpp +++ b/src/interfaces/Serializable.hpp @@ -9,4 +9,10 @@ public: virtual ~Serializable() {} virtual dv::value serialize() const = 0; virtual void deserialize(const dv::value& src) = 0; + + void deserializeOpt(const dv::optionalvalue& opt) { + if (opt.ptr) { + deserialize(*opt.ptr); + } + } }; diff --git a/src/logic/LevelController.cpp b/src/logic/LevelController.cpp index 4404fb3a..476a8f65 100644 --- a/src/logic/LevelController.cpp +++ b/src/logic/LevelController.cpp @@ -69,6 +69,8 @@ LevelController::LevelController( } void LevelController::update(float delta, bool pause) { + level->getWorld()->getInfo().weather.update(delta); + for (const auto& [_, player] : *level->players) { if (player->isSuspended()) { continue; diff --git a/src/logic/scripting/lua/libs/libweather.cpp b/src/logic/scripting/lua/libs/libweather.cpp index 3a2dc096..7b1fcecb 100644 --- a/src/logic/scripting/lua/libs/libweather.cpp +++ b/src/logic/scripting/lua/libs/libweather.cpp @@ -1,31 +1,43 @@ #include "libhud.hpp" +#include "world/Level.hpp" +#include "world/World.hpp" using namespace scripting; +static Weather& require_weather() { + if (level == nullptr) { + throw std::runtime_error("world is not open"); + } + return level->getWorld()->getInfo().weather; +} + static int l_change(lua::State* L) { - WeatherPreset weather {}; - weather.deserialize(lua::tovalue(L, 1)); + WeatherPreset preset {}; + preset.deserialize(lua::tovalue(L, 1)); float time = lua::tonumber(L, 2); std::string name; if (lua::isstring(L, 3)) { name = lua::tostring(L, 3); } - renderer->weather.change(std::move(weather), time, std::move(name)); + auto& weather = require_weather(); + weather.change(std::move(preset), time, std::move(name)); return 0; } static int l_get_current(lua::State* L) { - if (renderer->weather.t > 0.5f) { - return lua::pushstring(L, renderer->weather.nameB); + const auto& weather = require_weather(); + if (weather.t > 0.5f) { + return lua::pushstring(L, weather.nameB); } else { - return lua::pushstring(L, renderer->weather.nameA); + return lua::pushstring(L, weather.nameA); } } static int l_get_fall_intencity(lua::State* L) { - const auto& a = renderer->weather.a; - const auto& b = renderer->weather.b; - float t = renderer->weather.t; + auto& weather = require_weather(); + const auto& a = weather.a; + const auto& b = weather.b; + float t = weather.t; return lua::pushnumber(L, (a.fall.texture.empty() ? 0.0f : (1.0f - t)) + (b.fall.texture.empty() ? 0.0f : t) @@ -33,17 +45,23 @@ static int l_get_fall_intencity(lua::State* L) { } static int l_get_current_data(lua::State* L) { - if (renderer->weather.t > 0.5f) { - return lua::pushvalue(L, renderer->weather.b.serialize()); + auto& weather = require_weather(); + if (weather.t > 0.5f) { + return lua::pushvalue(L, weather.b.serialize()); } else { - return lua::pushvalue(L, renderer->weather.a.serialize()); + return lua::pushvalue(L, weather.a.serialize()); } } +static int l_is_transition(lua::State* L) { + return lua::pushboolean(L, require_weather().t < 1.0f); +} + const luaL_Reg weatherlib[] = { {"change", wrap_hud}, {"get_current", wrap_hud}, {"get_current_data", wrap_hud}, {"get_fall_intencity", wrap_hud}, + {"is_transition", wrap_hud}, {NULL, NULL} }; diff --git a/src/world/Weather.hpp b/src/world/Weather.hpp new file mode 100644 index 00000000..023995b9 --- /dev/null +++ b/src/world/Weather.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include + +#include "presets/WeatherPreset.hpp" + +struct Weather : Serializable { + WeatherPreset a {}; + WeatherPreset b {}; + std::string nameA; + std::string nameB; + float t = 1.0f; + float speed = 0.0f; + + void update(float delta) { + t += delta * speed; + t = std::min(t, 1.0f); + b.intensity = t; + a.intensity = 1.0f - t; + } + + void change(WeatherPreset preset, float time, std::string name="") { + std::swap(a, b); + std::swap(nameA, nameB); + b = std::move(preset); + t = 0.0f; + speed = 1.0f / std::max(time, 1.e-5f); + nameB = std::move(name); + update(0.0f); + } + + float fogOpacity() const { + return b.fogOpacity * t + a.fogOpacity * (1.0f - t); + } + + float fogDencity() const { + return b.fogDencity * t + a.fogDencity * (1.0f - t); + } + + float fogCurve() const { + return b.fogCurve * t + a.fogCurve * (1.0f - t); + } + + dv::value serialize() const override { + return dv::object({ + {"a", a.serialize()}, + {"b", b.serialize()}, + {"name-a", nameA}, + {"name-b", nameB}, + {"t", t}, + {"speed", speed}, + }); + } + + void deserialize(const dv::value& src) override { + a.deserializeOpt(src.at("a")); + b.deserializeOpt(src.at("b")); + src.at("name-a").get(nameA); + src.at("name-b").get(nameB); + src.at("t").get(t); + src.at("speed").get(speed); + } +}; diff --git a/src/world/World.cpp b/src/world/World.cpp index 313f75cd..1bea12c5 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -208,6 +208,7 @@ void WorldInfo::deserialize(const dv::value& root) { totalTime = timeobj["total-time"].asNumber(); } if (root.has("weather")) { + weather.deserialize(root["weather"]); fog = root["weather"]["fog"].asNumber(); } nextInventoryId = root["next-inventory-id"].asInteger(2); @@ -231,8 +232,8 @@ dv::value WorldInfo::serialize() const { timeobj["day-time-speed"] = daytimeSpeed; timeobj["total-time"] = totalTime; - auto& weatherobj = root.object("weather"); - weatherobj["fog"] = fog; + root["weather"] = weather.serialize(); + root["weather"]["fog"] = fog; root["next-inventory-id"] = nextInventoryId; root["next-entity-id"] = nextEntityId; diff --git a/src/world/World.hpp b/src/world/World.hpp index 531e7084..d889f0b3 100644 --- a/src/world/World.hpp +++ b/src/world/World.hpp @@ -4,9 +4,10 @@ #include #include -#include "io/fwd.hpp" #include "content/ContentPack.hpp" #include "interfaces/Serializable.hpp" +#include "io/fwd.hpp" +#include "Weather.hpp" #include "typedefs.hpp" #include "util/timeutil.hpp" @@ -33,7 +34,6 @@ struct WorldInfo : public Serializable { /// 0.5 - is noon float daytime = timeutil::time_value(10, 00, 00); - // looking bad float daytimeSpeed = 1.0f; /// @brief total time passed in the world (not depending on daytimeSpeed) @@ -46,6 +46,8 @@ struct WorldInfo : public Serializable { int major = 0, minor = -1; + Weather weather {}; + dv::value serialize() const override; void deserialize(const dv::value& src) override; };