Live World: raise max clock speed to ~20 years/second
The live clock capped at 1 month/second (liveRate <= 720 sim-hours/s), far too slow to watch civilizations, wars and empires evolve over centuries. Raise the ceiling to ~20 sim-years/second (a century in ~5 s). - liveRateMax() helper (20 x dayLengthHours x yearLengthDays); the [ / ] ramp and the load-resume clamp both use it (was the hardcoded 720 in two places). - HUD rate label gains a "yr/s" tier above "mo/s". - The per-year sim tick (wars + territory) now catches up one year at a time over any years a frame skips (bounded to 12/frame), so at high speed wars/borders are still simulated for every year instead of teleporting; a backward step still just refreshes territory without re-running wars. Render/input-only: no engine, save-format or config change. Build clean, 13/13 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
4a1f3377ba
commit
cc6813e211
2
BUILD.md
2
BUILD.md
@ -64,7 +64,7 @@ the full ~2.8x speedup; the default uses all cores for no extra gain:
|
||||
rewinds weather + storms via an undo history)
|
||||
wheel over the 2D map: zoom toward cursor (1-8x); drag pans when zoomed
|
||||
SPACE pause while forming / re-evolve once settled (or the on-screen button)
|
||||
[ / ] drift speed (My/s) -- in Live World: live clock rate (hours/s, hour->month)
|
||||
[ / ] drift speed (My/s) -- in Live World: live clock rate (hours/s -> up to ~20 years/s)
|
||||
S single tectonic tick (in Live World: step the clock forward, like '.')
|
||||
F fast-forward Phase-1 forming to settled (instant)
|
||||
R reseed planet (restart forming)
|
||||
|
||||
@ -61,7 +61,7 @@ scale with dynamic **weather** (clouds, rain, storms, fronts), day/night, and li
|
||||
**ecosystems / civilization** evolving in real time. This is a separate large effort;
|
||||
the fixed-grid Eulerian model + the climate fields are the groundwork for it.
|
||||
- **Clock + day/night groundwork** *(done — see `PlanetLive.cpp`)* — a slow real-time clock
|
||||
(hours → weeks/months, `liveTime`/`liveRate`, key `W` to enter once settled, `[`/`]` ramp
|
||||
(hours → up to ~20 years/sec, `liveTime`/`liveRate`, key `W` to enter once settled, `[`/`]` ramp
|
||||
the rate), a moving **day/night terminator** (sun from time-of-day rotation + seasonal
|
||||
declination via `axialTilt`; key `N`), a raylib-free per-cell **insolation field**
|
||||
(`computeInsolation`, the weather hook), a **live seasonal temperature** cycling the
|
||||
@ -472,7 +472,7 @@ Working and verified (logic tested headless):
|
||||
annual-mean `sTemp` swung toward the existing `summerTemp`/`winterTemp` by the seasonal phase,
|
||||
anti-phased across hemispheres). Viewer: key `W` (settled world) toggles **Live World** — drift
|
||||
freezes and `liveTime` advances at `liveRate` (sim hours/real-second), `[`/`]` ramp it
|
||||
hour→month; the HUD shows a `Year/Day/HH:MM` calendar (`dayLengthHours`/`yearLengthDays`).
|
||||
hour→~20 years/sec (`liveRateMax()` = 20 sim-years/s); the HUD shows a `Year/Day/HH:MM` calendar (`dayLengthHours`/`yearLengthDays`).
|
||||
`rebuildLiveOverlay()` builds a per-cell day/night brightness (`illum`, soft terminator, dim
|
||||
night floor) + `shadedColors` (base colour → snow on cold land / sea-ice on cold ocean via
|
||||
`snowTemp`/`seaIceTemp` → day/night dim); both the 3D globe and 2D map draw `displayColors()`
|
||||
@ -724,7 +724,7 @@ all in 3D + 2D) · `N` day/night terminator (Live World) · `T` tide-coloured co
|
||||
`P` territory / realms view + political borders (Realms tab lists nations) ·
|
||||
`X` culture / faiths view + cultural borders (Cultures tab lists peoples, ethos & religion) ·
|
||||
`SPACE` or on-screen button pause ·
|
||||
`[`/`]` drift speed (My/sec) — in **Live World** the live-clock rate (hours/sec, hour→month) ·
|
||||
`[`/`]` drift speed (My/sec) — in **Live World** the live-clock rate (hours/sec → up to ~20 years/sec) ·
|
||||
`S` single tick (in **Live World** steps the clock forward) · `.`/`,` step the live clock
|
||||
forward/back by one rate-unit (auto-pauses; `,` steps **everything** back incl. weather/storms via
|
||||
an undo history) ·
|
||||
@ -742,7 +742,7 @@ keeps running at a finer timestep (`cflDtMy()*phase3DtScale`) while rivers, lake
|
||||
and fluvial erosion evolve.
|
||||
|
||||
Live World (`W`, on a settled world): geological drift freezes and a slow real-time clock runs
|
||||
(`liveTime` in hours, `liveRate` = sim hours/real-second, ramped hour→month with `[`/`]`). A
|
||||
(`liveTime` in hours, `liveRate` = sim hours/real-second, ramped hour→~20 years/sec with `[`/`]`). A
|
||||
moving day/night terminator (`N`), a live seasonal temperature cycle and a moving snow/sea-ice
|
||||
line animate over whatever colour mode is active; the HUD shows a `Year/Day/HH:MM` calendar.
|
||||
**1–3 moons** orbit (sun-lit phases, orbit rings, solar/lunar eclipses) and, with the distant
|
||||
|
||||
@ -543,7 +543,7 @@ void Viewer::loadGame(const char* path) {
|
||||
phase3 = (p3 != 0); phase3Prompt = false;
|
||||
phase3PromptAt = phase3 ? elapsedMy : (elapsedMy + planet.cfg.phase3AfterMy);
|
||||
driftRate = dr;
|
||||
liveWorld = (lw != 0); liveTime = lh; liveRate = std::clamp(lr, 0.25, 720.0); // v8/v13: resume the Live World clock
|
||||
liveWorld = (lw != 0); liveTime = lh; liveRate = std::clamp(lr, 0.25, liveRateMax()); // v8/v13: resume the Live World clock
|
||||
settleRun = settleNeed; // keep the settled latch consistent
|
||||
dtMy = settled ? planet.cflDtMy() : 0.0;
|
||||
driftAccum = 0.0; formAccum = 0.0;
|
||||
@ -748,12 +748,19 @@ void Viewer::liveAdvance(double dtClock, double dtWeather) {
|
||||
long year = (long)std::floor(liveTime / yearHours);
|
||||
if (year != lastTerritoryYear) {
|
||||
std::vector<Nation> beforeNations = (dtWeather > 0.0) ? planet.nationList() : std::vector<Nation>{};
|
||||
if (dtWeather > 0.0) { // only advance wars going forward (not on a step back)
|
||||
ConflictUpdate wu = planet.stepConflict(year);
|
||||
for (const WarEvent& e : wu.events)
|
||||
appendEvent(5, e.severity, liveTime, e.cell, 0, e.title, e.detail);
|
||||
if (dtWeather > 0.0) { // advancing: simulate each crossed year (not on a step back)
|
||||
// At high clock rates a frame can span multiple years -- catch up one year at a time so
|
||||
// wars/territory aren't skipped (bounded: an extreme jump only simulates the most recent).
|
||||
const long maxCatch = 12;
|
||||
long firstYear = std::max(lastTerritoryYear + 1, year - maxCatch + 1);
|
||||
for (long y = firstYear; y <= year; ++y) {
|
||||
ConflictUpdate wu = planet.stepConflict(y);
|
||||
for (const WarEvent& e : wu.events)
|
||||
appendEvent(5, e.severity, liveTime, e.cell, 0, e.title, e.detail);
|
||||
if (y < year) rebuildTerritory(); // recompute between years so the next year's war sees it
|
||||
}
|
||||
}
|
||||
rebuildTerritory();
|
||||
rebuildTerritory(); // final recompute (also refreshes a backward year-cross)
|
||||
if (dtWeather > 0.0) detectNationEvents(beforeNations);
|
||||
territoryChanged = true;
|
||||
}
|
||||
|
||||
@ -80,7 +80,10 @@ struct Viewer {
|
||||
// temperature cycle and a moving snow line animate. liveRate is sim hours per real second.
|
||||
bool liveWorld = false, dayNightOn = true;
|
||||
double liveTime = 0.0; // hours since the live clock started
|
||||
double liveRate = 1.0; // sim hours advanced per real second (ramps hour->month)
|
||||
double liveRate = 1.0; // sim hours advanced per real second (ramps hour -> ~20 years)
|
||||
// Top clock speed: ~20 sim-years per real second (a century in ~5 s). Kept a code constant like the
|
||||
// old 720 (1 month/s); the [ / ] ramp and the load-resume clamp both clamp to this.
|
||||
double liveRateMax() const { return 20.0 * planet.cfg.dayLengthHours * planet.cfg.yearLengthDays; }
|
||||
// Step-back undo history: each forward step snapshots the clock + full weather state so a
|
||||
// backward step restores everything (weather is an integrated path, not analytically reversible).
|
||||
struct WxFrame { double t; WeatherSnapshot w; };
|
||||
|
||||
@ -314,7 +314,7 @@ void Viewer::handleInput() {
|
||||
// Speed control: Live World ramps the live clock (sim hours/s, ~hour -> month);
|
||||
// otherwise it sets the drift rate (My simulated per real second).
|
||||
if (IsKeyPressed(KEY_RIGHT_BRACKET)) {
|
||||
if (liveWorld) liveRate = std::min(liveRate * 1.5, 720.0);
|
||||
if (liveWorld) liveRate = std::min(liveRate * 1.5, liveRateMax());
|
||||
else driftRate = std::min(driftRate * 1.5, 80.0);
|
||||
}
|
||||
if (IsKeyPressed(KEY_LEFT_BRACKET)) {
|
||||
|
||||
@ -811,9 +811,10 @@ void Viewer::renderHUD() {
|
||||
int hh = (int)hod, mm = (int)((hod - hh) * 60.0);
|
||||
line(TextFormat("Live World Year %ld Day %ld %02d:%02d%s",
|
||||
year, doy, hh, mm, paused ? " [PAUSED]" : ""));
|
||||
const double weekH = 7.0 * dayH, monthH = 30.0 * dayH;
|
||||
const double weekH = 7.0 * dayH, monthH = 30.0 * dayH, yearHH = yrD * dayH;
|
||||
const char* rl; double rv;
|
||||
if (liveRate >= monthH) { rl = "mo/s"; rv = liveRate / monthH; }
|
||||
if (liveRate >= yearHH) { rl = "yr/s"; rv = liveRate / yearHH; }
|
||||
else if (liveRate >= monthH) { rl = "mo/s"; rv = liveRate / monthH; }
|
||||
else if (liveRate >= weekH) { rl = "wk/s"; rv = liveRate / weekH; }
|
||||
else if (liveRate >= dayH) { rl = "d/s"; rv = liveRate / dayH; }
|
||||
else { rl = "h/s"; rv = liveRate; }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user