Game version management
This commit is contained in:
@@ -4,11 +4,11 @@ using Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.сеть;
|
||||
|
||||
public static class Сеть
|
||||
public static class NetworkHelper
|
||||
{
|
||||
private static HttpClient _http = new();
|
||||
|
||||
static Сеть()
|
||||
static NetworkHelper()
|
||||
{
|
||||
// thanks for Sashok :3
|
||||
// https://github.com/new-sashok724/Launcher/blob/23485c3f7de6620d2c6b7b2dd9339c3beb6a0366/Launcher/source/helper/IOHelper.java#L259
|
||||
@@ -36,52 +36,9 @@ public static class Сеть
|
||||
|
||||
public static async Task<T> DownloadStringAndDeserialize<T>(string url)
|
||||
{
|
||||
var text = await _http.GetStringAsync(url);
|
||||
var text = await GetString(url);
|
||||
var result = JsonConvert.DeserializeObject<T>(text)
|
||||
?? throw new Exception($"can't deserialize {typeof(T).Name}");
|
||||
return result;
|
||||
}
|
||||
|
||||
private static readonly string[] VERSION_MANIFEST_URLS =
|
||||
{
|
||||
"https://piston-meta.mojang.com/mc/game/version_manifest_v2.json"
|
||||
};
|
||||
|
||||
private static async Task<List<RemoteVersionDescriptorProps>> GetRemoteVersionDescriptorsAsync()
|
||||
{
|
||||
List<RemoteVersionDescriptorProps> descriptors = new();
|
||||
foreach (var url in VERSION_MANIFEST_URLS)
|
||||
{
|
||||
try
|
||||
{
|
||||
var catalog = await DownloadStringAndDeserialize<GameVersionCatalog>(url);
|
||||
descriptors.AddRange(catalog.versions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LauncherApp.Logger.LogWarn(nameof(Сеть), ex);
|
||||
}
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private static List<GameVersionProps>? _versionPropsList;
|
||||
|
||||
/// <returns>empty list if couldn't find any remote versions</returns>
|
||||
public static async Task<IReadOnlyList<GameVersionProps>> GetDownloadableVersions()
|
||||
{
|
||||
if (_versionPropsList == null)
|
||||
{
|
||||
_versionPropsList = new();
|
||||
var rvdlist = await GetRemoteVersionDescriptorsAsync();
|
||||
foreach (var r in rvdlist)
|
||||
{
|
||||
if (r.type == "release")
|
||||
_versionPropsList.Add(new GameVersionProps(r.id, r.url));
|
||||
}
|
||||
}
|
||||
|
||||
return _versionPropsList;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using DTLib.Extensions;
|
||||
using Mlaumcherb.Client.Avalonia.зримое;
|
||||
using Mlaumcherb.Client.Avalonia.классы;
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
using static Mlaumcherb.Client.Avalonia.сеть.Сеть;
|
||||
using static Mlaumcherb.Client.Avalonia.сеть.NetworkHelper;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.сеть.TaskFactories;
|
||||
|
||||
@@ -39,9 +39,9 @@ public class AssetsDownloadTaskFactory : INetworkTaskFactory
|
||||
{
|
||||
if(!File.Exists(_indexFilePath))
|
||||
{
|
||||
LauncherApp.Logger.LogInfo(nameof(Сеть), $"started downloading asset index to '{_indexFilePath}'");
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"started downloading asset index to '{_indexFilePath}'");
|
||||
await DownloadFile(_descriptor.assetIndex.url, _indexFilePath);
|
||||
LauncherApp.Logger.LogInfo(nameof(Сеть), "finished downloading asset index");
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), "finished downloading asset index");
|
||||
}
|
||||
|
||||
string indexFileText = File.ReadAllText(_indexFilePath);
|
||||
@@ -102,7 +102,7 @@ public class AssetsDownloadTaskFactory : INetworkTaskFactory
|
||||
|
||||
private async Task Download(NetworkProgressReporter pr, CancellationToken ct)
|
||||
{
|
||||
LauncherApp.Logger.LogInfo(nameof(Сеть), $"started downloading assets '{_descriptor.assetIndex.id}'");
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"started downloading assets '{_descriptor.assetIndex.id}'");
|
||||
ParallelOptions opt = new()
|
||||
{
|
||||
MaxDegreeOfParallelism = LauncherApp.Config.max_parallel_downloads,
|
||||
@@ -114,7 +114,7 @@ public class AssetsDownloadTaskFactory : INetworkTaskFactory
|
||||
bool completed = false;
|
||||
while(!completed)
|
||||
{
|
||||
LauncherApp.Logger.LogDebug(nameof(Сеть), $"downloading asset '{a.name}' {a.hash}");
|
||||
LauncherApp.Logger.LogDebug(nameof(NetworkHelper), $"downloading asset '{a.name}' {a.hash}");
|
||||
try
|
||||
{
|
||||
await DownloadFile(a.url, a.filePath, _ct, pr.AddBytesCount);
|
||||
@@ -125,13 +125,13 @@ public class AssetsDownloadTaskFactory : INetworkTaskFactory
|
||||
// wait on rate limit
|
||||
if(httpException.StatusCode == HttpStatusCode.TooManyRequests)
|
||||
{
|
||||
LauncherApp.Logger.LogDebug(nameof(Сеть), "rate limit hit");
|
||||
LauncherApp.Logger.LogDebug(nameof(NetworkHelper), "rate limit hit");
|
||||
await Task.Delay(1000, _ct);
|
||||
}
|
||||
else throw;
|
||||
}
|
||||
}
|
||||
});
|
||||
LauncherApp.Logger.LogInfo(nameof(Сеть), $"finished downloading assets '{_descriptor.assetIndex.id}'");
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"finished downloading assets '{_descriptor.assetIndex.id}'");
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using DTLib.Extensions;
|
||||
using Mlaumcherb.Client.Avalonia.зримое;
|
||||
using Mlaumcherb.Client.Avalonia.классы;
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
using static Mlaumcherb.Client.Avalonia.сеть.Сеть;
|
||||
using static Mlaumcherb.Client.Avalonia.сеть.NetworkHelper;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.сеть.TaskFactories;
|
||||
|
||||
@@ -84,7 +84,7 @@ public class JavaDownloadTaskFactory : INetworkTaskFactory
|
||||
|
||||
private async Task Download(NetworkProgressReporter pr, CancellationToken ct)
|
||||
{
|
||||
LauncherApp.Logger.LogInfo(nameof(Сеть), "started downloading java runtime " +
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), "started downloading java runtime " +
|
||||
$"{_descriptor.javaVersion.majorVersion} '{_descriptor.javaVersion.component}'");
|
||||
|
||||
ParallelOptions opt = new()
|
||||
@@ -96,7 +96,7 @@ public class JavaDownloadTaskFactory : INetworkTaskFactory
|
||||
{
|
||||
if (f.props.downloads!.lzma != null)
|
||||
{
|
||||
LauncherApp.Logger.LogDebug(nameof(Сеть), $"downloading lzma-compressed file '{f.path}'");
|
||||
LauncherApp.Logger.LogDebug(nameof(NetworkHelper), $"downloading lzma-compressed file '{f.path}'");
|
||||
await using var pipe = new TransformStream(await GetStream(f.props.downloads.lzma.url, _ct));
|
||||
pipe.AddTransform(pr.AddBytesCount);
|
||||
await using var fs = File.OpenWrite(f.path);
|
||||
@@ -104,18 +104,18 @@ public class JavaDownloadTaskFactory : INetworkTaskFactory
|
||||
}
|
||||
else
|
||||
{
|
||||
LauncherApp.Logger.LogDebug(nameof(Сеть), $"downloading raw file '{f.path}'");
|
||||
LauncherApp.Logger.LogDebug(nameof(NetworkHelper), $"downloading raw file '{f.path}'");
|
||||
await DownloadFile(f.props.downloads.raw.url, f.path, _ct, pr.AddBytesCount);
|
||||
}
|
||||
|
||||
if(!OperatingSystem.IsWindows() && f.props.executable is true)
|
||||
{
|
||||
LauncherApp.Logger.LogDebug(nameof(Сеть), $"adding execute rights to file '{f.path}'");
|
||||
LauncherApp.Logger.LogDebug(nameof(NetworkHelper), $"adding execute rights to file '{f.path}'");
|
||||
System.IO.File.SetUnixFileMode(f.path.ToString(), UnixFileMode.UserExecute);
|
||||
}
|
||||
});
|
||||
|
||||
LauncherApp.Logger.LogInfo(nameof(Сеть), "finished downloading java runtime " +
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), "finished downloading java runtime " +
|
||||
$"{_descriptor.javaVersion.majorVersion} '{_descriptor.javaVersion.component}'");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using DTLib.Extensions;
|
||||
using Mlaumcherb.Client.Avalonia.зримое;
|
||||
using Mlaumcherb.Client.Avalonia.классы;
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
using static Mlaumcherb.Client.Avalonia.сеть.Сеть;
|
||||
using static Mlaumcherb.Client.Avalonia.сеть.NetworkHelper;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.сеть.TaskFactories;
|
||||
|
||||
@@ -43,7 +43,15 @@ public class LibrariesDownloadTaskFactory : INetworkTaskFactory
|
||||
|
||||
foreach (var l in _libraries.Libs)
|
||||
{
|
||||
if (!File.Exists(l.jarFilePath))
|
||||
// Forge installer downloads some libraries manually.
|
||||
// Such libraries have empty url in descriptor.
|
||||
if(l.jarFilePath is null)
|
||||
{
|
||||
LauncherApp.Logger.LogDebug(nameof(NetworkHelper), $"library artifact has empty url: '{l.name}'");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!File.Exists(l.jarFilePath.Value))
|
||||
{
|
||||
_libsToDownload.Add(l);
|
||||
}
|
||||
@@ -53,7 +61,7 @@ public class LibrariesDownloadTaskFactory : INetworkTaskFactory
|
||||
}
|
||||
else if (checkHashes)
|
||||
{
|
||||
using var fs = File.OpenRead(l.jarFilePath);
|
||||
using var fs = File.OpenRead(l.jarFilePath.Value);
|
||||
string hash = _hasher.ComputeHash(fs).HashToString();
|
||||
if(hash != l.artifact.sha1)
|
||||
_libsToDownload.Add(l);
|
||||
@@ -73,7 +81,7 @@ public class LibrariesDownloadTaskFactory : INetworkTaskFactory
|
||||
|
||||
private async Task Download(NetworkProgressReporter pr, CancellationToken ct)
|
||||
{
|
||||
LauncherApp.Logger.LogInfo(nameof(Сеть), $"started downloading libraries '{_descriptor.id}'");
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"started downloading libraries '{_descriptor.id}'");
|
||||
|
||||
ParallelOptions opt = new()
|
||||
{
|
||||
@@ -82,11 +90,13 @@ public class LibrariesDownloadTaskFactory : INetworkTaskFactory
|
||||
};
|
||||
await Parallel.ForEachAsync(_libsToDownload, opt, async (l, _ct) =>
|
||||
{
|
||||
LauncherApp.Logger.LogDebug(nameof(Сеть), $"downloading library '{l.name}' to '{l.jarFilePath}'");
|
||||
await DownloadFile(l.artifact.url, l.jarFilePath, _ct, pr.AddBytesCount);
|
||||
LauncherApp.Logger.LogDebug(nameof(NetworkHelper), $"downloading library '{l.name}' to '{l.jarFilePath}'");
|
||||
if(l.jarFilePath is null)
|
||||
throw new Exception("jarFilePath is null");
|
||||
await DownloadFile(l.artifact.url, l.jarFilePath.Value, _ct, pr.AddBytesCount);
|
||||
if (l is Libraries.NativeLib n)
|
||||
{
|
||||
var zipf = File.OpenRead(n.jarFilePath);
|
||||
var zipf = File.OpenRead(n.jarFilePath!.Value);
|
||||
ZipFile.ExtractToDirectory(zipf, _nativesDir.ToString(), true);
|
||||
if (n.extractionOptions?.exclude != null)
|
||||
{
|
||||
@@ -102,6 +112,6 @@ public class LibrariesDownloadTaskFactory : INetworkTaskFactory
|
||||
}
|
||||
});
|
||||
|
||||
LauncherApp.Logger.LogInfo(nameof(Сеть), $"finished downloading libraries '{_descriptor.id}'");
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"finished downloading libraries '{_descriptor.id}'");
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using DTLib.Extensions;
|
||||
using Mlaumcherb.Client.Avalonia.зримое;
|
||||
using Mlaumcherb.Client.Avalonia.классы;
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
using static Mlaumcherb.Client.Avalonia.сеть.Сеть;
|
||||
using static Mlaumcherb.Client.Avalonia.сеть.NetworkHelper;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.сеть.TaskFactories;
|
||||
|
||||
@@ -36,8 +36,13 @@ public class VersionFileDownloadTaskFactory : INetworkTaskFactory
|
||||
{
|
||||
if (!File.Exists(_filePath))
|
||||
return false;
|
||||
|
||||
if (!checkHashes)
|
||||
return true;
|
||||
|
||||
if (_descriptor.downloads is null)
|
||||
return true;
|
||||
|
||||
using var fs = File.OpenRead(_filePath);
|
||||
string hash = _hasher.ComputeHash(fs).HashToString();
|
||||
return hash == _descriptor.downloads.client.sha1;
|
||||
@@ -45,13 +50,18 @@ public class VersionFileDownloadTaskFactory : INetworkTaskFactory
|
||||
|
||||
private long GetTotalSize()
|
||||
{
|
||||
if(_descriptor.downloads is null)
|
||||
return 0;
|
||||
return _descriptor.downloads.client.size;
|
||||
}
|
||||
|
||||
private async Task Download(NetworkProgressReporter pr, CancellationToken ct)
|
||||
{
|
||||
LauncherApp.Logger.LogInfo(nameof(Сеть), $"started downloading version file '{_descriptor.id}'");
|
||||
if (_descriptor.downloads is null)
|
||||
throw new Exception($"can't download version file '{_descriptor.id}' because it has no download url");
|
||||
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"started downloading version file '{_descriptor.id}'");
|
||||
await DownloadFile(_descriptor.downloads.client.url, _filePath, ct, pr.AddBytesCount);
|
||||
LauncherApp.Logger.LogInfo(nameof(Сеть), $"finished downloading version file '{_descriptor.id}'");
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"finished downloading version file '{_descriptor.id}'");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user