Basic game template addon
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
@tool
|
||||
extends Node
|
||||
## Script for comparing the version of a plugin to the latest release on GitHub.
|
||||
|
||||
signal new_version_detected(version: String)
|
||||
signal versions_matched
|
||||
signal failed
|
||||
|
||||
const APIClient = MaaacksGameTemplatePlugin.APIClient
|
||||
|
||||
const API_RELEASES_URL := "https://api.github.com/repos/%s/%s/releases"
|
||||
|
||||
## The directory of the plugin to update. Typically in res://addons/.
|
||||
@export var plugin_directory : String
|
||||
## The URL of the GitHub repo to pull new releases.
|
||||
@export var plugin_github_url : String :
|
||||
set(value):
|
||||
plugin_github_url = value
|
||||
_update_urls()
|
||||
@export_group("Advanced")
|
||||
## If true, automatically check for a new version when ready.
|
||||
@export var auto_start : bool = false
|
||||
## Text to remove from the tag before comparing versions.
|
||||
@export var replace_tag_name : String = "v"
|
||||
## The default lowest version to display.
|
||||
@export var default_version : String = "0.0.0"
|
||||
## If true, test comparing versions.
|
||||
## Replace with @export_tool_button for Godot 4.4+
|
||||
@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 or response_body.is_empty():
|
||||
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://chjaeg7rfnixu
|
||||
@@ -0,0 +1,16 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://depfw7i463ojc"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://chjaeg7rfnixu" path="res://addons/maaacks_game_template/installer/check_plugin_version.gd" id="1_aqelj"]
|
||||
[ext_resource type="PackedScene" uid="uid://cf0hkngq1mgfy" path="res://addons/maaacks_game_template/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-Minimal-Game-Template"
|
||||
|
||||
[node name="APIClient" parent="." instance=ExtResource("2_5myc0")]
|
||||
api_url = "https://api.github.com/repos/Maaack/Godot-Minimal-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"]
|
||||
175
addons/maaacks_game_template/installer/copy_and_edit_files.gd
Normal file
175
addons/maaacks_game_template/installer/copy_and_edit_files.gd
Normal file
@@ -0,0 +1,175 @@
|
||||
@tool
|
||||
extends Node
|
||||
## Script for automatically copying Godot scenes and scripts without UIDs.
|
||||
|
||||
signal canceled
|
||||
signal completed(target_path : String)
|
||||
|
||||
const UID_PREG_MATCH = r'uid="uid:\/\/[0-9a-z]+" '
|
||||
const RUNNING_CHECK_DELAY : float = 0.25
|
||||
const RESAVING_DELAY : float = 1.0
|
||||
const RAW_COPY_EXTENSIONS : Array = ["gd", "md", "txt"]
|
||||
const OMIT_COPY_EXTENSIONS : Array = ["uid"]
|
||||
const REPLACE_CONTENT_EXTENSIONS : Array = ["gd", "tscn", "tres", "md"]
|
||||
|
||||
@onready var destination_dialog : FileDialog = $DestinationDialog
|
||||
|
||||
@export_dir var relative_path : String :
|
||||
set(value):
|
||||
relative_path = value
|
||||
if not relative_path.ends_with("/"):
|
||||
relative_path += "/"
|
||||
@export var replace_strings_map : Dictionary
|
||||
@export var visible : bool = true :
|
||||
set(value):
|
||||
visible = value
|
||||
if is_inside_tree():
|
||||
destination_dialog.visible = visible
|
||||
|
||||
func show() -> void:
|
||||
visible = true
|
||||
|
||||
func hide() -> void:
|
||||
visible = false
|
||||
|
||||
func close() -> void:
|
||||
queue_free()
|
||||
|
||||
func _remove_uids(content : String) -> String:
|
||||
var regex = RegEx.new()
|
||||
regex.compile(UID_PREG_MATCH)
|
||||
return regex.sub(content, "", true)
|
||||
|
||||
func _replace_paths(content : String, target_path : String) -> String:
|
||||
return content.replace(relative_path.trim_prefix("res://"), target_path.trim_prefix("res://"))
|
||||
|
||||
func _replace_strings(content : String) -> String:
|
||||
for key in replace_strings_map:
|
||||
var value : String = replace_strings_map[key]
|
||||
content = content.replace(key, value)
|
||||
return content
|
||||
|
||||
func _replace_content(content : String, target_path : String) -> String:
|
||||
var replaced_content : String
|
||||
replaced_content = _remove_uids(content)
|
||||
replaced_content = _replace_paths(replaced_content, target_path)
|
||||
replaced_content = _replace_strings(replaced_content)
|
||||
return replaced_content
|
||||
|
||||
func _replace_file_contents(file_path : String, target_path : String) -> void:
|
||||
var extension : String = file_path.get_extension()
|
||||
if extension not in REPLACE_CONTENT_EXTENSIONS:
|
||||
return
|
||||
var file = FileAccess.open(file_path, FileAccess.READ)
|
||||
if file == null:
|
||||
push_error("plugin error - null file: `%s`" % file_path)
|
||||
return
|
||||
var original_content = file.get_as_text()
|
||||
file.close()
|
||||
var replaced_content := _replace_content(original_content, target_path)
|
||||
if replaced_content == original_content: return
|
||||
file = FileAccess.open(file_path, FileAccess.WRITE)
|
||||
file.store_string(replaced_content)
|
||||
file.close()
|
||||
|
||||
func _save_resource(resource_path : String, resource_destination : String, whitelisted_extensions : PackedStringArray = []) -> Error:
|
||||
var extension : String = resource_path.get_extension()
|
||||
if whitelisted_extensions.size() > 0:
|
||||
if not extension in whitelisted_extensions:
|
||||
return OK
|
||||
if extension == "import":
|
||||
# skip import files
|
||||
return OK
|
||||
var file_object = load(resource_path)
|
||||
if file_object is Resource:
|
||||
var possible_extensions = ResourceSaver.get_recognized_extensions(file_object)
|
||||
if possible_extensions.has(extension):
|
||||
return ResourceSaver.save(file_object, resource_destination, ResourceSaver.FLAG_CHANGE_PATH)
|
||||
else:
|
||||
return ERR_FILE_UNRECOGNIZED
|
||||
else:
|
||||
return ERR_FILE_UNRECOGNIZED
|
||||
return OK
|
||||
|
||||
func _raw_copy_file_path(file_path : String, destination_path : String) -> Error:
|
||||
var dir := DirAccess.open("res://")
|
||||
var error := dir.copy(file_path, destination_path)
|
||||
return error
|
||||
|
||||
func _copy_file_path(file_path : String, destination_path : String, target_path : String) -> Error:
|
||||
var error : Error
|
||||
if file_path.get_extension() in OMIT_COPY_EXTENSIONS:
|
||||
return error
|
||||
if file_path.get_extension() in RAW_COPY_EXTENSIONS:
|
||||
error = _raw_copy_file_path(file_path, destination_path)
|
||||
else:
|
||||
error = _save_resource(file_path, destination_path)
|
||||
if error == ERR_FILE_UNRECOGNIZED:
|
||||
error = _raw_copy_file_path(file_path, destination_path)
|
||||
if not error:
|
||||
_replace_file_contents(destination_path, target_path)
|
||||
return error
|
||||
|
||||
func _copy_directory_path(dir_path : String, target_path : String) -> void:
|
||||
if not dir_path.ends_with("/"):
|
||||
dir_path += "/"
|
||||
var dir = DirAccess.open(dir_path)
|
||||
if dir:
|
||||
dir.list_dir_begin()
|
||||
var file_name = dir.get_next()
|
||||
var error : Error
|
||||
while file_name != "" and error == 0:
|
||||
var file_relative_path = dir_path.trim_prefix(relative_path)
|
||||
var destination_path = target_path + file_relative_path + file_name
|
||||
var full_file_path = dir_path + file_name
|
||||
if dir.current_is_dir():
|
||||
if not dir.dir_exists(destination_path):
|
||||
error = dir.make_dir(destination_path)
|
||||
_copy_directory_path(full_file_path, target_path)
|
||||
else:
|
||||
error = _copy_file_path(full_file_path, destination_path, target_path)
|
||||
file_name = dir.get_next()
|
||||
if error:
|
||||
push_error("plugin error - copying path: %s" % error)
|
||||
else:
|
||||
push_error("plugin error - accessing path: %s" % dir_path)
|
||||
|
||||
func _complete(target_path : String) -> void:
|
||||
completed.emit(target_path)
|
||||
close()
|
||||
|
||||
func _wait_for_scan_and_complete(target_path : String) -> void:
|
||||
var timer: Timer = Timer.new()
|
||||
var callable := func():
|
||||
if EditorInterface.get_resource_filesystem().is_scanning(): return
|
||||
timer.stop()
|
||||
_complete(target_path)
|
||||
timer.queue_free()
|
||||
timer.timeout.connect(callable)
|
||||
add_child(timer)
|
||||
timer.start(RUNNING_CHECK_DELAY)
|
||||
|
||||
func _delayed_saving_and_next_prompt(target_path : String) -> void:
|
||||
var timer: Timer = Timer.new()
|
||||
var callable := func():
|
||||
timer.stop()
|
||||
EditorInterface.save_all_scenes()
|
||||
EditorInterface.get_resource_filesystem().scan()
|
||||
_wait_for_scan_and_complete(target_path)
|
||||
timer.queue_free()
|
||||
timer.timeout.connect(callable)
|
||||
add_child(timer)
|
||||
timer.start(RESAVING_DELAY)
|
||||
|
||||
func _copy_to_directory(target_path : String) -> void:
|
||||
if not target_path.ends_with("/"):
|
||||
target_path += "/"
|
||||
_copy_directory_path(relative_path, target_path)
|
||||
_delayed_saving_and_next_prompt(target_path)
|
||||
|
||||
func _on_destination_dialog_dir_selected(dir):
|
||||
_copy_to_directory(dir)
|
||||
|
||||
func _on_destination_dialog_canceled():
|
||||
canceled.emit()
|
||||
close()
|
||||
@@ -0,0 +1 @@
|
||||
uid://terojwgplakq
|
||||
@@ -0,0 +1,16 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://6dpw3bj32ov"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://terojwgplakq" path="res://addons/maaacks_game_template/installer/copy_and_edit_files.gd" id="1_oyky1"]
|
||||
[ext_resource type="PackedScene" uid="uid://doa4t485iflon" path="res://addons/maaacks_game_template/installer/destination_dialog.tscn" id="2_g35hh"]
|
||||
|
||||
[node name="CopyAndEditFiles" type="Node"]
|
||||
script = ExtResource("1_oyky1")
|
||||
relative_path = "res://addons/maaacks_game_template/examples/"
|
||||
replace_strings_map = {
|
||||
"StateExample": "State"
|
||||
}
|
||||
|
||||
[node name="DestinationDialog" parent="." instance=ExtResource("2_g35hh")]
|
||||
|
||||
[connection signal="canceled" from="DestinationDialog" to="." method="_on_destination_dialog_canceled"]
|
||||
[connection signal="dir_selected" from="DestinationDialog" to="." method="_on_destination_dialog_dir_selected"]
|
||||
@@ -0,0 +1,15 @@
|
||||
[gd_scene format=3 uid="uid://byupuycr28u17"]
|
||||
|
||||
[node name="CopyConfirmationDialog" type="ConfirmationDialog"]
|
||||
oversampling_override = 1.0
|
||||
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,16 @@
|
||||
[gd_scene format=3 uid="uid://n2pm5se13638"]
|
||||
|
||||
[node name="DeleteExamplesConfirmationDialog" type="ConfirmationDialog"]
|
||||
oversampling_override = 1.0
|
||||
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,17 @@
|
||||
[gd_scene format=3 uid="uid://2ubjcuhlam2o"]
|
||||
|
||||
[node name="DeleteExamplesShortConfirmationDialog" type="ConfirmationDialog"]
|
||||
oversampling_override = 1.0
|
||||
title = "Delete Source Examples"
|
||||
initial_position = 2
|
||||
size = Vector2i(1024, 300)
|
||||
visible = true
|
||||
ok_button_text = "Yes"
|
||||
dialog_text = "This will delete the original examples folder from the plugin (inside of addons/).
|
||||
|
||||
Copies of the examples (outside of addons/) will not be affected.
|
||||
|
||||
Are you sure you would like to delete the examples folder?
|
||||
"
|
||||
dialog_autowrap = true
|
||||
cancel_button_text = "No"
|
||||
@@ -0,0 +1,12 @@
|
||||
[gd_scene format=3 uid="uid://doa4t485iflon"]
|
||||
|
||||
[node name="DestinationDialog" type="FileDialog"]
|
||||
oversampling_override = 1.0
|
||||
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://c8bnydo2t6vsu
|
||||
@@ -0,0 +1,84 @@
|
||||
[gd_scene load_steps=14 format=3 uid="uid://vr4wkvk734wg"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c8bnydo2t6vsu" path="res://addons/maaacks_game_template/installer/kenney_input_prompts_dialog.gd" id="1_nf1bc"]
|
||||
[ext_resource type="Texture2D" uid="uid://dxvbsbs428nj7" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-colored.png" id="2_0nqam"]
|
||||
[ext_resource type="Texture2D" uid="uid://5gjytq6nlww3" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-white.png" id="3_ynuxh"]
|
||||
[ext_resource type="Texture2D" uid="uid://cj4f8dma2647n" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-colored.png" id="4_dqbfh"]
|
||||
[ext_resource type="Texture2D" uid="uid://cj524k2rdjvjo" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-white.png" id="5_1tkva"]
|
||||
[ext_resource type="Texture2D" uid="uid://nqdhl41h0tpv" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-colored-2x.png" id="6_r3yyh"]
|
||||
[ext_resource type="Texture2D" uid="uid://df0qisbxrhsqa" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-white-2x.png" id="7_xgp8o"]
|
||||
[ext_resource type="Texture2D" uid="uid://1gr33hl6p8tu" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-colored-2x.png" id="8_ag5dy"]
|
||||
[ext_resource type="Texture2D" uid="uid://betu06qbgx5gf" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-white-2x.png" id="9_3b8mx"]
|
||||
[ext_resource type="Texture2D" uid="uid://cp7xvu3oujlnj" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-colored-vector.svg" id="10_ag5dy"]
|
||||
[ext_resource type="Texture2D" uid="uid://dl5p5qw3hp8y" path="res://addons/maaacks_game_template/assets/input-icons/icons-filled-white-vector.svg" id="11_3b8mx"]
|
||||
[ext_resource type="Texture2D" uid="uid://2xcu58kisr45" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-colored-vector.svg" id="12_rrkvx"]
|
||||
[ext_resource type="Texture2D" uid="uid://cf4s4f7tvltpp" path="res://addons/maaacks_game_template/assets/input-icons/icons-outlined-white-vector.svg" id="13_bkfjd"]
|
||||
|
||||
[node name="KenneyInputPromptsDialog" type="ConfirmationDialog"]
|
||||
oversampling_override = 1.0
|
||||
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,336 @@
|
||||
@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 DownloadAndExtract = MaaacksGameTemplatePlugin.DownloadAndExtract
|
||||
const RELATIVE_PATH_TO_CONFIGURE_SCENE = "scenes/menus/options_menu/input/input_icon_mapper.tscn"
|
||||
const REIMPORT_CHECK_DELAY : float = 0.5
|
||||
const OPEN_SCENE_DELAY : float = 0.5
|
||||
const MATCH_REGEX = """(\\[node name="InputIconMapper" instance=ExtResource\\("[0-9a-z_]+"\\)\\])[\\s\\S]*"""
|
||||
|
||||
const FILLED_WHITE_CONFIGURATION = """
|
||||
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 = """
|
||||
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 = """
|
||||
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 = """
|
||||
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.DownloadAndExtractStage.DOWNLOAD:
|
||||
_stage_label.text = "Downloading..."
|
||||
DownloadAndExtract.DownloadAndExtractStage.SAVE:
|
||||
_stage_label.text = "Saving..."
|
||||
DownloadAndExtract.DownloadAndExtractStage.EXTRACT:
|
||||
_stage_label.text = "Extracting..."
|
||||
DownloadAndExtract.DownloadAndExtractStage.DELETE:
|
||||
_stage_label.text = "Cleaning up..."
|
||||
DownloadAndExtract.DownloadAndExtractStage.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_mapper_path := copy_dir_path + RELATIVE_PATH_TO_CONFIGURE_SCENE
|
||||
var icon_mapper_string := FileAccess.get_file_as_string(input_mapper_path)
|
||||
var replacing_string := "$1\n"
|
||||
match(_configuration_index % 4):
|
||||
0:
|
||||
replacing_string += FILLED_COLOR_CONFIGURATION
|
||||
1:
|
||||
replacing_string += FILLED_WHITE_CONFIGURATION
|
||||
2:
|
||||
replacing_string += OUTLINED_COLOR_CONFIGURATION
|
||||
3:
|
||||
replacing_string += OUTLINED_WHITE_CONFIGURATION
|
||||
match(_configuration_index / 4):
|
||||
0:
|
||||
replacing_string = replacing_string.replace("Default", "Vector").replace(".png", ".svg")
|
||||
1:
|
||||
pass
|
||||
2:
|
||||
replacing_string = replacing_string.replace("Default", "Double")
|
||||
var regex = RegEx.new()
|
||||
regex.compile(MATCH_REGEX)
|
||||
icon_mapper_string = regex.sub(icon_mapper_string, replacing_string)
|
||||
var file_rewrite := FileAccess.open(input_mapper_path, FileAccess.WRITE)
|
||||
file_rewrite.store_string(icon_mapper_string)
|
||||
file_rewrite.close()
|
||||
if input_mapper_path in EditorInterface.get_open_scenes():
|
||||
EditorInterface.reload_scene_from_path(input_mapper_path)
|
||||
else:
|
||||
EditorInterface.open_scene_from_path(input_mapper_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://cl2gk653d5d6o
|
||||
@@ -0,0 +1,92 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://c56u7kqt1l8yp"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cl2gk653d5d6o" path="res://addons/maaacks_game_template/installer/kenney_input_prompts_installer.gd" id="1_ebstj"]
|
||||
[ext_resource type="PackedScene" uid="uid://vr4wkvk734wg" path="res://addons/maaacks_game_template/installer/kenney_input_prompts_dialog.tscn" id="1_pslk0"]
|
||||
[ext_resource type="PackedScene" uid="uid://5hhnbgqjwnic" path="res://addons/maaacks_game_template/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://bkno1by7i3hrb"
|
||||
|
||||
[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,8 @@
|
||||
@tool
|
||||
extends ConfirmationDialog
|
||||
|
||||
const MAIN_SCENE_UPDATE_TEXT = "Would you like to update the project's main scene?\n\nCurrent:\n%s\n\nNew:\n%s\n"
|
||||
|
||||
func set_main_scene_text(new_scene_path):
|
||||
var current_scene_path : String = ProjectSettings.get_setting("application/run/main_scene", "")
|
||||
dialog_text = MAIN_SCENE_UPDATE_TEXT % [current_scene_path, new_scene_path]
|
||||
@@ -0,0 +1 @@
|
||||
uid://exfk51fr7yx0
|
||||
@@ -0,0 +1,18 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://gblkpm37lq1j"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://exfk51fr7yx0" path="res://addons/maaacks_game_template/installer/main_scene_confirmation_dialog.gd" id="1_1ydgd"]
|
||||
|
||||
[node name="MainSceneConfirmationDialog" type="ConfirmationDialog"]
|
||||
oversampling_override = 1.0
|
||||
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"
|
||||
script = ExtResource("1_1ydgd")
|
||||
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,"location":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,"location":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,"location":0,"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,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":6,"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,"location":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,"location":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,14 @@
|
||||
[gd_scene format=3 uid="uid://cukfpfjy3827p"]
|
||||
|
||||
[node name="PlayOpeningConfirmationDialog" type="ConfirmationDialog"]
|
||||
oversampling_override = 1.0
|
||||
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,79 @@
|
||||
@tool
|
||||
extends RichTextLabel
|
||||
|
||||
const HEADING_STRING_REPLACEMENT = "$1[font_size=%d]$2[/font_size]"
|
||||
const BOLD_HEADING_STRING_REPLACEMENT = "$1[b][font_size=%d]$2[/font_size][/b]"
|
||||
|
||||
@export_group("Font Sizes")
|
||||
@export var h1_font_size: int
|
||||
@export var h2_font_size: int
|
||||
@export var h3_font_size: int
|
||||
@export var h4_font_size: int
|
||||
@export var h5_font_size: int
|
||||
@export var h6_font_size: int
|
||||
@export var bold_headings : bool
|
||||
@export_group("Extra Options")
|
||||
@export var disable_images : bool = false
|
||||
@export var disable_urls : bool = false
|
||||
@export var disable_bolds : bool = false
|
||||
|
||||
func regex_replace_imgs(markdown_text:String) -> String:
|
||||
var regex = RegEx.new()
|
||||
var match_string := "<img .* src=\"(.*)\" \\/>"
|
||||
var replace_string := ""
|
||||
if not disable_images:
|
||||
replace_string = "$1"
|
||||
regex.compile(match_string)
|
||||
return regex.sub(markdown_text, replace_string, true)
|
||||
|
||||
func regex_replace_urls(markdown_text:String) -> String:
|
||||
var regex = RegEx.new()
|
||||
var match_string := "(https:\\/\\/.*)($|\\s)"
|
||||
var replace_string := "$1"
|
||||
if not disable_urls:
|
||||
replace_string = "[url=$1]$1[/url]"
|
||||
regex.compile(match_string)
|
||||
return regex.sub(markdown_text, replace_string, true)
|
||||
|
||||
func regex_replace_bolds(markdown_text:String) -> String:
|
||||
var regex = RegEx.new()
|
||||
var match_string := "\\*\\*(.*)\\*\\*"
|
||||
var replace_string := "$1"
|
||||
if not disable_bolds:
|
||||
replace_string = "[b]$1[/b]"
|
||||
regex.compile(match_string)
|
||||
return regex.sub(markdown_text, replace_string, true)
|
||||
|
||||
func regex_replace_titles(markdown_text:String) -> String:
|
||||
var iter = 0
|
||||
var heading_font_sizes : Array[int] = [
|
||||
h1_font_size,
|
||||
h2_font_size,
|
||||
h3_font_size,
|
||||
h4_font_size,
|
||||
h5_font_size,
|
||||
h6_font_size]
|
||||
for heading_font_size in heading_font_sizes:
|
||||
iter += 1
|
||||
var regex = RegEx.new()
|
||||
var match_string : String = "([^#]|^)#{%d}\\s([^\n]*)" % iter
|
||||
var replace_string := HEADING_STRING_REPLACEMENT % [heading_font_size]
|
||||
if bold_headings:
|
||||
replace_string = BOLD_HEADING_STRING_REPLACEMENT % [heading_font_size]
|
||||
regex.compile(match_string)
|
||||
markdown_text = regex.sub(markdown_text, replace_string, true)
|
||||
return markdown_text
|
||||
|
||||
func from_release_notes(markdown_text : String) -> void:
|
||||
markdown_text = regex_replace_imgs(markdown_text)
|
||||
markdown_text = regex_replace_urls(markdown_text)
|
||||
markdown_text = regex_replace_bolds(markdown_text)
|
||||
markdown_text = regex_replace_titles(markdown_text)
|
||||
text = markdown_text
|
||||
|
||||
func _on_meta_clicked(meta: String) -> void:
|
||||
if meta.begins_with("https://"):
|
||||
var _err = OS.shell_open(meta)
|
||||
|
||||
func _ready() -> void:
|
||||
meta_clicked.connect(_on_meta_clicked)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cgv1xnmh7vr66
|
||||
@@ -0,0 +1,14 @@
|
||||
[gd_scene format=3 uid="uid://bie1wby7a56or"]
|
||||
|
||||
[node name="SetupCompleteDialog" type="AcceptDialog"]
|
||||
oversampling_override = 1.0
|
||||
title = "Setup Complete!"
|
||||
initial_position = 2
|
||||
size = Vector2i(1032, 360)
|
||||
visible = true
|
||||
dialog_text = "Thanks for installing Maaack's Minimal Game Template!
|
||||
|
||||
Go to `Project > Tools > Run Maaack's Minimal Game Template Setup...` for extra features.
|
||||
Each step of the setup can also be revisited.
|
||||
|
||||
See the included README for next steps and additional documentation."
|
||||
125
addons/maaacks_game_template/installer/setup_wizard.gd
Normal file
125
addons/maaacks_game_template/installer/setup_wizard.gd
Normal file
@@ -0,0 +1,125 @@
|
||||
@tool
|
||||
extends AcceptDialog
|
||||
|
||||
@export_file("*.tscn") var check_version_scene_path : String
|
||||
@export_dir var input_prompts_directory_path : String
|
||||
|
||||
@onready var plugin_label : Label = %PluginLabel
|
||||
@onready var update_label : Label = %UpdateLabel
|
||||
@onready var update_check_box : CheckBox = %UpdateCheckBox
|
||||
@onready var update_button : Button = %UpdateButton
|
||||
@onready var copy_check_box : CheckBox = %CopyCheckBox
|
||||
@onready var copy_button : Button = %CopyButton
|
||||
@onready var delete_check_box : CheckBox = %DeleteCheckBox
|
||||
@onready var delete_button : Button = %DeleteButton
|
||||
@onready var set_main_scene_check_box : CheckBox = %SetMainSceneCheckBox
|
||||
@onready var set_main_scene_button : Button = %SetMainSceneButton
|
||||
@onready var set_default_theme_check_box : CheckBox = %SetDefaultThemeCheckBox
|
||||
@onready var set_default_theme_button : Button = %SetDefaultThemeButton
|
||||
@onready var add_input_icons_check_box : CheckBox = %AddInputIconsCheckBox
|
||||
@onready var add_input_icons_button : Button = %AddInputIconsButton
|
||||
|
||||
func _refresh_plugin_details() -> void:
|
||||
for enabled_plugin in ProjectSettings.get_setting("editor_plugins/enabled"):
|
||||
if enabled_plugin.contains(MaaacksGameTemplatePlugin.get_settings_path()):
|
||||
var config := ConfigFile.new()
|
||||
var error = config.load(enabled_plugin)
|
||||
if error != OK:
|
||||
return
|
||||
var current_plugin_version : String = config.get_value("plugin", "version", "0.0.0")
|
||||
var plugin_name : String = config.get_value("plugin", "name", "Plugin")
|
||||
plugin_label.text = "%s v%s" % [plugin_name, current_plugin_version]
|
||||
|
||||
func _show_plugin_versions_match() -> void:
|
||||
update_label.text = "Using Latest Version"
|
||||
update_check_box.button_pressed = true
|
||||
update_button.disabled = true
|
||||
|
||||
func _enable_update_plugin_tool_option(tag_name : String) -> void:
|
||||
update_label.text = "Update to Latest Version v%s" % tag_name
|
||||
update_button.disabled = false
|
||||
|
||||
func _open_check_plugin_version() -> void:
|
||||
if check_version_scene_path.is_empty():
|
||||
push_warning("Variable \"check_version_scene_path\" is not set")
|
||||
return
|
||||
if ProjectSettings.get_setting(MaaacksGameTemplatePlugin.get_settings_path() + "disable_update_check", false):
|
||||
update_label.text = "Check for Latest Version"
|
||||
update_button.disabled = false
|
||||
return
|
||||
var check_version_scene : PackedScene = load(check_version_scene_path)
|
||||
var check_version_instance : Node = check_version_scene.instantiate()
|
||||
check_version_instance.auto_start = true
|
||||
check_version_instance.new_version_detected.connect(_enable_update_plugin_tool_option)
|
||||
check_version_instance.versions_matched.connect(_show_plugin_versions_match)
|
||||
add_child(check_version_instance)
|
||||
|
||||
func _refresh_copy_and_delete_examples() -> void:
|
||||
var examples_path = MaaacksGameTemplatePlugin.instance.get_plugin_examples_path()
|
||||
if MaaacksGameTemplatePlugin.get_copy_path() != examples_path:
|
||||
copy_check_box.button_pressed = true
|
||||
var dir := DirAccess.open("res://")
|
||||
if dir.dir_exists(examples_path):
|
||||
copy_button.disabled = false
|
||||
delete_button.disabled = false
|
||||
else:
|
||||
delete_check_box.button_pressed = true
|
||||
|
||||
func _refresh_main_scene() -> void:
|
||||
if MaaacksGameTemplatePlugin.instance.is_main_scene_set():
|
||||
set_main_scene_check_box.button_pressed = true
|
||||
else:
|
||||
set_main_scene_button.disabled = false
|
||||
|
||||
func _refresh_default_theme() -> void:
|
||||
set_default_theme_button.disabled = false
|
||||
if ProjectSettings.get_setting("gui/theme/custom", "") != "":
|
||||
set_default_theme_check_box.button_pressed = true
|
||||
|
||||
func _refresh_input_prompts() -> void:
|
||||
if input_prompts_directory_path.is_empty():
|
||||
push_warning("Variable \"input_prompts_directory_path\" is not set")
|
||||
return
|
||||
if DirAccess.dir_exists_absolute(input_prompts_directory_path):
|
||||
add_input_icons_check_box.button_pressed = true
|
||||
add_input_icons_button.disabled = false
|
||||
|
||||
func _refresh_options():
|
||||
_refresh_plugin_details()
|
||||
_open_check_plugin_version()
|
||||
_refresh_copy_and_delete_examples()
|
||||
_refresh_main_scene()
|
||||
_refresh_default_theme()
|
||||
_refresh_input_prompts()
|
||||
|
||||
func _ready():
|
||||
_refresh_options()
|
||||
|
||||
func _on_update_button_pressed():
|
||||
if ProjectSettings.get_setting(MaaacksGameTemplatePlugin.get_settings_path() + "disable_update_check", false):
|
||||
ProjectSettings.set_setting(MaaacksGameTemplatePlugin.get_settings_path() + "disable_update_check", false)
|
||||
_open_check_plugin_version()
|
||||
return
|
||||
else:
|
||||
tree_exited.connect(func(): MaaacksGameTemplatePlugin.instance.open_update_plugin())
|
||||
queue_free()
|
||||
|
||||
func _on_copy_button_pressed():
|
||||
tree_exited.connect(func(): MaaacksGameTemplatePlugin.instance.open_copy_and_edit_dialog())
|
||||
queue_free()
|
||||
|
||||
func _on_delete_button_pressed():
|
||||
tree_exited.connect(func(): MaaacksGameTemplatePlugin.instance.open_delete_examples_short_confirmation_dialog())
|
||||
queue_free()
|
||||
|
||||
func _on_set_main_scene_button_pressed():
|
||||
tree_exited.connect(func(): MaaacksGameTemplatePlugin.instance.open_main_scene_confirmation_dialog(MaaacksGameTemplatePlugin.get_copy_path()))
|
||||
queue_free()
|
||||
|
||||
func _on_set_default_theme_button_pressed():
|
||||
tree_exited.connect(func(): MaaacksGameTemplatePlugin.instance.open_theme_selection_dialog(MaaacksGameTemplatePlugin.get_copy_path()))
|
||||
queue_free()
|
||||
|
||||
func _on_add_input_icons_button_pressed():
|
||||
tree_exited.connect(func(): MaaacksGameTemplatePlugin.instance.open_input_icons_dialog())
|
||||
queue_free()
|
||||
@@ -0,0 +1 @@
|
||||
uid://dres77mrg8fxf
|
||||
153
addons/maaacks_game_template/installer/setup_wizard.tscn
Normal file
153
addons/maaacks_game_template/installer/setup_wizard.tscn
Normal file
@@ -0,0 +1,153 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://ffy0rjxas5op"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dres77mrg8fxf" path="res://addons/maaacks_game_template/installer/setup_wizard.gd" id="1_jck5m"]
|
||||
|
||||
[node name="SetupWizardDialog" type="AcceptDialog"]
|
||||
oversampling_override = 1.0
|
||||
title = "Setup Wizard"
|
||||
initial_position = 2
|
||||
size = Vector2i(576, 540)
|
||||
visible = true
|
||||
ok_button_text = "Done"
|
||||
dialog_autowrap = true
|
||||
script = ExtResource("1_jck5m")
|
||||
check_version_scene_path = "res://addons/maaacks_game_template/installer/check_plugin_version.tscn"
|
||||
input_prompts_directory_path = "res://assets/kenney_input-prompts/"
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
custom_minimum_size = Vector2(560, 483)
|
||||
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="PluginLabel" type="Label" parent="VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(384, 0)
|
||||
layout_mode = 2
|
||||
autowrap_mode = 3
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="StepsContainer" type="GridContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/h_separation = 12
|
||||
columns = 3
|
||||
|
||||
[node name="UpdateLabel" type="Label" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Update to Latest Version"
|
||||
|
||||
[node name="UpdateCheckBox" type="CheckBox" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
|
||||
[node name="UpdateButton" type="Button" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Run"
|
||||
|
||||
[node name="CopyLabel" type="Label" parent="VBoxContainer/StepsContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Copy Example Files"
|
||||
|
||||
[node name="CopyCheckBox" type="CheckBox" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
|
||||
[node name="CopyButton" type="Button" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Run"
|
||||
|
||||
[node name="DeleteLabel" type="Label" parent="VBoxContainer/StepsContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Delete Example Files"
|
||||
|
||||
[node name="DeleteCheckBox" type="CheckBox" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
|
||||
[node name="DeleteButton" type="Button" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Run"
|
||||
|
||||
[node name="SetMainSceneLabel" type="Label" parent="VBoxContainer/StepsContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Set the Main Scene"
|
||||
|
||||
[node name="SetMainSceneCheckBox" type="CheckBox" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
|
||||
[node name="SetMainSceneButton" type="Button" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Run"
|
||||
|
||||
[node name="SetDefaultThemeLabel" type="Label" parent="VBoxContainer/StepsContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Set the Default Theme"
|
||||
|
||||
[node name="SetDefaultThemeCheckBox" type="CheckBox" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
|
||||
[node name="SetDefaultThemeButton" type="Button" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Run"
|
||||
|
||||
[node name="AddInputIconsLabel" type="Label" parent="VBoxContainer/StepsContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Add Input Prompt Icons"
|
||||
|
||||
[node name="AddInputIconsCheckBox" type="CheckBox" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
|
||||
[node name="AddInputIconsButton" type="Button" parent="VBoxContainer/StepsContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Run"
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/StepsContainer/UpdateButton" to="." method="_on_update_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/StepsContainer/CopyButton" to="." method="_on_copy_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/StepsContainer/DeleteButton" to="." method="_on_delete_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/StepsContainer/SetMainSceneButton" to="." method="_on_set_main_scene_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/StepsContainer/SetDefaultThemeButton" to="." method="_on_set_default_theme_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/StepsContainer/AddInputIconsButton" to="." method="_on_add_input_icons_button_pressed"]
|
||||
@@ -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://cqlg20n7vu4jx
|
||||
@@ -0,0 +1,179 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://cmqcqq54rj454"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cqlg20n7vu4jx" 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/nodes/utilities/file_lister.gd" id="2_luhgx"]
|
||||
|
||||
[node name="ThemeSelectionDialog" type="ConfirmationDialog"]
|
||||
oversampling_override = 1.0
|
||||
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 = "Set the projects default theme to a start theme 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"]
|
||||
174
addons/maaacks_game_template/installer/update_plugin.gd
Normal file
174
addons/maaacks_game_template/installer/update_plugin.gd
Normal file
@@ -0,0 +1,174 @@
|
||||
@tool
|
||||
extends Node
|
||||
## Script for updating the version of a plugin to the latest release on GitHub.
|
||||
|
||||
signal update_completed
|
||||
|
||||
const DownloadAndExtract = MaaacksGameTemplatePlugin.DownloadAndExtract
|
||||
const APIClient = MaaacksGameTemplatePlugin.APIClient
|
||||
const ReleaseNotesLabel = preload("./release_notes_label.gd")
|
||||
|
||||
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"
|
||||
|
||||
## The directory of the plugin to update. Typically in res://addons/.
|
||||
@export var plugin_directory : String
|
||||
## The URL of the GitHub repo to pull new releases.
|
||||
@export var plugin_github_url : String :
|
||||
set(value):
|
||||
plugin_github_url = value
|
||||
_update_urls()
|
||||
@export_group("Advanced")
|
||||
## If true, automatically download the new version when ready.
|
||||
@export var auto_start : bool = false
|
||||
## Text to remove from the tag before showing to the user.
|
||||
@export var replace_tag_name : String = "v"
|
||||
## The default lowest version to display.
|
||||
@export var default_version : String = "0.0.0"
|
||||
## If true, test getting the new version.
|
||||
## Replace with @export_tool_button for Godot 4.4+
|
||||
@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_notes_label : ReleaseNotesLabel = %ReleaseNotesLabel
|
||||
@onready var _update_label : Label = %UpdateLabel
|
||||
@onready var _warning_message_button : LinkButton = %WarningMessageButton
|
||||
@onready var _warning_message_label : Label = %WarningMessageLabel
|
||||
@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
|
||||
if response_body.is_empty():
|
||||
push_error("Response was an empty 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_notes_label.from_release_notes(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_warning_message_button_pressed():
|
||||
_warning_message_label.show()
|
||||
_warning_message_button.hide()
|
||||
|
||||
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.DownloadAndExtractStage.DOWNLOAD:
|
||||
_stage_label.text = "Downloading..."
|
||||
DownloadAndExtract.DownloadAndExtractStage.SAVE:
|
||||
_stage_label.text = "Saving..."
|
||||
DownloadAndExtract.DownloadAndExtractStage.EXTRACT:
|
||||
_stage_label.text = "Extracting..."
|
||||
DownloadAndExtract.DownloadAndExtractStage.DELETE:
|
||||
_stage_label.text = "Cleaning up..."
|
||||
DownloadAndExtract.DownloadAndExtractStage.NONE:
|
||||
_installing_dialog.hide()
|
||||
@@ -0,0 +1 @@
|
||||
uid://txkhnw0u8jy4
|
||||
158
addons/maaacks_game_template/installer/update_plugin.tscn
Normal file
158
addons/maaacks_game_template/installer/update_plugin.tscn
Normal file
@@ -0,0 +1,158 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://d28bi7wdv8hbp"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://txkhnw0u8jy4" path="res://addons/maaacks_game_template/installer/update_plugin.gd" id="1_s6qpc"]
|
||||
[ext_resource type="PackedScene" uid="uid://cf0hkngq1mgfy" path="res://addons/maaacks_game_template/utilities/api_client.tscn" id="2_s6pdq"]
|
||||
[ext_resource type="PackedScene" uid="uid://5hhnbgqjwnic" path="res://addons/maaacks_game_template/utilities/download_and_extract.tscn" id="3_s6pdq"]
|
||||
[ext_resource type="Script" uid="uid://cgv1xnmh7vr66" path="res://addons/maaacks_game_template/installer/release_notes_label.gd" id="4_1amwf"]
|
||||
|
||||
[node name="UpdatePlugin" type="Node"]
|
||||
script = ExtResource("1_s6qpc")
|
||||
plugin_directory = "maaacks_game_template"
|
||||
plugin_github_url = "https://github.com/Maaack/Godot-Minimal-Game-Template"
|
||||
|
||||
[node name="APIClient" parent="." instance=ExtResource("2_s6pdq")]
|
||||
api_url = "https://api.github.com/repos/Maaack/Godot-Minimal-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="WarningMessageButton" type="LinkButton" parent="UpdateConfirmationDialog/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Warning About Updating"
|
||||
|
||||
[node name="WarningMessageLabel" type="Label" parent="UpdateConfirmationDialog/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(624, 205)
|
||||
layout_mode = 2
|
||||
text = "Not all updates are backwards compatible!
|
||||
|
||||
Updating can cause issues with previously copied examples. It is recommended to delete any copied example files before starting an update, if it is an option. Otherwise, pay attention to the Release Notes for an idea for how changes may impact your project.
|
||||
|
||||
Lastly, save your work and proceed with caution."
|
||||
autowrap_mode = 3
|
||||
|
||||
[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="ReleaseNotesLabel" 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
|
||||
focus_mode = 2
|
||||
bbcode_enabled = true
|
||||
selection_enabled = true
|
||||
script = ExtResource("4_1amwf")
|
||||
h1_font_size = 64
|
||||
h2_font_size = 48
|
||||
h3_font_size = 32
|
||||
h4_font_size = 24
|
||||
h5_font_size = 16
|
||||
h6_font_size = 12
|
||||
bold_headings = true
|
||||
|
||||
[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/WarningMessageButton" to="." method="_on_warning_message_button_pressed"]
|
||||
[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