using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Text.Json; using VeloeMinecraftLauncher.Entity.Version; namespace VeloeMinecraftLauncher.Utils; internal static class StartCommandBuilder { public static string Build(Entity.Version.Version version, string username) { var returnString = new StringBuilder(); char separator = ':'; if (OperatingSystem.IsWindows()) separator = ';'; if (version is null) return returnString.ToString(); // setting natives folder if (version.InheritsFrom is null) returnString.Append($"-Djava.library.path=\"{Path.GetDirectoryName(Settings.minecraftForlderPath + "versions/" + version.Id + "/natives/")}\""); else returnString.Append($"-Djava.library.path=\"{Path.GetDirectoryName(Settings.minecraftForlderPath + "versions/" + version.InheritsFrom + "/natives/")}\""); //for forge, vanilla optifine, fabric returnString.Append(" -cp \""); // add libraries foreach(var library in version.Libraries) { bool rulesVaild = true; //check if native if (library.Natives is not null) continue; //rules check if (library.Rules is not null) { rulesVaild = false; foreach (var rule in library.Rules) { bool isRuleOsExist = rule.Os is not null; if (rule.Action == "allow" && rule.Os is null) { rulesVaild = true; continue; } if (rule.Os is not null) if (rule.Action == "allow" && (rule.Os.Name == "linux" && OperatingSystem.IsLinux() || rule.Os.Name == "windows" && OperatingSystem.IsWindows()) ) { rulesVaild = true; continue; } } } //if no path if (library.Downloads is null) //for optifine { var libPath = GetLibPathFromName(library.Name); if (rulesVaild) returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "libraries/" + libPath +".jar") + separator); continue; } if (rulesVaild) returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "libraries/" + library.Downloads.Artifact.Path) + separator); } Entity.Version.Version? inheritsFrom = null; if (version.InheritsFrom is null) returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "versions/" + version.Id + "/" + version.Id + ".jar")); //main jar file else { //for forge, vanilla optifine, fabric //add libraries from inherited version var inheritsJsonString = File.ReadAllText(Settings.minecraftForlderPath + "versions/" + version.InheritsFrom + "/" + version.InheritsFrom + ".json"); inheritsFrom = JsonSerializer.Deserialize(inheritsJsonString, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); foreach (var library in inheritsFrom?.Libraries ?? new()) { bool rulesVaild = true; if (library.Natives is not null) continue; if (library.Rules is not null) { rulesVaild = false; foreach (var rule in library.Rules) { bool isRuleOsExist = rule.Os is not null; if (rule.Action == "allow" && rule.Os is null) { rulesVaild = true; continue; } if (rule.Os is not null) if (rule.Action == "allow" && (rule.Os.Name == "linux" && OperatingSystem.IsLinux() || rule.Os.Name == "windows" && OperatingSystem.IsWindows()) ) { rulesVaild = true; continue; } } } if(rulesVaild) returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "libraries/" + library.Downloads.Artifact.Path) + separator); } //main jar file //check here if there is jar file not inherited //check if it is not 0kb size (fabric) var fileInfo = new FileInfo($"{Settings.minecraftForlderPath}versions/{version.Id}/{version.Id}.jar"); if (fileInfo.Exists && fileInfo.Length > 0) returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "versions/" + version.Id + "/" + version.Id + ".jar"));//for optifine else returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "versions/" + version.InheritsFrom + "/" + version.InheritsFrom + ".jar"));//for forge } returnString.Append("\""); //check for jvm fabric options if (version.Arguments is not null && version.InheritsFrom is not null) { if (version.Arguments.Jvm is not null) foreach (var argument in version.Arguments.Jvm) { if (argument is null) continue; var type = argument.GetType(); if (!(argument is JsonElement)) continue; if (!(((JsonElement)argument).ValueKind == JsonValueKind.String)) continue; var value = ((JsonElement)argument).Deserialize(typeof(string)) as string; if (value is null) continue; //for new forge versions (1.18, 1.19) if (value.Contains("${version_name}")) { value = value.Replace("${version_name}", version.InheritsFrom); } if (value.Contains("${library_directory}")) { value = value.Replace("${library_directory}", Path.GetDirectoryName(Settings.minecraftForlderPath + "libraries/")); } if (value.Contains("${classpath_separator}")) { value = value.Replace("${classpath_separator}", separator.ToString()); } bool containsArgWithValue = value.Contains('='); bool containsPathValueOnly = value.StartsWith(Path.GetDirectoryName(Settings.minecraftForlderPath + "libraries/")!); //value = value.Replace(" ", ""); if (containsArgWithValue) value = value.Replace("=", "=\""); returnString.Append(" "); if (containsPathValueOnly) returnString.Append("\""); returnString.Append(value); if (containsArgWithValue || containsPathValueOnly) returnString.Append("\""); } } //max ram if (Settings.setMaxRam) returnString.Append($" -Xmx{Settings.maxRam}M "); returnString.Append(" " + version.MainClass); List args = new List(); List argsValues = new List(); if (version.Arguments is not null) { foreach (var argument in version.Arguments.Game) { if (argument is null) continue; var type = argument.GetType(); if (!(argument is JsonElement)) continue; if (!(((JsonElement)argument).ValueKind == JsonValueKind.String)) continue; var value = ((JsonElement)argument).Deserialize(typeof(string)) as string; if (value is null) continue; if (!(value).Contains("--")) { argsValues.Add(value); continue; } args.Add(value); } } if (version.MinecraftArguments is not null) { var minecraftArguments = version.MinecraftArguments.Split(' '); //args = version.minecraftArguments.Split(' ').Where(x=> x.Contains("--")).ToList(); for (int i = 0; i < minecraftArguments.Count(); i++) { if (minecraftArguments[i].Contains("--")) { args.Add(minecraftArguments[i]); if (minecraftArguments[i+1] is not null) argsValues.Add(minecraftArguments[i+1]); } //else // argsValues.Add(minecraftArguments[i]); } } Dictionary argsProvided = new Dictionary() { { "--username", false }, { "--version", false }, { "--gameDir", false}, { "--assetsDir", false }, { "--assetIndex", false }, { "--uuid", false }, { "--accessToken", false}, { "--userType", false}, { "--tweakClass", false } }; //check if all required arguments provided. Use inheritFrom if needed foreach (var arg in args) { argsProvided[arg] = true; } if (argsProvided.ContainsValue(false)) { if (inheritsFrom?.Arguments is not null) { foreach (var argument in inheritsFrom.Arguments.Game) { if (argument is null) continue; var type = argument.GetType(); if (!(argument is JsonElement)) continue; if (!(((JsonElement)argument).ValueKind == JsonValueKind.String)) continue; var value = ((JsonElement)argument).Deserialize(typeof(string)) as string; if (value is null) continue; if (!(value).Contains("--")) { argsValues.Add(value); continue; } if (!argsProvided.GetValueOrDefault(value, false)) { args.Add(value); argsProvided[value] = true; } } } if (inheritsFrom?.MinecraftArguments is not null) { var minecraftArguments = inheritsFrom.MinecraftArguments.Split(' '); //args = version.minecraftArguments.Split(' ').Where(x=> x.Contains("--")).ToList(); for (int i = 0; i < minecraftArguments.Count(); i++) { if (minecraftArguments[i].Contains("--")) { args.Add(minecraftArguments[i]); argsProvided[minecraftArguments[i]] = true; } else argsValues.Add(minecraftArguments[i]); } } } for (int i = 0; i < args.Count; i++) { switch (args[i]) { case "--username": returnString.Append(" --username " + username); break; case "--version": returnString.Append(" --version " + version.Id /*"'Copy of VeloeLauncher'"*/); break; case "--gameDir": //for forge if (!(argsValues.Where(x => x.Contains("forge")).Count() > 0 || version.Id.ToLower().Contains("fabric"))) returnString.Append(" --gameDir " + "\"" + Path.GetDirectoryName(Settings.minecraftForlderPath) + "\""); else returnString.Append(" --gameDir " + "\"" + Path.GetDirectoryName(Settings.minecraftForlderPath + "versions/" + version.Id + "/") + "\""); break; case "--assetsDir": //for forge if (version.InheritsFrom is null) returnString.Append(" --assetsDir " + "\"" + Path.GetDirectoryName(Settings.minecraftForlderPath + "assets/" + version.Assets + "/") + "\""); else if (inheritsFrom is not null) returnString.Append(" --assetsDir " + "\"" + Path.GetDirectoryName(Settings.minecraftForlderPath + "assets/" + inheritsFrom.Assets + "/") + "\""); break; case "--assetIndex": //for forge if (version.InheritsFrom is null) returnString.Append(" --assetIndex " + version.Assets); else if (inheritsFrom is not null) returnString.Append(" --assetIndex " + inheritsFrom.Assets); break; case "--uuid": returnString.Append(" --uuid sample_token"); break; case "--accessToken": returnString.Append(" --accessToken sample_token"); break; case "--userType": returnString.Append(" --userType offline"); break; case "--userProperties": returnString.Append(" --userProperties " + "{\"veloelauncher\":[\"wtfisthis\"]}"); break; case "--versionType": returnString.Append(" --versionType " + version.Type); break; case "--tweakClass": returnString.Append(" --tweakClass"); if (argsValues[i] is not null) returnString.Append(" " + argsValues[i]); break; //for new forge default: if (argsValues[i] is not null && !argsValues[i].Contains("${")) { returnString.Append($" {args[i]} {argsValues[i]}"); } break; } } return returnString.ToString(); } public static string GetLibPathFromName(string name, bool extention = false) { Debug.WriteLine($"GameLibPathFromName: {name}"); var dirs = name.Split(':'); dirs[0] = dirs[0].Replace('.', '/'); var libPath = String.Empty; foreach (var dir in dirs) { libPath += dir + "/"; } libPath += dirs[dirs.Length - 2] + "-" + dirs[dirs.Length - 1]; if (extention) libPath += ".jar"; if (File.Exists(Settings.minecraftForlderPath + "libraries/" + libPath)) Debug.WriteLine($"Lib exists: {Settings.minecraftForlderPath + "libraries/" + libPath}"); else Debug.WriteLine($"Lib not exists: {Settings.minecraftForlderPath + "libraries/" + libPath}"); return libPath; } }