#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 class uml: version = 0 versionSub = 8 versionSub2 = 1 versionBranch = "beta (dev)" versionString = str(version) + "." + str(versionSub) + "." +str(versionSub2)+ " " + versionBranch 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 api = True #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 testAccess(path): try: os.rename(path,path) return True except: return False 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: if areModsLoaded(): if output: print("Mods are already loaded and could not be unloaded.") return False #print("Claiming app folder...") #claimFolder(appPath) #print("Claiming mod folder...") #claimFolder(modPath) print("Testing access...") if testAccess(appPath) == False: if output: print("Can't access folder! Is it in use?") return print("Cloning app folder...") cloneFolder(appPath,tmpAppPath,False) print("Cloning mods...") cloneMods(modPath) os.rename(appPath,originalAppPath) os.rename(tmpAppPath,appPath) else: print("Testing access...") if testAccess(appPath) == False: if output: print("Can't access folder! Is it in use?") return 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("Testing access...") if testAccess(appPath) == False: if output: print("Can't access folder! Is it in use?") return print("Removing cloned app folder...") try: shutil.rmtree(appPath) except: if output: print("Can't delete folder! Is it in use?") return tries = 0 while tries < 100: try: os.rename(originalAppPath,appPath) tries + 1 except: time.sleep(0.1) tries + 1 else: break #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 api == True: return 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") if (dir[0] == '"' and dir[-1] == '"') or (dir[0] == "'" and dir[-1] == "'"): dir = dir[1:-1] if dir == "console": console() else: if os.path.isdir(dir) == True: return dir def console(): clear() print("UniversalModloader Console") print("Version: " +uml.versionString) while True: print("") cmd = input(os.getcwd()+ ">") if cmd == "exit": return if cmd.startswith("cd "): try: os.chdir(cmd[3:]) continue except Exception as e: print(e) continue continue if cmd.startswith("pyc "): try: exec(cmd[4:]) continue except Exception as e: print(e) continue if cmd.startswith("mc "): try: cloneFolder(cmd[3:],cmd[3:] + " - clone",True,False) continue except Exception as e: print(e) continue os.system(cmd) 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)+ os.sep,"") originalAppPath = appPath + " - umlOriginal" tmpAppPath = appPath + " - umlTemp" modPath = os.path.join(appPath + " - umlMods") originalModPath = modPath def init(): global api api = False title("Fier's Universal Modloader - " +uml.versionString) setupVariables() title("Fier's Universal Modloader - " +uml.versionString+ " : " +appName) cleanUp() checkUp() while True: mainMenu() if __name__ == "__main__": init()