Compare commits

...

23 commits

Author SHA1 Message Date
Miepee 47da221fa8 replace readme 2022-11-23 10:41:57 -06:00
Miepee e724b84c04 replace patches 2022-11-23 10:34:00 -06:00
Miepee d4cf843bcf
readme: make java dependencies clearer 2022-11-09 12:14:17 +01:00
Miepee 119bce6269 Use final path for desktop file replacement
Fixes #34
2022-11-09 12:12:43 +01:00
Miepee 56d7dd2d36 Fix wrapper unable to find the runner for real
Fix #32
2022-09-30 10:15:36 +02:00
Miepee d378132085 change way of executing unwrapped runner. 2022-09-29 21:39:37 +02:00
Miepee d34314b707 Comment out patchelf instructions, make moving of hidden files work 2022-09-29 14:32:42 +02:00
Miepee df69e1a369
Fix formatting, make appimage work (#31) 2022-08-14 23:53:03 +02:00
Ivv 3e2121c854
Patch out insecure dependencies and add NixOS instructions (#30)
* Patch out insecure dependencies and add NixOS instructions

This commit uses `patchelf` to remove the dependency on OpenSSL 1.0,
which is outdated and considered insecure. It replaces this dependency
with libcurl, of which the latest version works just fine.

This should make sure that any distrobution can run the generated binary
out of the box, without needing a dynamically linked placeholder.

I also noticed the game failed to start on my AMD machine, and after looking
through Mesa's Gitlab I found a workaround using an environment variable.
A wrapper bash script that sets this variable and executes the `runner` binary
is created to take care of this automatically.

This commit adds instructions on how to run the game on NixOS as well.

* readme: gramar fixes

* patcher: fix syntax error

* readme: add some codeblocks
2022-08-14 23:24:49 +02:00
Miepee 7d180c1dad
Rewrite patcher in Bash (#29)
* Add shell patcher

* Readme changes, exclude apk from git, slight android cleanage

* Implement review suggestions

- put main routine into seperate function
- use locals
- make some input access safe
- use tempdir for appimage creation
- check whether Java / xdelta is installed
- print errors to stderr
- Improve APK creation by copying less, and using tempDirs

Co-Authored-By: Ivv <41924494+ivarwithoutbones@users.noreply.github.com>

* Applied more review comments

- mention the new dependencies
- make linux default OS
- make patcher not create in a subdir into prefix with local
- change return to exit for non-0
- better indicate arguments
- remove unneded dirs from cleaning

Co-Authored-By: Ivv <41924494+ivarwithoutbones@users.noreply.github.com>

* Fixes mostly android bugs

- Removed credits
- make android builds not have unnecessary assets
- fix "is-installed" check
- Make android properly ignore systemwide

* Some more slight cleanups

- rename OUTPUT to GAMEDIR to be more understandable

* Fix application icon not being according to XDG in systemwide install

* Make accidental deletion of important folders impossible

Co-authored-by: Ivv <41924494+ivarwithoutbones@users.noreply.github.com>
2022-08-11 20:08:01 -05:00
Miepee 9175d9597c
fix typo 2022-07-27 12:32:14 +02:00
Miepee 7a3c8cb972 Rename custom suit folders to lowercase 2022-02-12 15:22:50 +01:00
Miepee d723f80592
Merge pull request #27 from AM2R-Community-Developers/gpu-fix
Gpu fix
2022-01-07 11:10:20 +01:00
Miepee 38da06337a
remove intel specific gpu workaround 2021-11-18 16:15:51 +01:00
Miepee 1fd4db41cf Put back x11 extension libs 2021-11-13 20:37:29 +01:00
Miepee e3b01200f3 add python shebang + install python3 on ubuntu because they're dumb 2021-11-11 12:28:54 +01:00
Miepee 7af143f1d3 dont use symlink, rename instead 2021-11-08 14:32:01 +01:00
Miepee f25eeedb89 remove GPU libs to test if those work on non-amd too 2021-11-04 10:50:58 +01:00
Miepee 2ffb6a38b3 attempt at integrating env vars into appimage 2021-11-03 21:32:29 +01:00
Miepee b69ea9ecb7
forgot argument for amd env var 2021-09-27 09:24:18 +02:00
Miepee dfc080f012
Mention GPU workarounds in readme 2021-09-27 09:21:43 +02:00
Miepee aff34ac0f8
Fix readme typo 2021-09-22 13:09:36 +02:00
Miepee 0e938101e5
Fixes #26 2021-09-22 12:57:39 +02:00
62 changed files with 409 additions and 338 deletions

7
.gitignore vendored
View file

@ -1,3 +1,4 @@
am2r_15_2/
ARCHIVE-am2r_15_2/
AM2R_11.zip
am2r_*/
ARCHIVE-am2r_*/
AM2R_11.zip
AndroidM2R_*

View file

@ -1,3 +0,0 @@
#! /bin/bash
ARCH=x86_64 ./utilities/appimagetool-x86_64.AppImage -n AM2R.AppDir

View file

@ -6,4 +6,4 @@ Icon=[REPLACE]/icon.png
Name=AM2R
Terminal=false
Type=Application
Version=1.0"
Version=1.0

View file

@ -2,10 +2,10 @@
This utility patches the official AM2R 1.1 release (Windows) to the fan-made Community Update (Linux).
## Dependencies
The patcher and the installer only require a small amount of dependencies:
The patcher and the installer only require a small amount of dependencies. Note that the Java-related packages (`java`, `jre`, `jdk`) packages are only required for building an Android APK.
### Arch (including Manjaro, EndeavourOS, RebornOS, etc.)
Make sure that multilib is enabled, as `lib32-libpulse` is a 32-bit library, and Arch does not enable 32-bit support by default.
Make sure that multilib is enabled, as `lib32-libpulse` is a 32-bit library and Arch does not enable 32-bit support by default.
To enable it, go to `/etc/pacman.conf`, search for `[multilib]`, and make sure that the next two lines are uncommented:
```
[multilib]
@ -13,39 +13,47 @@ Include = /etc/pacman.d/mirrorlist
```
Then install the following dependencies:
`sudo pacman -S --needed python xdelta3 jre8-openjdk lib32-libpulse`
`sudo pacman -S --needed unzip sed patchelf xdelta3 jre8-openjdk lib32-libpulse`
### Debian (including Ubuntu, Mint, PopOS, etc.)
Make sure that the i386 architecture is enabled for you, as libopenal1 requires the 32-bit version, and Ubuntu does not enable 32-bit support by default.
Make sure you enable the i386 architecture, as `libopenal1` requires the 32-bit version and Ubuntu does not enable 32-bit support by default.
To enable it, do the following:
```
sudo dpkg --add-architecture i386
sudo apt update && sudo apt install libc6:i386 libncurses5:i386 libstdc++6:i386
sudo apt update && sudo apt install libc6:i386 libncurses5:i386 libstdc++6:i386 libopenal1:i386
```
Then install the following dependencies:
`sudo apt install python xdelta3 openjdk-8-jre libopenal1:i386`
`sudo apt install unzip sed xdelta3 patchelf openjdk-8-jre`
### Nix (Including NixOS)
Enter a shell with all the required dependencies to run the script:
`nix shell nixpkgs#{gnused,unzip,xdelta,patchelf,jre}`
Note that the AppImage will **not** work on NixOS. Please follow the instructions in the manual installation section.
### Red Hat (including Fedora)
`sudo yum python xdelta java-1.8.0-openjdk`
`sudo yum unzip sed xdelta patchelf java-1.8.0-openjdk`
### Suse
`sudo zypper python xdelta3 java-1_8_0-openjdk`
`sudo zypper unzip sed xdelta3 patchelf java-1_8_0-openjdk`
## Controllers
In order to be able to use a controller, you *need* the two following packages as well:
In order to use a controller on some distributions, the two following packages are *mandatory*:
- jstest-gtk
- joystick
## Linux and Android patching process
To patch your copy of (Windows) AM2R v1.1, place the `AM2R_11.zip` (case-sensitive) file in the same folder as `patcher.py`. After installing the required dependencies for the version you would like to patch to, execute `patcher.py` via `python patcher.py`.
To patch your copy of (Windows) AM2R v1.1, place the `AM2R_11.zip` (case-sensitive) file in the same folder as `patcher.sh`. After installing the required dependencies for the version you would like to patch to, execute the patching script via `./patcher.sh`.
During the installation you will be asked, if you want to patch it for Linux or Android. Press the corresponding number for that.
If no arguments are applied, the patching script will run as *interactive* mode. For a list of all arguments for headless mode, run `./patcher.sh --help`.
## After patching
Navigate to the newly created folder.
If you have other questions/issues, please open an issue, post to [r/AM2R](https://www.reddit.com/r/AM2R/), or join the [Official AM2R Discord Server](https://discord.gg/YTQnkAJ).
If you have other questions/issues, please open an issue, post to [r/AM2R](https://www.reddit.com/r/AM2R/), join the [Official AM2R Discord Server](https://discord.gg/YTQnkAJ) or join the [Official AM2R Matrix Space](https://matrix.to/#/#am2r:matrix.org).
## Android installation instructions
You will need an Android device with a file explorer application installed, and a USB cable to connect said device to your computer.
@ -65,7 +73,8 @@ If for some reason, you are not able to access your phone, you can use the adb (
4. Open a terminal and type `adb devices`. This should show your phone. If it does, type `adb install [path-to-apk]`.
## Manual installation
This section, is if you don't like appimages, or want to run the game natively. Unless you have a very good reason for it, please use the AppImage instead!
Manual installation should not be used without due cause. Unless you have a very good reason for avoiding AppImages, please use the default installation instead!
If you cannot run AM2R after installing the packages, use `ldd` in order to find out which packages are missing.
### Dependencies
As said above, these dependencies are **only** needed if you want to run the game natively.
@ -73,25 +82,20 @@ As said above, these dependencies are **only** needed if you want to run the gam
### Arch (including Manjaro, EndeavourOS, RebornOS, etc.)
Make sure that multilib is enabled, as this is a 32-bit application and Arch does not do so by default.
To enable it, go to `/etc/pacman.conf`, search for `[multilib]`, and make sure that both this and the next line are uncommented. After that, install the following packages:
`sudo pacman -S --needed python xdelta3 lib32-openal lib32-openssl-1.0 lib32-libcurl-compat lib32-libpulse lib32-gcc-libs lib32-libxxf86vm lib32-libglvnd lib32-libxrandr lib32-glu`
`sudo pacman -S --needed unzip patchelf sed xdelta3 lib32-openal lib32-libcurl lib32-libpulse lib32-gcc-libs lib32-libxxf86vm lib32-libglvnd lib32-libxrandr lib32-glu`
### Debian (including Ubuntu, Mint, PopOS, etc.)
`sudo apt install python xdelta3 libc6:i386 libstdc++6:i386 zlib1g-dev:i386 libxxf86vm1:i386 libcurl3:i386 libssl1.0:i386 libopenal1:i386 libxrandr2:i386 libglu1:i386`
Make sure you enable the i386 architecture, as `libopenal1` requires the 32-bit version and Ubuntu does not enable 32-bit support by default.
To enable it, do the following:
```
sudo dpkg --add-architecture i386
```
After that you can run this:
`sudo apt install unzip patchelf sed xdelta3 libc6:i386 libstdc++6:i386 zlib1g-dev:i386 libxxf86vm1:i386 libcurl:i386 libopenal1:i386 libxrandr2:i386 libglu1:i386`
On newer versions (Debian 10+ or Ubuntu 18+) you may have to do the below command instead. Please make sure first, that you neither have `libcurl3` nor `libcurl4` installed.
`sudo apt install python python3 xdelta3 libc6:i386 libstdc++6:i386 zlib1g-dev:i386 libxxf86vm1:i386 libopenal1:i386 libxrandr2:i386 libglu1:i386 && wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl1.0/libssl1.0.0_1.0.2n-1ubuntu5.5_i386.deb && sudo dpkg -i libssl1.0.0_1.0.2n-1ubuntu5.5_i386.deb && wget http://archive.ubuntu.com/ubuntu/pool/universe/c/curl3/libcurl3_7.58.0-2ubuntu2_i386.deb && sudo dpkg -i libcurl3_7.58.0-2ubuntu2_i386.deb && rm libssl1.0.0_1.0.2n-1ubuntu5.5_i386.deb libcurl3_7.58.0-2ubuntu2_i386.deb && sudo apt install -f`
### Nix (Including NixOS)
After installation, the game can be run using the `steam-run` FHS environment. This avoids having to patch the dynamic linker and dynamically linked libraries. You can run it with the following command:
`NIXPKGS_ALLOW_UNFREE=1 nix shell --impure nixpkgs#steam-run --command steam-run ./runner`
### Red Hat (including Fedora)
`sudo yum install python xdelta openal-soft compat-openssl10`
If you cannot run AM2R after installing the packages, use `ldd` in order to find out which packages are missing.
After patching, if you want to launch AM2R via command line, make sure to do it like this: `env "LD_PRELOAD=libcurl.so.3" ./AM2R`.
However, there is also a .desktop file with the above command included (this one has the AM2R logo). You can just double click on that in order to start the game.
Some distributions don't give you any way to install libcurl3 anymore. Should that be the case, try to generate an empty library like so:
```
touch empty.c
gcc -c empty.c empty.c -fPIC
gcc -fPIC -shared -Wl,-soname,libcurl.so.4 empty.o -o libcurl.so.4
```
And then launch AM2R with LD_LIBRARY_PATH pointing to where your generated .so file is. For example `LD_LIBRARY_PATH=/home/me/libcurl-lib ./AM2R´
`sudo yum install unzip sed xdelta openal-soft patchelf`

Binary file not shown.

BIN
data/AM2R.AppDir/AppRun-game Executable file

Binary file not shown.

View file

@ -1,7 +1,7 @@
[Desktop Entry]
Categories=Game;
Comment=Another Metroid 2 Remake (Community Edition)
Exec=AM2R
Exec=runner
Icon=icon
Name=AM2R
Type=Application

Binary file not shown.

View file

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 728 B

After

Width:  |  Height:  |  Size: 728 B

View file

Before

Width:  |  Height:  |  Size: 649 B

After

Width:  |  Height:  |  Size: 649 B

View file

Before

Width:  |  Height:  |  Size: 649 B

After

Width:  |  Height:  |  Size: 649 B

Binary file not shown.

View file

@ -1,301 +0,0 @@
from zipfile import ZipFile
import os.path
from os import remove, mkdir, rename
from shutil import copy, copytree, rmtree, move
import glob
import subprocess
version = '15_2'
output = 'am2r_' + version
# Thanks, stackoverflow
def _find_getch():
try:
import termios
except ImportError:
# Non-POSIX. Return msvcrt's (Windows') getch.
import msvcrt
return msvcrt.getch
# POSIX system. Create and return a getch that manipulates the tty.
import sys, tty
def _getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
return _getch
getch = _find_getch()
# End stackoverflow code
# Residual file cleanup to prevent accidents
if os.path.isdir('utilities/android/assets'):
rmtree('utilities/android/assets')
if os.path.isdir(output):
rmtree(output)
if os.path.isdir("ARCHIVE-"+output):
rmtree("ARCHIVE-"+output)
if os.path.isdir('AM2R.AppDir'):
rmtree('AM2R.AppDir')
print("-------------------------------------------\n\nAM2R 1.5.1 Python Autopatching Utility\nScripted by Lojemiru\n\n-------------------------------------------\n")
# Check for AM2R_11.zip...
if os.path.isfile('AM2R_11.zip'):
print("AM2R_11.zip found! Extracting to " + output)
# Unzip AM2R_11.zip
try:
with ZipFile('AM2R_11.zip', 'r') as zipObj:
# Extract all the contents of zip file in current directory
zipObj.extractall(output)
except:
print("AM2R_11.zip failed to extract. Try unzipping the folder and run this utility again.")
quit()
else:
if os.path.isdir('AM2R_11'):
print("AM2R_11 found! Copying to " + output)
else:
print("AM2R_11 not found. Place AM2R_11.zip (case sensitive) in this folder and try again.")
quit()
print("\nSelect your patch type:\n\n1 - Linux\n2 - Android\n\nAwaiting input:\n")
type = getch()
# Determine type
if (type == '1'):
print("Linux selected.\nApplying AM2R patch...")
# apply AM2R.bps
# subprocess.call(['utilities/floating/./flips-linux', '-a', 'data/AM2R.bps', output+'/AM2R.exe', output+'/AM2R'])
subprocess.call(['xdelta3', '-dfs', output+'/AM2R.exe', 'data/AM2R.xdelta', output+'/AM2R'])
print("\nApplying data patch...")
# apply game.unx patch
# subprocess.call(['utilities/floating/./flips-linux', '-a', 'data/game.bps', output+'/data.win', output+'/game.unx'])
subprocess.call(['xdelta3', '-dfs', output+'/data.win', 'data/game.xdelta', output+'/game.unx'])
# clean up Windows files
print("\nCleaning up residual AM2R 1.1 files...")
remove(output+'/AM2R.exe')
remove(output+'/data.win')
# structure for Linux
print("\nFormatting game directory...")
os.mkdir(output+'/assets')
for z in glob.glob(output+'/*.*'):
move(z, output+'/assets')
# install new datafiles...
print("\nInstalling new datafiles...")
# copy the whole files_to_copy folder over
for file2 in glob.glob("data/files_to_copy/*"):
if (os.path.isdir(file2)):
copytree(file2, output+"/assets/"+os.path.basename(file2))
else:
copy(file2, output+'/assets')
print("\nInstall high quality in-game music? Increases filesize by 194 MB!\n\n[y/n]\n")
hq = getch()
# install HQ music
if (hq == 'y'):
print("Copying HQ music...")
for file in glob.glob("data/HDR_HQ_in-game_music/*.ogg"):
copy(file, output+'/assets')
# format music for linux
print("Formatting music files for Linux application recognition...")
for music in glob.glob(output+'/assets/*.ogg'):
rename(music, music.lower())
# remove old lang
rmtree(output+'/lang')
#make game executable
subprocess.call(["chmod", "+x", output+"/AM2R"])
#create AppImage
print("Creating Appimage...")
copytree("data/AM2R.AppDir", "AM2R.AppDir")
subprocess.call(["cp", "-rpT", output , "AM2R.AppDir/usr/bin"])
fd = os.open("/dev/null", os.O_WRONLY)
savefd = os.dup(2)
os.dup2(fd,2)
subprocess.call(["sh", "./AppImageCreation.sh", "-n"])
os.dup2(savefd,2)
rename("AM2R-x86_64.AppImage", "AM2R.AppImage")
rmtree("AM2R.AppDir")
#rename the output to archive, so we only have a new folder, containing the appimage and a desktop file for it
rename(output, "ARCHIVE-"+output)
mkdir(output)
move("AM2R.AppImage", output+"/AM2R.AppImage")
copy("data/files_to_copy/icon.png", output+"/icon.png")
#check if current OS is a fork of Debian
isDebianFork = 0
catOutput = subprocess.check_output(("cat", "/etc/os-release"))
catOutput = str(catOutput)
grep = "ID_LIKE=debian"
isDebianFork = catOutput.find(grep) >= 0
#if not debian, check for ubuntu instead
if(not isDebianFork):
grep = "ID_LIKE=ubuntu"
isDebianFork = catOutput.find(grep) >= 0
#cehck if current OS uses intel as gpu
isIntelGPU = 0
lspciOutput = subprocess.check_output(("lspci"))
lspciOutput = str(catOutput)
grep = "VGA compatible controller: Intel"
isIntelGPU = lspciOutput.find(grep) >= 0
print("\nDo you want to install AM2R systemwide?\n\n[y/n]\n")
inp = getch()
if( inp == 'y'):
#install it to /usr/local/bin
#first, create the folder in case it's not there
subprocess.call(["sudo", "mkdir", "-p", "/usr/local/bin/am2r/"])
#couldn't figure it out, how to do it with a normal cp command, so I just copy everything manually
#except for /assets
for file8 in glob.glob(output + "/*"):
subprocess.call(["sudo", "cp", "-p", file8 , "/usr/local/bin/am2r/"])
#subprocess.call(["sudo", "cp", "-rp", output+"/assets/" , "/usr/local/bin/am2r/"])
template = open("DesktopTemplate", "r")
fileContents = template.read()
fileContents = fileContents.replace("[REPLACE]", "/usr/local/bin/am2r")
if( isDebianFork and isIntelGPU):
fileContents = fileContents.replace("Exec=", "Exec=LIBGL_DRI3_DISABLE=1 ")
desktopFile = open(output+"/AM2R.desktop", "w+")
desktopFile.seek(0)
desktopFile.write(fileContents)
subprocess.call(["chmod", "+x", output+"/AM2R.desktop"])
subprocess.call(["sudo", "cp", "-fp", output+"/AM2R.desktop", "/usr/share/applications/AM2R.desktop"])
#we could chmod ./AM2R in the install folder, but it's not really necessary
else:
#creating the desktop file for local
cwd = os.getcwd()
desktopFilePath = output+"/AM2R.desktop"
copy("DesktopTemplate", desktopFilePath)
desktopFile = open(desktopFilePath, 'r+')
fileContents = desktopFile.read()
fileContents = fileContents.replace("[REPLACE]", cwd+"/"+output)
if( isDebianFork and isIntelGPU):
fileContents = fileContents.replace("Exec=", "Exec=LIBGL_DRI3_DISABLE=1 ")
desktopFile.seek(0)
desktopFile.write(fileContents)
#make the desktopFile executable. For some reason, this is not *necessary*, when copying it into /applications.
#But I'll do it anyways, because I want the local one to work as well
subprocess.call(["chmod", "+x", desktopFilePath])
print("Desktop file has been created!")
if( isDebianFork and isIntelGPU):
print("It has been detected, that you're running a fork of Debian along with an Intel GPU. Please use the provided .desktop File in order to launch the game.")
print("Ignore this message, if you installed AM2R systemwide")
elif (type == '2'):
print("Android selected.\nApplying data patch...")
# To be completely honest I don't know why I made the Android patch work like this.
# I'm going to revert it until I run into problems.
# subprocess.call(['utilities/floating/./flips-linux', '-a', 'data/game.bps', output+'/data.win', output+'/game.unx'])
# subprocess.call(['xdelta3', '-dfs', output+'/data.win', 'data/game.bps', output+'/game.unx'])
print("\nApplying Android patch...")
# subprocess.call(['utilities/floating/./flips-linux', '-a', 'data/droid.bps', output+'/game.unx', output+'/game.droid'])
subprocess.call(['xdelta3', '-dfs', output+'/data.win', 'data/droid.xdelta', output+'/game.droid'])
copy("data/android/AM2RWrapper.apk", "utilities/android/")
remove(output+"/D3DX9_43.dll")
remove(output+"/AM2R.exe")
remove(output+"/data.win")
# remove(output+"/game.unx")
copytree(output, "utilities/android/assets")
copy("data/android/AM2R.ini", "utilities/android/assets")
# Install new datafiles...
print("\nInstalling new datafiles...")
# Music
for file2 in glob.glob("data/files_to_copy/*.ogg"):
copy(file2, 'utilities/android/assets')
print("\nInstall high quality in-game music? Increases filesize by 194 MB!\n\n[y/n]\n")
hq = getch()
# Install HQ music
if (hq == 'y'):
print("Copying HQ music...")
for file in glob.glob("data/HDR_HQ_in-game_music/*.ogg"):
copy(file, 'utilities/android/assets')
# Remove old lang
rmtree('utilities/android/assets/lang')
# Install new lang
copytree('data/files_to_copy/lang', 'utilities/android/assets/lang')
# Text
for file3 in glob.glob("data/files_to_copy/*.txt"):
copy(file3, 'utilities/android/assets')
# Modifiers
copy('data/files_to_copy/modifiers.ini', 'utilities/android/assets')
os.chdir('utilities/android')
print("\nPackaging APK.")
print("If Java JDK 8 or newer is not present, this will fail!")
#decompile the apk
subprocess.call(["java", "-jar", "./apktool.jar", "d", "-f", "AM2RWrapper.apk"])
#copy
subprocess.call(["cp", "-r", "assets", "AM2RWrapper"])
subprocess.call(["cp", "-f", "../../data/android/apktool.yml", "AM2RWrapper/apktool.yml"])
#build
subprocess.call(["java", "-jar", "./apktool.jar", "b", "AM2RWrapper", "-o", "AM2RWrapper.apk"])
print("\nSigning APK...")
subprocess.call(['java', '-jar', 'uber-apk-signer.jar', '-a', 'AM2RWrapper.apk'])
# Cleanup
remove('AM2RWrapper.apk')
rmtree('assets')
rmtree('../../'+output)
rmtree('AM2RWrapper')
# Move APK
move('AM2RWrapper-aligned-debugSigned.apk', '../../AndroidM2R_'+version+'-signed.apk')
else:
print("Invalid input. Exiting.")
quit()
print("\nThe operation was completed successfully. See you next mission!")

370
patcher.sh Executable file
View file

@ -0,0 +1,370 @@
#!/usr/bin/env bash
# Exit on any error to avoid showing everything was successfull even though it wasnt
set -eou pipefail
# We want to move hidden files too
shopt -s dotglob
# Patching user variables
OSCHOICE="linux"
AM2RZIP=""
HQMUSIC=false
SYSTEMWIDE=false
APPIMAGE=false
PREFIX=""
# Patching internal variables
# Since people are likely to double click on this, I need a way to get the script_dir
dirResult="$(dirname '${BASH_SOURCE[0]}')"
SCRIPT_DIR="$(realpath $dirResult)"
VERSION="1.5.5"
GAMEDIR="${SCRIPT_DIR}/am2r_${VERSION}"
RESOURCES="${GAMEDIR}/assets"
checkInstalled()
{
local command="$1"
# Check wether a command is installed
if [ ! -x "$(command -v "${command}")" ] ; then
>&2 echo "${command} is not installed! Please install '${command}' from your local package manager!"
exit 1
fi
}
patch_am2r ()
{
checkInstalled "unzip"
checkInstalled "sed"
checkInstalled "xdelta3"
# Set prefix to default value if empty
if [ -z "$PREFIX" ]; then
if [ "$SYSTEMWIDE" = true ] && [ ! "$OSCHOICE" = "android" ]; then
PREFIX="/usr/local"
else
PREFIX="$SCRIPT_DIR/am2r_${VERSION}"
fi
fi
GAMEDIR=$(mktemp -d -u)
trap "rm -rf $GAMEDIR" EXIT
RESOURCES="${GAMEDIR}/assets"
local output=""
# We need to do variable adjustments based on the prefix
if [ "$SYSTEMWIDE" = true ]; then
output="${PREFIX}/opt/am2r"
else
output="${PREFIX}"
fi
# Create necessary directories
mkdir -p "$GAMEDIR" "$RESOURCES"
# Check for AM2R_11
if [[ -f "$AM2RZIP" ]]; then
echo "AM2R_11.zip found!"
unzip -q "$AM2RZIP" -d "$GAMEDIR"
elif [[ -d "$AM2RZIP" ]]; then
echo "AM2R_11 folder found!"
cp -R "$AM2RZIP" "$GAMEDIR"
else
echo "AM2R_11 not found! Please place AM2R_11.zip (case sensitive) into \"$SCRIPT_DIR\" or provide it via command line arguments and try again."
exit 1
fi
# Check for which OS we patch
if [ "$OSCHOICE" = "linux" ]; then
checkInstalled "patchelf"
echo "Patching for Linux..."
echo "Applying AM2R xdelta patch..."
xdelta3 -dfs "$GAMEDIR/AM2R.exe" "$SCRIPT_DIR/data/AM2R.xdelta" "$GAMEDIR/runner"
echo "Applying asset xdelta patch..."
xdelta3 -dfs "$GAMEDIR/data.win" "$SCRIPT_DIR/data/game.xdelta" "$RESOURCES/game.unx"
echo "Cleaning up residual AM2R 1.1 files..."
rm "$GAMEDIR/AM2R.exe" "$GAMEDIR/data.win" "$GAMEDIR/D3DX9_43.dll"
echo "Formatting game directory..."
# This won't move the runner, because it doesn't have a dot
mv $GAMEDIR/*.* "$RESOURCES/"
echo "Installing new datafiles..."
cp -R "$SCRIPT_DIR"/data/files_to_copy/* "$RESOURCES/"
if [ "$HQMUSIC" = true ]; then
echo "Copying HQ music..."
cp "$SCRIPT_DIR"/data/HDR_HQ_in-game_music/*.ogg "$RESOURCES/"
fi
# On Unix the music filenames need to be converted to lowercase.
find "$RESOURCES" -type f -exec bash -c '
target="{}"
# Only files are meant to be modified, not the folders they are contained in.
cd "$(dirname "${target}")"
target="$(basename "${target}")"
# Convert the filename to lowercase, if required.
! [[ "${target}" = "${target,,}" ]] && mv "${target}" "${target,,}"
' \;
# GameMaker games (like AMR2) link to OpenSSL 1.0.0, which is outdated and insecure.
# When attempting to link to newer versions, an error is raised at runtime claiming it cannot find
# the outdated version of OpenSSL, even though it has been patched to link to the newer version.
# After replacing it with libcurl, versioning is ignored, and the binary starts just fine.
# Currently, patchelf has a bug where this does not work correctly
# So it will stay commented out until it does
#echo "Patching insecure OpenSSL dependency with libcurl..."
#patchelf "$GAMEDIR/runner" \
# --replace-needed "libcrypto.so.1.0.0" "libcurl.so" \
# --replace-needed "libssl.so.1.0.0" "libcurl.so"
# An environment variable needs to be set on Mesa to avoid a race related to multithreaded shader compilation.
# To do this, we move the original executable to a hidden file, and create a bash script with the needed variable in place of the original.
echo "Creating wrapper script to fix Mesa support..."
mv "$GAMEDIR/runner" "$GAMEDIR/.runner-unwrapped"
echo '
#!/usr/bin/env bash
# This environment variable fixes Mesa support. If another driver is used this should not do anything.
# See https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4181 for more information.
radeonsi_sync_compile="true" exec "$(dirname "$(readlink -f "$0")")/.runner-unwrapped" "$@"
' > "$GAMEDIR/runner"
chmod +x "$GAMEDIR/runner" "$GAMEDIR/.runner-unwrapped"
# Remove old lang folder
rm -R "$GAMEDIR"/lang
chmod +x "$GAMEDIR/runner"
if [ "$SYSTEMWIDE" = true ]; then
mkdir -p "$PREFIX/bin"
if [ "$APPIMAGE" = true ]; then
ln -sf "$output/AM2R.AppImage" "$PREFIX/bin/am2r"
else
ln -sf "$output/runner" "$PREFIX/bin/am2r"
fi
fi
# Create .desktop file
echo "Creating desktop file..."
cp "$SCRIPT_DIR/data/files_to_copy/icon.png" "$GAMEDIR/icon.png"
local desktopPath="$GAMEDIR/AM2R.desktop"
# For systemwide we need to a) write to desktop file to a different directory
# and b) copy the icon to the proper XDG icon dir and c) use proper icon reference in desktop file
if [ "$SYSTEMWIDE" = true ]; then
mkdir -p "$PREFIX/share/applications"
desktopPath="$PREFIX/share/applications/AM2R.desktop"
mkdir -p "$PREFIX/share/icons/hicolor/72x72/apps"
mv "$GAMEDIR/icon.png" "$PREFIX/share/icons/hicolor/72x72/apps/am2r.icon"
fi
cp "$SCRIPT_DIR/DesktopTemplate" "$desktopPath"
# Replace with proper path
sed -i "s#\[REPLACE\]#$output#" "$desktopPath"
if [ "$SYSTEMWIDE" = true ]; then
sed -i "s#Icon=$output/icon.png#Icon=am2r#" "$desktopPath"
fi
if [ "$APPIMAGE" = false ]; then
# For non-appimage, the desktop file should point to runner
sed -i "s/AM2R.AppImage/runner/" "$desktopPath"
else
# Create AppImage
echo "Creating AppImage..."
# Dry/unsafe run with mktemp, as otherwise cp below will copy into the dir, rather than as the dir
local tempAppDir=$(mktemp -d -u)
trap "rm -rf $tempAppDir" EXIT
cp -R --preserve=links "$SCRIPT_DIR/data/AM2R.AppDir" $tempAppDir
mkdir -p "$tempAppDir/bin"
mv "$GAMEDIR"/* "$tempAppDir/bin"
ARCH=x86_64 "$SCRIPT_DIR/utilities/appimagetool-x86_64.AppImage" -n $tempAppDir "$GAMEDIR/AM2R.AppImage" 2> /dev/null
if [ "$SYSTEMWIDE" = false ] ; then
mv "$tempAppDir/bin/icon.png" "$GAMEDIR/icon.png"
fi
# For systemwide, we already moved the desktop file to prefix/share earlier above.
if [ "$SYSTEMWIDE" = false ]; then
mv "$tempAppDir/bin/AM2R.desktop" "$desktopPath"
fi
rm -R "$tempAppDir"
fi
elif [ "$OSCHOICE" = "android" ]; then
checkInstalled "java"
echo "Creating an APK for Android..."
local apktoolPath="$SCRIPT_DIR/utilities/android/apktool.jar"
local uberPath="$SCRIPT_DIR/utilities/android/uber-apk-signer.jar"
echo "Applying Android patch..."
xdelta3 -dfs "$GAMEDIR/data.win" "$SCRIPT_DIR/data/droid.xdelta" "$GAMEDIR/game.droid"
rm -rf "$GAMEDIR/D3DX9_43.dll" "$GAMEDIR/AM2R.exe" "$GAMEDIR/data.win" "$GAMEDIR/assets"
if [ -f "$SCRIPT_DIR/data/android/AM2R.ini" ]; then
cp -p "$SCRIPT_DIR/data/android/AM2R.ini" "$GAMEDIR/"
fi
echo "Installing new datafiles..."
cp -R "$SCRIPT_DIR"/data/files_to_copy/* "$GAMEDIR"
if [ "$HQMUSIC" = true ]; then
cp "$SCRIPT_DIR"/data/HDR_HQ_in-game_music/*.ogg "$GAMEDIR"
fi
echo "Packaging APK..."
# decompile the apk
# Dry/unsafe run with mktemp, as otherwise apktool below will GAMEDIR into the dir, rather than as the dir
local tempApkDir=$(mktemp -d -u)
trap "rm -rf $tempApkDir" EXIT
java -jar "$apktoolPath" -q d -f "$SCRIPT_DIR/data/android/AM2RWrapper.apk" -o "$tempApkDir"
mv "$GAMEDIR/"* "$tempApkDir/assets"
echo "Editing apktool.yml..."
sed -i "s/doNotCompress:/doNotCompress:\n- ogg/" "$tempApkDir/apktool.yml"
# build apk
echo "Building APK..."
java -jar "$apktoolPath" -q b "$tempApkDir" -o "$tempApkDir/AM2RWrapper.apk"
echo "Signing APK..."
java -jar "$uberPath" -a "$tempApkDir/AM2RWrapper.apk"
# Move APK
mv "$tempApkDir/AM2RWrapper-aligned-debugSigned.apk" "$PREFIX/AndroidM2R_"$VERSION"-signed.apk"
else
>&2 echo "Invalid OS \"$OSCHOICE\"! Cannot patch anything!"
exit 1
fi
# Put everything from temp directory into the proper output directory
# Moving does *not* work, as mv doesn't allow to overwrite existing directories
mkdir -p $output
cp -rf $GAMEDIR/* $output
echo ""
echo "The operation was completed successfully. See you next mission!"
return 0
}
# ----
# Main function starts here
# ---
main ()
{
echo "-------------------------------------------"
echo ""
echo "AM2R ${VERSION} Shell Autopatching Utility"
echo ""
echo "-------------------------------------------"
if (( $# <= 0 )); then
APPIMAGE=true
AM2RZIP="$SCRIPT_DIR/AM2R_11.zip"
local input=""
echo "Running in interactive mode. For a full list of arguments, run the script with \"--help\""
echo "Select your patch type:"
echo ""
echo "1 - Linux"
echo "2 - Android"
echo ""
echo "Awaiting input:"
read -n1 input
echo ""
if [[ "${input}" = "1" ]]; then
OSCHOICE="linux"
elif [[ "${input}" = "2" ]]; then
OSCHOICE="android"
else
>&2 echo "Invalid OS!"
exit 1
fi
echo "Install high quality in-game music? Increases filesize by 194 MB!"
echo "[y/n]"
read -n1 input
echo ""
if [[ "${input,,}" = "y" ]]; then
HQMUSIC=true
fi
if [ $OSCHOICE = "linux" ]; then
echo "Do you want to install AM2R systemwide?"
echo "[y/n]"
read -n1 input
echo ""
if [[ "${input,,}" = "y" ]]; then
SYSTEMWIDE=true
fi
fi
patch_am2r
local result=$?
echo "Press any key to quit..."
read -s -n1 INPUT
exit $result
fi
while (( $# > 0 )); do
case $1 in
-s|--os)
OSCHOICE="$2"
shift 2 # past argument and value
;;
-m|--hqmusic)
HQMUSIC=true
shift # past argument
;;
-w|--systemwide)
SYSTEMWIDE=true
shift # past argument
;;
-a|--appimage)
APPIMAGE=true
shift # past argument
;;
-p|--prefix)
PREFIX=$(realpath "$2")
shift 2 # past argument and value
;;
-z|--am2rzip)
AM2RZIP="$2"
shift 2 # past argument and value
;;
-h|--help)
echo -e "-s, --os\t\t\tThe operating system to patch to. Valid are \"linux\" and \"android\". Default is \"linux\""
echo -e "-m, --hqmusic\t\t\tIf provided, high quality music will be used, otherwise low quality music will be used instead."
echo -e "-w, --systemwide\t\tIf provided, Linux will get installed systemwide, otherwise Linux will get installed portably. Has no effect on Android."
echo -e "-a, --appimage\t\t\tIf provided, an AppImage will get generated, otherwise the raw binary will get generated instead. Has no effect on Android."
echo -e "-p, --prefix\t\t\tThe prefix used for patching operations. Default for systemwide is \"/usr/local\" and for non-systemwide \"<directory where this script resides>/am2r_<VersionNumber>\". As systemwide is ignored on Android, for Android this will always default to the latter option."
echo -e "-z, --am2rzip\t\t\tThe path to the AM2R_11 zip or directory. Default is \"<directory where the script resides>/AM2R_11.zip\""
exit 0
;;
*)
>&2 echo "Unknown option $1"
exit 1
;;
esac
done
# restore positional parameters
set -- "${POSITIONAL_ARGS[@]}"
# check if necessary variables are provided
if [ -z "$OSCHOICE" ]; then
>&2 echo "Missing argument! The OS needs to be provided via the \"--os\" flag! For further info use --help."
exit 1
fi
if [ -z "$AM2RZIP" ]; then
AM2RZIP="$SCRIPT_DIR/AM2R_11.zip"
fi
patch_am2r
}
main "$@"