################################################################################# # This file is part of Mana Launcher. # Copyright (C) 2021 Jesusalva # # Distributed under the MIT license. ################################################################################# init -3 python: renpy.add_python_directory("python-extra") import requests, zlib, base64, sys, copy, uuid, time, json, traceback import os.path, os, shutil, subprocess, hashlib, zipfile, pbkdf2 import hmac, struct # non-free imports import discord_rpc print("\n[STDBY] Loading Basic functions.......") ############################################################################# ## Compatibility # set PYTHON_VERSION variable (e.g. 2715, 3605 etc.) PYTHON_VERSION="%d%d%02d" % (sys.version_info.major, sys.version_info.minor, sys.version_info.micro) PYTHON_VERSION=int(PYTHON_VERSION) # Ren'Py should come with Python 2.7.10 (2710), but just in case # After all, I only tested with 2.7.10, 2.7.13 and 2.7.15 if (PYTHON_VERSION < 2700 or PYTHON_VERSION > 3000): execute=subprocess.run # FIXME: check must be set and True raise Exception("WARNING: Python version is not 2.7\nStrange bugs may happen on your client.\n\nClick on \"Ignore\" to continue.\nClick on \"Quit\" to exit.") else: execute=subprocess.call ############################################################################# # Functions # Encodes something to md5 def md5(string): return hashlib.md5(string.encode()).hexdigest() def md5sum(f): md5=hashlib.md5() fp=open(f, "rb") ct=fp.read() md5.update(ct) rt=copy.copy(md5.hexdigest()) fp.close() del ct return rt # Smart Print command def stdout(message, bd=False): if config.developer: if renpy.android: if not renpy.is_init_phase(): renpy.notify(message) else: if bd: print("\033[1m%s\033[0m" % message) else: print(message) renpy.write_log("[DEBUG] %s" % message) else: renpy.write_log("[GAME] %s" % message) return # Smart wait def sdelay(delta=0.02): try: renpy.pause(delta, hard=True) except: time.sleep(delta) return # IF Then Else (IFTE) def ifte(ifs, then, elses): if (ifs): return then else: return elses # Returns number of seconds since UNIX EPOCH def now(): return int(time.time()) # File Managment Functions def get_path(path): # Not all systems can record on the game folder if renpy.android: path=path.replace("/", "_") return renpy.config.savedir + "/" + path else: return renpy.config.basedir + "/" + path ############################################################################# # Global classes # We need to override standard list method. Original by Triptych (stackoverflow) class dlist(list): def __setitem__(self, index, value): size = len(self) if index >= size: self.extend(None for _ in range(size, index + 1)) list.__setitem__(self, index, value) # Search for array[?][key]==search in an array of dicts # Returns the dictionary, or returns None def dl_search(array, key, search): try: r=(item for item in array if item[key] == search).next() except: r=None if r is None: stdout("dlsearch: r is None") return r # Search for array[?][key]==search in an array of dicts # Returns the index, or returns -1 def dl_search_idx(array, key, search): try: r=next((i for i, item in enumerate(array) if item[key] == search), None) except: traceback.print_exc() r=-1 return ifte(r is None, -1, r) ############################################################################# ## Some other stuff if renpy.linux: os.environ["APPIMAGELAUNCHER_DISABLE"]="1" ############################################################################# ## Configuration and Defaults if (persistent.discord is None): persistent.discord = True if (persistent.steam is None): persistent.steam = False if (persistent.client is None): persistent.client = "manaplus" if (persistent.iconify is None): persistent.iconify = ifte(renpy.windows, False, True) ############################################################################# ## Conditional imports if persistent.steam: import _renpysteam as steam ############################################################################# # ["themanaworld.org", "germantmw.de", "moubootaurlegends.org"] if config.developer: VAULT_HOST = "https://localhost:13370" VAULT_CERT = "http://localhost/launcher/cert.pem" else: VAULT_HOST = "https://api.tmw2.org:13370" VAULT_CERT = "https://tmw2.org/launcher/cert.pem" ################### # Vault SSL wrapper vault=requests.Session() vault.cert = get_path("cert.pem") vault.verify = get_path("cert.pem") ############################################################################ ## Retrieve the Vault certificate. Otherwise, we cannot proceed. ## From here and until the end of this code block, ## ALL ERRORS ARE FATAL def build_vault(): while True: try: ###################################### # Fetch a new PEM Certificate stdout("Fetching SSL Certificate from %s" % VAULT_CERT) r = requests.get(VAULT_CERT) if (r.status_code != 200): raise Exception("\nFailed to fetch Vault SSL Certificate.\b\n Returned HTTP error %d.\n\nClick \"Ignore\" to retry.\n\n" % r.status_code) # Save it with open(get_path("cert.pem"), 'wb') as fd: for chunk in r.iter_content(chunk_size=128): fd.write(chunk) # Presumably all good, so do not continue and break the loop stdout("PEM Download OK") break except: traceback.print_exc() raise stdout("Automatically retry in 5 seconds...") time.sleep(5.0) ## End FATAL mode ############################################################# init 10 python: ######## ## Force Update if persistent.version != config.version: persistent.version = config.version if (persistent.client is not None and persistent.host is not None and handle_client(launch=True, download=False)): md5check_client(silent=True) ######### Done with pre-init label splashscreen: show TMW2 at truecenter with fade python: if persistent.hello is None: p1=2.5 p2=1.5 else: p1=0.5 p2=0.5 renpy.pause(p1) hide TMW2 with Dissolve(p2) call before_main_menu if persistent.hello is None: call screen preferences $ persistent.hello=True return label die: $ stdout("Program died.") pause return ####### Defaults default statusmsg = "Not yet initialized" default progress = 0 default responsive = True default has_steam = False default SCR_PROMPT = None default SCR_RESULT = None default MLP_DEST = None ## Command Line Interface init -4 python: USE_DUMMY_DATA = False AUTOLAUNCH = False def parse_command(): global USE_DUMMY_DATA, AUTOLAUNCH parser = renpy.arguments.ArgumentParser() ## Collect args parser.add_argument('args', nargs='+', help="Command-line arguments.") targs = parser.parse_args() args = targs.args ## Debug information if config.developer: print("Args: %s" % str(args)) print("") ## Command Line Defaults for cmd in args: if (cmd == "steam"): print("Steam Mode Enabled") persistent.steam = True elif (cmd == "dummy"): print("Dummy Mode Enabled") USE_DUMMY_DATA = True elif (cmd == "launch"): print("Auto-launch mode Enabled") AUTOLAUNCH = True elif (cmd == "version"): print("%s v%s %s" % (config.name, config.version, "Mirror Lake")) print("%s %s" % (str(renpy.version()), renpy.version_name)) if renpy.linux: print("Linux") elif renpy.windows: print("Windows") else: print("Unsupported plataform") renpy.quit() elif (cmd == "help"): print("=========================================================") print("Commands:") print("steam - Enables Steam login") print("dummy - do not login, use a dummy data for testing") print("launch - skip main menu screen") print("version - shows the program version and exits") print("help - shows this help screen and exits") print("") print("Last commands have precedence over earlier ones.") renpy.quit() else: print("\033[31;1mWARNING:\033[0m Unrecognized argument: %s" % cmd) return True renpy.arguments.register_command('adv', parse_command) label main_menu: ## Autolaunch - Skip main menu if AUTOLAUNCH: $stdout("Auto-launching...") $AUTOLAUNCH=False return call screen main_menu() $ renpy.quit()