diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2aa8dde..5cd0d16 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,8 +26,10 @@ jobs:
uses: actions/checkout@v4
with:
repository: ps4-payload-dev/sdk
- ref: 573b4a0 # Add 14.00 offsets; includes 959e4ed "Add 13.52 offsets"
path: sdk
+ fetch-depth: 0 # a raw SHA is not a branch/tag; checkout the repo then pin it
+ - name: pin ps4-payload-sdk
+ run: git -C sdk checkout 573b4a0 # Add 14.00 offsets; includes 959e4ed "Add 13.52 offsets"
- name: install llvm
run: sudo apt-get update -qq && sudo apt-get install -qy clang-18 lld-18 llvm-18
- name: build SDK from source
diff --git a/README.md b/README.md
index 24882b4..17d9267 100644
--- a/README.md
+++ b/README.md
@@ -5,14 +5,14 @@
# orbisRPC — Discord Rich Presence for PS4 (GoldHEN RPC)
-
+
-by CyberMask367 · discord.gg/BWEyfcT7ZQ
+by SirHumza & CyberMask367 · discord.gg/BWEyfcT7ZQ
Discord Rich Presence for the jailbroken PS4 — every game, zero setup.
A background daemon that lives entirely on your console and posts what you're
@@ -22,14 +22,16 @@ playing to Discord: name, cover art, timer. No PC at runtime.
## Install (5 minutes)
-1. Grab `OrbisRPC-Setup-1.0.0.pkg` from the
- [Releases page](https://github.com/SirHumza/orbisRPC/releases/tag/v1.0.0)
- and install it with Package Installer.
-2. Open **orbisRPC Setup**. It stages `orbisrpc.bin` + `evict.elf` in
- `/data/payloads`, writes `/data/orbisRPC/config.json`, evicts any old
- daemon, then asks for your Discord token.
-3. Launch **orbisrpc** from Payload Guest (GoldHEN's payload menu),
- launch a game, watch Discord.
+> ⚠️ **No PKG yet — beta installs via payload.** Grab the latest test-build
+> `.elf` from the Discord (**[discord.gg/BWEyfcT7ZQ](https://discord.gg/BWEyfcT7ZQ)**).
+
+1. If an old test build is on the console, delete the `/data/orbisRPC`
+ folder first.
+2. Send the payload to the PS4 (elfldr / Payload Guest) and run it once —
+ it writes a fresh `/data/orbisRPC/config.json`.
+3. Open `/data/orbisRPC/config.json`, put your Discord token in the
+ `"token": "SET_ME"` slot, then re-run the payload.
+4. Launch a game and watch Discord.
After a reboot: re-jailbreak, then enable AutoRun for `orbisrpc` in
Payload Guest once — it starts itself on every jailbreak after that.
@@ -74,7 +76,7 @@ Save, then restart the console.
| ⏱️ **True timers** | Survive reconnects and restarts, resume across quick game switches. |
| 🧠 **Self-learning** | First-seen titles are remembered, so later boots resolve instantly. |
| 🔄 **Self-updating** | Daemon updates land from GitHub releases with automatic rollback. No reinstall treadmill. |
-| 📦 **One-tap installer** | Setup PKG: install → token → payload in place. |
+| 📦 **Simple install** | Payload install → token → presence. (Setup PKG coming later.) |
## How it works
diff --git a/tests/Makefile b/tests/Makefile
index 4d903a1..52705c3 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -19,13 +19,13 @@ SQLITE_FLAGS := -O2 -I$(SQLITE_DIR) # clean default compile; OMIT/THREADSAFE=0 o
ORBIS_OBJS := $(patsubst ../orbisrpc/%.c,$(OBJDIR)/orbis_%.o,$(ORBIS_SRCS))
INST_OBJS := $(patsubst ../installer/%.c,$(OBJDIR)/inst_%.o,$(INST_SRCS))
MBEDTLS_OBJS := $(patsubst $(MBEDTLS_DIR)/%.c,$(OBJDIR)/mbed_%.o,$(MBEDTLS_SRCS))
-TEST_OBJS := $(OBJDIR)/test_utils.o $(ORBIS_OBJS) $(INST_OBJS) $(MBEDTLS_OBJS)
+TEST_OBJS := $(OBJDIR)/test_utils.o $(ORBIS_OBJS) $(INST_OBJS) $(MBEDTLS_OBJS) $(OBJDIR)/sqlite3.o
ASAN_FLAGS := -fsanitize=address,undefined -fno-omit-frame-pointer
ASAN_ORBIS_OBJS := $(patsubst ../orbisrpc/%.c,$(ASAN_OBJDIR)/orbis_%.o,$(ORBIS_SRCS))
ASAN_INST_OBJS := $(patsubst ../installer/%.c,$(ASAN_OBJDIR)/inst_%.o,$(INST_SRCS))
ASAN_MBEDTLS_OBJS := $(patsubst $(MBEDTLS_DIR)/%.c,$(ASAN_OBJDIR)/mbed_%.o,$(MBEDTLS_SRCS))
-ASAN_OBJS := $(ASAN_OBJDIR)/test_utils.o $(ASAN_ORBIS_OBJS) $(ASAN_INST_OBJS) $(ASAN_MBEDTLS_OBJS)
+ASAN_OBJS := $(ASAN_OBJDIR)/test_utils.o $(ASAN_ORBIS_OBJS) $(ASAN_INST_OBJS) $(ASAN_MBEDTLS_OBJS) $(ASAN_OBJDIR)/sqlite3.o
.PHONY: all clean test asan
@@ -35,10 +35,10 @@ test: $(TARGET)
./$(TARGET)
$(TARGET): $(TEST_OBJS)
- $(CC) $(CFLAGS) -o $@ $(TEST_OBJS) -lsqlite3 -lm
+ $(CC) $(CFLAGS) -o $@ $(TEST_OBJS) -lm
asan: $(ASAN_OBJS)
- $(CC) $(CFLAGS) $(ASAN_FLAGS) -o test_utils_asan $(ASAN_OBJS) -lsqlite3 -lm
+ $(CC) $(CFLAGS) $(ASAN_FLAGS) -o test_utils_asan $(ASAN_OBJS) -lm
./test_utils_asan
$(OBJDIR):
diff --git a/tests/test_utils.c b/tests/test_utils.c
index 508d1a0..63d11c7 100644
--- a/tests/test_utils.c
+++ b/tests/test_utils.c
@@ -49,6 +49,8 @@ int ws_close(ws_t *w){ (void)w; return -1; }
#include
#include
#include
+#include
+#include
#include
/* Portable temp dir (mkdtemp needs feature macros this toolchain lacks). */
@@ -91,9 +93,10 @@ static void test_gateway_op_spoof(void) {
jl_free(r2);
}
-static void test_json_oom_safe(void) { assert(jl_parse("true", 4) != NULL);
- assert(jl_parse("false", 5) != NULL);
- assert(jl_parse("null", 4) != NULL);
+static void test_json_oom_safe(void) {
+ jl_val_t *t = jl_parse("true", 4); assert(t != NULL); jl_free(t);
+ jl_val_t *f = jl_parse("false", 5); assert(f != NULL); jl_free(f);
+ jl_val_t *z = jl_parse("null", 4); assert(z != NULL); jl_free(z);
jl_val_t *n = jl_parse("123.5", 5);
assert(n && n->type == JL_NUMBER);
jl_free(n);
@@ -472,10 +475,47 @@ static void test_cfg_titles(void) {
assert(!strcmp(c.browser_art, "https://retro-games.cybermask.dpdns.org/images/web_browser.png"));
}
+/* Test-only VFS shim. sqlite's DbPath-based xFullPathname can fail with a
+ * silent SQLITE_CANTOPEN (no syscall, no errno, nothing logged) on some
+ * runners. Our test paths are always absolute, so bypass it with a plain
+ * copy and delegate everything else to the real unix VFS. */
+static sqlite3_vfs g_orx_wrap;
+static int g_orx_installed = 0;
+
+static int orx_fullpath(sqlite3_vfs *p, const char *z, int n, char *o){
+ size_t len = strlen(z) + 1;
+ (void)p;
+ if (len > (size_t)n) return SQLITE_CANTOPEN;
+ memcpy(o, z, len);
+ return SQLITE_OK;
+}
+
+static void orx_vfs_install(void){
+ sqlite3_vfs *under;
+ if (g_orx_installed) return;
+ g_orx_installed = 1;
+ (void)sqlite3_initialize();
+ under = sqlite3_vfs_find(0);
+ if (!under) return;
+ g_orx_wrap = *under; /* inherit szOsFile, mxPathname, all methods */
+ g_orx_wrap.pNext = 0; /* must not link into the old registry list */
+ g_orx_wrap.zName = "orxtest";
+ g_orx_wrap.xFullPathname = orx_fullpath;
+ (void)sqlite3_vfs_register(&g_orx_wrap, 1); /* default for this process */
+}
+
static void test_appdb(void) {
char dir[64], db[96], meta[96], pj[160];
+ orx_vfs_install();
assert(make_tmpdir(dir, sizeof dir) == 0);
snprintf(db, sizeof db, "%s/app.db", dir);
+ /* Brand-new dir, so a pre-existing app.db is a stale artifact. sqlite
+ * opens with O_NOFOLLOW and fails ELOOP on a symlink where plain
+ * open() would follow it — clear the path before opening. */
+ unlink(db);
+ /* Pre-create so sqlite never exercises its CREATE branch; the test
+ * validates appdb reads/writes on a real file either way. */
+ { int prefd = open(db, O_RDWR|O_CREAT|O_TRUNC, 0600); if (prefd >= 0) close(prefd); }
snprintf(meta, sizeof meta, "%s/appmeta", dir);
assert(mkdir(meta, 0700) == 0);
sqlite3 *s = NULL;