#Preload Exception handler import sys def preloadExceptionHandler(exc_type, exc_value, tb): import traceback print("An error has occurred while initializing:") traceback.print_exception(exc_type, exc_value, tb) input("\nPress ENTER to exit.") sys.exit(-1) #sys.excepthook = preloadExceptionHandler #Imports and variables import ctypes import os import shutil import webbrowser import time import stat scriptPath = os.path.dirname(os.path.realpath(__file__)) appPath = False appName = False originalAppPath = False tmpAppPath = False modPath = False originalModPath = False #Exception Handler def openFileWithStandardApp(path): # Windows if os.name == "nt": os.startfile(path) # Macintosh elif sys.platform == "darwin": subprocess.call(['open', path]) # Generic Unix (X11) else: subprocess.call(['xdg-open', path]) def exceptionCleanup(): success = True print("Attempting cleanup.") print("\nMaking folders visible...") try: #ctypes.windll.kernel32.SetFileAttributesW(appPath,128) #ctypes.windll.kernel32.SetFileAttributesW(originalAppPath,128) pass except Exception as e: success = False print(str(e)) print("\nUnloading mods...") try: unloadMods() except Exception as e: success = False print(str(e)) print("\nCleaning up temporary files...") try: cleanUp() except Exception as e: success = False print(str(e)) if success == False: print("\nCleanup not fully successful. Please review the errors, and go to X for a guide on how to reset your game manually. Sorry for the inconvenience, I tried :(") return success def logError(logFilePath,textList): logFile = False try: logFile = open(logFilePath,"w") except: return False try: for line in textList: logFile.write(line + "\n") except: logFile.close() return False logFile.close() return True def exceptionHandler(exc_type, exc_value, tb): clear() print("An error occurred, trying to revert everything...") exceptionCleanup() input() #sys.excepthook = exceptionHandler #Modloader def cloneMods(modDir): for root,dirs,files in walklevel(modDir,0): for dir in dirs: if dir[0] == "-": continue if dir[0] == "[" and dir[-1:] == "]": cloneMods(os.path.join(root,dir)) else: print("Applying Mod: " +dir) if os.path.isfile(os.path.join(root,dir,"uml_installscript.py")) == True: file = open(os.path.join(root,dir,"uml_installscript.py")) exec(file.read(),globals(),locals()) file.close() else: cloneFolder(os.path.join(root,dir),tmpAppPath,True,False,True) def loadMods(output = False): if areModsLoaded(): if unloadMods() == False: if output: print("Unloading mods failed!") return False print("Claiming app folder...") claimFolder(appPath) print("Claiming mod folder...") claimFolder(modPath) print("Cloning app folder...") cloneFolder(appPath,tmpAppPath,False) print("Cloning mods...") cloneMods(modPath) os.rename(appPath,originalAppPath) os.rename(tmpAppPath,appPath) #ctypes.windll.kernel32.SetFileAttributesW(originalAppPath,2) if output: print("\nMods have been loaded!") return True def unloadMods(output = False): if areModsLoaded() == False: if output: print("Mods are already unloaded.") return True print("Removing cloned app folder...") shutil.rmtree(appPath) os.rename(originalAppPath,appPath) #ctypes.windll.kernel32.SetFileAttributesW(appPath,128) if output: print("\nUnloading mods successful.") return True def openModsFolder(): if areModsLoaded(): webbrowser.open("file:///" +originalModPath) else: webbrowser.open("file:///" +modPath) def areModsLoaded(): if os.path.isdir(originalAppPath): return True return False def cloneFolder(src,dst,rpl,ignoreMods = True, isMod = False): for root,dirs,files in os.walk(src): newRoot = root.replace(src,dst) if ignoreMods == True: if root.replace(modPath,"") != root: continue if os.path.isdir(newRoot) == False: os.makedirs(newRoot) for file in files: if isMod == True: if file[:4] == "uml_": continue fullFile = os.path.join(root,file) newFile = os.path.join(newRoot,file) if os.path.isfile(newFile): if rpl == True: os.remove(newFile) os.link(fullFile,newFile) else: os.link(fullFile,newFile) def claimFolder(path): os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) for root,dirs,files in os.walk(path): for dir in dirs: os.chmod(os.path.join(root,dir), stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) for file in files: os.chmod(os.path.join(root,file), stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) def walklevel(some_dir, level=1): some_dir = some_dir.rstrip(os.path.sep) assert os.path.isdir(some_dir) num_sep = some_dir.count(os.path.sep) for root, dirs, files in os.walk(some_dir): yield root, dirs, files num_sep_this = root.count(os.path.sep) if num_sep + level <= num_sep_this: del dirs[:] def title(string): if os.name == "nt": os.system("title " +string) else: sys.stdout.write("\x1b]2;" +string+ "\x07") def clear(): os.system('cls' if os.name=='nt' else 'clear') def cleanUp(): if os.path.isdir(tmpAppPath): shutil.rmtree(tmpAppPath) def checkUp(): if os.path.isdir(modPath) == False: while True: clear() print("You selected the following path: '" +appPath+ "'") choice = input("Do you wish to set up that folder for mod-use? (y/n)\n") if choice == "y": os.makedirs(modPath) #ctypes.windll.kernel32.SetFileAttributesW(modPath,2) return if choice == "n": sys.exit(-1) def mainMenu(): clear() if areModsLoaded() == False: print("Welcome to Fier's Universal Modloader.") print("Mods are not loaded.") print("") print("Please choose an action:") print("1) Load Mods") print("2) Open Mods-Folder") choice = input("Choice: ") clear() if choice == "1": loadMods(True); input("Press ENTER to continue.") if choice == "2": openModsFolder() else: print("Welcome to Fier's Universal Modloader.") print("Mods are loaded.") print("") print("Please choose an action:") print("1) Reload Mods") print("2) Unload Mods") print("3) Open Mods-Folder") choice = input("Choice: ") clear() if choice == "1": loadMods(True); input("Press ENTER to continue.") if choice == "2": unloadMods(True); input("Press ENTER to continue.") if choice == "3": openModsFolder() def requestAppPath(): while True: clear() dir = input("Please insert a folder via Drag&Drop:\n") dir = dir.replace('"',"") if os.path.isdir(dir) == True: return dir def setupVariables(): global appPath global appName global originalAppPath global tmpAppPath global modPath global originalModPath if len(sys.argv) < 2: appPath = requestAppPath() else: appPath = sys.argv[1] if os.path.isdir(appPath) == False: raise NameError("Folder not found: " +appPath) if os.path.isdir(appPath.replace(" - umlOriginal","")): appPath = appPath.replace(" - umlOriginal","") appName = appPath.replace(os.path.dirname(appPath)+ "\\","") originalAppPath = appPath + " - umlOriginal" tmpAppPath = appPath + " - umlTemp" modPath = os.path.join(appPath + " - umlMods") originalModPath = modPath #Init setupVariables() title("Fier's Universal Modloader: " +appName) cleanUp() checkUp() while True: mainMenu()