InstalledGameVersionCatalog
This commit is contained in:
@@ -3,14 +3,13 @@
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
|
||||
public class VersionCatalogProps
|
||||
public class GameVersionCatalogProps
|
||||
{
|
||||
[JsonRequired] public required string name { get; init; }
|
||||
[JsonRequired] public required string url { get; init; }
|
||||
|
||||
public override string ToString() => name;
|
||||
|
||||
|
||||
public async Task<GameVersionCatalog> GetVersionCatalogAsync()
|
||||
{
|
||||
return await NetworkHelper.DownloadStringAndDeserialize<GameVersionCatalog>(url);
|
||||
@@ -1,83 +0,0 @@
|
||||
using Mlaumcherb.Client.Avalonia.зримое;
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class GameVersionProps : IComparable<GameVersionProps>, IEquatable<GameVersionProps>
|
||||
{
|
||||
public string Name { get; }
|
||||
public IOPath LocalDescriptorPath { get; }
|
||||
public RemoteVersionDescriptorProps? RemoteProps { get; }
|
||||
private bool _isDownloaded;
|
||||
public bool IsDownloaded
|
||||
{
|
||||
get => _isDownloaded;
|
||||
set
|
||||
{
|
||||
if(_isDownloaded != value)
|
||||
{
|
||||
_isDownloaded = value;
|
||||
StatusChanged?.Invoke(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
public event Action<bool>? StatusChanged;
|
||||
|
||||
private GameVersionProps(string name, RemoteVersionDescriptorProps? remoteProps)
|
||||
{
|
||||
|
||||
Name = name;
|
||||
RemoteProps = remoteProps;
|
||||
LocalDescriptorPath = PathHelper.GetVersionDescriptorPath(name);
|
||||
IsDownloaded = File.Exists(PathHelper.GetVersionJarFilePath(name));
|
||||
}
|
||||
|
||||
public GameVersionProps(string name)
|
||||
: this(name, null)
|
||||
{ }
|
||||
|
||||
public GameVersionProps(RemoteVersionDescriptorProps remoteProps)
|
||||
: this(remoteProps.id, remoteProps)
|
||||
{ }
|
||||
|
||||
public void DeleteFiles()
|
||||
{
|
||||
IsDownloaded = false;
|
||||
LauncherApp.Logger.LogInfo(Name, "Deleting files...");
|
||||
var verdir = PathHelper.GetVersionDir(Name);
|
||||
if(Directory.Exists(verdir))
|
||||
Directory.Delete(verdir);
|
||||
LauncherApp.Logger.LogInfo(Name, "Files deleted");
|
||||
}
|
||||
|
||||
public override string ToString() => Name;
|
||||
|
||||
public override int GetHashCode() => Name.GetHashCode();
|
||||
|
||||
public int CompareTo(GameVersionProps? other)
|
||||
{
|
||||
if (ReferenceEquals(this, other)) return 0;
|
||||
if (other is null) return 1;
|
||||
|
||||
if (Version.TryParse(Name, out var version1) && Version.TryParse(other.Name, out var version2))
|
||||
{
|
||||
return version1.CompareTo(version2);
|
||||
}
|
||||
|
||||
return String.Compare(Name, other.Name, StringComparison.InvariantCulture);
|
||||
}
|
||||
|
||||
public bool Equals(GameVersionProps? other)
|
||||
{
|
||||
if (other is null) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return Name == other.Name;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is GameVersionProps other) return Equals(other);
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
using Mlaumcherb.Client.Avalonia.зримое;
|
||||
using Mlaumcherb.Client.Avalonia.сеть;
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class InstalledGameVersionProps : IComparable<InstalledGameVersionProps>, IEquatable<InstalledGameVersionProps>
|
||||
{
|
||||
[JsonRequired] public string Id { get; }
|
||||
public GameVersionCatalogProps? CatalogProps { get; set; }
|
||||
|
||||
public RemoteVersionDescriptorProps? DescriptorProps { get; set; }
|
||||
|
||||
|
||||
private bool _isInstalled;
|
||||
[JsonIgnore]
|
||||
public bool IsInstalled
|
||||
{
|
||||
get => _isInstalled;
|
||||
set
|
||||
{
|
||||
_isInstalled = value;
|
||||
StatusChanged?.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore] public IOPath DescriptorPath { get; }
|
||||
|
||||
public event Action<bool>? StatusChanged;
|
||||
|
||||
public InstalledGameVersionProps(string id, GameVersionCatalogProps? catalogProps, RemoteVersionDescriptorProps? descriptorProps)
|
||||
{
|
||||
this.Id = id;
|
||||
this.CatalogProps = catalogProps;
|
||||
this.DescriptorProps = descriptorProps;
|
||||
DescriptorPath = PathHelper.GetVersionDescriptorPath(id);
|
||||
IsInstalled = File.Exists(PathHelper.GetVersionJarFilePath(id));
|
||||
}
|
||||
|
||||
public async Task<GameVersion> LoadDescriptor(bool checkForUpdates)
|
||||
{
|
||||
// check if DescriptorProps had been changed on on remote version catalog server
|
||||
if (checkForUpdates && CatalogProps is not null && DescriptorProps is not null)
|
||||
{
|
||||
var remoteCatalog = await NetworkHelper.DownloadStringAndDeserialize<GameVersionCatalog>(CatalogProps.url);
|
||||
|
||||
DescriptorProps = remoteCatalog.versions.Find(remoteProps => remoteProps.id == Id);
|
||||
if(DescriptorProps is null)
|
||||
LauncherApp.Logger.LogWarn(nameof(InstalledGameVersionProps),
|
||||
$"Game version '{Id}' was deleted from remote catalog '{CatalogProps.name}'."
|
||||
+ "It is kept locally, but can't be updated anymore.");
|
||||
}
|
||||
|
||||
// Descriptor is downloaded here
|
||||
if (HashHelper.CheckFileSHA1(DescriptorPath, DescriptorProps?.sha1, checkForUpdates))
|
||||
{
|
||||
if (DescriptorProps is null)
|
||||
throw new NullReferenceException(
|
||||
$"can't download game version descriptor '{Id}', because RemoteDescriptor is null");
|
||||
// download descriptor
|
||||
await NetworkHelper.DownloadFile(DescriptorProps.url, DescriptorPath);
|
||||
}
|
||||
|
||||
string descriptorText = File.ReadAllText(DescriptorPath);
|
||||
JObject descriptorRaw = JObject.Parse(descriptorText);
|
||||
|
||||
// Descriptors can inherit from other descriptors.
|
||||
// For example, 1.12.2-forge-14.23.5.2860 inherits from 1.12.2
|
||||
if (descriptorRaw.TryGetValue("inheritsFrom", out var v))
|
||||
{
|
||||
string parentDescriptorId = v.Value<string>()
|
||||
?? throw new Exception("inheritsFrom is null");
|
||||
LauncherApp.Logger.LogInfo(Id, $"merging descriptor '{parentDescriptorId}' with '{Id}'");
|
||||
IOPath parentDescriptorPath = PathHelper.GetVersionDescriptorPath(parentDescriptorId);
|
||||
if (!File.Exists(parentDescriptorPath))
|
||||
throw new Exception($"Версия '{Id} требует установить версию '{parentDescriptorId}'");
|
||||
string parentDescriptorText = File.ReadAllText(parentDescriptorPath);
|
||||
JObject parentDescriptorRaw = JObject.Parse(parentDescriptorText);
|
||||
parentDescriptorRaw.Merge(descriptorRaw,
|
||||
new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Concat });
|
||||
descriptorRaw = parentDescriptorRaw;
|
||||
// removing dependency
|
||||
descriptorRaw.Remove("inheritsFrom");
|
||||
File.WriteAllText(DescriptorPath, descriptorRaw.ToString());
|
||||
}
|
||||
|
||||
var descriptor = descriptorRaw.ToObject<GameVersionDescriptor>()
|
||||
?? throw new Exception($"can't parse descriptor file '{DescriptorPath}'");
|
||||
|
||||
return new GameVersion(this, descriptor);
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
if(!IsInstalled)
|
||||
return;
|
||||
|
||||
LauncherApp.Logger.LogInfo(Id, "Deleting files...");
|
||||
var verdir = PathHelper.GetVersionDir(Id);
|
||||
if(Directory.Exists(verdir))
|
||||
Directory.Delete(verdir);
|
||||
LauncherApp.Logger.LogInfo(Id, "Files deleted");
|
||||
IsInstalled = false;
|
||||
}
|
||||
|
||||
public override string ToString() => Id;
|
||||
|
||||
public override int GetHashCode() => Id.GetHashCode();
|
||||
|
||||
public int CompareTo(InstalledGameVersionProps? other)
|
||||
{
|
||||
if (ReferenceEquals(this, other))
|
||||
return 0;
|
||||
if (other is null)
|
||||
return 1;
|
||||
|
||||
return String.Compare(Id, other.Id, StringComparison.InvariantCulture);
|
||||
}
|
||||
|
||||
public bool Equals(InstalledGameVersionProps? other)
|
||||
{
|
||||
if (other is null) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return Id == other.Id;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is InstalledGameVersionProps other) return Equals(other);
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System.Linq;
|
||||
using Mlaumcherb.Client.Avalonia.зримое;
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class InstalledVersionCatalog
|
||||
{
|
||||
/// version_id, props
|
||||
[JsonRequired] public Dictionary<string, InstalledGameVersionProps> versions { get; set; } = new();
|
||||
|
||||
private IComparer<InstalledGameVersionProps> reverseComparer = new ReverseComparer<InstalledGameVersionProps>();
|
||||
|
||||
public static InstalledVersionCatalog Load()
|
||||
{
|
||||
InstalledVersionCatalog catalog;
|
||||
var installedCatalogPath = PathHelper.GetInstalledVersionCatalogPath();
|
||||
if (!File.Exists(installedCatalogPath))
|
||||
{
|
||||
LauncherApp.Logger.LogDebug(nameof(InstalledVersionCatalog), "creating new catalog");
|
||||
catalog = new InstalledVersionCatalog();
|
||||
}
|
||||
else
|
||||
{
|
||||
LauncherApp.Logger.LogDebug(nameof(InstalledVersionCatalog), "loading catalog from file");
|
||||
catalog = JsonConvert.DeserializeObject<InstalledVersionCatalog>(
|
||||
File.ReadAllText(installedCatalogPath))
|
||||
?? throw new NullReferenceException($"can't deserialize {installedCatalogPath}");
|
||||
}
|
||||
|
||||
catalog.CheckInstalledVersions();
|
||||
catalog.Save();
|
||||
return catalog;
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
var installedCatalogPath = PathHelper.GetInstalledVersionCatalogPath();
|
||||
LauncherApp.Logger.LogDebug(nameof(InstalledVersionCatalog), "saving catalog to file");
|
||||
var text = JsonConvert.SerializeObject(this, Formatting.Indented);
|
||||
File.WriteAllText(installedCatalogPath, text);
|
||||
LauncherApp.Logger.LogDebug(nameof(InstalledVersionCatalog), "catalog has been saved");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if any versions were installed or deleted manually.
|
||||
/// </summary>
|
||||
public void CheckInstalledVersions()
|
||||
{
|
||||
var versionsUpdated = new List<InstalledGameVersionProps>();
|
||||
Directory.Create(PathHelper.GetVersionsDir());
|
||||
foreach (var subdir in Directory.GetDirectories(PathHelper.GetVersionsDir()))
|
||||
{
|
||||
string id = subdir.LastName().ToString();
|
||||
if (!File.Exists(PathHelper.GetVersionDescriptorPath(id)))
|
||||
throw new Exception(
|
||||
$"Can't find version descriptor file in directory '{subdir}'. Rename it as directory name.");
|
||||
|
||||
if (versions.TryGetValue(id, out var foundProps))
|
||||
{
|
||||
versionsUpdated.Add(foundProps);
|
||||
}
|
||||
else
|
||||
{
|
||||
versionsUpdated.Add(new InstalledGameVersionProps(id, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
// reverse sort
|
||||
versionsUpdated.Sort(reverseComparer);
|
||||
// create dictionary from list
|
||||
versions = new Dictionary<string, InstalledGameVersionProps>(
|
||||
versionsUpdated.Select(props =>
|
||||
new KeyValuePair<string, InstalledGameVersionProps>(props.Id, props)
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ public class ModpackFilesManifest
|
||||
{
|
||||
public class FileProps
|
||||
{
|
||||
[JsonRequired] public string sha1 { get; set; }
|
||||
[JsonRequired] public string sha1 { get; set; } = "";
|
||||
public bool allow_edit { get; set; } = false;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public class MyModpackV1
|
||||
|
||||
// 1
|
||||
[JsonRequired] public int format_version { get; set; }
|
||||
[JsonRequired] public string name { get; set; }
|
||||
[JsonRequired] public string name { get; set; } = "";
|
||||
// zip archive with all files
|
||||
[JsonRequired] public Artifact zip { get; set; } = null!;
|
||||
// ModpackFilesManifest
|
||||
|
||||
Reference in New Issue
Block a user