* fix(gog): install scripts' support files reach the prefix
A goggame-<id>.script can copy files into the prefix with supportData
actions: default INI files, Plugins.txt and other settings that mods such
as one-click editions need. Only setRegistry actions were applied, so
those games started without their configuration and ran as the base game.
droiddeck-store-launch now applies supportData after the registry, once
per script revision: copies from {app} and {supportDir} into {userdocs}
and {localappdata}, matching paths without regard to case. Links are
copied as links, paths outside those folders are refused, and existing
files are replaced only when the action asks for it.
* Keep GOG support data copies inside the game and prefix folders
* Copy linked GOG support sources as links and keep a player's own links
Blood Omen ships dxconfig.exe beside kain.exe and the shortcut pointed at
the config tool: pickExe kept the first .exe the folder listing returned
when no title match was found. Read the game's play task from GOG's own
goggame-<id>.info manifest first - a primary game task, or a primary
launcher task for launcher games, and the product's manifest ahead of any
other goggame-*.info - then the product's temp_executable; without either,
rank the folder's exes so a word of the title wins, config and tool names
lose, and depth then size break the remaining ties.
GOG's galaxy_*.exe support installer is not the game either. The Witcher:
Enhanced Edition ships galaxy_the_witcher_enhanced_edition_2.1.0.15.exe
beside launcher.exe, and its build metadata names that file as the
product's temp executable, so launching it starts a 32-bit installer that
stops at "Path not found" under ARM64 FEX - the same dialog as the setup
stub #1174 removed. Play tasks, the hint and the name search skip it.
Fixes#680Fixes#694
Only a primary launcher task counts as a launch task: GOG files the
configuration tool beside a game as a non-primary launcher, so it now falls
through to the executable search instead of becoming the game.
The temp_executable hint is matched by basename with either separator and
must resolve inside the install folder, so a nested galaxy_*.exe is skipped
too and a hint cannot point outside the game.
GOG runs a task from the working directory it declares, and from the install
root when it declares none. That directory now reaches the sidecar and the
shortcut's Start In: a game in a subfolder (System/witcher.exe) starts where
GOG starts it instead of in System/, where it cannot find its Data folder.
* feat: choose default storage for new store installs
Store installs and the Epic Games Launcher can use internal storage, external storage, a folder picked through Choose folder..., or ask every time. The choice is stored in SessionPrefs and used by StoreInstallRoot; Storage > Default storage exposes it.
* fix: allow choosing any folder for default storage
The default storage choice can now hold an arbitrary folder path, not just internal or app-specific external storage. StoreInstallRoot resolves and validates picked folders, keeps a disconnected choice instead of silently falling back, and the folder picker stays available from Storage.
* fix: keep the Epic install folder when external storage is away
* test: use a unique missing folder for the Epic storage check
* fix: detect USB SSDs that the storage manager hides
List storage volumes that have no UUID instead of dropping them, keep volumes that are present but not yet mounted, and fall back to parsing /proc/mounts so USB OTG drives appear even when Android does not expose them as storage volumes or app directories. Prefer the system's volume description for removable drives. (Raw removable drives as move targets, the folder-picker fallback, and the unreadable-drive guidance follow with the move stack.)
* fix: compare mount paths as strings in StorageRootsTest
* fix: never drop a present storage volume from the drive list
Key volumes by description or index when they report no UUID and no directory, keep nofs/unmountable states so a plugged-in drive stays visible with guidance, only attach app directories on strict UUID matches, and accept any fstype under vold-managed locations plus usb-ish mounts directly under /mnt.
* fix: probe folder writes with a fresh temp file and keep Epic's folder unset while external storage is away
---------
Co-authored-by: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com>
* fix: find GOG Galaxy SDK cloud saves when remote-config lists no locations
cloudStorage.enabled with an empty locations list is Galaxy SDK IStorage
under __default. DroidDeck treated that as no cloud.
Use the SDK folder, strip/prefix the __default namespace, and inflate gzip
bodies GOG stores on download. An empty cached template is fetched again
so devices that already recorded "no cloud" recover.
* fix: keep an empty GOG namespace, expire cached none, close gzip
An explicit empty cloud_namespace is Auto Cloud and must not become
__default just because the path template looks like Galaxy storage.
A cached none is retried after a day so a later enablement is picked up.
GZIPInputStream is closed after a compressed download.
* fix: peel GOG cloud gzip only when the service or PUT compressor says so
GET asks for identity encoding so the body is what GOG stored. A
Content-Encoding of gzip is inflated once. Otherwise a gzip body is
inflated only when it round-trips as GOG's PUT gzip (deflate 6, mtime 0),
so a gzip-format save is not rewritten.
* Reject corrupt GOG cloud downloads
---------
Co-authored-by: xXJsonDeruloXx <danielhimebauch@gmail.com>
Co-authored-by: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com>
GOG lists every cloud object as <location name>/<path>. The location name
is not part of the local folder, so Silksong's saves/user1.dat belongs at
default/user1.dat, not default/saves/user1.dat. Strip the segment for local
paths and add it back for HEAD/GET/PUT, cache the location name, and migrate
files written by the old layout without touching files the game wrote.
Co-authored-by: xXJsonDeruloXx <danielhimebauch@gmail.com>
Co-authored-by: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com>
Both store modules are rewritten from a protocol-level spec: new Rust engines behind a small JNI surface (nativeCall/nativeInstall) and thin Kotlin facades, with the launcher's own user agent.
Epic: sign-in carries over, library, manifest download with byte-exact verification, assembly, uninstall, launch arguments, achievements.
Amazon: sign-in carries over, library, manifest download with per-file hash checks, path checks, executable detection from fuel.json, uninstall.
On-disk install layout is unchanged, so existing installs keep working.
Store game pages now take controller focus on their lead hero action (Install, Uninstall, Pause, Resume, Get, Buy), fall back to Back, and keep D-pad focus inside the page while it covers the library.
Space checks before Epic, GOG and Amazon installs (measured zero vs unknown), clear failure reasons with retry/clear, resume-aware checks, and safe per-file replacement so a failed or cancelled update never breaks an installed game.
Epic installs stream chunks straight into staged files in parallel (most bytes written once, a small budgeted cache for shared chunks, about 1x game size instead of 2x), pace updates by free space, and keep the lookahead, batch and bounded Java writers as hidden alternatives.
Co-authored-by: Juan Marti Mercado <juanma@microsoft.com>
Co-authored-by: The412Banner <the412banner@users.noreply.github.com>
The stores' sign-ins (files/stores/<store>/credentials.json: access and refresh
tokens, account id and name) were plain JSON. Other apps could not read them, but
every program in the Linux session runs as the app and could. They are now sealed
with AES-256-GCM under a non-exportable AndroidKeyStore key (StrongBox when the
device has one), so the session only ever sees ciphertext.
- Format: a versioned envelope {v, alg, iv, ct}, written atomically and readable
only by the app. No new dependencies (javax.crypto and KeyStore).
- Migration: an existing plaintext file is sealed at the next start, checked by
decrypting it, then the plaintext is removed; users stay signed in.
- No Keystore on the device: the file stays plain and the log says so once per
start.
- A sealed file that can never be opened (tampered, key gone or invalidated,
broken envelope) is removed and that store asks for sign-in again. A transient
Keystore error keeps the file and retries.
A Stores section (rail, under Games; Setup › Stores gate) with each store's sign-in,
library, storefront shelves and a download queue. Each store has two tabs, Store and
Library, and Library filters to All or Installed; libraries open from a saved copy
and refresh in the background, with install sizes on every card. Games install to internal storage,
or a card chosen at Install time, and are registered in the Steam client as non-Steam
games, so they launch through Steam and droiddeck-proton from either the front end or
the client.
- Downloads: GOG, Epic and Amazon engines in Rust (app/src/main/rust/stores, built by
cargo-ndk, nothing compiled in the tree). One adaptive fetch core with a latency
brake, stalled-host handoff and every CDN a store offers. Per-stage progress,
pause/resume, two-step cancel that deletes, failed downloads kept for retry, a
foreground service with Wi-Fi and wake locks and notification controls.
- Games tab: store source chips (Steam, GOG, Epic, Amazon, Custom) and store art.
- Epic: per-launch exchange code from the app and from Steam's Play button,
"Epic sign-in (EOS)", "Launch offline", and a game's web links opened in Android's
browser for EOS consent. The EOS overlay crashed games and is left out.
- Cloud saves (GOG, Epic): pulled before launch, pushed after the game or the session
ends, no upload before a first download, conflicts never overwritten, backups both
ways.
- Logs: every store line redacted; the engine log goes to daily files.