using System; using System.IO; using System.IO.Compression; using System.Net; using System.Security.Cryptography; internal static class EngineBootstrap { internal const string Url = "https://github.com/godotengine/godot-builds/releases/download/4.5-stable/Godot_v4.5-stable_win64.exe.zip"; internal const string Hash = "e8ef4867466bb01a2b762c4ec404f54266b40a5cbba0efa95e3ab325cd7d349b5dc11259e1c1525195080dc82294ff28044f7ac4acad833e4b054b4257e9aa1a"; internal static void Verify(string archive) { using (var stream = File.OpenRead(archive)) using (var sha = SHA512.Create()) if (BitConverter.ToString(sha.ComputeHash(stream)).Replace("-", "").ToLowerInvariant() != Hash) throw new InvalidDataException("Godot-Prüfsumme stimmt nicht. Bitte erneut versuchen."); } internal static void Install(string root, Action status, string offlineArchive) { string engine = Path.Combine(root, "tools", "godot"); if (File.Exists(Path.Combine(engine, "Godot_v4.5-stable_win64.exe")) && File.Exists(Path.Combine(engine, "Godot_v4.5-stable_win64_console.exe"))) return; Directory.CreateDirectory(engine); string archive = Path.Combine(engine, "download-" + Guid.NewGuid().ToString("N") + ".zip"); try { if (offlineArchive == null) { string besideSetup = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Godot_v4.5-stable_win64.exe.zip"); if (File.Exists(besideSetup)) offlineArchive = besideSetup; } if (offlineArchive != null) File.Copy(offlineArchive, archive); else { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; using (var client = new TimedClient()) { client.Headers[HttpRequestHeader.UserAgent] = "BLOCKLINE-Setup/1.0"; status("Godot 4.5 wird heruntergeladen …"); try { client.DownloadFile(Url, archive); } catch (WebException ex) { throw new IOException("Godot konnte nicht geladen werden. Internet/Firewall prüfen oder Godot_v4.5-stable_win64.exe.zip von der offiziellen Godot-Seite neben die Setup-Datei legen. " + ex.Message, ex); } } } status("Prüfsumme prüfen und Engine entpacken …"); Verify(archive); using (var zip = ZipFile.OpenRead(archive)) foreach (string name in new[] { "Godot_v4.5-stable_win64.exe", "Godot_v4.5-stable_win64_console.exe" }) { var entry = zip.GetEntry(name); if (entry == null) throw new InvalidDataException("Engine-Datei fehlt: " + name); string temp = Path.Combine(engine, name + ".part"); entry.ExtractToFile(temp, true); string target = Path.Combine(engine, name); if (File.Exists(target)) File.Delete(target); File.Move(temp, target); } } finally { if (File.Exists(archive)) File.Delete(archive); } } private sealed class TimedClient : WebClient { protected override WebRequest GetWebRequest(Uri uri) { var request = (HttpWebRequest)base.GetWebRequest(uri); request.Timeout = 300000; request.ReadWriteTimeout = 300000; return request; } } }