extends Node class_name DownloadManager ## Handles downloading game files with progress tracking and checksum verification signal download_started(file_name: String, total_size: int) signal download_progress(downloaded: int, total: int, percentage: float) signal download_completed(file_path: String) signal download_failed(error: String) var http_request: HTTPRequest var download_path: String = "" var expected_checksum_md5: String = "" var expected_checksum_sha256: String = "" var total_size: int = 0 var is_downloading: bool = false func _ready() -> void: http_request = HTTPRequest.new() add_child(http_request) http_request.request_completed.connect(_on_download_completed) http_request.download_file = "" # We'll set this per download # Ensure directories exist _ensure_directories() func _ensure_directories() -> void: var dir := DirAccess.open("user://") if dir: if not dir.dir_exists("game"): dir.make_dir("game") if not dir.dir_exists("backup"): dir.make_dir("backup") if not dir.dir_exists("temp"): dir.make_dir("temp") func _process(_delta: float) -> void: if is_downloading and http_request: var downloaded := http_request.get_downloaded_bytes() var body_size := http_request.get_body_size() if body_size > 0: var percentage := (float(downloaded) / float(body_size)) * 100.0 emit_signal("download_progress", downloaded, body_size, percentage) func download_file(url: String, file_name: String, size: int = 0, md5: String = "", sha256: String = "") -> void: if is_downloading: emit_signal("download_failed", "Download already in progress") return download_path = "user://temp/" + file_name expected_checksum_md5 = md5 expected_checksum_sha256 = sha256 total_size = size is_downloading = true # Set download file path http_request.download_file = download_path print("[DownloadManager] Starting download: ", url) print("[DownloadManager] Saving to: ", download_path) emit_signal("download_started", file_name, size) var error := http_request.request(url) if error != OK: is_downloading = false emit_signal("download_failed", "Failed to initiate download: " + str(error)) func _on_download_completed(result: int, response_code: int, _headers: PackedStringArray, _body: PackedByteArray) -> void: is_downloading = false if result != HTTPRequest.RESULT_SUCCESS: emit_signal("download_failed", "Download failed with result: " + str(result)) return if response_code != 200: emit_signal("download_failed", "Server returned error: " + str(response_code)) return # Verify checksum if provided if expected_checksum_md5 != "" or expected_checksum_sha256 != "": if not _verify_checksum(): emit_signal("download_failed", "Checksum verification failed - file may be corrupted") # Delete corrupted file var dir := DirAccess.open("user://temp/") if dir: dir.remove(download_path.get_file()) return print("[DownloadManager] Download completed: ", download_path) emit_signal("download_completed", download_path) func _verify_checksum() -> bool: ## Verify the downloaded file's checksum var file := FileAccess.open(download_path, FileAccess.READ) if not file: print("[DownloadManager] Could not open file for checksum verification") return false var content := file.get_buffer(file.get_length()) file.close() # Verify MD5 if provided if expected_checksum_md5 != "": var ctx := HashingContext.new() ctx.start(HashingContext.HASH_MD5) ctx.update(content) var calculated_md5 := ctx.finish().hex_encode() if calculated_md5.to_lower() != expected_checksum_md5.to_lower(): print("[DownloadManager] MD5 mismatch! Expected: ", expected_checksum_md5, " Got: ", calculated_md5) return false print("[DownloadManager] MD5 checksum verified") # Verify SHA256 if provided if expected_checksum_sha256 != "": var ctx := HashingContext.new() ctx.start(HashingContext.HASH_SHA256) ctx.update(content) var calculated_sha256 := ctx.finish().hex_encode() if calculated_sha256.to_lower() != expected_checksum_sha256.to_lower(): print("[DownloadManager] SHA256 mismatch! Expected: ", expected_checksum_sha256, " Got: ", calculated_sha256) return false print("[DownloadManager] SHA256 checksum verified") return true func cancel_download() -> void: if is_downloading: http_request.cancel_request() is_downloading = false print("[DownloadManager] Download cancelled")