now it works
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class GameVersionCatalog
|
||||
{
|
||||
[JsonRequired] public List<RemoteVersionDescriptorProps> versions { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class AssetProperties
|
||||
{
|
||||
[JsonRequired] public string hash { get; set; } = "";
|
||||
[JsonRequired] public int size { get; set; }
|
||||
}
|
||||
|
||||
public class AssetIndex
|
||||
{
|
||||
[JsonRequired] public Dictionary<string, AssetProperties> objects { get; set; } = new();
|
||||
}
|
||||
|
||||
public class RemoteVersionDescriptorProps
|
||||
{
|
||||
[JsonRequired] public string id { get; set; } = "";
|
||||
[JsonRequired] public string type { get; set; } = "";
|
||||
[JsonRequired] public string url { get; set; } = "";
|
||||
[JsonRequired] public string sha1 { get; set; } = "";
|
||||
[JsonRequired] public DateTime time { get; set; }
|
||||
[JsonRequired] public DateTime releaseTime { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using System.Linq;
|
||||
// ReSharper disable CollectionNeverUpdated.Global
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class GameVersionDescriptor
|
||||
{
|
||||
[JsonRequired] public string id { get; set; } = "";
|
||||
[JsonRequired] public DateTime time { get; set; }
|
||||
[JsonRequired] public DateTime releaseTime { get; set; }
|
||||
[JsonRequired] public string type { get; set; } = "";
|
||||
[JsonRequired] public string mainClass { get; set; } = "";
|
||||
[JsonRequired] public Downloads downloads { get; set; } = null!;
|
||||
[JsonRequired] public List<Library> libraries { get; set; } = null!;
|
||||
[JsonRequired] public AssetIndexProperties assetIndex { get; set; } = null!;
|
||||
[JsonRequired] public string assets { get; set; } = "";
|
||||
public JavaVersion javaVersion { get; set; } = new() { component = "jre-legacy", majorVersion = 8 };
|
||||
public string? minecraftArguments { get; set; }
|
||||
public ArgumentsNew? arguments { get; set; }
|
||||
}
|
||||
|
||||
public class Artifact
|
||||
{
|
||||
[JsonRequired] public string url { get; set; } = "";
|
||||
[JsonRequired] public string sha1 { get; set; } = "";
|
||||
[JsonRequired] public int size { get; set; }
|
||||
}
|
||||
|
||||
public class Os
|
||||
{
|
||||
public string? name { get; set; }
|
||||
public string? arch { get; set; }
|
||||
}
|
||||
|
||||
public class Rule
|
||||
{
|
||||
[JsonRequired] public string action { get; set; } = "";
|
||||
public Os? os { get; set; }
|
||||
public Dictionary<string, bool>? features { get; set; }
|
||||
}
|
||||
|
||||
public class LibraryDownloads
|
||||
{
|
||||
public Artifact? artifact { get; set; }
|
||||
public Dictionary<string, Artifact>? classifiers { get; set; }
|
||||
}
|
||||
|
||||
public class Extract
|
||||
{
|
||||
public List<string>? exclude { get; set; }
|
||||
}
|
||||
|
||||
public class Natives
|
||||
{
|
||||
public string? linux { get; set; }
|
||||
public string? osx { get; set; }
|
||||
public string? windows { get; set; }
|
||||
}
|
||||
|
||||
public class Library
|
||||
{
|
||||
[JsonRequired] public string name { get; set; } = "";
|
||||
public List<Rule>? rules { get; set; }
|
||||
public Natives? natives { get; set; }
|
||||
public Extract? extract { get; set; }
|
||||
[JsonRequired] public LibraryDownloads downloads { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class AssetIndexProperties
|
||||
{
|
||||
[JsonRequired] public string id { get; set; } = "";
|
||||
[JsonRequired] public string url { get; set; } = "";
|
||||
[JsonRequired] public string sha1 { get; set; } = "";
|
||||
[JsonRequired] public int size { get; set; }
|
||||
[JsonRequired] public int totalSize { get; set; }
|
||||
}
|
||||
|
||||
public class Downloads
|
||||
{
|
||||
[JsonRequired] public Artifact client { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class JavaVersion
|
||||
{
|
||||
[JsonRequired] public string component { get; set; } = "";
|
||||
[JsonRequired] public int majorVersion { get; set; }
|
||||
}
|
||||
|
||||
public class ArgValue
|
||||
{
|
||||
public struct StringOrArray : IEnumerable<string>
|
||||
{
|
||||
private string[] ar;
|
||||
|
||||
public StringOrArray(ICollection<string> v) => ar = v.ToArray();
|
||||
public StringOrArray(string v) => ar = [v];
|
||||
public static implicit operator StringOrArray(string[] v) => new(v);
|
||||
public static implicit operator StringOrArray(string v) => new(v);
|
||||
public static implicit operator string[](StringOrArray sar) => sar.ar;
|
||||
public IEnumerator<string> GetEnumerator() => ar.AsEnumerable().GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => ar.GetEnumerator();
|
||||
}
|
||||
public ArgValue() { }
|
||||
public ArgValue(string arg) => value = arg;
|
||||
public static implicit operator ArgValue(string arg) => new(arg);
|
||||
[JsonRequired] public StringOrArray value { get; set; } = [];
|
||||
public List<Rule> rules { get; set; } = new();
|
||||
}
|
||||
|
||||
public class ArgumentsNew
|
||||
{
|
||||
[JsonRequired] public List<ArgValue> jvm { get; set; } = new();
|
||||
[JsonRequired] public List<ArgValue> game { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class JavaVersionCatalog
|
||||
{
|
||||
[JsonProperty("linux")]
|
||||
public Dictionary<string, JavaVersionProps[]>? linux_x86 { get; set; }
|
||||
[JsonProperty("linux-i386")]
|
||||
public Dictionary<string, JavaVersionProps[]>? linux_x64 { get; set; }
|
||||
[JsonProperty("mac-os")]
|
||||
public Dictionary<string, JavaVersionProps[]>? osx_x64 { get; set; }
|
||||
[JsonProperty("mac-os-arm64")]
|
||||
public Dictionary<string, JavaVersionProps[]>? osx_arm64 { get; set; }
|
||||
[JsonProperty("windows-arm64")]
|
||||
public Dictionary<string, JavaVersionProps[]>? windows_arm64 { get; set; }
|
||||
[JsonProperty("windows-x64")]
|
||||
public Dictionary<string, JavaVersionProps[]>? windows_x64 { get; set; }
|
||||
[JsonProperty("windows-x86")]
|
||||
public Dictionary<string, JavaVersionProps[]>? windows_x86 { get; set; }
|
||||
|
||||
public JavaVersionProps GetVersionProps(JavaVersion version)
|
||||
{
|
||||
var arch = RuntimeInformation.OSArchitecture;
|
||||
Dictionary<string, JavaVersionProps[]>? propsDict = null;
|
||||
switch (arch)
|
||||
{
|
||||
case Architecture.X86:
|
||||
if (OperatingSystem.IsWindows())
|
||||
propsDict = windows_x86;
|
||||
else if (OperatingSystem.IsLinux())
|
||||
propsDict = linux_x86;
|
||||
break;
|
||||
case Architecture.X64:
|
||||
if (OperatingSystem.IsWindows())
|
||||
propsDict = windows_x64;
|
||||
else if (OperatingSystem.IsLinux())
|
||||
propsDict = linux_x64;
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
propsDict = osx_x64;
|
||||
break;
|
||||
case Architecture.Arm64:
|
||||
if (OperatingSystem.IsWindows())
|
||||
propsDict = windows_arm64;
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
propsDict = osx_arm64;
|
||||
break;
|
||||
}
|
||||
|
||||
if (propsDict != null && propsDict.TryGetValue(version.component, out var props_array))
|
||||
{
|
||||
if (props_array.Length != 0)
|
||||
return props_array[0];
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException($"Can't download java {version.majorVersion} for your operating system. " +
|
||||
$"Download it manually to directory {PathHelper.GetJavaRuntimeDir(version.component)}");
|
||||
}
|
||||
}
|
||||
|
||||
public class JavaVersionProps
|
||||
{
|
||||
/// url of JavaDistributiveManifest
|
||||
[JsonRequired] public Artifact manifest { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class JavaDistributiveManifest
|
||||
{
|
||||
[JsonRequired] public Dictionary<string, JavaDistributiveElementProps> files { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class JavaDistributiveElementProps
|
||||
{
|
||||
/// "directory" / "file"
|
||||
[JsonRequired] public string type { get; set; } = "";
|
||||
public bool? executable { get; set; }
|
||||
public JavaCompressedArtifact? downloads { get; set; }
|
||||
}
|
||||
|
||||
public class JavaCompressedArtifact
|
||||
{
|
||||
public Artifact? lzma { get; set; }
|
||||
[JsonRequired] public Artifact raw { get; set; } = null!;
|
||||
}
|
||||
40
Mlaumcherb.Client.Avalonia/классы/Буржуазия/Rules.cs
Normal file
40
Mlaumcherb.Client.Avalonia/классы/Буржуазия/Rules.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public static class Rules
|
||||
{
|
||||
public static bool Check(ICollection<Rule>? rules, ICollection<string> features)
|
||||
{
|
||||
if(rules is null || rules.Count == 0)
|
||||
return true;
|
||||
|
||||
bool allowed = false;
|
||||
foreach (var r in rules)
|
||||
{
|
||||
if (r.os != null && !PlatformHelper.CheckOs(r.os))
|
||||
continue;
|
||||
|
||||
if (r.features == null)
|
||||
allowed = r.action == "allow";
|
||||
else
|
||||
{
|
||||
foreach (var feature in features)
|
||||
{
|
||||
if (r.features.TryGetValue(feature, out bool is_enabled))
|
||||
{
|
||||
if (is_enabled)
|
||||
{
|
||||
allowed = r.action == "allow";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(allowed)
|
||||
break;
|
||||
}
|
||||
|
||||
return allowed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class ArgumentsWithPlaceholders
|
||||
{
|
||||
protected List<string> _raw_args = new();
|
||||
|
||||
public IEnumerable<string> FillPlaceholders(Dictionary<string, string> values)
|
||||
{
|
||||
foreach (var _s in _raw_args)
|
||||
{
|
||||
string arg = _s;
|
||||
int begin = arg.IndexOf("${", StringComparison.Ordinal);
|
||||
while(begin != -1)
|
||||
{
|
||||
int keyBegin = begin + 2;
|
||||
int end = arg.IndexOf('}', keyBegin);
|
||||
if (end != -1)
|
||||
{
|
||||
var key = arg.Substring(keyBegin, end - keyBegin);
|
||||
if (!values.TryGetValue(key, out var value))
|
||||
throw new Exception($"can't find value for placeholder '{key}'");
|
||||
arg = arg.Replace("${"+ key + "}", value);
|
||||
}
|
||||
if(end + 1 < arg.Length)
|
||||
begin = arg.IndexOf("${", end + 1, StringComparison.Ordinal);
|
||||
else break;
|
||||
}
|
||||
yield return arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using DTLib.Extensions;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class GameArguments : ArgumentsWithPlaceholders
|
||||
{
|
||||
private static readonly string[] _initial_arguments =
|
||||
[
|
||||
"--width", "${resolution_width}",
|
||||
"--height", "${resolution_height}",
|
||||
];
|
||||
|
||||
private static readonly string[] _enabled_features =
|
||||
[
|
||||
];
|
||||
|
||||
public GameArguments(GameVersionDescriptor d)
|
||||
{
|
||||
_raw_args.AddRange(_initial_arguments);
|
||||
|
||||
if (d.minecraftArguments is not null)
|
||||
{
|
||||
_raw_args.AddRange(d.minecraftArguments.SplitToList(' ', quot: '"'));
|
||||
}
|
||||
else if (d.arguments is not null)
|
||||
{
|
||||
foreach (var av in d.arguments.game)
|
||||
{
|
||||
if(Rules.Check(av.rules, _enabled_features))
|
||||
{
|
||||
foreach (var arg in av.value)
|
||||
{
|
||||
if(!_raw_args.Contains(arg))
|
||||
_raw_args.Add(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else throw new Exception("no game arguments specified in descriptor");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class GameVersionProps : IComparable<GameVersionProps>, IEquatable<GameVersionProps>
|
||||
{
|
||||
public string Name { get; }
|
||||
public IOPath LocalDescriptorPath { get; }
|
||||
public string? RemoteDescriptorUrl { get; }
|
||||
private bool _isDownloaded;
|
||||
public bool IsDownloaded
|
||||
{
|
||||
get => _isDownloaded;
|
||||
set
|
||||
{
|
||||
bool downloadCompleted = value && !_isDownloaded;
|
||||
_isDownloaded = value;
|
||||
if(downloadCompleted)
|
||||
OnDownloadCompleted?.Invoke();
|
||||
}
|
||||
}
|
||||
public event Action? OnDownloadCompleted;
|
||||
|
||||
public GameVersionProps(string name, string? url)
|
||||
{
|
||||
Name = name;
|
||||
LocalDescriptorPath = PathHelper.GetVersionDescriptorPath(name);
|
||||
RemoteDescriptorUrl = url;
|
||||
IsDownloaded = File.Exists(PathHelper.GetVersionJarFilePath(name));
|
||||
}
|
||||
|
||||
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,49 @@
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class JavaArguments : ArgumentsWithPlaceholders
|
||||
{
|
||||
private static readonly string[] _initial_arguments =
|
||||
[
|
||||
"-XX:+UnlockExperimentalVMOptions",
|
||||
"-XX:+UseG1GC",
|
||||
"-XX:G1NewSizePercent=20",
|
||||
"-XX:G1ReservePercent=20",
|
||||
"-XX:MaxGCPauseMillis=50",
|
||||
"-XX:G1HeapRegionSize=32M",
|
||||
"-XX:+DisableExplicitGC",
|
||||
"-XX:+AlwaysPreTouch",
|
||||
"-XX:+ParallelRefProcEnabled",
|
||||
"-Xms${xms}M",
|
||||
"-Xmx${xmx}M",
|
||||
"-Dfile.encoding=UTF-8",
|
||||
"-Dlog4j.configurationFile=${path}",
|
||||
"-Djava.library.path=${natives_directory}",
|
||||
"-Dminecraft.client.jar=${client_jar}",
|
||||
"-Dminecraft.launcher.brand=${launcher_name}",
|
||||
"-Dminecraft.launcher.version=${launcher_version}",
|
||||
"-cp", "${classpath}"
|
||||
];
|
||||
|
||||
private static readonly string[] _enabled_features =
|
||||
[
|
||||
];
|
||||
|
||||
public JavaArguments(GameVersionDescriptor d)
|
||||
{
|
||||
_raw_args.AddRange(_initial_arguments);
|
||||
if (d.arguments is not null)
|
||||
{
|
||||
foreach (var av in d.arguments.jvm)
|
||||
{
|
||||
if (Rules.Check(av.rules, _enabled_features))
|
||||
{
|
||||
foreach (var arg in av.value)
|
||||
{
|
||||
if(!_raw_args.Contains(arg))
|
||||
_raw_args.Add(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
Mlaumcherb.Client.Avalonia/классы/Пролетариат/Libraries.cs
Normal file
80
Mlaumcherb.Client.Avalonia/классы/Пролетариат/Libraries.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using DTLib.Extensions;
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia.классы;
|
||||
|
||||
public class Libraries
|
||||
{
|
||||
private static readonly string[] enabled_features = [];
|
||||
|
||||
public record JarLib(string name, IOPath jarFilePath, Artifact artifact);
|
||||
public record NativeLib(string name, IOPath jarFilePath, Artifact artifact, Extract? extractionOptions)
|
||||
: JarLib(name, jarFilePath, artifact);
|
||||
|
||||
public IReadOnlyCollection<JarLib> Libs { get; }
|
||||
|
||||
public Libraries(GameVersionDescriptor descriptor)
|
||||
{
|
||||
List<JarLib> libs = new();
|
||||
HashSet<string> libHashes = new();
|
||||
|
||||
foreach (var l in descriptor.libraries)
|
||||
{
|
||||
if (l.rules != null && !Rules.Check(l.rules, enabled_features))
|
||||
continue;
|
||||
|
||||
if (l.natives != null)
|
||||
{
|
||||
string? nativesKey;
|
||||
if (OperatingSystem.IsWindows())
|
||||
nativesKey = l.natives.windows;
|
||||
else if (OperatingSystem.IsLinux())
|
||||
nativesKey = l.natives.linux;
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
nativesKey = l.natives.osx;
|
||||
else throw new PlatformNotSupportedException();
|
||||
if(nativesKey is null)
|
||||
throw new Exception($"nativesKey for '{l.name}' is null");
|
||||
|
||||
// example: "natives-windows-${arch}"
|
||||
if (nativesKey.Contains('$'))
|
||||
{
|
||||
var span = nativesKey.AsSpan();
|
||||
nativesKey = span.After("${").Before('}') switch
|
||||
{
|
||||
"arch" => span.Before("${").ToString() + PlatformHelper.GetArchOld(),
|
||||
_ => throw new Exception($"unknown placeholder in {nativesKey}")
|
||||
};
|
||||
}
|
||||
|
||||
Artifact artifact = null!;
|
||||
if(l.downloads.classifiers != null && !l.downloads.classifiers.TryGetValue(nativesKey, out artifact!))
|
||||
throw new Exception($"can't find artifact for '{l.name}' with nativesKey '{nativesKey}'");
|
||||
|
||||
// skipping duplicates (WHO THE HELL CREATES THIS DISCRIPTORS AAAAAAAAA)
|
||||
if(!libHashes.Add(artifact.sha1))
|
||||
continue;
|
||||
|
||||
string urlTail = artifact.url.AsSpan().After("://").After('/').ToString();
|
||||
IOPath jarFilePath = Path.Concat(PathHelper.GetLibrariesDir(), urlTail);
|
||||
libs.Add(new NativeLib(l.name, jarFilePath, artifact, l.extract));
|
||||
}
|
||||
else
|
||||
{
|
||||
Artifact? artifact = l.downloads.artifact;
|
||||
if (artifact == null)
|
||||
throw new NullReferenceException($"artifact for '{l.name}' is null");
|
||||
|
||||
// skipping duplicates
|
||||
if(!libHashes.Add(artifact.sha1))
|
||||
continue;
|
||||
|
||||
string urlTail = artifact.url.AsSpan().After("://").After('/').ToString();
|
||||
IOPath jarFilePath = Path.Concat(PathHelper.GetLibrariesDir(), urlTail);
|
||||
libs.Add(new JarLib(l.name, jarFilePath, artifact));
|
||||
}
|
||||
}
|
||||
|
||||
Libs = libs;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user