From 6261c7ee7625ed08f3f0ee8d17a6cbc6ed4ed5ac Mon Sep 17 00:00:00 2001 From: Iceflower Date: Sun, 1 Sep 2024 01:45:21 +0200 Subject: [PATCH 1/3] [plugin_reloader] Add plugin reloader --- README.md | 2 + .../plugin_reloader/internal/reloader.gd | 61 ++++++++++++++++++ .../plugin_reloader/internal/reloader.tscn | 21 ++++++ addons/kenyoni/plugin_reloader/plugin.cfg | 19 ++++++ addons/kenyoni/plugin_reloader/plugin.gd | 20 ++++++ doc/docs/addons/plugin_reloader.md | 20 ++++++ .../plugin_reloader/plugin_reloader.png | Bin 0 -> 44523 bytes project.godot | 2 +- 8 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 addons/kenyoni/plugin_reloader/internal/reloader.gd create mode 100644 addons/kenyoni/plugin_reloader/internal/reloader.tscn create mode 100644 addons/kenyoni/plugin_reloader/plugin.cfg create mode 100644 addons/kenyoni/plugin_reloader/plugin.gd create mode 100644 doc/docs/addons/plugin_reloader.md create mode 100644 doc/docs/addons/plugin_reloader/plugin_reloader.png diff --git a/README.md b/README.md index 4c62d48..9ba2854 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ If you import any plugin or open a Godot project for the first time, the plugins Manage license and copyright for third party graphics, software or libraries. - [Logging](https://kenyoni-software.github.io/godot-addons/addons/glogging) Simple logger. +- [Plugin Reloader](https://kenyoni-software.github.io/godot-addons/addons/plugin_reloader) + Enable or disable plugins from within the editor main screen. - [QR Code](https://kenyoni-software.github.io/godot-addons/addons/qr_code) QRCodeRect and QR Code generation. - [TextureButtonColored](https://kenyoni-software.github.io/godot-addons/addons/texture_button_colored) diff --git a/addons/kenyoni/plugin_reloader/internal/reloader.gd b/addons/kenyoni/plugin_reloader/internal/reloader.gd new file mode 100644 index 0000000..9b67310 --- /dev/null +++ b/addons/kenyoni/plugin_reloader/internal/reloader.gd @@ -0,0 +1,61 @@ +@tool +extends MarginContainer + +@export var _reload_button: CheckButton +@export var _option_button: OptionButton + +var _last_selection: String = "" + +func _ready() -> void: + self._option_button.item_selected.connect(func(idx: int) -> void: + self._last_selection = self._option_button.get_item_metadata(idx) + self._update_button_bar() + ) + self._reload_button.toggled.connect(func(toggled: bool) -> void: + EditorInterface.set_plugin_enabled("res://addons/" + self._last_selection + "/plugin.cfg", toggled) + self._reload_plugin_list() + ) + + EditorInterface.get_resource_filesystem().filesystem_changed.connect(self._reload_plugin_list) + self._reload_plugin_list() + +func _update_button_bar() -> void: + if self._last_selection != "": + self._reload_button.set_pressed_no_signal(EditorInterface.is_plugin_enabled("res://addons/" + self._last_selection + "/plugin.cfg")) + self._option_button.icon = null + self._reload_button.disabled = self._last_selection == "" + +func _reload_plugin_list() -> void: + self._option_button.clear() + for dir: String in DirAccess.get_directories_at("res://addons/"): + self._add_plugin_to_list(dir) + # subfolder + for sub_dir: String in DirAccess.get_directories_at("res://addons/" + dir): + self._add_plugin_to_list(dir + "/" + sub_dir) + + if self._last_selection == "" && self._option_button.get_item_count() > 0: + self._last_selection = self._option_button.get_item_metadata(0) + self._update_button_bar() + +func _add_plugin_to_list(plugin_id: String) -> void: + # ignore the current plugin + if plugin_id == "kenyoni/plugin_reloader": + return + + var cfg_path: String = "res://addons/" + plugin_id + "/plugin.cfg" + if !FileAccess.file_exists(cfg_path): + return + + var plugin_cfg: ConfigFile = ConfigFile.new() + plugin_cfg.load(cfg_path) + var plugin_name: String = plugin_cfg.get_value("plugin", "name", plugin_id) + self._option_button.add_item(plugin_name) + var idx: int = self._option_button.get_item_count() - 1 + self._option_button.set_item_metadata(idx, plugin_id) + self._option_button.set_item_tooltip(idx, "res://addons/" + plugin_id + "/") + if EditorInterface.is_plugin_enabled(cfg_path): + self._option_button.set_item_icon(idx, self.get_theme_icon(&"TileChecked", &"EditorIcons")) + else: + self._option_button.set_item_icon(idx, self.get_theme_icon(&"TileUnchecked", &"EditorIcons")) + if plugin_id == self._last_selection: + self._option_button.select(idx) diff --git a/addons/kenyoni/plugin_reloader/internal/reloader.tscn b/addons/kenyoni/plugin_reloader/internal/reloader.tscn new file mode 100644 index 0000000..44ebfbe --- /dev/null +++ b/addons/kenyoni/plugin_reloader/internal/reloader.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=2 format=3 uid="uid://dryoyuj4vl0l5"] + +[ext_resource type="Script" path="res://addons/kenyoni/plugin_reloader/internal/reloader.gd" id="1_kd7gg"] + +[node name="Reloader" type="MarginContainer" node_paths=PackedStringArray("_reload_button", "_option_button")] +offset_right = 76.0 +offset_bottom = 24.0 +script = ExtResource("1_kd7gg") +_reload_button = NodePath("HBoxContainer/reload_button") +_option_button = NodePath("HBoxContainer/OptionButton") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 +theme_override_constants/separation = 0 + +[node name="reload_button" type="CheckButton" parent="HBoxContainer"] +layout_mode = 2 + +[node name="OptionButton" type="OptionButton" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 diff --git a/addons/kenyoni/plugin_reloader/plugin.cfg b/addons/kenyoni/plugin_reloader/plugin.cfg new file mode 100644 index 0000000..78c4c44 --- /dev/null +++ b/addons/kenyoni/plugin_reloader/plugin.cfg @@ -0,0 +1,19 @@ +[plugin] + +name="Plugin Reloader" +description="Quickly reload plugins from the editor." +author="Kenyoni Software" +version="1.0.0" +script="plugin.gd" +license="MIT" +repository="https://github.com/kenyoni-software/godot-addons" +keywords=[ + "tool" +] +classifiers=[ + "Development Status :: 5 - Production/Stable", + "License :: OSI Approved :: MIT License" +] + +[plugin.dependencies] +godot=">=4.2" diff --git a/addons/kenyoni/plugin_reloader/plugin.gd b/addons/kenyoni/plugin_reloader/plugin.gd new file mode 100644 index 0000000..94fe541 --- /dev/null +++ b/addons/kenyoni/plugin_reloader/plugin.gd @@ -0,0 +1,20 @@ +@tool +extends EditorPlugin + +const ReloaderScene: PackedScene = preload("res://addons/kenyoni/plugin_reloader/internal/reloader.tscn") +const Reloader := preload("res://addons/kenyoni/plugin_reloader/internal/reloader.gd") + +var _reloader: Reloader + +func _get_plugin_name() -> String: + return "Plugin Reloader" + +func _enter_tree() -> void: + self._reloader = ReloaderScene.instantiate() + self.add_control_to_container(CustomControlContainer.CONTAINER_TOOLBAR, self._reloader) + # move before editor run bar + self._reloader.get_parent().move_child(self._reloader, self._reloader.get_parent().find_child("@EditorRunBar@*", true, false).get_index()) + +func _exit_tree() -> void: + self.remove_control_from_container(CustomControlContainer.CONTAINER_TOOLBAR, self._reloader) + self._reloader.queue_free() diff --git a/doc/docs/addons/plugin_reloader.md b/doc/docs/addons/plugin_reloader.md new file mode 100644 index 0000000..f6f82ca --- /dev/null +++ b/doc/docs/addons/plugin_reloader.md @@ -0,0 +1,20 @@ +# Plugin Reloader + +Enable or disable plugins from within the editor main screen. + +## Compatibility + +| Godot | Version | +|-------|----------| +| 4.3 | >= 1.0.0 | +| 4.2 | >= 1.0.0 | + +## Screenshot + +![plugin reloader screenshot](plugin_reloader/plugin_reloader.png "Plugin Reloader") + +## Changelog + +### 1.0.0 + +- Initial release diff --git a/doc/docs/addons/plugin_reloader/plugin_reloader.png b/doc/docs/addons/plugin_reloader/plugin_reloader.png new file mode 100644 index 0000000000000000000000000000000000000000..6a92d5c6334eb45cde63dab302e267270009e3c3 GIT binary patch literal 44523 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 Date: Sun, 1 Sep 2024 15:25:00 +0200 Subject: [PATCH 2/3] [ci] Support subfolder plugins --- .github/workflows/publish.yml | 26 +++++++++++++++++++++----- publisher/cli.go | 4 ++-- publisher/internal/addon.go | 10 +++++++++- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 654a13b..25ad962 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,51 +15,67 @@ jobs: config: - { id: "aspect_ratio_resize_container", + id-name: "aspect_ratio_resize_container", name: "AspectRatioResizeContainer", asset-id: "2089", } - { id: "custom_theme_overrides", + id-name: "custom_theme_overrides", name: "Custom Theme Overrides", asset-id: "2091", } - { id: "git_sha_project_setting", + id-name: "git_sha_project_setting", name: "Git SHA Project Setting", asset-id: "1979", } - { id: "glogging", + id-name: "glogging", name: "GLogging", asset-id: "no-deploy", } - { id: "hide_private_properties", + id-name: "hide_private_properties", name: "Hide Private Properties", asset-id: "1989", } - { id: "icon_explorer", + id-name: "icon_explorer", name: "Icon Explorer", asset-id: "2511", } - { id: "icons_patcher", + id-name: "icons_patcher", name: "Icons Patcher", asset-id: "1980", } - { id: "licenses", + id-name: "licenses", name: "License Manager", asset-id: "1969", } + - { + id: "kenyoni/plugin_reloader", + id-name: "plugin_reloader", + name: "Plugin Reloader", + asset-id: "no-deploy", + } - { id: "qr_code", + id-name: "qr_code", name: "QR Code", asset-id: "2090", } - { id: "texture_button_colored", + id-name: "texture_button_colored", name: "TextureButtonColored", asset-id: "2092", } @@ -92,20 +108,20 @@ jobs: uses: actions/upload-artifact@v3 with: name: ${{ matrix.config.name }} - path: archives/${{ matrix.config.id }}-*.zip + path: archives/${{ matrix.config.id-name }}-*.zip - uses: mukunku/tag-exists-action@v1.2.0 id: checkTag with: - tag: ${{ matrix.config.id }}-${{ steps.prepare-artifacts.outputs.version }} + tag: ${{ matrix.config.id-name }}-${{ steps.prepare-artifacts.outputs.version }} - name: Prepare Release if: ${{ steps.checkTag.outputs.exists == 'false' }} run: | git config user.name github-actions git config user.email github-actions@github.com - git tag ${{ matrix.config.id }}-${{ steps.prepare-artifacts.outputs.version }} - git push origin tag ${{ matrix.config.id }}-${{ steps.prepare-artifacts.outputs.version }} + git tag ${{ matrix.config.id-name }}-${{ steps.prepare-artifacts.outputs.version }} + git push origin tag ${{ matrix.config.id-name }}-${{ steps.prepare-artifacts.outputs.version }} # wait 5s that the pushed tag is available in the next step, sometimes the next step saw only the local tag - name: Wait 5s @@ -117,7 +133,7 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} run: | - gh release create ${{ matrix.config.id }}-${{ steps.prepare-artifacts.outputs.version }} ./archives/* --title "${{ matrix.config.name }} ${{ steps.prepare-artifacts.outputs.version }}" --notes "${{ steps.prepare-artifacts.outputs.notes }}" + gh release create ${{ matrix.config.id-name }}-${{ steps.prepare-artifacts.outputs.version }} ./archives/* --title "${{ matrix.config.name }} ${{ steps.prepare-artifacts.outputs.version }}" --notes "${{ steps.prepare-artifacts.outputs.notes }}" #- name: Deploy to Godot Asset Library # if: ${{ matrix.config.asset-id != 'no-deploy' }} diff --git a/publisher/cli.go b/publisher/cli.go index b5fd0de..d6d6938 100644 --- a/publisher/cli.go +++ b/publisher/cli.go @@ -181,7 +181,7 @@ func doActionAssetLibrary(baseDir string, addonId string, cfg assetLibraryAction assetData := internal.AssetData{ AssetId: cfg.AssetId, Title: plgCfg.Plugin.Name, - Description: fmt.Sprintf("%s\n\n%s", plgCfg.Plugin.Description, fmt.Sprintf("More detailed information and documentation is available at https://kenyoni-software.github.io/godot-addons/addons/%s", addon.Id())), + Description: fmt.Sprintf("%s\n\n%s", plgCfg.Plugin.Description, fmt.Sprintf("More detailed information and documentation is available at https://kenyoni-software.github.io/godot-addons/addons/%s", addon.IdName())), VersionString: plgCfg.Plugin.Version, GodotVersion: gdMinversion, CategoryId: cfg.Category, @@ -222,7 +222,7 @@ func doActionZip(baseDir string, addonId string, cfg zipActionCfg) { if outputDir == "" { outputDir = filepath.Join(addon.ProjectPath(), "archives") } - outputFile := filepath.Join(outputDir, addon.Id()+"-"+strings.ReplaceAll(plgCfg.Plugin.Version, ".", "_")+".zip") + outputFile := filepath.Join(outputDir, addon.IdName()+"-"+strings.ReplaceAll(plgCfg.Plugin.Version, ".", "_")+".zip") err = addon.Zip(outputFile) if err != nil { log.Fatalln(err) diff --git a/publisher/internal/addon.go b/publisher/internal/addon.go index 0e6daa3..cc67ef0 100644 --- a/publisher/internal/addon.go +++ b/publisher/internal/addon.go @@ -5,6 +5,7 @@ import ( "log" "os" "path/filepath" + "strings" "github.com/pelletier/go-toml/v2" ) @@ -39,10 +40,17 @@ func NewAddon(id string, projectPath string) *Addon { } } +// Id contains the namespace directory and the addon directory name like "kenyoni/addon_name" func (addon *Addon) Id() string { return addon.addonId } +// IdName is only the addon directory name like "addon_name" +func (addon *Addon) IdName() string { + splitted := strings.Split(addon.addonId, "/") + return splitted[len(splitted)-1] +} + func (addon *Addon) ProjectPath() string { return addon.projectPath } @@ -74,7 +82,7 @@ func (addon *Addon) Zip(outputFile string) error { if err != nil { return err } - exampleDir := filepath.Join(addon.ProjectPath(), "examples", addon.Id()) + exampleDir := filepath.Join(addon.ProjectPath(), "examples", addon.IdName()) // zip example directory only if it exists if _, err := os.Stat(exampleDir); err == nil { err = ZipDir(zw, exampleDir, filepath.Join("examples", addon.Id())) From c5abf12cdd847eac715f2ae4f35e42eb53fa732b Mon Sep 17 00:00:00 2001 From: Iceflower Date: Sun, 1 Sep 2024 15:36:14 +0200 Subject: [PATCH 3/3] [doc] Fix readme newline --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ba2854..7f5363e 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ If you import any plugin or open a Godot project for the first time, the plugins Manage license and copyright for third party graphics, software or libraries. - [Logging](https://kenyoni-software.github.io/godot-addons/addons/glogging) Simple logger. -- [Plugin Reloader](https://kenyoni-software.github.io/godot-addons/addons/plugin_reloader) +- [Plugin Reloader](https://kenyoni-software.github.io/godot-addons/addons/plugin_reloader) Enable or disable plugins from within the editor main screen. - [QR Code](https://kenyoni-software.github.io/godot-addons/addons/qr_code) QRCodeRect and QR Code generation.