Modpack format v2
This commit is contained in:
parent
23ec6dd194
commit
da58c11e59
@ -18,12 +18,12 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.2.0" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.2.0" />
|
||||
<PackageReference Include="Avalonia.Themes.Simple" Version="11.2.0" />
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.0" />
|
||||
<PackageReference Include="Avalonia.Labs.Gif" Version="11.2.0" />
|
||||
<PackageReference Include="CliWrap" Version="3.6.7" />
|
||||
<PackageReference Include="Avalonia" Version="11.2.*" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.2.*" />
|
||||
<PackageReference Include="Avalonia.Themes.Simple" Version="11.2.*" />
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.*" />
|
||||
<PackageReference Include="Avalonia.Labs.Gif" Version="11.2.*" />
|
||||
<PackageReference Include="CliWrap" Version="3.7.0" />
|
||||
<PackageReference Include="DTLib" Version="1.6.1" />
|
||||
<PackageReference Include="LZMA-SDK" Version="22.1.1" />
|
||||
<PackageReference Include="MessageBox.Avalonia" Version="3.2.0" />
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class MyModpackRemoteProps
|
||||
{
|
||||
[JsonRequired] public int format_version { get; set; }
|
||||
[JsonRequired] public Artifact artifact { get; set; } = null!;
|
||||
}
|
||||
@ -2,37 +2,30 @@
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class MyModpackRemoteProps
|
||||
public class MyModpackV2
|
||||
{
|
||||
[JsonRequired] public int format_version { get; set; }
|
||||
[JsonRequired] public Artifact artifact { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class MyModpackV1
|
||||
{
|
||||
// 1
|
||||
// 2
|
||||
[JsonRequired] public int format_version { get; set; }
|
||||
[JsonRequired] public string name { get; set; } = "";
|
||||
// zip archive with all files
|
||||
[JsonRequired] public Artifact zip { get; set; } = null!;
|
||||
/// relative_path, hash
|
||||
/// relative_path, props
|
||||
// ReSharper disable once CollectionNeverUpdated.Global
|
||||
[JsonRequired] public Dictionary<string, FileProps> files { get; set; } = new();
|
||||
|
||||
|
||||
public class FileProps
|
||||
{
|
||||
[JsonRequired] public string sha1 { get; set; } = "";
|
||||
[JsonRequired] public Artifact artifact { get; set; } = null!;
|
||||
// disable hash validation, allowing users to edit this file
|
||||
public bool allow_edit { get; set; }
|
||||
// don't re-download file if it was deleted by user
|
||||
public bool optional { get; set; }
|
||||
}
|
||||
|
||||
/// <param name="unmatchedFilesLocalPaths">relative, absolute</param>
|
||||
public Dictionary<IOPath, IOPath> CheckFiles(IOPath basedir, bool checkHashes, bool downloadOptionalFiles)
|
||||
|
||||
public record FileCheckResult(FileProps props, IOPath relativePath, IOPath absolutePath);
|
||||
public List<FileCheckResult> CheckFiles(IOPath basedir, bool checkHashes, bool downloadOptionalFiles)
|
||||
{
|
||||
Dictionary<IOPath, IOPath> unmatchedFiles = new();
|
||||
List<FileCheckResult> unmatchedFiles = new();
|
||||
IOPath launcherRoot = PathHelper.GetRootFullPath();
|
||||
foreach (var p in files)
|
||||
{
|
||||
@ -40,11 +33,12 @@ public class MyModpackV1
|
||||
continue;
|
||||
|
||||
IOPath relativePath = new IOPath(p.Key);
|
||||
// libraries can be in modpacks, they are placed in global libraries directory
|
||||
var absolutePath = Path.Concat(relativePath.StartsWith("libraries")
|
||||
? launcherRoot : basedir, relativePath);
|
||||
if (!HashHelper.CheckFileSHA1(absolutePath, p.Value.sha1, checkHashes && !p.Value.allow_edit))
|
||||
if (!HashHelper.CheckFileSHA1(absolutePath, p.Value.artifact.sha1, checkHashes && !p.Value.allow_edit))
|
||||
{
|
||||
unmatchedFiles.Add(relativePath, absolutePath);
|
||||
unmatchedFiles.Add(new FileCheckResult(p.Value, relativePath, absolutePath));
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,17 +5,15 @@ namespace Mlaumcherb.Client.Avalonia.сеть.TaskFactories;
|
||||
public class ModpackDownloadTaskFactory : INetworkTaskFactory
|
||||
{
|
||||
INetworkTaskFactory _implementationVersion;
|
||||
private GameVersionDescriptor _descriptor;
|
||||
|
||||
public ModpackDownloadTaskFactory(GameVersionDescriptor descriptor)
|
||||
{
|
||||
if(descriptor.modpack is null)
|
||||
throw new ArgumentNullException(nameof(descriptor.modpack));
|
||||
|
||||
_descriptor = descriptor;
|
||||
_implementationVersion = descriptor.modpack.format_version switch
|
||||
{
|
||||
1 => new MyModpackV1DownloadTaskFactory(descriptor),
|
||||
2 => new MyModpackV2DownloadTaskFactory(descriptor),
|
||||
_ => throw new Exception($"Unknown Modpack format_version: {descriptor.modpack.format_version}")
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using Mlaumcherb.Client.Avalonia.зримое;
|
||||
using Mlaumcherb.Client.Avalonia.классы;
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.сеть.TaskFactories;
|
||||
|
||||
public class MyModpackV1DownloadTaskFactory : INetworkTaskFactory
|
||||
public class MyModpackV2DownloadTaskFactory : INetworkTaskFactory
|
||||
{
|
||||
private readonly GameVersionDescriptor _descriptor;
|
||||
private IOPath _modpackDescriptorPath;
|
||||
private IOPath _versionDir;
|
||||
private MyModpackV1? _modpack;
|
||||
private MyModpackV2? _modpack;
|
||||
// relative, absolute
|
||||
private Dictionary<IOPath, IOPath> _filesToDosnload = new();
|
||||
private List<MyModpackV2.FileCheckResult> _filesToDownload = new();
|
||||
|
||||
public MyModpackV1DownloadTaskFactory(GameVersionDescriptor descriptor)
|
||||
public MyModpackV2DownloadTaskFactory(GameVersionDescriptor descriptor)
|
||||
{
|
||||
_descriptor = descriptor;
|
||||
_modpackDescriptorPath = PathHelper.GetModpackDescriptorPath(_descriptor.id);
|
||||
@ -26,7 +26,7 @@ public class MyModpackV1DownloadTaskFactory : INetworkTaskFactory
|
||||
if(_descriptor.modpack is null)
|
||||
throw new ArgumentNullException(nameof(_descriptor.modpack));
|
||||
|
||||
(_modpack, bool didDownloadModpackDescriptor) = await NetworkHelper.ReadOrDownloadAndDeserialize<MyModpackV1>(
|
||||
(_modpack, bool didDownloadModpackDescriptor) = await NetworkHelper.ReadOrDownloadAndDeserialize<MyModpackV2>(
|
||||
_modpackDescriptorPath,
|
||||
_descriptor.modpack.artifact.url,
|
||||
_descriptor.modpack.artifact.sha1,
|
||||
@ -36,12 +36,12 @@ public class MyModpackV1DownloadTaskFactory : INetworkTaskFactory
|
||||
$"{_modpack.format_version} != {_descriptor.modpack.format_version}");
|
||||
|
||||
NetworkTask? networkTask = null;
|
||||
_filesToDosnload = _modpack.CheckFiles(_versionDir, checkHashes, didDownloadModpackDescriptor);
|
||||
if(_filesToDosnload.Count > 0)
|
||||
_filesToDownload = _modpack.CheckFiles(_versionDir, checkHashes, didDownloadModpackDescriptor);
|
||||
if(_filesToDownload.Count > 0)
|
||||
{
|
||||
networkTask = new NetworkTask(
|
||||
$"modpack '{_modpack.name}'",
|
||||
_modpack.zip.size,
|
||||
_filesToDownload.Sum(f => f.props.artifact.size),
|
||||
Download
|
||||
);
|
||||
}
|
||||
@ -52,23 +52,19 @@ public class MyModpackV1DownloadTaskFactory : INetworkTaskFactory
|
||||
private async Task Download(NetworkProgressReporter pr, CancellationToken ct)
|
||||
{
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"started downloading modpack '{_modpack!.name}'");
|
||||
if(string.IsNullOrEmpty(_modpack.zip.url))
|
||||
throw new Exception($"modpack '{_modpack.name}' doesn't have a url to download");
|
||||
|
||||
var _archivePath = Path.Concat(PathHelper.GetCacheDir(), "modpacks", _modpack.name + ".zip");
|
||||
await NetworkHelper.DownloadFile(_modpack.zip.url, _archivePath, ct, pr.AddBytesCount);
|
||||
|
||||
await using var zipf = File.OpenRead(_archivePath);
|
||||
using var archive = new ZipArchive(zipf);
|
||||
foreach (var entry in archive.Entries)
|
||||
ParallelOptions opt = new()
|
||||
{
|
||||
IOPath relativePath = new(entry.FullName);
|
||||
if(_filesToDosnload.TryGetValue(relativePath, out var absolutePath))
|
||||
MaxDegreeOfParallelism = LauncherApp.Config.max_parallel_downloads,
|
||||
CancellationToken = ct
|
||||
};
|
||||
await Parallel.ForEachAsync(_filesToDownload, opt, async (f, _ct) =>
|
||||
{
|
||||
Directory.Create(absolutePath.ParentDir());
|
||||
entry.ExtractToFile(absolutePath.ToString(), true);
|
||||
}
|
||||
}
|
||||
LauncherApp.Logger.LogDebug(nameof(NetworkHelper), $"downloading file '{f.relativePath}'");
|
||||
if(string.IsNullOrEmpty(f.props.artifact.url))
|
||||
throw new Exception($"file '{f.relativePath}' doesn't have a url to download");
|
||||
await NetworkHelper.DownloadFile(f.props.artifact.url, f.absolutePath, _ct, pr.AddBytesCount);
|
||||
});
|
||||
|
||||
LauncherApp.Logger.LogInfo(nameof(NetworkHelper), $"finished downloading modpack '{_modpack.name}'");
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user