From 244cac85fe3bdf1aff543792b5148f7ebdc5a2b0 Mon Sep 17 00:00:00 2001 From: GanstaKingofSA Date: Fri, 7 Jul 2023 12:27:35 -0500 Subject: [PATCH 1/2] r8/r7 to r6 --- ddmd_settings.json | 8 +- game/mod_content.rpy | 2 - game/mod_dir_browser.rpy | 41 +++++--- game/mod_installer.rpy | 208 ++++++++++++++++++++++++++------------- game/mod_list.rpy | 5 +- game/mod_prompt.rpy | 5 +- game/mod_screen.rpy | 18 ++-- game/mod_services.rpy | 17 +++- game/mod_settings.rpy | 48 ++++----- game/options.rpy | 2 +- game/saves.rpy | 15 +-- renpy/bootstrap.py | 12 +-- renpy/main.py | 200 +++++++++++++++---------------------- 13 files changed, 302 insertions(+), 279 deletions(-) diff --git a/ddmd_settings.json b/ddmd_settings.json index 72f8213..e0aeb56 100644 --- a/ddmd_settings.json +++ b/ddmd_settings.json @@ -1,5 +1,3 @@ -[ - { - "config_gl2": false - } -] \ No newline at end of file +{ + "config_gl2": false +} \ No newline at end of file diff --git a/game/mod_content.rpy b/game/mod_content.rpy index 4296fd2..ee8e3af 100644 --- a/game/mod_content.rpy +++ b/game/mod_content.rpy @@ -36,10 +36,8 @@ image ddmd_transfer_icon_hover = "sdc_system/settings_app/transferHover.png" image ddmd_time_clock = DynamicDisplayable(ddmd_app.get_current_time) default persistent.mod_list_disclaimer_accepted = False -define modSearchCriteria = "" default persistent.self_extract = None -define tempFolderName = "" default persistent.transfer_warning = False diff --git a/game/mod_dir_browser.rpy b/game/mod_dir_browser.rpy index 43a2cc5..14c0b67 100644 --- a/game/mod_dir_browser.rpy +++ b/game/mod_dir_browser.rpy @@ -1,31 +1,40 @@ ## Copyright 2023 Azariel Del Carmen (GanstaKingofSA) init python: + import errno + def can_access(path, drive=False): - try: - if not renpy.windows or drive: - return os.access(path, os.R_OK) - else: - for x in os.listdir(path): + if drive: + if os.name == "nt" and len(path) == 2 and path[1] == ":": + return os.path.isdir(path) + return False + + if os.name == "nt": + try: + for entry in os.listdir(path): break - except OSError as e: - if e.errno == 13 or e.errno == 2 or e.errno == 22: - return False - raise - return True + return True + except WindowsError as e: + if e.errno == errno.EACCES or e.winerror == 59: + return False + raise + else: + return os.access(path, os.R_OK) def get_network_drives(): - temp = subprocess.run("powershell (Get-WmiObject -ClassName Win32_MappedLogicalDisk).Name", check=True, shell=True, stdout=subprocess.PIPE).stdout.decode("utf-8").replace("\r\n", "").split(":") - temp.pop(-1) - return temp + result = subprocess.check_output("net use", shell=True) + output_lines = result.strip().split('\r\n')[1:] + drives = [line.split()[1].rstrip(':') for line in output_lines if line.startswith('OK')] + return drives def get_physical_drives(net_drives): - temp = subprocess.run("powershell (Get-PSDrive -PSProvider FileSystem).Name", check=True, shell=True, stdout=subprocess.PIPE).stdout.decode("utf-8").split("\r\n") - temp.pop(-1) + temp = subprocess.check_output("powershell (Get-PSDrive -PSProvider FileSystem).Name", shell=True) + temp = temp.decode("utf-8").strip().split("\r\n") - for x in temp: + for x in temp[:]: if x in net_drives: temp.remove(x) + return temp screen pc_directory(loc=None, ml=False, mac=False): diff --git a/game/mod_installer.rpy b/game/mod_installer.rpy index 0d8e41e..75db8d9 100644 --- a/game/mod_installer.rpy +++ b/game/mod_installer.rpy @@ -1,107 +1,173 @@ init python in ddmd_mod_installer: from store import persistent - from zipfile import ZipFile + from zipfile import ZipFile, BadZipfile import os import shutil import tempfile - tempFolderName = "" + modFolderName = "" - def valid_zip(filePath): - """ - Returns whether the given ZIP file is a valid Ren'Py/DDLC mod ZIP file. - filePath - the direct path to the ZIP file. - """ - zip_contents = [] + def inInvalidDir(path): + for x in ("lib", "renpy"): + if os.path.normpath(x) in os.path.normpath(path): + return True + if path.endswith(".app"): + return True + return False - with ZipFile(filePath, "r") as temp_zip: - zip_contents = temp_zip.namelist() + def check_mod_validity(zipPath, copy): + if not copy: + # ZIP file check + with ZipFile(zipPath, "r") as temp_zip: + zip_contents = temp_zip.namelist() - for x in zip_contents: - if x.endswith((".rpa", ".rpyc", ".rpy")): - del zip_contents - return True + mod_files = zip_contents + else: + # Folder check + mod_files = [] - return False + for mod_src, dirs, files in os.walk(zipPath): + for mod_f in files: + mod_files.append(os.path.join(mod_src, mod_f)) - def inInvalidDir(path): - for x in ("lib", "renpy"): - if x + "/" in path.replace("\\", "/"): - return True + # Check if mod files contain Ren'Py files + if any(file.endswith((".rpa", ".rpyc", ".rpy")) for file in mod_files): + return True return False - def install_mod(zipPath, copy=False): - global tempFolderName + def get_top_level_folder(mod_dir): + top_level_folder = None + + for entry in os.listdir(mod_dir): + if os.path.isdir(os.path.join(mod_dir, entry)): + top_level_folder = entry + break - if not tempFolderName: + return top_level_folder + + def identify_mod_format(mod_dir): + """ + Identifies the format of the mod package based on its content and structure. + mod_dir: The path to the mod package directory. + Returns: A string indicating the format of the mod package. + """ + top_level_folder = get_top_level_folder(mod_dir) + + if os.path.isdir(os.path.join(mod_dir, top_level_folder, "characters")) and os.path.isdir(os.path.join(mod_dir, top_level_folder, "game")): + return 1 # Standard Format + elif os.path.isdir(os.path.join(mod_dir, top_level_folder, "game")): + return 2 # Standard Format (No Characters Folder) + elif os.path.isdir(os.path.join(mod_dir, "characters")) and os.path.isdir(os.path.join(mod_dir, "game")): + return 3 # Standard Format without top folder + elif os.path.isdir(os.path.join(mod_dir, "game")): + if any(f.endswith((".rpa", ".rpyc", ".rpy")) for f in os.listdir(os.path.join(mod_dir, "game"))): + return 5 # Possible Format 2 or 4 (game folder with RPAs or RPYC/RPY files) + else: + return 4 # Standard Format without top folder (No Characters Folder) + elif any(f.endswith(".rpa") for f in os.listdir(mod_dir)): + return 6 # Possible Format 1 (RPAs without game folder) + elif os.path.isdir(os.path.join(mod_dir, "mod_assets")) or any(f.endswith((".rpyc", ".rpy")) for f in os.listdir(mod_dir)): + return 7 # Possible Format 3 (RPYC/RPY files without game folder) + return -1 # Unknown Format + + def extract_mod_from_zip(zipPath): + mod_dir = tempfile.mkdtemp(prefix="NewDDML_", suffix="_TempArchive") + try: + with ZipFile(zipPath, "r") as tempzip: + tempzip.extractall(mod_dir) + return mod_dir + except BadZipFile: + shutil.rmtree(mod_dir) + return None + + def move_mod_files(mod_folder_path, mod_dir_path, mod_format_id, copy): + """ + Moves or copies the mod files from the mod directory or mod package folder to the mod folder. + mod_folder_path: Path to the mod folder. + mod_dir_path: Path to the mod directory or mod package folder. + mod_format_id: Integer value indicating the mod format ID. + copy: Boolean value indicating whether to copy the files (macOS only). + """ + if mod_format_id in (1, 2, 3, 4, 5): + characters_dir = os.path.join(mod_dir_path, "characters") + game_dir = os.path.join(mod_dir_path, "game") + if copy: + # Copy characters folder (if applicable) + if os.path.isdir(characters_dir): + shutil.copytree(characters_dir, mod_folder_path) + # Copy game folder to mod_folder_path + shutil.copytree(game_dir, mod_folder_path) + else: + # Move characters folder (if applicable) + if os.path.isdir(characters_dir): + shutil.move(characters_dir, mod_folder_path) + # Move game folder to mod_folder_path + shutil.move(os.path.join(mod_dir_path, "game"), mod_folder_path) + elif mod_format_id in (6, 7): + game_folder_path = os.path.join(mod_folder_path, "game") + # Create game folder in mod_folder_path + os.makedirs(game_folder_path) + # Move all files from mod_dir_path to game folder in mod_folder_path + for entry in os.listdir(mod_dir_path): + entry_path = os.path.join(mod_dir_path, entry) + if os.path.isfile(entry_path): + shutil.move(entry_path, game_folder_path) + elif os.path.isdir(entry_path): + shutil.move(entry_path, os.path.join(game_folder_path, entry)) + + def install_mod(zipPath, modFolderName, copy=False): + if not modFolderName: renpy.show_screen("ddmd_dialog", message="Error: The folder name cannot be blank.") return - elif tempFolderName.lower() in ("ddlc mode", "stock mode", "ddlc", "stock"): - tempFolderName = "" - renpy.show_screen("ddmd_dialog", message="Error: %s is a reserved folder name. Please try another folder name." % tempFolderName) + elif modFolderName.lower() in ("ddlc mode", "stock mode", "ddlc", "stock"): + modFolderName = "" + renpy.show_screen("ddmd_dialog", message="Error: %s is a reserved folder name. Please try another folder name." % modFolderName) return - elif os.path.exists(os.path.join(persistent.ddml_basedir, "game/mods/" + tempFolderName)): - tempFolderName = "" + elif os.path.exists(os.path.join(persistent.ddml_basedir, "game/mods/" + modFolderName)): + modFolderName = "" renpy.show_screen("ddmd_dialog", message="Error: This mod folder already exists. Please try another folder name.") return else: renpy.show_screen("ddmd_progress", message="Installing mod. Please wait.") - folderPath = os.path.join(persistent.ddml_basedir, "game/mods", tempFolderName) + folderPath = os.path.join(persistent.ddml_basedir, "game/mods", modFolderName) try: + if not check_mod_validity(zipPath, copy): + raise Exception("Given file/folder is an invalid DDLC Mod Package. Please select a different file/folder.") + if not copy: - if not valid_zip(zipPath): - raise Exception("Given ZIP file is a invalid DDLC Mod ZIP Package. Please select a different ZIP file.") - return - - mod_dir = tempfile.mkdtemp(prefix="NewDDML_", suffix="_TempArchive") - - with ZipFile(zipPath, "r") as tempzip: - tempzip.extractall(mod_dir) - + mod_dir = extract_mod_from_zip(zipPath) + if mod_dir is None: + raise Exception("Invalid mod structure. Please select a different ZIP file.") else: - validMod = False - for mod_src, dirs, files in os.walk(zipPath): - for mod_f in files: - if mod_f.endswith((".rpa", ".rpyc", ".rpy")): - validMod = True - if validMod: - mod_dir = zipPath - else: - raise Exception("Given Mod Folder is a invalid DDLC Mod Folder Package. Please select a different mod folder.") - return - + mod_dir = zipPath + + mod_format_id = identify_mod_format(mod_dir) + print("Mod Format ID: %d" % mod_format_id) + if mod_format_id == -1: + raise Exception("Mod is packaged in a way that is unknown to DDMD. Re-download the mod that follows a proper DDLC mod package standard or contact 'bronya_rand' with the mod in question.") + os.makedirs(folderPath) - os.makedirs(os.path.join(folderPath, "game")) - - for mod_src, dirs, files in os.walk(mod_dir): - dst_dir = mod_src.replace(mod_dir, folderPath) - for d in dirs: - if d == "characters": - shutil.move(os.path.join(mod_src, d), os.path.join(dst_dir, d)) - for f in files: - if f.endswith((".rpa", ".rpyc", ".rpy")): - if not inInvalidDir(mod_src): - mod_dir = mod_src - break - - for mod_src, dirs, files in os.walk(mod_dir): - dst_dir = mod_src.replace(mod_dir, folderPath + "/game") - for mod_d in dirs: - shutil.move(os.path.join(mod_src, mod_d), os.path.join(dst_dir, mod_d)) - for mod_f in files: - shutil.move(os.path.join(mod_src, mod_f), os.path.join(dst_dir, mod_f)) + if mod_format_id in (1, 2): + top_level_folder = get_top_level_folder(mod_dir) + mod_dir_path = os.path.join(mod_dir, top_level_folder) + move_mod_files(folderPath, mod_dir_path, mod_format_id, copy) + else: + move_mod_files(folderPath, mod_dir, mod_format_id, copy) + + renpy.hide_screen("ddmd_progress") + renpy.show_screen("ddmd_dialog", message="%s has been installed successfully." % modFolderName) + except BadZipfile: renpy.hide_screen("ddmd_progress") - renpy.show_screen("ddmd_dialog", message="%s has been installed successfully." % tempFolderName) + renpy.show_screen("ddmd_dialog", message="Error: Invalid ZIP file. Please select a different ZIP file.") except OSError as err: if os.path.exists(folderPath): shutil.rmtree(folderPath) renpy.hide_screen("ddmd_progress") - renpy.show_screen("ddmd_dialog", message="A error has occured during installation.", message2=str(err)) + renpy.show_screen("ddmd_dialog", message="An error has occured during installation.", message2=str(err)) except Exception as err: if os.path.exists(folderPath): shutil.rmtree(folderPath) renpy.hide_screen("ddmd_progress") - renpy.show_screen("ddmd_dialog", message="A error has occured during installation.", message2=str(err)) - tempFolderName = "" \ No newline at end of file + renpy.show_screen("ddmd_dialog", message="An unexpected error has occured during installation.", message2=str(err)) \ No newline at end of file diff --git a/game/mod_list.rpy b/game/mod_list.rpy index f01904d..fdd58cb 100644 --- a/game/mod_list.rpy +++ b/game/mod_list.rpy @@ -55,13 +55,14 @@ screen mod_search(xs=480, ys=220): xalign .5 yalign .5 spacing 8 + default modSearchCriteria = "" label _("Search For?"): text_size 20 xalign 0.5 input: - value VariableInputValue("modSearchCriteria") + value ScreenVariableInputValue("modSearchCriteria") length 24 allow "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz[[]] " @@ -70,7 +71,7 @@ screen mod_search(xs=480, ys=220): spacing 100 textbutton _("OK") action [Hide("mod_search", Dissolve(0.25)), Function(search_script, modSearchCriteria)] - textbutton _("Clear") action SetVariable("modSearchCriteria", "") + textbutton _("Clear") action SetScreenVariable("modSearchCriteria", "") screen mod_list_info(mod): zorder 102 diff --git a/game/mod_prompt.rpy b/game/mod_prompt.rpy index 14ca6ea..cf59bac 100644 --- a/game/mod_prompt.rpy +++ b/game/mod_prompt.rpy @@ -77,18 +77,19 @@ screen mod_name_input(zipPath, copy=False, xs=480, ys=220): xalign .5 yalign .5 spacing 8 + default tempFolderName = "" label _("Enter the name you wish to call this mod."): text_size int(18 * res_scale) xalign 0.5 - input default "" value FieldInputValue(ddmd_mod_installer, "tempFolderName") length 24 allow "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789:-" + input default "" value ScreenVariableInputValue("tempFolderName") length 24 allow "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789:-" hbox: xalign 0.5 spacing 100 - textbutton _("OK") action [Hide("mod_name_input"), Function(ddmd_mod_installer.install_mod, zipPath=zipPath, copy=copy)] + textbutton _("OK") action [Hide("mod_name_input"), Function(ddmd_mod_installer.install_mod, zipPath=zipPath, modFolderName=tempFolderName, copy=copy)] screen ddmd_progress(message, xs=480, ys=220): modal True diff --git a/game/mod_screen.rpy b/game/mod_screen.rpy index 48df060..fb283db 100644 --- a/game/mod_screen.rpy +++ b/game/mod_screen.rpy @@ -33,10 +33,12 @@ init python: def run(self): sleep(1.5) self.show_notif() + + start_overlay = SteamLikeOverlay() - def get_ddmc_modlist(): - with renpy.file("ddmc.json") as mod_json: - return json.load(mod_json) + def get_ddmc_modlist(): + with renpy.file("ddmc.json") as mod_json: + return json.load(mod_json) def set_settings_json(): temp = [ @@ -267,9 +269,9 @@ screen mods(): xpos int(450 * res_scale) ypos int(50 * res_scale) xsize int(700 * res_scale) - if selectedMod == "DDLC" and renpy.version_tuple > (6, 99, 12, 4, 2187): + if ddmd_app_functions.selectedMod == "DDLC" and renpy.version_tuple > (6, 99, 12, 4, 2187): label _("Stock Mode") - elif selectedMod == "DDLC" and renpy.version_tuple == (6, 99, 12, 4, 2187): + elif ddmd_app_functions.selectedMod == "DDLC" and renpy.version_tuple == (6, 99, 12, 4, 2187): label _("DDLC Mode") else: label "[ddmd_app_functions.selectedMod]" @@ -281,10 +283,10 @@ screen mods(): vbox: xpos 0.2 yoffset -20 - textbutton _("Open Save Directory") action Function(open_save_dir) + textbutton _("Open Save Directory") action Function(ddmd_app_settings.open_save_dir) if ddmd_app_functions.loadedMod != "DDLC": - textbutton _("Open Running Mods' Game Directory") action Function(open_dir, config.gamedir) - textbutton _("Open Mod Docker's Game Directory") action Function(open_dir, persistent.ddml_basedir + "/game") + textbutton _("Open Running Mods' Game Directory") action Function(ddmd_app_settings.open_dir, config.gamedir) + textbutton _("Open Mod Docker's Game Directory") action Function(ddmd_app_settings.open_dir, persistent.ddml_basedir + "/game") if ddmd_app_functions.selectedMod != ddmd_app_functions.loadedMod: textbutton _("Delete Saves") action Show("ddmd_confirm", message=_("Are you sure you want to remove %s save files?") % ddmd_app_functions.selectedMod, yes_action=[Hide("ddmd_confirm"), Function(ddmd_app_settings.delete_saves, ddmd_app_functions.selectedMod)], no_action=Hide("ddmd_confirm")) if ddmd_app_functions.selectedMod != "DDLC": diff --git a/game/mod_services.rpy b/game/mod_services.rpy index e5dd6d7..e8434dd 100644 --- a/game/mod_services.rpy +++ b/game/mod_services.rpy @@ -15,14 +15,21 @@ init -1 python in ddmd_services: def run(self): for modfolder in os.listdir(self.modpath): - if os.path.exists(os.path.join(self.modpath, modfolder, "game")): + if os.path.isdir(os.path.join(self.modpath, modfolder, "game")): self.mods[modfolder] = os.path.join(self.modpath, modfolder, "game") while True: - modFolders = [] + modFolders = {} + for entry in os.listdir(self.modpath): + entry_path = os.path.join(self.modpath, entry) + if os.path.isdir(entry_path) and os.path.exists(os.path.join(entry_path, "game")): + modFolders[entry] = entry_path + for modfolder in os.listdir(self.modpath): - if os.path.exists(os.path.join(self.modpath, modfolder, "game")): - modFolders.append(modfolder) + modfolder_path = os.path.join(self.modpath, modfolder) + if os.path.exists(os.path.join(modfolder_path, "game")): + if modfolder not in modFolders: + modFolders[modfolder] = modfolder_path if len(modFolders) < len(self.mods): for mod in self.mods.keys(): @@ -30,7 +37,7 @@ init -1 python in ddmd_services: self.mods.pop(mod) elif len(modFolders) > len(self.mods): for mod in modFolders: - if not self.mods.get(mod): + if mod not in self.mods: self.mods[mod] = os.path.join(self.modpath, mod, "game") sleep(5) diff --git a/game/mod_settings.rpy b/game/mod_settings.rpy index 7dc8980..106f544 100644 --- a/game/mod_settings.rpy +++ b/game/mod_settings.rpy @@ -14,47 +14,33 @@ init python: return hashlib.sha256(open(path, "rb").read()).hexdigest() == 'da7ba6d3cf9ec1ae666ec29ae07995a65d24cca400cd266e470deb55e03a51d4' def transfer_data(ddmm_path): - modsTransferred = [] try: - for dirs in os.listdir(ddmm_path): - if not os.path.exists(os.path.join(persistent.ddml_basedir, "game/mods", dirs)): - modsTransferred.append(dirs) - os.makedirs(os.path.join(persistent.ddml_basedir, "game/mods", dirs)) - os.makedirs(os.path.join(persistent.ddml_basedir, "game/mods", dirs, "game")) + for mod_dir in os.listdir(ddmm_path): + mod_path = os.path.join(persistent.ddml_basedir, "game/mods", mod_dir) - for ddmm_src, mod_dirs, mod_files in os.walk(ddmm_path + "/" + dirs): - dst_dir = ddmm_src.replace(ddmm_path + "/" + dirs, os.path.join(persistent.ddml_basedir, "game/mods", dirs)) - for d in mod_dirs: - if d == "characters": - shutil.copytree(os.path.join(ddmm_src, d), os.path.join(dst_dir, d)) - for f in mod_files: - if f.endswith((".rpa", ".rpyc", ".rpy")): - if not f.startswith("00"): - mod_dir = ddmm_src - break + if not os.path.exists(mod_path): + os.makedirs(mod_path) - for ddmm_src, mod_dirs, mod_files in os.walk(mod_dir): - dst_dir = ddmm_src.replace(mod_dir, os.path.join(persistent.ddml_basedir, "game/mods", dirs, "game")) - for mod_d in mod_dirs: - shutil.copytree(os.path.join(ddmm_src, mod_d), os.path.join(dst_dir, mod_d)) - for mod_f in mod_files: - if mod_f.endswith(".rpa"): - if is_original_file(os.path.join(ddmm_src, mod_f)): - continue - shutil.copy2(os.path.join(ddmm_src, mod_f), os.path.join(dst_dir, mod_f)) + for ddmm_src, mod_dirs, _ in os.walk(os.path.join(ddmm_path, mod_dir)): + dst_dir = ddmm_src.replace(os.path.join(ddmm_path, mod_dir), mod_path) + for d in mod_dirs: + if d in ("characters", "game"): + shutil.copytree(os.path.join(ddmm_src, d), os.path.join(dst_dir, d)) renpy.hide_screen("ddmd_progress") renpy.show_screen("ddmd_dialog", message="Transferred all data sucessfully.") except OSError as err: - if modsTransferred and os.path.exists(os.path.join(persistent.ddml_basedir, "game/mods", modsTransferred[-1])): - shutil.rmtree(os.path.join(persistent.ddml_basedir, "game/mods", modsTransferred[-1])) + mod_path = os.path.join(persistent.ddml_basedir, "game/mods", mod_dir) + if os.path.exists(mod_path): + shutil.rmtree(mod_path) renpy.hide_screen("ddmd_progress") - renpy.show_screen("ddmd_dialog", message="A error has occured while transferring.", message2=str(err)) + renpy.show_screen("ddmd_dialog", message="A error has occured while transferring %s." % mod_dir, message2=str(err)) except Exception as err: - if modsTransferred and os.path.exists(os.path.join(persistent.ddml_basedir, "game/mods", modsTransferred[-1])): - shutil.rmtree(os.path.join(persistent.ddml_basedir, "game/mods", modsTransferred[-1])) + mod_path = os.path.join(persistent.ddml_basedir, "game/mods", mod_dir) + if os.path.exists(mod_path): + shutil.rmtree(mod_path) renpy.hide_screen("ddmd_progress") - renpy.show_screen("ddmd_dialog", message="A unknown error has occured while transferring.", message2=str(err)) + renpy.show_screen("ddmd_dialog", message="A unknown error has occured while transferring %s." % mod_dir, message2=str(err)) def transfer_ddmm_data(): if not renpy.windows: diff --git a/game/options.rpy b/game/options.rpy index 0f1ef8a..31405ab 100644 --- a/game/options.rpy +++ b/game/options.rpy @@ -11,7 +11,7 @@ define config.window_title = config.name define gui.show_name = False # This controls the version number of your mod. -define config.version = "1.0.9" +define config.version = "1.1.0" # This adds information about your mod in the About screen. # DDLC does not have a 'About' screen so you can leave this blank. diff --git a/game/saves.rpy b/game/saves.rpy index af39464..b84d3e9 100644 --- a/game/saves.rpy +++ b/game/saves.rpy @@ -11,7 +11,7 @@ python early: elif renpy.windows: if 'APPDATA' in os.environ: - return os.environ['APPDATA'] + "/RenPy/DD-ModDocker" + return os.path.join(os.environ['APPDATA'], "RenPy", "DD-ModDocker") else: rv = "~/RenPy/DD-ModDocker" return os.path.expanduser(rv) @@ -21,19 +21,10 @@ python early: return os.path.expanduser(rv) try: - with open(renpy.config.basedir + "/selectedmod.json", "r") as mod_json: + with open(os.path.join(renpy.config.basedir, "selectedmod.json"), "r") as mod_json: temp = json.load(mod_json) selectedMod = temp['modName'] except IOError: selectedMod = "DDLC" - renpy.config.savedir = save_path() - - if os.path.exists(renpy.config.basedir + "/game/MLSaves"): - for src, dirs, files in os.walk(renpy.config.basedir + "/game/MLSaves"): - for d in dirs: - src_dir = os.path.join(src, d) - dst_dir = src_dir.replace(src, renpy.config.savedir) - shutil.move(src_dir, dst_dir) - - renpy.config.savedir = renpy.config.savedir + "/" + selectedMod \ No newline at end of file + renpy.config.savedir = os.path.join(save_path(), selectedMod) \ No newline at end of file diff --git a/renpy/bootstrap.py b/renpy/bootstrap.py index ad73ebf..a33d30f 100644 --- a/renpy/bootstrap.py +++ b/renpy/bootstrap.py @@ -339,13 +339,13 @@ def bootstrap(renpy_base): from json import load as load_json - if os.path.exists(basedir + "/selectedMod.json"): - with open(basedir + "/selectedMod.json", "r") as sm: + try: + json_path = os.path.join(basedir, "selectedMod.json") + with open(json_path, "r") as sm: mod = load_json(sm) - renpy.display.presplash.start( - basedir, gamedir + "/mods/" + mod["modName"] + "/game" - ) - else: + mod_game_path = os.path.join(gamedir, "mods", mod["modName"], "game") + renpy.display.presplash.start(basedir, mod_game_path) + except IOError: renpy.display.presplash.start(basedir, gamedir) # Ditto for the Ren'Py module. diff --git a/renpy/main.py b/renpy/main.py index 478fdc5..f19a443 100644 --- a/renpy/main.py +++ b/renpy/main.py @@ -270,36 +270,45 @@ def main(): # Note the game directory. old_gamedir = renpy.config.gamedir + # Load the selected mod info or stock/DDLC # Load the selected mod info or stock/DDLC def init_load_json(): - if os.path.exists(renpy.config.basedir + "/selectedmod.json"): - import json + import json + mod_json_path = os.path.join(renpy.config.basedir, "selectedmod.json") + if not os.path.exists(mod_json_path): + return None - try: - with open(renpy.config.basedir + "/selectedmod.json", "r") as mod_json: - temp = json.load(mod_json) - return temp - except: - return None - else: + try: + with open(mod_json_path, "r") as mod_json: + return json.load(mod_json) + except (IOError, ValueError): return None temp = init_load_json() - if temp: + is_ddlc_mode = False + if temp is None: + # Handle the case when no mod is selected (Load DDLC itself) + mod_name = None + is_rpa = None + is_ddlc_mode = True + else: + if "modName" in temp and "isRPA" in temp: + mod_name = temp["modName"] + is_rpa = temp["isRPA"] + else: + raise Exception("Mod JSON Data is corrupt or invalid. Remove 'selectedmod.json', run DDMD, select the mod you want to load again and try again.") + + if not is_ddlc_mode: # Redefine game directory to mod directory - if not os.path.exists( - os.path.join(renpy.config.gamedir, "mods", temp["modName"], "game") - ): - raise Exception( - "'game' folder could not be found in %s." - % os.path.join(renpy.config.gamedir, "mods", temp["modName"]).replace( - "\\", "/" - ) - ) - renpy.config.gamedir = os.path.join( - renpy.config.gamedir, "mods", temp["modName"], "game" - ).replace("\\", "/") + mod_dir = os.path.join(renpy.config.gamedir, "mods", mod_name) + mod_game_path = os.path.join(mod_dir, "game") + mod_dir_normalized = os.path.normpath(mod_dir).replace("\\", "/") + + if not os.path.exists(mod_game_path): + raise Exception("'game' folder could not be found in {}.".format(mod_dir_normalized)) + + renpy.config.gamedir = os.path.normpath(mod_game_path).replace("\\", "/") game.basepath = renpy.config.gamedir if renpy.config.gamedir != old_gamedir: @@ -329,43 +338,32 @@ def init_load_json(): if fn.lower().endswith(".rpe"): load_rpe(dir + "/" + fn) - def find_archives(temp): - if ( - os.path.exists(renpy.config.basedir + "/game/ddml.rpa") - and "ddml" not in renpy.config.archives - ): + def find_archives(mod_name, is_rpa, is_ddlc_mode): + if os.path.exists(os.path.join(renpy.config.basedir, "game", "ddml.rpa")) and "ddml" not in renpy.config.archives: renpy.config.archives.append("ddml") renpy.config.archives.append("audio") renpy.config.archives.append("fonts") renpy.config.archives.append("images") - if not temp: + if is_ddlc_mode: + renpy.config.archives.append("scripts") + elif not is_rpa: renpy.config.archives.append("scripts") - else: - if temp["isRPA"]: - for i in sorted(os.listdir(renpy.config.gamedir)): - base, ext = os.path.splitext(i) - - # Check if the archive does not have any of the extensions in archive_extensions - if not i.endswith(".rpa"): - continue + if is_rpa: + for i in sorted(os.listdir(renpy.config.gamedir)): + base, ext = os.path.splitext(i) - base = i[:-4] + # Check if the archive does not have any of the extensions in archive_extensions + if not (ext in archive_extensions): + continue - if base in renpy.config.archives: - renpy.config.archives.remove(base) + if base in renpy.config.archives: + renpy.config.archives.remove(base) - renpy.config.archives.append( - "mods/" + temp["modName"] + "/game/" + base - ) - else: - renpy.config.archives.append("scripts") + renpy.config.archives.append("mods/{}/game/{}".format(mod_name, base)) - if ( - os.path.exists(renpy.config.basedir + "/game/mod_patches.rpa") - and "mod_patches" not in renpy.config.archives - ): + if os.path.exists(os.path.join(renpy.config.basedir, "game", "mod_patches.rpa")) and "mod_patches" not in renpy.config.archives: renpy.config.archives.append("mod_patches") renpy.config.archives.reverse() @@ -374,16 +372,16 @@ def find_archives(temp): renpy.loader.index_archives() if not inRenpy: - find_archives(temp) + find_archives(mod_name, is_rpa, is_ddlc_mode) # Start auto-loading. renpy.loader.auto_init() if not inRenpy: - if temp and temp["isRPA"]: - log_clock("Loading %s needed RPAs" % temp["modName"]) - else: + if is_ddlc_mode: log_clock("Loading Stock/DDLC RPAs") + else: + log_clock("Loading %s needed RPAs" % mod_name) else: log_clock("Loader init") @@ -444,81 +442,50 @@ def find_archives(temp): renpy.game.script.scan_script_files() if not inRenpy: - mods_list = [] - - if temp: - - # raise Exception(renpy.game.script.script_files) - for x in renpy.game.script.script_files[:]: - - # Make sure we add the needed DDMD files - ddmd_files = [ - "mod_screen", - "mod_settings", - "ml_patches", - "mod_content", - "mod_dir_browser", - "mod_list", - "mod_prompt", - "mod_styles", - "mod_transforms", - "saves", - ] - - for df in ddmd_files: - if (df in x[0] and x[1]) or df in x[0]: - mods_list.append(x) + mods_set = set() - # Check if the script file in the list is defined in mods folder - if "mods/" + temp["modName"] + "/" in x[0]: - mods_list.append(x) + if not is_ddlc_mode: - elif x[1] and "renpy/" in x[1].replace("\\", "/"): - mods_list.append(x) - - # Check if file in RPA - elif not x[1]: - rpycDeclared = False - for y in mods_list[:]: - - if y[0].split("/")[-1] == x[0]: - rpycDeclared = True - break + # Make sure we add the needed DDMD files + ddmd_files = {"mod_installer", "mod_services", "mod_screen", "mod_settings", "ml_patches", "mod_content", "mod_dir_browser", "mod_list", + "mod_prompt", "mod_styles", "mod_transforms", "saves"} + + for x in renpy.game.script.script_files: - if not rpycDeclared: + if x[0] in ddmd_files or (x[1] is not None and "renpy/" in x[1].replace("\\", "/")): + mods_set.add(x) - mods_list.append(x) + for x in renpy.game.script.script_files: + if "mods/" + mod_name + "/" in x[0]: + mods_set.add(x) + elif x[1] is None and x[0].split("/")[-1] not in [y[0].split("/")[-1] for y in mods_set]: + mods_set.add(x) - continue - - renpy.game.script.script_files = mods_list + renpy.game.script.script_files = list(mods_set) else: - for x in renpy.game.script.script_files[:]: - - if "mods/" in x[0]: - renpy.game.script.script_files.remove(x) + renpy.game.script.script_files = [x for x in renpy.game.script.script_files if "mods/" not in x[0]] # Load all .rpy files. renpy.game.script.load_script() # sets renpy.game.script. if not inRenpy: - if temp: - log_clock("Loading %s needed RPYC/RPYs" % temp["modName"]) + if not is_ddlc_mode: + log_clock("Loading %s needed RPYC/RPYs" % mod_name) else: log_clock("Loading Stock/DDLC RPYC/RPYs") - if not os.path.exists(renpy.config.basedir + "/ddmd_settings.json"): - with open( - renpy.config.basedir + "/ddmd_settings.json", "wb" - ) as ddmd_settings: + settings_path = os.path.join(renpy.config.basedir, "ddmd_settings.json") + if not os.path.isfile(settings_path): + with open(settings_path, "wb") as ddmd_settings: ddmd_settings.write( renpy.exports.file("sdc_system/backups/settings.backup").read() ) - if not os.path.exists(renpy.config.basedir + "/game/ddmc.json"): - with open(renpy.config.basedir + "/game/ddmc.json", "wb") as ddmc_json: + ddmc_json_path = os.path.join(renpy.config.basedir, "game", "ddmc.json") + if not os.path.isfile(ddmc_json_path): + with open(ddmc_json_path, "wb") as ddmc_json: ddmc_json.write( renpy.exports.file("sdc_system/backups/ddmc.backup").read() ) @@ -526,15 +493,10 @@ def find_archives(temp): def init_load_settings(): import json - with open( - renpy.config.basedir + "/ddmd_settings.json", "r" - ) as ddmd_settings: + with open(settings_path, "r") as ddmd_settings: ddmd_configuration = json.load(ddmd_settings) - for ddmd in ddmd_configuration: - renpy.config.gl2 = ddmd["config_gl2"] - - del ddmd_configuration + renpy.config.gl2 = ddmd_configuration.get("config_gl2", False) init_load_settings() log_clock("Loading DDMD Settings") @@ -592,10 +554,12 @@ def init_load_settings(): "\\", "/" ) if temp: - renpy.config.basedir = os.path.join( - renpy.config.basedir, "game/mods", temp["modName"] - ).replace("\\", "/") - del temp + mod_base_folder = os.path.join(renpy.config.basedir, "game/mods", mod_name) + renpy.config.basedir = os.path.normpath(mod_base_folder).replace("\\", "/") + + del temp + del mod_name + del is_rpa if renpy.parser.report_parse_errors(): raise renpy.game.ParseErrorException() From 95a433b8d9341056870ae0f77aaa52dbfb63e6f1 Mon Sep 17 00:00:00 2001 From: GanstaKingofSA Date: Fri, 7 Jul 2023 12:30:32 -0500 Subject: [PATCH 2/2] fix settings format for r6 too --- game/mod_screen.rpy | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/game/mod_screen.rpy b/game/mod_screen.rpy index fb283db..241778d 100644 --- a/game/mod_screen.rpy +++ b/game/mod_screen.rpy @@ -41,11 +41,9 @@ init python: return json.load(mod_json) def set_settings_json(): - temp = [ - { + temp = { "config_gl2": config.gl2 - } - ] + } with open(persistent.ddml_basedir + "/ddmd_settings.json", "w") as ddmd_settings: json.dump(temp, ddmd_settings)