From 7d180c1dad902e4dce57088785a25b2d4242d6e6 Mon Sep 17 00:00:00 2001 From: Miepee <38186597+Miepee@users.noreply.github.com> Date: Fri, 12 Aug 2022 03:08:01 +0200 Subject: [PATCH] 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> --- .gitignore | 1 + AppImageCreation.sh | 3 - README.md | 22 +-- patcher.py | 271 ---------------------------------- patcher.sh | 343 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 356 insertions(+), 284 deletions(-) delete mode 100755 AppImageCreation.sh delete mode 100644 patcher.py create mode 100755 patcher.sh diff --git a/.gitignore b/.gitignore index 262b39e..66df715 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ am2r_*/ ARCHIVE-am2r_*/ AM2R_11.zip +AndroidM2R_* diff --git a/AppImageCreation.sh b/AppImageCreation.sh deleted file mode 100755 index a377ac4..0000000 --- a/AppImageCreation.sh +++ /dev/null @@ -1,3 +0,0 @@ -#! /bin/bash -ARCH=x86_64 ./utilities/appimagetool-x86_64.AppImage -n AM2R.AppDir - diff --git a/README.md b/README.md index c47dd9a..ce4be50 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ 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 xdelta3 jre8-openjdk lib32-libpulse` ### Debian (including Ubuntu, Mint, PopOS, etc.) @@ -25,13 +25,13 @@ sudo apt update && sudo apt install libc6:i386 libncurses5:i386 libstdc++6:i386 ``` Then install the following dependencies: -`sudo apt install python3 xdelta3 openjdk-8-jre libopenal1:i386` +`sudo apt install unzip sed xdelta3 openjdk-8-jre libopenal1:i386` ### Red Hat (including Fedora) -`sudo yum python xdelta java-1.8.0-openjdk` +`sudo yum unzip sed xdelta java-1.8.0-openjdk` ### Suse -`sudo zypper python xdelta3 java-1_8_0-openjdk` +`sudo zypper unzip sed xdelta3 java-1_8_0-openjdk` ## Controllers In order to be able to use a controller, you *need* the two following packages as well: @@ -39,13 +39,15 @@ In order to be able to use a controller, you *need* the two following packages a - 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. @@ -73,16 +75,16 @@ 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 sed xdelta3 lib32-openal lib32-openssl-1.0 lib32-libcurl-compat 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` +`sudo apt install unzip sed xdelta3 libc6:i386 libstdc++6:i386 zlib1g-dev:i386 libxxf86vm1:i386 libcurl3:i386 libssl1.0: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` +`sudo apt install unzip sed 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` ### Red Hat (including Fedora) -`sudo yum install python xdelta openal-soft compat-openssl10` +`sudo yum install unzip sed 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`. diff --git a/patcher.py b/patcher.py deleted file mode 100644 index 22544b5..0000000 --- a/patcher.py +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/env python - -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_5' - -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.5 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+'/runner']) - - 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+"/runner"]) - - #create AppImage - print("Creating Appimage...") - copytree("data/AM2R.AppDir", "AM2R.AppDir", symlinks=True) - 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") - - 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") - - 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) - - 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!") - -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") - # Only copy the file over if it exists - if (os.path.exists("data/android/AM2R.ini")): - 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!") diff --git a/patcher.sh b/patcher.sh new file mode 100755 index 0000000..70ead82 --- /dev/null +++ b/patcher.sh @@ -0,0 +1,343 @@ +#!/usr/bin/env bash + +# exit on any error to avoid showing everything was successfull even though it wasnt +set -eou pipefail + +# 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" + +patch_am2r () +{ + # 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 + + # Check whether Xdelta is installed + if [ ! -x "$(command -v xdelta3)" ] ; then + >&2 echo "Xdelta is not installed! Please install 'xdelta3' from your local package manager!" + exit 1 + fi + + 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,,}" + ' \; + + # 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\]#$GAMEDIR#" "$desktopPath" + + if [ "$SYSTEMWIDE" = true ]; then + sed -i "s#Icon=$GAMEDIR/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 + + # Check whether Xdelta is installed + if [ ! -x "$(command -v xdelta3)" ]; then + >&2 echo "Xdelta is not installed! Please install 'xdelta3' from your local package manager!" + exit 1 + fi + + # Check whether Java is installed + if [ ! -x "$(command -v java)" ]; then + >&2 echo "Java is not installed! Please install a Java runtime from your local package manager!" + exit 1 + fi + + 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 -r -f $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 \"/am2r_\". 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 \"/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 "$@"