Files
tekton/addons/godotsteam/editor/updates/updates.gd
T
2026-04-29 01:36:49 +08:00

187 lines
5.9 KiB
GDScript

@tool
extends MarginContainer
###
# Super-huge thanks to Nathan Hoad and Marcus Skov for ideas and inspiration on how to create a
# plug-in updater.
###
const TEMP_FILE = "user://update.zip"
const VERSION_URL: StringName = "https://godotengine.org/asset-library/api/asset/2445"
var download_location: String = ""
var downloading_update: bool = false
# This will act as both our version checker and update downloader
var http_request: HTTPRequest = null
var is_actively_downloading: bool = false
var new_version: String = ""
@onready var cancel_button: Button = %CancelButton
@onready var downloading: ProgressBar = %Downloading
@onready var install_button: Button = %InstallButton
@onready var installed_label: Label = %InstalledLabel
@onready var update_label: Label = %UpdateLabel
@onready var update_button: Button = %UpdateButton
func _ready() -> void:
connect_signals()
set_defaults()
check_for_updates()
func _process(delta: float) -> void:
if is_actively_downloading:
downloading.value = http_request.get_downloaded_bytes() * 100 / http_request.get_body_size()
#region Setup
func set_defaults() -> void:
downloading.value = 0
installed_label.text = "Installed version %s" % Steam.get_godotsteam_version()
update_button.text = "Up-to-date"
update_button.disabled = true
update_label.text = ""
updating_visibility(false, false, false, true)
#endregion
#region Signals
func connect_signals() -> void:
cancel_button.pressed.connect(_on_cancel_pressed)
install_button.pressed.connect(_on_install_pressed)
update_button.pressed.connect(_on_update_pressed)
#endregion
#region Checking for updates
func check_for_updates() -> void:
if not ProjectSettings.get_setting("steam/updates/godotsteam/check_for_updates"):
return
http_request = HTTPRequest.new()
add_child(http_request)
http_request.request_completed.connect(_on_http_request_completed)
if http_request.request(VERSION_URL) != OK:
printerr("Failed to request GodotSteam plug-in remote current version")
func _on_http_request_completed(result: int, _response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
http_request.request_completed.disconnect(_on_http_request_completed)
http_request.queue_free()
if result != HTTPRequest.RESULT_SUCCESS:
return
var response = JSON.parse_string(body.get_string_from_utf8())
if response == null:
return
download_location = response.download_url
new_version = response.version_string
if convert_version(new_version) > convert_version(Steam.get_godotsteam_version()):
print("New GodotSteam version %s available" % new_version)
update_label.text = "New version %s" % new_version
update_button.text = "Download"
update_button.disabled = false
#endregion
#region Updating versions
func _on_cancel_pressed() -> void:
updating_visibility(false, false, false, true)
if is_actively_downloading:
http_request.cancel_request()
http_request.queue_free()
is_actively_downloading = false
update_label.text = "Canceling %s plug-in update download" % new_version
else:
DirAccess.remove_absolute(TEMP_FILE)
update_label.text = "Canceling %s plug-in update and deleting temporary files" % new_version
update_button.text = "Download"
update_button.disabled = false
update_label.text = "New version %s" % new_version
func _on_install_pressed() -> void:
print("Removing older GodotSteam %s plug-in" % Steam.get_godotsteam_version())
OS.move_to_trash(ProjectSettings.globalize_path("res://addons/godotsteam"))
update_button.text = "Unpacking"
print("Unpacking new %s plug-in" % new_version)
var zip_reader: ZIPReader = ZIPReader.new()
zip_reader.open(TEMP_FILE)
var files: PackedStringArray = zip_reader.get_files()
var base_path := files[1]
# Remove archive folder
files.remove_at(0)
# Remove assets folder
files.remove_at(0)
for path in files:
var new_file_path: String = path.replace(base_path, "")
if path.ends_with("/"):
DirAccess.make_dir_recursive_absolute("res://addons/%s" % new_file_path)
else:
var file: FileAccess = FileAccess.open("res://addons/%s" % new_file_path, FileAccess.WRITE)
file.store_buffer(zip_reader.read_file(path))
zip_reader.close()
restart_post_update()
func _on_update_pressed() -> void:
is_actively_downloading = true
update_label.text = "Downloading %s plug-in update, please wait" % new_version
updating_visibility(true, true, false, false)
http_request = HTTPRequest.new()
add_child(http_request)
http_request.request_completed.connect(_on_download_request_completed)
if http_request.request(download_location) != OK:
printerr("Failed to request %s plug-in update download" % new_version)
is_actively_downloading = false
update_button.text = "Failed"
update_button.disabled = false
return
func _on_download_request_completed(result: int, _response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
http_request.request_completed.disconnect(_on_download_request_completed)
http_request.queue_free()
is_actively_downloading = false
updating_visibility(true, false, true, false)
if result != HTTPRequest.RESULT_SUCCESS:
printerr("Failed to download new GodotSteam version %s" % result)
update_button.disabled = false
return
update_label.text = "Update downloaded, ready to install %s" % new_version
var zip_file: FileAccess = FileAccess.open(TEMP_FILE, FileAccess.WRITE)
zip_file.store_buffer(body)
zip_file.close()
func restart_post_update() -> void:
update_button.text = "Restarting"
update_label.text = "Updated to version %s, restarting the editor" % new_version
DirAccess.remove_absolute(TEMP_FILE)
EditorInterface.restart_editor(true)
#endregion
#region Helpers
func convert_version(version_string: String) -> int:
return int(version_string.replace(".", "").rpad(4, "0"))
func updating_visibility(cancel: bool, download: bool, install: bool, update: bool) -> void:
cancel_button.visible = cancel
downloading.visible = download
install_button.visible = install
update_button.visible = update
#endregion