Introduces core game logic for launching Minecraft, including asset, library, and Java runtime management. Adds Forge mod support, OS utilities, and file helpers. Updates frontend to handle game launch, log streaming, and UI feedback. Minor bugfixes and style improvements are also included.
124 lines
5.2 KiB
C#
124 lines
5.2 KiB
C#
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<MinecraftVersion> 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>();
|
|
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<string> GenerateGameArguments(MinecraftVersion version, AuthenticateResponse auth, string gameRoot) {
|
|
string? rawArgs = version.MinecraftArguments;
|
|
|
|
if (string.IsNullOrEmpty(rawArgs)) {
|
|
return new List<string>();
|
|
}
|
|
|
|
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<string> logHandler) {
|
|
string javaPath = SettingsManager.ReadSettings().JavaPath;
|
|
|
|
string nativesDir = Path.Combine(gameRoot, "versions", version.Id!, "natives");
|
|
|
|
var jvmArgs = new List<string> {
|
|
$"-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();
|
|
}
|
|
|
|
} |