Downloader.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. using Avalonia.Controls.ApplicationLifetimes;
  2. using Avalonia.Threading;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Net.Http;
  9. using System.Text;
  10. using System.Text.Json;
  11. using System.Threading.Tasks;
  12. using System.IO.Compression;
  13. using VeloeMinecraftLauncher.Entity.Assets;
  14. using VeloeMinecraftLauncher.ViewModels;
  15. using VeloeMinecraftLauncher.Views;
  16. using VeloeMinecraftLauncher.Entity.VersionManifest;
  17. using System.Collections.ObjectModel;
  18. namespace VeloeMinecraftLauncher.MinecraftLauncher
  19. {
  20. internal static class Downloader
  21. {
  22. public static async Task<TaskStatus> StartDownload(
  23. Action<string> DownloadingFileName,
  24. Action<bool> IsControlsEnabled,
  25. Action<WebClient> SetProgressBar,
  26. Action<WebClient> RemoveProgressBar,
  27. Entity.Version.Version versionJson,
  28. bool DownloadJava = false,
  29. bool InstallForge = false,
  30. bool InstallOptifine = false,
  31. bool InstallForgeOptifine = false,
  32. bool InstallFabric = false
  33. )
  34. {
  35. try
  36. {
  37. Settings.logger.Debug("Downloading minecraft {0}", versionJson.id);
  38. var webClient = new WebClient();
  39. SetProgressBar(webClient);
  40. //webClient.DownloadProgressChanged += WebClient_DownloadProgressChanged;
  41. //download java
  42. if (DownloadJava)
  43. {
  44. Settings.logger.Debug("Getting required Java version.");
  45. if (versionJson.javaVersion.majorVersion != null)
  46. {
  47. string javaUrl = "";
  48. switch (versionJson.javaVersion.majorVersion)
  49. {
  50. case 8:
  51. if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
  52. javaUrl = "https://files.veloe.link/launcher/java/8/windows64/java.zip";
  53. if (!Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
  54. javaUrl = "https://files.veloe.link/launcher/java/8/windows32/java.zip";
  55. if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
  56. javaUrl = "https://files.veloe.link/launcher/java/8/linux64/java.zip";
  57. if (!Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
  58. javaUrl = "https://files.veloe.link/launcher/java/8/linux32/java.zip";
  59. break;
  60. case 16:
  61. if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
  62. javaUrl = "https://files.veloe.link/launcher/java/16/windows64/java.zip";
  63. if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
  64. javaUrl = "https://files.veloe.link/launcher/java/16/linux64/java.zip";
  65. break;
  66. case 17:
  67. if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
  68. javaUrl = "https://files.veloe.link/launcher/java/17/windows64/java.zip";
  69. if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
  70. javaUrl = "https://files.veloe.link/launcher/java/17/linux64/java.zip";
  71. break;
  72. case 18:
  73. if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
  74. javaUrl = "https://files.veloe.link/launcher/java/18/windows64/java.zip";
  75. if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
  76. javaUrl = "https://files.veloe.link/launcher/java/18/linux64/java.zip";
  77. break;
  78. }
  79. if (javaUrl != "")
  80. {
  81. Settings.logger.Debug("Downloading Java");
  82. DownloadingFileName("java.zip");
  83. webClient.DownloadFileAsync(new System.Uri(javaUrl), Settings.MinecraftForlderPath + "java.zip");
  84. waitWhileBisy(ref webClient);
  85. Settings.logger.Debug("Unpacking Java");
  86. DownloadingFileName("Unpacking java.zip");
  87. ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}java.zip", Settings.MinecraftForlderPath, true);
  88. File.Delete($"{Settings.MinecraftForlderPath}java.zip");
  89. }
  90. else
  91. Settings.logger.Debug("Required Java version don't found in json file."); //log that java was not downloaded;
  92. }
  93. }
  94. //download json
  95. var path = Settings.MinecraftForlderPath + "/versions/" + versionJson.id;
  96. if (!Directory.Exists(path))
  97. {
  98. Settings.logger.Debug("Creating path: {0}", path);
  99. Directory.CreateDirectory(path);
  100. }
  101. //Settings.logger.Debug("Downloading {0}", $"{versionJson.id}.json");
  102. //DownloadingFileName($"{versionJson.id}.json");
  103. //webClient.DownloadFileAsync(new System.Uri(versionJson.url), path + "/" + versionJson.id + ".json");
  104. //waitWhileBisy(ref webClient);
  105. //download jar
  106. if (!Directory.Exists(path))
  107. {
  108. Settings.logger.Debug("Creating path: {0}", path);
  109. Directory.CreateDirectory(path);
  110. }
  111. string chksum = String.Empty;
  112. //here hash check
  113. if (File.Exists(path + "/" + versionJson.id + ".jar"))
  114. {
  115. DownloadingFileName($"Checking hash: {versionJson.id}.jar");
  116. FileStream fop = File.OpenRead(path + "/" + versionJson.id + ".jar");
  117. byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
  118. chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();
  119. fop.Close();
  120. fop.Dispose();
  121. }
  122. if (chksum != versionJson.downloads.client.sha1)
  123. {
  124. Settings.logger.Debug("Downloading {0}", $"{versionJson.id}.jar");
  125. DownloadingFileName($"{versionJson.id}.jar");
  126. webClient.DownloadFileAsync(new System.Uri(versionJson.downloads.client.url), path + "/" + versionJson.id + ".jar");
  127. waitWhileBisy(ref webClient);
  128. }
  129. //end download jar
  130. //download libraries
  131. Settings.logger.Debug("Downloading libraries.");
  132. foreach (var library in versionJson.libraries)
  133. {
  134. var libPath = Settings.MinecraftForlderPath + "libraries/";
  135. string[] libPathSplit = new[] { "" };
  136. string libUrl = "";
  137. string sha1 = String.Empty;
  138. // getting path and url if universal lib
  139. if (library.natives is null)
  140. {
  141. libPath = Settings.MinecraftForlderPath + "libraries/";
  142. libPathSplit = library.downloads.artifact.path.Split('/');
  143. libUrl = library.downloads.artifact.url;
  144. sha1 = library.downloads.artifact.sha1;
  145. for (int i = 0; i < libPathSplit.Length - 1; i++)
  146. {
  147. libPath += libPathSplit[i] + "/";
  148. }
  149. }
  150. else
  151. { // getting path if native
  152. libPath = Settings.MinecraftForlderPath + "libraries/";
  153. libPathSplit = new[] { "" };
  154. libUrl = "";
  155. if (OperatingSystem.IsWindows() && library.natives.windows is not null)
  156. {
  157. if (library.downloads.classifiers.NativesWindows is not null)
  158. {
  159. libPathSplit = library.downloads.classifiers.NativesWindows.path.Split('/');
  160. libUrl = library.downloads.classifiers.NativesWindows.url;
  161. sha1 = library.downloads.classifiers.NativesWindows.sha1;
  162. }
  163. else
  164. {
  165. if (Environment.Is64BitOperatingSystem)
  166. {
  167. libPathSplit = library.downloads.classifiers.NativesWindows64.path.Split('/');
  168. libUrl = library.downloads.classifiers.NativesWindows64.url;
  169. sha1 = library.downloads.classifiers.NativesWindows64.sha1;
  170. }
  171. else
  172. {
  173. libPathSplit = library.downloads.classifiers.NativesWindows32.path.Split('/');
  174. libUrl = library.downloads.classifiers.NativesWindows32.url;
  175. sha1 = library.downloads.classifiers.NativesWindows32.sha1;
  176. }
  177. }
  178. }
  179. if (OperatingSystem.IsLinux() && library.natives.linux is not null)
  180. {
  181. libPathSplit = library.downloads.classifiers.NativesLinux.path.Split('/');
  182. libUrl = library.downloads.classifiers.NativesLinux.url;
  183. sha1 = library.downloads.classifiers.NativesLinux.url;
  184. }
  185. for (int i = 0; i < libPathSplit.Length - 1; i++)
  186. {
  187. libPath += libPathSplit[i] + "/";
  188. }
  189. }
  190. //if no lib url
  191. if (libUrl == String.Empty)
  192. continue;
  193. //checking rules
  194. if (library.rules == null)
  195. {
  196. if (!Directory.Exists(libPath))
  197. {
  198. Settings.logger.Debug("Creating path: {0}", path);
  199. Directory.CreateDirectory(libPath);
  200. }
  201. chksum = String.Empty;
  202. if (File.Exists(libPath + "/" + libPathSplit.Last()))
  203. {
  204. DownloadingFileName($"Checking hash: {libPathSplit.Last()}");
  205. FileStream fop = File.OpenRead(libPath + "/" + libPathSplit.Last());
  206. byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
  207. chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();
  208. fop.Close();
  209. fop.Dispose();
  210. }
  211. if (chksum != sha1)
  212. {
  213. Settings.logger.Debug("Downloading: {0}", libPathSplit.Last());
  214. DownloadingFileName(libPathSplit.Last());
  215. webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libPathSplit.Last());
  216. waitWhileBisy(ref webClient);
  217. }
  218. }
  219. else
  220. {
  221. foreach (var rule in library.rules)
  222. {
  223. if (rule.action == "allow") // && rule.os is null
  224. {
  225. if (!Directory.Exists(libPath))
  226. {
  227. Settings.logger.Debug("Creating path: {0}", path);
  228. Directory.CreateDirectory(libPath);
  229. }
  230. chksum = String.Empty;
  231. if (File.Exists(libPath + "/" + libPathSplit.Last()) && sha1 != String.Empty)
  232. {
  233. DownloadingFileName($"Checking hash: {libPathSplit.Last()}");
  234. FileStream fop = File.OpenRead(libPath + "/" + libPathSplit.Last());
  235. byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
  236. chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();
  237. fop.Close();
  238. fop.Dispose();
  239. }
  240. if (chksum != sha1)
  241. {
  242. Settings.logger.Debug("Downloading: {0}", libPathSplit.Last());
  243. DownloadingFileName(libPathSplit.Last());
  244. webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libPathSplit.Last());
  245. waitWhileBisy(ref webClient);
  246. }
  247. continue;
  248. }
  249. //fabic on start needs all libraries for all os, so os check removed
  250. /*
  251. if (rule.action == "allow" && (rule.os.name == "windows" || rule.os.name == "linux" || rule.os.name == "osx" ))
  252. {
  253. if (!Directory.Exists(libPath))
  254. {
  255. Settings.logger.Debug("Creating path: {0}", path);
  256. Directory.CreateDirectory(libPath);
  257. }
  258. Settings.logger.Debug("Downloading: {0}", libPathSplit.Last());
  259. DownloadingFileName = libPathSplit.Last();
  260. webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libPathSplit.Last());
  261. waitWhileBisy(ref webClient);
  262. }
  263. */
  264. }
  265. }
  266. //unpacking native libs
  267. if (((library.natives is not null || library.downloads.classifiers is not null) && File.Exists(libPath + "/" + libPathSplit.Last())) /*&& chksum != sha1*/)
  268. {
  269. try
  270. {
  271. if (!((
  272. library.downloads.classifiers.NativesWindows is not null ||
  273. library.downloads.classifiers.NativesWindows64 is not null ||
  274. library.downloads.classifiers.NativesWindows32 is not null) && OperatingSystem.IsWindows() ||
  275. library.downloads.classifiers.NativesLinux is not null && OperatingSystem.IsLinux()))
  276. continue;
  277. if (!Directory.Exists(Settings.MinecraftForlderPath + "versions/" + versionJson.id + "/natives/"))
  278. {
  279. Settings.logger.Debug("Creating path: {0}", Settings.MinecraftForlderPath + "versions/" + versionJson.id + "/natives/");
  280. Directory.CreateDirectory(Settings.MinecraftForlderPath + "versions/" + versionJson.id + "/natives/");
  281. }
  282. Settings.logger.Debug("Extracting {0} to {1}", libPathSplit.Last(), Settings.MinecraftForlderPath + "versions/" + versionJson.id + "/natives/");
  283. ZipFile.ExtractToDirectory(libPath + "/" + libPathSplit.Last(), Settings.MinecraftForlderPath + "versions/" + versionJson.id + "/natives/", true);
  284. }
  285. catch (IOException ex)
  286. {
  287. Settings.logger.Error("IOException in VersionsDownloaderViewModel on native lib extraction");
  288. }
  289. //TODO delete META-INF and sha1 files after
  290. }
  291. }
  292. var assetsJson = Downloader.DownloadAndDeserializeJsonData<AssetsManifest>(versionJson.assetIndex.url);
  293. var assetsPath = Settings.MinecraftForlderPath + "assets/" + versionJson.assets + "/objects";
  294. var assetsUrl = "https://resources.download.minecraft.net/";
  295. //download assets json
  296. Settings.logger.Debug("Downloading: {0}", versionJson.assets + ".json");
  297. if (!Directory.Exists(Settings.MinecraftForlderPath + "/assets/" + versionJson.assets + "/indexes/"))
  298. Directory.CreateDirectory(Settings.MinecraftForlderPath + "/assets/" + versionJson.assets + "/indexes/");
  299. webClient.DownloadFileAsync(new System.Uri(versionJson.assetIndex.url), Settings.MinecraftForlderPath + "/assets/" + versionJson.assets + "/indexes/" + versionJson.assets + ".json");
  300. //download assets
  301. foreach (var asset in assetsJson.Objects)
  302. {
  303. var folder = asset.Value.hash.Substring(0, 2);
  304. if (!Directory.Exists(assetsPath + "/" + folder))
  305. Directory.CreateDirectory(assetsPath + "/" + folder);
  306. chksum = String.Empty;
  307. //here hash check
  308. if (File.Exists(assetsPath + "/" + folder + "/" + asset.Value.hash))
  309. {
  310. DownloadingFileName($"Checking hash: {asset.Value.hash}");
  311. FileStream fop = File.OpenRead(assetsPath + "/" + folder + "/" + asset.Value.hash);
  312. byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
  313. chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();
  314. fop.Close();
  315. fop.Dispose();
  316. }
  317. if (chksum != asset.Value.hash)
  318. {
  319. Settings.logger.Debug("Downloading: {0}", asset.Value.hash);
  320. DownloadingFileName($"Asset {asset.Value.hash}");
  321. webClient.DownloadFileAsync(new System.Uri(assetsUrl + folder + "/" + asset.Value.hash), assetsPath + "/" + folder + "/" + asset.Value.hash);
  322. waitWhileBisy(ref webClient);
  323. }
  324. }
  325. if (InstallForge)
  326. {
  327. var forgePath = $"Forge{versionJson.id}";
  328. var forgeUrl = $"https://files.veloe.link/launcher/forge/Forge{versionJson.id}/";
  329. if (!Directory.Exists($"{Settings.MinecraftForlderPath}versions/Forge{versionJson.id}"))
  330. {
  331. Settings.logger.Debug("Creating path: {0}", $"{Settings.MinecraftForlderPath}versions/" + forgePath);
  332. Directory.CreateDirectory($"{Settings.MinecraftForlderPath}versions/" + forgePath);
  333. }
  334. waitWhileBisy(ref webClient);
  335. Settings.logger.Debug("Downloading: {0}", $"Forge{versionJson.id}.json");
  336. DownloadingFileName($"Forge{versionJson.id}.json");
  337. webClient.DownloadFileAsync(new System.Uri($"{forgeUrl}Forge{versionJson.id}.json"), Settings.MinecraftForlderPath + "versions/" + forgePath + "/" + forgePath + ".json");
  338. waitWhileBisy(ref webClient);
  339. Settings.logger.Debug("Downloading: {0}", "libraries.zip");
  340. DownloadingFileName("libraries.zip");
  341. webClient.DownloadFileAsync(new System.Uri(forgeUrl + "libraries.zip"), Settings.MinecraftForlderPath + "versions/" + forgePath + "/libraries.zip");
  342. waitWhileBisy(ref webClient);
  343. Settings.logger.Debug("Extracting: {0}", "libraries.zip");
  344. DownloadingFileName("Unpacking libraries.zip");
  345. ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}versions/Forge{versionJson.id}/libraries.zip", Settings.MinecraftForlderPath, true);
  346. File.Delete($"{Settings.MinecraftForlderPath}versions/Forge{versionJson.id}/libraries.zip");
  347. }
  348. if (InstallOptifine)
  349. {
  350. var optifinePath = $"Optifine{versionJson.id}";
  351. var optifineUrl = $"https://files.veloe.link/launcher/optifine/Optifine{versionJson.id}/";
  352. if (!Directory.Exists($"{Settings.MinecraftForlderPath}versions/Optifine{versionJson.id}"))
  353. {
  354. Settings.logger.Debug("Creating path: {0}", $"{Settings.MinecraftForlderPath}Optifine/" + optifinePath);
  355. Directory.CreateDirectory($"{Settings.MinecraftForlderPath}Optifine/" + optifinePath);
  356. }
  357. Settings.logger.Debug("Downloading: {0}", $"Optifine{versionJson.id}.json");
  358. DownloadingFileName($"Optifine{versionJson.id}.json");
  359. webClient.DownloadFileAsync(new System.Uri($"{optifineUrl}Optifine{versionJson.id}.json"), Settings.MinecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".json");
  360. waitWhileBisy(ref webClient);
  361. Settings.logger.Debug("Downloading: {0}", $"Optifine{versionJson.id}.json");
  362. DownloadingFileName($"Optifine{versionJson.id}.json");
  363. webClient.DownloadFileAsync(new System.Uri($"{optifineUrl}Optifine{versionJson.id}.jar"), Settings.MinecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".jar");
  364. waitWhileBisy(ref webClient);
  365. Settings.logger.Debug("Downloading: {0}", "libraries.zip");
  366. DownloadingFileName("libraries.zip");
  367. webClient.DownloadFileAsync(new System.Uri(optifineUrl + "libraries.zip"), Settings.MinecraftForlderPath + "versions/" + optifinePath + "/libraries.zip");
  368. waitWhileBisy(ref webClient);
  369. Settings.logger.Debug("Extracting: {0}", "libraries.zip");
  370. DownloadingFileName("Unpacking libraries.zip");
  371. ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}versions/Optifine{versionJson.id}/libraries.zip", Settings.MinecraftForlderPath, true);
  372. File.Delete($"{Settings.MinecraftForlderPath}versions/Optifine{versionJson.id}/libraries.zip");
  373. }
  374. if (InstallForgeOptifine)
  375. {
  376. if (!Directory.Exists($"{Settings.MinecraftForlderPath}versions/Forge{versionJson.id}/mods"))
  377. {
  378. Settings.logger.Debug("Creating path: {0}", $"{Settings.MinecraftForlderPath}versions/Forge" + versionJson.id + "/mods");
  379. Directory.CreateDirectory($"{Settings.MinecraftForlderPath}versions/Forge" + versionJson.id + "/mods");
  380. }
  381. Settings.logger.Debug("Downloading: {0}", $"Optifine{versionJson.id}.jar");
  382. DownloadingFileName($"Optifine{versionJson.id}.jar");
  383. webClient.DownloadFileAsync(new System.Uri(@$"https://files.veloe.link/launcher/forge/Forge{versionJson.id}/Optifine{versionJson.id}.jar"),
  384. Settings.MinecraftForlderPath + "versions/Forge" + versionJson.id + "/mods/" + "Optifine" + versionJson.id + ".jar");
  385. waitWhileBisy(ref webClient);
  386. }
  387. RemoveProgressBar(webClient);
  388. //Progress = 100;
  389. Settings.logger.Debug("Downloading finished.");
  390. DownloadingFileName("Finished!");
  391. IsControlsEnabled(true);
  392. webClient.Dispose();
  393. }
  394. catch (Exception ex)
  395. {
  396. IsControlsEnabled(true);
  397. DownloadingFileName($"Error occured while downloading {versionJson.id}.");
  398. Settings.logger.Error(ex.Message);
  399. Settings.logger.Error(ex.StackTrace);
  400. return TaskStatus.Faulted;
  401. }
  402. return TaskStatus.RanToCompletion;
  403. }
  404. public static async Task<TaskStatus> StartDownloadMcTfc(Action<string> DownloadingFileName,
  405. Action<bool> IsControlsEnabled,
  406. Action<WebClient> SetProgressBar,
  407. Action<WebClient> RemoveProgressBar,
  408. ObservableCollection<Entity.VersionManifest.Version> FilteredVersions,
  409. bool DownloadJava = false,
  410. bool InstallForge = false,
  411. bool InstallOptifine = false,
  412. bool InstallForgeOptifine = false,
  413. bool InstallFabric = false)
  414. {
  415. try
  416. {
  417. var FilteredVersion = FilteredVersions.Where(x => x.id == "1.12.2").FirstOrDefault();
  418. if (FilteredVersion is null)
  419. return TaskStatus.Faulted;
  420. InstallForge = true;
  421. InstallForgeOptifine = true;
  422. Settings.logger.Debug("Downloading {0}.json", FilteredVersion.id);
  423. DownloadingFileName($"{FilteredVersion.id}.json");
  424. var versionJson = Downloader.DownloadAndDeserializeJsonData<Entity.Version.Version>(FilteredVersion.url, Settings.MinecraftForlderPath + "versions/" + FilteredVersion.id + "/", FilteredVersion.id + ".json");
  425. await Downloader.StartDownload(
  426. DownloadingFileName,
  427. IsControlsEnabled,
  428. SetProgressBar,
  429. RemoveProgressBar,
  430. versionJson,
  431. DownloadJava,
  432. InstallForge,
  433. InstallOptifine,
  434. InstallForgeOptifine,
  435. InstallFabric);
  436. IsControlsEnabled(false);
  437. var mcTfcUrl = $"https://files.veloe.link/launcher/McTFC/McTFC.zip";
  438. if (!Directory.Exists($"{Settings.MinecraftForlderPath}versions/McTFC"))
  439. {
  440. Settings.logger.Debug("Creating path: {0}", $"{Settings.MinecraftForlderPath}versions/McTFC");
  441. Directory.CreateDirectory($"{Settings.MinecraftForlderPath}versions/McTFC");
  442. }
  443. WebClient webClient = new WebClient();
  444. SetProgressBar(webClient);
  445. Settings.logger.Debug("Downloading: {0}", "McTFC.zip");
  446. DownloadingFileName("McTFC.zip");
  447. webClient.DownloadFileAsync(new System.Uri(mcTfcUrl), Settings.MinecraftForlderPath + "versions/McTFC.zip");
  448. waitWhileBisy(ref webClient);
  449. Settings.logger.Debug("Extracting: {0}", "McTFC.zip");
  450. DownloadingFileName("Unpacking McTFC.zip");
  451. ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}versions/McTFC.zip", Settings.MinecraftForlderPath + "versions/McTFC", true);
  452. File.Delete($"{Settings.MinecraftForlderPath}versions/McTFC.zip");
  453. RemoveProgressBar(webClient);
  454. //Progress = 100;
  455. Settings.logger.Debug("Downloading McTFC finished.");
  456. DownloadingFileName("Finished McTFC!");
  457. IsControlsEnabled(true);
  458. webClient.Dispose();
  459. }
  460. catch (Exception ex)
  461. {
  462. IsControlsEnabled(true);
  463. DownloadingFileName("Error occured while downloading McTFC.");
  464. var message = ex.Message;
  465. var stackTrace = ex.StackTrace;
  466. Settings.logger.Error(ex.Message);
  467. Settings.logger.Error(ex.StackTrace);
  468. Exception innerException = ex.InnerException;
  469. while (innerException is not null)
  470. {
  471. message += "\n" + innerException.Message;
  472. stackTrace += "\n" + innerException.StackTrace;
  473. Settings.logger.Error(innerException.Message);
  474. Settings.logger.Error(innerException.StackTrace);
  475. innerException = innerException.InnerException;
  476. }
  477. Dispatcher.UIThread.InvokeAsync(() =>
  478. {
  479. if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
  480. {
  481. Dispatcher.UIThread.InvokeAsync(() =>
  482. {
  483. var ErrorMessageViewModel = new ErrorWindowViewModel(message, stackTrace);
  484. var ErrorMessage = new ErrorWindow()
  485. {
  486. DataContext = ErrorMessageViewModel
  487. };
  488. ErrorMessage.ShowDialog(desktop.MainWindow);
  489. });
  490. }
  491. });
  492. return TaskStatus.Faulted;
  493. }
  494. return TaskStatus.RanToCompletion;
  495. }
  496. public static T DownloadAndDeserializeJsonData<T>(string url, string path = "", string filename = "") where T : new()
  497. {
  498. using (var webClient = new HttpClient())
  499. {
  500. var jsonData = string.Empty;
  501. try
  502. {
  503. Settings.logger.Debug($"Downloading: {url.Split('/').Last()}");
  504. jsonData = webClient.GetStringAsync(url).Result;
  505. if (string.IsNullOrEmpty(jsonData))
  506. {
  507. Settings.logger.Warning("Empty string!");
  508. return new T();
  509. }
  510. else
  511. {
  512. if (filename != "")
  513. {
  514. if (!Directory.Exists(path))
  515. {
  516. Settings.logger.Debug("Creating path: {0}", path);
  517. Directory.CreateDirectory(path);
  518. }
  519. File.WriteAllText(path + filename, jsonData);
  520. }
  521. //Settings.logger.Debug("Return serialized string.");
  522. return JsonSerializer.Deserialize<T>(jsonData);
  523. }
  524. /*
  525. return string.IsNullOrEmpty(jsonData)
  526. ? new T()
  527. : JsonSerializer.Deserialize<T>(jsonData);*/
  528. }
  529. catch (Exception ex)
  530. {
  531. var message = ex.Message;
  532. var stackTrace = ex.StackTrace;
  533. Settings.logger.Error(ex.Message);
  534. Settings.logger.Error(ex.StackTrace);
  535. Exception innerException = ex.InnerException;
  536. while (innerException is not null)
  537. {
  538. message += "\n" + innerException.Message;
  539. stackTrace += "\n" + innerException.StackTrace;
  540. Settings.logger.Error(innerException.Message);
  541. Settings.logger.Error(innerException.StackTrace);
  542. innerException = innerException.InnerException;
  543. }
  544. Dispatcher.UIThread.InvokeAsync(() =>
  545. {
  546. if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
  547. {
  548. Dispatcher.UIThread.InvokeAsync(() =>
  549. {
  550. var ErrorMessageViewModel = new ErrorWindowViewModel(message, stackTrace);
  551. var ErrorMessage = new ErrorWindow()
  552. {
  553. DataContext = ErrorMessageViewModel
  554. };
  555. ErrorMessage.ShowDialog(desktop.MainWindow);
  556. });
  557. }
  558. });
  559. return new T();
  560. }
  561. }
  562. }
  563. private static void waitWhileBisy(ref WebClient webClient)
  564. {
  565. while (webClient.IsBusy)
  566. {
  567. Task.Delay(100).Wait();
  568. }
  569. }
  570. }
  571. }