mod_hook_packer.gd 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. class_name _ModLoaderModHookPacker
  2. extends RefCounted
  3. # This class is used to generate mod hooks on demand and pack them into a zip file.
  4. # Currently all of the included functions are internal and should only be used by the mod loader itself.
  5. const LOG_NAME := "ModLoader:ModHookPacker"
  6. static func start() -> void:
  7. ModLoaderLog.info("Generating mod hooks .zip", LOG_NAME)
  8. var hook_pre_processor = _ModLoaderModHookPreProcessor.new()
  9. hook_pre_processor.process_begin()
  10. var mod_hook_pack_path := _ModLoaderPath.get_path_to_hook_pack()
  11. # Create mod hook pack path if necessary
  12. if not DirAccess.dir_exists_absolute(mod_hook_pack_path.get_base_dir()):
  13. var error := DirAccess.make_dir_recursive_absolute(mod_hook_pack_path.get_base_dir())
  14. if not error == OK:
  15. ModLoaderLog.error("Error creating the mod hook directory at %s" % mod_hook_pack_path, LOG_NAME)
  16. return
  17. ModLoaderLog.debug("Created dir at: %s" % mod_hook_pack_path, LOG_NAME)
  18. # Create mod hook zip
  19. var zip_writer := ZIPPacker.new()
  20. var error: Error
  21. if not FileAccess.file_exists(mod_hook_pack_path):
  22. # Clear cache if the hook pack does not exist
  23. _ModLoaderCache.remove_data("hooks")
  24. error = zip_writer.open(mod_hook_pack_path)
  25. else:
  26. # If there is a pack already, append to it
  27. error = zip_writer.open(mod_hook_pack_path, ZIPPacker.APPEND_ADDINZIP)
  28. if not error == OK:
  29. ModLoaderLog.error("Error (%s) writing to hooks zip, consider deleting this file: %s" % [error, mod_hook_pack_path], LOG_NAME)
  30. return
  31. ModLoaderLog.debug("Scripts requiring hooks: %s" % [ModLoaderStore.hooked_script_paths], LOG_NAME)
  32. var cache := _ModLoaderCache.get_data("hooks")
  33. var cached_script_paths: Dictionary = {} if cache.is_empty() or not cache.has("hooked_script_paths") else cache.hooked_script_paths
  34. if cached_script_paths == ModLoaderStore.hooked_script_paths:
  35. ModLoaderLog.info("Scripts are already processed according to cache, skipping process.", LOG_NAME)
  36. zip_writer.close()
  37. return
  38. var new_hooks_created := false
  39. # Get all scripts that need processing
  40. for path in ModLoaderStore.hooked_script_paths.keys():
  41. var method_mask: Array[String] = []
  42. method_mask.assign(ModLoaderStore.hooked_script_paths[path])
  43. var processed_source_code := hook_pre_processor.process_script_verbose(path, false, method_mask)
  44. # Skip writing to the zip if no new hooks were created for this script
  45. if not hook_pre_processor.script_paths_hooked.has(path):
  46. ModLoaderLog.debug("No new hooks were created in \"%s\", skipping writing to hook pack." % path, LOG_NAME)
  47. continue
  48. zip_writer.start_file(path.trim_prefix("res://"))
  49. zip_writer.write_file(processed_source_code.to_utf8_buffer())
  50. zip_writer.close_file()
  51. ModLoaderLog.debug("Hooks created for script: %s" % path, LOG_NAME)
  52. new_hooks_created = true
  53. if new_hooks_created:
  54. _ModLoaderCache.update_data("hooks", {"hooked_script_paths": ModLoaderStore.hooked_script_paths})
  55. _ModLoaderCache.save_to_file()
  56. ModLoader.new_hooks_created.emit()
  57. zip_writer.close()