basic ECS spawner

This commit is contained in:
2026-01-15 15:27:48 +01:00
parent 24a781f36a
commit eb737b469c
860 changed files with 58621 additions and 32 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018-2021 Will Nations
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,7 @@
[plugin]
name="Godot Plugin Refresher"
description="A toolbar addition to facilitate toggling off/on a selected plugin. Updated for Godot 4.3"
author="willnationsdev"
version="1.2"
script="plugin_refresher_plugin.gd"

View File

@@ -0,0 +1,73 @@
@tool
extends HBoxContainer
signal request_refresh_plugin(p_name: String)
signal confirm_refresh_plugin(p_name: String)
@onready var options: OptionButton = $OptionButton
func _ready() -> void:
if get_tree().edited_scene_root == self:
return # This is the scene opened in the editor!
$RefreshButton.icon = EditorInterface.get_editor_theme().get_icon("Reload", "EditorIcons")
func update_items(p_plugins_info: Array) -> void:
if not options:
return
options.clear()
var plugins := p_plugins_info[0] as Dictionary
var display_names_map := p_plugins_info[1] as Dictionary
var plugin_dirs: Array[String] = []
plugin_dirs.assign(plugins.keys())
for idx in plugin_dirs.size():
var plugin_dirname := plugin_dirs[idx]
var plugin_data = plugins[plugin_dirname] # Array[String] used as a Tuple<String, String>.
var plugin_name := plugin_data[0] as String
var plugin_path := plugin_data[1] as String
var display_name := display_names_map[plugin_path] as String
options.add_item(display_name, idx)
options.set_item_metadata(idx, plugin_path)
# Note: For whatever reason, statically typing `p_name` inexplicably causes
# an error about converting from Nil to String, even if the value is converted.
func select_plugin(p_name) -> void:
if not options or not p_name:
return
for idx in options.get_item_count():
var plugin := str(options.get_item_metadata(idx))
if plugin == str(p_name):
options.selected = options.get_item_id(idx)
break
func _on_RefreshButton_pressed() -> void:
if options.selected == -1:
return # nothing selected
var plugin := str(options.get_item_metadata(options.selected))
if not plugin:
return
emit_signal("request_refresh_plugin", plugin)
func show_warning(p_name: String) -> void:
$ConfirmationDialog.dialog_text = (
"""
Plugin `%s` is currently disabled.\n
Do you want to enable it now?
"""
% [p_name]
)
$ConfirmationDialog.popup_centered()
func _on_ConfirmationDialog_confirmed() -> void:
var plugin := options.get_item_metadata(options.selected) as String
emit_signal("confirm_refresh_plugin", plugin)

View File

@@ -0,0 +1 @@
uid://bf4gdvb18b3od

View File

@@ -0,0 +1,21 @@
[gd_scene load_steps=2 format=3 uid="uid://dnladpgp5dwts"]
[ext_resource type="Script" uid="uid://bf4gdvb18b3od" path="res://addons/godot-plugin-refresher/plugin_refresher.gd" id="1"]
[node name="HBoxContainer" type="HBoxContainer"]
script = ExtResource("1")
[node name="VSeparator" type="VSeparator" parent="."]
layout_mode = 2
[node name="OptionButton" type="OptionButton" parent="."]
layout_mode = 2
[node name="RefreshButton" type="Button" parent="."]
layout_mode = 2
[node name="ConfirmationDialog" type="ConfirmationDialog" parent="."]
dialog_autowrap = true
[connection signal="pressed" from="RefreshButton" to="." method="_on_RefreshButton_pressed"]
[connection signal="confirmed" from="ConfirmationDialog" to="." method="_on_ConfirmationDialog_confirmed"]

View File

@@ -0,0 +1,156 @@
@tool
extends EditorPlugin
const ADDONS_PATH := "res://addons/"
const PLUGIN_CONFIG_DIR := "plugins/plugin_refresher"
const PLUGIN_CONFIG := "settings.cfg"
const PLUGIN_NAME := "Godot Plugin Refresher"
const SETTINGS := "settings"
const SETTING_RECENT := "recently_used"
const Refresher := preload("plugin_refresher.gd")
var plugin_config := ConfigFile.new()
var refresher: Refresher = null
func _enter_tree() -> void:
refresher = preload("plugin_refresher.tscn").instantiate() as Refresher
add_control_to_container(CONTAINER_TOOLBAR, refresher)
# Watch whether any plugin is changed, added or removed on the filesystem
var efs := EditorInterface.get_resource_filesystem()
efs.filesystem_changed.connect(_on_filesystem_changed)
refresher.request_refresh_plugin.connect(_on_request_refresh_plugin)
refresher.confirm_refresh_plugin.connect(_on_confirm_refresh_plugin)
_reload_plugins_list()
_load_settings()
func _exit_tree() -> void:
remove_control_from_container(CONTAINER_TOOLBAR, refresher)
refresher.free()
func _reload_plugins_list() -> void:
var cfg_paths: Array[String] = []
var plugins := {}
var display_names_map := {} # full path to display name
find_cfgs(ADDONS_PATH, cfg_paths)
for cfg_path in cfg_paths:
var plugin_cfg := ConfigFile.new()
var err := plugin_cfg.load(cfg_path)
if err:
push_error("ERROR LOADING PLUGIN FILE: %s" % err)
else:
var plugin_name := plugin_cfg.get_value("plugin", "name")
if plugin_name != PLUGIN_NAME:
var addon_dir_name = cfg_path.split("addons/")[-1].split("/plugin.cfg")[0]
plugins[addon_dir_name] = [plugin_name, cfg_path]
# This will be an array of the addon/* directory names.
var plugin_dirs: Array[String] = []
plugin_dirs.assign(plugins.keys()) # typed array "casting"
var plugin_names: Array[String] = []
plugin_names.assign(plugin_dirs.map(func(k): return plugins[k][0]))
for plugin_dirname in plugin_dirs:
var plugin_name = plugins[plugin_dirname][0]
var display_name = plugin_name if plugin_names.count(plugin_name) == 1 else "%s (%s)" % [plugin_name, plugin_dirname]
display_names_map[plugins[plugin_dirname][1]] = display_name
refresher.update_items([plugins, display_names_map])
func find_cfgs(dir_path: String, cfgs: Array):
var dir := DirAccess.open(dir_path)
var cfg_path := dir_path.path_join("plugin.cfg")
if dir.file_exists(cfg_path):
cfgs.append(cfg_path)
return
if dir:
dir.list_dir_begin()
var file_name := dir.get_next()
while file_name != "":
if dir.current_is_dir():
find_cfgs(dir_path.path_join(file_name), cfgs)
file_name = dir.get_next()
func _load_settings() -> void:
var path := get_settings_path()
if not FileAccess.file_exists(path):
# Create new if running for the first time
var config := ConfigFile.new()
DirAccess.make_dir_recursive_absolute(path.get_base_dir())
config.save(path)
else:
plugin_config.load(path)
func _save_settings() -> void:
plugin_config.save(get_settings_path())
func get_settings_path() -> String:
var editor_paths := EditorInterface.get_editor_paths()
var dir := editor_paths.get_project_settings_dir()
var home := dir.path_join(PLUGIN_CONFIG_DIR)
var path := home.path_join(PLUGIN_CONFIG)
return path
func _on_filesystem_changed() -> void:
if refresher:
_reload_plugins_list()
var recent = get_recent_plugin()
if recent:
refresher.select_plugin(recent)
func get_recent_plugin() -> String:
if not plugin_config.has_section_key(SETTINGS, SETTING_RECENT):
return "" # not saved yet
var recent = str(plugin_config.get_value(SETTINGS, SETTING_RECENT))
return recent
func _on_request_refresh_plugin(p_path: String) -> void:
assert(not p_path.is_empty())
var disabled := not EditorInterface.is_plugin_enabled(p_path)
if disabled:
refresher.show_warning(p_path)
else:
refresh_plugin(p_path)
func _on_confirm_refresh_plugin(p_path: String) -> void:
refresh_plugin(p_path)
func get_plugin_path() -> String:
return get_script().resource_path.get_base_dir()
func refresh_plugin(p_path: String) -> void:
print("Refreshing plugin: ", p_path)
var enabled := EditorInterface.is_plugin_enabled(p_path)
if enabled: # can only disable an active plugin
EditorInterface.set_plugin_enabled(p_path, false)
EditorInterface.set_plugin_enabled(p_path, true)
plugin_config.set_value(SETTINGS, SETTING_RECENT, p_path)
_save_settings()

View File

@@ -0,0 +1 @@
uid://dg1pimj67d104