diff --git a/Млаумчерб.Клиент/LauncherLogger.cs b/Млаумчерб.Клиент/LauncherLogger.cs index cd7d219..a76eb34 100644 --- a/Млаумчерб.Клиент/LauncherLogger.cs +++ b/Млаумчерб.Клиент/LauncherLogger.cs @@ -1,7 +1,4 @@ -using DTLib.Filesystem; -using DTLib.Logging; - -namespace Млаумчерб.Клиент; +namespace Млаумчерб.Клиент; public class LauncherLogger : FileLogger { diff --git a/Млаумчерб.Клиент/Главне.cs b/Млаумчерб.Клиент/Главне.cs index 26adaf6..a46a181 100644 --- a/Млаумчерб.Клиент/Главне.cs +++ b/Млаумчерб.Клиент/Главне.cs @@ -6,6 +6,7 @@ global using DTLib.Logging; global using DTLib.Filesystem; global using File = DTLib.Filesystem.File; global using Directory = DTLib.Filesystem.Directory; +global using Path = DTLib.Filesystem.Path; using System.Globalization; using Avalonia; diff --git a/Млаумчерб.Клиент/Игра.cs b/Млаумчерб.Клиент/Игра.cs index 31c2145..b21d01a 100644 --- a/Млаумчерб.Клиент/Игра.cs +++ b/Млаумчерб.Клиент/Игра.cs @@ -1,6 +1,8 @@ -using System.Threading.Tasks; -using DTLib.Filesystem; -using Path = DTLib.Filesystem.Path; +using System.Threading; +using System.Threading.Tasks; +using CliWrap; +using DTLib.Extensions; +using Млаумчерб.Клиент.классы; namespace Млаумчерб.Клиент; @@ -11,6 +13,7 @@ public interface IGame Progress BeginUpdate(); void EndUpdate(); Task Launch(); + void Close(); } public class MinecraftVersion : IGame @@ -18,6 +21,13 @@ public class MinecraftVersion : IGame public string Name { get; } public IOPath InstallationDirectory { get; } + private IOPath JavawFilePath; + + private JavaArguments javaArgs; + private GameArguments gameArgs; + private CancellationTokenSource? cts; + private CommandTask commandTask; + public MinecraftVersion(string name) { Name = name; @@ -34,8 +44,28 @@ public class MinecraftVersion : IGame throw new NotImplementedException(); } - public Task Launch() + public async Task Launch() { - throw new NotImplementedException(); + var javaArgsList = javaArgs.FillPlaceholders([]); + var gameArgsList = gameArgs.FillPlaceholders([]); + var command = Cli.Wrap(JavawFilePath.ToString()) + .WithWorkingDirectory(InstallationDirectory.ToString()) + .WithArguments(javaArgsList) + .WithArguments(gameArgsList); + Приложение.Логгер.LogInfo(nameof(MinecraftVersion), + $"launching the game" + + "\njava: " + command.TargetFilePath + + "\nworking_dir: " + command.WorkingDirPath + + "\njava_arguments: \n\t" + javaArgsList.MergeToString("\n\t") + + "\ngame_arguments: \n\t" + gameArgsList.MergeToString("\n\t")); + cts = new(); + commandTask = command.ExecuteAsync(cts.Token); + var result = await commandTask; + Приложение.Логгер.LogInfo(nameof(MinecraftVersion), $"game exited with code {result.ExitCode}"); + } + + public void Close() + { + cts?.Cancel(); } } \ No newline at end of file diff --git a/Млаумчерб.Клиент/Млаумчерб.Клиент.csproj b/Млаумчерб.Клиент/Млаумчерб.Клиент.csproj index 6f12b6f..d91b81b 100644 --- a/Млаумчерб.Клиент/Млаумчерб.Клиент.csproj +++ b/Млаумчерб.Клиент/Млаумчерб.Клиент.csproj @@ -18,6 +18,7 @@ + diff --git a/Млаумчерб.Клиент/Настройки.cs b/Млаумчерб.Клиент/Настройки.cs index fccfe8b..b30f30a 100644 --- a/Млаумчерб.Клиент/Настройки.cs +++ b/Млаумчерб.Клиент/Настройки.cs @@ -1,5 +1,4 @@ -using DTLib.Logging; -using Newtonsoft.Json; +using Newtonsoft.Json; namespace Млаумчерб.Клиент; diff --git a/Млаумчерб.Клиент/Ошибки.cs b/Млаумчерб.Клиент/Ошибки.cs index b55b0eb..31a2545 100644 --- a/Млаумчерб.Клиент/Ошибки.cs +++ b/Млаумчерб.Клиент/Ошибки.cs @@ -1,6 +1,5 @@ using Avalonia.Controls; using DTLib.Ben.Demystifier; -using DTLib.Logging; using MsBox.Avalonia; using MsBox.Avalonia.Dto; using MsBox.Avalonia.Enums; diff --git a/Млаумчерб.Клиент/классы/Буржуазия.cs b/Млаумчерб.Клиент/классы/Буржуазия.cs index b6e4022..5b1d621 100644 --- a/Млаумчерб.Клиент/классы/Буржуазия.cs +++ b/Млаумчерб.Клиент/классы/Буржуазия.cs @@ -17,7 +17,8 @@ public class Os public class Rule { [JsonRequired] public string action { get; set; } = ""; - [JsonRequired] public Os os { get; set; } = null!; + public Os? os { get; set; } + public Dictionary? features { get; set; } } public class Classifiers @@ -80,6 +81,18 @@ public class JavaVersion [JsonRequired] public int majorVersion { get; set; } } +public class ArgValue +{ + [JsonRequired] public string value { get; set; } = ""; + public List rules { get; set; } = new(); +} + +public class ArgumentsNew +{ + [JsonRequired] public List jvm { get; set; } = new(); + [JsonRequired] public List game { get; set; } = new(); +} + public class MinecraftVersionDescriptor { [JsonRequired] public string id { get; set; } = ""; @@ -94,5 +107,52 @@ public class MinecraftVersionDescriptor [JsonRequired] public List libraries { get; set; } = null!; [JsonRequired] public AssetIndex assetIndex { get; set; } = null!; [JsonRequired] public string assets { get; set; } = ""; - // public string minecraftArguments { get; set; } + public string? minecraftArguments { get; set; } + public ArgumentsNew? arguments { get; set; } +} + +public static class Буржуазия +{ + public static bool CheckOs(Os os) + { + return os.name switch + { + "osx" => OperatingSystem.IsWindows(), + "linux" => OperatingSystem.IsLinux(), + "windows" => OperatingSystem.IsWindows(), + _ => throw new ArgumentOutOfRangeException(os.name) + }; + } + + public static bool CheckRules(ICollection rules, ICollection enabled_features) + { + bool allowed = false; + foreach (var r in rules) + { + if (r.os == null || CheckOs(r.os)) + { + if (r.features != null) + { + foreach (var feature in enabled_features) + { + if(r.features.TryGetValue(feature, out bool is_enabled)) + { + if (is_enabled) + { + if (r.action == "allow") + allowed = true; + else return false; + } + } + } + } + + if (r.action == "allow") + allowed = true; + else return false; + } + } + + return allowed; + } } \ No newline at end of file diff --git a/Млаумчерб.Клиент/классы/Пролетариат.cs b/Млаумчерб.Клиент/классы/Пролетариат.cs index efa37f2..666a95c 100644 --- a/Млаумчерб.Клиент/классы/Пролетариат.cs +++ b/Млаумчерб.Клиент/классы/Пролетариат.cs @@ -1,6 +1,89 @@ -namespace Млаумчерб.Клиент.классы; +using DTLib.Extensions; + +namespace Млаумчерб.Клиент.классы; public class Пролетариат { -} \ No newline at end of file +} + +public class ArgumentsWithPlaceholders +{ + protected List raw_args = new(); + + public List FillPlaceholders(Dictionary values) + { + List result = new(); + foreach (var a in raw_args) + { + var f = a; + int begin = a.IndexOf('$'); + if (begin != -1) + { + int keyBegin = begin + 2; + int end = a.IndexOf('}', keyBegin); + if (end != -1) + { + var key = a.Substring(keyBegin, end - keyBegin); + if (!values.TryGetValue(key, out var v)) + throw new Exception($"can't find value for placeholder '{key}'"); + f = v; + } + } + result.Add(f); + } + + return result; + } +} + +public class JavaArguments : ArgumentsWithPlaceholders +{ + private static readonly string[] _initial_arguments = + [ + + ]; + + private static readonly string[] _enabled_features = + [ + + ]; + + public JavaArguments(MinecraftVersionDescriptor d) + { + raw_args.AddRange(_initial_arguments); + if (d.arguments is not null) + { + foreach (var av in d.arguments.jvm) + { + if(Буржуазия.CheckRules(av.rules, _enabled_features)) + raw_args.Add(av.value); + } + } + } +} + +public class GameArguments : ArgumentsWithPlaceholders +{ + private static readonly string[] _enabled_features = + [ + "has_custom_resolution" + ]; + + public GameArguments(MinecraftVersionDescriptor d) + { + 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(Буржуазия.CheckRules(av.rules, _enabled_features)) + raw_args.Add(av.value); + } + } + } +} +