Fix deterministic live weather rewind
This commit is contained in:
parent
1358e81426
commit
695e07ba99
@ -407,12 +407,12 @@ void Viewer::liveStepForward() {
|
|||||||
liveAdvance(liveRate, liveRate);
|
liveAdvance(liveRate, liveRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step everything back: restore the most recent snapshot strictly before the current time (clock +
|
// Step everything back: restore the newest snapshot at or before the current time (clock +
|
||||||
// weather + storms) -- so storms reverse whether they were born while stepping or during a run. If
|
// weather + storms) -- so storms reverse whether they were born while stepping or during a run. If
|
||||||
// the history is exhausted, fall back to rewinding the deterministic sky only.
|
// the history is exhausted, fall back to rewinding the deterministic sky only.
|
||||||
void Viewer::liveStepBack() {
|
void Viewer::liveStepBack() {
|
||||||
paused = true;
|
paused = true;
|
||||||
while (!wxUndo.empty() && wxUndo.back().t >= liveTime - 1e-6) wxUndo.pop_back(); // drop any future frames
|
while (!wxUndo.empty() && wxUndo.back().t > liveTime + 1e-6) wxUndo.pop_back(); // drop only true future frames
|
||||||
if (!wxUndo.empty()) {
|
if (!wxUndo.empty()) {
|
||||||
WxFrame f = wxUndo.back(); wxUndo.pop_back();
|
WxFrame f = wxUndo.back(); wxUndo.pop_back();
|
||||||
liveTime = f.t;
|
liveTime = f.t;
|
||||||
|
|||||||
@ -220,7 +220,7 @@ private:
|
|||||||
// Weather (Live World; saved v10). sHasWeather latches once spun up/loaded.
|
// Weather (Live World; saved v10). sHasWeather latches once spun up/loaded.
|
||||||
std::vector<double> sHumidity, sCloud, sRain;
|
std::vector<double> sHumidity, sCloud, sRain;
|
||||||
bool sHasWeather = false;
|
bool sHasWeather = false;
|
||||||
// Moving weather systems (transient agents; not saved). Separate RNG keeps tectonic
|
// Moving weather systems (saved with weather state). Separate RNG keeps tectonic
|
||||||
// determinism intact (seeded from cfg.seed in initWeather).
|
// determinism intact (seeded from cfg.seed in initWeather).
|
||||||
std::vector<WeatherSystem> sStorms;
|
std::vector<WeatherSystem> sStorms;
|
||||||
uint32_t sWeatherRng = 1;
|
uint32_t sWeatherRng = 1;
|
||||||
|
|||||||
@ -28,7 +28,7 @@ enum class PlateType { Oceanic, Continental };
|
|||||||
// A moving weather system (Live World): a drifting low-pressure disturbance that travels with the
|
// A moving weather system (Live World): a drifting low-pressure disturbance that travels with the
|
||||||
// steering wind and stamps clouds & rain onto the weather fields. Geometry is fixed, so this is a
|
// steering wind and stamps clouds & rain onto the weather fields. Geometry is fixed, so this is a
|
||||||
// world-object agent (a point on the sphere, like a moon), not a cell. The intense tropical ones
|
// world-object agent (a point on the sphere, like a moon), not a cell. The intense tropical ones
|
||||||
// (strength past weatherHurricaneStrength) are hurricanes/typhoons. Transient -- not saved.
|
// (strength past weatherHurricaneStrength) are hurricanes/typhoons. Saved with the weather state.
|
||||||
struct WeatherSystem {
|
struct WeatherSystem {
|
||||||
uint32_t id = 0; // stable id (for the viewer follow-cam; assigned at spawn)
|
uint32_t id = 0; // stable id (for the viewer follow-cam; assigned at spawn)
|
||||||
Vec3 pos; // unit position on the sphere
|
Vec3 pos; // unit position on the sphere
|
||||||
|
|||||||
@ -22,6 +22,24 @@ static void check(bool cond, const char* what) {
|
|||||||
if (!cond) ++failures;
|
if (!cond) ++failures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool sameStorms(const std::vector<WeatherSystem>& a, const std::vector<WeatherSystem>& b) {
|
||||||
|
if (a.size() != b.size()) return false;
|
||||||
|
for (size_t i = 0; i < a.size(); ++i) {
|
||||||
|
if (a[i].id != b[i].id
|
||||||
|
|| a[i].pos.x != b[i].pos.x || a[i].pos.y != b[i].pos.y || a[i].pos.z != b[i].pos.z
|
||||||
|
|| a[i].strength != b[i].strength || a[i].radius != b[i].radius
|
||||||
|
|| a[i].age != b[i].age || a[i].life != b[i].life || a[i].spin != b[i].spin
|
||||||
|
|| a[i].tropical != b[i].tropical) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sameWeatherSnapshot(const WeatherSnapshot& a, const WeatherSnapshot& b) {
|
||||||
|
return a.humidity == b.humidity && a.cloud == b.cloud && a.rain == b.rain
|
||||||
|
&& sameStorms(a.storms, b.storms)
|
||||||
|
&& a.rng == b.rng && a.nextId == b.nextId;
|
||||||
|
}
|
||||||
|
|
||||||
// Run a fixed weather sequence on a planet (returns whether rain ever fell, max cloud + storms).
|
// Run a fixed weather sequence on a planet (returns whether rain ever fell, max cloud + storms).
|
||||||
static void runWeather(Planet& p, bool& everRained, double& maxCloud, int& maxStorms) {
|
static void runWeather(Planet& p, bool& everRained, double& maxCloud, int& maxStorms) {
|
||||||
p.initWeather();
|
p.initWeather();
|
||||||
@ -139,6 +157,19 @@ int main() {
|
|||||||
check(rt, "captureWeather/restoreWeather round-trips the full weather state");
|
check(rt, "captureWeather/restoreWeather round-trips the full weather state");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::printf("Weather: snapshot deterministic replay\n");
|
||||||
|
{
|
||||||
|
Planet wc; wc.generate(cfg); wc.initWeather();
|
||||||
|
for (int k = 0; k < 90; ++k) { wc.computeInsolation(0.25, std::fmod(0.2 + 0.01 * k, 1.0)); wc.stepWeather(1.0); }
|
||||||
|
WeatherSnapshot snap = wc.captureWeather();
|
||||||
|
for (int k = 0; k < 180; ++k) { wc.computeInsolation(0.25, std::fmod(0.4 + 0.01 * k, 1.0)); wc.stepWeather(1.0); }
|
||||||
|
WeatherSnapshot first = wc.captureWeather();
|
||||||
|
wc.restoreWeather(snap);
|
||||||
|
for (int k = 0; k < 180; ++k) { wc.computeInsolation(0.25, std::fmod(0.4 + 0.01 * k, 1.0)); wc.stepWeather(1.0); }
|
||||||
|
WeatherSnapshot second = wc.captureWeather();
|
||||||
|
check(sameWeatherSnapshot(first, second), "restored weather snapshot replays storms and RNG exactly");
|
||||||
|
}
|
||||||
|
|
||||||
std::printf(failures ? "\nSOME WEATHER CHECKS FAILED (%d)\n" : "\nALL WEATHER CHECKS PASSED\n", failures);
|
std::printf(failures ? "\nSOME WEATHER CHECKS FAILED (%d)\n" : "\nALL WEATHER CHECKS PASSED\n", failures);
|
||||||
return failures ? 1 : 0;
|
return failures ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user