import os
import subprocess
import shutil
import sys



print("\n")
print("================================================================================")
print("CRYSIS 3 MOD ENABLER")
print("AUTHOR: Lord Zapharos (www.lordzapharos.com)")
print("DATE: 19 August 2020")
print("================================================================================")
print("Welcome!")
print("\n")
print("This script will unlock your legal copy of Crysis 3 to enable mod support. All")
print("of your Crysis 3 data files will first be backed up, then unpacked, and finally")
print("will be repacked in a way that permits singleplayer modding. Keep in mind that")
print("unlocking your game can take a while (30-60 minutes). However, you will only")
print("need to run this script ONCE to unlock your game.")
print("\n")
print("Do not open Crysis 3 while this script is running. YOU MUST HAVE AT LEAST 30 GB")
print("of free space on your hard drive before proceeding. Type 'q' or 'quit' at any")
print("time to stop this script.")
print("\n")
print("ATTENTION: YOU MUST HAVE A LEGAL COPY OF CRYSIS 3 TO USE THIS SCRIPT. PLAYING")
print("ONLINE WITH AN UNLOCKED GAME MAY RESULT IN A TEMPORARY OR PERMANENT BAN. THE")
print("SCRIPT AUTHOR ASSUMES NO LIABILITY FOR ANY DAMAGE(S) INCURRED AS A RESULT OF OR")
print("IN RELATION TO THE USAGE OF THIS SCRIPT. YOU UNLOCK YOUR GAME AT YOUR OWN RISK!")
print("\n")
print("With that out of the way, let's get started!")
print("\n")
print("================================================================================")



doBackup = True
if len(sys.argv) - 1 == 1:
    if sys.argv[1] == "--noBackup":
        doBackup = False



pyRoot = os.path.abspath(os.getcwd())
cryAssetsFile = pyRoot + "\\assetList.dat"
try:
    with open(cryAssetsFile) as f:
        pakFileNames = f.readlines()
except Exception:
    print("\nThe file '" + cryAssetsFile + "'")
    print("could not be located or read. Please verify that the file exists and that you")
    print("are allowed to read it, then try again.")
    print("\n")
    quit()
pakFileNames = [x.strip() for x in pakFileNames]



cryVideosFile = pyRoot + "\\signList.dat"
try:
    with open(cryVideosFile) as f:
        videoFileNames = f.readlines()
except Exception:
    print("\nThe file '" + cryVideosFile + "'")
    print("could not be located or read. Please verify that the file exists and that you")
    print("are allowed to read it, then try again.")
    print("\n")
    quit()
videoFileNames = [x.strip() for x in videoFileNames]



root = ""
while len(root) == 0:
    root = input("Enter full path to Crysis 3 (e.g. C:\Games\Crysis 3): ")
    if root == "q" or root == "Q" or root == "QUIT" or root == "quit" or root.lower() == "quit":
        print("\nUser requested exit. Your game files have NOT been changed.\n")
        quit()
    if len(root) > 0 and not os.path.exists(root):
        print("\nThe path '" + root + "' does not appear to exist. Did you spell it correctly?\n")
        root = ""
root = root.replace("/", "\\")
if root[-1:] == "\\":
    root = root[:-1]



if not os.path.isfile(root + "\\Bin32\crysis3.exe"):
    print("\nThe chosen path '" + root + "'")
    print("is not a valid Crysis 3 game folder because it does not contain the application")
    print("'Bin32\crysis3.exe'. Are you sure you typed the folder correctly?")
    print("\n")
    print("This script will now exit.")
    print("\n")
    quit()



if doBackup:
    print("\nYour chosen game folder '" + root + "'")
    print("is currently being backed up to the '__gameBackup' folder in this directory.")
    print("This backup can take several minutes; please be patient!")
    print("\n")
    print("Backing up game folder...")
    print("\n\n")

    backupDir = pyRoot + "\\__gameBackup"
    for pakFile in pakFileNames:
        sourceName = root + "\\" + pakFile
        backupName = backupDir + "\\" + pakFile
        backupParentDir = os.path.dirname(backupName)

        if os.path.isfile(backupName):
            print("\nThe file '" + backupName + "'")
            print("already exists as a backup, which means that your Crysis 3 was already unlocked")
            print("previously. There is nothing more for this script to do, so it will now exit.")
            print("\n")
            quit()

        try:
            if not os.path.exists(backupParentDir):
                os.makedirs(backupParentDir)
            shutil.copyfile(sourceName, backupName)
        except Exception:
            print("\nThe file '" + sourceName + "'")
            print("could not be backed up to '" + backupDir + "'.")
            print("Please make sure that the destination location is writable, then try again.")
            print("\n")
            quit()

    for videoFile in videoFileNames:
        sourceName = root + "\\" + videoFile
        backupName = backupDir + "\\" + videoFile
        backupParentDir = os.path.dirname(backupName)

        if os.path.isfile(backupName):
            print("\nThe file '" + backupName + "'")
            print("already exists as a backup, which means that your Crysis 3 was already unlocked")
            print("previously. There is nothing more for this script to do, so it will now exit.")
            print("\n")
            quit()

        try:
            if not os.path.exists(backupParentDir):
                os.makedirs(backupParentDir)
            shutil.copyfile(sourceName, backupName)
        except Exception:
            print("\nThe file '" + sourceName + "'")
            print("could not be backed up to '" + backupDir + "'.")
            print("Please make sure that the destination location is writable, then try again.")
            print("\n")
            quit()

    for pakFile in pakFileNames: # sanity check for all backup files
        backupName = backupDir + "\\" + pakFile

        if not os.path.isfile(backupName):
            print("\nThe backup file '" + backupName + "'")
            print("does not appear to exist. If anything were to go wrong, your Crysis 3 game")
            print("would be permanently corrupted. To avoid any risk of this happening, this script")
            print("will now exit.")
            print("\n")
            quit()

    for videoFile in videoFileNames: # sanity check for all video backup files
        backupName = backupDir + "\\" + videoFile

        if not os.path.isfile(backupName):
            print("\nThe backup file '" + backupName + "'")
            print("does not appear to exist. If anything were to go wrong, your Crysis 3 game")
            print("would be permanently corrupted. To avoid any risk of this happening, this script")
            print("will now exit.")
            print("\n")
            quit()

    print("\nSuccess! Your game folder '" + root + "'")
    print("has been backed up to '" + backupDir + "'.")
    print("In the unlikely event that anything goes wrong with this script, just copy the")
    print("contents of '__gameBackup' back into your game folder. This will restore your")
    print("game to its original (unmodded) state. Make sure to overwrite all files when")
    print("prompted.")
    print("\n")
    print("This script is now ready to unlock Crysis 3. You will see several messages")
    print("during this process, which can be safely ignored unless there is an")
    print("error. DO NOT START CRYSIS 3 UNTIL THIS SCRIPT TELLS YOU TO DO SO!")
    print("\n")
    print("Are you ready to unlock Crysis 3? This process can take 30-60 minutes.")

else:
    print("\n\nYou have chosen NOT to back up '" + root + "'.")
    print("If anything goes wrong during the usage of this tool, you will have to restore")
    print("your files manually by re-downloading them from Origin.")
    print("\n")
    print("If you believe this is wrong, type 'quit' or 'q', then run this script WITHOUT")
    print("the --noBackup option. CREATING A BACKUP IS STRONGLY RECOMMENDED as it allows")
    print("you to recover much more quickly if anything goes wrong.")
    print("\n")
    print("This script is now ready to unlock Crysis 3. You will see several messages")
    print("during this process, which can be safely ignored unless there is an")
    print("error. DO NOT START CRYSIS 3 UNTIL THIS SCRIPT TELLS YOU TO DO SO!")
    print("\n")
    print("Are you ready to unlock Crysis 3? This process can take 30-60 minutes.")



proceed = ""
while len(proceed) == 0 \
        or (proceed != "y" and proceed != "Y" and proceed != "yes" and proceed != "YES" \
            and proceed.lower() != "yes"):
    proceed = input("Unlock Crysis 3? (yes/no): ")
    if proceed == "n" or proceed == "N" or proceed == "no" or proceed == "NO" \
            or proceed.lower() == "no" or proceed == "q" or proceed == "Q" \
            or proceed == "quit" or proceed == "QUIT" or proceed.lower() == "quit":
        print("\nUser requested exit. Your game folder has NOT been changed.")
        print("\n")
        quit()
print("\n\n")
print("================================================================================")
print("Decrypting original game assets (please be patient!)...")
print("\n\n")



unpackDir = pyRoot + "\\__modResources"
for pakFile in pakFileNames:
    sourceName = root + "\\" + pakFile
    destName = unpackDir + "\\" + pakFile
    destParentDir = os.path.dirname(destName)

    try:
        if not os.path.exists(destParentDir):
            os.makedirs(destParentDir)
        subprocess.check_call("bin\\unpackCrysis3.exe \"" + sourceName + "\" \"" + destName + "\"")
    except Exception:
        print("\nThe file '" + sourceName + "'")
        print("could not be unpacked to '" + unpackDir + "'.")
        print("Please make sure that the source file exists and that the destination location")
        print("is writable, then try again.")
        print("\n")
        quit()



videosDir = pyRoot + "\\__videosInput"
for videoFile in videoFileNames:
    sourceName = root + "\\" + videoFile
    destName = videosDir + "\\" + videoFile
    destParentDir = os.path.dirname(destName)

    try:
        if not os.path.exists(destParentDir):
            os.makedirs(destParentDir)
        shutil.copyfile(sourceName, destName)
    except Exception:
        print("\nThe file '" + sourceName + "'")
        print("could not be unpacked to '" + videosDir + "'.")
        print("Please make sure that the source file exists and that the destination location")
        print("is writable, then try again.")
        print("\n")
        quit()



print("\n\n")
print("================================================================================")
print("Re-encrypting assets with public modder's key (this can take 30-60 minutes!)...")
print("\n\n")



try:
    command = "run.bat \"" + unpackDir + "\" \"" + root + "\""
    subprocess.check_call(command, shell=True, cwd="bin")
except Exception:
    print("\nRe-encryption failed. Please restore your backup files from '__gameBackup', then")
    print("try again. Please also make sure that Crysis 3 is closed.")
    print("\n")
    quit()



try:
    command = "runSign.bat \"" + videosDir + "\" \"" + root + "\""
    subprocess.check_call(command, shell=True, cwd="bin")
except Exception:
    print("\nVideo signing failed. Please restore your backup files from '__gameBackup', then")
    print("try again. Please also make sure that Crysis 3 is closed.")
    print("\n")
    quit()



print("\n\n")
print("================================================================================")
print("'" + root + "' has been unlocked!")
print("\n")
print("You should now be able to install and run mods. Please note that Crysis 3 will")
print("NOT open normally unless you open 'crysis3ModEnabler.CT' in Cheat Engine first.")
print("Please see the 'readme.pdf' file for more information.")
print("\n")
print("If you ever need to revert to a 'locked' Crysis 3 (e.g. to play multiplayer),")
print("just copy the contents of '__gameBackup' back into your Crysis 3 game folder.")
print("Make sure to overwrite all files when prompted.")
print("\n")
print("To create or use mods, please see the 'readme.pdf' file. Resources for modders")
print("have been copied into the '__modResources' folder in this directory.")
print("\n")
print("UNLOCKED CRYSIS HAS ONLY BEEN TESTED OFFLINE IN SINGLEPLAYER. MAKE SURE YOU ARE")
print("OFFLINE BEFORE ATTEMPTING TO RUN AN UNLOCKED CRYSIS 3. IF YOU RUN CRYSIS 3 WHILE")
print("ONLINE OR DURING MULTIPLAYER, YOU MAY RECEIVE A TEMPORARY OR PERMANENT BAN. THE")
print("SCRIPT AUTHOR IS NOT LIABLE FOR ANY DAMAGES INCURRED FROM USING UNLOCKED CRYSIS.")
print("\n")
print("Have fun!")
print("This script will now exit.")
print("\n")
