Compare commits
23 commits
Patchdata-
...
master
Author | SHA1 | Date | |
---|---|---|---|
Miepee | 47da221fa8 | ||
Miepee | e724b84c04 | ||
d4cf843bcf | |||
Miepee | 119bce6269 | ||
Miepee | 56d7dd2d36 | ||
Miepee | d378132085 | ||
Miepee | d34314b707 | ||
df69e1a369 | |||
3e2121c854 | |||
7d180c1dad | |||
9175d9597c | |||
Miepee | 7a3c8cb972 | ||
d723f80592 | |||
38da06337a | |||
Miepee | 1fd4db41cf | ||
e3b01200f3 | |||
Miepee | 7af143f1d3 | ||
Miepee | f25eeedb89 | ||
Miepee | 2ffb6a38b3 | ||
b69ea9ecb7 | |||
dfc080f012 | |||
aff34ac0f8 | |||
0e938101e5 |
7
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
am2r_15_2/
|
||||
ARCHIVE-am2r_15_2/
|
||||
AM2R_11.zip
|
||||
am2r_*/
|
||||
ARCHIVE-am2r_*/
|
||||
AM2R_11.zip
|
||||
AndroidM2R_*
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#! /bin/bash
|
||||
ARCH=x86_64 ./utilities/appimagetool-x86_64.AppImage -n AM2R.AppDir
|
||||
|
|
@ -6,4 +6,4 @@ Icon=[REPLACE]/icon.png
|
|||
Name=AM2R
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Version=1.0"
|
||||
Version=1.0
|
||||
|
|
62
README.md
|
@ -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`
|
||||
|
|
BIN
data/AM2R.AppDir/AppRun-game
Executable 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
|
||||
|
|
BIN
data/AM2R.xdelta
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 718 B After Width: | Height: | Size: 718 B |
Before Width: | Height: | Size: 649 B After Width: | Height: | Size: 649 B |
Before Width: | Height: | Size: 817 B After Width: | Height: | Size: 817 B |
Before Width: | Height: | Size: 728 B After Width: | Height: | Size: 728 B |
Before Width: | Height: | Size: 649 B After Width: | Height: | Size: 649 B |
Before Width: | Height: | Size: 649 B After Width: | Height: | Size: 649 B |
BIN
data/game.xdelta
301
patcher.py
|
@ -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
|
@ -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 "$@"
|