UniversalModloader/UniversalModloader.py
Fierelier e4569f1c57 Basic error correction
- Added basic error correction.
- Program now asks before setting up the game for mod-use
2017-07-21 14:23:23 +02:00

294 lines
7.6 KiB
Python

#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
logtext = ""
logtext = logtext + "Attempting cleanup.\n"
logtext = logtext + "Making folders visible...\n"
try:
ctypes.windll.kernel32.SetFileAttributesW(appPath,128)
ctypes.windll.kernel32.SetFileAttributesW(originalAppPath,128)
except Exception as e:
success = False
logtext = logtext + str(e) + "\n"
logtext = logtext + "Unloading mods...\n"
try:
unloadMods()
except Exception as e:
success = False
logtext = logtext + str(e) + "\n"
logtext = logtext + "Cleaning up temporary files...\n"
try:
cleanUp()
except Exception as e:
success = False
logtext = logtext + str(e) + "\n"
if success == False:
logtext = logtext + "\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 logtext
def exceptionHandler(exc_type, exc_value, tb):
import traceback
while True:
clear()
print("An exception has occurred:")
traceback.print_exception(exc_type, exc_value, tb)
cleanupLog = exceptionCleanup()
print("\n" +cleanupLog)
choice = input("\nWould you like to log this exception? (y/n)\n")
if choice.lower() == "y":
success = False
fileCreated = False
errorFilePath = os.path.join(scriptPath,"error.log")
try:
errorFile = open(errorFilePath,"w")
fileCreated = True
try:
traceback.print_exception(exc_type, exc_value, tb, None, errorFile)
errorFile.write("\n" +cleanupLog)
success = True
except:
input("Writing to errorlog-file failed. Press ENTER to continue.")
except:
input("Creating errorlog-file failed. Press ENTER to continue.")
if fileCreated: errorFile.close()
if success:
try:
openFileWithStandardApp(errorFilePath)
except:
input("Opening errorlog-file failed. You can find it at '" +errorFilePath+ "'. Press ENTER to continue.")
elif choice.lower() != "n":
continue
sys.exit(-1)
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:
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
claimFolder(appPath)
cloneFolder(appPath,tmpAppPath,False)
cloneMods(modPath)
os.rename(appPath,originalAppPath)
os.rename(tmpAppPath,appPath)
ctypes.windll.kernel32.SetFileAttributesW(originalAppPath,2)
if output: print("Mods have been loaded!")
return True
def unloadMods(output = False):
if areModsLoaded() == False:
if output: print("Mods are already unloaded.")
return True
shutil.rmtree(appPath)
os.rename(originalAppPath,appPath)
ctypes.windll.kernel32.SetFileAttributesW(appPath,128)
if output: print("Unloading 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)
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 areModsLoaded() == False:
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)
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 = os.path.join(originalAppPath,"umlMods")
#Init
setupVariables()
title("Fier's Universal Modloader: " +appName)
cleanUp()
checkUp()
while True:
mainMenu()