From 4293ebda7f0ebb129aae0e45289a2deb2170bef6 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Wed, 15 Jan 2020 23:31:55 +0000 Subject: [PATCH] Blog post about Stardew Valley --- content/post/stardew-valley.md | 220 +++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 content/post/stardew-valley.md diff --git a/content/post/stardew-valley.md b/content/post/stardew-valley.md new file mode 100644 index 0000000..6201a5a --- /dev/null +++ b/content/post/stardew-valley.md @@ -0,0 +1,220 @@ ++++ +title = "Stardew Valley on aarch64" +date = "2020-01-15" +tags = ["PBP", "hacking"] ++++ + +#### Stardew Valley on aarch64 + +At the end of last year I got a [Pinebook Pro](https://pine64.org/pinebook-pro) - +mostly for reasons of paranoia. So far, it's been pretty good, but there was +one thing that I couldn't get working: [Stardew Valley](https://stardewvalley.com/) + +You could call me a little bit addicted to this game, but it's proprietary, +closed-source, and the authors don't release binaries compiled for aarch64 - +although they do very kindly release x86_32 and x86_64 Linux binaries, which +is more than most companies do. + +I [left a message on the forum](https://community.playstarbound.com/threads/arm-arm64-aarch64-linux-support.158840/) +and moved on, confident that it wouldn't ever happen. I vaguely knew it was +written in C#, but it's not an ecosystem I have any experience in. I figured it +was going to be the kind of thing that comes under "possible, but not trivial" - +and aarch64 + linux is super-niche. + +Fast forward a few weeks, I mentioned it in passing on the `#pinebook` IRC +channel, which went a little like: + +``` + stardew valley never got back to me *sob* + lupine: trying to get Stardew Valley on the pbp as well? + The game itself is written in C# so runs through Mono + they don't distribute aarch64-linux executables + You just need to build the libraries it needs and it should run + it's closed source, so "just need to build" is rather an issue +``` + +They rather roundly assured me that it wasn't an issue at all, and literally +10 minutes later I had a working Stardew Valley setup. This is incredible. + +I'm documenting the steps I took so I can come back to this in the future, but +maybe it'll be useful for others too. + +First, you need a copy of the game. I was working with v1.4 as shipppd by +[GOG Games](https://www.gog.com/game/stardew_valley). It comes as one of those +`.sh` files that contains an archive. That doesn't have aarch64 support, and +doesn't run on the PBP. Fortunately, I'd already installed it on an amd64 laptop +so I just rsynced that over: + +``` +lupine@pbp:~$ rsync -avzP '10.0.1.104:GOG Games' . + +# Might as well grab my savegames at the same time +lupine@pbp:~$ rsync -avzP 10.0.1.104:.config/StardewValley .config/StardewValley +``` + +I'm sure it's possible to make it run, I'm just being lazy. I'll update this in +the future if I work out how to go from the `.sh` file. + +What does this give us?: + +``` +lupine@pbp:~/GOG Games/Stardew Valley/game$ ls -lh +total 438M +-rwxrwxr-x 1 lupine lupine 12K Dec 8 23:58 BmFont.dll +drwx--x--x 17 lupine lupine 4.0K Dec 8 23:58 Content +-rwxrwxr-x 1 lupine lupine 330K Dec 8 23:58 GalaxyCSharp.dll +-rwxrwxr-x 1 lupine lupine 336 Dec 8 23:58 GalaxyCSharp.dll.config +-rwxrwxr-x 1 lupine lupine 91K Dec 8 23:58 goggame-1453375253.hashdb +-rwxrwxr-x 1 lupine lupine 782 Dec 8 23:58 goggame-1453375253.info +drwx--x--x 2 lupine lupine 4.0K Dec 8 23:58 lib +drwx--x--x 2 lupine lupine 4.0K Dec 8 23:58 lib64 +-rwxrwxr-x 1 lupine lupine 197M Dec 8 23:59 libGalaxyPeer64.so +-rwxrwxr-x 1 lupine lupine 177M Dec 8 23:59 libGalaxyPeer.so +-rwxrwxr-x 1 lupine lupine 5.3M Dec 8 23:59 libSkiaSharp.dll +-rwxrwxr-x 1 lupine lupine 119K Dec 8 23:58 Lidgren.Network.dll +lrwxrwxrwx 1 lupine lupine 14 Dec 9 00:00 mcs -> mcs.bin.x86_64 +-rwxrwxr-x 1 lupine lupine 17M Dec 8 23:59 mcs.bin.x86 +-rwxrwxr-x 1 lupine lupine 16M Dec 8 23:59 mcs.bin.x86_64 +drwx--x--x 3 lupine lupine 4.0K Dec 8 23:59 mono +-rwxrwxr-x 1 lupine lupine 2.5K Dec 8 23:59 monoconfig +-rwxrwxr-x 1 lupine lupine 1.3M Dec 8 23:58 MonoGame.Framework.dll +-rwxrwxr-x 1 lupine lupine 527 Dec 8 23:58 MonoGame.Framework.dll.config +-rwxrwxr-x 1 lupine lupine 203K Dec 8 23:58 Mono.Posix.dll +-rwxrwxr-x 1 lupine lupine 328K Dec 8 23:58 Mono.Security.dll +-rwxrwxr-x 1 lupine lupine 3.6M Dec 8 23:59 mscorlib.dll +-rwxrwxr-x 1 lupine lupine 267K Dec 8 23:58 SkiaSharp.dll +-rwxrwxr-x 1 lupine lupine 1.2K Dec 8 23:58 StardewValley +-rwxrwxr-x 1 lupine lupine 4.0M Dec 8 23:58 StardewValley.bin.x86 +-rwxrwxr-x 1 lupine lupine 3.8M Dec 8 23:58 StardewValley.bin.x86_64 +-rwxrwxr-x 1 lupine lupine 4.1M Dec 8 23:58 StardewValley.exe +-rwxrwxr-x 1 lupine lupine 6.5K Dec 8 23:58 StardewValley.GameData.dll +-rwxrwxr-x 1 lupine lupine 127K Dec 8 23:58 System.Configuration.dll +-rwxrwxr-x 1 lupine lupine 879K Dec 8 23:58 System.Core.dll +-rwxrwxr-x 1 lupine lupine 2.0M Dec 8 23:58 System.Data.dll +-rwxrwxr-x 1 lupine lupine 2.2M Dec 8 23:58 System.dll +-rwxrwxr-x 1 lupine lupine 442K Dec 8 23:58 System.Drawing.dll +-rwxrwxr-x 1 lupine lupine 966K Dec 8 23:58 System.Runtime.Serialization.dll +-rwxrwxr-x 1 lupine lupine 130K Dec 8 23:58 System.Security.dll +-rwxrwxr-x 1 lupine lupine 3.1M Dec 8 23:58 System.Xml.dll +-rwxrwxr-x 1 lupine lupine 131K Dec 8 23:58 System.Xml.Linq.dll +-rwxrwxr-x 1 lupine lupine 161K Dec 8 23:58 WindowsBase.dll +-rwxrwxr-x 1 lupine lupine 48K Dec 8 23:59 xTile.dll +-rwxrwxr-x 1 lupine lupine 9.0K Dec 8 23:59 xTilePipeline.dll +``` + +The magic here is that not all the `.dll` and `.exe` files here are **Windows** +object files. Instead, many of the are just Mono bytecode, which is analogous to +JVM bytecode: + +``` +lupine@pbp:~/GOG Games/Stardew Valley/game$ file StardewValley* +StardewValley: Bourne-Again shell script, ASCII text executable +StardewValley.bin.x86: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=4801f8881feefa8aa515f9fadc02c01598c44131, not stripped +StardewValley.bin.x86_64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=04fe4f2c2ca8b4dc7faf70c643417bf0df632a9e, not stripped +StardewValley.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows +StardewValley.GameData.dll: PE32 executable (DLL) (console) Intel 80386 Mono/.Net assembly, for MS Windows +``` + +We need Mono to run these assemblies. I guess the `StardewVelly.bin.*` files are +just stripped-down Mono runtimes that invoke `StardewValley.exe`! + +The `mcs.*` binaries are "Mono C Sharp" - I don't know C#, but I assume it's +another essential part of the runtime. + +Debian has Mono + MCS already, so... + +``` +lupine@pbp~/GOG Games/Stardew Valley/game$ sudo apt install mono-runtime mono-rcs +lupine@pbp~/GOG Games/Stardew Valley/game$ ln -sf `which mcs` +``` + +We can then try to run the game: + +``` +lupine@pbp~/GOG Games/Stardew Valley/game$ mono StardewValley.exe +``` + +Amazingly, that's **almost sufficient**, all by itself, to get a fully working +game, at least for me. It starts up, and the only obviously broken thing is +sound. There are some complaints on the comamnd line that don't seem to get in +the way of actually playing it. + +Wat. + +No sound is annoying though, how about we fix that? + +Turns out Stardew Valley only **requires** two external libraries: SDL and +libasound. I've no idea if the graphics is working even though it can't find +SDL, or if it can find my native SDL libary but not the libasound one, or what, +but it's trivial to fix. Edit `MonoGame.Framework.dll.config` and add these +two lines: + +``` + + +``` + +Now you just need to put those two .so files into that directory locally, and +sound begins to work! + +(I just symlinked `/usr/lib/aarch64-linux-gnu` into place, which does the same +job). + +At this point the game works perfectly, including LAN multiplayer - which is +ridiculous - and despite worries about endianness, it can load and run my saves +as well. + +There are a few complaints on the console though. Let's see what we can do +about them. + + +``` +Your mono runtime and class libraries are out of sync. +The out of sync library is: /home/lupine/GOG Games/Stardew Valley/game/System.dll +``` + +OK, these are shipped with `mono-runtime` (actually in `libmono-system4.0-cil`) +anyway. The complaint is that these assemblies were compiled with a different +version of Mono, but it's falling back to the main ones anyway, so we can just +move these out of the way. + +The only `System.*.dll` file we need to keep is `System.Runtime.Serialization.dll` - +the rest can be moved out of the way. + +``` +System.TypeInitializationException: The type initializer for 'Galaxy.Api.GalaxyInstance' threw an exception. ---> System.TypeInitializationException: The type initializer for 'CustomExceptionHelper' threw an exception. ---> System.DllNotFoundException: GalaxyCSharpGlue + at (wrapper managed-to-native) Galaxy.Api.GalaxyInstance+CustomExceptionHelper.CustomExceptionRegisterCallback(Galaxy.Api.GalaxyInstance/CustomExceptionHelper/CustomExceptionDelegate) + at Galaxy.Api.GalaxyInstance+CustomExceptionHelper..cctor () [0x00011] in <22373852dcce42128dc7e065ea92368d>:0 + --- End of inner exception stack trace --- + at (wrapper managed-to-native) System.Object.__icall_wrapper_mono_generic_class_init(intptr) + at Galaxy.Api.GalaxyInstance..cctor () [0x00000] in <22373852dcce42128dc7e065ea92368d>:0 + --- End of inner exception stack trace --- + at StardewValley.SDKs.GalaxyHelper.Initialize () [0x00000] in <1ed49e648be548bcae8e4508597c9f4c>:0 + +``` + +I am **astonished** that this one isn't a fatal error - but the game runs fine +even though it can't find an external library. Ridiculous. + +Galaxy is GOG's multiplayer gubbins. If you've got a Steam game, it's different, +I'm sure, but the functionality this stuff is *for* is to negotiate multiplayer +games with strangers. + +I have no use for this myself, but `libGalaxyCSharpGlue.so` is looked up via +another dllmap in `GalaxyCSharp.dll.config` - it's not packaged by Debian, and +it may even be proprietary GOG code, but if we can get an aarch64 version of it, +making it work should be as simple as adding an entry there. + +If this did become a fatal error at some point, the minimum work would be a stub +implementation that meets the ABI but always says "no games available" or some +such. + +And... that's all the errors. Despite a different architecture, despite being +short some libraries, and despite running reverse-engineered (Panfrost) graphics +drivers with only a bare whisper of OpenGL support, my favourite game is running +at normal speed on an architecture its authors and publishers didn't even think +about. + +Again I say: ridiculous + +...maybe I should learn some CSharp?