From d0c4814e757deb14d07791ac98d5b2371dcc22e3 Mon Sep 17 00:00:00 2001 From: Fierelier Date: Fri, 13 May 2022 12:36:23 +0200 Subject: [PATCH] Split code into modules --- offline-minecraft-launcher.py | 324 ++++------------------------------ oml/modules/01_main.modlist | 3 + oml/modules/colorama.py | 54 ++++++ oml/modules/download.py | 28 +++ oml/modules/minecraft.py | 223 +++++++++++++++++++++++ 5 files changed, 346 insertions(+), 286 deletions(-) create mode 100644 oml/modules/01_main.modlist create mode 100644 oml/modules/colorama.py create mode 100644 oml/modules/download.py create mode 100644 oml/modules/minecraft.py diff --git a/offline-minecraft-launcher.py b/offline-minecraft-launcher.py index ef9aaf3..37a0e8e 100644 --- a/offline-minecraft-launcher.py +++ b/offline-minecraft-launcher.py @@ -22,66 +22,36 @@ import subprocess import json import hashlib import platform -import urllib.request import re import copy -class coloramaFallback: - class Fore: - BLACK = "" - RED = "" - GREEN = "" - YELLOW = "" - BLUE = "" - MAGENTA = "" - CYAN = "" - WHITE = "" - RESET = "" - - class Back: - BLACK = "" - RED = "" - GREEN = "" - YELLOW = "" - BLUE = "" - MAGENTA = "" - CYAN = "" - WHITE = "" - RESET = "" - - class Style: - DIM = "" - NORMAL = "" - BRIGHT = "" - RESET_ALL = "" +omlPath = p(sp,"oml") -def coloramaInit(): - global colorama - coloramaSuccess = False - if not "-nocolor" in sys.argv: - try: - import colorama - colorama.init() - coloramaSuccess = True - except Exception as e: - print("Could not import/init colorama: " +str(e),file=sys.stderr) - print("Colors deactivated.\n",file=sys.stderr) +def runCode(str, lcs = False, description = "loose-code"): + if lcs == False: lcs = {} + code = compile(str,description,"exec") + exec(code,globals(),lcs) + return lcs - if not coloramaSuccess: - colorama = coloramaFallback - -def colored(color,st,bright = True): - if bright: - st = colorama.Style.BRIGHT + st +def runScript(sf, lcs = False): + if lcs == False: lcs = {} - return color + st + colorama.Style.RESET_ALL + code = False + with open(sf,"r",encoding="utf-8") as script: + code = script.read() + + runCode(code,lcs,sf) + return lcs -def download(url,decode = "utf-8"): - request = urllib.request.Request(url,headers={"User-Agent":"Mozilla/5.0"}) - response = urllib.request.urlopen(request) - rt = response.read() - if decode == False: return rt - return response.read().decode(decode) +def readGenericListFile(path): + rtn = [] + with open(path,"r",encoding="utf-8") as listf: + for line in listf: + line = line.split("#",1)[0] + line = line.strip(" \t\r\n") + if line == "": continue + rtn.append(line) + return rtn def readFile(file,decode = "utf-8"): fileh = False @@ -91,246 +61,28 @@ def readFile(file,decode = "utf-8"): if decode == False: return data return data.decode(decode) -def fileDl(url,file,read = True,decode = "utf-8"): - if os.path.isfile(file): - if read == True: - return readFile(file,decode) - return - - #print(url) - data = download(url,False) - fileh = open(tmpFile,"wb") - fileh.write(data) - fileh.close() - if pUp(file) != "" and not os.path.isdir(pUp(file)): os.makedirs(pUp(file)) - os.rename(tmpFile,file) - if read == False: return - if decode == False: return data - return data.decode(decode) - def readJsonFile(file): fileh = open(file,"r") data = fileh.read() fileh.close() return json.loads(data) -def findArgument(args,searchFor): - for arg in args: - if arg.startswith(searchFor): return True - return False - -def findInChain(versionsPath,version,path): - versionPath = p(versionsPath,version) - clientJson = readJsonFile(p(versionPath,version + ".json")) - curPath = copy.deepcopy(clientJson) - success = True - for dir in path: - if dir in curPath: - curPath = curPath[dir] - else: - success = False - break - - if success == False: - return findInChain(versionsPath,clientJson["inheritsFrom"],path) - return curPath - -def findInChainDeepest(versionsPath,version,path): - found = False - while True: - versionPath = p(versionsPath,version) - clientJson = readJsonFile(p(versionPath,version + ".json")) - curPath = copy.deepcopy(clientJson) - for dir in path: - if dir in curPath: - curPath = curPath[dir] - else: - if "inheritsFrom" in clientJson: - version = clientJson["inheritsFrom"] - continue - else: - curPath = False - break - - found = curPath - if "inheritsFrom" in clientJson: - version = clientJson["inheritsFrom"] - continue - else: - break - - if found == False: raise - return found - -def parseJavaLibraryName(libName): - libSplit = libName.split(":",2) - libPackage = libSplit[0] - libName = libSplit[1] - libVersion = libSplit[2] - libFilePath = libPackage.replace(".","/") + "/" +libName+ "/" +libVersion+ "/" +libName+ "-" +libVersion+ ".jar" - return libPackage,libName,libVersion,libFilePath - -def checkRules(ruleList): - action = "disallow" - for rule in ruleList: - if "os" in rule: - if "name" in rule["os"]: - rule["os"]["name"] = rule["os"]["name"].replace("osx","macos") - if not re.search(rule["os"]["name"],lv["osName"]): continue - - if "arch" in rule["os"]: - if not re.search(rule["os"]["arch"],lv["jvmArch"]): continue - - if "version" in rule["os"]: - if not re.search(rule["os"]["version"],lv["osVersion"]): continue - - action = rule["action"] - else: - action = rule["action"] - - return action - -def getLibraryPrettyName(library): - libraryName = library["package"]+ ":" +library["name"]+ ":" +library["version"] - if library["type"] == "native": - libraryName += " (" +library["nativeOS"]+ ")" - return libraryName - -def getFileHash(file): - with open(file,"rb") as fileh: - return hashlib.sha1(fileh.read()).hexdigest() - -def checkLibraryHash(library): - hash = False - if library["dumb"] == False: - if library["type"] == "library": - hash = library["data"]["downloads"]["artifact"]["sha1"] - else: - hash = library["data"]["downloads"]["classifiers"]["natives-" +library["nativeOS"]]["sha1"] - else: - if not os.path.isfile(library["filePathOS"] + ".sha1"): - print(colored(colorama.fore.RED,"No .sha1 file found, can't verify."),file=sys.stderr) - return False - else: - with open(library["filePathOS"] + ".sha1","r") as fileh: - hash = fileh.read() - - match = (hash == getFileHash(library["filePathOS"])) - if not match: - print(colored(colorama.Fore.RED,library["filePathOS"]+ " is corrupt!"),file=sys.stderr) - - return match - -def processVersion(versionsPath,libraryPath,nativePath,version): - versionPath = p(versionsPath,version) - clientJson = readJsonFile(p(versionPath,version + ".json")) - libraries = [] - arguments = [] - jvmArguments = [] - - if "inheritsFrom" in clientJson: - _,libraries,_,_= processVersion(versionsPath,libraryPath,nativePath,clientJson["inheritsFrom"]) - - for library in clientJson["libraries"]: - lBase = {} - lBase["package"],lBase["name"],lBase["version"],lBase["filePath"] = parseJavaLibraryName(library["name"]) - lBase["type"] = "library" - lBase["data"] = library - lBase["dumb"] = False - - if "downloads" in library: # not dumb - if "classifiers" in library["downloads"]: # classifiers (usually for natives, their sources and their documentation) - for classifier in library["downloads"]["classifiers"]: - l = copy.deepcopy(lBase) - native = library["downloads"]["classifiers"][classifier] - if classifier.startswith("natives-"): - l["type"] = "native" - l["nativeOS"] = classifier.replace("natives-","",1) - else: - continue # TODO: add source and javadoc handling - - l["filePathOS"] = p(nativePath,native["path"].replace("/",os.path.sep)) - if "url" in native and native["url"] != "": - l["url"] = native["url"] - - libraries.append(l) - - if "artifact" in library["downloads"]: # artifact (usually for libraries) - l = copy.deepcopy(lBase) - if "path" in library["downloads"]["artifact"]: - l["filePathOS"] = p(libraryPath,library["downloads"]["artifact"]["path"].replace("/",os.path.sep)) - - if "url" in library["downloads"]["artifact"] and library["downloads"]["artifact"]["url"] != "": - l["url"] = library["downloads"]["artifact"]["url"] - - libraries.append(l) - else: # dumb - lBase["dumb"] = True - if "natives" in library: # natives - lBaseTwo = copy.deepcopy(lBase) - lBaseTwo["type"] = "native" - if not "url" in library: - lBaseTwo["url"] = "https://libraries.minecraft.net" - else: - lBaseTwo["url"] = library["url"] - - while len(lBaseTwo["url"]) > 0 and lBaseTwo["url"][-1] == "/": lBaseTwo["url"] = lBaseTwo["url"][:-1] - lBaseTwo["url"] = lBaseTwo["url"] + "/" + lBaseTwo["filePath"] - - for native in library["natives"]: - l = copy.deepcopy(lBaseTwo) - l["nativeOS"] = native - native = "natives-" + native - l["filePath"] = l["filePath"][:-4] + "-" + native + ".jar" - l["url"] = l["url"][:-4] + "-" + native + ".jar" - l["filePathOS"] = p(nativePath,l["filePath"].replace("/",os.path.sep)) - libraries.append(l) - else: # libraries - l = copy.deepcopy(lBase) - if not "url" in library: - l["url"] = "https://libraries.minecraft.net" - else: - l["url"] = library["url"] - - while len(l["url"]) > 0 and l["url"][-1] == "/": l["url"] = l["url"][:-1] - l["url"] = l["url"] + "/" + l["filePath"] - l["filePathOS"] = p(libraryPath,l["filePath"].replace("/",os.path.sep)) - libraries.append(l) - - if os.path.isfile(p(versionPath,version + ".jar")): - libraries.append({"type":"client","filePathOS":p(versionPath,version + ".jar")}) - - if "arguments" in clientJson: - if "game" in clientJson["arguments"]: - for arg in clientJson["arguments"]["game"]: - if type(arg) != str: continue - arguments.append(arg) - if "jvm" in clientJson["arguments"]: - for arg in clientJson["arguments"]["jvm"]: - if type(arg) != str: - if "value" in arg: - if type(arg["value"]) != list: - arg["value"] = [arg["value"]] - - if "rules" in arg: - if checkRules(arg["rules"]) == "allow": - for value in arg["value"]: - jvmArguments.append(value) - else: - for value in arg["value"]: - jvmArguments.append(value) - else: - jvmArguments.append(arg) - elif "minecraftArguments" in clientJson: - margs = clientJson["minecraftArguments"].replace('"',"").split(" ") - for arg in margs: - if type(arg) != str: continue - arguments.append(arg) - - return clientJson,libraries,arguments,jvmArguments - def main(): - coloramaInit() + print("Running modules...") + for root,dirs,files in os.walk(p(omlPath,"modules")): + for file in files: + sfile = file.rsplit(".",1) + if len(sfile) < 2: continue + if sfile[1] != "modlist": continue + ffile = p(root,file) + lfile = ffile.replace(p(omlPath,"modules") + os.path.sep,"",1) + print("> " +lfile) + for mod in readGenericListFile(ffile): + print(">> " +mod+ " ...") + runScript(p(omlPath,"modules",mod)) + break + print("") + print(colored(colorama.Fore.GREEN,"Reading config...")) config = configparser.ConfigParser() config.optionxform = str diff --git a/oml/modules/01_main.modlist b/oml/modules/01_main.modlist new file mode 100644 index 0000000..2a481a8 --- /dev/null +++ b/oml/modules/01_main.modlist @@ -0,0 +1,3 @@ +colorama.py +download.py +minecraft.py \ No newline at end of file diff --git a/oml/modules/colorama.py b/oml/modules/colorama.py new file mode 100644 index 0000000..6ea79d2 --- /dev/null +++ b/oml/modules/colorama.py @@ -0,0 +1,54 @@ +def main(): + class coloramaFallback: + class Fore: + BLACK = "" + RED = "" + GREEN = "" + YELLOW = "" + BLUE = "" + MAGENTA = "" + CYAN = "" + WHITE = "" + RESET = "" + + class Back: + BLACK = "" + RED = "" + GREEN = "" + YELLOW = "" + BLUE = "" + MAGENTA = "" + CYAN = "" + WHITE = "" + RESET = "" + + class Style: + DIM = "" + NORMAL = "" + BRIGHT = "" + RESET_ALL = "" + + def coloramaInit(): + global colorama + coloramaSuccess = False + if not "-nocolor" in sys.argv: + try: + import colorama + colorama.init() + coloramaSuccess = True + except Exception as e: + print("Could not import/init colorama: " +str(e),file=sys.stderr) + print("Colors deactivated.\n",file=sys.stderr) + + if not coloramaSuccess: + colorama = coloramaFallback + + coloramaInit() +main() + +global colored +def colored(color,st,bright = True): + if bright: + st = colorama.Style.BRIGHT + st + + return color + st + colorama.Style.RESET_ALL \ No newline at end of file diff --git a/oml/modules/download.py b/oml/modules/download.py new file mode 100644 index 0000000..fd7b1d7 --- /dev/null +++ b/oml/modules/download.py @@ -0,0 +1,28 @@ +global urllib +import urllib.request + +global download +def download(url,decode = "utf-8"): + request = urllib.request.Request(url,headers={"User-Agent":"Mozilla/5.0"}) + response = urllib.request.urlopen(request) + rt = response.read() + if decode == False: return rt + return response.read().decode(decode) + +global fileDl +def fileDl(url,file,read = True,decode = "utf-8"): + if os.path.isfile(file): + if read == True: + return readFile(file,decode) + return + + #print(url) + data = download(url,False) + fileh = open(tmpFile,"wb") + fileh.write(data) + fileh.close() + if pUp(file) != "" and not os.path.isdir(pUp(file)): os.makedirs(pUp(file)) + os.rename(tmpFile,file) + if read == False: return + if decode == False: return data + return data.decode(decode) \ No newline at end of file diff --git a/oml/modules/minecraft.py b/oml/modules/minecraft.py new file mode 100644 index 0000000..4aafc12 --- /dev/null +++ b/oml/modules/minecraft.py @@ -0,0 +1,223 @@ +global findInChain +def findInChain(versionsPath,version,path): + versionPath = p(versionsPath,version) + clientJson = readJsonFile(p(versionPath,version + ".json")) + curPath = copy.deepcopy(clientJson) + success = True + for dir in path: + if dir in curPath: + curPath = curPath[dir] + else: + success = False + break + + if success == False: + return findInChain(versionsPath,clientJson["inheritsFrom"],path) + return curPath + +global findInChainDeepest +def findInChainDeepest(versionsPath,version,path): + found = False + while True: + versionPath = p(versionsPath,version) + clientJson = readJsonFile(p(versionPath,version + ".json")) + curPath = copy.deepcopy(clientJson) + for dir in path: + if dir in curPath: + curPath = curPath[dir] + else: + if "inheritsFrom" in clientJson: + version = clientJson["inheritsFrom"] + continue + else: + curPath = False + break + + found = curPath + if "inheritsFrom" in clientJson: + version = clientJson["inheritsFrom"] + continue + else: + break + + if found == False: raise + return found + +global parseJavaLibraryName +def parseJavaLibraryName(libName): + libSplit = libName.split(":",2) + libPackage = libSplit[0] + libName = libSplit[1] + libVersion = libSplit[2] + libFilePath = libPackage.replace(".","/") + "/" +libName+ "/" +libVersion+ "/" +libName+ "-" +libVersion+ ".jar" + return libPackage,libName,libVersion,libFilePath + +global checkRules +def checkRules(ruleList): + action = "disallow" + for rule in ruleList: + if "os" in rule: + if "name" in rule["os"]: + rule["os"]["name"] = rule["os"]["name"].replace("osx","macos") + if not re.search(rule["os"]["name"],lv["osName"]): continue + + if "arch" in rule["os"]: + if not re.search(rule["os"]["arch"],lv["jvmArch"]): continue + + if "version" in rule["os"]: + if not re.search(rule["os"]["version"],lv["osVersion"]): continue + + action = rule["action"] + else: + action = rule["action"] + + return action + +global getLibraryPrettyName +def getLibraryPrettyName(library): + libraryName = library["package"]+ ":" +library["name"]+ ":" +library["version"] + if library["type"] == "native": + libraryName += " (" +library["nativeOS"]+ ")" + return libraryName + +global getFileHash +def getFileHash(file): + with open(file,"rb") as fileh: + return hashlib.sha1(fileh.read()).hexdigest() + +global checkLibraryHash +def checkLibraryHash(library): + hash = False + if library["dumb"] == False: + if library["type"] == "library": + hash = library["data"]["downloads"]["artifact"]["sha1"] + else: + hash = library["data"]["downloads"]["classifiers"]["natives-" +library["nativeOS"]]["sha1"] + else: + if not os.path.isfile(library["filePathOS"] + ".sha1"): + print(colored(colorama.fore.RED,"No .sha1 file found, can't verify."),file=sys.stderr) + return False + else: + with open(library["filePathOS"] + ".sha1","r") as fileh: + hash = fileh.read() + + match = (hash == getFileHash(library["filePathOS"])) + if not match: + print(colored(colorama.Fore.RED,library["filePathOS"]+ " is corrupt!"),file=sys.stderr) + + return match + +global processVersion +def processVersion(versionsPath,libraryPath,nativePath,version): + versionPath = p(versionsPath,version) + clientJson = readJsonFile(p(versionPath,version + ".json")) + libraries = [] + arguments = [] + jvmArguments = [] + + if "inheritsFrom" in clientJson: + _,libraries,_,_= processVersion(versionsPath,libraryPath,nativePath,clientJson["inheritsFrom"]) + + for library in clientJson["libraries"]: + lBase = {} + lBase["package"],lBase["name"],lBase["version"],lBase["filePath"] = parseJavaLibraryName(library["name"]) + lBase["type"] = "library" + lBase["data"] = library + lBase["dumb"] = False + + if "downloads" in library: # not dumb + if "classifiers" in library["downloads"]: # classifiers (usually for natives, their sources and their documentation) + for classifier in library["downloads"]["classifiers"]: + l = copy.deepcopy(lBase) + native = library["downloads"]["classifiers"][classifier] + if classifier.startswith("natives-"): + l["type"] = "native" + l["nativeOS"] = classifier.replace("natives-","",1) + else: + continue # TODO: add source and javadoc handling + + l["filePathOS"] = p(nativePath,native["path"].replace("/",os.path.sep)) + if "url" in native and native["url"] != "": + l["url"] = native["url"] + + libraries.append(l) + + if "artifact" in library["downloads"]: # artifact (usually for libraries) + l = copy.deepcopy(lBase) + if "path" in library["downloads"]["artifact"]: + l["filePathOS"] = p(libraryPath,library["downloads"]["artifact"]["path"].replace("/",os.path.sep)) + + if "url" in library["downloads"]["artifact"] and library["downloads"]["artifact"]["url"] != "": + l["url"] = library["downloads"]["artifact"]["url"] + + libraries.append(l) + else: # dumb + lBase["dumb"] = True + if "natives" in library: # natives + lBaseTwo = copy.deepcopy(lBase) + lBaseTwo["type"] = "native" + if not "url" in library: + lBaseTwo["url"] = "https://libraries.minecraft.net" + else: + lBaseTwo["url"] = library["url"] + + while len(lBaseTwo["url"]) > 0 and lBaseTwo["url"][-1] == "/": lBaseTwo["url"] = lBaseTwo["url"][:-1] + lBaseTwo["url"] = lBaseTwo["url"] + "/" + lBaseTwo["filePath"] + + for native in library["natives"]: + l = copy.deepcopy(lBaseTwo) + l["nativeOS"] = native + native = "natives-" + native + l["filePath"] = l["filePath"][:-4] + "-" + native + ".jar" + l["url"] = l["url"][:-4] + "-" + native + ".jar" + l["filePathOS"] = p(nativePath,l["filePath"].replace("/",os.path.sep)) + libraries.append(l) + else: # libraries + l = copy.deepcopy(lBase) + if not "url" in library: + l["url"] = "https://libraries.minecraft.net" + else: + l["url"] = library["url"] + + while len(l["url"]) > 0 and l["url"][-1] == "/": l["url"] = l["url"][:-1] + l["url"] = l["url"] + "/" + l["filePath"] + l["filePathOS"] = p(libraryPath,l["filePath"].replace("/",os.path.sep)) + libraries.append(l) + + if os.path.isfile(p(versionPath,version + ".jar")): + libraries.append({"type":"client","filePathOS":p(versionPath,version + ".jar")}) + + if "arguments" in clientJson: + if "game" in clientJson["arguments"]: + for arg in clientJson["arguments"]["game"]: + if type(arg) != str: continue + arguments.append(arg) + if "jvm" in clientJson["arguments"]: + for arg in clientJson["arguments"]["jvm"]: + if type(arg) != str: + if "value" in arg: + if type(arg["value"]) != list: + arg["value"] = [arg["value"]] + + if "rules" in arg: + if checkRules(arg["rules"]) == "allow": + for value in arg["value"]: + jvmArguments.append(value) + else: + for value in arg["value"]: + jvmArguments.append(value) + else: + jvmArguments.append(arg) + elif "minecraftArguments" in clientJson: + margs = clientJson["minecraftArguments"].replace('"',"").split(" ") + for arg in margs: + if type(arg) != str: continue + arguments.append(arg) + + return clientJson,libraries,arguments,jvmArguments + +global findArgument +def findArgument(args,searchFor): + for arg in args: + if arg.startswith(searchFor): return True + return False \ No newline at end of file