AM2R-Autopatcher-Linux/patcher.py

272 lines
9.4 KiB
Python

#!/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!")