#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 umlBuild = 0 umlVer = 0 umlFeatureSet = 7.1 umlBranch = "beta (dev)" umlVerStr = str(umlVer) + "." + str(umlFeatureSet) + "." +str(umlBuild)+ " " + umlBranch 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, fast = False): if fast == False: if areModsLoaded(): if unloadMods() == False: if output: print("Unloading mods failed!") return False if fast == True: if areModsLoaded() == False: if output: print("Can not fast-load mods when mods aren't loaded.") return False if fast == 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) else: os.rename(appPath,tmpAppPath) cloneMods(modPath) 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): maxCount = 0 count = 0 for root,dirs,files in os.walk(src): newRoot = root.replace(src,dst) if ignoreMods == True: if root.replace(modPath,"") != root: continue maxCount = maxCount + len(files) sys.stdout.write("\r" +str(count)+ "/" +str(maxCount)) sys.stdout.flush() 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: count = count + 1 sys.stdout.write("\r" +str(count)+ "/" +str(maxCount)) sys.stdout.flush() 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) print("") 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) Fast-Load Mods") print("3) Unload Mods") print("4) Open Mods-Folder") choice = input("Choice: ") clear() if choice == "1": loadMods(True); input("Press ENTER to continue.") if choice == "2": loadMods(True,True); input("Press ENTER to continue.") if choice == "3": unloadMods(True); input("Press ENTER to continue.") if choice == "4": openModsFolder() def requestAppPath(): while True: clear() dir = input("Please insert a folder via Drag&Drop:\n") dir = dir.replace('"',"") if dir == "console": console() else: if os.path.isdir(dir) == True: return dir def console(): clear() print("UniversalModloader Console") print("Version: " +umlVerStr) print("") while True: cmd = input(os.getcwd()+ ">") if cmd == "exit": return if cmd.startswith("pyc "): try: exec(cmd[4:]) except Exception as e: print(e) else: os.system(cmd) print("") 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 appPath == "console": console() 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 title("Fier's Universal Modloader - " +umlVerStr) setupVariables() title("Fier's Universal Modloader - " +umlVerStr+ " : " +appName) cleanUp() checkUp() while True: mainMenu()