diff --git a/game/src/mod_menu.rpy b/game/src/mod_menu.rpy index 24bb1fb..801f5e7 100644 --- a/game/src/mod_menu.rpy +++ b/game/src/mod_menu.rpy @@ -190,380 +190,387 @@ init -999 python: # Contains the mod_name's of previous mods that have successfully loaded, mirroring mod_menu_metadata while in this loop. Only used for ID checking. mod_name_list = [] - for file in loadable_mod_metadata: - mod_data_final = {} - mod_jsonfail_list = [] # List of languages that has an associated metadata language file that failed to load. - mod_preferred_modname = [] - mod_exception = False - mod_in_root_folder = file.count("/", len(mods_dir)) is 0 - mod_folder_name = file.split("/")[-2] - # mod_name is used only to display debugging information via mod_menu_errorcodes. Contains the mod folder name and whatever translations of - # the mod's name that exist. Kind of a cursed implemnetation but with how early error reporting this is before solidifying the mod name - # this is just what I came up with. - # Other than what's directly defined here, it will contain mod names by their language code if they exist. The "None" key will be the fallback if a name of user's - # current language is not there. - mod_name = {} - if mod_in_root_folder: - mod_name["Folder"] = None # 'None' will make it default to 'in root of mods folder' when used in the errorcode conversion. - else: - mod_name["Folder"] = mod_folder_name - - - # Quickly get the names of mods for debugging information, and in the process get raw values from each metadata file that exists. - - # Make the base metadata file (presumably english) organized like a lang_data object, moving the ID to the mod_data_final object. - try: - mod_data = json.load(renpy.open_file(file)) - except Exception as e: + if load_metadata: + for file in loadable_mod_metadata: + mod_data_final = {} + mod_jsonfail_list = [] # List of languages that has an associated metadata language file that failed to load. + mod_preferred_modname = [] + mod_exception = False + mod_in_root_folder = file.count("/", len(mods_dir)) is 0 + mod_folder_name = file.split("/")[-2] + # mod_name is used only to display debugging information via mod_menu_errorcodes. Contains the mod folder name and whatever translations of + # the mod's name that exist. Kind of a cursed implemnetation but with how early error reporting this is before solidifying the mod name + # this is just what I came up with. + # Other than what's directly defined here, it will contain mod names by their language code if they exist. The "None" key will be the fallback if a name of user's + # current language is not there. + mod_name = {} if mod_in_root_folder: - print("//////////// ERROR IN ROOT FOLDER MOD:") + mod_name["Folder"] = None # 'None' will make it default to 'in root of mods folder' when used in the errorcode conversion. else: - print(f"//////////// ERROR IN MOD '{mod_folder_name}':") - print(" "+str(e)) - print("//////////// END OF ERROR") - mod_exception = True - mod_jsonfail_list.append("None") + mod_name["Folder"] = mod_folder_name - if not mod_jsonfail_list: - if _preferences.language == None and isinstance(mod_data.get("Name"), str): - mod_name["None"] = mod_data["Name"] - # Move these non-language specific pairs out of mod_data, into the base of the final mod dict. - move_key_to_dict(mod_data, mod_data_final, "ID") - move_key_to_dict(mod_data, mod_data_final, "Label") - # Then store the rest like any other language, just our default one. - mod_data_final['None'] = mod_data + # Quickly get the names of mods for debugging information, and in the process get raw values from each metadata file that exists. - # Find language metadata files in the same place as our original metadata file, and then get values from it. - for lang in renpy.known_languages(): - lang_file = file[:-5] + "_" + lang + ".json" # Finds the metadata file. ex: metadata_es.json - if renpy.loadable(lang_file): - try: - lang_data = (json.load(renpy.open_file(lang_file))) - except Exception as e: - if mod_in_root_folder: - print(f"//////////// ERROR FOR {lang} METADATA IN ROOT FOLDER MOD:") - else: - print(f"//////////// ERROR FOR {lang} METADATA IN MOD '{mod_folder_name}':") - print(" "+str(e)) - print("//////////// END OF ERROR") - mod_jsonfail_list.append(lang) - - # Attempt to use this mod's translation of it's name if it matches the user's language preference. - if not lang in mod_jsonfail_list: - if _preferences.language == lang and isinstance(lang_data.get("Name"), str): - mod_name[lang] = lang_data["Name"] - mod_data_final[lang] = lang_data - - # Finally report if any of the jsons failed to load, now that we have the definitive list of mod names we could display. - for lang_code in mod_jsonfail_list: - mod_menu_errorcodes.append([ ModError.Metadata_Fail, { "mod_name": mod_name, "lang_code": lang_code }]) - - # - # Sanitize/Clean metadata values - # - - # Make sure our main metadata loaded - if not "None" in mod_jsonfail_list: - if mod_data_final.get("Label") != None and not isinstance(mod_data_final.get("Label"), str): - mod_menu_errorcodes.append([ ModError.Label_Not_String, { "mod_name": mod_name }]) - mod_data_final["Label"] = None - - # If we don't have an ID, don't put it in the mod loader - if mod_data_final.get("ID") == None: - mod_menu_errorcodes.append([ ModError.No_ID, { "mod_name": mod_name }]) + # Make the base metadata file (presumably english) organized like a lang_data object, moving the ID to the mod_data_final object. + try: + mod_data = json.load(renpy.open_file(file)) + except Exception as e: + if mod_in_root_folder: + print("//////////// ERROR IN ROOT FOLDER MOD:") + else: + print(f"//////////// ERROR IN MOD '{mod_folder_name}':") + print(" "+str(e)) + print("//////////// END OF ERROR") mod_exception = True - elif not isinstance(mod_data_final["ID"], str): - mod_menu_errorcodes.append([ ModError.ID_Not_String, { "mod_name": mod_name }]) - mod_exception = True - else: - # Detect already loaded metadata that has the same ID as our current one, and if so, don't load them - # We'll never get a match for the first mod loaded, so this is fine. - for i, x in enumerate(mod_menu_metadata): - if x["ID"] == mod_data_final["ID"]: - mod_menu_errorcodes.append([ ModError.Similar_IDs_Found, { "mod_name": mod_name, "mod_name2": mod_name_list[i] }]) - mod_exception = True - break + mod_jsonfail_list.append("None") - # Since lang keys will only be added to the mod data dict if their respective metadata successfully loaded, no need to check if they can. - for lang_key in mod_data_final.keys(): - if lang_key is "None" or lang_key in renpy.known_languages(): - lang_data = mod_data_final[lang_key] + if not mod_jsonfail_list: + if _preferences.language == None and isinstance(mod_data.get("Name"), str): + mod_name["None"] = mod_data["Name"] - # The JSON object returns an actual python list, but renpy only works with it's own list object and the automation for this fails with JSON. - # So we gotta make all lists revertable - for x in lang_data.keys(): - if type(lang_data[x]) == python_list: - lang_data[x] = renpy.revertable.RevertableList(lang_data[x]) + # Move these non-language specific pairs out of mod_data, into the base of the final mod dict. + move_key_to_dict(mod_data, mod_data_final, "ID") + move_key_to_dict(mod_data, mod_data_final, "Label") + # Then store the rest like any other language, just our default one. + mod_data_final['None'] = mod_data - # Automatically give the name of the mod from the folder it's using if there's no defined name, but report an error if one is defined but not a string - if value_isnt_valid_string(lang_data, "Name"): - if lang_data.get("Name") != None: - mod_menu_errorcodes.append([ ModError.Name_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) - - lang_data["Name"] = mod_folder_name - - # Default "Display" to 'both' mode - if lang_data.get("Display") != None: - if not isinstance(lang_data.get("Display"), str): - if lang_data.get("Display") != None: - mod_menu_errorcodes.append([ ModError.Display_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) - lang_data["Display"] = "both" - elif lang_data["Display"] not in ["both","icon","name"]: - mod_menu_errorcodes.append([ ModError.Display_Invalid_Mode, { "mod_name": mod_name, "display_mode": lang_data["Display"], "lang_code": lang_key }]) - lang_data["Display"] = "both" - - if value_isnt_valid_string(lang_data, "Version"): - mod_menu_errorcodes.append([ ModError.Version_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) - lang_data["Version"] = None - - # See if "Authors" is a list or string, and if it's a list search through the contents of the list to check if they're valid strings - if value_isnt_valid_string(lang_data, "Authors") and value_isnt_valid_list(lang_data, "Authors"): - mod_menu_errorcodes.append([ ModError.Authors_Not_String_Or_List, { "mod_name": mod_name, "lang_code": lang_key }]) - lang_data["Authors"] = None - elif isinstance(lang_data.get("Authors"), list): - # Search through and call out entries that aren't strings - for i, s in enumerate(lang_data["Authors"]): - if not isinstance(s, str): - mod_menu_errorcodes.append([ ModError.Authors_Contents_Not_String, { "mod_name": mod_name, "author_number": i + 1, "lang_code": lang_key }]) - # And then mutate the list to only include strings - lang_data["Authors"][:] = [x for x in lang_data["Authors"] if isinstance(x, str)] - - if lang_data["Authors"] == []: - lang_data["Authors"] = None - - # Do the same as 'Authors' to 'Links' - if value_isnt_valid_string(lang_data, "Links") and value_isnt_valid_list(lang_data, "Links"): - mod_menu_errorcodes.append([ ModError.Links_Not_String_Or_List, { "mod_name": mod_name, "lang_code": lang_key }]) - lang_data["Links"] = None - elif isinstance(lang_data.get("Links"), list): - for i, s in enumerate(lang_data["Links"]): - if not isinstance(s, str): - mod_menu_errorcodes.append([ ModError.Links_Contents_Not_String, { "mod_name": mod_name, "link_number": i + 1, "lang_code": lang_key }]) - lang_data["Links"][:] = [x for x in lang_data["Links"] if isinstance(x, str)] - - if lang_data["Links"] == []: - lang_data["Links"] = None - - if value_isnt_valid_string(lang_data, "Description"): - mod_menu_errorcodes.append([ ModError.Description_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) - lang_data["Description"] = None - - if value_isnt_valid_string(lang_data, "Mobile Description"): - mod_menu_errorcodes.append([ ModError.Mobile_Description_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) - lang_data["Mobile Description"] = None - - if lang_data.get("Screenshot Displayables") != None: - if not isinstance(lang_data.get("Screenshot Displayables"), list): - mod_menu_errorcodes.append([ ModError.Screenshot_Displayables_Not_List, { "mod_name": mod_name, "lang_code": lang_key }]) - lang_data["Screenshot Displayables"] = None - else: - # Instead of remaking the list to only include strings, replace the non-strings with empty strings ("") so subsequent strings will still be in the right - # place when eventually showing displayable screenshots over non-displayable ones - for i, s in enumerate(lang_data["Screenshot Displayables"]): - if not isinstance(s, str): - mod_menu_errorcodes.append([ ModError.Screenshot_Displayables_Contents_Not_String, { "mod_name": mod_name, "screenshot_number": i + 1, "lang_code": lang_key }]) - s = "" - - if lang_data["Screenshot Displayables"] == []: - lang_data["Screenshot Displayables"] = None - - if value_isnt_valid_string(lang_data, "Icon Displayable"): - mod_menu_errorcodes.append([ ModError.Icon_Displayable_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) - lang_data["Icon Displayable"] = None - - if value_isnt_valid_string(lang_data, "Thumbnail Displayable"): - mod_menu_errorcodes.append([ ModError.Thumbnail_Displayable_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) - lang_data["Thumbnail Displayable"] = None - - # If our mod does not follow the structure of 'mods/Mod Name/metadata.json', don't load them - this_mod_dir = file[len(mods_dir):-len("metadata.json")] # If the metadata file is in another place, this will connect the filepath between it and the mods folder. - if file.count("/", len(mods_dir)) > 1: - good_folder = "'{color=#ffbdbd}" + mods_dir + mod_folder_name + "/{/color}'" - curr_folder = "'{color=#ffbdbd}" + mods_dir + this_mod_dir + "{/color}'" - mod_menu_errorcodes.append([ ModError.Installed_Incorrectly, { "mod_name": mod_name, "good_dir": good_folder, "curr_dir": curr_folder }]) - mod_exception = True - elif mod_in_root_folder: - mod_menu_errorcodes.append([ ModError.Installed_Incorrectly, { "mod_name": mod_name, "good_dir": mods_dir + "My Mod/", "curr_dir": mods_dir }]) - mod_exception = True - - # - # Collect mod scripts and metadata images - # - - mod_scripts = [] - mod_screenshots = {} - this_mod_dir_length = len(mods_dir + this_mod_dir) - for i in all_mod_files: - if i.startswith(mods_dir + this_mod_dir): - # Collect mod scripts - if not mod_exception and i.endswith(".rpym"): - mod_scripts.append(i[:-5]) - continue - - # This will only allow files that are at the root of the mod folder and have one period. - elif i.count("/", this_mod_dir_length) == 0 and i.count(".", this_mod_dir_length) == 1: - this_file = i[this_mod_dir_length:] - - if this_file.startswith("thumbnail."): - if is_valid_metadata_image(this_file, mod_name): - mod_data_final["None"]["Thumbnail"] = i - elif this_file.startswith("thumbnail_"): - trimmed_string = this_file[len("thumbnail_"):this_file.find(".")] - for lang in renpy.known_languages(): - if lang == trimmed_string: - if is_valid_metadata_image(this_file, mod_name): - mod_data_final[lang]["Thumbnail"] = i - - - elif this_file.startswith("icon."): - if is_valid_metadata_image(this_file, mod_name): - if mod_data_final.get("None") == None: - mod_data_final["None"] = {} - mod_data_final["None"]["Icon"] = i - elif this_file.startswith("icon_"): - trimmed_string = this_file[len("icon_"):this_file.find(".")] - for lang in renpy.known_languages(): - if lang == trimmed_string: - if is_valid_metadata_image(this_file, mod_name): - if mod_data_final.get(lang) == None: - mod_data_final["None"] = {} - mod_data_final[lang]["Icon"] = i - - - elif this_file.startswith("screenshot"): - # Disect the string after "screenshot" for the number and possible lang code - trimmed_string = this_file[len("screenshot"):this_file.find(".")] - number = "" - lang_code = "" - seperator = trimmed_string.find("_") - if seperator != -1: - number = trimmed_string[:seperator] - lang_code = trimmed_string[seperator + 1:] + # Find language metadata files in the same place as our original metadata file, and then get values from it. + for lang in renpy.known_languages(): + lang_file = file[:-5] + "_" + lang + ".json" # Finds the metadata file. ex: metadata_es.json + if renpy.loadable(lang_file): + try: + lang_data = (json.load(renpy.open_file(lang_file))) + except Exception as e: + if mod_in_root_folder: + print(f"//////////// ERROR FOR {lang} METADATA IN ROOT FOLDER MOD:") else: - number = trimmed_string + print(f"//////////// ERROR FOR {lang} METADATA IN MOD '{mod_folder_name}':") + print(" "+str(e)) + print("//////////// END OF ERROR") + mod_jsonfail_list.append(lang) - # See if we can extract the number - try: - converted_number = int(number) - except: - continue + # Attempt to use this mod's translation of it's name if it matches the user's language preference. + if not lang in mod_jsonfail_list: + if _preferences.language == lang and isinstance(lang_data.get("Name"), str): + mod_name[lang] = lang_data["Name"] + mod_data_final[lang] = lang_data - if not is_valid_metadata_image(this_file, mod_name): - continue + # Finally report if any of the jsons failed to load, now that we have the definitive list of mod names we could display. + for lang_code in mod_jsonfail_list: + mod_menu_errorcodes.append([ ModError.Metadata_Fail, { "mod_name": mod_name, "lang_code": lang_code }]) - if seperator == -1: - if mod_screenshots.get("None") == None: - mod_screenshots["None"] = [] - mod_screenshots["None"].append((i, converted_number)) - elif lang_code in renpy.known_languages(): - if mod_screenshots.get(lang_code) == None: - mod_screenshots[lang_code] = [] - mod_screenshots[lang_code].append((i, converted_number)) + # + # Sanitize/Clean metadata values + # + + # Make sure our main metadata loaded + if not "None" in mod_jsonfail_list: + if mod_data_final.get("Label") != None and not isinstance(mod_data_final.get("Label"), str): + mod_menu_errorcodes.append([ ModError.Label_Not_String, { "mod_name": mod_name }]) + mod_data_final["Label"] = None + + # If we don't have an ID, don't put it in the mod loader + if mod_data_final.get("ID") == None: + mod_menu_errorcodes.append([ ModError.No_ID, { "mod_name": mod_name }]) + mod_exception = True + elif not isinstance(mod_data_final["ID"], str): + mod_menu_errorcodes.append([ ModError.ID_Not_String, { "mod_name": mod_name }]) + mod_exception = True + else: + # Detect already loaded metadata that has the same ID as our current one, and if so, don't load them + # We'll never get a match for the first mod loaded, so this is fine. + for i, x in enumerate(mod_menu_metadata): + if x["ID"] == mod_data_final["ID"]: + mod_menu_errorcodes.append([ ModError.Similar_IDs_Found, { "mod_name": mod_name, "mod_name2": mod_name_list[i] }]) + mod_exception = True + break + + # Since lang keys will only be added to the mod data dict if their respective metadata successfully loaded, no need to check if they can. + for lang_key in mod_data_final.keys(): + if lang_key is "None" or lang_key in renpy.known_languages(): + lang_data = mod_data_final[lang_key] + + # The JSON object returns an actual python list, but renpy only works with it's own list object and the automation for this fails with JSON. + # So we gotta make all lists revertable + for x in lang_data.keys(): + if type(lang_data[x]) == python_list: + lang_data[x] = renpy.revertable.RevertableList(lang_data[x]) + + # Automatically give the name of the mod from the folder it's using if there's no defined name, but report an error if one is defined but not a string + if value_isnt_valid_string(lang_data, "Name"): + if lang_data.get("Name") != None: + mod_menu_errorcodes.append([ ModError.Name_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) + + lang_data["Name"] = mod_folder_name + + # Default "Display" to 'both' mode + if lang_data.get("Display") != None: + if not isinstance(lang_data.get("Display"), str): + if lang_data.get("Display") != None: + mod_menu_errorcodes.append([ ModError.Display_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) + lang_data["Display"] = "both" + elif lang_data["Display"] not in ["both","icon","name"]: + mod_menu_errorcodes.append([ ModError.Display_Invalid_Mode, { "mod_name": mod_name, "display_mode": lang_data["Display"], "lang_code": lang_key }]) + lang_data["Display"] = "both" + + if value_isnt_valid_string(lang_data, "Version"): + mod_menu_errorcodes.append([ ModError.Version_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) + lang_data["Version"] = None + + # See if "Authors" is a list or string, and if it's a list search through the contents of the list to check if they're valid strings + if value_isnt_valid_string(lang_data, "Authors") and value_isnt_valid_list(lang_data, "Authors"): + mod_menu_errorcodes.append([ ModError.Authors_Not_String_Or_List, { "mod_name": mod_name, "lang_code": lang_key }]) + lang_data["Authors"] = None + elif isinstance(lang_data.get("Authors"), list): + # Search through and call out entries that aren't strings + for i, s in enumerate(lang_data["Authors"]): + if not isinstance(s, str): + mod_menu_errorcodes.append([ ModError.Authors_Contents_Not_String, { "mod_name": mod_name, "author_number": i + 1, "lang_code": lang_key }]) + # And then mutate the list to only include strings + lang_data["Authors"][:] = [x for x in lang_data["Authors"] if isinstance(x, str)] + + if lang_data["Authors"] == []: + lang_data["Authors"] = None + + # Do the same as 'Authors' to 'Links' + if value_isnt_valid_string(lang_data, "Links") and value_isnt_valid_list(lang_data, "Links"): + mod_menu_errorcodes.append([ ModError.Links_Not_String_Or_List, { "mod_name": mod_name, "lang_code": lang_key }]) + lang_data["Links"] = None + elif isinstance(lang_data.get("Links"), list): + for i, s in enumerate(lang_data["Links"]): + if not isinstance(s, str): + mod_menu_errorcodes.append([ ModError.Links_Contents_Not_String, { "mod_name": mod_name, "link_number": i + 1, "lang_code": lang_key }]) + lang_data["Links"][:] = [x for x in lang_data["Links"] if isinstance(x, str)] + + if lang_data["Links"] == []: + lang_data["Links"] = None + + if value_isnt_valid_string(lang_data, "Description"): + mod_menu_errorcodes.append([ ModError.Description_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) + lang_data["Description"] = None + + if value_isnt_valid_string(lang_data, "Mobile Description"): + mod_menu_errorcodes.append([ ModError.Mobile_Description_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) + lang_data["Mobile Description"] = None + + if lang_data.get("Screenshot Displayables") != None: + if not isinstance(lang_data.get("Screenshot Displayables"), list): + mod_menu_errorcodes.append([ ModError.Screenshot_Displayables_Not_List, { "mod_name": mod_name, "lang_code": lang_key }]) + lang_data["Screenshot Displayables"] = None + else: + # Instead of remaking the list to only include strings, replace the non-strings with empty strings ("") so subsequent strings will still be in the right + # place when eventually showing displayable screenshots over non-displayable ones + for i, s in enumerate(lang_data["Screenshot Displayables"]): + if not isinstance(s, str): + mod_menu_errorcodes.append([ ModError.Screenshot_Displayables_Contents_Not_String, { "mod_name": mod_name, "screenshot_number": i + 1, "lang_code": lang_key }]) + s = "" + + if lang_data["Screenshot Displayables"] == []: + lang_data["Screenshot Displayables"] = None + + if value_isnt_valid_string(lang_data, "Icon Displayable"): + mod_menu_errorcodes.append([ ModError.Icon_Displayable_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) + lang_data["Icon Displayable"] = None + + if value_isnt_valid_string(lang_data, "Thumbnail Displayable"): + mod_menu_errorcodes.append([ ModError.Thumbnail_Displayable_Not_String, { "mod_name": mod_name, "lang_code": lang_key }]) + lang_data["Thumbnail Displayable"] = None + + # If our mod does not follow the structure of 'mods/Mod Name/metadata.json', don't load them + this_mod_dir = file[len(mods_dir):-len("metadata.json")] # If the metadata file is in another place, this will connect the filepath between it and the mods folder. + if file.count("/", len(mods_dir)) > 1: + good_folder = "'{color=#ffbdbd}" + mods_dir + mod_folder_name + "/{/color}'" + curr_folder = "'{color=#ffbdbd}" + mods_dir + this_mod_dir + "{/color}'" + mod_menu_errorcodes.append([ ModError.Installed_Incorrectly, { "mod_name": mod_name, "good_dir": good_folder, "curr_dir": curr_folder }]) + mod_exception = True + elif mod_in_root_folder: + mod_menu_errorcodes.append([ ModError.Installed_Incorrectly, { "mod_name": mod_name, "good_dir": mods_dir + "My Mod/", "curr_dir": mods_dir }]) + mod_exception = True + + # + # Collect mod scripts and metadata images + # + + mod_scripts = [] + mod_screenshots = {} + this_mod_dir_length = len(mods_dir + this_mod_dir) + for i in all_mod_files: + if i.startswith(mods_dir + this_mod_dir): + # Collect mod scripts + if not mod_exception and i.endswith(".rpym"): + mod_scripts.append(i[:-5]) + continue + + # This will only allow files that are at the root of the mod folder and have one period. + elif i.count("/", this_mod_dir_length) == 0 and i.count(".", this_mod_dir_length) == 1: + this_file = i[this_mod_dir_length:] + + if this_file.startswith("thumbnail."): + if is_valid_metadata_image(this_file, mod_name): + mod_data_final["None"]["Thumbnail"] = i + elif this_file.startswith("thumbnail_"): + trimmed_string = this_file[len("thumbnail_"):this_file.find(".")] + for lang in renpy.known_languages(): + if lang == trimmed_string: + if is_valid_metadata_image(this_file, mod_name): + mod_data_final[lang]["Thumbnail"] = i - # Don't load the mod if there's mod breaking errors - if mod_exception: - continue + elif this_file.startswith("icon."): + if is_valid_metadata_image(this_file, mod_name): + if mod_data_final.get("None") == None: + mod_data_final["None"] = {} + mod_data_final["None"]["Icon"] = i + elif this_file.startswith("icon_"): + trimmed_string = this_file[len("icon_"):this_file.find(".")] + for lang in renpy.known_languages(): + if lang == trimmed_string: + if is_valid_metadata_image(this_file, mod_name): + if mod_data_final.get(lang) == None: + mod_data_final["None"] = {} + mod_data_final[lang]["Icon"] = i - # We're now gonna clean up the screenshots to be more usable as-is. - # Refine collected screenshots so that translated screenshots use the 'None' screenshots (the ones without a lang code) - # as a base, and then either replacing or adding the translated screenshots according to their order/number. - for lang_key in mod_screenshots.keys(): - if lang_key != "None": - if mod_screenshots.get("None") == None: - temp_list_with_indexes = mod_screenshots[lang_key] + elif this_file.startswith("screenshot"): + # Disect the string after "screenshot" for the number and possible lang code + trimmed_string = this_file[len("screenshot"):this_file.find(".")] + number = "" + lang_code = "" + seperator = trimmed_string.find("_") + if seperator != -1: + number = trimmed_string[:seperator] + lang_code = trimmed_string[seperator + 1:] + else: + number = trimmed_string + + # See if we can extract the number + try: + converted_number = int(number) + except: + continue + + if not is_valid_metadata_image(this_file, mod_name): + continue + + if seperator == -1: + if mod_screenshots.get("None") == None: + mod_screenshots["None"] = [] + mod_screenshots["None"].append((i, converted_number)) + elif lang_code in renpy.known_languages(): + if mod_screenshots.get(lang_code) == None: + mod_screenshots[lang_code] = [] + mod_screenshots[lang_code].append((i, converted_number)) + + + # Don't load the mod if there's mod breaking errors + if mod_exception: + continue + + # We're now gonna clean up the screenshots to be more usable as-is. + + # Refine collected screenshots so that translated screenshots use the 'None' screenshots (the ones without a lang code) + # as a base, and then either replacing or adding the translated screenshots according to their order/number. + for lang_key in mod_screenshots.keys(): + if lang_key != "None": + if mod_screenshots.get("None") == None: + temp_list_with_indexes = mod_screenshots[lang_key] + else: + temp_list_with_indexes = mod_screenshots["None"] + for i, lang_images in enumerate(mod_screenshots[lang_key]): + u = 0 + while u < len(temp_list_with_indexes): + if lang_images[1] > temp_list_with_indexes[u][1] and u == len(temp_list_with_indexes) - 1: + temp_list_with_indexes.append(lang_images) + break + elif lang_images[1] == temp_list_with_indexes[u][1]: + temp_list_with_indexes[u] = lang_images + break + elif lang_images[1] < temp_list_with_indexes[u][1]: + temp_list_with_indexes.insert(u, lang_images) + break + + u += 1 else: temp_list_with_indexes = mod_screenshots["None"] - for i, lang_images in enumerate(mod_screenshots[lang_key]): - u = 0 - while u < len(temp_list_with_indexes): - if lang_images[1] > temp_list_with_indexes[u][1] and u == len(temp_list_with_indexes) - 1: - temp_list_with_indexes.append(lang_images) - break - elif lang_images[1] == temp_list_with_indexes[u][1]: - temp_list_with_indexes[u] = lang_images - break - elif lang_images[1] < temp_list_with_indexes[u][1]: - temp_list_with_indexes.insert(u, lang_images) - break - u += 1 - else: - temp_list_with_indexes = mod_screenshots["None"] + # Get rid of the tuples and just leave the screenshot files + mod_data_final[lang_key]["Screenshots"] = [] + for i in temp_list_with_indexes: + mod_data_final[lang_key]["Screenshots"].append(i[0]) - # Get rid of the tuples and just leave the screenshot files - mod_data_final[lang_key]["Screenshots"] = [] - for i in temp_list_with_indexes: - mod_data_final[lang_key]["Screenshots"].append(i[0]) - - # Make a copy of the current screenshots list, then put displayable screenshots wherever the values of "Screenshot Displayables" correspond in this list - # mod_screenshots will return an empty list if there were no screenshot files to begin with, so this works fine. - for lang_key in mod_data_final.keys(): - if lang_key is "None" or lang_key in renpy.known_languages(): - if mod_data_final[lang_key].get("Screenshots") == None: - mod_screenshots = [] - else: - mod_screenshots = mod_data_final[lang_key]["Screenshots"] - - if mod_data_final[lang_key].get("Screenshot Displayables") != None: - mod_displayable_list = mod_screenshots.copy() - - for i, x in enumerate(mod_data_final[lang_key]["Screenshot Displayables"]): - if i < len(mod_screenshots): - if x != "": - mod_displayable_list[i] = x - else: - mod_displayable_list.append(x) - - if mod_displayable_list != []: - mod_data_final[lang_key]["Screenshot Displayables"] = mod_displayable_list + # Make a copy of the current screenshots list, then put displayable screenshots wherever the values of "Screenshot Displayables" correspond in this list + # mod_screenshots will return an empty list if there were no screenshot files to begin with, so this works fine. + for lang_key in mod_data_final.keys(): + if lang_key is "None" or lang_key in renpy.known_languages(): + if mod_data_final[lang_key].get("Screenshots") == None: + mod_screenshots = [] else: - mod_data_final[lang_key]["Screenshot Displayables"] = None + mod_screenshots = mod_data_final[lang_key]["Screenshots"] - # Store the collected scripts and screenshots - mod_data_final["Scripts"] = mod_scripts + if mod_data_final[lang_key].get("Screenshot Displayables") != None: + mod_displayable_list = mod_screenshots.copy() - # Make our mod loadable - mod_menu_metadata.append(mod_data_final) - mod_name_list.append(mod_name) # This will mirror mod_menu_metadata + for i, x in enumerate(mod_data_final[lang_key]["Screenshot Displayables"]): + if i < len(mod_screenshots): + if x != "": + mod_displayable_list[i] = x + else: + mod_displayable_list.append(x) + + if mod_displayable_list != []: + mod_data_final[lang_key]["Screenshot Displayables"] = mod_displayable_list + else: + mod_data_final[lang_key]["Screenshot Displayables"] = None + + # Store the collected scripts and screenshots + mod_data_final["Scripts"] = mod_scripts + + # Make our mod loadable + mod_menu_metadata.append(mod_data_final) + mod_name_list.append(mod_name) # This will mirror mod_menu_metadata - # Sort mod metadata list according to enabled_mods, while dropping mods from enabled_mods if they aren't installed - # This will also apply the state of a mod if it's supposed to be enabled/disabled - # The effect will be that mod_menu_metadata is sorted from first to last to be loaded - temp_list = [] - for saved_mod_id, saved_mod_state in persistent.enabled_mods: + # Sort mod metadata list according to enabled_mods, while dropping mods from enabled_mods if they aren't installed + # This will also apply the state of a mod if it's supposed to be enabled/disabled + # The effect will be that mod_menu_metadata is sorted from first to last to be loaded + temp_list = [] + for saved_mod_id, saved_mod_state in persistent.enabled_mods: + for mod in mod_menu_metadata: + if mod["ID"] == saved_mod_id: + mod["Enabled"] = saved_mod_state + temp_list.append(mod) + break + + # Now inverse search to find new mods and append them to metadata list. New mods are by default enabled, and are the last to be loaded for mod in mod_menu_metadata: - if mod["ID"] == saved_mod_id: - mod["Enabled"] = saved_mod_state + mod_not_found = True + for saved_mod_id in persistent.enabled_mods: + if mod["ID"] == saved_mod_id[0]: + mod_not_found = False + if mod_not_found: + # If this mod doesn't have any loadable scripts, treat it as on (Say, if a mod changed something in the base game and the label points there) + if not mod["Scripts"]: + mod["Enabled"] = True + # Otherwise set mods to the default state + else: + mod["Enabled"] = persistent.newmods_default_state temp_list.append(mod) - break - # Now inverse search to find new mods and append them to metadata list. New mods are by default enabled, and are the last to be loaded - for mod in mod_menu_metadata: - mod_not_found = True - for saved_mod_id in persistent.enabled_mods: - if mod["ID"] == saved_mod_id[0]: - mod_not_found = False - if mod_not_found: - mod["Enabled"] = persistent.newmods_default_state - temp_list.append(mod) + mod_menu_metadata = temp_list - mod_menu_metadata = temp_list + # Rewrite enabled_mods to reflect the new mod order, and load all the mods + persistent.enabled_mods.clear() - # Rewrite enabled_mods to reflect the new mod order, and load all the mods - persistent.enabled_mods.clear() - for mod in mod_menu_metadata: - persistent.enabled_mods.append( [ mod["ID"], mod["Enabled"] ] ) + for mod in mod_menu_metadata: + persistent.enabled_mods.append( [ mod["ID"], mod["Enabled"] ] ) - # Making the load_mods check here makes it so the NOLOAD flag doesn't overwrite the previously saved load order - if load_mods and mod["Enabled"]: - for script in mod["Scripts"]: - renpy.include_module(script) - else: - mod["Enabled"] = False + # Making the load_mods check here makes it so the NOLOAD flag doesn't overwrite the previously saved load order + if load_mods and mod["Enabled"]: + for script in mod["Scripts"]: + renpy.include_module(script) + else: + mod["Enabled"] = False # Now convert our errorcodes to errorstrings init python: