Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Goldberg macOS Steamworks compatibility shim

A compatibility shim that lets an older Goldberg Steam Emulator libsteam_api.dylib work with games built against a newer Steamworks SDK (1.58 or later) on macOS.

Goldberg isn't bundled. Grab a macOS build yourself (for example from the inflation/goldberg_emulator releases) and drop its libsteam_api.dylib into place. The shim wraps that dylib: it keeps every symbol Goldberg already provides and only fills in the newer entry points that recent games look for.

Why you'd want Goldberg at all: if the game isn't on your Steam account (e.g. a pirated copy) and you launch it without an emulator, Steam refuses to start it with a license error. Goldberg stands in for the Steam client so the game starts; this shim just keeps an old Goldberg build working with newer games.

The problem

Games using a recent steam_api / Steamworks.NET fail on an old Goldberg build, first with:

System.EntryPointNotFoundException: Unable to find an entry point named
'SteamInternal_SteamAPI_Init' in shared library 'steam_api'.

and then, once that's resolved, a silent init failure (Everest/Celeste logs Steam not found! and quits).

Two SDK changes that old Goldberg builds predate cause this:

  1. SteamInternal_SteamAPI_Init, the flat init entry point added in SDK 1.58. Old Goldberg never exported it.
  2. ISteamTimeline (STEAMTIMELINE_INTERFACE_V001, added in 2024). Wrappers like Steamworks.NET's CSteamAPIContext.Init() fetch every interface and abort if any returns NULL. Old Goldberg doesn't implement Timeline, so init failed even though the game never touches it.

What the shim does

  • Adds SteamInternal_SteamAPI_Init and forwards it to Goldberg's legacy SteamAPI_Init().
  • Returns a no-op object from SteamInternal_FindOrCreateUserInterface for any interface Goldberg returns NULL for, so all-or-nothing init succeeds.
  • Reads the AppID from the sibling steam_appid.txt on load, which fixes launches from Finder (working directory is /).
  • Re-exports everything else from your Goldberg dylib unchanged.

Requirements

  • macOS with the Xcode command line tools (clang, nm, codesign, install_name_tool).
  • An existing Goldberg libsteam_api.dylib already placed where the game loads it. This tool does not provide one.

Usage

# point it at the folder containing your Goldberg libsteam_api.dylib
./install.sh /path/to/game/libdir

The installer backs up your original to libsteam_api.goldberg-orig.dylib, builds a universal (x86_64 + arm64) shim, installs it as libsteam_api.dylib, ad-hoc signs it, and clears the quarantine flag. Re-running is safe.

AppID

Goldberg needs the game's Steam AppID. The shim reads it from a steam_appid.txt file (one line, just the number) next to libsteam_api.dylib, and sets the SteamAppId/SteamGameId environment variables from it so launches from Finder work. The AppID is in the game's Steam store URL, e.g. store.steampowered.com/app/504230/ means 504230. You can also set SteamAppId in the environment yourself instead.

steam_appid.txt for Celeste is just:

504230

Other things worth knowing

  • The shim only re-exports the architectures your Goldberg dylib actually contains. If the game runs as x86_64 under Rosetta, the dylib needs an x86_64 slice; check with lipo -archs libsteam_api.dylib.
  • Goldberg's own configuration (save location, achievements, DLC, unlocks) lives in a steam_settings folder next to the dylib. The shim leaves all of that alone; see the Goldberg docs to set it up.
  • If a game uses a hardened runtime with library validation it may reject an ad-hoc signed dylib. The games this was tested with load it fine, but that's a possible failure mode elsewhere.

To revert:

cd /path/to/game/libdir
cp libsteam_api.goldberg-orig.dylib libsteam_api.dylib
codesign -s - -f libsteam_api.dylib

How it works

The shim is one C file linked with -reexport_library against your renamed Goldberg dylib, so the final libsteam_api.dylib exports the shim's overrides plus every original Goldberg symbol. See src/shim.c and install.sh.

Notes

  • Verified with Celeste + Everest. Other games may request additional newer entry points; the same approach extends to them.
  • The Timeline stub is a no-op, which is fine for games that don't use Steam Timeline. A game that actually calls into an unimplemented interface would need a real implementation.
  • This is an interoperability and game-preservation tool, meant for things like LAN/offline play and testing without the Steam client. Only use it with software you're entitled to run, and follow the rules that apply to you.

Credits and license

Builds on the Goldberg Steam Emulator (LGPL-3.0) and its forks. Goldberg is not included here; supply your own dylib.

The shim source is MIT licensed (see LICENSE). It dynamically links and re-exports Goldberg at install time rather than bundling it, so it's a separate work; redistributing a Goldberg binary is still subject to Goldberg's own license.

About

A compatibility shim that lets an older Goldberg Steam Emulator libsteam_api.dylib work with games built against a newer Steamworks SDK (1.58 or later) on macOS.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages