4 ## Script that checks for new versions and can install them.
6 signal update_check_completed(result:UpdateCheckResult)
7 signal downdload_completed(result:DownloadResult)
9 enum UpdateCheckResult {UPDATE_AVAILABLE, UP_TO_DATE, NO_ACCESS}
10 enum DownloadResult {SUCCESS, FAILURE}
11 enum ReleaseState {ALPHA, BETA, STABLE}
13 const REMOTE_RELEASES_URL := "https://api.github.com/repos/dialogic-godot/dialogic/releases"
14 const TEMP_FILE_NAME := "user://temp.zip"
16 var current_version := ""
17 var update_info: Dictionary
18 var current_info: Dictionary
20 var version_indicator: Button
22 func _ready() -> void:
23 request_update_check()
25 setup_version_indicator()
29 func get_current_version() -> String:
30 var plugin_cfg := ConfigFile.new()
31 plugin_cfg.load("res://addons/dialogic/plugin.cfg")
32 return plugin_cfg.get_value('plugin', 'version', 'unknown version')
35 func request_update_check() -> void:
36 if $UpdateCheckRequest.get_http_client_status() == HTTPClient.STATUS_DISCONNECTED:
37 $UpdateCheckRequest.request(REMOTE_RELEASES_URL)
40 func _on_UpdateCheck_request_completed(result:int, response_code:int, headers:PackedStringArray, body:PackedByteArray) -> void:
41 if result != HTTPRequest.RESULT_SUCCESS:
42 update_check_completed.emit(UpdateCheckResult.NO_ACCESS)
45 # Work out the next version from the releases information on GitHub
46 var response: Variant = JSON.parse_string(body.get_string_from_utf8())
47 if typeof(response) != TYPE_ARRAY: return
50 var current_release_info := get_release_tag_info(get_current_version())
52 # GitHub releases are in order of creation, not order of version
53 var versions: Array = (response as Array).filter(compare_versions.bind(current_release_info))
54 if versions.size() > 0:
55 update_info = versions[0]
56 update_check_completed.emit(UpdateCheckResult.UPDATE_AVAILABLE)
58 update_info = current_info
59 update_check_completed.emit(UpdateCheckResult.UP_TO_DATE)
62 func compare_versions(release, current_release_info:Dictionary) -> bool:
63 var checked_release_info := get_release_tag_info(release.tag_name)
65 if checked_release_info.major < current_release_info.major:
68 if checked_release_info.minor < current_release_info.minor:
71 if checked_release_info.state < current_release_info.state:
74 elif checked_release_info.state == current_release_info.state:
75 if checked_release_info.state_version < current_release_info.state_version:
78 if checked_release_info.state_version == current_release_info.state_version:
79 current_info = release
82 if checked_release_info.state == ReleaseState.STABLE:
83 if checked_release_info.minor == current_release_info.minor:
84 current_info = release
90 func get_release_tag_info(release_tag:String) -> Dictionary:
91 release_tag = release_tag.strip_edges().trim_prefix('v')
92 release_tag = release_tag.substr(0, release_tag.find('('))
93 release_tag = release_tag.to_lower()
95 var regex := RegEx.create_from_string(r"(?<major>\d+\.\d+)(-(?<state>alpha|beta)-)?(?(2)(?<stateversion>\d*)|\.(?<minor>\d*))?")
97 var result: RegExMatch = regex.search(release_tag)
101 var info: Dictionary = {'tag':release_tag}
102 info['major'] = float(result.get_string('major'))
103 info['minor'] = int(result.get_string('minor'))
105 match result.get_string('state'):
107 info['state'] = ReleaseState.ALPHA
109 info['state'] = ReleaseState.BETA
111 info['state'] = ReleaseState.STABLE
113 info['state_version'] = int(result.get_string('stateversion'))
118 func request_update_download() -> void:
119 # Safeguard the actual dialogue manager repo from accidentally updating itself
120 if DirAccess.dir_exists_absolute("res://test-project/"):
121 prints("[Dialogic] Looks like you are working on the addon. You can't update the addon from within itself.")
122 downdload_completed.emit(DownloadResult.FAILURE)
125 $DownloadRequest.request(update_info.zipball_url)
128 func _on_DownloadRequest_completed(result:int, response_code:int, headers:PackedStringArray, body:PackedByteArray):
129 if result != HTTPRequest.RESULT_SUCCESS:
130 downdload_completed.emit(DownloadResult.FAILURE)
133 # Save the downloaded zip
134 var zip_file: FileAccess = FileAccess.open(TEMP_FILE_NAME, FileAccess.WRITE)
135 zip_file.store_buffer(body)
138 OS.move_to_trash(ProjectSettings.globalize_path("res://addons/dialogic"))
140 var zip_reader: ZIPReader = ZIPReader.new()
141 zip_reader.open(TEMP_FILE_NAME)
142 var files: PackedStringArray = zip_reader.get_files()
144 var base_path: String = files[0].path_join('addons/')
146 if not "dialogic/" in path:
149 var new_file_path: String = path.replace(base_path, "")
150 if path.ends_with("/"):
151 DirAccess.make_dir_recursive_absolute("res://addons/".path_join(new_file_path))
153 var file: FileAccess = FileAccess.open("res://addons/".path_join(new_file_path), FileAccess.WRITE)
154 file.store_buffer(zip_reader.read_file(path))
157 DirAccess.remove_absolute(TEMP_FILE_NAME)
159 downdload_completed.emit(DownloadResult.SUCCESS)
162 ###################### SOME UI MANAGEMENT #####################################
163 ################################################################################
165 func setup_version_indicator() -> void:
166 version_indicator = %Sidebar.get_node('%CurrentVersion')
167 version_indicator.pressed.connect($Window/UpdateInstallWindow.open)
168 version_indicator.text = get_current_version()
171 func _on_update_check_completed(result:int):
172 var result_color: Color
174 UpdateCheckResult.UPDATE_AVAILABLE:
175 result_color = version_indicator.get_theme_color("warning_color", "Editor")
176 version_indicator.icon = version_indicator.get_theme_icon("StatusWarning", "EditorIcons")
177 $Window/UpdateInstallWindow.load_info(update_info, result)
178 UpdateCheckResult.UP_TO_DATE:
179 result_color = version_indicator.get_theme_color("success_color", "Editor")
180 version_indicator.icon = version_indicator.get_theme_icon("StatusSuccess", "EditorIcons")
181 $Window/UpdateInstallWindow.load_info(current_info, result)
182 UpdateCheckResult.NO_ACCESS:
183 result_color = version_indicator.get_theme_color("success_color", "Editor")
184 version_indicator.icon = version_indicator.get_theme_icon("GuiRadioCheckedDisabled", "EditorIcons")
185 $Window/UpdateInstallWindow.load_info(update_info, result)
187 version_indicator.add_theme_color_override('font_color', result_color)
188 version_indicator.add_theme_color_override('font_hover_color', result_color.lightened(0.5))
189 version_indicator.add_theme_color_override('font_pressed_color', result_color)
190 version_indicator.add_theme_color_override('font_focus_color', result_color)