Skip to content

run.sh: keep the Steam overlay on macOS via STEAM_DYLD_INSERT_LIBRARIES - #121

Merged
ManlyMarco merged 1 commit into
NeighTools:masterfrom
223n:feature/macos-steam-overlay
Sep 25, 2026
Merged

ManlyMarco merged 1 commit into
NeighTools:masterfrom
223n:feature/macos-steam-overlay

Conversation

@223n

@223n 223n commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

On macOS, Steam starts a game with DYLD_INSERT_LIBRARIES set to its loader and overlay (steamloader.dylib:gameoverlayrenderer.dylib). run.sh runs under /bin/sh, which is a platform binary, so dyld strips that variable before the script sees it. So under Steam the ${doorstop_name}:${DYLD_INSERT_LIBRARIES} branch never runs: the game is started with only libdoorstop.dylib inserted, and Shift+Tab does nothing. Steam passes the same list as STEAM_DYLD_INSERT_LIBRARIES, which is not stripped, for launch scripts like this one. This change uses it when DYLD_INSERT_LIBRARIES is empty and keeps it after Doorstop, the way the Linux branch already keeps Steam's LD_PRELOAD. When DYLD_INSERT_LIBRARIES does reach the script (SIP off, or a shell that isn't a platform binary), nothing changes.

Valve's own launch scripts do the same thing (dota.sh, and cs2.sh: "Workaround OS X El Capitan 10.11 System Integrity Protection (SIP) which does not allow DYLD_INSERT_LIBRARIES to be set for system processes"). MelonLoader's melonloader-launch.sh puts its bootstrap in front of STEAM_DYLD_INSERT_LIBRARIES (LavaGang/MelonLoader#1138).

Tested on Drag'n Wash (Unity 6000.3.14f1, Mono) with BepInEx 5.4.23.5 and the ci build of master (d8973b2), on macOS 27.2, Apple A18 Pro, with archpreference="x86_64". The game was started from Steam with the launch option "<game folder>/run_bepinex.sh" %command%.

  • Before: the game was started with DYLD_INSERT_LIBRARIES=libdoorstop.dylib, Steam's console log had no GameOverlay start for it, and Shift+Tab did nothing.
  • After: DYLD_INSERT_LIBRARIES=libdoorstop.dylib:…/steamloader.dylib:…/gameoverlayrenderer.dylib, BepInEx still reached "Chainloader startup complete", and Shift+Tab opened the overlay.
  • On the first launch after the change, the first frame after the title scene loaded took 17.8 s, against 2.8 s before the change and 3.8 s on the launch after that. I have not found the cause. Each number is from a single launch.

Not run with the arm64 preference or on Intel. Both libraries in Steam's list are universal (x86_64 and arm64), so an arm64 run can load them.

/bin/sh is a platform binary, so the DYLD_INSERT_LIBRARIES that Steam
sets (its loader and overlay) is stripped before run.sh sees it, and the
game was started with only libdoorstop.dylib inserted. Steam passes the
same list as STEAM_DYLD_INSERT_LIBRARIES; use it when
DYLD_INSERT_LIBRARIES is empty and keep it after Doorstop, as Valve's
own launch scripts and MelonLoader do.
@ManlyMarco
ManlyMarco merged commit 7fcce68 into NeighTools:master Sep 25, 2026
@223n
223n deleted the feature/macos-steam-overlay branch September 25, 2026 20:51
TomXV pushed a commit to TomXV/dragnwash-localization that referenced this pull request Sep 26, 2026
… mod on macOS

The Doorstop in BepInEx 5.4.23.5 cannot hook Unity 6.3 games on macOS
(NeighTools/UnityDoorstop#108), so the script only stopped with that
known issue. It now installs the setup checked by hand in
223n/dragnwash-modframework#3: BepInEx 5.4.23.5 for macOS with the
Doorstop from UnityDoorstop's ci pre-release, pinned by SHA-256 to its
4.5.0 build (which has NeighTools/UnityDoorstop#117); the game started
as x86_64 under Rosetta, since BepInEx/BepInEx#1402 is not released; and
run_bepinex.sh handing Steam's overlay libraries on to the game. That
last change was merged upstream as NeighTools/UnityDoorstop#121, so a
run.sh from 4.6.0 on is left as it is. The script also installs the
ModFramework release mod-install.json names, the mod and the language,
sets the Steam launch option, and has a Check mode.

The ci pre-release is rebuilt under the same URL. Since it became 4.6.0
the pinned zip answers 404, so installs that have to download it stop
with a message pointing to the issue, until the stable 4.6.0 is released,
tested and pinned. A game folder that already has the pinned
libdoorstop.dylib, or --doorstop-zip with a saved copy, still installs;
--bepinex-zip and --framework-zip take local copies too.

Uninstall removes only what the script added: a marker file lists the
ModFramework parts it put there, and parts switched off in the Mods
screen are left off. run_bepinex.sh and libdoorstop.dylib are backed up
once, localconfig.vdf before every edit.

Run once on the real game on an Apple A18 Pro with macOS 27.2, over a
setup made by hand with the ci 4.6.0 Doorstop (whose libdoorstop.dylib
is the pinned one, byte for byte), so it downloaded nothing: the
translation, the Steam overlay and the F1 window worked. A fresh install
has only been run against a sandboxed game folder and Steam tree, under
/bin/bash 3.2, so the script stays experimental and out of the release
zip. The README, PLAN and ROADMAP say the same in each language.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants