🔭 Dvergr Astrolabe
Daylight and night, in real minutes, set once on the server. No client install, ever.
A vanilla Valheim day is 30 real minutes: 21 of daylight and 9 of night. Dvergr Astrolabe lets the server decide those two numbers - a lazy hour of daylight with a 5-minute night, or a 10-minute day and a 20-minute night for a horror server - and every player sees it with nothing installed on their side. Steam, Xbox, PlayFab and crossplay parties alike, because the server is the only machine that owns the world clock.
⚙️ Settings
BepInEx/config/wubarrk.dvergrastrolabe.cfg on the server. Edits are picked up within 5 seconds, no restart.
The defaults are vanilla, so installing the mod changes nothing until you set them.
| Setting | Default | What it does |
|---|---|---|
[2 - Day And Night] DayMinutes |
21 |
Real minutes from sunrise to sunset: the whole stretch in which the sun is above the horizon and the game counts as day (the Day N banner fires at its start). 0.5 to 180. |
[2 - Day And Night] NightMinutes |
9 |
Real minutes from sunset to sunrise: dusk, the midnight day-counter tick and dawn. 0.5 to 180. |
[2 - Day And Night] HoldSchedule |
true |
Hold every sunrise and sunset to its scheduled time: after a stretch at vanilla speed (boats), a server hitch or a mid-day config edit, the rest of the segment runs faster or slower to land the boundary on time anyway. Off = each segment runs at its nominal rate and a pause shifts the schedule. |
[2 - Day And Night] CatchUpLimit |
4 |
How far from the nominal rate the catch-up may go, as a ratio either side (a 0.525x day may run between 0.131x and 2.1x). Higher absorbs longer pauses at the cost of a visibly faster or slower sun afterwards. 1 = never deviate. |
[3 - Client Sync] ClockPushInterval |
0.5 |
Seconds between extra pushes of the clock to clients (vanilla pushes every 2 s). Keeps the sun moving smoothly when the rate is far from 1x. 2 adds no extra traffic. |
[4 - Boats] PauseFor |
Ships |
Ships = the whole server's clock runs at vanilla speed while any player is near a boat. Water = also while any player is over water. Off = never pause; boats take damage under sail while the schedule is active. Read Boats below before changing it. |
[4 - Boats] PauseRadius |
64 |
Metres around each player in which a boat under way pauses the schedule. A sailing player's reported position trails the hull by a couple of seconds, so keep it generous. 8 to 256. |
[4 - Boats] MooredRadius |
24 |
The same for a boat at rest. Only someone aboard takes the hits, so this just covers the deck, and a boat docked beside your base does not pause the schedule whenever anyone is home. 4 to 256. |
[4 - Boats] UnderWaySpeed |
2 |
Metres per second a boat must be moving, between two checks, to count as under way. A moored hull drifts far slower; a rowed Karve is faster. 0.1 to 20. |
[4 - Boats] CheckInterval |
0.5 |
Seconds between boat checks (one cheap sector query per connected player each). The schedule reacts to a boat within this delay. 0.1 to 5. |
[5 - Compatibility] BandDetection |
Auto |
Where sunrise and sunset fall in the game day. Auto reads them from the running game, so a mod that moves them (Gamma of Night Lights' day/night cycle) is followed and DayMinutes / NightMinutes mean its daylight and night. Vanilla assumes the vanilla knees whatever other mods do. Read Pairing with Gamma of Night Lights below. |
[5 - Compatibility] BandProbeSteps |
1000 |
How finely the day is sampled to find that band: sunrise and sunset are located to within 1/steps of a day, and a mod that sets the night in whole percent lands exactly on the grid at 1000. 100 to 10000. |
[1 - General] Enabled |
true |
Master switch. Off = vanilla 21 + 9. |
[1 - General] VerboseLogging |
false |
Log every sunrise and sunset with the day number, how long the segment that just ended really ran, and the rate that just took effect; also every pause and resume near boats. |
A few starting points:
| Feel | DayMinutes |
NightMinutes |
Full day |
|---|---|---|---|
| Vanilla | 21 | 9 | 30 min |
| Long lazy days | 45 | 10 | 55 min |
| Builders' server | 60 | 5 | 65 min |
| Horror server | 10 | 20 | 30 min |
| Quick test | 1 | 1 | 2 min |
🔭 How it works
Every machine in a Valheim game turns one number into the time of day: the world clock, in game-seconds. Only the server advances it, and every 2 seconds it pushes the value to each client, which simply adopts it. Time of day is that clock modulo the day length, 1800 game-seconds: the stretch from 0.15 to 0.85 of each day (1260 seconds) is daylight, the remaining 540 seconds are night. That is where vanilla's 21 + 9 comes from. Astrolabe reads those numbers from the running game rather than assuming them (the day length from EnvMan, the two knees by sampling the function that turns the clock into the sun's position), so a mod that changes them changes what Astrolabe paces; see Pairing with Gamma of Night Lights below.
The server cannot change the 1800 baked into an unmodded client. It can change how fast the clock runs.
Astrolabe scales the server's clock tick to 1260 / (DayMinutes x 60) game-seconds per real second while the
sun is up and 540 / (NightMinutes x 60) while it is down, switching exactly at sunrise and sunset (a tick
that straddles the boundary is split so each side runs at its own rate). A day is still 1800 game-seconds,
the clock still only counts up, the world save stores it unchanged. It just takes as long as you said.
Holding the schedule. Those rates are the nominal ones. Each segment also gets a deadline, sunset at sunrise
plus DayMinutes and sunrise at sunset plus NightMinutes, and every tick the clock runs at whatever rate still
spends the segment's remaining game-seconds inside the remaining time, within CatchUpLimit either side of
nominal. While nothing interferes that is exactly the nominal rate. When something does (a stretch at vanilla
speed near a boat, a server hitch, a config edit mid-day) the rest of the segment absorbs it and the boundary
still lands on time.
Between pushes an unmodded client runs its own copy of the clock at 1x, so each push applies a small correction. The sun and the rendered water smooth it over about 2 seconds; Astrolabe pushes every 0.5 s by default so it stays under a degree of sun movement at any sane setting, at the cost of one tiny packet per client per half second. The water surface that boats are simulated against is not smoothed, whatever the push interval, which is why the schedule pauses near them (see Boats below).
⛵ Boats: how time works when someone is on the water
The short version. While any player is near a boat, the whole server's clock runs at vanilla speed. The moment nobody is, the schedule takes over again and, by default, makes up the lost ground so sunrise and sunset still land when you scheduled them. Boats never take extra damage. The schedule only slips when boats are in use for more of a segment than it can absorb, and the log tells you when that happens.
Why the pause exists. Between pushes an unmodded client runs its own copy of the clock at vanilla speed and then hard-sets it to the server's value. While the schedule is active every push therefore nudges the client's clock by a fraction of a second. The sun and the rendered water smooth that away, but the water surface that boats are simulated against is computed from the raw clock, so each nudge moves it a few centimetres to a few decimetres in a single physics step. A boat with anyone aboard treats that as a slam and takes vanilla's water-impact damage: 10 per hit, up to thirty hits a minute. That is what 0.1.0 did to a Karve under sail: constant bobbing and 60-150 hull damage a minute. Pushing more often does not help, the check is per physics step. The only clean state while a boat is in use is vanilla speed, where a push carries nothing the client did not already have.
What "near a boat" means. Within PauseRadius (64 m) of a boat that is under way, or MooredRadius
(24 m) of one at rest. Every vanilla boat and any modded one counts. A boat is under way when it moved faster
than UnderWaySpeed between two checks CheckInterval apart, and positions are checked every half second.
A player only takes the hits while aboard, which is why a boat docked beside your base pauses the schedule for
someone standing on or right beside it, not for everyone at home.
One clock, one pause. There is one world clock for the whole server, so none of this is per player. The first player near a boat pauses the schedule for everyone, the tenth adds nothing, and it resumes when the last one leaves. A player at a base far from any boat sees the sun move at vanilla speed for as long as somebody else is sailing. Nobody sees a jolt in either direction: changing the rate is continuous.
Catching up. With HoldSchedule on (the default), each segment has a deadline: sunset at sunrise plus
DayMinutes, sunrise at sunset plus NightMinutes. After a pause the rest of the segment runs faster or
slower, up to CatchUpLimit times the nominal rate either side, so the boundary lands on the deadline
anyway. After a ten-minute sail in a 40-minute day the remaining daylight runs at about 0.37x instead of
0.525x, which nobody notices. How much boating a segment can absorb depends on how far it is from vanilla,
because boating runs the game clock at vanilla pace and a segment only has so many game-seconds:
| Segment | Boating it absorbs with the boundary still on time | Beyond that |
|---|---|---|
| Day 40 min | about 18 min | sunset comes early by the excess |
| Day 60 min | about 17 min | sunset comes early by the excess |
| Day 120 min | about 16 min | sunset comes early by the excess |
| Night 5 min | about 4 min | sunrise runs late by what the cap cannot close |
| Night 10 min | about 9 min | sunrise comes early by the excess |
| Night 20 min | about 8 min | sunrise comes early by the excess |
| Vanilla 21 + 9 | everything | never: there is nothing to absorb |
The rule of thumb: a segment stretched longer than vanilla absorbs a little under its vanilla length of
boating (21 minutes for a day, 9 for a night); a segment shortened below vanilla absorbs most of its own
length. Raise CatchUpLimit to absorb more at the cost of a stranger-looking sun afterwards. If someone is on
a boat for longer than that, the server is simply on vanilla time for the rest of that segment and the next
one starts fresh. On a server where a boat is in use around the clock, the schedule never runs. That is the
limit of a mod that puts nothing on clients, and you should know it before advertising the lengths.
Reading it in the log. With VerboseLogging on, every pause and resume is logged with who and which
boat, and every sunrise and sunset says how long the segment really ran, what was scheduled and how much of
it was at vanilla speed:
[Info :DvergrAstrolabe] schedule paused, clock at vanilla speed: Thorium is 12 m from a Karve under way.
[Info :DvergrAstrolabe] schedule resumed after 6.5 min at vanilla speed.
[Info :DvergrAstrolabe] sunset, day 12: daylight ran 40.0 real min (40 scheduled, 6.5 of them at vanilla speed near boats); clock at 0.9x for the next 10 real min.
Other settings. PauseFor = Water also pauses for any player standing or swimming over water (by the
world's terrain height, so not raised ground), which spares swimmers, fishing floats and floating items the
bobbing at the cost of pausing far more often on a coastal server. PauseFor = Off never pauses; use it only
on a world without boats. HoldSchedule = false runs every segment at its nominal rate and lets a pause shift
the schedule instead. If the boat lookup ever fails on a future game build the mod logs an error and keeps the
clock at vanilla speed until restart rather than risk hulls.
🌗 Pairing with Gamma of Night Lights
Some configurations need two mods, and the pairing is not obvious, so here it is spelled out. The partner is
shudnal's Gamma of Night Lights (tested against 1.0.10). Only its [Day night cycle] section matters here:
Enabled, Night length (the percentage of the game day that is night, vanilla 30) and Day length in seconds
(how long a game day is, vanilla 1800). Its other sections (luminance, fog, sun and moon intensity) are pure
lighting and have nothing to do with Astrolabe; the two mods do not conflict anywhere.
The two mods turn different knobs. Astrolabe changes how fast the clock runs and keeps the per-day economy: a crop always takes one day, so a longer day costs more real minutes. Gamma changes how the game day is divided and how big it is, at a flat 1x clock, and keeps the per-real-minute economy: production is vanilla at every instant. The consequence, which is the question that started all of this: with Astrolabe alone you cannot have a flat 1x clock and a night longer than the day. The daylight band is a fixed share of the game day (70% in vanilla), so any unequal real-minute split means an off-1x rate in both segments; the only 30-minute split where both sit at 1x is 21 + 9, which is why vanilla is 21 + 9. A long night with untouched real-time production is Gamma's job, not Astrolabe's.
The formula.
production rate = Day length in seconds (Gamma) / ((DayMinutes + NightMinutes) x 60) (Astrolabe)
Gamma sets the numerator, Astrolabe sets the denominator, and Gamma's Night length sets the split
independently of both. For any cycle length you like, Gamma's day length divided by it is your production
multiplier. Set Night length to the night's share of your real cycle (NightMinutes / (DayMinutes + NightMinutes), 75 for 45 of 60) and both segments land on that same multiplier, so there is no fast-day,
slow-night contrast at all; that is the real point of the pairing. (Any other split still averages to the
same multiplier over a full cycle, but day and night then run at different speeds.) All three rows below are
a 60-real-minute cycle, 45 of it night:
| Production | Gamma Day length in seconds |
Gamma Night length |
Astrolabe DayMinutes / NightMinutes |
Detected band (day / night game-s) | Both rates |
|---|---|---|---|---|---|
| vanilla 1x | 3600 | 75 | Astrolabe disabled (or 15 / 45) | 900 / 2700 | 1x |
| 1.5x | 5400 | 75 | 15 / 45 | 1350 / 4050 | 1.5x |
| 2x | 7200 | 75 | 15 / 45 | 1800 / 5400 | 2x |
The 1x row needs no Astrolabe at all: Gamma alone already lands a 60-minute cycle at 1x, so do not install it for that. The 1.5x and 2x rows are not expressible by either mod alone.
Order of operations. Set Gamma's Day length in seconds and Night length first, then set Astrolabe's
DayMinutes / NightMinutes to the real minutes you want. Astrolabe reads the band Gamma produced; Gamma has no
idea Astrolabe exists. It reads it by sampling EnvMan.RescaleDayFraction, which Gamma's
EnvMan_RescaleDayFraction_DayNightLength prefix reshapes (its EnvMan_GetMorningStartSec_DayNightLength and
EnvMan_SkipToMorning_DayNightLength prefixes move the sleep target the same way, and Astrolabe already follows
the sleep skip). This only works with band detection on, [5 - Compatibility] BandDetection = Auto, the default
since 0.3.0. On 0.2.1 and earlier Astrolabe assumed the vanilla 0.15 / 0.85 knees, so with Gamma's cycle
active every rate was wrong by the band ratio and the segment it treated as the long one was the short one. The
one-glance check that the two are cooperating is the day cycle line (and every schedule line) in the log,
which prints the detected band: daylight band 900 of 3600 game-s (25%, sunrise and sunset moved by another mod).
The caveat, up front. Astrolabe's whole pitch is that clients install nothing. Gamma's cycle feature does not share that property: it patches EnvMan, which runs on every machine, so it must be installed on the clients too, or the server will think it is night while players still see daylight. The moment you reach for this pairing you have given up the no-client-install property, for Gamma's part of it, not Astrolabe's. Anyone who needs zero client install (Xbox, PlayFab, crossplay parties) is limited to Astrolabe alone and the per-day economy, and that is the recommendation for that case.
Which to use.
- Clients cannot install anything: Astrolabe alone. Production tracks days, not real minutes.
- Clients have your pack and you want vanilla real-time production with a different day/night feel: Gamma alone. You do not need Astrolabe.
- You want a specific total real cycle length and a flat production multiplier: both, per the table.
Any other cycle mod. The detection is not tied to Gamma: whatever patches RescaleDayFraction is followed.
The band is re-read every 5 seconds, at every sunrise and sunset and after each config edit, so a change on the
other mod's side is picked up within seconds and the rest of the current segment absorbs it the way it absorbs a
pause. If detection ever fails on a game build this mod has not seen, it falls back to the vanilla knees and logs
an error; BandDetection = Vanilla forces that by hand. A mod that changes the day length alone was always
followed.
📏 What changes, and what doesn't
Untouched. Boats: the whole clock runs at vanilla speed while anyone is near one (see Boats), so hulls take no extra damage. The day counter (it ticks at midnight, the Day N banner still appears at sunrise). Sleeping: still allowed from noon, still skips to the next sunrise in 12 real seconds. World saves. The empty-server freeze: with nobody online the clock stops exactly as in vanilla (if you run Let It Grow's time flows while empty, its tick is the scaled one, so the two agree).
Stretch with your day (they run on the game clock). Crops and trees, smelters, kilns and furnaces, cooking stations, fermenters, beehives and sap collectors, fires' fuel, item despawn, berry and pickable respawn, creature spawners, taming hunger, pregnancy and growing up, creature and tame health regeneration, trap and ballista rearm, snow damage. With a 45-minute day these still take exactly as many days as before, which now means more real minutes. With a 1-minute night, monsters regenerate health nine times faster than you are used to while it is dark.
Do not stretch (they run on the wall clock). Raids and random events, Rested, food, comfort. A longer day therefore gets more raids per game day, a shorter one fewer.
Fine print. At very long stretches (a rate under 0.2x: days over 105 minutes or nights over 45) a
client-owned fire, beehive or sap collector can occasionally drop a fraction of a second of progress when a
clock correction lands mid-tick; lower ClockPushInterval to 0.25 to shrink it further. The log warns you, at
startup and after each config edit, when a setting lands at or under that floor, or above the point where one
clock push moves the sun more than a degree in a single step (about 11x at the default push interval); the line
names the setting and the number to change. The vanilla 10-game-second lockout between two sleep attempts scales
with the night rate too.
📦 Install
Server side only. Drop DvergrAstrolabe.dll into BepInEx/plugins/ on the dedicated server (for a
player-hosted world, on the hosting player's game). Start it once to generate the cfg, set DayMinutes and
NightMinutes, done. Nothing goes on clients; if the DLL ends up on a client by accident it does nothing. (A mod
that changes the game's own cycle, such as Gamma of Night Lights, is a different matter: see Pairing with Gamma
of Night Lights.)
Requires the BepInExPack for Valheim (5.4.2350). Built against the Valheim 1.0 dedicated server.
🧪 Checking it works
BepInEx/LogOutput.log on the server, at startup and after every config edit:
[Message:DvergrAstrolabe] schedule (startup): daylight 45 real min at 0.467x, night 10 real min at 0.9x; one full day = 55 real min (30 at vanilla speed); daylight band 1260 of 1800 game-s (70%, vanilla assumed until the world loads); each sunrise and sunset is held to its scheduled time, catching up at up to 4x the nominal rate after a pause; clock pushed to clients every 0.5 s (plus vanilla's 2 s); pauses at vanilla speed while any player is within 64 m of a boat under way or 24 m of one at rest.
[Message:DvergrAstrolabe] day cycle (read from EnvMan): 1800 game-s per day, daylight band 1260 of 1800 game-s (70%, vanilla); daylight runs at 0.467x for 45 real min and night at 0.9x for 10.
[Message:DvergrAstrolabe] clock patch live: EnvMan found, day 12, raw day-fraction 0.412 (daylight), 1 player(s) connected.
[Message:DvergrAstrolabe] boat guard ready: sector query OK (312 objects, 1 boat(s) within a zone of the world origin).
With Gamma of Night Lights at 3600 / 75 and Astrolabe at 15 / 45, the day cycle line shows the band it found
and the flat pace that follows from it:
[Message:DvergrAstrolabe] day cycle (read from EnvMan): 3600 game-s per day, daylight band 900 of 3600 game-s (25%, sunrise and sunset moved by another mod); daylight runs at 1x for 15 real min and night at 1x for 45.
[Message:DvergrAstrolabe] note: sunrise and sunset in this world sit at raw day-fraction 0.375 and 0.625 instead of vanilla's 0.15 and 0.85, so another mod shapes the cycle (Gamma of Night Lights' day/night cycle does exactly this) and Astrolabe paces the band it defines. That mod has to be on every client as well, or the night the server paces is not the night players see; Astrolabe itself still needs nothing on clients.
With VerboseLogging on, every transition and every pause as well. The segment lengths are measured, so the log
proves the schedule by itself:
[Info :DvergrAstrolabe] sunset, day 12: daylight ran 45.0 real min (45 scheduled); clock at 0.9x for the next 10 real min.
[Info :DvergrAstrolabe] schedule paused, clock at vanilla speed: Thorium is 12 m from a Karve under way.
[Info :DvergrAstrolabe] schedule resumed after 6.5 min at vanilla speed.
[Info :DvergrAstrolabe] sunrise, day 13: night ran 9.3 real min (10 scheduled, 6.5 of them at vanilla speed near boats); clock at 0.467x for the next 45 real min.
A Valheim mod by Wubarrk.