Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initial test on Balatro+ (App Store and Apple Arcade edition) #86

Open
yozlet opened this issue Oct 17, 2024 · 10 comments
Open

initial test on Balatro+ (App Store and Apple Arcade edition) #86

yozlet opened this issue Oct 17, 2024 · 10 comments

Comments

@yozlet
Copy link

yozlet commented Oct 17, 2024

If anyone's thinking of adding support for the Mac App Store version of Balatro, and the Apple Arcade ("Balatro+") release, here's some initial information from a couple of hours playing around with it. Caveats: I have very little lua experience and even less rust, nor am I an iOS/macOS developer, so consider everything here vague at best and unverified. I haven't even bought Balatro on Steam, so all my experience is with the AA version on iPadOS and macOS.

All the exploration below is with the macOS version of Balatro+, though I'm guessing the packages for the other Apple OSes have very few differences: the source includes the logic for iOS/iPadOS and tvOS. Similarly, it would surprise me if there's any major difference between the non-Arcade App Store package and the Apple Arcade Balatro+ package.

The Balatro+ (Apple Arcade version) package includes:

  • the game's (updated for Apple OSes and APIs) lua source and assets in Contents/Resources/game/

  • a custom binary launcher: Contents/MacOS/Balatro

  • a license.txt which specifies:

    Clockwork Valley ("Licensor") grants LocalThunk, inc ("Licensee") a non-exclusive, non-transferable, revocable license to access and use the software solely for the purpose of assisting in the development of Balatro Arcade.

(According to the file, Clockwork Valley is Maarten de Meyer. The file also lists these open source components: LOVE, ENet, FreeType, GLAD, glslang, Kepler Project's lua-compat-5.3, lua-enet, LuaJIT, Lua's UTF-8 module, LuaSocket, LZ4, LodePNG, TinyEXR, UTF8-CPP, xxHash, dr_flac, stb_image, libmpg123, OpenAL Soft.)

My guess is that the Balatro binary is basically love but with extra logic compiled in for exposing Core Data, CloudKit, GameKit, and other Apple APIs, all gathered into a love.platform table.

Fascinatingly – and wonderfully – most if not all of the new logic that uses those APIs seems to be out in the relative open in the included lua source, rather than more hidden in that custom binary. You can, for example, see lots of specific handling for tvOS.

So that's the good news. Now for some bad news:

  • you can't modify the lua source, even as root - I'm guessing it's all covered by SIP
  • the Balatro binary appears to be closed off to the dyld hijacking trick that the macOS version of lovely uses. (I tried compiling and using the much simpler tool on that page, and verified that it worked on the standard love binary.)

At this point I need to stress that I am not an experienced C or macOS hacker, and I may well have missed some major windows that are still open. More importantly, the Balatro binary could have been written with command line arguments that allow for custom logic injection, even though the standard love command doesn't have any. (Maybe we should just ask Maarten de Meyer.)

Talking of the standard love command, what happens when you point a normal love2d build at Balatro+'s game folder? It actually gets pretty far: it produces a nice big window, loads the m6x11plus.ttf font, and uses it to display the traceback showing that it got about three lines into main.lua's love.load event before hitting a call to love.platform.earlyInit - which, of course, doesn't exist in the standard love2d API.

But that's far enough to show that those new APIs are what's getting in the way, and fortunately all the interaction points are clear in the lua code. Some of those methods are easily stubbed/faked, but others have been moved in as the primary load-bearing I/O points for loading and saving the player's profile and progress.

The main issue I hit with lovely: currently, on macOS, it demands that love exist within a .app folder - why? I was using a homebrew-installed binary and ended up commenting those lines out and rebuilding. (Yes, I could have faked it, but I was in the source anyway.)

I'm leaving this here for now. I'm happy to answer questions and try things out, but please don't expect me to do much more work on this. Others who have more experience will likely get much further, faster.

@yozlet yozlet changed the title initial work on Balatro+ (Apple Arcade edition) initial test on Balatro+ (Apple Arcade edition) Oct 17, 2024
@yozlet yozlet changed the title initial test on Balatro+ (Apple Arcade edition) initial test on Balatro+ (App Store and Apple Arcade edition) Oct 17, 2024
@WilsontheWolf
Copy link
Contributor

Does the balatro .app have a Frameworks/Lua.framework from the apple arcade? If not it's probably like the iOS version, which I've been working on trying to get lovely to work on, but haven't quite got success

@yozlet
Copy link
Author

yozlet commented Oct 20, 2024

@WilsontheWolf No Frameworks/ folder and no .framework files anywhere. Yup, I'm fairly sure this is the same as the iOS version.

In the meantime, I've made a little more progress since my first message. I'm following the path of using the supplied Balatro binary to read a modified version of the game's source, rather than trying to get the standard love command to work. This is because of all the extra love.platform functions - I'd rather not have to stub or reimplement them yet.

The Balatro binary seems to accept a couple of the same flags that love does:

/Applications/Balatro.app/Contents/MacOS/Balatro --version prints LOVE 11.5 (Mysterious Mysteries) - so yes, this is basically a love build with extra stuff thrown in.

/Applications/Balatro.app/Contents/MacOS/Balatro --game $NAME looks for a folder relative to the game's save data location, which is ~/Library/Containers/com.playstack.balatroarcade/Data/.

I tried copying the game/ folder (which has all the lua source and resources) out of /Applications/ and into somewhere more usable, then added a symlink to it in the Data/ folder above.

/Applications/Balatro.app/Contents/MacOS/Balatro --game game tries to run the copied game folder but produces this error:

Error: [love "boot.lua"]:278: module 'conf' not found:
	no field package.preload['conf']
	no file 'conf' in LOVE paths.
	no file './conf.lua'
	no file '/usr/local/share/luajit-2.1/conf.lua'
	no file '/usr/local/share/lua/5.1/conf.lua'
	no file '/usr/local/share/lua/5.1/conf/init.lua'
	no file './conf.so'
	no file '/usr/local/lib/lua/5.1/conf.so'
	no file '/usr/local/lib/lua/5.1/loadall.so'
stack traceback:
	[love "boot.lua"]:354: in function <[love "boot.lua"]:350>
	[C]: in function 'error'
	[love "boot.lua"]:278: in function <[love "boot.lua"]:126>
	[C]: in function 'xpcall'
	[love "boot.lua"]:364: in function <[love "boot.lua"]:357>
	[C]: in function 'xpcall'

... which is weird, since there's definitely a conf.lua in that folder. I've also tried running this command while my working directory is the game folder (so ./conf.lua exists) but it still can't find it.

Note that when invoking Balatro --game $NAME, it shows a different error depending on whether the $NAME path resolves to a folder with a main.lua file in it. So it's definitely finding the right folder and trying to run it. But for some reason, that bit of boot.lua (which is in the Balatro binary) isn't looking in the same folder for conf.lua. And yet, when $NAME points to the original game folder (inBalatro.app/Contents/Resources/game/) it starts up just fine.

@WilsontheWolf
Copy link
Contributor

Okay. In that case, you can probably extract the game.love and stick it into a regular macos build of balatro, and then you should be able to use lovely

@yozlet
Copy link
Author

yozlet commented Oct 20, 2024

... and minutes later, some actual success:

The problem seems to be that the Balatro binary can't properly read files outside of the /Applications/Balatro.app/ folder. (See, I'd probably know things like this if I was a proper macOS dev.) So I (as root) copied /Contents/Resources/game/ to /Contents/Resources/moddedgame/, tweaked some of the strings in the en-us.lua locale file, and ran

/Applications/Balatro.app/Contents/MacOS/Balatro --game '/Applications/Balatro.app/Contents/Resources/moddedgame/'

... and it booted up fine, and showed the altered strings. Even better, it loaded my saved game profile as normal.

So I'm thinking that a modding process that copies the source over and runs the lua transformations on the copied version may be enough here?

@yozlet
Copy link
Author

yozlet commented Oct 20, 2024

@WilsontheWolf Yep, either keeping it unzipped or compressing to a .love file, either should work as long as it ends up in the Balatro.app folder.

@scj643
Copy link

scj643 commented Dec 2, 2024

So the reason why it cant see files outside of the Balatro.app folder is because of App Sandbox.

It can access files in the .app and ~/Library/Containers/com.playstack.balatroarcade

Also the app has com.apple.security.cs.disable-library-validation so injection should be possible with a code signed library.

@scj643
Copy link

scj643 commented Dec 2, 2024

Also the Apple Arcade version on the Mac is not the same as the non Apple Arcade version since the non Apple Arcade version is iOS only.

@scj643
Copy link

scj643 commented Dec 2, 2024

Just tested what you did earlier and having it in ~/Library/Containers/com.playstack.balatroarcade/Data/ and running with --game works.

@gallantcrusader
Copy link

bump to see y'alls progress

@scj643
Copy link

scj643 commented Dec 20, 2024

Another thing to know. The binary file in Balatro.app is FairPlay encrypted so doing stuff with the binary is most likely a dead end. It won't be easy to mod the Apple Arcade version without just manually patching the game files.

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

No branches or pull requests

4 participants