Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
120 commits
Select commit Hold shift + click to select a range
c9ac7fa
Add Android client spike with AWT stubs and JNI wrappers.
MaatheusGois Aug 23, 2026
dead7d5
Ship Android display/input fixes and the iOS RoboVM port.
MaatheusGois Aug 23, 2026
1ecbe08
Update README.md
MaatheusGois Aug 23, 2026
fb4914b
Update asset link in README.md
MaatheusGois Aug 23, 2026
7115394
Fix Android IME shrink and use sticky immersive fullscreen.
MaatheusGois Aug 23, 2026
7f34bea
Add real mobile PCM audio via voidsound and document it.
MaatheusGois Aug 23, 2026
0c0c550
Open soft keyboard from in-game text field taps on Android and iOS.
MaatheusGois Aug 23, 2026
d29611c
Document how to run desktop, Android, and iOS clients.
MaatheusGois Aug 23, 2026
466b399
Add client-level Makefile and slim READMEs for run + server IP.
MaatheusGois Aug 23, 2026
4efc991
Add Void app icons for Android and iOS.
MaatheusGois Aug 23, 2026
7c67454
Update README.md
MaatheusGois Aug 23, 2026
3341eed
Fix Android viewport shrinking after resume.
MaatheusGois Aug 24, 2026
6ae26ef
Add 4-finger developer console toggle on mobile.
MaatheusGois Aug 24, 2026
029991d
Halve developer console height on mobile only.
MaatheusGois Aug 24, 2026
c465aa9
Use the Windows arrow for the virtual gamepad cursor on Android and iOS.
MaatheusGois Aug 24, 2026
b91c9cb
Hide the virtual cursor when the gamepad disconnects.
MaatheusGois Aug 24, 2026
fd97b04
Ship mobile soft-keyboard, chat lift, server prefs, and device deploy.
MaatheusGois Aug 25, 2026
5ed3b6d
Document mobile AWT/sound shims and allow iPad window resize.
MaatheusGois Aug 25, 2026
42f12c2
Lift login interface 744 only enough for the focused field to sit abo…
MaatheusGois Aug 25, 2026
0bc94a3
Enable iPad window resize with deferred layout, and stop stealing aud…
MaatheusGois Aug 25, 2026
6a4ad7d
Update README with additional asset link
MaatheusGois Aug 25, 2026
a1d6f1d
Add default left-click swaps, login prefs, and iOS gamepad.
MaatheusGois Aug 25, 2026
dc0f38f
Update README.md
MaatheusGois Aug 25, 2026
d459e2f
Document auto-login, default left-click, and mobile extras in README.
MaatheusGois Aug 25, 2026
3bdfa6a
Disable native SW3D/OpenGL toolkits on macOS desktop.
MaatheusGois Aug 26, 2026
fca40cd
Fix macOS auto-login stuck behind Leave Alone dialog.
MaatheusGois Aug 26, 2026
2488108
Add Microbot runtime with menu-inject API and in-game HUD.
MaatheusGois Aug 26, 2026
4f2780f
Deobfuscate mouse/font APIs and split client into source roots.
MaatheusGois Aug 26, 2026
428c879
Rename deobfuscated Class* types and fix RoboVM AOT for iOS.
MaatheusGois Aug 28, 2026
8168057
Rename client source roots to domain folders.
MaatheusGois Aug 28, 2026
8581020
Organize client/src into fine-grained domain source roots.
MaatheusGois Aug 28, 2026
c54f544
Rename multi-char toolkit shorts to meaningful class names.
MaatheusGois Aug 28, 2026
eacef10
Remove obsolete decode documentation.
MaatheusGois Aug 28, 2026
1bfe55f
Rename evidenced fields and methods across client deobfuscation.
MaatheusGois Aug 28, 2026
1663704
Rename evidenced fields and methods across client deobfuscation.
MaatheusGois Aug 28, 2026
9cb9e0c
Rename evidenced fields and methods across client deobfuscation.
MaatheusGois Aug 28, 2026
1d3fca1
Fix mobile reflection after deob renames and gate future breakage.
MaatheusGois Aug 28, 2026
740f546
Keep iOS screen awake while game is open.
MaatheusGois Aug 28, 2026
2c891e0
Fix iOS splash text orientation via UIGraphics.
MaatheusGois Aug 29, 2026
c090fb1
Note reflection string updates in the deobfuscate skill.
MaatheusGois Aug 29, 2026
de6a4c5
Fix mobile console IME hit-testing and iOS device deploy.
MaatheusGois Aug 29, 2026
a85bb12
Decorate item console echoes with names and wire lean-ctx for Cursor.
MaatheusGois Aug 29, 2026
34b55ff
Fix inverted mobile console drag scroll and rename mouseWheelDelta.
MaatheusGois Aug 29, 2026
ed9561b
Fix item console replay/IME and rename item definition types.
MaatheusGois Aug 29, 2026
5cebeaa
Rename evidenced NPC combat/menu fields and keep Attack on stronger m…
MaatheusGois Aug 29, 2026
e555078
Rename widget fields, add desktop gamepad, and ship widget-debug skill.
MaatheusGois Aug 29, 2026
20e6e60
Ship gamecontrollerdb.txt so jamepad stops failing classpath lookup.
MaatheusGois Aug 29, 2026
005f65a
Rename cursor, NPC, and widget types with reflection sync.
MaatheusGois Aug 29, 2026
8bcb52a
Update 4 areas across 5 files (+70 −3 lines)
MaatheusGois Aug 29, 2026
9718e0f
Update apk
MaatheusGois Aug 29, 2026
c2f20e9
Fix Android Learn alias for D-pad hat axes and document host paths.
MaatheusGois Aug 29, 2026
ea71688
Add affiliation disclaimer and harden desktop gamepad.
MaatheusGois Aug 29, 2026
195c216
Ship Apple TV client with Top Shelf wallpaper and docs.
MaatheusGois Aug 30, 2026
fa7c141
Update README with new asset links and features
MaatheusGois Aug 30, 2026
20a93f7
Rename evidenced fields and methods across client deobfuscation.
MaatheusGois Aug 30, 2026
10707c2
Deob lote 52: rename SpriteSub3 rasterizer fields to english
MaatheusGois Aug 30, 2026
2a344ac
Deob lote 50 (partial): name ModelProvider methods, fields and impl c…
MaatheusGois Aug 30, 2026
6437e88
Deob lote 56: rename reflective canvas/display fields + sync mobile h…
MaatheusGois Aug 30, 2026
de8505c
Deob lote 55: rename PacketReader own methods (opcode dispatch)
MaatheusGois Aug 30, 2026
fce49d3
Resolve Component182 float writer island
Copilot Aug 30, 2026
fbf3ab6
Document resolved float serialization methods
Copilot Aug 30, 2026
878b2be
Correct unresolved token inventory
Copilot Aug 30, 2026
bc794a9
Keep deobfuscation token tables consistent
Copilot Aug 30, 2026
e9ad182
Finalize deobfuscation inventory ordering
Copilot Aug 30, 2026
2bd75b5
Deob lote 53: rename 3D scene/particle API methods + vertex coordinat…
MaatheusGois Aug 30, 2026
5ffd5fd
Merge pull request #1 from MaatheusGois/copilot/desofuscar-codigo-e-d…
MaatheusGois Aug 30, 2026
38c0400
Deob lote 54: rename 34 GlToolkitSub2 GL binding methods (1:1 with Op…
MaatheusGois Aug 30, 2026
83e5be1
Deob lote 57: rename 10 CS2 own methods in ClientScriptExecutor
MaatheusGois Aug 30, 2026
4dec042
Deob lote 58: rename NodeSub16Sub5 audio synthesis methods (15 methods)
MaatheusGois Aug 30, 2026
95d2825
Deob lote 59: rename BrowserUrlOpener MIDI synthesizer methods (30 me…
MaatheusGois Aug 30, 2026
1d4ad3f
Deob lote 60: rename DisplayModeManagerContainer164 scene renderer me…
MaatheusGois Aug 30, 2026
b957be7
Deob lote 61: rename DisplayModeManagerContainer190 + 282 scene metho…
MaatheusGois Aug 30, 2026
a2f0388
Deob lote 62: rename DisplayModeManagerContainer229 world map loader …
MaatheusGois Aug 30, 2026
e6b92f0
Deob lote 63: rename RenderableSub4/Sub6 file-specific methods (8 met…
MaatheusGois Aug 30, 2026
d5feb45
Deob lote 64: rename Renderable subclasses file-specific methods (19 …
MaatheusGois Aug 30, 2026
b37f90e
Add Component Lab browser
Copilot Aug 30, 2026
7c539db
Polish and validate Component Lab
Copilot Aug 30, 2026
1166bc0
Address Component Lab review feedback
Copilot Aug 30, 2026
6e9ea70
Finalize Component Lab polish
Copilot Aug 30, 2026
ec8bddc
Harden Component Lab server
Copilot Aug 30, 2026
a01f0d8
Clarify Component Lab factory
Copilot Aug 30, 2026
f4892ba
Finalize request handler factory
Copilot Aug 30, 2026
dd6a163
Merge pull request #2 from MaatheusGois/copilot/create-mini-app-for-c…
MaatheusGois Aug 30, 2026
177aaae
Deobfuscate Component182 scene pass
Copilot Aug 30, 2026
87e96a9
Validate Component182 deobfuscation
Copilot Aug 30, 2026
f74f8df
Name Component182 primary render flag
Copilot Aug 30, 2026
5a25bc4
Implement world map teleport hook
Copilot Aug 30, 2026
114d6f2
Validate world map teleport
Copilot Aug 30, 2026
514bcd8
Clarify teleport plane menu identifier
Copilot Aug 30, 2026
3eb3192
Document teleport menu parameter mapping
Copilot Aug 30, 2026
610efc4
Merge pull request #3 from MaatheusGois/copilot/worldmap-activities-t…
MaatheusGois Aug 30, 2026
57b40b4
Implement dialogue TTS API and platform bridges
Copilot Aug 30, 2026
ea14a7f
Add local buffer rendering to Component Lab
Copilot Aug 30, 2026
ef07a61
Fix mobile lifecycle bridge and iOS speech bindings
Copilot Aug 30, 2026
8fc82f5
Clarify buffer card row layout
Copilot Aug 30, 2026
29813c5
Harden TTS process invocation and scanner state
Copilot Aug 30, 2026
dee1dfe
Make dialogue TTS backend replaceable and document gender fallback
Copilot Aug 30, 2026
18b825e
Drain desktop TTS process output safely
Copilot Aug 30, 2026
79dc04f
Improve TTS diagnostics and widget scan safety
Copilot Aug 30, 2026
7507846
Merge pull request #4 from MaatheusGois/copilot/dialogue-tts-poc-native
MaatheusGois Aug 30, 2026
e2dfb38
Merge main into component lab branch
Copilot Aug 30, 2026
d251b37
Verify main synchronization
Copilot Aug 30, 2026
8cced8e
Merge pull request #5 from MaatheusGois/copilot/add-component-lab-for…
MaatheusGois Aug 30, 2026
34bb358
Lote 54: GlToolkit* renderer island - renamed ~100 method#### to mean…
MaatheusGois Aug 30, 2026
bfcc78d
Update 5 areas across 764 files (rename_in_file,main) (+317 −1524 lines)
MaatheusGois Aug 30, 2026
2f0ae12
Rename evidenced collision/scene/pref/GL tokens and disable dialogue …
MaatheusGois Aug 30, 2026
2ae8e0d
Add widget dump/map tooling and harden UI/font rendering paths.
MaatheusGois Aug 30, 2026
cd6ebea
Rename evidenced client methods
Copilot Aug 30, 2026
f23184d
Document lote 69 deobfuscation batch
Copilot Aug 30, 2026
4c1e295
Merge pull request #7 from MaatheusGois/copilot/desobfuscate
MaatheusGois Aug 30, 2026
214655b
Deobfuscate GL binding methods in lote 70
Copilot Aug 30, 2026
7eb31d6
Complete lote 70 GL deobfuscation
Copilot Aug 30, 2026
2b516f1
Clarify texture combine documentation
Copilot Aug 30, 2026
5c6a677
Remove obfuscated Javadoc parameter reference
Copilot Aug 30, 2026
f0a0f30
Merge pull request #8 from MaatheusGois/copilot/desobfuscate-again
MaatheusGois Aug 30, 2026
6374a8f
Document deobfuscation batch constraints
Copilot Aug 30, 2026
cf41ae9
Rename preference option methods
Copilot Aug 30, 2026
e68fb64
Merge pull request #9 from MaatheusGois/copilot/desobfuscate-another-one
MaatheusGois Aug 30, 2026
1782aa9
Deobfuscate shared buffer and preference state handles
Copilot Aug 30, 2026
39a7155
Merge pull request #10 from MaatheusGois/copilot/desobfuscate-yet-again
MaatheusGois Aug 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
37 changes: 37 additions & 0 deletions .cursor/rules/deobfuscate-on-learn.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
description: On any evidenced understanding of obfuscated client code, run void-client-deobfuscate skill
alwaysApply: true
---

# Deobfuscate when you learn

When you **figure out** what an obfuscated class / method / field / constant / flow does (call sites, strings, protocol, bit flags — not guesses), **do not leave the names as-is**.

## Mandatory next step

1. Read and follow the skill:
`.cursor/skills/void-client-deobfuscate/SKILL.md`
2. Also follow the workspace rename+comment rule (`void-client-deobfuscate.mdc`).
3. Apply a small lote: rename with evidence, comment densely, sync reflection strings if needed, verify.

## Triggers (any of these)

- Bugfix that reveals intent (`item` console echo, camera, packets, …)
- You can explain a `method####` / `anInt####` / `aBoolean####` / opaque class in plain English
- A misnamed type (e.g. “NumberFormatter” that is actually an item def)
- User asks to clarify / rename / “desofuscar”

## Do not skip

- Waiting for the user to say `/void-client-deobfuscate` — if you learned it, deobfuscate in the same turn (or immediately after the fix).
- Renaming without evidence, global replace of non-unique `methodNNN`, or skipping `check_reflection.py` when hosts look up members by string.

## Verify before claiming done

```bash
python3 .cursor/skills/void-client-deobfuscate/scripts/check_reflection.py
./gradlew :client:compileJava
cd ios && ./gradlew compileJava
```

Commit / push only when the user asks.
38 changes: 38 additions & 0 deletions .cursor/rules/lean-ctx.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
description: "lean-ctx hybrid: MUST use ctx_read/ctx_search (MCP) + lean-ctx -c (CLI). NEVER use native Read/Grep/Shell."
alwaysApply: true
---

# lean-ctx — Context Engineering Layer
<!-- lean-ctx-rules-v12 -->

## Mode: Hybrid (MCP reads + CLI shell)

CRITICAL: ALWAYS use lean-ctx tools. This is NOT optional.

## Tool Mapping (MANDATORY)
| Instead of | MUST USE | Example |
|------------|----------|---------|
| Read/cat/head/tail | `ctx_read(path, mode)` | `ctx_read("src/main.rs")` (omit mode = auto) |
| Grep/rg/find | `ctx_search(pattern, path)` | `ctx_search("fn handle", "src/")` |
| Shell/bash | `lean-ctx -c "<cmd>"` | `lean-ctx -c "cargo test"` |
| ls/find | `lean-ctx ls [path]` | `lean-ctx ls src/ --depth 3` |
| Edit (when Read unavail.) | `ctx_edit(path, old, new)` | `ctx_edit("f.rs", "old", "new")` |

## ctx_read Modes (omit mode to auto-select — recommended)
| Goal | Mode |
|------|------|
| Exploring / unsure (default) | `auto` |
| Edit target | `full` |
| API surface | `signatures` |
| Post-edit check | `diff` |
| Overview | `map` |
| Region | `lines:N-M` |

## Workflow: Orient → Locate → Read → Edit → Verify → Record
Use `ctx_overview` or `ctx_compose` first. Then `ctx_search`/`ctx_semantic_search`.
Read with `ctx_read(path, mode)`. Edit with native Edit or `ctx_edit`.
Verify: `ctx_read(path, "diff")` + `lean-ctx -c "test cmd"`.

REMINDER: You MUST use lean-ctx tools. NEVER use native Read, Grep, or Shell directly.
<!-- /lean-ctx -->
42 changes: 42 additions & 0 deletions .cursor/rules/lean-ctx.mdc.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
description: "lean-ctx: context compression layer. Tools replace native Read/Grep/Shell — see tool descriptions."
globs: **/*
alwaysApply: true
---

# lean-ctx — Context Engineering Layer
<!-- lean-ctx-rules-v12 -->

## Tool Mapping (MANDATORY — use instead of native equivalents)
| Instead of | Use | Example |
|------------|-----|---------|
| Read/cat/head/tail | `ctx_read(path, mode)` | `ctx_read("src/main.rs")` (omit mode = auto) |
| Grep/rg/find | `ctx_search(pattern, path)` | `ctx_search("fn handle", "src/")` |
| Shell/bash | `ctx_shell(command)` | `ctx_shell("cargo test")` |
| ls/find (tree) | `lean-ctx ls [path]` or `ctx_tree(path)` | `ctx_tree("src", depth=3)` |
| Edit (when Read unavailable) | `ctx_edit(path, old, new)` | `ctx_edit("f.rs", "old", "new")` |

## ctx_read Mode Selection (omit mode to auto-select — recommended)
| Goal | Mode | When |
|------|------|------|
| Exploring / unsure | `auto` (default) | Omit mode; system picks optimal |
| Edit this file | `full` | Right before an edit |
| Understand API | `signatures` | Context-only, won't edit |
| Large file overview | `map` | >500 lines, won't edit |
| Re-read after edit | `diff` | Post-edit verification |
| Specific region | `lines:N-M` | Know exact location |

## Workflow
1. **Orient:** `ctx_overview(task)` or `ctx_compose(task, path)`
2. **Locate:** `ctx_search(pattern, path)` or `ctx_semantic_search(query)`
3. **Read:** `ctx_read(path, mode)` — pick mode from table above
4. **Edit:** `ctx_edit(path, old, new)` or native Edit
5. **Verify:** `ctx_read(path, "diff")` + `ctx_shell("test command")`
6. **Record:** `ctx_knowledge(action="remember", content="...")`

## Session
- **Start:** `ctx_session(action="status")` + `ctx_knowledge(action="wakeup")`
- **End:** `ctx_session(action="decision", content="what was done + next steps")`

NEVER use native Read/Grep/Shell when ctx_* equivalents are available.
<!-- /lean-ctx -->
92 changes: 92 additions & 0 deletions .cursor/skills/run-mobile-device/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
name: run-mobile-device
description: >-
Build, install, and launch Void OSRS on a physical iPad, Apple TV, or Android phone.
Use when the user says restart, deploy, run on device, iPad, Apple TV, tvOS,
make android, install, or relaunch the mobile client.
---

# Run Void on device

Game server must already be up on **TCP 43594**.

This skill lives in the **void-client** repo. Run scripts from `void-client/` (this directory).

**Always execute the scripts** (do not paste gradle/signing flags by hand):

| Device | Command | `block_until_ms` |
| iPad | `bash .cursor/skills/run-mobile-device/scripts/ios-device.sh` | `240000` |
| Apple TV | `bash .cursor/skills/run-mobile-device/scripts/tvos-device.sh` | `300000` |
| Android USB | `bash .cursor/skills/run-mobile-device/scripts/android-device.sh` | `180000` |

When the user says **restart** / **deploy** without a platform:

1. Just edited `ios/` for tvOS / Apple TV → tvOS script.
2. Just edited `ios/` or `GameController.java` → iPad script.
3. Just edited `android/` or `MainActivity.java` → Android script.
4. Else: iPad if `xcrun devicectl list devices` shows a physical iPad `available`; else Apple TV if available; else Android if `adb devices` has `device`.

Do **not** use `make ios` for a physical iPad (Simulator only).

## iOS iPad

The script: checks arm64 JDK 17 → **`robovmInstall`** (flat signed bundle in `build/robovm/`) → **always** re-wrap into a fresh `Void.app` → **`devicectl install` + `launch`**.

Do **not** reuse a previous `Void.app` — `robovmInstall` writes beside it; keeping the old wrap installs a stale binary. Do **not** use `launchIOSDevice` (AppLauncher `--console` hangs).

Defaults (override with env):

| Env | Default |
|-----|---------|
| `JAVA_17` | `$HOME/.jdks/jdk-17.0.20.1+1/Contents/Home` |
| `IOS_UDID` | `00008120-000E7D8830214932` (hardware UDID, **not** the `Identifier` from `devicectl list`) |
| `IOS_SIGN_IDENTITY` | `Apple Development: Matheus Gois (885DD2XQL9)` |
| `IOS_PROVISIONING_PROFILE` | `bdd4f76c-78f2-493c-b2e0-66f72e688f77` |

If install fails, re-query UDID:

```bash
xcrun devicectl list devices
xcrun devicectl device info details --device iPad # Hardware.UDID
```

Signing rediscovery: `security find-identity -v -p codesigning`. Team `CTAFH43K36`.

Bundle id: `world.gregs.voidosrs.ios`.

Simulator only if asked: `make ios` / `make ios-relaunch`.

## Apple TV (tvOS)

Same wrap/`devicectl` flow as iPad, but **`-Pvoid.platform=tvos`** → patched RoboVM uses **AppleTVOS.sdk** (`robovm-tvos.xml`, bundle `world.gregs.voidosrs.tvos`).

| Env | Default |
|-----|---------|
| `TVOS_UDID` | `7d5160e9f84ba36ad9abee5c1aff2fd89c2e7b07` (TV Sala - Gois) |
| `TVOS_PROVISIONING_PROFILE` | `39f19b56-ca6f-4e80-90f5-187667971c3e` (tvOS Team Provisioning Profile: *) |
| `IOS_SIGN_IDENTITY` | same as iPad |

Requires the patched plugin jar (`ios/tools/patches/apply_tvos_robovm_patch.py`). Input: DualShock / Siri Remote (`GCMicroGamepad`) + on-screen keyboard.

```bash
make tvos-sim # Apple TV Simulator (simctl; no signing)
make tvos-device # physical Apple TV
```

Simulator note: RoboVM only matches iPhone/iPad device families, so `tvos-sim.sh` builds with `skipLaunch` then installs via `simctl` onto an Apple TV runtime (Mach-O stamped `TVOSSIMULATOR`).

## Android USB

The script refuses to hang if `adb devices` is empty. Then `make android` (installDebug + reverse `:43594` + launch).

- Package `world.gregs.voidosrs.android` / `.MainActivity`
- USB reverse → phone uses host `127.0.0.1:43594`
- LAN: `make android-server SERVER_IP=<lan-ip>`
- Logs: `make android-log`
- Already installed: `make android-run`

## Server host

Saved in `{user.home}/void-server.txt` (in-app picker). Do not change unless asked.

Overrides: `-Dvoid.server=<host>` (host only, no `http://` / port). Android also `adb shell setprop debug.void.server <host>` then relaunch.
16 changes: 16 additions & 0 deletions .cursor/skills/run-mobile-device/scripts/android-device.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# Install debug APK, adb reverse :43594, launch MainActivity.
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/../../../.." && pwd)"

devices="$(adb devices | awk 'NR>1 && $2=="device" {print $1}')"
if [[ -z "$devices" ]]; then
echo "no Android device (adb devices empty / unauthorized). Plug in USB and authorize." >&2
adb devices -l >&2
exit 1
fi

cd "$ROOT"
make android
echo "OK — android launched"
56 changes: 56 additions & 0 deletions .cursor/skills/run-mobile-device/scripts/inject-tvos-icons.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Compile tvOS brandassets (App Icon + Top Shelf) into Assets.car and merge
# the actool partial Info.plist into the app. RoboVM's actool always targets
# iphoneos, so this must run after the .app is assembled.
set -euo pipefail

APP="${1:?usage: inject-tvos-icons.sh /path/to/Void.app}"
ROOT="$(cd "$(dirname "$0")/../../../.." && pwd)"
ASSETS="$ROOT/ios/data/Assets.xcassets"
TMP="$(mktemp -d "${TMPDIR:-/tmp}/void-tvos-icons.XXXXXX")"
trap 'rm -rf "$TMP"' EXIT

if [[ ! -d "$ASSETS/App Icon & Top Shelf Image.brandassets" ]]; then
echo "missing tvOS brandassets under $ASSETS" >&2
exit 1
fi
if [[ ! -d "$APP" || ! -f "$APP/Info.plist" ]]; then
echo "not an app bundle: $APP" >&2
exit 1
fi

xcrun actool "$ASSETS" \
--compile "$TMP" \
--platform appletvos \
--minimum-deployment-target 13.0 \
--target-device tv \
--app-icon "App Icon & Top Shelf Image" \
--output-partial-info-plist "$TMP/partial.plist" \
--compress-pngs \
--errors --warnings \
--output-format human-readable-text >/dev/null

if [[ ! -f "$TMP/Assets.car" ]]; then
echo "actool did not produce Assets.car" >&2
exit 1
fi

cp "$TMP/Assets.car" "$APP/Assets.car"

# Merge CFBundleIcons + TVTopShelfImage from actool partial into Info.plist.
python3 - "$APP/Info.plist" "$TMP/partial.plist" <<'PY'
import plistlib, sys
app_path, partial_path = sys.argv[1], sys.argv[2]
with open(app_path, "rb") as f:
info = plistlib.load(f)
with open(partial_path, "rb") as f:
partial = plistlib.load(f)
for key in ("CFBundleIcons", "TVTopShelfImage"):
if key in partial:
info[key] = partial[key]
info["CFBundleIconName"] = "App Icon & Top Shelf Image"
with open(app_path, "wb") as f:
plistlib.dump(info, f)
PY

echo "injected tvOS App Icon + Top Shelf into $APP"
69 changes: 69 additions & 0 deletions .cursor/skills/run-mobile-device/scripts/ios-device.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env bash
# Build + sign via robovmInstall, wrap flat installDir into Void.app, then
# install/launch on iPad via devicectl (no AppLauncher --console hang).
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/../../../.." && pwd)"
IOS="$ROOT/ios"
INSTALL_DIR="$IOS/build/robovm"
APP="$INSTALL_DIR/Void.app"
JAVA_17="${JAVA_17:-$HOME/.jdks/jdk-17.0.20.1+1/Contents/Home}"
UDID="${IOS_UDID:-00008120-000E7D8830214932}"
SIGN_ID="${IOS_SIGN_IDENTITY:-Apple Development: Matheus Gois (885DD2XQL9)}"
PROFILE="${IOS_PROVISIONING_PROFILE:-bdd4f76c-78f2-493c-b2e0-66f72e688f77}"
BUNDLE="${IOS_BUNDLE:-world.gregs.voidosrs.ios}"

if [[ ! -x "$JAVA_17/bin/java" ]]; then
echo "missing arm64 JDK 17 at JAVA_17=$JAVA_17" >&2
exit 1
fi
if ! "$JAVA_17/bin/java" -XshowSettings:properties -version 2>&1 | grep -q 'os.arch = aarch64'; then
echo "JAVA_17 must be arm64 (os.arch=aarch64)" >&2
"$JAVA_17/bin/java" -XshowSettings:properties -version 2>&1 | grep os.arch >&2 || true
exit 1
fi

# robovmInstall always writes flat into INSTALL_DIR. A leftover Void.app from the
# previous wrap makes getAppDir prefer it and our old script would install that
# stale bundle instead of the freshly linked binary.
rm -rf "$APP"

cd "$IOS"
JAVA_HOME="$JAVA_17" PATH="$JAVA_17/bin:$PATH" ./gradlew --no-daemon robovmInstall \
-Probovm.arch=arm64 \
-Probovm.iosSkipSigning=false \
-Probovm.iosSignIdentity="$SIGN_ID" \
-Probovm.iosProvisioningProfile="$PROFILE"

if [[ ! -x "$INSTALL_DIR/Void" || ! -f "$INSTALL_DIR/Info.plist" ]]; then
echo "build finished but flat install missing ($INSTALL_DIR/Void)" >&2
ls -la "$INSTALL_DIR" >&2 || true
exit 1
fi

# Wrap flat installDir → Void.app for devicectl (every run, never reuse stale wrap).
mkdir -p "$APP"
shopt -s nullglob
for item in "$INSTALL_DIR"/*; do
base="$(basename "$item")"
case "$base" in
Void.app|.gitkeep|ipabuild|*.ipa) continue ;;
esac
mv "$item" "$APP/"
done
shopt -u nullglob

if [[ ! -x "$APP/Void" ]]; then
echo "failed to assemble $APP" >&2
ls -la "$APP" >&2 || true
exit 1
fi

echo "installing $APP ($(du -sh "$APP/Void" | awk '{print $1}'))…"
xcrun devicectl device install app --device "$UDID" "$APP"
if ! xcrun devicectl device process launch --device "$UDID" "$BUNDLE"; then
echo "install OK — unlock the iPad and relaunch:" >&2
echo " xcrun devicectl device process launch --device $UDID $BUNDLE" >&2
exit 1
fi
echo "OK — launched $BUNDLE on $UDID"
Loading