mirror of
https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
synced 2025-10-22 23:48:11 +00:00
added the game
This commit is contained in:
220
addons/mod_loader/resources/mod_data.gd
Normal file
220
addons/mod_loader/resources/mod_data.gd
Normal file
@@ -0,0 +1,220 @@
|
||||
class_name ModData
|
||||
extends Resource
|
||||
##
|
||||
## Stores and validates all Data required to load a mod successfully
|
||||
## If some of the data is invalid, [member is_loadable] will be false
|
||||
|
||||
|
||||
const LOG_NAME := "ModLoader:ModData"
|
||||
|
||||
const MOD_MAIN := "mod_main.gd"
|
||||
const MANIFEST := "manifest.json"
|
||||
const OVERWRITES := "overwrites.gd"
|
||||
|
||||
# These 2 files are always required by mods.
|
||||
# [i]mod_main.gd[/i] = The main init file for the mod
|
||||
# [i]manifest.json[/i] = Meta data for the mod, including its dependencies
|
||||
enum RequiredModFiles {
|
||||
MOD_MAIN,
|
||||
MANIFEST,
|
||||
}
|
||||
|
||||
enum OptionalModFiles {
|
||||
OVERWRITES
|
||||
}
|
||||
|
||||
# Specifies the source from which the mod has been loaded:
|
||||
# UNPACKED = From the mods-unpacked directory ( only when in the editor ).
|
||||
# LOCAL = From the local mod zip directory, which by default is ../game_dir/mods.
|
||||
# STEAM_WORKSHOP = Loaded from ../Steam/steamapps/workshop/content/1234567/[..].
|
||||
enum Sources {
|
||||
UNPACKED,
|
||||
LOCAL,
|
||||
STEAM_WORKSHOP,
|
||||
}
|
||||
|
||||
## Name of the Mod's zip file
|
||||
var zip_name := ""
|
||||
## Path to the Mod's zip file
|
||||
var zip_path := ""
|
||||
|
||||
## Directory of the mod. Has to be identical to [method ModManifest.get_mod_id]
|
||||
var dir_name := ""
|
||||
## Path to the mod's unpacked directory
|
||||
var dir_path := ""
|
||||
## False if any data is invalid
|
||||
var is_loadable := true
|
||||
## True if overwrites.gd exists
|
||||
var is_overwrite := false
|
||||
## True if mod can't be disabled or enabled in a user profile
|
||||
var is_locked := false
|
||||
## Flag indicating whether the mod should be loaded
|
||||
var is_active := true
|
||||
## Is increased for every mod depending on this mod. Highest importance is loaded first
|
||||
var importance := 0
|
||||
## Contents of the manifest
|
||||
var manifest: ModManifest
|
||||
# Updated in load_configs
|
||||
## All mod configs
|
||||
var configs := {}
|
||||
## The currently applied mod config
|
||||
var current_config: ModConfig: set = _set_current_config
|
||||
## Specifies the source from which the mod has been loaded
|
||||
var source: int
|
||||
|
||||
var load_errors: Array[String] = []
|
||||
var load_warnings: Array[String] = []
|
||||
|
||||
|
||||
|
||||
func _init(_manifest: ModManifest, path: String) -> void:
|
||||
manifest = _manifest
|
||||
|
||||
if _ModLoaderPath.is_zip(path):
|
||||
zip_name = _ModLoaderPath.get_file_name_from_path(path)
|
||||
zip_path = path
|
||||
# Use the dir name of the passed path instead of the manifest data so we can validate
|
||||
# the mod dir has the same name as the mod id in the manifest
|
||||
dir_name = _ModLoaderFile.get_mod_dir_name_in_zip(zip_path)
|
||||
else:
|
||||
dir_name = path.split("/")[-1]
|
||||
|
||||
dir_path = _ModLoaderPath.get_unpacked_mods_dir_path().path_join(dir_name)
|
||||
source = get_mod_source()
|
||||
|
||||
_has_required_files()
|
||||
# We want to avoid checking if mod_dir_name == mod_id when manifest parsing has failed
|
||||
# to prevent confusing error messages.
|
||||
if not manifest.has_parsing_failed:
|
||||
_is_mod_dir_name_same_as_id(manifest)
|
||||
|
||||
is_overwrite = _is_overwrite()
|
||||
is_locked = manifest.get_mod_id() in ModLoaderStore.ml_options.locked_mods
|
||||
|
||||
if not load_errors.is_empty() or not manifest.validation_messages_error.is_empty():
|
||||
is_loadable = false
|
||||
|
||||
|
||||
# Load each mod config json from the mods config directory.
|
||||
func load_configs() -> void:
|
||||
# If the default values in the config schema are invalid don't load configs
|
||||
if not manifest.load_mod_config_defaults():
|
||||
return
|
||||
|
||||
var config_dir_path := _ModLoaderPath.get_path_to_mod_configs_dir(dir_name)
|
||||
var config_file_paths := _ModLoaderPath.get_file_paths_in_dir(config_dir_path)
|
||||
for config_file_path in config_file_paths:
|
||||
_load_config(config_file_path)
|
||||
|
||||
# Set the current_config based on the user profile
|
||||
if ModLoaderUserProfile.is_initialized() and ModLoaderConfig.has_current_config(dir_name):
|
||||
current_config = ModLoaderConfig.get_current_config(dir_name)
|
||||
else:
|
||||
current_config = ModLoaderConfig.get_config(dir_name, ModLoaderConfig.DEFAULT_CONFIG_NAME)
|
||||
|
||||
|
||||
# Create a new ModConfig instance for each Config JSON and add it to the configs dictionary.
|
||||
func _load_config(config_file_path: String) -> void:
|
||||
var config_data := _ModLoaderFile.get_json_as_dict(config_file_path)
|
||||
var mod_config = ModConfig.new(
|
||||
dir_name,
|
||||
config_data,
|
||||
config_file_path,
|
||||
manifest.config_schema
|
||||
)
|
||||
|
||||
# Add the config to the configs dictionary
|
||||
configs[mod_config.name] = mod_config
|
||||
|
||||
|
||||
# Update the mod_list of the current user profile
|
||||
func _set_current_config(new_current_config: ModConfig) -> void:
|
||||
ModLoaderUserProfile.set_mod_current_config(dir_name, new_current_config)
|
||||
current_config = new_current_config
|
||||
# We can't emit the signal if the ModLoader is not initialized yet
|
||||
if ModLoader:
|
||||
ModLoader.current_config_changed.emit(new_current_config)
|
||||
|
||||
|
||||
func set_mod_state(should_activate: bool, force := false) -> bool:
|
||||
if is_locked and should_activate != is_active:
|
||||
ModLoaderLog.error(
|
||||
"Unable to toggle mod \"%s\" since it is marked as locked. Locked mods: %s"
|
||||
% [manifest.get_mod_id(), ModLoaderStore.ml_options.locked_mods], LOG_NAME)
|
||||
return false
|
||||
|
||||
if should_activate and not is_loadable:
|
||||
ModLoaderLog.error(
|
||||
"Unable to activate mod \"%s\" since it has the following load errors: %s"
|
||||
% [manifest.get_mod_id(), ", ".join(load_errors)], LOG_NAME)
|
||||
return false
|
||||
|
||||
if should_activate and manifest.validation_messages_warning.size() > 0:
|
||||
if not force:
|
||||
ModLoaderLog.warning(
|
||||
"Rejecting to activate mod \"%s\" since it has the following load warnings: %s"
|
||||
% [manifest.get_mod_id(), ", ".join(load_warnings)], LOG_NAME)
|
||||
return false
|
||||
ModLoaderLog.info(
|
||||
"Forced to activate mod \"%s\" despite the following load warnings: %s"
|
||||
% [manifest.get_mod_id(), ", ".join(load_warnings)], LOG_NAME)
|
||||
|
||||
is_active = should_activate
|
||||
return true
|
||||
|
||||
|
||||
# Validates if [member dir_name] matches [method ModManifest.get_mod_id]
|
||||
func _is_mod_dir_name_same_as_id(mod_manifest: ModManifest) -> bool:
|
||||
var manifest_id := mod_manifest.get_mod_id()
|
||||
if not dir_name == manifest_id:
|
||||
load_errors.push_back('Mod directory name "%s" does not match the data in manifest.json. Expected "%s" (Format: {namespace}-{name})' % [ dir_name, manifest_id ])
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
func _is_overwrite() -> bool:
|
||||
return _ModLoaderFile.file_exists(get_optional_mod_file_path(OptionalModFiles.OVERWRITES), zip_path)
|
||||
|
||||
|
||||
# Confirms that all files from [member required_mod_files] exist
|
||||
func _has_required_files() -> bool:
|
||||
var has_required_files := true
|
||||
|
||||
for required_file in RequiredModFiles:
|
||||
var required_file_path := get_required_mod_file_path(RequiredModFiles[required_file])
|
||||
|
||||
if not _ModLoaderFile.file_exists(required_file_path, zip_path):
|
||||
load_errors.push_back(
|
||||
"ERROR - %s is missing a required file: %s. For more information, please visit \"%s\"." %
|
||||
[dir_name, required_file_path, ModLoaderStore.URL_MOD_STRUCTURE_DOCS]
|
||||
)
|
||||
has_required_files = false
|
||||
|
||||
return has_required_files
|
||||
|
||||
|
||||
# Converts enum indices [member RequiredModFiles] into their respective file paths
|
||||
# All required mod files should be in the root of the mod directory
|
||||
func get_required_mod_file_path(required_file: RequiredModFiles) -> String:
|
||||
match required_file:
|
||||
RequiredModFiles.MOD_MAIN:
|
||||
return dir_path.path_join(MOD_MAIN)
|
||||
RequiredModFiles.MANIFEST:
|
||||
return dir_path.path_join(MANIFEST)
|
||||
return ""
|
||||
|
||||
|
||||
func get_optional_mod_file_path(optional_file: OptionalModFiles) -> String:
|
||||
match optional_file:
|
||||
OptionalModFiles.OVERWRITES:
|
||||
return dir_path.path_join(OVERWRITES)
|
||||
return ""
|
||||
|
||||
|
||||
func get_mod_source() -> Sources:
|
||||
if zip_path.contains("workshop"):
|
||||
return Sources.STEAM_WORKSHOP
|
||||
if zip_path == "":
|
||||
return Sources.UNPACKED
|
||||
|
||||
return Sources.LOCAL
|
||||
Reference in New Issue
Block a user