thegates/app/scripts/ui/world/loading_status.gd
2025-08-20 00:29:40 +07:00

162 lines
4.3 KiB
GDScript

extends Control
enum ProgressStatus {
CONNECTING,
DOWNLOADING,
STARTING,
ERROR
}
class DownloadItem:
var body_size: int
var downloaded_bytes: int
@export var gate_events: GateEvents
@export var progress_bar_background: Control
@export var progress_bar_error: Control
@export var progress_bar: Control
@export var label: Label
const TWEEN_DURATION_S = 0.2
const SPEED_DELAY_MS = 300
const ZERO_SPEED_DELAY_MS = 2000
var download_items: Dictionary
# For calculating speed
var last_bytes: int
var last_ticks: int
var last_speed: String
var last_is_zero: bool
var first_zero_ticks: int
func _ready() -> void:
gate_events.gate_info_loaded.connect(on_gate_info_loaded)
gate_events.gate_entered.connect(on_gate_entered)
gate_events.gate_error.connect(on_gate_error)
set_progress("Connecting...", ProgressStatus.CONNECTING)
func on_gate_info_loaded(_gate: Gate) -> void:
gate_events.download_progress.connect(show_progress)
last_ticks = Time.get_ticks_msec()
func show_progress(url: String, body_size: int, downloaded_bytes: int) -> void:
if body_size < 0: return
var item = download_items.get_or_add(url, DownloadItem.new()) as DownloadItem
item.body_size = body_size
item.downloaded_bytes = downloaded_bytes
var sum_downloaded_bytes = get_sum(&"downloaded_bytes")
var sum_body_size = get_sum(&"body_size")
var downloaded = StringTools.bytes_to_string(sum_downloaded_bytes)
var body = StringTools.bytes_to_string(sum_body_size)
var speed = get_speed(sum_downloaded_bytes)
var text = "Downloading resources — %s of %s (%s/sec)" % [downloaded, body, speed]
var progress = float(sum_downloaded_bytes) / sum_body_size
set_progress(text, ProgressStatus.DOWNLOADING, progress)
func get_sum(property: StringName) -> int:
var result: int = 0
for item in download_items.values():
result += item.get(property)
return result
func get_speed(bytes: int) -> String:
var delta_bytes = bytes - last_bytes
var delta_ticks = Time.get_ticks_msec() - last_ticks
if delta_ticks < SPEED_DELAY_MS and not last_speed.is_empty() and not last_is_zero:
return last_speed
var bytes_sec = 0
if delta_bytes != 0 and delta_ticks != 0:
bytes_sec = int(delta_bytes / (delta_ticks / 1000.0))
if should_write_current_speed(bytes_sec):
last_bytes = bytes
last_ticks = Time.get_ticks_msec()
last_speed = StringTools.bytes_to_string(bytes_sec)
return last_speed
func should_write_current_speed(bytes_sec: int) -> bool:
if last_speed.is_empty():
last_is_zero = bytes_sec == 0
return true
if bytes_sec != 0:
last_is_zero = false
return true
if not last_is_zero:
first_zero_ticks = Time.get_ticks_msec()
last_is_zero = true
return false
var delta_zero_tiks = Time.get_ticks_msec() - first_zero_ticks
if delta_zero_tiks < ZERO_SPEED_DELAY_MS:
return false
return true
func on_gate_entered() -> void:
gate_events.download_progress.disconnect(show_progress)
set_progress("Starting the gate...", ProgressStatus.STARTING)
func on_gate_error(code: GateEvents.GateError) -> void:
match code:
GateEvents.GateError.NOT_FOUND:
set_progress("Gate not found", ProgressStatus.ERROR)
GateEvents.GateError.INVALID_CONFIG:
set_progress("Gate not found", ProgressStatus.ERROR)
GateEvents.GateError.MISSING_PACK, GateEvents.GateError.MISSING_LIBS:
set_progress("Cannot load gate resources", ProgressStatus.ERROR)
_:
set_progress("Unknown error", ProgressStatus.ERROR)
func set_progress(text: String, status: ProgressStatus, progress: float = 0.0) -> void:
label.text = text
match status:
ProgressStatus.CONNECTING:
progress_bar.show()
progress_bar_error.hide()
move_progress_bar(0.0, 0.0)
ProgressStatus.DOWNLOADING:
progress_bar.show()
progress_bar_error.hide()
move_progress_bar(progress, FileDownloader.PROGRESS_DELAY)
ProgressStatus.STARTING:
progress_bar.show()
progress_bar_error.hide()
move_progress_bar(1.0, TWEEN_DURATION_S)
ProgressStatus.ERROR:
progress_bar.hide()
progress_bar_error.show()
_:
progress_bar.hide()
progress_bar_error.hide()
func move_progress_bar(progress: float, tween_duration: float) -> void:
var full_size = progress_bar_background.size
var current_size = Vector2(lerp(0.0, full_size.x, progress), full_size.y)
var tween = get_tree().create_tween()
tween.tween_property(progress_bar, "size", current_size, tween_duration)