ludic/packages/ludic.update/install.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

101 lines
3.9 KiB
Text

# install.ludic - where Velopack put this copy: its root, its packages, its updater, and whether
# it is an install at all. Windows: <root>\Update.exe, <root>\current\<game>.exe, <root>\packages.
# macOS: the .app IS the install and UpdateMac sits beside the binary in Contents/MacOS.
# "0.10.2" beats "0.9.9": compared a number at a time, not as text
export function update_newer(a: string, b: string) -> bool {
let pa = Text.split(a, ".")
let pb = Text.split(b, ".")
for i in 0 .. 3 {
var x = 0
var y = 0
if i < len(pa) { x = Text.to_int(pa[i]) }
if i < len(pb) { y = Text.to_int(pb[i]) }
if x != y { return x > y }
}
return false
}
# Velopack runs the game with --veloapp-install / -updated / -obsolete / -uninstall and kills it if
# it is still running 15-30 s later: a game that sees one exits at once
export function update_is_install_hook() -> bool {
let a = Os.args()
for i in 1 .. len(a) {
let s = a[i]
if len(s) >= 10 { if s[0..10] == "--veloapp-" { return true } }
}
return false
}
function update__mac() -> bool { return UpdateWorld.platform() == "macos" }
function update__sep() -> string {
if UpdateWorld.platform() == "windows" { return "\\" }
return "/"
}
# the directory above p, with no ".." left in it (UpdateMac is handed it as its root)
function update__up(p: string) -> string {
var cut = -1
for i in 0 .. len(p) { if p[i..i + 1] == "/" or p[i..i + 1] == "\\" { cut = i } }
if cut < 0 { return "." }
return p[0..cut]
}
# the executable's directory
export function update_dir() -> string { return update__up(UpdateWorld.exe()) }
export function update_root(update_st: UpdateState) -> string {
let c = update__conf(update_st)
if len(c.root) > 0 { return c.root }
if update__mac() { return update__up(update__up(update_dir())) }
return update_dir() + "\\.."
}
# where the packages live: never inside a macOS bundle, which is read-only and which apply replaces
export function update_packages(update_st: UpdateState) -> string {
let c = update__conf(update_st)
if len(c.packages) > 0 { return c.packages }
if update__mac() and len(c.mac_packages) > 0 { return c.mac_packages }
return update_root(update_st) + update__sep() + "packages"
}
function update__feed_file() -> string {
if update__mac() { return "releases.osx.json" }
return "releases.win.json"
}
function update__updater(update_st: UpdateState) -> string {
if update__mac() { return update_root(update_st) + "/Contents/MacOS/UpdateMac" }
return update_root(update_st) + update__sep() + "Update.exe"
}
# A quarantined Mac app still where it was downloaded runs from a read-only /AppTranslocation/
# image that vanishes when it exits: nothing there can be updated in place
export function update_translocated() -> bool {
return update__mac() and Text.contains(UpdateWorld.exe(), "/AppTranslocation/")
}
# can this copy update itself? A copy Velopack did not install downloads the game again instead.
export function update_installed(update_st: UpdateState) -> bool { return update_st.update__installed }
@alloc_ok("once, when the updater is configured")
function update__installed_now(update_st: UpdateState) -> bool {
if len(update__conf(update_st).root) > 0 { return true }
if update_translocated() { return false }
if update__mac() { return Fs.exists(update_dir() + "/UpdateMac") }
return Fs.exists(update_dir() + "/../Update.exe")
}
# a page in the player's browser (the site, the changelog)
export function update_open(url: string) -> void {
if update__mac() { System.run(`open "{url}"`) } else { System.run(`cmd /c start "" "{url}"`) }
}
# a path inside a PowerShell single-quoted string: a quote is written twice
function update__psq(p: string) -> string { return "'" + Text.replace(p, "'", "''") + "'" }
function update__powershell() -> string {
var root = "C:\\Windows"
if Os.has_env("SystemRoot") and len(Os.env("SystemRoot")) > 0 { root = Os.env("SystemRoot") }
return root + "\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
}