From a4f12f84fdcbf884c494a83e199161cfac52fddb Mon Sep 17 00:00:00 2001 From: Madison Date: Sun, 4 Oct 2026 23:38:22 +0900 Subject: [PATCH] Frame: use Half-Life from Steam where it is, read only The Android container on the Frame shows the headset's Steam folders at the same paths, read only. At start the app looks for steamapps/common/Half-Life (valve/liblist.gam) in the Steam library and in the other libraries libraryfolders.vdf lists, and gives the engine that folder as XASH3D_RODIR. The engine searches it after the writable folder, so the saves, the settings and the files this app puts in /sdcard/Documents/Lambda1VR (the replacement models and sprites) win over Steam's. Nothing is written into the Steam folder. If there's no Half-Life there, a copy in Documents is used as before, and a [data] line in the log says which one it was. Builds. Haven't tried it on the headset yet. --- docs/STEAM_FRAME_VR.md | 22 ++++--- .../drbeef/lambda1vr/GLES3JNIActivity.java | 63 +++++++++++++++++++ 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/docs/STEAM_FRAME_VR.md b/docs/STEAM_FRAME_VR.md index 82f373c..268e67b 100644 --- a/docs/STEAM_FRAME_VR.md +++ b/docs/STEAM_FRAME_VR.md @@ -43,14 +43,22 @@ that for logs. Start it from the Steam library to actually play. ## Game data -Copy the `valve` folder from your Steam copy of Half-Life to -`~/Documents/Lambda1VR/valve` on the headset. Inside Lepton that's -`/sdcard/Documents/Lambda1VR/valve`. Documents is the headset's own folder, so -it's still there after a Lepton reset. On the Quest it's `/sdcard/xash`, that -hasn't changed. +Install Half-Life from Steam on the Frame, and that's it. The Android container shows the headset's +Steam folders (read only), so the game uses the files where Steam put them, there's nothing to copy. At +start the app looks for `steamapps/common/Half-Life/valve/liblist.gam` in the Steam library (and in the +other libraries `libraryfolders.vdf` lists, like one on an SD card) and tells the engine to treat that folder +as read only (`-rodir`). The expansions (Opposing Force, Blue Shift) are in the same folder on Steam. -The app makes the folder on first start and puts its own files in it (config, -the weapon models and so on), like it does on the Quest. +`~/Documents/Lambda1VR` is the writable side, and it wins when the same file is in both. Inside Lepton it's +`/sdcard/Documents/Lambda1VR`, the headset's own folder, so it survives a Lepton reset. It holds your saves and +settings, and the files this app puts there on first start (the replacement weapon models, the sprites, the +loading screens), like it does on the Quest. The engine also makes empty folders there with the names of the +game folders in Steam's. On the Quest it's `/sdcard/xash`, that hasn't changed. + +If there's no Half-Life in Steam on the headset, it falls back to the old way: copy the `valve` folder from a +PC's Steam copy to `~/Documents/Lambda1VR/valve`. A copy there is used too when Steam has one as well (it's +found first, so a stale copy would be used over the Steam files). The log says which one it picked, with a +`[data]` line. ## Controls diff --git a/java/com/drbeef/lambda1vr/GLES3JNIActivity.java b/java/com/drbeef/lambda1vr/GLES3JNIActivity.java index cc136cf..c088815 100644 --- a/java/com/drbeef/lambda1vr/GLES3JNIActivity.java +++ b/java/com/drbeef/lambda1vr/GLES3JNIActivity.java @@ -151,6 +151,53 @@ import static android.system.Os.setenv; System.exit(0); } + /** + * The Frame's Android container shows the headset's Steam folders at the same paths, read only. If + * Half-Life is installed there, the game's files can be used from where they are instead of a copy. + * Looks in the Steam library folders (the main one, and the others libraryfolders.vdf lists, such as + * one on an SD card) for steamapps/common/Half-Life/valve/liblist.gam. Returns the Half-Life folder or null. + */ + private String findSteamHalfLife() + { + final String steam = "/home/steamos/.local/share/Steam"; + java.util.ArrayList libraries = new java.util.ArrayList(); + libraries.add(steam); + + try + { + BufferedReader br = new BufferedReader(new FileReader(steam + "/steamapps/libraryfolders.vdf")); + String line; + while ((line = br.readLine()) != null) + { + // "path" "/some/library" + line = line.trim(); + if (line.startsWith("\"path\"")) + { + String[] parts = line.split("\""); + if (parts.length >= 4 && !libraries.contains(parts[3])) + { + libraries.add(parts[3]); + } + } + } + br.close(); + } catch (IOException e) + { + Log.i(TAG, "[data] no libraryfolders.vdf: " + e.getMessage()); + } + + for (String library : libraries) + { + File liblist = new File(library + "/steamapps/common/Half-Life/valve/liblist.gam"); + if (liblist.canRead()) + { + return library + "/steamapps/common/Half-Life"; + } + Log.i(TAG, "[data] no Half-Life in the Steam library " + library); + } + return null; + } + public void create() { copy_asset(getFilesDir().getPath(), "extras.pak", false); @@ -509,6 +556,22 @@ import static android.system.Os.setenv; try { ApplicationInfo info = getApplicationInfo(); setenv("XASH3D_BASEDIR", DATA_DIR, true); + + if (BuildConfig.STEAM_FRAME) + { + // Half-Life from Steam, read only, in place. The folder above is searched after it, so what's + // in there (the saves, the settings, this app's own models and sprites) wins over Steam's files. + String steamHalfLife = findSteamHalfLife(); + if (steamHalfLife != null) + { + setenv("XASH3D_RODIR", steamHalfLife, true); + Log.i(TAG, "[data] game files: Steam, in place, read only (" + steamHalfLife + "); saves and settings in " + DATA_DIR); + } + else + { + Log.i(TAG, "[data] game files: no Steam install of Half-Life found, using the copy in " + DATA_DIR); + } + } setenv("XASH3D_GAMELIBDIR", info.nativeLibraryDir, true); setenv("XASH3D_GAMEDIR", "valve", true); setenv( "XASH3D_EXTRAS_PAK1", getFilesDir().getPath() + "/extras.pak", true );