feat(core): add rain and clear weather state machine

This commit is contained in:
dualfroz committed 2026-08-23 16:34:27 +02:00
1 parent 7d38a1184e
commit e295652051
2 files changed
+215

No files matched your search

+99
View File
@@ -0,0 +1,99 @@
#pragma once
#include <cstdint>
#include <vector>
#include "Math.h"
namespace vf {
enum class WeatherState : uint8_t {
Clear = 0,
Rain = 1,
Thunder = 2,
};
enum class Precipitation : uint8_t {
None = 0,
Rain = 1,
Snow = 2,
};
const char* weatherStateName(WeatherState state);
struct LightningStrike {
Vec3i pos;
long long tick;
};
struct WeatherConfig {
long long clearMin = 6000;
long long clearMax = 18000;
long long rainMin = 6000;
long long rainMax = 12000;
long long thunderMin = 3000;
long long thunderMax = 9000;
// Odds (in 256ths) that a rain spell escalates into a thunderstorm.
uint32_t thunderChance = 96;
// Mean ticks between lightning strikes while thundering.
long long strikeInterval = 120;
// Horizontal window strikes are placed in, and their nominal ground height.
int strikeMinX = -128;
int strikeMaxX = 128;
int strikeMinZ = -128;
int strikeMaxZ = 128;
int strikeGroundY = 64;
// Per-tick gradient ramp toward the target intensity.
double rainRampPerTick = 0.01;
double thunderRampPerTick = 0.01;
// Below this biome temperature falling precipitation is snow, not rain.
float snowTemperature = 0.15f;
};
// Deterministic weather state machine. Clear, Rain and Thunder alternate on
// seeded durations; a rain spell may escalate to thunder and always decays back
// through rain before clearing. Rain and thunder gradients ramp smoothly so the
// sky fades rather than snapping. While thundering, lightning strikes are placed
// at seeded positions. Two Weather instances with the same seed and config
// produce identical state, gradient and strike sequences.
class Weather {
public:
explicit Weather(uint32_t seed = 1u, const WeatherConfig& config = {});
void tick();
void advance(long long ticks);
WeatherState state() const { return currentState; }
bool isRaining() const { return currentState != WeatherState::Clear; }
bool isThundering() const { return currentState == WeatherState::Thunder; }
double rainGradient() const { return rainLevel; }
double thunderGradient() const { return thunderLevel; }
long long ticksUntilChange() const { return stateTimer; }
long long currentTick() const { return tickCounter; }
Precipitation precipitationAt(float temperature) const;
const std::vector<LightningStrike>& strikesThisTick() const { return tickStrikes; }
long long totalStrikes() const { return strikeCount; }
const WeatherConfig& settings() const { return config; }
private:
uint32_t nextRandom();
long long rollDuration(long long lo, long long hi);
void enterState(WeatherState next);
void stepGradients();
void stepLightning();
WeatherConfig config;
uint32_t rngState;
WeatherState currentState = WeatherState::Clear;
long long stateTimer;
long long tickCounter = 0;
double rainLevel = 0.0;
double thunderLevel = 0.0;
long long strikeCount = 0;
std::vector<LightningStrike> tickStrikes;
};
} // namespace vf