|  | 
| 1 |  | -extends Node | 
|  | 1 | +class_name _ModLoaderModHookPacker | 
|  | 2 | +extends RefCounted | 
| 2 | 3 | 
 | 
| 3 | 4 | 
 | 
| 4 |  | -const ModHookPreprocessorScript = preload("res://addons/mod_loader/internal/mod_hook_preprocessor.gd") | 
| 5 |  | -static var ModHookPreprocessor | 
|  | 5 | +# This class is used to generate mod hooks on demand and pack them into a zip file. | 
|  | 6 | +# Currently all of the included functions are internal and should only be used by the mod loader itself. | 
| 6 | 7 | 
 | 
|  | 8 | +const LOG_NAME := "ModLoader:ModHookPacker" | 
| 7 | 9 | 
 | 
| 8 |  | -func _ready() -> void: | 
| 9 |  | -	run_script() | 
| 10 |  | -	await get_tree().process_frame | 
| 11 |  | -	get_tree().quit() | 
| 12 | 10 | 
 | 
|  | 11 | +static func start() -> void: | 
|  | 12 | +	var hook_pre_processor = _ModLoaderModHookPreProcessor.new() | 
|  | 13 | +	hook_pre_processor.process_begin() | 
| 13 | 14 | 
 | 
| 14 |  | -func run_script() -> void: | 
| 15 |  | -	ModHookPreprocessor = ModHookPreprocessorScript.new() | 
| 16 |  | -	ModHookPreprocessor.process_begin() | 
|  | 15 | +	var mod_hook_pack_path := _ModLoaderPath.get_path_to_hook_pack() | 
| 17 | 16 | 
 | 
| 18 |  | -	# TODO: consider mac location | 
| 19 |  | -	var res := OS.get_executable_path().get_base_dir() | 
| 20 |  | -	if OS.has_feature("editor"): | 
| 21 |  | -		res = ProjectSettings.globalize_path("res://").rsplit("/", true, 2)[0] | 
| 22 |  | - | 
| 23 |  | -	var save_base_path := res.path_join("godot_mod_loader/") | 
| 24 |  | -	prints("Saved to:", save_base_path) | 
| 25 |  | -	DirAccess.make_dir_recursive_absolute(save_base_path) | 
|  | 17 | +	# Create mod hook pack path if necessary | 
|  | 18 | +	if not DirAccess.dir_exists_absolute(mod_hook_pack_path.get_base_dir()): | 
|  | 19 | +		var error := DirAccess.make_dir_recursive_absolute(mod_hook_pack_path.get_base_dir()) | 
|  | 20 | +		if not error == OK: | 
|  | 21 | +			ModLoaderLog.error("Error creating the mod hook directory at %s" % mod_hook_pack_path, LOG_NAME) | 
|  | 22 | +			return | 
|  | 23 | +		ModLoaderLog.debug("Created dir at: %s" % mod_hook_pack_path, LOG_NAME) | 
| 26 | 24 | 
 | 
|  | 25 | +	# Create mod hook zip | 
| 27 | 26 | 	var zip_writer := ZIPPacker.new() | 
| 28 |  | -	var err := zip_writer.open(save_base_path.path_join("temp_test_mod.zip")) | 
| 29 |  | -	if err != OK: | 
| 30 |  | -		printerr(err) | 
| 31 |  | - | 
| 32 |  | -	transform_scripts_recursive(ModHookPreprocessor.process_script, zip_writer) | 
| 33 |  | - | 
| 34 |  | -	zip_writer.close() | 
| 35 |  | - | 
| 36 |  | - | 
| 37 |  | -func transform_scripts_recursive(callback: Callable, zip_writer: ZIPPacker, path := "res://") -> void: | 
| 38 |  | -	var dir := DirAccess.open(path) | 
| 39 |  | -	if not dir: | 
| 40 |  | -		printt("An error occurred when trying to access the path:", path) | 
|  | 27 | +	var error: Error | 
|  | 28 | + | 
|  | 29 | +	if not FileAccess.file_exists(mod_hook_pack_path): | 
|  | 30 | +		# Clear cache if the hook pack does not exist | 
|  | 31 | +		_ModLoaderCache.remove_data("hooks") | 
|  | 32 | +		error = zip_writer.open(mod_hook_pack_path) | 
|  | 33 | +	else: | 
|  | 34 | +		# If there is a pack already append to it | 
|  | 35 | +		error = zip_writer.open(mod_hook_pack_path, ZIPPacker.APPEND_ADDINZIP) | 
|  | 36 | +	if not error == OK: | 
|  | 37 | +		ModLoaderLog.error("Error(%s) writing to zip file at path: %s" % [error, mod_hook_pack_path], LOG_NAME) | 
| 41 | 38 | 		return | 
| 42 | 39 | 
 | 
| 43 |  | -	dir.list_dir_begin() | 
| 44 |  | -	var file_name = dir.get_next() | 
| 45 |  | -	while file_name != "": | 
| 46 |  | -		if path.begins_with("res://addons") or path.begins_with("res://mods-unpacked"): | 
| 47 |  | -			file_name = dir.get_next() | 
| 48 |  | -			continue | 
|  | 40 | +	var cache := _ModLoaderCache.get_data("hooks") | 
|  | 41 | +	var script_paths_with_hook: Array = [] if cache.is_empty() else cache.script_paths | 
|  | 42 | +	var new_hooks_created := false | 
| 49 | 43 | 
 | 
| 50 |  | -		if dir.current_is_dir(): | 
| 51 |  | -			transform_scripts_recursive(callback, zip_writer, dir.get_current_dir() + file_name + "/") | 
| 52 |  | -			file_name = dir.get_next() | 
|  | 44 | +	# Get all scripts that need processing | 
|  | 45 | +	ModLoaderLog.debug("Scripts requiring hooks: %s" % [ModLoaderStore.hooked_script_paths.keys()], LOG_NAME) | 
|  | 46 | +	for path in ModLoaderStore.hooked_script_paths.keys(): | 
|  | 47 | +		if path in script_paths_with_hook: | 
| 53 | 48 | 			continue | 
| 54 | 49 | 
 | 
| 55 |  | -		if file_name.get_extension() != "gd": | 
| 56 |  | -			file_name = dir.get_next() | 
| 57 |  | -			continue | 
|  | 50 | +		var processed_source_code := hook_pre_processor.process_script(path) | 
| 58 | 51 | 
 | 
| 59 |  | -		var processed: String = callback.call(dir.get_current_dir() + file_name) | 
| 60 |  | -		zip_writer.start_file(path.trim_prefix("res://").path_join(file_name)) | 
| 61 |  | -		zip_writer.write_file(processed.to_utf8_buffer()) | 
|  | 52 | +		zip_writer.start_file(path.trim_prefix("res://")) | 
|  | 53 | +		zip_writer.write_file(processed_source_code.to_utf8_buffer()) | 
| 62 | 54 | 		zip_writer.close_file() | 
| 63 | 55 | 
 | 
| 64 |  | -		file_name = dir.get_next() | 
|  | 56 | +		ModLoaderLog.debug("Hooks created for script: %s" % path, LOG_NAME) | 
|  | 57 | +		new_hooks_created = true | 
|  | 58 | +		script_paths_with_hook.push_back(path) | 
|  | 59 | + | 
|  | 60 | +	if new_hooks_created: | 
|  | 61 | +		_ModLoaderCache.update_data("hooks", {"script_paths": script_paths_with_hook}) | 
|  | 62 | +		_ModLoaderCache.save_to_file() | 
|  | 63 | +		ModLoader.new_hooks_created.emit() | 
|  | 64 | + | 
|  | 65 | +	zip_writer.close() | 
0 commit comments