mirror of
https://git.cavemanon.xyz/Cavemanon/SnootGame.git
synced 2025-01-22 09:16:56 +01:00
Fix NOMODS flag clearing the load order
Mods that don't have loadable scripts are forced on
This commit is contained in:
parent
b1719c4b21
commit
a266c9508c
1 changed files with 349 additions and 342 deletions
|
@ -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.
|
# 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 = []
|
mod_name_list = []
|
||||||
|
|
||||||
for file in loadable_mod_metadata:
|
if load_metadata:
|
||||||
mod_data_final = {}
|
for file in loadable_mod_metadata:
|
||||||
mod_jsonfail_list = [] # List of languages that has an associated metadata language file that failed to load.
|
mod_data_final = {}
|
||||||
mod_preferred_modname = []
|
mod_jsonfail_list = [] # List of languages that has an associated metadata language file that failed to load.
|
||||||
mod_exception = False
|
mod_preferred_modname = []
|
||||||
mod_in_root_folder = file.count("/", len(mods_dir)) is 0
|
mod_exception = False
|
||||||
mod_folder_name = file.split("/")[-2]
|
mod_in_root_folder = file.count("/", len(mods_dir)) is 0
|
||||||
# mod_name is used only to display debugging information via mod_menu_errorcodes. Contains the mod folder name and whatever translations of
|
mod_folder_name = file.split("/")[-2]
|
||||||
# the mod's name that exist. Kind of a cursed implemnetation but with how early error reporting this is before solidifying the mod name
|
# mod_name is used only to display debugging information via mod_menu_errorcodes. Contains the mod folder name and whatever translations of
|
||||||
# this is just what I came up with.
|
# the mod's name that exist. Kind of a cursed implemnetation but with how early error reporting this is before solidifying the mod name
|
||||||
# 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
|
# this is just what I came up with.
|
||||||
# current language is not there.
|
# 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
|
||||||
mod_name = {}
|
# current language is not there.
|
||||||
if mod_in_root_folder:
|
mod_name = {}
|
||||||
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 mod_in_root_folder:
|
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:
|
else:
|
||||||
print(f"//////////// ERROR IN MOD '{mod_folder_name}':")
|
mod_name["Folder"] = mod_folder_name
|
||||||
print(" "+str(e))
|
|
||||||
print("//////////// END OF ERROR")
|
|
||||||
mod_exception = True
|
|
||||||
mod_jsonfail_list.append("None")
|
|
||||||
|
|
||||||
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.
|
# Quickly get the names of mods for debugging information, and in the process get raw values from each metadata file that exists.
|
||||||
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
|
|
||||||
|
|
||||||
# Find language metadata files in the same place as our original metadata file, and then get values from it.
|
# Make the base metadata file (presumably english) organized like a lang_data object, moving the ID to the mod_data_final object.
|
||||||
for lang in renpy.known_languages():
|
try:
|
||||||
lang_file = file[:-5] + "_" + lang + ".json" # Finds the metadata file. ex: metadata_es.json
|
mod_data = json.load(renpy.open_file(file))
|
||||||
if renpy.loadable(lang_file):
|
except Exception as e:
|
||||||
try:
|
if mod_in_root_folder:
|
||||||
lang_data = (json.load(renpy.open_file(lang_file)))
|
print("//////////// ERROR IN ROOT FOLDER MOD:")
|
||||||
except Exception as e:
|
else:
|
||||||
if mod_in_root_folder:
|
print(f"//////////// ERROR IN MOD '{mod_folder_name}':")
|
||||||
print(f"//////////// ERROR FOR {lang} METADATA IN ROOT FOLDER MOD:")
|
print(" "+str(e))
|
||||||
else:
|
print("//////////// END OF ERROR")
|
||||||
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 }])
|
|
||||||
mod_exception = True
|
mod_exception = True
|
||||||
elif not isinstance(mod_data_final["ID"], str):
|
mod_jsonfail_list.append("None")
|
||||||
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.
|
if not mod_jsonfail_list:
|
||||||
for lang_key in mod_data_final.keys():
|
if _preferences.language == None and isinstance(mod_data.get("Name"), str):
|
||||||
if lang_key is "None" or lang_key in renpy.known_languages():
|
mod_name["None"] = mod_data["Name"]
|
||||||
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.
|
# Move these non-language specific pairs out of mod_data, into the base of the final mod dict.
|
||||||
# So we gotta make all lists revertable
|
move_key_to_dict(mod_data, mod_data_final, "ID")
|
||||||
for x in lang_data.keys():
|
move_key_to_dict(mod_data, mod_data_final, "Label")
|
||||||
if type(lang_data[x]) == python_list:
|
# Then store the rest like any other language, just our default one.
|
||||||
lang_data[x] = renpy.revertable.RevertableList(lang_data[x])
|
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
|
# Find language metadata files in the same place as our original metadata file, and then get values from it.
|
||||||
if value_isnt_valid_string(lang_data, "Name"):
|
for lang in renpy.known_languages():
|
||||||
if lang_data.get("Name") != None:
|
lang_file = file[:-5] + "_" + lang + ".json" # Finds the metadata file. ex: metadata_es.json
|
||||||
mod_menu_errorcodes.append([ ModError.Name_Not_String, { "mod_name": mod_name, "lang_code": lang_key }])
|
if renpy.loadable(lang_file):
|
||||||
|
try:
|
||||||
lang_data["Name"] = mod_folder_name
|
lang_data = (json.load(renpy.open_file(lang_file)))
|
||||||
|
except Exception as e:
|
||||||
# Default "Display" to 'both' mode
|
if mod_in_root_folder:
|
||||||
if lang_data.get("Display") != None:
|
print(f"//////////// ERROR FOR {lang} METADATA IN ROOT FOLDER MOD:")
|
||||||
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:]
|
|
||||||
else:
|
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
|
# Attempt to use this mod's translation of it's name if it matches the user's language preference.
|
||||||
try:
|
if not lang in mod_jsonfail_list:
|
||||||
converted_number = int(number)
|
if _preferences.language == lang and isinstance(lang_data.get("Name"), str):
|
||||||
except:
|
mod_name[lang] = lang_data["Name"]
|
||||||
continue
|
mod_data_final[lang] = lang_data
|
||||||
|
|
||||||
if not is_valid_metadata_image(this_file, mod_name):
|
# Finally report if any of the jsons failed to load, now that we have the definitive list of mod names we could display.
|
||||||
continue
|
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:
|
# Sanitize/Clean metadata values
|
||||||
mod_screenshots["None"] = []
|
#
|
||||||
mod_screenshots["None"].append((i, converted_number))
|
|
||||||
elif lang_code in renpy.known_languages():
|
# Make sure our main metadata loaded
|
||||||
if mod_screenshots.get(lang_code) == None:
|
if not "None" in mod_jsonfail_list:
|
||||||
mod_screenshots[lang_code] = []
|
if mod_data_final.get("Label") != None and not isinstance(mod_data_final.get("Label"), str):
|
||||||
mod_screenshots[lang_code].append((i, converted_number))
|
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
|
elif this_file.startswith("icon."):
|
||||||
if mod_exception:
|
if is_valid_metadata_image(this_file, mod_name):
|
||||||
continue
|
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)
|
elif this_file.startswith("screenshot"):
|
||||||
# as a base, and then either replacing or adding the translated screenshots according to their order/number.
|
# Disect the string after "screenshot" for the number and possible lang code
|
||||||
for lang_key in mod_screenshots.keys():
|
trimmed_string = this_file[len("screenshot"):this_file.find(".")]
|
||||||
if lang_key != "None":
|
number = ""
|
||||||
if mod_screenshots.get("None") == None:
|
lang_code = ""
|
||||||
temp_list_with_indexes = mod_screenshots[lang_key]
|
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:
|
else:
|
||||||
temp_list_with_indexes = mod_screenshots["None"]
|
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
|
# Get rid of the tuples and just leave the screenshot files
|
||||||
else:
|
mod_data_final[lang_key]["Screenshots"] = []
|
||||||
temp_list_with_indexes = mod_screenshots["None"]
|
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
|
# Make a copy of the current screenshots list, then put displayable screenshots wherever the values of "Screenshot Displayables" correspond in this list
|
||||||
mod_data_final[lang_key]["Screenshots"] = []
|
# mod_screenshots will return an empty list if there were no screenshot files to begin with, so this works fine.
|
||||||
for i in temp_list_with_indexes:
|
for lang_key in mod_data_final.keys():
|
||||||
mod_data_final[lang_key]["Screenshots"].append(i[0])
|
if lang_key is "None" or lang_key in renpy.known_languages():
|
||||||
|
if mod_data_final[lang_key].get("Screenshots") == None:
|
||||||
# Make a copy of the current screenshots list, then put displayable screenshots wherever the values of "Screenshot Displayables" correspond in this list
|
mod_screenshots = []
|
||||||
# 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
|
|
||||||
else:
|
else:
|
||||||
mod_data_final[lang_key]["Screenshot Displayables"] = None
|
mod_screenshots = mod_data_final[lang_key]["Screenshots"]
|
||||||
|
|
||||||
# Store the collected scripts and screenshots
|
if mod_data_final[lang_key].get("Screenshot Displayables") != None:
|
||||||
mod_data_final["Scripts"] = mod_scripts
|
mod_displayable_list = mod_screenshots.copy()
|
||||||
|
|
||||||
# Make our mod loadable
|
for i, x in enumerate(mod_data_final[lang_key]["Screenshot Displayables"]):
|
||||||
mod_menu_metadata.append(mod_data_final)
|
if i < len(mod_screenshots):
|
||||||
mod_name_list.append(mod_name) # This will mirror mod_menu_metadata
|
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
|
# 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
|
# 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
|
# The effect will be that mod_menu_metadata is sorted from first to last to be loaded
|
||||||
temp_list = []
|
temp_list = []
|
||||||
for saved_mod_id, saved_mod_state in persistent.enabled_mods:
|
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:
|
for mod in mod_menu_metadata:
|
||||||
if mod["ID"] == saved_mod_id:
|
mod_not_found = True
|
||||||
mod["Enabled"] = saved_mod_state
|
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)
|
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
|
mod_menu_metadata = temp_list
|
||||||
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
|
# 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
|
for mod in mod_menu_metadata:
|
||||||
persistent.enabled_mods.clear()
|
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
|
# 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"]:
|
if load_mods and mod["Enabled"]:
|
||||||
for script in mod["Scripts"]:
|
for script in mod["Scripts"]:
|
||||||
renpy.include_module(script)
|
renpy.include_module(script)
|
||||||
else:
|
else:
|
||||||
mod["Enabled"] = False
|
mod["Enabled"] = False
|
||||||
|
|
||||||
# Now convert our errorcodes to errorstrings
|
# Now convert our errorcodes to errorstrings
|
||||||
init python:
|
init python:
|
||||||
|
|
Loading…
Reference in a new issue