241 lines
5.6 KiB
Python
Executable File
241 lines
5.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import sys
|
|
import os
|
|
import shutil
|
|
import webbrowser
|
|
import configparser
|
|
import subprocess
|
|
import ctypes
|
|
|
|
oldexcepthook = sys.excepthook
|
|
def newexcepthook(type,value,traceback):
|
|
oldexcepthook(type,value,traceback)
|
|
input("Press ENTER to quit.")
|
|
sys.excepthook = newexcepthook
|
|
|
|
p = os.path.join
|
|
pUp = os.path.dirname
|
|
s = False
|
|
if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
|
|
s = os.path.realpath(sys.executable)
|
|
else:
|
|
s = os.path.realpath(__file__)
|
|
sp = pUp(s)
|
|
|
|
version = (1,2,0,"beta (dev)")
|
|
pathGame = ""
|
|
pathTemp = ""
|
|
pathOrig = ""
|
|
pathMods = ""
|
|
stateModded = False
|
|
listLinked = []
|
|
listLinkedFolders = []
|
|
config = configparser.ConfigParser()
|
|
config["default"] = {
|
|
"linkMethod": "hardlink"
|
|
}
|
|
config.read(p(sp,os.path.splitext(os.path.basename(s))[0] + ".ini"))
|
|
if config["default"]["linkMethod"] == "reflink":
|
|
fancyReflink = False
|
|
try:
|
|
from reflink import reflink
|
|
fancyReflink = True
|
|
except:
|
|
print("python3-reflink not installed, using shell for reflink (slow)\n")
|
|
|
|
|
|
def filterDd(text):
|
|
while text[-1] in ['"',"'"," ",os.path.sep]: text = text[:-1]
|
|
while text[0] in ['"',"'"," "]: text = text[1:]
|
|
return text
|
|
|
|
def questionYesNo(text):
|
|
while True:
|
|
response = input(text).lower()
|
|
if response == "y": return True
|
|
if response == "n": return False
|
|
|
|
def questionMultChoice(options):
|
|
length = len(options)
|
|
index = 0
|
|
while index < length:
|
|
print(str(index + 1)+ ": " +options[index])
|
|
index = index + 1
|
|
|
|
response = input("Choice: ")
|
|
try:
|
|
response = int(response)
|
|
except:
|
|
return False
|
|
|
|
if response < 1: return False
|
|
if response > index: return False
|
|
return options[response - 1]
|
|
|
|
def getModState():
|
|
if os.path.isdir(pathOrig):
|
|
return True
|
|
|
|
return False
|
|
|
|
def getModlist(path,sort = True):
|
|
modList = []
|
|
for root,dirs,files in os.walk(path):
|
|
for file in dirs:
|
|
ffile = p(root,file)
|
|
lfile = ffile.replace(path + os.path.sep,"",1)
|
|
if lfile[0] == "-": continue
|
|
if lfile[0] == "[" and lfile[-1] == "]":
|
|
modList = modList + getModlist(ffile,False)
|
|
continue
|
|
|
|
modList.append(ffile)
|
|
break
|
|
|
|
if sort == True: return sorted(modList)
|
|
return modList
|
|
|
|
btrfsdll = False
|
|
def linkFile(src,dst,method = False):
|
|
if not method: method = config["default"]["linkMethod"]
|
|
if method == "hardlink":
|
|
os.link(src,dst)
|
|
return
|
|
|
|
if method == "copy":
|
|
shutil.copy(src,dst)
|
|
return
|
|
|
|
if method == "reflink":
|
|
if fancyReflink == False:
|
|
if os.name == "nt":
|
|
global btrfsdll
|
|
if not btrfsdll: btrfsdll = ctypes.cdll.LoadLibrary("shellbtrfs.dll")
|
|
btrfsdll.ReflinkCopyW(0,0,'"' +src+ '" "' +dst+ '"',1)
|
|
else:
|
|
subprocess.call(["cp","-n","--reflink=always",src,dst])
|
|
return
|
|
else:
|
|
reflink(src,dst)
|
|
return
|
|
|
|
raise Exception("uml", "invalid link method")
|
|
|
|
|
|
def cloneFolder(src,dst):
|
|
global listLinked
|
|
global listLinkedFolders
|
|
|
|
for root,dirs,files in os.walk(src):
|
|
for file in dirs:
|
|
ffile = p(root,file)
|
|
lfile = ffile.replace(src + os.path.sep,"",1)
|
|
nfile = p(dst,lfile)
|
|
nnfile = nfile
|
|
if config["default"]["windowsPaths"] == "true": nnfile = nnfile.lower()
|
|
if nnfile in listLinkedFolders: continue
|
|
os.makedirs(nfile)
|
|
listLinkedFolders.append(nnfile)
|
|
|
|
for file in files:
|
|
ffile = p(root,file)
|
|
lfile = ffile.replace(src + os.path.sep,"",1)
|
|
nfile = p(dst,lfile)
|
|
nnfile = nfile
|
|
if config["default"]["windowsPaths"] == "true": nnfile = nnfile.lower()
|
|
if nnfile in listLinked: continue
|
|
linkFile(ffile,nfile)
|
|
listLinked.append(nnfile)
|
|
|
|
def loadMods():
|
|
print("")
|
|
global listLinked
|
|
global listLinkedFolders
|
|
global stateModded
|
|
|
|
os.makedirs(pathTemp)
|
|
|
|
print("Getting mod-list...")
|
|
listMods = getModlist(pathMods)
|
|
|
|
for ffile in reversed(listMods):
|
|
lfile = ffile.replace(pathMods + os.path.sep,"",1)
|
|
print("Load mod: " +lfile)
|
|
cloneFolder(ffile,pathTemp)
|
|
|
|
print("Linking game...")
|
|
cloneFolder(pathGame,pathTemp)
|
|
os.rename(pathGame,pathOrig)
|
|
os.rename(pathTemp,pathGame)
|
|
|
|
listLinked = []
|
|
listLinkedFolders = []
|
|
stateModded = True
|
|
|
|
def unloadMods():
|
|
global stateModded
|
|
print("")
|
|
print("Removing modded game...")
|
|
shutil.rmtree(pathGame)
|
|
print("Renaming original game...")
|
|
os.rename(pathOrig,pathGame)
|
|
stateModded = False
|
|
|
|
def main():
|
|
global pathGame, pathMods, pathTemp, pathOrig, stateModded
|
|
pathGame = ""
|
|
if len(sys.argv) > 1:
|
|
pathGame = sys.argv[1]
|
|
|
|
while pathGame == "" or os.path.isdir(pathGame) == False:
|
|
pathGame = filterDd(input("Path to game - you may drag & drop:\n"))
|
|
|
|
pathGame = pathGame.rstrip("/\\")
|
|
pathMods = pathGame + " - umlMods"
|
|
pathTemp = pathGame + " - umlTemp"
|
|
pathOrig = pathGame + " - umlOriginal"
|
|
|
|
if not os.path.isdir(pathMods):
|
|
if questionYesNo("\nIt doesn't look like you modded this game before.\nDo you want to create the mod folder? (y/n)\n") == True:
|
|
os.makedirs(pathMods)
|
|
else:
|
|
sys.exit()
|
|
|
|
if os.path.isdir(pathTemp):
|
|
print("\nRemoving temporary folder...")
|
|
shutil.rmtree(pathTemp)
|
|
|
|
stateModded = getModState()
|
|
|
|
while True:
|
|
print("")
|
|
print("Modded: " +str(stateModded))
|
|
choice = False
|
|
|
|
if stateModded == False: choice = questionMultChoice([
|
|
"Load mods",
|
|
"Open mod-folder"
|
|
])
|
|
|
|
if stateModded == True: choice = questionMultChoice([
|
|
"Reload mods",
|
|
"Unload mods",
|
|
"Open mod-folder"
|
|
])
|
|
|
|
curModState = getModState()
|
|
if curModState != stateModded:
|
|
stateModded = curModState
|
|
print("\nMod-state has changed, refreshing menu.")
|
|
continue
|
|
|
|
if choice == False: continue
|
|
if choice == "Load mods": loadMods()
|
|
if choice == "Reload mods": unloadMods(); loadMods()
|
|
if choice == "Unload mods": unloadMods()
|
|
if choice == "Open mod-folder": webbrowser.open("file://" +pathMods)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|