ludic/packages/ludic.update/latest.ludic
Orkuncakilkaya 3ac1179440 fix(allocs): ludic.update, steps, effects and telemetry at 0 frame allocs and 0 keeps
ludic.update: whether this copy can update itself is worked out once, when the updater is configured
(the panel asked every frame, building the path to the executable each time); the notes are a list
the state keeps, filled by update_notes_for when the version or the language changes, which the
game calls from its update tick. The feed's address is declared (once, when a check starts).
ludic.steps, ludic.effects, ludic.telemetry: what is left is made on an event and declared with its
bound - an arc's tables, a chapter's columns, a step's fact, an effect's start, end and clear, the
fact pool's growth, the player id, a props record's nesting stack - and two pushes into a caller's
kept list, at most a chapter's steps and the ring's size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:13:06 +03:00

77 lines
3.9 KiB
Text

# latest.ludic - "a new version is out": latest.json asked once, polled a frame at a time, so a
# slow or absent network costs the frame nothing - it simply never says there is one.
# latest.json is {"version": "0.5.1", "notes": {"en": ["...", ...], "tr": [...]}}
# once a frame on the screen that shows it; with show_current, the notes of the version being
# played are kept too (a launcher shows them)
export function update_check_tick(update_st: mut UpdateState, show_current: bool) -> void {
if update_st.update__ask == UPDATE_ASK_IDLE {
@alloc_ok("the feed's address: once, when the check starts")
update_st.update__ask_h = UpdateNet.get(update__conf(update_st).feed + "/" + update__conf(update_st).latest)
update_st.update__ask = UPDATE_ASKING
if update_st.update__ask_h < 0 { update_st.update__ask = UPDATE_NONE }
return
}
if update_st.update__ask != UPDATE_ASKING { return }
let st = UpdateNet.poll(update_st.update__ask_h)
if st < 0 { return }
update_st.update__ask = UPDATE_NONE
if st > 0 { update__latest_read(update_st, Json.parse(UpdateNet.text(update_st.update__ask_h)), show_current) }
UpdateNet.free(update_st.update__ask_h)
update_st.update__ask_h = -1
}
function update__latest_read(update_st: mut UpdateState, v: Val, show_current: bool) -> void {
if v == null or Value.kind(v) != 6 or Value.has(v, "version") == 0 { return }
let ver = Value.as_str(Value.get(v, "version"))
let mine = update__conf(update_st).version
if update_newer(ver, mine) { update_st.update__ask = UPDATE_NEWER }
else if ver == mine and show_current { update_st.update__ask = UPDATE_CURRENT }
else { return }
update_st.update__latest = ver
if Value.has(v, "notes") != 0 { update_st.update__notes = Value.get(v, "notes") }
}
export function update_ask_state(update_st: UpdateState) -> int { return update_st.update__ask }
export function update_latest(update_st: UpdateState) -> string { return update_st.update__latest }
export function update_shown(update_st: UpdateState) -> bool { return update_st.update__ask == UPDATE_NEWER or update_st.update__ask == UPDATE_CURRENT }
export function update_fresh(update_st: UpdateState) -> bool { return update_st.update__ask == UPDATE_NEWER }
# the notes in the language the game asked for (update_notes_for), else English, else none
export function update_notes(update_st: UpdateState, lang: string) -> []string { return update_st.update__notes_list }
# the notes kept for this language: filled when the version or the language changes, so the panel
# reading them every frame makes nothing
export function update_notes_for(update_st: mut UpdateState, lang: string) -> void {
if (update_st.update__notes_lang == lang) and (update_st.update__notes_of == update_st.update__latest) { return }
update_st.update__notes_lang = lang
update_st.update__notes_of = update_st.update__latest
let out = update_st.update__notes_list
List.clear(out)
if update_st.update__notes == null or Value.kind(update_st.update__notes) != 6 { return }
var key = lang
if Value.has(update_st.update__notes, key) == 0 { key = "en" }
if Value.has(update_st.update__notes, key) == 0 { return }
let l = Value.get(update_st.update__notes, key)
for i in 0 .. Value.count(l) { push(update_st.update__notes_list, Value.as_str(Value.at(l, i))) }
}
# back to before anything was asked or installed (tests)
export function update_reset(update_st: mut UpdateState) -> void {
if update_st.update__ask_h >= 0 { UpdateNet.free(update_st.update__ask_h) }
update_st.update__ask_h = -1
update_st.update__ask = UPDATE_ASK_IDLE
update_st.update__latest = ""
update_st.update__notes = null
update__release(update_st)
update_st.update__state = UPDATE_IDLE
update_st.update__err = UPDATE_ERR_NONE
update_st.update__target = ""
update_st.update__files = null
update_st.update__total_bytes = 0
update_st.update__done_bytes = 0
update_st.update__i = 0
update_st.update__rate = 0
update_st.update__rate_t = -1
q_clear(update_facts(update_st))
}