mirror of
https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
synced 2025-10-22 15:38:14 +00:00
added the game
This commit is contained in:
163
addons/mod_loader/setup/global_script_class_cache_mod_loader.cfg
Normal file
163
addons/mod_loader/setup/global_script_class_cache_mod_loader.cfg
Normal file
@@ -0,0 +1,163 @@
|
||||
list=Array[Dictionary]([{
|
||||
"base": &"RefCounted",
|
||||
"class": &"JSONSchema",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/JSON_Schema_Validator/json_schema_validator.gd"
|
||||
}, {
|
||||
"base": &"Resource",
|
||||
"class": &"ModConfig",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/resources/mod_config.gd"
|
||||
}, {
|
||||
"base": &"Resource",
|
||||
"class": &"ModData",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/resources/mod_data.gd"
|
||||
}, {
|
||||
"base": &"Object",
|
||||
"class": &"ModLoaderConfig",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/api/config.gd"
|
||||
}, {
|
||||
"base": &"Resource",
|
||||
"class": &"ModLoaderCurrentOptions",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/resources/options_current.gd"
|
||||
}, {
|
||||
"base": &"Object",
|
||||
"class": &"ModLoaderDeprecated",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/api/deprecated.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"ModLoaderHookChain",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/api/hook_chain.gd"
|
||||
}, {
|
||||
"base": &"Object",
|
||||
"class": &"ModLoaderLog",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/api/log.gd"
|
||||
}, {
|
||||
"base": &"Object",
|
||||
"class": &"ModLoaderMod",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/api/mod.gd"
|
||||
}, {
|
||||
"base": &"Resource",
|
||||
"class": &"ModLoaderOptionsProfile",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/resources/options_profile.gd"
|
||||
}, {
|
||||
"base": &"Object",
|
||||
"class": &"ModLoaderUserProfile",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/api/profile.gd"
|
||||
}, {
|
||||
"base": &"Node",
|
||||
"class": &"ModLoaderUtils",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/mod_loader_utils.gd"
|
||||
}, {
|
||||
"base": &"Resource",
|
||||
"class": &"ModManifest",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/resources/mod_manifest.gd"
|
||||
}, {
|
||||
"base": &"Resource",
|
||||
"class": &"ModUserProfile",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/resources/mod_user_profile.gd"
|
||||
}, {
|
||||
"base": &"Node",
|
||||
"class": &"Utilities",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://tools/utilities.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"_ModLoaderCLI",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/cli.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"_ModLoaderCache",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/cache.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"_ModLoaderDependency",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/dependency.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"_ModLoaderFile",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/file.gd"
|
||||
}, {
|
||||
"base": &"Object",
|
||||
"class": &"_ModLoaderGodot",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/godot.gd"
|
||||
}, {
|
||||
"base": &"Object",
|
||||
"class": &"_ModLoaderHooks",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/hooks.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"_ModLoaderModHookPacker",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/mod_hook_packer.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"_ModLoaderModHookPreProcessor",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/mod_hook_preprocessor.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"_ModLoaderPath",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/path.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"_ModLoaderSceneExtension",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/scene_extension.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"_ModLoaderScriptExtension",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/script_extension.gd"
|
||||
}, {
|
||||
"base": &"Node",
|
||||
"class": &"_ModLoaderSteam",
|
||||
"icon": "",
|
||||
"language": &"GDScript",
|
||||
"path": "res://addons/mod_loader/internal/third_party/steam.gd"
|
||||
}])
|
209
addons/mod_loader/setup/setup_log.gd
Normal file
209
addons/mod_loader/setup/setup_log.gd
Normal file
@@ -0,0 +1,209 @@
|
||||
class_name ModLoaderSetupLog
|
||||
|
||||
|
||||
# Slimed down version of ModLoaderLog for the ModLoader Self Setup
|
||||
|
||||
const MOD_LOG_PATH := "user://logs/modloader.log"
|
||||
|
||||
enum VERBOSITY_LEVEL {
|
||||
ERROR,
|
||||
WARNING,
|
||||
INFO,
|
||||
DEBUG,
|
||||
}
|
||||
|
||||
|
||||
class ModLoaderLogEntry:
|
||||
extends Resource
|
||||
|
||||
var mod_name: String
|
||||
var message: String
|
||||
var type: String
|
||||
var time: String
|
||||
|
||||
|
||||
func _init(_mod_name: String, _message: String, _type: String, _time: String) -> void:
|
||||
mod_name = _mod_name
|
||||
message = _message
|
||||
type = _type
|
||||
time = _time
|
||||
|
||||
|
||||
func get_entry() -> String:
|
||||
return time + get_prefix() + message
|
||||
|
||||
|
||||
func get_prefix() -> String:
|
||||
return "%s %s: " % [type.to_upper(), mod_name]
|
||||
|
||||
|
||||
func get_md5() -> String:
|
||||
return str(get_prefix(), message).md5_text()
|
||||
|
||||
|
||||
# API log functions
|
||||
# =============================================================================
|
||||
|
||||
# Logs the error in red and a stack trace. Prefixed FATAL-ERROR
|
||||
# Stops the execution in editor
|
||||
# Always logged
|
||||
static func fatal(message: String, mod_name: String) -> void:
|
||||
_log(message, mod_name, "fatal-error")
|
||||
|
||||
|
||||
# Logs the message and pushed an error. Prefixed ERROR
|
||||
# Always logged
|
||||
static func error(message: String, mod_name: String) -> void:
|
||||
_log(message, mod_name, "error")
|
||||
|
||||
|
||||
# Logs the message and pushes a warning. Prefixed WARNING
|
||||
# Logged with verbosity level at or above warning (-v)
|
||||
static func warning(message: String, mod_name: String) -> void:
|
||||
_log(message, mod_name, "warning")
|
||||
|
||||
|
||||
# Logs the message. Prefixed INFO
|
||||
# Logged with verbosity level at or above info (-vv)
|
||||
static func info(message: String, mod_name: String) -> void:
|
||||
_log(message, mod_name, "info")
|
||||
|
||||
|
||||
# Logs the message. Prefixed SUCCESS
|
||||
# Logged with verbosity level at or above info (-vv)
|
||||
static func success(message: String, mod_name: String) -> void:
|
||||
_log(message, mod_name, "success")
|
||||
|
||||
|
||||
# Logs the message. Prefixed DEBUG
|
||||
# Logged with verbosity level at or above debug (-vvv)
|
||||
static func debug(message: String, mod_name: String) -> void:
|
||||
_log(message, mod_name, "debug")
|
||||
|
||||
|
||||
# Logs the message formatted with [method JSON.print]. Prefixed DEBUG
|
||||
# Logged with verbosity level at or above debug (-vvv)
|
||||
static func debug_json_print(message: String, json_printable, mod_name: String) -> void:
|
||||
message = "%s\n%s" % [message, JSON.stringify(json_printable, " ")]
|
||||
_log(message, mod_name, "debug")
|
||||
|
||||
|
||||
# Internal log functions
|
||||
# =============================================================================
|
||||
|
||||
static func _log(message: String, mod_name: String, log_type: String = "info") -> void:
|
||||
var time := "%s " % _get_time_string()
|
||||
var log_entry := ModLoaderLogEntry.new(mod_name, message, log_type, time)
|
||||
|
||||
match log_type.to_lower():
|
||||
"fatal-error":
|
||||
push_error(message)
|
||||
_write_to_log_file(log_entry.get_entry())
|
||||
_write_to_log_file(JSON.stringify(get_stack(), " "))
|
||||
assert(false, message)
|
||||
"error":
|
||||
printerr(message)
|
||||
push_error(message)
|
||||
_write_to_log_file(log_entry.get_entry())
|
||||
"warning":
|
||||
print(log_entry.get_prefix() + message)
|
||||
push_warning(message)
|
||||
_write_to_log_file(log_entry.get_entry())
|
||||
"info", "success":
|
||||
print(log_entry.get_prefix() + message)
|
||||
_write_to_log_file(log_entry.get_entry())
|
||||
"debug":
|
||||
print(log_entry.get_prefix() + message)
|
||||
_write_to_log_file(log_entry.get_entry())
|
||||
|
||||
|
||||
# Internal Date Time
|
||||
# =============================================================================
|
||||
|
||||
# Returns the current time as a string in the format hh:mm:ss
|
||||
static func _get_time_string() -> String:
|
||||
var date_time := Time.get_datetime_dict_from_system()
|
||||
return "%02d:%02d:%02d" % [ date_time.hour, date_time.minute, date_time.second ]
|
||||
|
||||
|
||||
# Returns the current date as a string in the format yyyy-mm-dd
|
||||
static func _get_date_string() -> String:
|
||||
var date_time := Time.get_datetime_dict_from_system()
|
||||
return "%s-%02d-%02d" % [ date_time.year, date_time.month, date_time.day ]
|
||||
|
||||
|
||||
# Returns the current date and time as a string in the format yyyy-mm-dd_hh:mm:ss
|
||||
static func _get_date_time_string() -> String:
|
||||
return "%s_%s" % [ _get_date_string(), _get_time_string() ]
|
||||
|
||||
|
||||
# Internal File
|
||||
# =============================================================================
|
||||
|
||||
static func _write_to_log_file(string_to_write: String) -> void:
|
||||
if not FileAccess.file_exists(MOD_LOG_PATH):
|
||||
_rotate_log_file()
|
||||
|
||||
var log_file := FileAccess.open(MOD_LOG_PATH, FileAccess.READ_WRITE)
|
||||
|
||||
if log_file == null:
|
||||
assert(false, "Could not open log file, error code: %s" % error)
|
||||
return
|
||||
|
||||
log_file.seek_end()
|
||||
log_file.store_string("\n" + string_to_write)
|
||||
log_file.close()
|
||||
|
||||
|
||||
# Keeps log backups for every run, just like the Godot; gdscript implementation of
|
||||
# https://github.com/godotengine/godot/blob/1d14c054a12dacdc193b589e4afb0ef319ee2aae/core/io/logger.cpp#L151
|
||||
static func _rotate_log_file() -> void:
|
||||
var MAX_LOGS: int = ProjectSettings.get_setting("debug/file_logging/max_log_files")
|
||||
|
||||
if FileAccess.file_exists(MOD_LOG_PATH):
|
||||
if MAX_LOGS > 1:
|
||||
var datetime := _get_date_time_string().replace(":", ".")
|
||||
var backup_name: String = MOD_LOG_PATH.get_basename() + "_" + datetime
|
||||
if MOD_LOG_PATH.get_extension().length() > 0:
|
||||
backup_name += "." + MOD_LOG_PATH.get_extension()
|
||||
|
||||
var dir := DirAccess.open(MOD_LOG_PATH.get_base_dir())
|
||||
if not dir == null:
|
||||
dir.copy(MOD_LOG_PATH, backup_name)
|
||||
_clear_old_log_backups()
|
||||
|
||||
# only File.WRITE creates a new file, File.READ_WRITE throws an error
|
||||
var log_file := FileAccess.open(MOD_LOG_PATH, FileAccess.WRITE)
|
||||
if log_file == null:
|
||||
assert(false, "Could not open log file, error code: %s" % error)
|
||||
log_file.store_string('%s Created log' % _get_date_string())
|
||||
log_file.close()
|
||||
|
||||
|
||||
static func _clear_old_log_backups() -> void:
|
||||
var MAX_LOGS := int(ProjectSettings.get_setting("debug/file_logging/max_log_files"))
|
||||
var MAX_BACKUPS := MAX_LOGS - 1 # -1 for the current new log (not a backup)
|
||||
var basename := MOD_LOG_PATH.get_file().get_basename() as String
|
||||
var extension := MOD_LOG_PATH.get_extension() as String
|
||||
|
||||
var dir := DirAccess.open(MOD_LOG_PATH.get_base_dir())
|
||||
if dir == null:
|
||||
return
|
||||
|
||||
dir.list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547
|
||||
var file := dir.get_next()
|
||||
var backups := []
|
||||
while file.length() > 0:
|
||||
if (not dir.current_is_dir() and
|
||||
file.begins_with(basename) and
|
||||
file.get_extension() == extension and
|
||||
not file == MOD_LOG_PATH.get_file()):
|
||||
backups.append(file)
|
||||
file = dir.get_next()
|
||||
dir.list_dir_end()
|
||||
|
||||
if backups.size() > MAX_BACKUPS:
|
||||
backups.sort()
|
||||
backups.resize(backups.size() - MAX_BACKUPS)
|
||||
for file_to_delete in backups:
|
||||
dir.remove(file_to_delete)
|
1
addons/mod_loader/setup/setup_log.gd.uid
Normal file
1
addons/mod_loader/setup/setup_log.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://djchjoj06bcko
|
286
addons/mod_loader/setup/setup_utils.gd
Normal file
286
addons/mod_loader/setup/setup_utils.gd
Normal file
@@ -0,0 +1,286 @@
|
||||
class_name ModLoaderSetupUtils
|
||||
|
||||
|
||||
# Slimed down version of ModLoaderUtils for the ModLoader Self Setup
|
||||
|
||||
const LOG_NAME := "ModLoader:SetupUtils"
|
||||
|
||||
|
||||
static var ModLoaderSetupLog: Object = load("res://addons/mod_loader/setup/setup_log.gd")
|
||||
|
||||
|
||||
# Get the path to a local folder. Primarily used to get the (packed) mods
|
||||
# folder, ie "res://mods" or the OS's equivalent, as well as the configs path
|
||||
static func get_local_folder_dir(subfolder: String = "") -> String:
|
||||
var game_install_directory := OS.get_executable_path().get_base_dir()
|
||||
|
||||
if OS.get_name() == "macOS":
|
||||
game_install_directory = game_install_directory.get_base_dir().get_base_dir()
|
||||
|
||||
# Fix for running the game through the Godot editor (as the EXE path would be
|
||||
# the editor's own EXE, which won't have any mod ZIPs)
|
||||
# if OS.is_debug_build():
|
||||
if OS.has_feature("editor"):
|
||||
game_install_directory = "res://"
|
||||
|
||||
return game_install_directory.path_join(subfolder)
|
||||
|
||||
|
||||
# Provide a path, get the file name at the end of the path
|
||||
static func get_file_name_from_path(path: String, make_lower_case := true, remove_extension := false) -> String:
|
||||
var file_name := path.get_file()
|
||||
|
||||
if make_lower_case:
|
||||
file_name = file_name.to_lower()
|
||||
|
||||
if remove_extension:
|
||||
file_name = file_name.trim_suffix("." + file_name.get_extension())
|
||||
|
||||
return file_name
|
||||
|
||||
|
||||
# Get an array of all autoloads -> ["autoload/AutoloadName", ...]
|
||||
static func get_autoload_array() -> Array:
|
||||
var autoloads := []
|
||||
|
||||
# Get all autoload settings
|
||||
for prop in ProjectSettings.get_property_list():
|
||||
var name: String = prop.name
|
||||
if name.begins_with("autoload/"):
|
||||
autoloads.append(name.trim_prefix("autoload/"))
|
||||
|
||||
return autoloads
|
||||
|
||||
|
||||
# Get the index of a specific autoload
|
||||
static func get_autoload_index(autoload_name: String) -> int:
|
||||
var autoloads := get_autoload_array()
|
||||
var autoload_index := autoloads.find(autoload_name)
|
||||
|
||||
return autoload_index
|
||||
|
||||
|
||||
# Get the path where override.cfg will be stored.
|
||||
# Not the same as the local folder dir (for mac)
|
||||
static func get_override_path() -> String:
|
||||
var base_path := ""
|
||||
if OS.has_feature("editor"):
|
||||
base_path = ProjectSettings.globalize_path("res://")
|
||||
else:
|
||||
# this is technically different to res:// in macos, but we want the
|
||||
# executable dir anyway, so it is exactly what we need
|
||||
base_path = OS.get_executable_path().get_base_dir()
|
||||
|
||||
return base_path.path_join("override.cfg")
|
||||
|
||||
|
||||
# Register an array of classes to the global scope, since Godot only does that in the editor.
|
||||
static func register_global_classes_from_array(new_global_classes: Array) -> void:
|
||||
var registered_classes: Array = ProjectSettings.get_setting("_global_script_classes")
|
||||
var registered_class_icons: Dictionary = ProjectSettings.get_setting("_global_script_class_icons")
|
||||
|
||||
for new_class in new_global_classes:
|
||||
if not _is_valid_global_class_dict(new_class):
|
||||
continue
|
||||
for old_class in registered_classes:
|
||||
if old_class.class == new_class.class:
|
||||
if OS.has_feature("editor"):
|
||||
ModLoaderSetupLog.info('Class "%s" to be registered as global was already registered by the editor. Skipping.' % new_class.class, LOG_NAME)
|
||||
else:
|
||||
ModLoaderSetupLog.info('Class "%s" to be registered as global already exists. Skipping.' % new_class.class, LOG_NAME)
|
||||
continue
|
||||
|
||||
registered_classes.append(new_class)
|
||||
registered_class_icons[new_class.class] = "" # empty icon, does not matter
|
||||
|
||||
ProjectSettings.set_setting("_global_script_classes", registered_classes)
|
||||
ProjectSettings.set_setting("_global_script_class_icons", registered_class_icons)
|
||||
|
||||
|
||||
# Checks if all required fields are in the given [Dictionary]
|
||||
# Format: { "base": "ParentClass", "class": "ClassName", "language": "GDScript", "path": "res://path/class_name.gd" }
|
||||
static func _is_valid_global_class_dict(global_class_dict: Dictionary) -> bool:
|
||||
var required_fields := ["base", "class", "language", "path"]
|
||||
if not global_class_dict.has_all(required_fields):
|
||||
ModLoaderSetupLog.fatal("Global class to be registered is missing one of %s" % required_fields, LOG_NAME)
|
||||
return false
|
||||
|
||||
if not FileAccess.file_exists(global_class_dict.path):
|
||||
ModLoaderSetupLog.fatal('Class "%s" to be registered as global could not be found at given path "%s"' %
|
||||
[global_class_dict.class, global_class_dict.path], LOG_NAME)
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
# Check if the provided command line argument was present when launching the game
|
||||
static func is_running_with_command_line_arg(argument: String) -> bool:
|
||||
for arg in OS.get_cmdline_args():
|
||||
if argument == arg.split("=")[0]:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
# Get the command line argument value if present when launching the game
|
||||
static func get_cmd_line_arg_value(argument: String) -> String:
|
||||
var args := _get_fixed_cmdline_args()
|
||||
|
||||
for arg_index in args.size():
|
||||
var arg := args[arg_index] as String
|
||||
|
||||
var key := arg.split("=")[0]
|
||||
if key == argument:
|
||||
# format: `--arg=value` or `--arg="value"`
|
||||
if "=" in arg:
|
||||
var value := arg.trim_prefix(argument + "=")
|
||||
value = value.trim_prefix('"').trim_suffix('"')
|
||||
value = value.trim_prefix("'").trim_suffix("'")
|
||||
return value
|
||||
|
||||
# format: `--arg value` or `--arg "value"`
|
||||
elif arg_index +1 < args.size() and not args[arg_index +1].begins_with("--"):
|
||||
return args[arg_index + 1]
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
static func _get_fixed_cmdline_args() -> PackedStringArray:
|
||||
return fix_godot_cmdline_args_string_space_splitting(OS.get_cmdline_args())
|
||||
|
||||
|
||||
# Reverses a bug in Godot, which splits input strings at spaces even if they are quoted
|
||||
# e.g. `--arg="some value" --arg-two 'more value'` becomes `[ --arg="some, value", --arg-two, 'more, value' ]`
|
||||
static func fix_godot_cmdline_args_string_space_splitting(args: PackedStringArray) -> PackedStringArray:
|
||||
if not OS.has_feature("editor"): # only happens in editor builds
|
||||
return args
|
||||
if OS.has_feature("windows"): # windows is unaffected
|
||||
return args
|
||||
|
||||
var fixed_args := PackedStringArray([])
|
||||
var fixed_arg := ""
|
||||
# if we encounter an argument that contains `=` followed by a quote,
|
||||
# or an argument that starts with a quote, take all following args and
|
||||
# concatenate them into one, until we find the closing quote
|
||||
for arg in args:
|
||||
var arg_string := arg as String
|
||||
if '="' in arg_string or '="' in fixed_arg or \
|
||||
arg_string.begins_with('"') or fixed_arg.begins_with('"'):
|
||||
if not fixed_arg == "":
|
||||
fixed_arg += " "
|
||||
fixed_arg += arg_string
|
||||
if arg_string.ends_with('"'):
|
||||
fixed_args.append(fixed_arg.trim_prefix(" "))
|
||||
fixed_arg = ""
|
||||
continue
|
||||
# same thing for single quotes
|
||||
elif "='" in arg_string or "='" in fixed_arg \
|
||||
or arg_string.begins_with("'") or fixed_arg.begins_with("'"):
|
||||
if not fixed_arg == "":
|
||||
fixed_arg += " "
|
||||
fixed_arg += arg_string
|
||||
if arg_string.ends_with("'"):
|
||||
fixed_args.append(fixed_arg.trim_prefix(" "))
|
||||
fixed_arg = ""
|
||||
continue
|
||||
|
||||
else:
|
||||
fixed_args.append(arg_string)
|
||||
|
||||
return fixed_args
|
||||
|
||||
|
||||
# Slightly modified version of:
|
||||
# https://gist.github.com/willnationsdev/00d97aa8339138fd7ef0d6bd42748f6e
|
||||
# Removed .import from the extension filter.
|
||||
# p_match is a string that filters the list of files.
|
||||
# If p_match_is_regex is false, p_match is directly string-searched against the FILENAME.
|
||||
# If it is true, a regex object compiles p_match and runs it against the FILEPATH.
|
||||
static func get_flat_view_dict(
|
||||
p_dir := "res://",
|
||||
p_match := "",
|
||||
p_match_file_extensions: Array[StringName] = [],
|
||||
p_match_is_regex := false,
|
||||
include_empty_dirs := false,
|
||||
ignored_dirs: Array[StringName] = []
|
||||
) -> PackedStringArray:
|
||||
var data: PackedStringArray = []
|
||||
var regex: RegEx
|
||||
|
||||
if p_match_is_regex:
|
||||
regex = RegEx.new()
|
||||
var _compile_error: int = regex.compile(p_match)
|
||||
if not regex.is_valid():
|
||||
return data
|
||||
|
||||
var dirs := [p_dir]
|
||||
var first := true
|
||||
while not dirs.is_empty():
|
||||
var dir_name : String = dirs.back()
|
||||
var dir := DirAccess.open(dir_name)
|
||||
dirs.pop_back()
|
||||
|
||||
if dir_name.lstrip("res://").get_slice("/", 0) in ignored_dirs:
|
||||
continue
|
||||
|
||||
if dir:
|
||||
var _dirlist_error: int = dir.list_dir_begin()
|
||||
var file_name := dir.get_next()
|
||||
if include_empty_dirs and not dir_name == p_dir:
|
||||
data.append(dir_name)
|
||||
while file_name != "":
|
||||
if not dir_name == "res://":
|
||||
first = false
|
||||
# ignore hidden, temporary, or system content
|
||||
if not file_name.begins_with(".") and not file_name.get_extension() == "tmp":
|
||||
# If a directory, then add to list of directories to visit
|
||||
if dir.current_is_dir():
|
||||
dirs.push_back(dir.get_current_dir() + "/" + file_name)
|
||||
# If a file, check if we already have a record for the same name
|
||||
else:
|
||||
var path := dir.get_current_dir() + ("/" if not first else "") + file_name
|
||||
# grab all
|
||||
if not p_match and not p_match_file_extensions:
|
||||
data.append(path)
|
||||
# grab matching strings
|
||||
elif not p_match_is_regex and p_match and file_name.contains(p_match):
|
||||
data.append(path)
|
||||
# garb matching file extension
|
||||
elif p_match_file_extensions and file_name.get_extension() in p_match_file_extensions:
|
||||
data.append(path)
|
||||
# grab matching regex
|
||||
elif p_match_is_regex:
|
||||
var regex_match := regex.search(path)
|
||||
if regex_match != null:
|
||||
data.append(path)
|
||||
# Move on to the next file in this directory
|
||||
file_name = dir.get_next()
|
||||
# We've exhausted all files in this directory. Close the iterator.
|
||||
dir.list_dir_end()
|
||||
return data
|
||||
|
||||
|
||||
static func copy_file(from: String, to: String) -> void:
|
||||
ModLoaderSetupLog.debug("Copy file from: \"%s\" to: \"%s\"" % [from, to], LOG_NAME)
|
||||
var global_to_path := ProjectSettings.globalize_path(to.get_base_dir())
|
||||
|
||||
if not DirAccess.dir_exists_absolute(global_to_path):
|
||||
ModLoaderSetupLog.debug("Creating dir \"%s\"" % global_to_path, LOG_NAME)
|
||||
DirAccess.make_dir_recursive_absolute(global_to_path)
|
||||
|
||||
var file_from := FileAccess.open(from, FileAccess.READ)
|
||||
var file_from_error := file_from.get_error()
|
||||
|
||||
if not file_from_error == OK:
|
||||
ModLoaderSetupLog.error("Error accessing file \"%s\": %s" % [from, error_string(file_from_error)], LOG_NAME)
|
||||
return
|
||||
|
||||
var file_from_content := file_from.get_buffer(file_from.get_length())
|
||||
var file_to := FileAccess.open(to, FileAccess.WRITE)
|
||||
var file_to_error := file_to.get_error()
|
||||
|
||||
if not file_to_error == OK:
|
||||
ModLoaderSetupLog.error("Error writing file \"%s\": %s" % [to, error_string(file_to_error)], LOG_NAME)
|
||||
return
|
||||
|
||||
file_to.store_buffer(file_from_content)
|
1
addons/mod_loader/setup/setup_utils.gd.uid
Normal file
1
addons/mod_loader/setup/setup_utils.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://2tin8kqukljx
|
Reference in New Issue
Block a user