forge support
This commit is contained in:
parent
cb85b132c3
commit
631f5c9126
@ -17,16 +17,16 @@ public record Config
|
||||
public int max_memory { get; set; } = 4096;
|
||||
public string minecraft_dir { get; set; } = ".";
|
||||
public bool download_java { get; set; } = true;
|
||||
public bool redirect_game_output { get; set; } = false;
|
||||
public string? last_launched_version { get; set; }
|
||||
public int max_parallel_downloads { get; set; } = 16;
|
||||
|
||||
|
||||
public VersionCatalogProps[] version_catalogs { get; set; } =
|
||||
[
|
||||
new() { Name = "Mojang", Url = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json" }
|
||||
];
|
||||
|
||||
[JsonIgnore] static IOPath _filePath = "config.json";
|
||||
|
||||
[JsonIgnore] private static IOPath _filePath = "config.json";
|
||||
|
||||
public static Config LoadFromFile()
|
||||
{
|
||||
|
||||
@ -7,6 +7,7 @@ using Mlaumcherb.Client.Avalonia.классы;
|
||||
using Mlaumcherb.Client.Avalonia.сеть;
|
||||
using Mlaumcherb.Client.Avalonia.сеть.TaskFactories;
|
||||
using Mlaumcherb.Client.Avalonia.холопы;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using static Mlaumcherb.Client.Avalonia.холопы.PathHelper;
|
||||
|
||||
namespace Mlaumcherb.Client.Avalonia;
|
||||
@ -62,8 +63,31 @@ public class GameVersion
|
||||
private GameVersion(GameVersionProps props)
|
||||
{
|
||||
_props = props;
|
||||
|
||||
string descriptorText = File.ReadAllText(props.LocalDescriptorPath);
|
||||
_descriptor = JsonConvert.DeserializeObject<GameVersionDescriptor>(descriptorText)
|
||||
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(Name, $"merging descriptor '{parentDescriptorId}' with '{Name}'");
|
||||
IOPath parentDescriptorPath = GetVersionDescriptorPath(parentDescriptorId);
|
||||
if (!File.Exists(parentDescriptorPath))
|
||||
throw new Exception($"Версия '{Name} требует установить версию '{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(props.LocalDescriptorPath, descriptorRaw.ToString());
|
||||
}
|
||||
|
||||
_descriptor = descriptorRaw.ToObject<GameVersionDescriptor>()
|
||||
?? throw new Exception($"can't parse descriptor file '{props.LocalDescriptorPath}'");
|
||||
_javaArgs = new JavaArguments(_descriptor);
|
||||
_gameArgs = new GameArguments(_descriptor);
|
||||
@ -190,9 +214,13 @@ public class GameVersion
|
||||
var command = Cli.Wrap(JavaExecutableFilePath.ToString())
|
||||
.WithWorkingDirectory(WorkingDirectory.ToString())
|
||||
.WithArguments(argsList)
|
||||
.WithStandardOutputPipe(PipeTarget.ToDelegate(LogGameOut))
|
||||
.WithStandardErrorPipe(PipeTarget.ToDelegate(LogGameError))
|
||||
.WithValidation(CommandResultValidation.None);
|
||||
if (LauncherApp.Config.redirect_game_output)
|
||||
{
|
||||
command = command
|
||||
.WithStandardOutputPipe(PipeTarget.ToDelegate(LogGameOut))
|
||||
.WithStandardErrorPipe(PipeTarget.ToDelegate(LogGameError));
|
||||
}
|
||||
LauncherApp.Logger.LogInfo(Name, "launching the game");
|
||||
LauncherApp.Logger.LogDebug(Name, "java: " + command.TargetFilePath);
|
||||
LauncherApp.Logger.LogDebug(Name, "working_dir: " + command.WorkingDirPath);
|
||||
|
||||
@ -15,6 +15,12 @@ public class LauncherApp : Application
|
||||
Config = Config.LoadFromFile();
|
||||
Logger.DebugLogEnabled = Config.debug;
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
|
||||
// some file required by forge installer
|
||||
if (!File.Exists("launcher_profiles.json"))
|
||||
{
|
||||
File.WriteAllText("launcher_profiles.json", "{}");
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
|
||||
@ -90,6 +90,9 @@
|
||||
<CheckBox IsChecked="{Binding #window.EnableJavaDownload}">
|
||||
Скачивать джаву
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding #window.RedirectGameOutput}">
|
||||
Выводить лог игры в лаунчер
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<Button Name="LaunchButton" Grid.Row="1"
|
||||
|
||||
@ -51,6 +51,15 @@ public partial class MainWindow : Window
|
||||
set => SetValue(EnableJavaDownloadProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> RedirectGameOutputProperty =
|
||||
AvaloniaProperty.Register<MainWindow, bool>(nameof(RedirectGameOutput),
|
||||
defaultBindingMode: BindingMode.TwoWay, defaultValue: false);
|
||||
public bool RedirectGameOutput
|
||||
{
|
||||
get => GetValue(RedirectGameOutputProperty);
|
||||
set => SetValue(RedirectGameOutputProperty, value);
|
||||
}
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
@ -65,6 +74,7 @@ public partial class MainWindow : Window
|
||||
PlayerName = LauncherApp.Config.player_name;
|
||||
MemoryLimit = LauncherApp.Config.max_memory;
|
||||
EnableJavaDownload = LauncherApp.Config.download_java;
|
||||
RedirectGameOutput = LauncherApp.Config.redirect_game_output;
|
||||
|
||||
InstalledVersionComboBox.SelectedIndex = 0;
|
||||
InstalledVersionComboBox.IsEnabled = false;
|
||||
@ -119,6 +129,7 @@ public partial class MainWindow : Window
|
||||
LauncherApp.Config.player_name = PlayerName;
|
||||
LauncherApp.Config.max_memory = MemoryLimit;
|
||||
LauncherApp.Config.download_java = EnableJavaDownload;
|
||||
LauncherApp.Config.redirect_game_output = RedirectGameOutput;
|
||||
LauncherApp.Config.SaveToFile();
|
||||
if (selectedVersion == null)
|
||||
return;
|
||||
|
||||
@ -21,6 +21,7 @@ public class GameVersionDescriptor
|
||||
|
||||
public class Artifact
|
||||
{
|
||||
public string? path = null;
|
||||
[JsonRequired] public string url { get; set; } = "";
|
||||
[JsonRequired] public string sha1 { get; set; } = "";
|
||||
[JsonRequired] public int size { get; set; }
|
||||
|
||||
@ -7,18 +7,22 @@ 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)
|
||||
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; }
|
||||
|
||||
private IOPath? TryGetJarFilePath(Artifact artifact)
|
||||
private IOPath GetJarFilePath(Artifact artifact)
|
||||
{
|
||||
if(string.IsNullOrEmpty(artifact.url))
|
||||
return null;
|
||||
string urlTail = artifact.url.AsSpan().After("://").After('/').ToString();
|
||||
return Path.Concat(PathHelper.GetLibrariesDir(), urlTail);
|
||||
string relativePath;
|
||||
if (!string.IsNullOrEmpty(artifact.path))
|
||||
relativePath = artifact.path;
|
||||
else if (!string.IsNullOrEmpty(artifact.url))
|
||||
relativePath = artifact.url.AsSpan().After("://").After('/').ToString();
|
||||
else throw new ArgumentException("Artifact must have a path or url");
|
||||
|
||||
return Path.Concat(PathHelper.GetLibrariesDir(), relativePath);
|
||||
}
|
||||
|
||||
public Libraries(GameVersionDescriptor descriptor)
|
||||
@ -63,7 +67,7 @@ public class Libraries
|
||||
if(!libHashes.Add(artifact.sha1))
|
||||
continue;
|
||||
|
||||
libs.Add(new NativeLib(l.name, TryGetJarFilePath(artifact), artifact, l.extract));
|
||||
libs.Add(new NativeLib(l.name, GetJarFilePath(artifact), artifact, l.extract));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -75,7 +79,7 @@ public class Libraries
|
||||
if(!libHashes.Add(artifact.sha1))
|
||||
continue;
|
||||
|
||||
libs.Add(new JarLib(l.name, TryGetJarFilePath(artifact), artifact));
|
||||
libs.Add(new JarLib(l.name, GetJarFilePath(artifact), artifact));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -43,15 +43,7 @@ public class LibrariesDownloadTaskFactory : INetworkTaskFactory
|
||||
|
||||
foreach (var l in _libraries.Libs)
|
||||
{
|
||||
// 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))
|
||||
if (!File.Exists(l.jarFilePath))
|
||||
{
|
||||
_libsToDownload.Add(l);
|
||||
}
|
||||
@ -61,7 +53,7 @@ public class LibrariesDownloadTaskFactory : INetworkTaskFactory
|
||||
}
|
||||
else if (checkHashes)
|
||||
{
|
||||
using var fs = File.OpenRead(l.jarFilePath.Value);
|
||||
using var fs = File.OpenRead(l.jarFilePath);
|
||||
string hash = _hasher.ComputeHash(fs).HashToString();
|
||||
if(hash != l.artifact.sha1)
|
||||
_libsToDownload.Add(l);
|
||||
@ -91,12 +83,12 @@ public class LibrariesDownloadTaskFactory : INetworkTaskFactory
|
||||
await Parallel.ForEachAsync(_libsToDownload, opt, async (l, _ct) =>
|
||||
{
|
||||
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(string.IsNullOrEmpty(l.artifact.url))
|
||||
throw new Exception($"library '{l.name}' doesn't have a url to download");
|
||||
await DownloadFile(l.artifact.url, l.jarFilePath, _ct, pr.AddBytesCount);
|
||||
if (l is Libraries.NativeLib n)
|
||||
{
|
||||
var zipf = File.OpenRead(n.jarFilePath!.Value);
|
||||
var zipf = File.OpenRead(n.jarFilePath);
|
||||
ZipFile.ExtractToDirectory(zipf, _nativesDir.ToString(), true);
|
||||
if (n.extractionOptions?.exclude != null)
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user