Or: How to save GameMaker: Studio 1.4 games from YoYo Games Ltd neglect
I recently published a game built in GameMaker: Studio 1.4 (GM:S1) for Linux (and Windows). It was a process. No, it was 100 times that. Not only that, but I ran into others with similar troubles who were getting a general ¯\_(ツ)_/¯ response. I aim to fix that here.
Hopefully, this may also help to run on more Linux flavors than just Ubuntu.
If you are a gamer hoping to fix a game you found (such as Legend of Xenia, Spelunky SD or Spelunky Classic HD), jump to the “Include all needed libs” section and follow the hint. If you are getting a message regarding libcrypto.so.1.0.0
missing or libcurl.so.4
errors, you are definitely in the right place.
Links
First, I want to point you to the sites that saved me. They aren’t required reading here, but they should help if you get stuck or need to diverge from what’s here.
YoYo’s own post is probably required reading even though it, um, uh, well:
32-bit Linux limitation for no good reason
GM:S1 targets only 32-bit Linux. This terribly odd given that their Linux dev setup instructions are for 64-bit Linux. Furthermore, my GM:S1 install includes a make file for 64-bit Linux but no 64-bit library (libyoyo_yyc-x64.a
) to go with it. (I wonder if any other 1.x releases had it.)
This is not terribly surprising given YoYo’s rotten bait-and-switch business practice. They sold v1 at a deep discount on Humble Bundle a few months before release of v2 (with no clue to this given on Humble Bundle). Only then to desupport v1 only a year after that. v2 didn’t contain much new other than, maybe, 64-bit and other new target platforms. That’s a horrible reason to hold back on 64-bit support, in my opinion, especially given the high cost of the upgrade.
I wonder if the OSX lib is 64-bit? It would be insane if that was only 32-bit since that expired in, what?, 2011! I wonder if it is linkable in Linux with clang? Doubtful. Enough wondering.
Okay, done with the hating, onto the fixing.
Build on Ubuntu 14.04, 32-bit
Ubuntu 14.04 was the supported target version of GM:S 1.4.
Okay, so you’ve got only one Linux box and it’s running something else. Cool. But… I’m guessing that Ubuntu 14 runs pretty okay for the occasional GM:S build on an 8GB USB stick. I haven’t tried it yet… but I did boot Ubuntu 16 from a DVD once and that wasn’t too terribly bad… once.
[[I’m fortunate to have an eSATA port on my old laptop, for which I bought a cable (12v/5v eSATA to 22-pin SATA) and a stack of salvaged 2.5″ HDs — all for maybe $20. My Ubuntu 14 install takes only 4.9GB on one of those HDs. That’s the default install, so, less if you whack the office apps etc.]]
You should be able to build fine on 64-bit Ubuntu 14.04, but I was having trouble installing 32-bit multi-architecture support on this so I just installed 32-bit Ubuntu 14.04 instead. Keep it simple.
I succeeded at testing and building on 64-bit Mint 19.2 as well, but this build wasn’t terribly compatible with older Linux versions. Thus, test on what suits you but… Do your final build on the oldest version of Linux you want to target.
Dev env setup
You can install that longer list of packages that YoYo recommends, but this all that I found to be necessary for YYC builds on 32-bit Ubuntu 14.04. (P-code builds can probably leave out clang
and libssl-dev
, but I haven’t verified that yet. They don’t hurt p-code builds on Ubuntu 14.)
sudo apt update sudo apt install openssh-server sudo apt install clang sudo apt install libopenal1 sudo apt install libssl-dev
Build to ZIP
Always build to ZIP. Then, uh, ignore the ZIP. We’re gonna work with the files it created before zipping them up.
BTW, you can totally shorten those default build directories to something more like:
- Linux Install Dir: gamemaker
- Application Install Dir: gamemaker
Include all needed libs
Hint: If you trust my packaging, you can skip the rest of this by just grabbing my River Raid Squadron game and copying its lib folder and launch script (the script will need to be edited with the name of your game). You may also need to read my help for running on 64-bit linux.
This is where it gets interesting and where those links up top saved the day.
If you ldd
a YYC build of your game, you will get a long list of dependencies. This is everything I needed to copy to meet those dependencies, aside from built-in and other very standard libraries:
mkdir lib cd lib cp -av /lib/i386-linux-gnu/libssl.so.1.0.0* . cp -av /lib/i386-linux-gnu/libcrypto.so.1.0.0* . cp -av /usr/lib/i386-linux-gnu/libXrandr.so.2* . cp -av /usr/lib/i386-linux-gnu/libXrender.so.1* . cp -av /usr/lib/i386-linux-gnu/libopenal.so.1* . cp -av /usr/lib/i386-linux-gnu/libcurl.so.4* . cp -av /usr/lib/i386-linux-gnu/libidn.so.11* . cp -av /usr/lib/i386-linux-gnu/librtmp.so.0* . cp -av /usr/lib/i386-linux-gnu/libgnutls.so.26* . cp -av /lib/i386-linux-gnu/libgcrypt.so.11* . cp -av /lib/i386-linux-gnu/libgpg-error.so.0* . cp -av /usr/lib/i386-linux-gnu/libpulse.so.0* . cp -av /usr/lib/i386-linux-gnu/pulseaudio/libpulsecommon-11.1.so* . cp -av /lib/i386-linux-gnu/libdbus-1.so.3* . #cp -av /lib/i386-linux-gnu/libgcrypt.so.20* . #cp -av /lib/i386-linux-gnu/libgpg-error.so.0* . #cp -av /lib/i386-linux-gnu/liblzma.so.5* . #cp -av /lib/i386-linux-gnu/libsystemd.so.0* . cp -av /lib/i386-linux-gnu/libwrap.so.0* . cp -av /usr/lib/i386-linux-gnu/libasyncns.so.0* . cp -av /usr/lib/i386-linux-gnu/libFLAC.so.8* . #cp -av /usr/lib/i386-linux-gnu/liblz4.so.1* . cp -av /usr/lib/i386-linux-gnu/libogg.so.0* . cp -av /usr/lib/i386-linux-gnu/libsndfile.so.1* . cp -av /usr/lib/i386-linux-gnu/libvorbisenc.so.2* . cp -av /usr/lib/i386-linux-gnu/libvorbis.so.0* . cp -av /lib/i386-linux-gnu/libjson-c.so.2* . cp -av /usr/lib/i386-linux-gnu/libgssapi_krb5.so.2* . cp -av /usr/lib/i386-linux-gnu/liblber-2.4.so.2* . cp -av /usr/lib/i386-linux-gnu/libldap_r-2.4.so.2* . cp -av /usr/lib/i386-linux-gnu/libkrb5.so.3* . cp -av /usr/lib/i386-linux-gnu/libk5crypto.so.3* . cp -av /lib/i386-linux-gnu/libcom_err.so.2* . cp -av /usr/lib/i386-linux-gnu/libkrb5support.so.0* . #cp -av /lib/i386-linux-gnu/libresolv.so.2* . #cp -av /lib/i386-linux-gnu/libresolv-2.* . cp -av /usr/lib/i386-linux-gnu/libsasl2.so.2* . cp -av /usr/lib/i386-linux-gnu/libgssapi.so.3* . cp -av /usr/lib/i386-linux-gnu/libtasn1.so.6* . cp -av /usr/lib/i386-linux-gnu/libp11-kit.so.0* . #cp -av /lib/i386-linux-gnu/libgpg-error.so.0* . cp -av /lib/i386-linux-gnu/libkeyutils.so.1* . cp -av /usr/lib/i386-linux-gnu/libheimntlm.so.0* . cp -av /usr/lib/i386-linux-gnu/libkrb5.so.26* . cp -av /usr/lib/i386-linux-gnu/libasn1.so.8* . cp -av /usr/lib/i386-linux-gnu/libhcrypto.so.4* . cp -av /usr/lib/i386-linux-gnu/libroken.so.18* . cp -av /usr/lib/i386-linux-gnu/libffi.so.6* . # Added for Ubuntu 20 cp -av /usr/lib/i386-linux-gnu/libwind.so.0* . cp -av /usr/lib/i386-linux-gnu/libheimbase.so.1* . cp -av /usr/lib/i386-linux-gnu/libhx509.so.5* . cp -av /usr/lib/i386-linux-gnu/libsqlite3.so.0* . #cp -av /lib/i386-linux-gnu/libcrypt.so.1* . #cp -av /lib/i386-linux-gnu/libcrypt-2.* . cp -av /lib/i386-linux-gnu/libz.so.1* . cp -av /usr/lib/i386-linux-gnu/libGLU.so.1* .
Side note: libz.so.1
wasn’t really needed but, because it is the first that pops up if not having 32-bit Mesa packages on your 64-bit OS yet, it can be a red herring. It’s only 100kB so it adds less than 1% to the total size.
Also note the ones I commented out. They aren’t needed but I didn’t remove them from the list for… I don’t know why. Maybe I suspect they’ll come back and bite me later.
Anyway, this amounts to 86 files/linked files. Just under 14MB. Not great; but not too bad for a game engine either.
Note that this is for YYC builds but also works for p-code builds. If you really want to know, the p-code list of libs is probably quite a bit shorter, but I haven’t gotten around to narrowing that down yet. I’ll add more info here if and when I do.
CAUTION: Be aware that if you build (or are trying to run a game that was built) on another version of Ubuntu, these libs can shift slightly to other versions and those games may or may not work with this set. Maybe someday I’ll post a complete resource for all possible permutations (if there is any demand for it) but not today.
You will need a launch script
In order to set the env to find those libs, you need a launch script. This is the script I use for testing (the filename is test
):
#!/bin/bash # Adapted from: # https://itch.io/docs/itch/integrating/platforms/linux.html # Move to exe's directory (required for audio libs) cd "`dirname "$0"`" # Set the libpath and execute the binary export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib/ exec ./River_Raid_Squadron $@
Drop this in the same folder as your game (~/gamemaker/yyc/River_Raid_Squadron) and change the filename on the last line to match your game. (Make sure the script has execute privs.)
Of course, running this on your Ubuntu 14 build box doesn’t really test much. You can copy it to another box and test, or you can move on to the next step before testing.
Prep for packaging
Okay, this gets a little weird because I want to shift files and folders around so that the user sees only one executable point of entry to the game. Solve this part how you like, this is how I chose to do it.
In short, I wrote a script to copy and rename the script and executable, and copy in the assets and lib folder, to look like this:
Some Game/ game x86/ game.x86 assets/ lib/
I also edit the launch script for the new location and names.
Here’s my script:
#!/bin/bash gmsname="River_Raid_Squadron" gamename="River Raid Squadron" shortname="rrs" arch="x86" exename="$shortname.$arch" version_in="Game/gml_Script_Title.gml.cpp" yellow="\e[33m" ltyellow="\e[1;33m" colorend="\e[0m" if test -d "$gamename"; then echo Clearing folder: $gamename rm -fr "$gamename"/* else echo Making folder: $gamename mkdir "$gamename" fi mkdir "$gamename/$arch" echo Copy with renaming: echo -ne $yellow cp -av "yyc/$gmsname/$gmsname" "$gamename/$arch/$exename" cp -av "yyc/$gmsname/test" "$gamename/$shortname" echo -ne $colorend echo Copying lib and assets folders... cp -a "yyc/$gmsname/lib" "$gamename/$arch" cp -a "yyc/$gmsname/assets" "$gamename/$arch" echo echo Parsing out the version into VERSION.txt... egrep -oh "[0-9]+\.[0-9]+\.[0-9]+" "yyc/$gmsname/$version_in" > $gamename/$arch/VERSION.txt" echo -ne $ltyellow cat "$gamename/$arch/VERSION.txt" echo -ne $colorend echo echo Editing launch script from: echo -ne $yellow grep "$gmsname\|$exename" "$gamename/$shortname" echo -ne $colorend sed -i "s/\bexec\b/cd $arch; exec/" "$gamename/$shortname" sed -i "s/$gmsname/$exename/" "$gamename/$shortname" echo Edited launch script to: echo -ne $ltyellow grep "$gmsname\|$exename" "$gamename/$shortname" echo -ne $colorend # If using butler with itch.io, validate what we just did. #~/itchio/butler/butler validate "$gamename" echo read -p "Press [Enter] to continue..."
Here’s the output launch script with the last line changed:
#!/bin/bash # Adapted from: # https://itch.io/docs/itch/integrating/platforms/linux.html # Move to exe's directory (required for audio libs) cd "`dirname "$0"`" # Set the libpath and execute the binary export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib/ cd x86; exec ./rrs.x86 $@
Why not just start with that launch script? You can. This is just the workflow that works best for me at the moment. (One could, of course, also combine the two cd
commands. Up to you.)
Packaging
From here, packaging is up to you. A zip of the Some Game
folder from above would be enough. Or, you could follow Ethan Lee’s advice (that second link up top) and use MojoSetup for packaging.
Personally, I have a script that sends that folder to itch.io via butler, and that’s all I need for distribution (no zip needed). I have another script that zips it up and tags it with a version number simply for archiving. I could share those scripts but they feel beyond the point of this post.
32-bit on 64-bit
This is info you may need to pass on to your users (from my game’s help post here):
If running 64-bit Linux, you need to install multi-architecture (multiarch) support for i386, if it didn’t come built into your flavor. It’s hard (impossible) to find authoritative sites on how to do this… so, basically (and at your own risk, of course), for Ubuntu 14+ and GM:S games:
sudo dpkg --add-architecture i386 sudo apt update sudo apt install libc6-i386 sudo apt install libstdc++6:i386
If wanting more help, this site came the closest: https://unix.stackexchange.com/questions/12956/how-do-i-run-32-bit-programs-on-a…
You will also need to install i386 support for Mesa/OpenGL/X11 (whatever you want to call it) if your graphics drivers didn’t install it/these already. Again, I found no authoritative source for this. (Hint: UDPATE: 32-bit mesa-utils is now dead in Ubuntu 20. Hint: mesa-utils:i386
is all you may need — although, be forewarned that installing this has been known to uninstall your desktop environment, such as Cinnamon. Watch for such funny business and compensate as needed.libgl1:i386
is all you may need.)
C is a basic requirement, and I consider the standard packages from C++, Mesa, OpenGL, and X11 to be common enough to expect most users to already have them. And, if not, they should if they expect most games to run. (There are a few less-standard libs from this group that I do provide: libGLU, libXrandr, and libXrender.) Side note: common collision points if missing the standard packages are libstdc++.so.6
and libXxf86vm.so.1
.
Miscellaneous GameMaker issues
- For me, at least, code changes don’t make it into YYC builds. P-code builds run fine but YYC builds do not. Both Linux and Windows. I found no help on this so, dunno, maybe I broke something unique in GM:S — maybe when I renamed my project, because GM:S names the build according to folder name instead of the name in project settings! Or, maybe, few do YYC builds to ZIP (I doubt ZIP has anything to do with it, however). Eventually, I found the YYC build cache and saw that YYC builds never update files in the cache if they already exist. Thus, I have to manually clear it out before final build. Ugh.
- My GM:S install had set its temp folder to AppData\Local instead of AppData\Local\Temp, which is stupid. Change it and then go clean out all the
gm_*
folders and random????????.???
files from Local (again, at your own risk).
UPDATE June 2021: Linus Torvalds appears to agree that including all the libraries like this, as very large distributions of binaries, is the only solution for Linux desktop (what he says Valve is now doing). He also explains why I didn’t have to include the core libraries (yet). Basically, library developers keep breaking their libraries by “fixing” them; and it’s a continuous fight for him to keep others from breaking the core libraries.
this is an almost complete how-to GMS1.x + AppImage guide haha it works great, thanks. although you also need to include libffi.so.6 to run in 21.04 (latest version as of this comment) but yeah you can skip the launch script if you pack it as an appimage instead!
LikeLiked by 1 person
Ah, man, libffi is not standard anymore?… or they broke it? Ugh. Thanks for the note. I don’t remember why, exactly, I left it out. Looks like it is part of both clang and mesa-utils:i386. Do you not need mesa-utils:i386 in your setup? Next thing you know, I’ll need to include all of libc6! Anyway, yes, I’ll take another look if I ever get back to finishing River Raid Squadron — which I hope will be soon.
LikeLike
I finally got back around to publishing an update to RRS. I dug into the libffi thing and found that mesa-utils:i386 appears to be dead as of Ubuntu 20. Digging deeper I found that libgl1 has moved on from libffi6 to libffi7 which, of course, breaks things like a good Linux package always does. Anyway, yes, thanks for the note. I’ve updated RRS and this post accordingly.
LikeLike