Skip to content

Commit

Permalink
feat: ✨ added zip_name and zip_path to ModData
Browse files Browse the repository at this point in the history
  • Loading branch information
KANAjetzt committed Jun 23, 2023
1 parent 5021759 commit 924f783
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 43 deletions.
3 changes: 2 additions & 1 deletion addons/mod_loader/api/profile.gd
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ static func _update_disabled_mods() -> void:
# Iterate through the mod list in the current user profile to find disabled mods
for mod_id in current_user_profile.mod_list:
var mod_list_entry: Dictionary = current_user_profile.mod_list[mod_id]
ModLoaderStore.mod_data[mod_id].is_active = mod_list_entry.is_active
if ModLoaderStore.mod_data.has(mod_id):
ModLoaderStore.mod_data[mod_id].is_active = mod_list_entry.is_active

ModLoaderLog.debug(
"Updated the active state of all mods, based on the current user profile \"%s\""
Expand Down
37 changes: 27 additions & 10 deletions addons/mod_loader/internal/file.gd
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,20 @@ static func _get_json_string_as_dict(string: String) -> Dictionary:


# Load the mod ZIP from the provided directory
static func load_zips_in_folder(folder_path: String) -> int:
var temp_zipped_mods_count := 0
static func load_zips_in_folder(folder_path: String) -> Dictionary:
var zip_data := {}

var mod_dir := Directory.new()
var mod_dir_open_error := mod_dir.open(folder_path)
if not mod_dir_open_error == OK:
ModLoaderLog.error("Can't open mod folder %s (Error: %s)" % [folder_path, mod_dir_open_error], LOG_NAME)
return -1
return {}
var mod_dir_listdir_error := mod_dir.list_dir_begin()
if not mod_dir_listdir_error == OK:
ModLoaderLog.error("Can't read mod folder %s (Error: %s)" % [folder_path, mod_dir_listdir_error], LOG_NAME)
return -1
return {}



# Get all zip folders inside the game mod folder
while true:
Expand All @@ -76,9 +78,25 @@ static func load_zips_in_folder(folder_path: String) -> int:
# Go to the next file
continue

var mod_folder_path := folder_path.plus_file(mod_zip_file_name)
var mod_folder_global_path := ProjectSettings.globalize_path(mod_folder_path)
var is_mod_loaded_successfully := ProjectSettings.load_resource_pack(mod_folder_global_path, false)
var mod_zip_path := folder_path.plus_file(mod_zip_file_name)
var mod_zip_global_path := ProjectSettings.globalize_path(mod_zip_path)
var is_mod_loaded_successfully := ProjectSettings.load_resource_pack(mod_zip_global_path, false)

# Get the current directories inside UNPACKED_DIR
# This array is used to determine which directory is new
var current_mod_dirs := _ModLoaderPath.get_dir_paths_in_dir(_ModLoaderPath.get_unpacked_mods_dir_path())
# Create a backup to reference when the next mod is loaded
var current_mod_dirs_backup := current_mod_dirs.duplicate()

# Remove all directory paths that existed before, leaving only the one added last
for previous_mod_dir in ModLoaderStore.previous_mod_dirs:
current_mod_dirs.erase(previous_mod_dir)

# The key is the mod_id of the latest loaded mod, and the value is the path to the zip file
zip_data[current_mod_dirs[0].get_slice("/", 3)] = mod_zip_global_path

# Update previous_mod_dirs in ModLoaderStore to use for the next mod
ModLoaderStore.previous_mod_dirs = current_mod_dirs_backup

# Notifies developer of an issue with Godot, where using `load_resource_pack`
# in the editor WIPES the entire virtual res:// directory the first time you
Expand All @@ -94,7 +112,7 @@ static func load_zips_in_folder(folder_path: String) -> int:
"Please unpack your mod ZIPs instead, and add them to ", _ModLoaderPath.get_unpacked_mods_dir_path()), LOG_NAME)
ModLoaderStore.has_shown_editor_zips_warning = true

ModLoaderLog.debug("Found mod ZIP: %s" % mod_folder_global_path, LOG_NAME)
ModLoaderLog.debug("Found mod ZIP: %s" % mod_zip_global_path, LOG_NAME)

# If there was an error loading the mod zip file
if not is_mod_loaded_successfully:
Expand All @@ -104,11 +122,10 @@ static func load_zips_in_folder(folder_path: String) -> int:

# Mod successfully loaded!
ModLoaderLog.success("%s loaded." % mod_zip_file_name, LOG_NAME)
temp_zipped_mods_count += 1

mod_dir.list_dir_end()

return temp_zipped_mods_count
return zip_data


# Save Data
Expand Down
12 changes: 6 additions & 6 deletions addons/mod_loader/internal/third_party/steam.gd
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const LOG_NAME := "ModLoader:ThirdParty:Steam"
# Load mod ZIPs from Steam workshop folders. Uses 2 loops: One for each
# workshop item's folder, with another inside that which loops over the ZIPs
# inside each workshop item's folder
static func load_steam_workshop_zips() -> int:
var temp_zipped_mods_count := 0
static func load_steam_workshop_zips() -> Dictionary:
var zip_data := {}
var workshop_folder_path := _get_path_to_workshop()

ModLoaderLog.info("Checking workshop items, with path: \"%s\"" % workshop_folder_path, LOG_NAME)
Expand All @@ -19,11 +19,11 @@ static func load_steam_workshop_zips() -> int:
var workshop_dir_open_error := workshop_dir.open(workshop_folder_path)
if not workshop_dir_open_error == OK:
ModLoaderLog.error("Can't open workshop folder %s (Error: %s)" % [workshop_folder_path, workshop_dir_open_error], LOG_NAME)
return -1
return {}
var workshop_dir_listdir_error := workshop_dir.list_dir_begin()
if not workshop_dir_listdir_error == OK:
ModLoaderLog.error("Can't read workshop folder %s (Error: %s)" % [workshop_folder_path, workshop_dir_listdir_error], LOG_NAME)
return -1
return {}

# Loop 1: Workshop folders
while true:
Expand All @@ -42,11 +42,11 @@ static func load_steam_workshop_zips() -> int:
continue

# Loop 2: ZIPs inside the workshop folders
temp_zipped_mods_count += _ModLoaderFile.load_zips_in_folder(ProjectSettings.globalize_path(item_path))
zip_data.merge(_ModLoaderFile.load_zips_in_folder(ProjectSettings.globalize_path(item_path)))

workshop_dir.list_dir_end()

return temp_zipped_mods_count
return zip_data


# Get the path to the Steam workshop folder. Only works for Steam games, as it
Expand Down
60 changes: 38 additions & 22 deletions addons/mod_loader/mod_loader.gd
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,20 @@ func _exit_tree() -> void:
func _load_mods() -> void:
# Loop over "res://mods" and add any mod zips to the unpacked virtual
# directory (UNPACKED_DIR)
var unzipped_mods := _load_mod_zips()
if unzipped_mods > 0:
ModLoaderLog.success("DONE: Loaded %s mod files into the virtual filesystem" % unzipped_mods, LOG_NAME)
else:
var zip_data := _load_mod_zips()

if zip_data.empty():
ModLoaderLog.info("No zipped mods found", LOG_NAME)
else:
ModLoaderLog.success("DONE: Loaded %s mod files into the virtual filesystem" % zip_data.size(), LOG_NAME)

# Initializes the mod_data dictionary if zipped mods are loaded.
# If mods are unpacked in the "mods-unpacked" directory,
# mod_data is initialized in the _setup_mods() function.
for mod_id in zip_data.keys():
var zip_path: String = zip_data[mod_id]
_init_mod_data(mod_id, zip_path)


# Loop over UNPACKED_DIR. This triggers _init_mod_data for each mod
# directory, which adds their data to mod_data.
Expand Down Expand Up @@ -219,19 +228,21 @@ func _check_autoload_positions() -> void:

# Loop over "res://mods" and add any mod zips to the unpacked virtual directory
# (UNPACKED_DIR)
func _load_mod_zips() -> int:
var zipped_mods_count := 0
func _load_mod_zips() -> Dictionary:
var zip_data := {}

if not ModLoaderStore.ml_options.steam_workshop_enabled:
var mods_folder_path := _ModLoaderPath.get_path_to_mods()

# If we're not using Steam workshop, just loop over the mod ZIPs.
zipped_mods_count += _ModLoaderFile.load_zips_in_folder(mods_folder_path)
var loaded_zip_data := _ModLoaderFile.load_zips_in_folder(mods_folder_path)
zip_data.merge(loaded_zip_data)
else:
# If we're using Steam workshop, loop over the workshop item directories
zipped_mods_count += _ModLoaderSteam.load_steam_workshop_zips()
var loaded_workshop_zip_data := _ModLoaderSteam.load_steam_workshop_zips()
zip_data.merge(loaded_workshop_zip_data)

return zipped_mods_count
return zip_data


# Loop over UNPACKED_DIR and triggers `_init_mod_data` for each mod directory,
Expand Down Expand Up @@ -271,8 +282,12 @@ func _setup_mods() -> int:
ModLoaderLog.info("Skipped setting up mod: \"%s\"" % mod_dir_name, LOG_NAME)
continue

# Init the mod data for each mod
_init_mod_data(mod_dir_name)
# Checks if there is no existing mod_data for this mod,
# indicating that the mod is loaded from UNPACKED_DIR
if not ModLoaderStore.mod_data.has(mod_dir_name):
# If there is no existing mod_data for this mod, initialize it now.
_init_mod_data(mod_dir_name)

unpacked_mods_count += 1

dir.list_dir_end()
Expand All @@ -282,19 +297,20 @@ func _setup_mods() -> int:
# Add a mod's data to mod_data.
# The mod_folder_path is just the folder name that was added to UNPACKED_DIR,
# which depends on the name used in a given mod ZIP (eg "mods-unpacked/Folder-Name")
func _init_mod_data(mod_folder_path: String) -> void:
# The file name should be a valid mod id
var dir_name := _ModLoaderPath.get_file_name_from_path(mod_folder_path, false, true)

# Path to the mod in UNPACKED_DIR (eg "res://mods-unpacked/My-Mod")
var local_mod_path := _ModLoaderPath.get_unpacked_mods_dir_path().plus_file(dir_name)

var mod := ModData.new(local_mod_path)
mod.dir_name = dir_name
func _init_mod_data(mod_id: String, zip_path := "") -> void:
# Path to the mod in UNPACKED_DIR (eg "res://mods-unpacked/My-Mod")
var local_mod_path := _ModLoaderPath.get_unpacked_mods_dir_path().plus_file(mod_id)

var mod := ModData.new()
if not zip_path.empty():
mod.zip_name = _ModLoaderPath.get_file_name_from_path(zip_path)
mod.zip_path = zip_path
mod.dir_path = local_mod_path
mod.dir_name = mod_id
var mod_overwrites_path := mod.get_optional_mod_file_path(ModData.optional_mod_files.OVERWRITES)
mod.is_overwrite = _ModLoaderFile.file_exists(mod_overwrites_path)
mod.is_locked = true if dir_name in ModLoaderStore.ml_options.locked_mods else false
ModLoaderStore.mod_data[dir_name] = mod
mod.is_locked = true if mod_id in ModLoaderStore.ml_options.locked_mods else false
ModLoaderStore.mod_data[mod_id] = mod

# Get the mod file paths
# Note: This was needed in the original version of this script, but it's
Expand Down
3 changes: 3 additions & 0 deletions addons/mod_loader/mod_loader_store.gd
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ var mod_missing_dependencies := {}
# Helps to decide whether a script extension should go through the _ModLoaderScriptExtension.handle_script_extensions() process
var is_initializing := true

# Used when loading mod zips to determine which mod zip corresponds to which mod directory in the UNPACKED_DIR.
var previous_mod_dirs := []

# Store all extenders paths
var script_extensions := []

Expand Down
8 changes: 4 additions & 4 deletions addons/mod_loader/resources/mod_data.gd
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ enum optional_mod_files {
OVERWRITES
}

# 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 Directory
Expand All @@ -47,10 +51,6 @@ var current_config: ModConfig setget _set_current_config
var file_paths: PoolStringArray = []


func _init(_dir_path: String) -> void:
dir_path = _dir_path


# Load meta data from a mod's manifest.json file
func load_manifest() -> void:
if not _has_required_files():
Expand Down

0 comments on commit 924f783

Please sign in to comment.