Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
DvergrAstrolabe
Day length, daylight and night in real minutes, with production as its own dial: vanilla pace or faster at any cycle length. Server-synced and version-locked, required on clients too; the full maths is printed to the log.
| Date uploaded | a week ago |
| Version | 0.4.0 |
| Download link | Wubarrk-DvergrAstrolabe-0.4.0.zip |
| Downloads | 119 |
| Dependency string | Wubarrk-DvergrAstrolabe-0.4.0 |
This mod requires the following mods to function
denikson-BepInExPack_Valheim
BepInEx pack for Valheim. Preconfigured with the correct entry point for mods and preferred defaults for the community.
Preferred version: 5.4.2350README
๐ญ Dvergr Astrolabe
How long a day takes. How much of it is daylight. How fast the world works. Three dials, one cfg, the full maths in the log.
๐ฐ Wubarrk lives on Hexium - don't miss out
Dvergr Astrolabe is published here and on valheim.hexium.gg. The rest of the
Wubarrk and RavenIron Studios catalogue is Hexium only: that is where the current builds live, every one of
them tagged Valheim 1.0. The old copies under the Wubarrk name here on Thunderstore are pre-1.0 lines, most
of them deprecated, and they are not kept current. Hexium packages install with one click from the
Gale mod manager, or unzip into BepInEx/plugins like any other mod.
Here is what you are missing.
Server-side only, nothing on clients - the same family as this mod, so Steam, Xbox, PlayFab and crossplay parties all get it with nothing installed:
- Wonderland - automation, world governance, status effects and Discord notifications for a server whose players run plain vanilla, with vanilla-client enforcement built in.
- Get Off My Lawn - active wards keep wild creatures and raids out of your base, and doors inside wards close themselves.
- TortalPortal LITE - a portal network with progression-gated gates, one-way corpse-run recovery, fast-transit terminals, per-portal ore upgrades and portal caps.
Client and server:
- Njord - a mythic overhaul of ship handling, steering and seafaring, with a Harbourmaster who gives every new Viking their first hull and refits the rest.
- Shadows of Midgard - a stealth and perception engine: creatures see, hear, remember and doubt, with vision cones, line of sight, noise, light, weather and camouflage tracked for each player separately.
- Wings of the Valkyrie - four tiers of upgradable runic dragon wings with real armour and resistances, and a Valkyrie Flight skill that grows with every wingbeat.
- Fatty - a food overhaul: no stat decay, a bigger food bar with a drink slot, stack the same food for extra stats, and diet-based synergy buffs. Works with any food mod.
- StackIT - server-synced stack sizes, item weights and carry capacity, plus hold Shift to harvest a whole berry patch.
- TortalPortal - total portal control: pick destinations from a map UI, with destination photos, PIN locks, tame teleportation, travel filters and a procedural runic gateway.
- AwayFromHome - build a Keeper Stone and that place keeps living while you are elsewhere: animals fed, smelters reloaded, production that no longer stops on an empty server.
- Let It Grow - a full farming overhaul: configurable growth speed and conditions, hover grow-timers, and Scarecrow and Farm Silo automation that tends farms nobody is near.
- RuneboundRest - server-authoritative Rested and Comfort: config-driven comfort, resting conditions and duration, plus a Well Rested buff for a full night in your own claimed bed.
- Blighted World Heart - a massive raid boss that summons endless waves and unique sub-bosses, dropping dozens of custom weapons and armours with Poison, Spirit and Defense affixes.
- Dvergr Allies - tame, breed and lead an army of Dvergr: four classes, breeding genetics, star-level weapon scaling and native combat AI.
- Mists of Avalor - a procedural black-stone crypt-labyrinth in a forsaken sky-realm: true-damage traps, restless dead, keys torn from mutant bosses, and the Avalorian Greatsword off the Warden. Bring a torch.
- VikingOS (beta) - rebuild the interface: move, resize and rotate any HUD, inventory or chat element in a live edit mode, plus chat that keeps your capitals and drag-and-drop item sharing.
RavenIron Studios:
- FireFront - fire that actually spreads: structure to structure, into the trees, across open ground. Wind-driven, rain-damped, stopped by water, with burn scars, tree regrowth and fires that remember who lit them.
- Ragnarok's Wrath - the world reacts and remembers: seasons, devastating storms, spreading plague with visible miasma, fire scars, tiring soil and earned titles.
- Undertow - the sea gets its own motion: currents in a learnable shape, tides, storm surge and flotsam, carrying whatever floats on them. No HUD.
- Cairn - stack stones on a headland and they burn: a trail of cairns you build yourself, lit and remembered, for worlds with no map.
- Valkyries Cargo - a Valkyrie air-drops Ingvar the Far-Travelled, a dwarven merchant, beside your hearth when rested; buy and sell at supply-and-demand prices before he vanishes.
- The Raven's Call (server-only) - admin and analytics: kills, deaths, bosses, gear and playtime narrated to Discord and Chronicle logs, with a web dashboard. Pairs with WhereTheCrowFlies, the client companion that witnesses and reports the events.
- RavenEye - for server owners: restores the vanilla map to listed admins only on no-map worlds, with every player pinned. Does nothing for anyone else.
Two are published in both places: Valheim 1.0 Compatibility, the preloader that carries pre-1.0 mods across, and The Eye, the API dump tool for mod developers. Questions, bug reports, the clan: Discord. ๐
A vanilla Valheim day is 30 real minutes: 21 of daylight and 9 of night, and everything that grows, smelts, ferments or burns runs at one game-second per real second. Dvergr Astrolabe lets you set all of that: the length of a full day in real minutes, how many of those minutes the sun is up and how many it is down, and, separately, how fast production runs - vanilla pace whatever the day length, or faster. The mod solves the game-day length, the sunrise and sunset points and the clock rate that give exactly what you typed, applies them on the server and on every client, and prints every step of the working to the log.
0.4 is a client and server mod. The server's cfg is the authority (ServerSync, locked by default), every connecting client adopts it, and the mod is required on both sides: a vanilla client is turned away at the door. That is what makes production an independent dial - 0.3 and earlier could only pace the server's clock and had to trade real minutes against production (see Upgrading from 0.3).
โ๏ธ Settings
BepInEx/config/wubarrk.dvergrastrolabe.cfg on the server (on the hosting player's game for a player-hosted
world, on your own game for single player). Edits are picked up within 5 seconds, no restart, and pushed to every
connected client. The defaults are vanilla, so installing the mod changes nothing until you set them. Every key in
the file carries a plain-language comment with worked examples ("60 = each day takes one real hour"), so the cfg
explains itself; this table is the short form.
| Setting | Default | What it does |
|---|---|---|
[2 - Cycle] CycleMinutes |
30 |
Real minutes one full game day takes, sunrise to sunrise. 0.5 to 1440. The game day becomes L = round(R x 60 x CycleMinutes) game-seconds. |
[2 - Cycle] DaytimeMinutes |
21 |
Real minutes the sun is up: sunrise to sunset, the stretch the game counts as day (the Day N banner fires at its start; sleeping opens halfway through). 0.25 to 1440. |
[2 - Cycle] NightMinutes |
9 |
Real minutes the sun is down: sunset to sunrise, through dusk, the midnight day-counter tick and dawn. 0.25 to 1440. |
[2 - Cycle] LengthRule |
FitToCycle |
Which length gives way when daytime + night is not the cycle. FitToCycle keeps the cycle exact and scales the other two to fit, keeping their ratio. DaytimePlusNight makes the cycle their sum. CycleMinusNight keeps the night exact. CycleMinusDaytime keeps daytime exact. Agreeing values give the same answer under every rule. |
[3 - Production] ProductionScale |
1 |
How fast everything on the game clock runs, as a multiple of vanilla: 1 = vanilla, 2 = twice as fast, 0.5 = half. 0.01 to 100. Never touches the sun. |
[3 - Production] ProductionBasis |
RealTime |
What 1 means. RealTime = vanilla production per real minute whatever the cycle length (the day is stretched to fit). GameDays = vanilla production per game day, as 0.3 behaved (the day stays 1800 game-seconds and the clock slows or speeds to fit). |
[4 - Clock] SleepSkipPushInterval |
0.5 |
Seconds between extra clock pushes to clients while everyone sleeps and the server runs the night forward in 12 real seconds. Vanilla pushes every 2 s (6 visible steps); 0.5 gives 24. Server side. 0.1 to 2. |
[4 - Clock] WaveSpeed |
Vanilla |
Vanilla = the water surface runs on real time, so waves look and hit exactly as in vanilla at any clock rate. FollowClock = water time is the game clock, as an unmodded game has it. |
[5 - Compatibility] PatchSelfCheck |
true |
After applying, sample the game's own sunrise/sunset function and confirm it answers with Astrolabe's values; re-check the day length every 5 s and put it back if another mod changes it. Read Other cycle mods. |
[5 - Compatibility] SelfCheckSteps |
1000 |
How finely that check samples the day. 100 to 10000. |
[1 - General] Enabled |
true |
Master switch, synced. Off = vanilla on every machine. |
[1 - General] LockConfiguration |
true |
The server's values are the only ones that count. Keep it on: every machine must agree on the day length, the knees and the clock rate. |
[1 - General] VerboseLogging |
false |
Log every sunrise and sunset with how long the segment really ran, each sleep skip, and the self-check on success. Per machine, not synced. |
A few starting points (all LengthRule = FitToCycle, ProductionBasis = RealTime):
| Feel | CycleMinutes |
DaytimeMinutes |
NightMinutes |
ProductionScale |
Game day L |
Clock R |
Production per real min | Per game day |
|---|---|---|---|---|---|---|---|---|
| Vanilla | 30 | 21 | 9 | 1 | 1800 | 1x | 1x | 1x |
| Long lazy days | 60 | 45 | 15 | 1 | 3600 | 1x | 1x | 2x |
| Long days, busy world | 60 | 45 | 15 | 2 | 7200 | 2x | 2x | 4x |
| Builders' server | 120 | 100 | 20 | 1 | 7200 | 1x | 1x | 4x |
| Horror server | 30 | 10 | 20 | 1 | 1800 | 1x | 1x | 1x |
| Vanilla economy, long days (0.3 feel) | 45 | 40 | 5 | 1 (GameDays) |
1800 | 0.667x | 0.667x | 1x |
| Quick test | 2 | 1 | 1 | 1 | 120 | 1x | 1x | 0.067x |
Read the two production columns together: with RealTime a crop that took one vanilla day of growth still takes
30 real minutes however long you make the day, which on a 60-minute day is half a day. With GameDays it still
takes one day, which is now 45 real minutes.
๐ The mathematics
Every machine in a Valheim game turns one number into the time of day: the world clock, in game-seconds, which only ever counts up. Three things decide what that number means, and Astrolabe sets all three on every machine:
| Quantity | Symbol | Where the game keeps it | Vanilla |
|---|---|---|---|
| Game-seconds in one day | L |
EnvMan.m_dayLengthSec |
1800 |
| Raw day-fraction of sunrise and sunset | s, e |
the knees of EnvMan.RescaleDayFraction |
0.15, 0.85 |
| Game-seconds the clock grows per real second | R |
the dt in ZNet.UpdateNetTime |
1 |
Raw day-fraction is (clock mod L) / L; RescaleDayFraction maps the stretch from s to e linearly onto the
visual 0.25..0.75 in which the sun is above the horizon and EnvMan.IsDay is true, and the two tails onto
0..0.25 and 0.75..1. So daylight lasts (e - s) x L / R real seconds and a whole day L / R.
Given the three lengths T (cycle), D (daytime) and N (night) in real minutes, and the production scale P,
the solver runs six steps. The log prints them with your numbers in, every time the settings are applied.
1. Reconcile the lengths so that D + N = T, by LengthRule:
| Rule | Cycle | Daytime | Night |
|---|---|---|---|
FitToCycle |
T |
T x D / (D + N) |
T x N / (D + N) |
DaytimePlusNight |
D + N |
D |
N |
CycleMinusNight |
T |
T - N |
N |
CycleMinusDaytime |
T |
D |
T - D |
(A rule that would leave a segment under 15 seconds floors it at 15 seconds and stretches the cycle instead, and
the log warns.) From here on T, D, N are the reconciled values.
2. Daylight share: f = D / T. Vanilla 0.7.
3. Requested clock rate, game-seconds per real second:
RealTimebasis:R0 = PGameDaysbasis:R0 = P x 1800 / (60 x T)
4. Day length: L = round(R0 x 60 x T) game-seconds. It has to be a whole number because the game stores it as
one; vanilla's 1800 is the point R0 = 1, T = 30.
5. Exact clock rate: R = L / (60 x T). Recomputed from the rounded L so that one game day takes exactly T
real minutes; the rounding lands on R instead, by at most 0.5 / L relative (one part in 3600 on a 30-minute
day), and the log prints the production scale actually realised.
6. Sunrise and sunset: s = 0.5 - f / 2, e = 0.5 + f / 2. Noon stays at raw 0.5 and midnight (the day
counter's tick) at raw 0, as in vanilla; the daylight band is centred on noon and f wide. Vanilla's 0.15 / 0.85 is
f = 0.7.
What follows. With those in place, on every machine:
daylight = f x L / R real seconds = 60 x D (exactly D minutes)
night = (1 - f) x L / R real seconds = 60 x N
full day = L / R real seconds = 60 x T
production = R x vanilla, per real minute
= L / 1800 x vanilla, per game day
a vanilla day of work (1800 game-seconds of growth, smelting, fuel)
= 30 / R real minutes = 1800 / L game days
sun, by day = 180 / D degrees per real minute (vanilla 8.57)
sun, by night = 180 / N degrees per real minute (vanilla 20)
The sun's pace depends on the two lengths alone. P changes R and L together and in the same ratio, which is
why production is a dial of its own: the sky looks identical at ProductionScale = 1 and = 3, only the crops and
the smelters and the weather know the difference. The vanilla night is faster than the vanilla day (20 degrees a
minute against 8.57) and stays so at any setting that keeps the 70/30 split; a 45/15 split makes it 12 against 4.
Worked examples.
T / D / N / P / basis |
f |
R0 |
L |
R |
s / e |
Per real min | Per game day | Sun day / night | |
|---|---|---|---|---|---|---|---|---|---|
| Vanilla | 30 / 21 / 9 / 1 / RealTime | 0.7 | 1 | 1800 | 1 | 0.15 / 0.85 | 1x | 1x | 8.57 / 20 |
| Long days | 60 / 45 / 15 / 1 / RealTime | 0.75 | 1 | 3600 | 1 | 0.125 / 0.875 | 1x | 2x | 4 / 12 |
| Long days, busy | 60 / 45 / 15 / 2 / RealTime | 0.75 | 2 | 7200 | 2 | 0.125 / 0.875 | 2x | 4x | 4 / 12 |
| 0.3 feel | 45 / 40 / 5 / 1 / GameDays | 0.889 | 0.667 | 1800 | 0.667 | 0.056 / 0.944 | 0.667x | 1x | 4.5 / 36 |
| Horror | 30 / 10 / 20 / 1 / RealTime | 0.333 | 1 | 1800 | 1 | 0.333 / 0.667 | 1x | 1x | 18 / 9 |
| Rounding | 33.3 / 20 / 13.3 / 1.37 / RealTime | 0.6 | 1.37 | 2737 | 1.36987 | 0.2 / 0.8 | 1.37x | 1.52x | 9 / 13.5 |
The last row shows step 5 at work: 1.37 x 60 x 33.3 = 2737.26 rounds to 2737, the cycle stays exactly 33.3
minutes, and the realised production scale is 1.36987 instead of 1.37.
Vanilla is a fixed point. At the defaults the solver returns L = 1800, R = 1, s = 0.15, e = 0.85, and the
patched RescaleDayFraction is bit-for-bit the vanilla function (it uses the same float constants). The mod then
changes nothing at all, which is checked by its own test suite and by the self-check in the log.
๐ญ Where it meets the game
On every machine (server, host and each client), from the same synced settings and the same solver, so all of them agree to the game-second:
EnvMan.m_dayLengthSecis set toLwhen the world loads and whenever the settings change.EnvMan.RescaleDayFractionis replaced by the same function withsandefor knees.EnvMan.GetMorningStartSecreturnsday x L + L x s, andEnvMan.SkipToMorning(sleeping) usesswhere vanilla hardcodes 0.15 when it picks which sunrise to skip to. The night is still skipped in 12 real seconds.ZNet.UpdateNetTimeaddsdt x Rto the world clock instead ofdt: on the server while anyone is connected, on each client between the server's pushes. Because the clients run at the sameR, a push from the server carries nothing but network jitter, exactly as in vanilla - no corrections, at any rate.ZNet.GetWrappedDayTimeSeconds, which only the water and the fish read, returns the clock divided byRwhileWaveSpeed = Vanilla, so the water runs on real time.
Nothing is ever done to the clock itself: it keeps counting up through every change, so every timestamp in the world (when a crop was planted, when a smelter last ran, how long a fire has burned) stays valid.
๐ What changes, and what doesn't
Runs at R times vanilla per real minute (lives on the game clock). Crops and trees, smelters, kilns and
furnaces, cooking stations, fermenters, beehives and sap collectors, fuel, item despawn, berry and pickable
respawn, creature spawners, taming hunger, breeding and growing up, creature and tame health regeneration, trap
and ballista rearm, snow damage, weather periods and wind changes, the 10-game-second lockout between two sleep
attempts. With RealTime and ProductionScale = 1 all of it is vanilla per real minute at any cycle length.
Runs on the wall clock, unaffected. Raids and random events, Rested, food, comfort. A longer day therefore gets more raids per game day, a shorter one fewer, the same as 0.3.
The day counter and the time of day when L changes. The day number is clock / L and the time of day is
clock mod L, and the clock is never re-based (doing that would make every timestamp in the world jump by hours).
So the first time a world runs with a different L, both shift once: a world on day 277 of 1800-second days reads
day 138 at L = 3600, and the time of day moves to wherever clock mod 3600 falls. After that everything is
consistent again. The log prints exactly what happened:
[Message:DvergrAstrolabe] day length changed on a running world, 1800 -> 3600 game-seconds: the world clock (499321 game-s) is untouched, so the day counter now reads 138 (was 277) and the time of day moved from raw 0.401 to 0.700 of the day; everything stamped in game-seconds (crops, smelters, fires) carries on unchanged. ProductionBasis = GameDays with ProductionScale = 1 keeps the day at 1800 and never does this.
The jump only happens when L changes, that is when CycleMinutes or ProductionScale change under RealTime,
or ProductionScale under GameDays. Changing only DaytimeMinutes / NightMinutes moves the knees, which
shifts where in the day the sun is right now but not the day number. If you want long days on an existing world
with no jump at all, GameDays with ProductionScale = 1 keeps L = 1800 forever, at the price of production
tracking days instead of real minutes.
Sleeping. Still allowed from the afternoon (visual 0.5, the middle of daytime) and through the night, still
skips to the next sunrise in 12 real seconds whatever the lengths. SleepSkipPushInterval only decides how many
steps clients see it in.
New worlds. A new world starts with the clock at 2040 game-seconds. On an 1800-second day that is day 1, just before sunrise; on a 3600-second day it is day 0, just past noon. Cosmetic.
๐ง Client and server
The cfg lives on the server. ServerSync (compiled in, nothing extra to install) pushes every synced value to each
client on connection and whenever the server's file changes, and LockConfiguration (default on) makes the
server's values the only ones that count: a client's own cfg is ignored while connected. Each client logs the full
working as it receives the values, so a player can read the same six steps the admin sees.
Both sides must run the same version (0.4.0). The handshake checks it on connection. A vanilla client, or one on another version, is refused with the game's own "incompatible version" message; a client running the mod that joins a server without it is refused with "DvergrAstrolabe is not installed on the server". That rules out Xbox, PlayStation and PlayFab crossplay players, who cannot install mods: a server for them is a server on Astrolabe 0.3.0, the server-only line, whose limits are described under Upgrading from 0.3.
Single player and player-hosted worlds. Your own cfg is the authority; the host's cfg is the server's for everyone who joins.
Why both sides. 0.3 and earlier changed only the rate of the server's clock and left every client's 1800-second day alone, which worked but tied production to the cycle length and bobbed every boat on every clock push. With the day length and the knees set on every machine the clock can run at the same rate everywhere, pushes carry nothing, and production becomes a number you type.
โต Boats and water
0.3 and earlier had to pause the schedule whenever anyone was near a boat, because every clock push moved an unmodded client's
water surface in one step and the hull took it as a slam (10 damage per hit, up to thirty a minute). That whole
mechanism is gone: every machine runs the clock at the same R, a push changes nothing the client did not already
have, and boats sail through any setting untouched.
What remains is a choice about how the water looks. Water time is the game clock, so at ProductionScale = 3 the
waves would roll three times as fast and a storm would move the surface under a hull three times as quickly,
which the game counts as a slam past 2.5 m/s. WaveSpeed = Vanilla (default) feeds the water the clock divided by
R instead: real time, identical on every machine, so waves look and hit exactly as in vanilla whatever the clock
does. FollowClock leaves it as an unmodded game would have it. While R is 1 the two are the same. Changing R
with Vanilla selected moves the water phase once, on every machine at the same moment.
๐ Other cycle mods
Astrolabe 0.4 owns the cycle. A mod that also sets the day length or moves sunrise and sunset is a conflict, not a partner, and the log tells you so:
- Gamma of Night Lights (shudnal): turn off its
[Day night cycle]section (Enabled = false). Its luminance, fog, sun and moon sections are pure lighting and coexist fine. With the cycle section left on, Gamma writes its own day length every frame and Astrolabe puts its value back every 5 seconds, which flickers the clock and printsanother mod set EnvMan.m_dayLengthSec to 3600; Astrolabe put its 2700 back ...once per foreign value. On the sunrise/sunset function Astrolabe's patch runs last and wins; the self-check line confirms it, or reports the other mod's knees if it did not. - Anything else that patches
EnvMan.RescaleDayFractionor writesEnvMan.m_dayLengthSec: same two lines. The 0.3 detection that followed another mod's band is gone; there is nothing to follow when the band is yours. - Let It Grow's time flows while empty: its postfix on
ZNet.UpdateNetTimereceives the already-scaleddt, so the two agree. - Clock and HUD mods that read
EnvMan.m_dayLengthSecorGetDayFraction()show the right time, because those are what Astrolabe sets.
PatchSelfCheck = false turns both checks off if a mod you trust takes the job on purpose.
โฌ๏ธ Upgrading from 0.3
- Clients need the mod now. That is the whole change.
- Your settings carry over. On first start with a 0.3 (or earlier) cfg,
DayMinutes+NightMinutesbecomeCycleMinutes(their sum),DaytimeMinutesandNightMinutes, withProductionBasis = GameDays, which keeps the 1800-second day and the per-day economy your server was tuned around and leaves the day counter where it is. The log says so. Switch toRealTimewhen you want vanilla real-time production. The old keys stay in the file, ignored; delete them when you like. - One visible difference after migrating: 0.3 paced daylight and night at two different clock rates inside the vanilla 0.15 / 0.85 band; 0.4 moves the band and runs one flat rate. Production is the same per day and now even across the day instead of faster at night. The sun's position shifts once when the band moves.
- Removed:
[4 - Boats]entirely,HoldSchedule,CatchUpLimit,ClockPushInterval,BandDetection,BandProbeSteps. None of them has a job once every machine runs the same clock. - The 0.3 limits are gone with them: no pausing near boats, no catch-up afterwards, no schedule slip on a server where someone is always sailing, no fast-day/slow-night production contrast, no 0.2x floor.
๐ฆ Install
On the dedicated server and on every client (for a player-hosted world: the host and every guest). Drop
DvergrAstrolabe.dll into BepInEx/plugins/, or install from Hexium with Gale. Start the server once to generate
the cfg, set the three lengths and the production scale, done; clients need no cfg of their own.
Requires the BepInExPack for Valheim (5.4.2350). Built against Valheim 1.0.17.
๐งช Checking it works
BepInEx/LogOutput.log, on the server at startup and after every config edit, on each client as the values arrive
(the clients' lines say client instead of dedicated server). This is a 60 / 45 / 15 server, straight from the
testbed:
[Message:DvergrAstrolabe] cycle (startup, no world loaded):
settings : CycleMinutes = 60, DaytimeMinutes = 45, NightMinutes = 15, LengthRule = FitToCycle, ProductionScale = 1, ProductionBasis = RealTime
1 lengths : FitToCycle: daytime + night as typed = 45 + 15 = 60 = CycleMinutes, nothing to adjust -> cycle 60 real min = daytime 45 + night 15
2 share : daylight share f = daytime / cycle = 45 / 60 = 0.75 (vanilla 0.7)
3 rate : ProductionBasis RealTime: requested clock rate R0 = ProductionScale = 1 game-seconds per real second (vanilla 1)
4 day : day length L = round(R0 x 60 x cycle) = round(1 x 60 x 60) = 3600 game-seconds (vanilla 1800) -> EnvMan.m_dayLengthSec on every machine
5 clock : exact clock rate R = L / (60 x cycle) = 3600 / 3600 = 1 game-seconds per real second -> ZNet.UpdateNetTime adds dt x R on every machine
6 band : sunrise at raw day-fraction 0.5 - f/2 = 0.125, sunset at 0.5 + f/2 = 0.875 (vanilla 0.15 / 0.85) -> EnvMan.RescaleDayFraction, GetMorningStartSec and SkipToMorning on every machine
check : daylight = f x L = 2700 game-s, at R that is 45 real min; night = 900 game-s = 15 real min; full day = 3600 game-s = 60 real min
production : 1x vanilla per real minute (= R; a vanilla day of work, 1800 game-s, takes 30 real min); 2x vanilla per game day (= L / 1800; one game day holds 2 vanilla days of growth); realised ProductionScale 1 (requested 1)
sun : 4 degrees per real minute by day (180 / daytime; vanilla 8.57), 12 by night (180 / night; vanilla 20); the sun's pace depends on the lengths only, never on ProductionScale
[Message:DvergrAstrolabe] DvergrAstrolabe initialized.
[Info :DvergrAstrolabe] EnvMan.m_dayLengthSec 1800 -> 3600 game-seconds.
[Info :DvergrAstrolabe] self-check: EnvMan.RescaleDayFraction answers with sunrise at raw 0.125 and sunset at 0.875, as set (1000 samples); EnvMan.m_dayLengthSec = 3600.
[Message:DvergrAstrolabe] clock live on the dedicated server: day 0, raw day-fraction 0.567 (daylight), EnvMan day length 3600 game-s, clock at 1x, 0 player(s).
With VerboseLogging on, every sunrise and sunset is measured against its schedule, so the log proves the lengths
by itself:
[Info :DvergrAstrolabe] sunset, day 12 (dedicated server): daylight ran 45.00 real min (45 scheduled); night for the next 15 real min.
[Info :DvergrAstrolabe] sleep: skipping from 46500 to the sunrise of day 13 at 47250 game-s (750 game-s in 12 real s).
[Info :DvergrAstrolabe] sunrise, day 13 (dedicated server): night ran 2.70 real min (15 scheduled); daylight for the next 45 real min.
In game, astrolabe in the F5 console (and on the server console) prints the same working for the machine you
are on plus its live clock, so a player can check what the server runs them on:
Dvergr Astrolabe 0.4.0 on this client:
settings : CycleMinutes = 60, ...
...
live : world clock 44811 game-s, day 12, raw day-fraction 0.448 (daylight), visual 0.465, EnvMan day length 3600 game-s, clock running; settings from the server (locked)
A Valheim mod by Wubarrk.
CHANGELOG
Changelog
0.4.0
A new line of the mod: it now runs on the server and on every client, and owns the whole day/night cycle instead of pacing the server's clock around a vanilla one. Settings carry over from 0.3 (see Upgrading from 0.3 in the README); clients that do not have the mod can no longer join.
Added
- Three lengths in real minutes.
[2 - Cycle]CycleMinutes(the full day, vanilla 30),DaytimeMinutes(sunrise to sunset, vanilla 21) andNightMinutes(sunset to sunrise, vanilla 9), withLengthRuledeciding which one gives way when they do not add up (FitToCyclekeeps the cycle exact and scales the other two, the default;DaytimePlusNight,CycleMinusNight,CycleMinusDaytime). - Production as its own dial.
[3 - Production]ProductionScale(1 = vanilla, 2 = twice as fast, 0.01 to 100) runs everything on the game clock - crops, smelters, fermenters, beehives, fuel, respawns, spawners, taming, regeneration, weather - at that multiple, without touching the sun.ProductionBasissays what 1 means:RealTime(vanilla per real minute whatever the cycle length) orGameDays(vanilla per game day, the 0.3 economy). - The full mathematics, in the log and in the README. The solver derives the game-day length
L, the exact clock rateRand the sunrise/sunset knees from the settings in six steps, and prints each step with your numbers in at startup, after every settings change, and on every client as the values arrive. The README has the formulas, their consequences and worked examples; theastrolabeconsole command prints the working plus the live clock of the machine you are on. - Server-synced, version-locked. ServerSync (compiled in) pushes the settings to every client and
[1 - General]LockConfiguration(default on) makes the server's values the only ones that count. Both sides must run the same version; a vanilla client is refused at the door. [4 - Clock]WaveSpeed(Vanilla, default: the water runs on real time whatever the clock rate, so waves look and hit as in vanilla;FollowClockas an unmodded game) andSleepSkipPushInterval(how many steps clients see the 12-second sleep skip in).[5 - Compatibility]PatchSelfCheck(samples the game's own sunrise/sunset function after applying and reports another mod's knees if they won; re-asserts the day length every 5 s with a warning naming the other mod) andSelfCheckSteps.- Every cfg comment explains its setting in plain words and gives worked examples ("60 = each day takes one real hour"), with the formula underneath for those who want it.
- Automatic migration of a 0.3 (or earlier) cfg:
DayMinutes+NightMinutesbecome the three lengths withProductionBasis = GameDays, keeping the 1800-second day, the per-day economy and the day counter of the existing world.
Changed
- The day/night cycle is set on every machine (
EnvMan.m_dayLengthSec,RescaleDayFraction,GetMorningStartSec,SkipToMorning) and the clock runs at one flat rateReverywhere (ZNet.UpdateNetTimeon the server and on every client). Daylight and night no longer run at two different rates: the band moves instead. A sunrise/sunset patch from another mod on the same method loses to Astrolabe's (it runs last). - Changing the day length on a running world shifts the day counter and the time of day once (the clock itself is never re-based, so every timestamp in the world stays valid); the log prints the before and after.
- A sleep taken in the pre-dawn with a late sunrise no longer risks skipping an extra day, and with an early one no
longer risks rewinding the clock:
SkipToMorninguses the configured sunrise instead of vanilla's 0.15.
Removed
[4 - Boats](PauseFor,PauseRadius,MooredRadius,UnderWaySpeed,CheckInterval),HoldSchedule,CatchUpLimit,ClockPushInterval,BandDetection,BandProbeSteps. With every machine on the same clock a push carries nothing, so there is nothing to pause for, nothing to catch up, and no other mod's band to follow. The 0.3 limits go with them: no schedule slip while someone sails, no 0.2x floor, no fast-night production.
0.3.0
Fixed
- Sunrise and sunset were hardcoded at vanilla's raw day-fractions 0.15 and 0.85. With a mod that moves them
(Gamma of Night Lights' day/night cycle sets the night as a percentage of the day) Astrolabe paced the wrong
stretch: at Gamma's
3600 / 75the real daylight band is 900 game-seconds, but Astrolabe fitted 1260 intoDayMinutes, so every rate was off by 1260/900 and the segment it treated as the long one was the short one. Found on ProximaMaxi.
Added
- The daylight band is read from the running game. Astrolabe samples
EnvMan.RescaleDayFraction(the patched version, whoever patched it) to find where the game's day begins and ends, and paces that band; the day length was already read live. Re-read every 5 seconds, at every sunrise and sunset and after a config edit, so a synced change on the other mod is picked up within seconds. Gamma sets the size and the split of the day, Astrolabe sets how long it takes in real minutes, and when both segments land on the same multiplier there is no fast-day, slow-night contrast at all: Gamma3600 / 75+ Astrolabe15 / 45runs a flat 1x with a 45-minute night,7200 / 75+15 / 45a flat 2x. See Pairing with Gamma of Night Lights in the README. Detection that fails falls back to the vanilla knees and logs an error; an unmodded game detects exactly 0.15 / 0.85 and behaves as 0.2.1 did. [5 - Compatibility]:BandDetection=Auto(default) orVanilla(force the vanilla knees, the escape hatch), andBandProbeSteps(1000) for how finely the band is sampled.- Logging. The schedule line reports the daylight band (
daylight band 900 of 3600 game-s (25%, sunrise and sunset moved by another mod)), aday cycleline is printed when the world loads and whenever the band or the day length changes, andVerboseLoggingadds the two detected fractions. A warning names the setting and the number whenever a schedule implies a nominal rate at or under 0.2x (progress drift on client-owned fires, beehives and sap collectors) or fast enough that one clock push moves the sun more than a degree (about 11x at the default 0.5 s push interval). When another mod has moved the band, one note reminds you that it must be on the clients too.
0.2.1
Fixed
- Rebuilt against Valheim 1.0.16 and re-verified (static reference check on client and dedicated server, headless 1.0.16 dedicated-server boot).
0.2.0
Fixed
- Boats took water-impact damage under sail while the schedule was active (60-150 hull damage a minute on
a Karve at a 40-minute day, with constant bobbing). Every clock push moved an unmodded client's physics
water surface in a single step, and vanilla's
Ship.UpdateWaterForcecounts a jump like that as a slam: 10 blunt per hit, up to thirty hits a minute, whenever someone is aboard. The sun and the rendered water are smoothed; the surface boats float on is not, whatever the push interval. Found on the live server through Wonderland's boat-upkeep log.
Added
[4 - Boats]. The whole server's clock runs at vanilla speed while any player is withinPauseRadius(64 m) of a boat under way orMooredRadius(24 m) of one at rest, where pushes change nothing; the switch is seamless.PauseFor=Ships(default),Water(also anyone over water) orOff;UnderWaySpeedandCheckIntervaltune the detection. A boat docked beside a base only pauses it for someone on or beside the deck. The README's Boats section explains exactly how time behaves around boats.HoldSchedule(default on) andCatchUpLimit(default 4) in[2 - Day And Night]. Every sunrise and sunset is now held to its scheduled time: after a pause near boats, a server hitch or a mid-day config edit, the rest of the segment runs faster or slower (within the limit) to land the boundary on time. A 40-minute day absorbs about 18 minutes of boating, a 5-minute night about 4. Off = fixed rates, as 0.1.0 behaved.- Self-verifying sunrise and sunset lines. With
VerboseLoggingon, each line now reports how long the segment that just ended really ran, what was scheduled, and how much of it was spent at vanilla speed near boats; every pause and resume is logged with who and which boat. - Boat guard self-test at startup ("boat guard ready: sector query OK ..."). If the lookup ever throws, the mod logs an error and keeps the clock at vanilla speed until restart rather than risk hulls.
0.1.0
Added
- Day and night length in real minutes.
DayMinutes(sunrise to sunset, vanilla 21) andNightMinutes(sunset to sunrise, vanilla 9) in[2 - Day And Night]. The server paces its authoritative world clock (ZNet.UpdateNetTime) at a different rate inside and outside the daylight band, so every connected client sees the new lengths with nothing installed. The clock itself, the day counter, sleeping and the world save are untouched: a day is still 1800 game-seconds, it just takes as long as you say in wall time. - Smoother sun at rates far from 1x.
ClockPushIntervalin[3 - Client Sync](default0.5s) pushes the clock to clients more often than vanilla's 2 s, shrinking the correction each push applies. Set2to add no extra traffic. - Live config reload. Edit the cfg on a running server; the new schedule is picked up within 5 seconds and logged.