summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Dubé <159546+serprex@users.noreply.github.com>2026-09-28 00:46:39 +0000
committerGitHub <noreply@github.com>2026-09-28 00:46:39 +0000
commitb939163c3d45e4048ca98186aa244cf8ecd3bdac (patch)
tree34d87a2addd4994cae8c70f15e9eb7e9ca619cfa
parentca1e4c22505a7c2101ca816c31023daaf4e2638e (diff)
publish appimage unzipped, store to ~/.local/share/soh when SHIP_HOME unset (#7252)
-rw-r--r--.github/workflows/generate-builds.yml5
-rw-r--r--README.md17
-rw-r--r--soh/soh/Extractor/Extract.cpp6
-rw-r--r--soh/soh/OTRGlobals.cpp38
4 files changed, 44 insertions, 22 deletions
diff --git a/.github/workflows/generate-builds.yml b/.github/workflows/generate-builds.yml
index 40c63424b..2148ce3f5 100644
--- a/.github/workflows/generate-builds.yml
+++ b/.github/workflows/generate-builds.yml
@@ -165,7 +165,6 @@ jobs:
cmake --build build-cmake --config Release -j4
(cd build-cmake && cpack -G External)
- mv README.md readme.txt
mv build-cmake/*.appimage soh.appimage
env:
CC: gcc-12
@@ -174,9 +173,7 @@ jobs:
uses: actions/upload-artifact@v7
with:
name: soh-linux
- path: |
- soh.appimage
- readme.txt
+ path: soh.appimage
- name: Save Cache deps folder
if: ${{ github.ref_name == github.event.repository.default_branch }}
uses: actions/cache/save@v5
diff --git a/README.md b/README.md
index 4dd7f0315..70a4fafb0 100644
--- a/README.md
+++ b/README.md
@@ -21,27 +21,14 @@ You can verify you have dumped a supported copy of the game by using the compati
* Launch `soh.exe`
#### Linux
-* Place your supported copy of the game in the same folder as the appimage.
* Execute `soh.appimage`. You may have to `chmod +x` the appimage via terminal.
+* When prompted, select your supported copy of the game.
+* Saves, settings and `oot.o2r` are stored in `~/.local/share/soh/`. If the folder you launch from already has `shipofharkinian.json`, `oot.o2r` or `oot-mq.o2r`, that folder is used instead. Set `SHIP_HOME` to choose another folder.
#### macOS
* Run `soh.app`. When prompted, select your supported copy of the game.
* You should see a notification saying `Processing OTR`, then, once the process is complete, you should get a notification saying `OTR Successfully Generated`, then the game should start.
-#### Nintendo Switch
-* Run one of the PC releases to generate an `oot.o2r` and/or `oot-mq.o2r` file. After launching the game on PC, you will be able to find these files in the same directory as `soh.exe` or `soh.appimage`. On macOS, these files can be found in `/Users/<username>/Library/Application Support/com.shipofharkinian.soh/`
-* Copy the files to your sd card
-```
-sdcard
-└── switch
- └── soh
- ├── oot-mq.o2r
- ├── oot.o2r
- ├── soh.nro
- └── soh.o2r
-```
-* Launch via Atmosphere's `Game+R` launcher method.
-
### 4. Play!
Congratulations, you are now sailing with the Ship of Harkinian! Have fun!
diff --git a/soh/soh/Extractor/Extract.cpp b/soh/soh/Extractor/Extract.cpp
index b4c98f392..4e6e26b76 100644
--- a/soh/soh/Extractor/Extract.cpp
+++ b/soh/soh/Extractor/Extract.cpp
@@ -257,15 +257,15 @@ void Extractor::GetRoms(std::vector<std::string>& roms) {
// Go through each file in the directory
while ((dir = readdir(d)) != NULL) {
struct stat path;
+ std::string fullPath = mSearchPath + "/" + dir->d_name;
// Check if current entry is not folder
- stat(dir->d_name, &path);
- if (S_ISREG(path.st_mode)) {
+ if (stat(fullPath.c_str(), &path) == 0 && S_ISREG(path.st_mode)) {
// Get the position of the extension character.
char* ext = strrchr(dir->d_name, '.');
if (ext != NULL && (strcmp(ext, ".z64") == 0 || strcmp(ext, ".n64") == 0 || strcmp(ext, ".v64") == 0)) {
- roms.push_back(dir->d_name);
+ roms.push_back(fullPath);
}
}
}
diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp
index 30b7dcd91..0341e4f36 100644
--- a/soh/soh/OTRGlobals.cpp
+++ b/soh/soh/OTRGlobals.cpp
@@ -2,6 +2,7 @@
#include "OTRAudio.h"
#include <algorithm>
#include <atomic>
+#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <vector>
@@ -1545,7 +1546,44 @@ bool VerifyArchiveVersion(OTRVersion version) {
return version.major != INT16_MAX && version.major != gBuildVersionMajor;
}
+#ifdef __linux__
+// When run as an AppImage, keep user data in ~/.local/share/soh instead of the launch folder.
+// Keep using the launch folder if it already has data from older versions.
+static void SetAppImageHome() {
+ if (getenv("APPIMAGE") == nullptr || getenv("SHIP_HOME") != nullptr) {
+ return;
+ }
+
+ for (const char* file : { "shipofharkinian.json", "oot.o2r", "oot-mq.o2r" }) {
+ if (std::filesystem::exists(file)) {
+ return;
+ }
+ }
+
+ std::filesystem::path home;
+ const char* dataHome = getenv("XDG_DATA_HOME");
+ const char* userHome = getenv("HOME");
+ if (dataHome != nullptr && std::filesystem::path(dataHome).is_absolute()) {
+ home = dataHome;
+ } else if (userHome != nullptr && userHome[0] != '\0') {
+ home = std::filesystem::path(userHome) / ".local" / "share";
+ } else {
+ return;
+ }
+ home /= appShortName;
+
+ std::error_code ec;
+ std::filesystem::create_directories(home, ec);
+ if (!ec) {
+ setenv("SHIP_HOME", home.c_str(), 0);
+ }
+}
+#endif
+
extern "C" void InitOTR(int argc, char* argv[]) {
+#ifdef __linux__
+ SetAppImageHome();
+#endif
OTRGlobals::Instance = new OTRGlobals();
OTRGlobals::Instance->RunExtract(argc, argv);