Files
last-hearth/mods/hearth/clock.lua
T
2026-11-03 12:41:09 -05:00

64 lines
3.5 KiB
Lua
Executable File

-- Loaded after content/interface; schema and the persistence instance come from init.
local C, M, P = core, hearth.model, hearth.persistence
local singleplayer = C.is_singleplayer()
local deployment = C.settings:get("hearth_environment")
if deployment == nil then deployment = singleplayer and "local" or "production" end
if deployment ~= "local" and deployment ~= "staging" and deployment ~= "production" then
error("Last Hearth: hearth_environment must be local, staging, or production.", 0)
end
if not singleplayer and deployment == "local" then
error("Last Hearth: dedicated servers cannot use the local environment.", 0)
end
local date_setting = C.settings:get("hearth_preview_date")
local weather_setting = C.settings:get("hearth_preview_weather") or "auto"
local function nonempty(value) return value ~= nil and value ~= "" end
if deployment == "production" and (nonempty(date_setting) or weather_setting ~= "auto"
or C.settings:get("hearth_launcher_mode") ~= nil or C.settings:get("hearth_smoke_token") ~= nil
or C.settings:get("hearth_m1_course") ~= nil or C.settings:get("hearth_m1_course_nonce") ~= nil
or C.settings:get("hearth_m1_course_snag") ~= nil or C.settings:get("hearth_course_token") ~= nil) then
error("Last Hearth: production rejects fixture and launcher test settings.", 0)
end
local preview_date
if nonempty(date_setting) then
preview_date = tonumber(date_setting)
if not preview_date or preview_date ~= preview_date or preview_date < 946684800
or preview_date > 4102444800 or preview_date % 1 ~= 0 then
error("Last Hearth: hearth_preview_date must be an integer UTC timestamp from 2000 through 2100.", 0)
end
end
if weather_setting ~= "auto" and weather_setting ~= "clear" and weather_setting ~= "rain" then
error("Last Hearth: hearth_preview_weather must be auto, clear, or rain.", 0)
end
local configured = M.location(C.settings:get("hearth_latitude"), C.settings:get("hearth_longitude"))
if (deployment == "production" or not singleplayer) and not configured then
error("Last Hearth: server/production requires explicit valid hearth_latitude and hearth_longitude settings.", 0)
end
-- Always validate stored data, even when settings take precedence. Corrupt saves
-- must fail startup, not disappear behind a configured location or neutral preview.
local stored = P.load_world("location")
local selected = configured or (singleplayer and stored)
hearth.has_location = selected ~= nil and selected ~= false
-- The existing location form and HUD disclose this unchosen neutral preview.
local location = selected or {latitude = 0, longitude = 0}
function hearth.climate_at(timestamp)
if type(timestamp) ~= "number" or timestamp ~= timestamp or timestamp < 0 then return nil end
return M.solar(math.floor(timestamp), location.latitude, location.longitude)
end
function hearth.set_location(lat, lon)
assert(singleplayer, "Only local worlds can select location in game")
local value = assert(M.location(lat, lon), "Invalid reference coordinates")
-- Publish only after a successful save; never silently replace a failed record.
P.save_world("location", value)
location, hearth.has_location = value, true
end
function hearth.clock_update()
local now = preview_date or os.time()
hearth.clock = M.solar(now, location.latitude, location.longitude)
hearth.weather = M.weather(now, location.latitude, location.longitude)
if weather_setting ~= "auto" then hearth.weather = weather_setting end
C.set_timeofday(hearth.clock.timeofday)
end
C.after(0, hearth.clock_update)