gd: added menu template
This commit is contained in:
@ -0,0 +1,76 @@
|
||||
@tool
|
||||
extends Node
|
||||
|
||||
signal new_version_detected(version: String)
|
||||
signal versions_matched
|
||||
signal failed
|
||||
|
||||
const API_RELEASES_URL := "https://api.github.com/repos/%s/%s/releases"
|
||||
|
||||
@export var plugin_directory : String
|
||||
@export var plugin_github_url : String :
|
||||
set(value):
|
||||
plugin_github_url = value
|
||||
_update_urls()
|
||||
@export_group("Advanced")
|
||||
@export var auto_start : bool = false
|
||||
@export var default_version : String = "0.0.0"
|
||||
@export var replace_tag_name : String = "v"
|
||||
@export var _test_action : bool = false :
|
||||
set(value):
|
||||
if value and Engine.is_editor_hint():
|
||||
compare_versions()
|
||||
|
||||
@onready var _api_client : APIClient = $APIClient
|
||||
|
||||
var _zipball_url : String
|
||||
|
||||
func get_plugin_version() -> String :
|
||||
if not plugin_directory.is_empty():
|
||||
for enabled_plugin in ProjectSettings.get_setting("editor_plugins/enabled"):
|
||||
if enabled_plugin.contains(plugin_directory):
|
||||
var config := ConfigFile.new()
|
||||
var error = config.load(enabled_plugin)
|
||||
if error != OK:
|
||||
return default_version
|
||||
return config.get_value("plugin", "version", default_version)
|
||||
return default_version
|
||||
|
||||
func _update_urls() -> void:
|
||||
if plugin_github_url.is_empty(): return
|
||||
if _api_client == null: return
|
||||
var regex := RegEx.create_from_string("https:\\/\\/github\\.com\\/([\\w-]+)\\/([\\w-]+)\\/*")
|
||||
var regex_match := regex.search(plugin_github_url)
|
||||
if regex_match == null: return
|
||||
var username := regex_match.get_string(1)
|
||||
var repository := regex_match.get_string(2)
|
||||
_api_client.api_url = API_RELEASES_URL % [username, repository]
|
||||
|
||||
func _on_api_client_request_failed(error) -> void:
|
||||
failed.emit()
|
||||
queue_free()
|
||||
|
||||
func _on_api_client_response_received(response_body) -> void:
|
||||
if response_body is not Array:
|
||||
failed.emit()
|
||||
queue_free()
|
||||
return
|
||||
var latest_release : Dictionary = response_body.front()
|
||||
var tag_name := default_version
|
||||
if latest_release.has("tag_name"):
|
||||
tag_name = latest_release["tag_name"]
|
||||
if replace_tag_name:
|
||||
tag_name = tag_name.replacen(replace_tag_name, "")
|
||||
var current_tag_name = get_plugin_version()
|
||||
if tag_name != current_tag_name:
|
||||
new_version_detected.emit(tag_name)
|
||||
else:
|
||||
versions_matched.emit()
|
||||
queue_free()
|
||||
|
||||
func compare_versions() -> void:
|
||||
_api_client.request()
|
||||
|
||||
func _ready() -> void:
|
||||
if auto_start:
|
||||
compare_versions()
|
@ -0,0 +1 @@
|
||||
uid://ye1geusqp1gd
|
@ -0,0 +1,16 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://b5m61gpvjy1ao"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://ye1geusqp1gd" path="res://addons/maaacks_game_template/installer/check_plugin_version.gd" id="1_aqelj"]
|
||||
[ext_resource type="PackedScene" uid="uid://drhhakm62vjsy" path="res://addons/maaacks_game_template/base/scenes/utilities/api_client.tscn" id="2_5myc0"]
|
||||
|
||||
[node name="CheckPluginVersion" type="Node"]
|
||||
script = ExtResource("1_aqelj")
|
||||
plugin_directory = "maaacks_game_template"
|
||||
plugin_github_url = "https://github.com/Maaack/Godot-Game-Template"
|
||||
|
||||
[node name="APIClient" parent="." instance=ExtResource("2_5myc0")]
|
||||
api_url = "https://api.github.com/repos/Maaack/Godot-Game-Template/releases"
|
||||
request_method = 0
|
||||
|
||||
[connection signal="request_failed" from="APIClient" to="." method="_on_api_client_request_failed"]
|
||||
[connection signal="response_received" from="APIClient" to="." method="_on_api_client_response_received"]
|
@ -0,0 +1,14 @@
|
||||
[gd_scene format=3 uid="uid://cyx4i4v30bw4o"]
|
||||
|
||||
[node name="CopyConfirmationDialog" type="ConfirmationDialog"]
|
||||
title = "Copy Examples"
|
||||
initial_position = 2
|
||||
size = Vector2i(1024, 148)
|
||||
visible = true
|
||||
exclusive = false
|
||||
ok_button_text = "Yes"
|
||||
dialog_text = "Plugin enabled. It is recommended to copy the example scenes to a destination outside of the addons/ folder before editing them.
|
||||
|
||||
Would you like to copy the examples now?"
|
||||
dialog_autowrap = true
|
||||
cancel_button_text = "No"
|
@ -0,0 +1,15 @@
|
||||
[gd_scene format=3 uid="uid://vgdxevcnv0vx"]
|
||||
|
||||
[node name="DeleteExamplesConfirmationDialog" type="ConfirmationDialog"]
|
||||
title = "Delete Source Examples"
|
||||
initial_position = 2
|
||||
size = Vector2i(1024, 256)
|
||||
visible = true
|
||||
ok_button_text = "Yes"
|
||||
dialog_text = "If the copied scenes work as expected, you may delete the source examples folder. This avoids confusing both developers and the Godot editor.
|
||||
|
||||
This will also remove the option to copy the examples again. However, one copy is enough for most use cases.
|
||||
|
||||
Would you like to delete the source examples folder now?"
|
||||
dialog_autowrap = true
|
||||
cancel_button_text = "No"
|
@ -0,0 +1,11 @@
|
||||
[gd_scene format=3 uid="uid://d03csqgcaxm0m"]
|
||||
|
||||
[node name="DeleteExamplesShortConfirmationDialog" type="ConfirmationDialog"]
|
||||
title = "Delete Source Examples"
|
||||
initial_position = 2
|
||||
size = Vector2i(1024, 128)
|
||||
visible = true
|
||||
ok_button_text = "Yes"
|
||||
dialog_text = "Are you sure you would like to delete the source examples folder?"
|
||||
dialog_autowrap = true
|
||||
cancel_button_text = "No"
|
@ -0,0 +1,11 @@
|
||||
[gd_scene format=3 uid="uid://ckx50am7thhd2"]
|
||||
|
||||
[node name="DestinationDialog" type="FileDialog"]
|
||||
title = "Select a Destination"
|
||||
initial_position = 2
|
||||
size = Vector2i(1024, 640)
|
||||
visible = true
|
||||
exclusive = false
|
||||
ok_button_text = "Select Current Folder"
|
||||
mode_overrides_title = false
|
||||
file_mode = 2
|
@ -0,0 +1,12 @@
|
||||
@tool
|
||||
extends ConfirmationDialog
|
||||
|
||||
const SHORT_DESCRIPTION : String = "Choose a style for icons in the input remapping menu. This style can be changed later."
|
||||
|
||||
signal configuration_selected(index : int)
|
||||
|
||||
func _on_item_list_item_selected(index) -> void:
|
||||
configuration_selected.emit(index)
|
||||
|
||||
func set_short_description() -> void:
|
||||
%Label.text = SHORT_DESCRIPTION
|
@ -0,0 +1 @@
|
||||
uid://bduy6qihnm0qo
|
@ -0,0 +1,83 @@
|
||||
[gd_scene load_steps=14 format=3 uid="uid://d3x8m40qtdrj"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bduy6qihnm0qo" path="res://addons/maaacks_game_template/installer/kenney_input_prompts_dialog.gd" id="1_nf1bc"]
|
||||
[ext_resource type="Texture2D" uid="uid://cmni5hv40bfaa" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-colored.png" id="2_0nqam"]
|
||||
[ext_resource type="Texture2D" uid="uid://deskx061vlcgx" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-white.png" id="3_ynuxh"]
|
||||
[ext_resource type="Texture2D" uid="uid://bohem6w6kcl3x" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-colored.png" id="4_dqbfh"]
|
||||
[ext_resource type="Texture2D" uid="uid://bq211jkfnm7k7" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-white.png" id="5_1tkva"]
|
||||
[ext_resource type="Texture2D" uid="uid://bt1yqttw3d5xn" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-colored-2x.png" id="6_r3yyh"]
|
||||
[ext_resource type="Texture2D" uid="uid://bit8o3p506th6" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-white-2x.png" id="7_xgp8o"]
|
||||
[ext_resource type="Texture2D" uid="uid://cqb86gp1gh3y8" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-colored-2x.png" id="8_ag5dy"]
|
||||
[ext_resource type="Texture2D" uid="uid://d3bsc6o2ae88q" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-white-2x.png" id="9_3b8mx"]
|
||||
[ext_resource type="Texture2D" uid="uid://ix1d2e62f233" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-colored-vector.svg" id="10_ag5dy"]
|
||||
[ext_resource type="Texture2D" uid="uid://c37gofthe2bh3" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-white-vector.svg" id="11_3b8mx"]
|
||||
[ext_resource type="Texture2D" uid="uid://bsgf78aysgdnd" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-colored-vector.svg" id="12_rrkvx"]
|
||||
[ext_resource type="Texture2D" uid="uid://c1lpc33fpmd4p" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-white-vector.svg" id="13_bkfjd"]
|
||||
|
||||
[node name="KenneyInputPromptsDialog" type="ConfirmationDialog"]
|
||||
title = "Add Kenney Input Prompts Pack"
|
||||
initial_position = 2
|
||||
size = Vector2i(1024, 640)
|
||||
visible = true
|
||||
ok_button_text = "Yes"
|
||||
dialog_autowrap = true
|
||||
cancel_button_text = "No"
|
||||
script = ExtResource("1_nf1bc")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
custom_minimum_size = Vector2(560, 443)
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 8.0
|
||||
offset_top = 8.0
|
||||
offset_right = -8.0
|
||||
offset_bottom = -49.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 16
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(384, 0)
|
||||
layout_mode = 2
|
||||
text = "Would you like to install Kenney's Input Prompts?
|
||||
|
||||
This adds icons for a majority of input keys and devices in the input remapping menu. They are Creative Commons Zero (CC0) licensed, about 3.9 MB in size (7.6 MB with *.import files), and get installed into the assets folder.
|
||||
|
||||
Choose a style for icons in the input remapping menu. The style can be changed later."
|
||||
autowrap_mode = 3
|
||||
|
||||
[node name="ItemList" type="ItemList" parent="VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
item_count = 12
|
||||
same_column_width = true
|
||||
item_0/text = "Filled and Colored Vector"
|
||||
item_0/icon = ExtResource("10_ag5dy")
|
||||
item_1/text = "Filled and White Vector"
|
||||
item_1/icon = ExtResource("11_3b8mx")
|
||||
item_2/text = "Outlined and Colored Vector"
|
||||
item_2/icon = ExtResource("12_rrkvx")
|
||||
item_3/text = "Outlined and White Vector"
|
||||
item_3/icon = ExtResource("13_bkfjd")
|
||||
item_4/text = "Filled and Colored 64x64"
|
||||
item_4/icon = ExtResource("2_0nqam")
|
||||
item_5/text = "Filled and White 64x64"
|
||||
item_5/icon = ExtResource("3_ynuxh")
|
||||
item_6/text = "Outlined and Colored 64x64"
|
||||
item_6/icon = ExtResource("4_dqbfh")
|
||||
item_7/text = "Outlined and White 64x64"
|
||||
item_7/icon = ExtResource("5_1tkva")
|
||||
item_8/text = "Filled and Colored 128x128"
|
||||
item_8/icon = ExtResource("6_r3yyh")
|
||||
item_9/text = "Filled and White 128x128"
|
||||
item_9/icon = ExtResource("7_xgp8o")
|
||||
item_10/text = "Outlined and Colored 128x128"
|
||||
item_10/icon = ExtResource("8_ag5dy")
|
||||
item_11/text = "Outlined and White 128x128"
|
||||
item_11/icon = ExtResource("9_3b8mx")
|
||||
|
||||
[connection signal="item_selected" from="VBoxContainer/ItemList" to="." method="_on_item_list_item_selected"]
|
@ -0,0 +1,342 @@
|
||||
@tool
|
||||
## Tool for installing icons and setting up the configuration of the input icon mapper.
|
||||
extends Node
|
||||
|
||||
## Sent when the user selects to cancel the installation process.
|
||||
signal canceled
|
||||
## Sent when the installation process has completed.
|
||||
signal completed
|
||||
|
||||
const REIMPORT_CHECK_DELAY : float = 0.5
|
||||
const OPEN_SCENE_DELAY : float = 0.5
|
||||
const REGEX_PREFIX = """\\[node name="InputIconMapper" parent="." index="0"\\][\\s\\S]*"""
|
||||
|
||||
const FILLED_WHITE_CONFIGURATION = """
|
||||
[node name="InputIconMapper" parent="." index="0"]
|
||||
replace_strings = {
|
||||
"Capslock": "Caps Lock",
|
||||
"Generic Stick": "Generic Left Stick",
|
||||
"Guide": "Home",
|
||||
"Slash Back": "Back Slash",
|
||||
"Slash Forward": "Slash",
|
||||
"Stick L": "Left Stick",
|
||||
"Stick R": "Right Stick",
|
||||
"Trigger L 1": "Left Shoulder",
|
||||
"Trigger L 2": "Left Trigger",
|
||||
"Trigger R 1": "Right Shoulder",
|
||||
"Trigger R 2": "Right Trigger"
|
||||
}
|
||||
filtered_strings = Array[String](["keyboard", "color", "button", "arrow"])
|
||||
directories = Array[String](["res://assets/kenney_input-prompts/Keyboard & Mouse/Default", "res://assets/kenney_input-prompts/Generic/Default", "res://assets/kenney_input-prompts/Xbox Series/Default", "res://assets/kenney_input-prompts/PlayStation Series/Default", "res://assets/kenney_input-prompts/Nintendo Switch/Default", "res://assets/kenney_input-prompts/Steam Deck/Default"])
|
||||
filter = "color"
|
||||
ends_with = ".png"
|
||||
not_ends_with = "outline.png"
|
||||
"""
|
||||
const FILLED_COLOR_CONFIGURATION = """
|
||||
[node name="InputIconMapper" parent="." index="0"]
|
||||
prioritized_strings = Array[String](["color"])
|
||||
replace_strings = {
|
||||
"Capslock": "Caps Lock",
|
||||
"Generic Stick": "Generic Left Stick",
|
||||
"Guide": "Home",
|
||||
"Slash Back": "Back Slash",
|
||||
"Slash Forward": "Slash",
|
||||
"Stick L": "Left Stick",
|
||||
"Stick R": "Right Stick",
|
||||
"Trigger L 1": "Left Shoulder",
|
||||
"Trigger L 2": "Left Trigger",
|
||||
"Trigger R 1": "Right Shoulder",
|
||||
"Trigger R 2": "Right Trigger"
|
||||
}
|
||||
filtered_strings = Array[String](["keyboard", "color", "button", "arrow"])
|
||||
directories = Array[String](["res://assets/kenney_input-prompts/Keyboard & Mouse/Default", "res://assets/kenney_input-prompts/Generic/Default", "res://assets/kenney_input-prompts/Xbox Series/Default", "res://assets/kenney_input-prompts/PlayStation Series/Default", "res://assets/kenney_input-prompts/Nintendo Switch/Default", "res://assets/kenney_input-prompts/Steam Deck/Default"])
|
||||
ends_with = ".png"
|
||||
not_ends_with = "outline.png"
|
||||
"""
|
||||
const OUTLINED_WHITE_CONFIGURATION = """
|
||||
[node name="InputIconMapper" parent="." index="0"]
|
||||
prioritized_strings = Array[String](["outline"])
|
||||
replace_strings = {
|
||||
"Capslock": "Caps Lock",
|
||||
"Generic Stick": "Generic Left Stick",
|
||||
"Guide": "Home",
|
||||
"Slash Back": "Back Slash",
|
||||
"Slash Forward": "Slash",
|
||||
"Stick L": "Left Stick",
|
||||
"Stick R": "Right Stick",
|
||||
"Trigger L 1": "Left Shoulder",
|
||||
"Trigger L 2": "Left Trigger",
|
||||
"Trigger R 1": "Right Shoulder",
|
||||
"Trigger R 2": "Right Trigger"
|
||||
}
|
||||
filtered_strings = Array[String](["keyboard", "color", "button", "arrow", "outline"])
|
||||
directories = Array[String](["res://assets/kenney_input-prompts/Keyboard & Mouse/Default", "res://assets/kenney_input-prompts/Generic/Default", "res://assets/kenney_input-prompts/Xbox Series/Default", "res://assets/kenney_input-prompts/PlayStation Series/Default", "res://assets/kenney_input-prompts/Nintendo Switch/Default", "res://assets/kenney_input-prompts/Steam Deck/Default"])
|
||||
filter = "color"
|
||||
ends_with = ".png"
|
||||
"""
|
||||
const OUTLINED_COLOR_CONFIGURATION = """
|
||||
[node name="InputIconMapper" parent="." index="0"]
|
||||
prioritized_strings = Array[String](["outline", "color"])
|
||||
replace_strings = {
|
||||
"Capslock": "Caps Lock",
|
||||
"Generic Stick": "Generic Left Stick",
|
||||
"Guide": "Home",
|
||||
"Slash Back": "Back Slash",
|
||||
"Slash Forward": "Slash",
|
||||
"Stick L": "Left Stick",
|
||||
"Stick R": "Right Stick",
|
||||
"Trigger L 1": "Left Shoulder",
|
||||
"Trigger L 2": "Left Trigger",
|
||||
"Trigger R 1": "Right Shoulder",
|
||||
"Trigger R 2": "Right Trigger"
|
||||
}
|
||||
filtered_strings = Array[String](["keyboard", "color", "button", "arrow", "outline"])
|
||||
directories = Array[String](["res://assets/kenney_input-prompts/Keyboard & Mouse/Default", "res://assets/kenney_input-prompts/Generic/Default", "res://assets/kenney_input-prompts/Xbox Series/Default", "res://assets/kenney_input-prompts/PlayStation Series/Default", "res://assets/kenney_input-prompts/Nintendo Switch/Default", "res://assets/kenney_input-prompts/Steam Deck/Default"])
|
||||
ends_with = ".png"
|
||||
"""
|
||||
|
||||
const PACKAGE_EXTRA_DIRECTORIES := [
|
||||
"Flairs",
|
||||
"Nintendo Gamecube",
|
||||
"Nintendo Switch 2",
|
||||
"Nintendo Wii",
|
||||
"Nintendo WiiU",
|
||||
"Playdate",
|
||||
"Steam Controller",
|
||||
"Touch",
|
||||
]
|
||||
|
||||
const PACKAGE_EXTRA_FILES := [
|
||||
"Preview",
|
||||
]
|
||||
|
||||
## Path start where the project examples have been copied.
|
||||
@export_dir var copy_dir_path : String
|
||||
## Path end where the zipped files are to be extracted.
|
||||
@export var extract_extension : String
|
||||
|
||||
@onready var _download_and_extract_node : DownloadAndExtract = $DownloadAndExtract
|
||||
@onready var _skip_installation_dialog : ConfirmationDialog = $SkipInstallationDialog
|
||||
@onready var _kenney_input_prompts_dialog : ConfirmationDialog = $KenneyInputPromptsDialog
|
||||
@onready var _installing_dialog : AcceptDialog = $InstallingDialog
|
||||
@onready var _clean_up_dialog : ConfirmationDialog = $CleanUpDialog
|
||||
@onready var _error_dialog : AcceptDialog = $ErrorDialog
|
||||
@onready var _stage_label : Label = %StageLabel
|
||||
@onready var _progress_bar : ProgressBar = %ProgressBar
|
||||
|
||||
var _configuration_index : int = -1
|
||||
## State flag of whether the tool is waiting for the filesystem to finish scanning.
|
||||
var scanning : bool = false
|
||||
## State flag for whether the tool is waiting for the filesystem to finish reimporting.
|
||||
var reimporting : bool = false
|
||||
## Flag for whether the tool will force a download and extraction, even if the contents exist.
|
||||
var force : bool = false
|
||||
|
||||
func _download_and_extract() -> void:
|
||||
_installing_dialog.show()
|
||||
_download_and_extract_node.run.call_deferred()
|
||||
|
||||
func _run_complete() -> void:
|
||||
completed.emit()
|
||||
queue_free()
|
||||
|
||||
func _clean_up_or_complete() -> void:
|
||||
if _has_extras():
|
||||
_clean_up_dialog.show()
|
||||
else:
|
||||
_run_complete()
|
||||
|
||||
func _process(_delta : float) -> void:
|
||||
if _installing_dialog.visible:
|
||||
_progress_bar.value = _download_and_extract_node.get_progress()
|
||||
match _download_and_extract_node.stage:
|
||||
DownloadAndExtract.Stage.DOWNLOAD:
|
||||
_stage_label.text = "Downloading..."
|
||||
DownloadAndExtract.Stage.SAVE:
|
||||
_stage_label.text = "Saving..."
|
||||
DownloadAndExtract.Stage.EXTRACT:
|
||||
_stage_label.text = "Extracting..."
|
||||
DownloadAndExtract.Stage.DELETE:
|
||||
_stage_label.text = "Cleaning up..."
|
||||
DownloadAndExtract.Stage.NONE:
|
||||
_installing_dialog.hide()
|
||||
elif scanning:
|
||||
var file_system := EditorInterface.get_resource_filesystem()
|
||||
if not file_system.is_scanning():
|
||||
scanning = false
|
||||
await get_tree().create_timer(REIMPORT_CHECK_DELAY).timeout
|
||||
if reimporting:
|
||||
await file_system.resources_reimported
|
||||
reimporting = false
|
||||
_configure_and_complete()
|
||||
|
||||
func _delete_recursive(path : String) -> void:
|
||||
if not path.ends_with("/"):
|
||||
path += "/"
|
||||
var dir_access := DirAccess.open(path)
|
||||
if dir_access == null:
|
||||
return
|
||||
var directories := dir_access.get_directories()
|
||||
for directory in directories:
|
||||
_delete_recursive(path + directory)
|
||||
DirAccess.remove_absolute(path + directory)
|
||||
var files := dir_access.get_files()
|
||||
for file in files:
|
||||
DirAccess.remove_absolute(path + file)
|
||||
|
||||
func get_full_path() -> String:
|
||||
var full_path := copy_dir_path
|
||||
if not full_path.ends_with("/"):
|
||||
full_path += "/"
|
||||
full_path += extract_extension
|
||||
if not full_path.ends_with("/"):
|
||||
full_path += "/"
|
||||
return full_path
|
||||
|
||||
func _has_extras() -> bool:
|
||||
var full_path := get_full_path()
|
||||
var directories := DirAccess.get_directories_at(full_path)
|
||||
for directory in directories:
|
||||
for key in PACKAGE_EXTRA_DIRECTORIES:
|
||||
if directory.contains(key):
|
||||
return true
|
||||
var files := DirAccess.get_files_at(full_path)
|
||||
for file in files:
|
||||
for key in PACKAGE_EXTRA_FILES:
|
||||
if file.contains(key):
|
||||
return true
|
||||
return false
|
||||
|
||||
func _delete_extras() -> void:
|
||||
var full_path := get_full_path()
|
||||
var directories := DirAccess.get_directories_at(full_path)
|
||||
for directory in directories:
|
||||
for key in PACKAGE_EXTRA_DIRECTORIES:
|
||||
if directory.contains(key):
|
||||
_delete_recursive(full_path + directory)
|
||||
DirAccess.remove_absolute(full_path + directory)
|
||||
continue
|
||||
var files := DirAccess.get_files_at(full_path)
|
||||
for file in files:
|
||||
for key in PACKAGE_EXTRA_FILES:
|
||||
if file.contains(key):
|
||||
DirAccess.remove_absolute(full_path + file)
|
||||
continue
|
||||
EditorInterface.get_resource_filesystem().scan()
|
||||
|
||||
func _configure_icons() -> void:
|
||||
var input_options_menu_path := copy_dir_path + "scenes/menus/options_menu/input/input_options_menu.tscn"
|
||||
var input_options_menu := FileAccess.get_file_as_string(input_options_menu_path)
|
||||
var regex := RegEx.new()
|
||||
regex.compile(REGEX_PREFIX + """\\[node""")
|
||||
var result = regex.sub(input_options_menu, "[node")
|
||||
if result == input_options_menu:
|
||||
regex.clear()
|
||||
regex.compile(REGEX_PREFIX)
|
||||
result = regex.sub(input_options_menu, "")
|
||||
input_options_menu = result
|
||||
match(_configuration_index % 4):
|
||||
0:
|
||||
input_options_menu += FILLED_COLOR_CONFIGURATION
|
||||
1:
|
||||
input_options_menu += FILLED_WHITE_CONFIGURATION
|
||||
2:
|
||||
input_options_menu += OUTLINED_COLOR_CONFIGURATION
|
||||
3:
|
||||
input_options_menu += OUTLINED_WHITE_CONFIGURATION
|
||||
match(_configuration_index / 4):
|
||||
0:
|
||||
input_options_menu = input_options_menu.replace("Default", "Vector").replace(".png", ".svg")
|
||||
1:
|
||||
pass
|
||||
2:
|
||||
input_options_menu = input_options_menu.replace("Default", "Double")
|
||||
var file_rewrite := FileAccess.open(input_options_menu_path, FileAccess.WRITE)
|
||||
file_rewrite.store_string(input_options_menu)
|
||||
file_rewrite.close()
|
||||
if input_options_menu_path in EditorInterface.get_open_scenes():
|
||||
EditorInterface.reload_scene_from_path(input_options_menu_path)
|
||||
else:
|
||||
EditorInterface.open_scene_from_path(input_options_menu_path)
|
||||
await get_tree().create_timer(OPEN_SCENE_DELAY).timeout
|
||||
EditorInterface.save_scene()
|
||||
await get_tree().create_timer(REIMPORT_CHECK_DELAY).timeout
|
||||
_clean_up_or_complete()
|
||||
|
||||
func _configure_and_complete() -> void:
|
||||
if _configuration_index >= 0:
|
||||
_configure_icons()
|
||||
return
|
||||
_clean_up_or_complete()
|
||||
|
||||
func _scan_filesystem_and_reimport() -> void:
|
||||
var file_system := EditorInterface.get_resource_filesystem()
|
||||
file_system.scan()
|
||||
scanning = true
|
||||
await file_system.resources_reimporting
|
||||
reimporting = true
|
||||
|
||||
func _enable_forced_install() -> void:
|
||||
force = true
|
||||
_download_and_extract_node.force = true
|
||||
_kenney_input_prompts_dialog.show.call_deferred()
|
||||
|
||||
func _enable_skipped_install() -> void:
|
||||
_kenney_input_prompts_dialog.set_short_description()
|
||||
_kenney_input_prompts_dialog.show.call_deferred()
|
||||
|
||||
func _show_error_dialog(error : String) -> void:
|
||||
_installing_dialog.hide()
|
||||
_error_dialog.show()
|
||||
_error_dialog.dialog_text = "%s!" % error
|
||||
|
||||
func _ready() -> void:
|
||||
_skip_installation_dialog.hide()
|
||||
_kenney_input_prompts_dialog.hide()
|
||||
_installing_dialog.hide()
|
||||
_installing_dialog.get_ok_button().hide()
|
||||
_clean_up_dialog.hide()
|
||||
_error_dialog.hide()
|
||||
_download_and_extract_node.extract_path = get_full_path()
|
||||
if _download_and_extract_node.extract_path_exists():
|
||||
_skip_installation_dialog.show()
|
||||
else:
|
||||
_kenney_input_prompts_dialog.show()
|
||||
|
||||
func _on_kenney_input_prompts_dialog_canceled() -> void:
|
||||
canceled.emit()
|
||||
queue_free()
|
||||
|
||||
func _on_kenney_input_prompts_dialog_configuration_selected(index: int) -> void:
|
||||
_configuration_index = index
|
||||
|
||||
func _on_kenney_input_prompts_dialog_confirmed() -> void:
|
||||
if _download_and_extract_node.extract_path_exists() and not force:
|
||||
_configure_and_complete()
|
||||
return
|
||||
_download_and_extract()
|
||||
|
||||
func _on_skip_installation_dialog_canceled() -> void:
|
||||
_enable_forced_install()
|
||||
|
||||
func _on_skip_installation_dialog_confirmed() -> void:
|
||||
_enable_skipped_install()
|
||||
|
||||
func _on_error_dialog_confirmed() -> void:
|
||||
queue_free()
|
||||
|
||||
func _on_error_dialog_canceled() -> void:
|
||||
queue_free()
|
||||
|
||||
func _on_download_and_extract_run_completed() -> void:
|
||||
_scan_filesystem_and_reimport()
|
||||
|
||||
func _on_download_and_extract_run_failed(error : String) -> void:
|
||||
_show_error_dialog(error)
|
||||
|
||||
func _on_clean_up_dialog_confirmed() -> void:
|
||||
_delete_extras()
|
||||
_run_complete()
|
||||
|
||||
func _on_clean_up_dialog_canceled() -> void:
|
||||
_run_complete()
|
@ -0,0 +1 @@
|
||||
uid://ca36dy2vkk46q
|
@ -0,0 +1,92 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://d27twrcwmfxrs"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://ca36dy2vkk46q" path="res://addons/maaacks_game_template/installer/kenney_input_prompts_installer.gd" id="1_ebstj"]
|
||||
[ext_resource type="PackedScene" uid="uid://d3x8m40qtdrj" path="res://addons/maaacks_game_template/installer/kenney_input_prompts_dialog.tscn" id="1_pslk0"]
|
||||
[ext_resource type="PackedScene" uid="uid://dlkmofxhavh10" path="res://addons/maaacks_game_template/base/scenes/utilities/download_and_extract.tscn" id="3_ebstj"]
|
||||
|
||||
[node name="KenneyInputPromptsInstaller" type="Node"]
|
||||
script = ExtResource("1_ebstj")
|
||||
copy_dir_path = "res://"
|
||||
extract_extension = "assets/kenney_input-prompts"
|
||||
|
||||
[node name="DownloadAndExtract" parent="." instance=ExtResource("3_ebstj")]
|
||||
zip_url = "https://github.com/Maaack/Kenney-Input-Prompts/archive/refs/tags/1.3.zip"
|
||||
extract_path = "res://assets/kenney_input-prompts/"
|
||||
skip_base_zip_dir = true
|
||||
zip_file_path = "res://kenney_input-prompts.zip"
|
||||
metadata/_custom_type_script = "uid://bqu3bc0tttrfk"
|
||||
|
||||
[node name="SkipInstallationDialog" type="ConfirmationDialog" parent="."]
|
||||
title = "Skip Installation?"
|
||||
initial_position = 2
|
||||
size = Vector2i(682, 160)
|
||||
ok_button_text = "Skip"
|
||||
dialog_text = "The input prompts pack appears to already be installed.
|
||||
|
||||
Do you want to force a reinstall of the pack, or skip to picking a style?"
|
||||
cancel_button_text = "Reinstall"
|
||||
|
||||
[node name="KenneyInputPromptsDialog" parent="." instance=ExtResource("1_pslk0")]
|
||||
visible = false
|
||||
|
||||
[node name="InstallingDialog" type="AcceptDialog" parent="."]
|
||||
title = "Installing..."
|
||||
initial_position = 2
|
||||
size = Vector2i(400, 100)
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="InstallingDialog"]
|
||||
offset_left = 4.0
|
||||
offset_top = 4.0
|
||||
offset_right = 396.0
|
||||
offset_bottom = 96.0
|
||||
theme_override_constants/margin_left = 16
|
||||
theme_override_constants/margin_top = 16
|
||||
theme_override_constants/margin_right = 16
|
||||
theme_override_constants/margin_bottom = 16
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="InstallingDialog/MarginContainer"]
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="StageLabel" type="Label" parent="InstallingDialog/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="ProgressBar" type="ProgressBar" parent="InstallingDialog/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
max_value = 1.0
|
||||
step = 0.001
|
||||
|
||||
[node name="CleanUpDialog" type="ConfirmationDialog" parent="."]
|
||||
auto_translate_mode = 1
|
||||
title = "Clean Up Extra Content?"
|
||||
initial_position = 2
|
||||
size = Vector2i(1024, 210)
|
||||
ok_button_text = "Yes"
|
||||
dialog_text = "Kenney's Input Prompts contains extra content not used by the input remapping menu.
|
||||
|
||||
This includes icons for devices not currently detected and preview images. Removing the extras cuts the total size of extracted assets by almost 50%. The option to change input icon styles will remain available after the clean up, too.
|
||||
|
||||
Would you like to have the extra content removed?"
|
||||
dialog_autowrap = true
|
||||
cancel_button_text = "No"
|
||||
|
||||
[node name="ErrorDialog" type="AcceptDialog" parent="."]
|
||||
title = "Error!"
|
||||
initial_position = 2
|
||||
size = Vector2i(400, 128)
|
||||
|
||||
[connection signal="run_completed" from="DownloadAndExtract" to="." method="_on_download_and_extract_run_completed"]
|
||||
[connection signal="run_failed" from="DownloadAndExtract" to="." method="_on_download_and_extract_run_failed"]
|
||||
[connection signal="canceled" from="SkipInstallationDialog" to="." method="_on_skip_installation_dialog_canceled"]
|
||||
[connection signal="confirmed" from="SkipInstallationDialog" to="." method="_on_skip_installation_dialog_confirmed"]
|
||||
[connection signal="canceled" from="KenneyInputPromptsDialog" to="." method="_on_kenney_input_prompts_dialog_canceled"]
|
||||
[connection signal="configuration_selected" from="KenneyInputPromptsDialog" to="." method="_on_kenney_input_prompts_dialog_configuration_selected"]
|
||||
[connection signal="confirmed" from="KenneyInputPromptsDialog" to="." method="_on_kenney_input_prompts_dialog_confirmed"]
|
||||
[connection signal="canceled" from="CleanUpDialog" to="." method="_on_clean_up_dialog_canceled"]
|
||||
[connection signal="confirmed" from="CleanUpDialog" to="." method="_on_clean_up_dialog_confirmed"]
|
||||
[connection signal="canceled" from="ErrorDialog" to="." method="_on_error_dialog_canceled"]
|
||||
[connection signal="confirmed" from="ErrorDialog" to="." method="_on_error_dialog_confirmed"]
|
@ -0,0 +1,14 @@
|
||||
[gd_scene format=3 uid="uid://b8kr3y0cjxr8m"]
|
||||
|
||||
[node name="MainSceneConfirmationDialog" type="ConfirmationDialog"]
|
||||
title = "Update Main Scene"
|
||||
initial_position = 2
|
||||
size = Vector2i(1024, 192)
|
||||
visible = true
|
||||
exclusive = false
|
||||
ok_button_text = "Yes"
|
||||
dialog_text = "Would you like to update the project's main scene?
|
||||
|
||||
"
|
||||
dialog_autowrap = true
|
||||
cancel_button_text = "No"
|
36
addons/maaacks_game_template/installer/override.cfg
Normal file
36
addons/maaacks_game_template/installer/override.cfg
Normal file
@ -0,0 +1,36 @@
|
||||
; Project settings override file.
|
||||
; Adds gamepad inputs to built-in actions.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
|
||||
[input]
|
||||
|
||||
ui_accept={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194309,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194310,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":32,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":true,"script":null)
|
||||
]
|
||||
}
|
||||
ui_cancel={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194305,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":4,"pressure":0.0,"pressed":true,"script":null)
|
||||
]
|
||||
}
|
||||
ui_page_up={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194323,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":true,"script":null)
|
||||
]
|
||||
}
|
||||
ui_page_down={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194324,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":10,"pressure":0.0,"pressed":true,"script":null)
|
||||
]
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
[gd_scene format=3 uid="uid://b8808yj7a0ghj"]
|
||||
|
||||
[node name="PlayOpeningConfirmationDialog" type="ConfirmationDialog"]
|
||||
title = "Run & Test"
|
||||
initial_position = 2
|
||||
size = Vector2i(1024, 148)
|
||||
visible = true
|
||||
ok_button_text = "Yes"
|
||||
dialog_text = "It is recommended to run the opening scene of the plugin and test if any issues occurred during the copying process.
|
||||
|
||||
Would you like to run and test the scenes now?"
|
||||
dialog_autowrap = true
|
||||
cancel_button_text = "No"
|
@ -0,0 +1,33 @@
|
||||
@tool
|
||||
extends ConfirmationDialog
|
||||
|
||||
signal theme_selected(theme_file: String)
|
||||
|
||||
@export_dir var theme_directories : Array[String] :
|
||||
set(value):
|
||||
theme_directories = value
|
||||
if is_inside_tree():
|
||||
%FileLister.directories = theme_directories
|
||||
_fill_with_themes()
|
||||
|
||||
func _fill_with_themes() -> void:
|
||||
%ItemList.clear()
|
||||
for file in %FileLister.files:
|
||||
if file is String:
|
||||
var readable_name = file.get_file().get_basename().capitalize()
|
||||
%ItemList.add_item(readable_name)
|
||||
|
||||
func _ready() -> void:
|
||||
get_ok_button().disabled = true
|
||||
|
||||
func _preview_theme(theme_file: String) -> void:
|
||||
var theme_resource : Theme = load(theme_file)
|
||||
if theme_resource == null: return
|
||||
%ThemePreviewContainer.theme = theme_resource
|
||||
|
||||
func _on_item_list_item_selected(index) -> void:
|
||||
get_ok_button().disabled = false
|
||||
if index < %FileLister.files.size():
|
||||
var file = %FileLister.files[index]
|
||||
_preview_theme(file)
|
||||
theme_selected.emit(file)
|
@ -0,0 +1 @@
|
||||
uid://c6p8xjvlrgsfk
|
@ -0,0 +1,178 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://d25mdvmlbn35"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c6p8xjvlrgsfk" path="res://addons/maaacks_game_template/installer/theme_selection_dialog.gd" id="1_5u0gx"]
|
||||
[ext_resource type="Script" uid="uid://bij7wsh8d44gv" path="res://addons/maaacks_game_template/base/scripts/file_lister.gd" id="2_luhgx"]
|
||||
|
||||
[node name="ThemeSelectionDialog" type="ConfirmationDialog"]
|
||||
title = "Use a Starter Theme"
|
||||
initial_position = 2
|
||||
size = Vector2i(1024, 704)
|
||||
visible = true
|
||||
ok_button_text = "Yes"
|
||||
dialog_autowrap = true
|
||||
cancel_button_text = "No"
|
||||
script = ExtResource("1_5u0gx")
|
||||
|
||||
[node name="FileLister" type="Node" parent="."]
|
||||
unique_name_in_owner = true
|
||||
script = ExtResource("2_luhgx")
|
||||
ends_with = ".tres"
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
custom_minimum_size = Vector2(560, 443)
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 8.0
|
||||
offset_top = 8.0
|
||||
offset_right = -8.0
|
||||
offset_bottom = -49.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 16
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer"]
|
||||
custom_minimum_size = Vector2(384, 0)
|
||||
layout_mode = 2
|
||||
text = "A custom theme was not detected for the project. Starter options are provided below. These can be customized as needed.
|
||||
|
||||
Requires restarting the editor to take full effect."
|
||||
autowrap_mode = 3
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ItemList" type="ItemList" parent="VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="VSeparator" type="VSeparator" parent="VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/margin_left = 16
|
||||
theme_override_constants/margin_right = 16
|
||||
|
||||
[node name="ThemePreviewContainer" type="TabContainer" parent="VBoxContainer/HBoxContainer/MarginContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
current_tab = 0
|
||||
|
||||
[node name="Tab1" type="Control" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer"]
|
||||
layout_mode = 2
|
||||
metadata/_tab_index = 0
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab1"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/margin_left = 8
|
||||
theme_override_constants/margin_top = 8
|
||||
theme_override_constants/margin_right = 8
|
||||
theme_override_constants/margin_bottom = 8
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab1/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab1/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Label"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab1/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Button" type="Button" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab1/MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Button"
|
||||
|
||||
[node name="Button2" type="Button" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab1/MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
toggle_mode = true
|
||||
button_pressed = true
|
||||
text = "Button"
|
||||
|
||||
[node name="Button3" type="Button" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab1/MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
disabled = true
|
||||
text = "Button"
|
||||
|
||||
[node name="CheckButton" type="CheckButton" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab1/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "CheckButton"
|
||||
|
||||
[node name="CheckBox" type="CheckBox" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab1/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "CheckBox"
|
||||
|
||||
[node name="MenuButton" type="MenuButton" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab1/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "MenuButton"
|
||||
|
||||
[node name="OptionButton" type="OptionButton" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab1/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
selected = 0
|
||||
item_count = 2
|
||||
popup/item_0/text = "OptionButton"
|
||||
popup/item_0/id = 0
|
||||
popup/item_1/text = "OptionButton2"
|
||||
popup/item_1/id = 1
|
||||
|
||||
[node name="Tab2" type="Control" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
metadata/_tab_index = 1
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab2"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/margin_left = 8
|
||||
theme_override_constants/margin_top = 8
|
||||
theme_override_constants/margin_right = 8
|
||||
theme_override_constants/margin_bottom = 8
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab2/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab2/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Another label"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="LineEdit" type="LineEdit" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab2/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="TextEdit" type="TextEdit" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab2/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="HSlider" type="HSlider" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab2/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HScrollBar" type="HScrollBar" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab2/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab2/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ProgressBar" type="ProgressBar" parent="VBoxContainer/HBoxContainer/MarginContainer/ThemePreviewContainer/Tab2/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
value = 50.0
|
||||
|
||||
[connection signal="item_selected" from="VBoxContainer/HBoxContainer/ItemList" to="." method="_on_item_list_item_selected"]
|
153
addons/maaacks_game_template/installer/update_plugin.gd
Normal file
153
addons/maaacks_game_template/installer/update_plugin.gd
Normal file
@ -0,0 +1,153 @@
|
||||
@tool
|
||||
extends Node
|
||||
|
||||
signal update_completed
|
||||
|
||||
const API_RELEASES_URL := "https://api.github.com/repos/%s/%s/releases"
|
||||
const UPDATE_CONFIRMATION_MESSAGE := "This will update the contents of the plugin folder (addons/%s/).\nFiles outside of the plugin folder will not be affected.\n\nUpdate %s to v%s?"
|
||||
const PLUGIN_EXTRACT_PATH := "res://addons/%s/"
|
||||
const PLUGIN_TEMP_ZIP_PATH := "res://%s_%s_update.zip"
|
||||
|
||||
@export var plugin_directory : String
|
||||
@export var plugin_github_url : String :
|
||||
set(value):
|
||||
plugin_github_url = value
|
||||
_update_urls()
|
||||
@export_group("Advanced")
|
||||
@export var auto_start : bool = false
|
||||
@export var default_version : String = "0.0.0"
|
||||
@export var replace_tag_name : String = "v"
|
||||
@export var _test_action : bool = false :
|
||||
set(value):
|
||||
if value and Engine.is_editor_hint():
|
||||
get_newest_version()
|
||||
|
||||
@onready var _api_client : APIClient = $APIClient
|
||||
@onready var _download_and_extract_node : DownloadAndExtract = $DownloadAndExtract
|
||||
@onready var _update_confirmation_dialog : ConfirmationDialog = $UpdateConfirmationDialog
|
||||
@onready var _installing_dialog : AcceptDialog = $InstallingDialog
|
||||
@onready var _error_dialog : AcceptDialog = $ErrorDialog
|
||||
@onready var _success_dialog : AcceptDialog = $SuccessDialog
|
||||
@onready var _release_label : RichTextLabel = %ReleaseLabel
|
||||
@onready var _update_label : Label = %UpdateLabel
|
||||
@onready var _release_notes_button : LinkButton = %ReleaseNotesButton
|
||||
@onready var _release_notes_panel : Panel = %ReleaseNotesPanel
|
||||
@onready var _stage_label : Label = %StageLabel
|
||||
@onready var _progress_bar : ProgressBar = %ProgressBar
|
||||
|
||||
var _zipball_url : String
|
||||
var _newest_version : String
|
||||
var _plugin_name : String
|
||||
var _current_plugin_version : String
|
||||
|
||||
func _load_plugin_details() -> void:
|
||||
if plugin_directory.is_empty(): return
|
||||
for enabled_plugin in ProjectSettings.get_setting("editor_plugins/enabled"):
|
||||
if enabled_plugin.contains(plugin_directory):
|
||||
var config := ConfigFile.new()
|
||||
var error = config.load(enabled_plugin)
|
||||
if error != OK:
|
||||
return
|
||||
_current_plugin_version = config.get_value("plugin", "version", default_version)
|
||||
_plugin_name = config.get_value("plugin", "name", "Plugin")
|
||||
|
||||
func _update_urls() -> void:
|
||||
if plugin_github_url.is_empty(): return
|
||||
if _api_client == null: return
|
||||
var regex := RegEx.create_from_string("https:\\/\\/github\\.com\\/([\\w-]+)\\/([\\w-]+)\\/*")
|
||||
var regex_match := regex.search(plugin_github_url)
|
||||
if regex_match == null: return
|
||||
var username := regex_match.get_string(1)
|
||||
var repository := regex_match.get_string(2)
|
||||
_api_client.api_url = API_RELEASES_URL % [username, repository]
|
||||
|
||||
func _show_error_dialog(error : String) -> void:
|
||||
_error_dialog.show()
|
||||
_error_dialog.dialog_text = "%s!" % error
|
||||
|
||||
func _show_success_dialog() -> void:
|
||||
_success_dialog.show()
|
||||
_success_dialog.dialog_text = "%s updated to v%s." % [_plugin_name, _newest_version]
|
||||
|
||||
func _on_api_client_request_failed(error : String) -> void:
|
||||
_show_error_dialog(error)
|
||||
|
||||
func _on_api_client_response_received(response_body : Variant) -> void:
|
||||
if response_body is not Array:
|
||||
push_error("Response was not an array")
|
||||
return
|
||||
var latest_release : Dictionary = response_body.front()
|
||||
_newest_version = default_version
|
||||
if latest_release.has("tag_name"):
|
||||
var tag_name = latest_release["tag_name"]
|
||||
if replace_tag_name:
|
||||
tag_name = tag_name.replacen(replace_tag_name, "")
|
||||
_newest_version = tag_name
|
||||
if latest_release.has("zipball_url"):
|
||||
_zipball_url = latest_release["zipball_url"]
|
||||
_download_and_extract_node.zip_url = _zipball_url
|
||||
_download_and_extract_node.zip_file_path = PLUGIN_TEMP_ZIP_PATH % [plugin_directory, _newest_version]
|
||||
_update_label.text = UPDATE_CONFIRMATION_MESSAGE % [plugin_directory, _plugin_name, _newest_version]
|
||||
if latest_release.has("body"):
|
||||
_release_label.text = latest_release["body"]
|
||||
_update_confirmation_dialog.show()
|
||||
|
||||
func _on_download_and_extract_zip_saved() -> void:
|
||||
OS.move_to_trash(ProjectSettings.globalize_path(PLUGIN_EXTRACT_PATH % plugin_directory))
|
||||
|
||||
func _on_download_and_extract_run_failed(error : String) -> void:
|
||||
_show_error_dialog(error)
|
||||
|
||||
func _on_download_and_extract_run_completed() -> void:
|
||||
update_completed.emit()
|
||||
_show_success_dialog()
|
||||
|
||||
func _on_error_dialog_canceled() -> void:
|
||||
queue_free()
|
||||
|
||||
func _on_error_dialog_confirmed() -> void:
|
||||
queue_free()
|
||||
|
||||
func _on_success_dialog_canceled() -> void:
|
||||
queue_free()
|
||||
|
||||
func _on_success_dialog_confirmed() -> void:
|
||||
queue_free()
|
||||
|
||||
func _on_update_confirmation_dialog_canceled() -> void:
|
||||
queue_free()
|
||||
|
||||
func _on_update_confirmation_dialog_confirmed() -> void:
|
||||
_download_and_extract_node.run()
|
||||
_installing_dialog.show()
|
||||
|
||||
func _on_release_notes_button_pressed() -> void:
|
||||
_release_notes_panel.show()
|
||||
_release_notes_button.hide()
|
||||
|
||||
func get_newest_version() -> void:
|
||||
_api_client.request()
|
||||
|
||||
func _ready() -> void:
|
||||
_load_plugin_details()
|
||||
_update_confirmation_dialog.hide()
|
||||
_installing_dialog.hide()
|
||||
_error_dialog.hide()
|
||||
_success_dialog.hide()
|
||||
if auto_start:
|
||||
get_newest_version()
|
||||
|
||||
func _process(_delta : float) -> void:
|
||||
if _installing_dialog.visible:
|
||||
_progress_bar.value = _download_and_extract_node.get_progress()
|
||||
match _download_and_extract_node.stage:
|
||||
DownloadAndExtract.Stage.DOWNLOAD:
|
||||
_stage_label.text = "Downloading..."
|
||||
DownloadAndExtract.Stage.SAVE:
|
||||
_stage_label.text = "Saving..."
|
||||
DownloadAndExtract.Stage.EXTRACT:
|
||||
_stage_label.text = "Extracting..."
|
||||
DownloadAndExtract.Stage.DELETE:
|
||||
_stage_label.text = "Cleaning up..."
|
||||
DownloadAndExtract.Stage.NONE:
|
||||
_installing_dialog.hide()
|
@ -0,0 +1 @@
|
||||
uid://cwj8dpqveao6o
|
128
addons/maaacks_game_template/installer/update_plugin.tscn
Normal file
128
addons/maaacks_game_template/installer/update_plugin.tscn
Normal file
@ -0,0 +1,128 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://gynblau0ojia"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cwj8dpqveao6o" path="res://addons/maaacks_game_template/installer/update_plugin.gd" id="1_s6qpc"]
|
||||
[ext_resource type="PackedScene" uid="uid://drhhakm62vjsy" path="res://addons/maaacks_game_template/base/scenes/utilities/api_client.tscn" id="2_s6pdq"]
|
||||
[ext_resource type="PackedScene" uid="uid://dlkmofxhavh10" path="res://addons/maaacks_game_template/base/scenes/utilities/download_and_extract.tscn" id="3_s6pdq"]
|
||||
|
||||
[node name="UpdatePlugin" type="Node"]
|
||||
script = ExtResource("1_s6qpc")
|
||||
plugin_directory = "maaacks_game_template"
|
||||
plugin_github_url = "https://github.com/Maaack/Godot-Game-Template"
|
||||
|
||||
[node name="APIClient" parent="." instance=ExtResource("2_s6pdq")]
|
||||
api_url = "https://api.github.com/repos/Maaack/Godot-Game-Template/releases"
|
||||
request_method = 0
|
||||
|
||||
[node name="DownloadAndExtract" parent="." instance=ExtResource("3_s6pdq")]
|
||||
extract_path = "res://"
|
||||
path_match_string = "addons/"
|
||||
skip_base_zip_dir = true
|
||||
force = true
|
||||
|
||||
[node name="UpdateConfirmationDialog" type="ConfirmationDialog" parent="."]
|
||||
auto_translate_mode = 1
|
||||
title = "Update Plugin?"
|
||||
initial_position = 2
|
||||
size = Vector2i(640, 360)
|
||||
dialog_autowrap = true
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="UpdateConfirmationDialog"]
|
||||
offset_left = 8.0
|
||||
offset_top = 8.0
|
||||
offset_right = 632.0
|
||||
offset_bottom = 311.0
|
||||
theme_override_constants/margin_bottom = 16
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="UpdateConfirmationDialog/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="UpdateLabel" type="Label" parent="UpdateConfirmationDialog/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "This will update the contents of the plugin folder (addons/plugin_directory/).
|
||||
Files outside of the plugin folder will not be affected.
|
||||
|
||||
Update to v0.0.0?"
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="UpdateConfirmationDialog/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ReleaseNotesButton" type="LinkButton" parent="UpdateConfirmationDialog/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Show Release Notes"
|
||||
|
||||
[node name="ReleaseNotesPanel" type="Panel" parent="UpdateConfirmationDialog/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(0, 420)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ReleaseLabel" type="RichTextLabel" parent="UpdateConfirmationDialog/MarginContainer/VBoxContainer/ReleaseNotesPanel"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="InstallingDialog" type="AcceptDialog" parent="."]
|
||||
auto_translate_mode = 1
|
||||
title = "Installing..."
|
||||
initial_position = 2
|
||||
size = Vector2i(400, 111)
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="InstallingDialog"]
|
||||
offset_left = 4.0
|
||||
offset_top = 4.0
|
||||
offset_right = 396.0
|
||||
offset_bottom = 96.0
|
||||
theme_override_constants/margin_left = 16
|
||||
theme_override_constants/margin_top = 16
|
||||
theme_override_constants/margin_right = 16
|
||||
theme_override_constants/margin_bottom = 16
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="InstallingDialog/MarginContainer"]
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="StageLabel" type="Label" parent="InstallingDialog/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="ProgressBar" type="ProgressBar" parent="InstallingDialog/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
max_value = 1.0
|
||||
step = 0.001
|
||||
|
||||
[node name="ErrorDialog" type="AcceptDialog" parent="."]
|
||||
auto_translate_mode = 1
|
||||
title = "Error!"
|
||||
initial_position = 2
|
||||
size = Vector2i(400, 128)
|
||||
|
||||
[node name="SuccessDialog" type="AcceptDialog" parent="."]
|
||||
auto_translate_mode = 1
|
||||
title = "Update Complete"
|
||||
initial_position = 2
|
||||
size = Vector2i(400, 128)
|
||||
dialog_text = "%s updated to v%s."
|
||||
|
||||
[connection signal="request_failed" from="APIClient" to="." method="_on_api_client_request_failed"]
|
||||
[connection signal="response_received" from="APIClient" to="." method="_on_api_client_response_received"]
|
||||
[connection signal="run_completed" from="DownloadAndExtract" to="." method="_on_download_and_extract_run_completed"]
|
||||
[connection signal="run_failed" from="DownloadAndExtract" to="." method="_on_download_and_extract_run_failed"]
|
||||
[connection signal="zip_saved" from="DownloadAndExtract" to="." method="_on_download_and_extract_zip_saved"]
|
||||
[connection signal="canceled" from="UpdateConfirmationDialog" to="." method="_on_update_confirmation_dialog_canceled"]
|
||||
[connection signal="confirmed" from="UpdateConfirmationDialog" to="." method="_on_update_confirmation_dialog_confirmed"]
|
||||
[connection signal="pressed" from="UpdateConfirmationDialog/MarginContainer/VBoxContainer/ReleaseNotesButton" to="." method="_on_release_notes_button_pressed"]
|
||||
[connection signal="canceled" from="ErrorDialog" to="." method="_on_error_dialog_canceled"]
|
||||
[connection signal="confirmed" from="ErrorDialog" to="." method="_on_error_dialog_confirmed"]
|
||||
[connection signal="canceled" from="SuccessDialog" to="." method="_on_success_dialog_canceled"]
|
||||
[connection signal="confirmed" from="SuccessDialog" to="." method="_on_success_dialog_confirmed"]
|
Reference in New Issue
Block a user