using System.Diagnostics; using Lentia.Core.Auth.Yggdrasil; using Lentia.Core.Game.Extra; using Lentia.Core.Utils; using Lentia.Utils; namespace Lentia.Core.Game; public static class GameHelper { public static async Task PrepareGame(string targetVersion, string gameRoot, bool installForge) { try { string versionUrl = await VersionsHelper.GetVersionUrlAsync(targetVersion); MinecraftVersion version = await VersionsHelper.GetVersionDetailsAsync(versionUrl); MinecraftVersion workingVersion = version; if (installForge) { MinecraftVersion? forgeMeta = await ForgeHelper.ProcessForge(version, gameRoot); if (forgeMeta != null) { workingVersion = version; } } AssetsIndex assetsIndex = await AssetsHelper.GetAssetsIndexAsync(version.AssetIndex!.Url!); await AssetsHelper.DownloadAssetsParallel(assetsIndex, gameRoot); await JavaHelper.GetJavaExecutablePath(version, gameRoot); await VersionsHelper.DownloadClientJar(version, gameRoot); await LibrariesHelper.DownloadLibraries(workingVersion.Libraries!, gameRoot); LibrariesHelper.ExtractNatives(workingVersion, gameRoot); await VersionsHelper.DownloadLoggingConfig(version, gameRoot); return workingVersion; } catch (Exception) { throw; } } public static string BuildClasspath(MinecraftVersion version, string gameRoot) { var paths = new List(); string libRoot = Path.Combine(gameRoot, "libraries"); paths.Add(Path.Combine(gameRoot, "versions", version.Id!, $"{version.Id}.jar")); foreach (var lib in version.Libraries!) { if (LibrariesHelper.IsAllowed(lib.Rules, OsHelper.GetOSName())) { string relPath = ForgeHelper.GeneratePathFromArtifactName(lib.Name!); paths.Add(Path.Combine(libRoot, relPath)); } } string separator = Path.PathSeparator.ToString(); return string.Join(separator, paths); } public static List GenerateGameArguments(MinecraftVersion version, AuthenticateResponse auth, string gameRoot) { string? rawArgs = version.MinecraftArguments; if (string.IsNullOrEmpty(rawArgs)) { return new List(); } rawArgs = rawArgs.Replace("${auth_player_name}", auth.User.Username); rawArgs = rawArgs.Replace("${version_name}", version.Id ?? "Lentia"); rawArgs = rawArgs.Replace("${game_directory}", gameRoot); rawArgs = rawArgs.Replace("${assets_root}", Path.Combine(gameRoot, "assets")); rawArgs = rawArgs.Replace("${assets_index_name}", version.AssetIndex?.Id ?? "legacy"); rawArgs = rawArgs.Replace("${auth_uuid}", auth.SelectedProfile.Id); rawArgs = rawArgs.Replace("${auth_access_token}", auth.AccessToken); rawArgs = rawArgs.Replace("${user_type}", "mojang"); rawArgs = rawArgs.Replace("${user_properties}", "{}"); return rawArgs.Split(" ", StringSplitOptions.RemoveEmptyEntries).ToList(); } public static void Launch(MinecraftVersion version, AuthenticateResponse auth, string gameRoot, Action logHandler) { string javaPath = SettingsManager.ReadSettings().JavaPath; string nativesDir = Path.Combine(gameRoot, "versions", version.Id!, "natives"); var jvmArgs = new List { $"-Xmx{SettingsManager.ReadSettings().Ram.Max}M", $"-Djava.library.path={nativesDir}", "-Dminecraft.launcher.brand=Lentia", "-Dminecraft.launcher.version=1.0.0" }; // if (version.Logging?.Client?.Argument != null) { // string logConfig = Path.Combine(gameRoot, "assets", "log_configs", version.Logging.Client.File?.Id ?? "client-log4j2.xml"); // jvmArgs.Add(version.Logging.Client.Argument.Replace("${path}", logConfig)); // } string classpath = BuildClasspath(version, gameRoot); jvmArgs.Add("-cp"); jvmArgs.Add(classpath); jvmArgs.Add(version.MainClass ?? "net.minecraft.client.main.Main"); var gameArgs = GenerateGameArguments(version, auth, gameRoot); jvmArgs.AddRange(gameArgs); var startInfo = new ProcessStartInfo(javaPath) { WorkingDirectory = gameRoot, Arguments = string.Join(" ", jvmArgs.Select(a => a.Contains(" ") ? $"\"{a}\"" : a)), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true }; var process = new Process { StartInfo = startInfo, EnableRaisingEvents = true }; process.OutputDataReceived += (s, e) => { if (e.Data != null) logHandler(e.Data); }; process.ErrorDataReceived += (s, e) => { if (e.Data != null) logHandler($"[ERROR] {e.Data}"); }; process.Exited += (sender, e) => { logHandler("GAME_CLOSED"); }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); } }