StartCommandBuilder.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Text.Json;
  8. using VeloeMinecraftLauncher.Entity.Version;
  9. namespace VeloeMinecraftLauncher.Utils;
  10. internal static class StartCommandBuilder
  11. {
  12. public static string Build(Entity.Version.Version version, string username)
  13. {
  14. var returnString = new StringBuilder();
  15. char separator = ':';
  16. if (OperatingSystem.IsWindows())
  17. separator = ';';
  18. if (version is null)
  19. return returnString.ToString();
  20. // setting natives folder
  21. if (version.InheritsFrom is null)
  22. returnString.Append($"-Djava.library.path=\"{Path.GetDirectoryName(Settings.minecraftForlderPath + "versions/" + version.Id + "/natives/")}\"");
  23. else
  24. returnString.Append($"-Djava.library.path=\"{Path.GetDirectoryName(Settings.minecraftForlderPath + "versions/" + version.InheritsFrom + "/natives/")}\""); //for forge, vanilla optifine, fabric
  25. returnString.Append(" -cp \"");
  26. // add libraries
  27. foreach(var library in version.Libraries)
  28. {
  29. bool rulesVaild = true;
  30. //check if native
  31. if (library.Natives is not null)
  32. continue;
  33. //rules check
  34. if (library.Rules is not null)
  35. {
  36. rulesVaild = false;
  37. foreach (var rule in library.Rules)
  38. {
  39. bool isRuleOsExist = rule.Os is not null;
  40. if (rule.Action == "allow" && rule.Os is null)
  41. {
  42. rulesVaild = true;
  43. continue;
  44. }
  45. if (rule.Os is not null)
  46. if (rule.Action == "allow" &&
  47. (rule.Os.Name == "linux" && OperatingSystem.IsLinux() ||
  48. rule.Os.Name == "windows" && OperatingSystem.IsWindows())
  49. )
  50. {
  51. rulesVaild = true;
  52. continue;
  53. }
  54. }
  55. }
  56. //if no path
  57. if (library.Downloads is null) //for optifine
  58. {
  59. var libPath = GetLibPathFromName(library.Name);
  60. if (rulesVaild)
  61. returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "libraries/" + libPath +".jar") + separator);
  62. continue;
  63. }
  64. if (rulesVaild)
  65. returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "libraries/" + library.Downloads.Artifact.Path) + separator);
  66. }
  67. Entity.Version.Version? inheritsFrom = null;
  68. if (version.InheritsFrom is null)
  69. returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "versions/" + version.Id + "/" + version.Id + ".jar")); //main jar file
  70. else
  71. {
  72. //for forge, vanilla optifine, fabric
  73. //add libraries from inherited version
  74. var inheritsJsonString = File.ReadAllText(Settings.minecraftForlderPath + "versions/" + version.InheritsFrom + "/" + version.InheritsFrom + ".json");
  75. inheritsFrom = JsonSerializer.Deserialize<Entity.Version.Version>(inheritsJsonString, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
  76. foreach (var library in inheritsFrom?.Libraries ?? new())
  77. {
  78. bool rulesVaild = true;
  79. if (library.Natives is not null)
  80. continue;
  81. if (library.Rules is not null)
  82. {
  83. rulesVaild = false;
  84. foreach (var rule in library.Rules)
  85. {
  86. bool isRuleOsExist = rule.Os is not null;
  87. if (rule.Action == "allow" && rule.Os is null)
  88. {
  89. rulesVaild = true;
  90. continue;
  91. }
  92. if (rule.Os is not null)
  93. if (rule.Action == "allow" &&
  94. (rule.Os.Name == "linux" && OperatingSystem.IsLinux() ||
  95. rule.Os.Name == "windows" && OperatingSystem.IsWindows())
  96. )
  97. {
  98. rulesVaild = true;
  99. continue;
  100. }
  101. }
  102. }
  103. if(rulesVaild)
  104. returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "libraries/" + library.Downloads.Artifact.Path) + separator);
  105. }
  106. //main jar file
  107. //check here if there is jar file not inherited
  108. //check if it is not 0kb size (fabric)
  109. var fileInfo = new FileInfo($"{Settings.minecraftForlderPath}versions/{version.Id}/{version.Id}.jar");
  110. if (fileInfo.Exists && fileInfo.Length > 0)
  111. returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "versions/" + version.Id + "/" + version.Id + ".jar"));//for optifine
  112. else
  113. returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "versions/" + version.InheritsFrom + "/" + version.InheritsFrom + ".jar"));//for forge
  114. }
  115. returnString.Append("\"");
  116. //check for jvm fabric options
  117. if (version.Arguments is not null && version.InheritsFrom is not null)
  118. {
  119. if (version.Arguments.Jvm is not null)
  120. foreach (var argument in version.Arguments.Jvm)
  121. {
  122. if (argument is null)
  123. continue;
  124. var type = argument.GetType();
  125. if (!(argument is JsonElement))
  126. continue;
  127. if (!(((JsonElement)argument).ValueKind == JsonValueKind.String))
  128. continue;
  129. var value = ((JsonElement)argument).Deserialize(typeof(string)) as string;
  130. if (value is null) continue;
  131. //for new forge versions (1.18, 1.19)
  132. if (value.Contains("${version_name}"))
  133. {
  134. value = value.Replace("${version_name}", version.InheritsFrom);
  135. }
  136. if (value.Contains("${library_directory}"))
  137. {
  138. value = value.Replace("${library_directory}", Path.GetDirectoryName(Settings.minecraftForlderPath + "libraries/"));
  139. }
  140. if (value.Contains("${classpath_separator}"))
  141. {
  142. value = value.Replace("${classpath_separator}", separator.ToString());
  143. }
  144. bool containsArgWithValue = value.Contains('=');
  145. bool containsPathValueOnly = value.StartsWith(Path.GetDirectoryName(Settings.minecraftForlderPath + "libraries/")!);
  146. //value = value.Replace(" ", "");
  147. if (containsArgWithValue)
  148. value = value.Replace("=", "=\"");
  149. returnString.Append(" ");
  150. if (containsPathValueOnly)
  151. returnString.Append("\"");
  152. returnString.Append(value);
  153. if (containsArgWithValue || containsPathValueOnly)
  154. returnString.Append("\"");
  155. }
  156. }
  157. //max ram
  158. if (Settings.setMaxRam)
  159. returnString.Append($" -Xmx{Settings.maxRam}M ");
  160. returnString.Append(" " + version.MainClass);
  161. List<string> args = new List<string>();
  162. List<string> argsValues = new List<string>();
  163. if (version.Arguments is not null)
  164. {
  165. foreach (var argument in version.Arguments.Game)
  166. {
  167. if (argument is null)
  168. continue;
  169. var type = argument.GetType();
  170. if (!(argument is JsonElement))
  171. continue;
  172. if (!(((JsonElement)argument).ValueKind == JsonValueKind.String))
  173. continue;
  174. var value = ((JsonElement)argument).Deserialize(typeof(string)) as string;
  175. if (value is null) continue;
  176. if (!(value).Contains("--"))
  177. {
  178. argsValues.Add(value);
  179. continue;
  180. }
  181. args.Add(value);
  182. }
  183. }
  184. if (version.MinecraftArguments is not null)
  185. {
  186. var minecraftArguments = version.MinecraftArguments.Split(' ');
  187. //args = version.minecraftArguments.Split(' ').Where(x=> x.Contains("--")).ToList();
  188. for (int i = 0; i < minecraftArguments.Count(); i++)
  189. {
  190. if (minecraftArguments[i].Contains("--"))
  191. {
  192. args.Add(minecraftArguments[i]);
  193. if (minecraftArguments[i+1] is not null)
  194. argsValues.Add(minecraftArguments[i+1]);
  195. }
  196. //else
  197. // argsValues.Add(minecraftArguments[i]);
  198. }
  199. }
  200. Dictionary<string, bool> argsProvided = new Dictionary<string, bool>()
  201. {
  202. { "--username", false },
  203. { "--version", false },
  204. { "--gameDir", false},
  205. { "--assetsDir", false },
  206. { "--assetIndex", false },
  207. { "--uuid", false },
  208. { "--accessToken", false},
  209. { "--userType", false},
  210. { "--tweakClass", false }
  211. };
  212. //check if all required arguments provided. Use inheritFrom if needed
  213. foreach (var arg in args)
  214. {
  215. argsProvided[arg] = true;
  216. }
  217. if (argsProvided.ContainsValue(false))
  218. {
  219. if (inheritsFrom?.Arguments is not null)
  220. {
  221. foreach (var argument in inheritsFrom.Arguments.Game)
  222. {
  223. if (argument is null)
  224. continue;
  225. var type = argument.GetType();
  226. if (!(argument is JsonElement))
  227. continue;
  228. if (!(((JsonElement)argument).ValueKind == JsonValueKind.String))
  229. continue;
  230. var value = ((JsonElement)argument).Deserialize(typeof(string)) as string;
  231. if (value is null) continue;
  232. if (!(value).Contains("--"))
  233. {
  234. argsValues.Add(value);
  235. continue;
  236. }
  237. if (!argsProvided.GetValueOrDefault(value, false))
  238. {
  239. args.Add(value);
  240. argsProvided[value] = true;
  241. }
  242. }
  243. }
  244. if (inheritsFrom?.MinecraftArguments is not null)
  245. {
  246. var minecraftArguments = inheritsFrom.MinecraftArguments.Split(' ');
  247. //args = version.minecraftArguments.Split(' ').Where(x=> x.Contains("--")).ToList();
  248. for (int i = 0; i < minecraftArguments.Count(); i++)
  249. {
  250. if (minecraftArguments[i].Contains("--"))
  251. {
  252. args.Add(minecraftArguments[i]);
  253. argsProvided[minecraftArguments[i]] = true;
  254. }
  255. else
  256. argsValues.Add(minecraftArguments[i]);
  257. }
  258. }
  259. }
  260. for (int i = 0; i < args.Count; i++)
  261. {
  262. switch (args[i])
  263. {
  264. case "--username":
  265. returnString.Append(" --username " + username);
  266. break;
  267. case "--version":
  268. returnString.Append(" --version " + version.Id /*"'Copy of VeloeLauncher'"*/);
  269. break;
  270. case "--gameDir":
  271. //for forge
  272. if (!(argsValues.Where(x => x.Contains("forge")).Count() > 0 || version.Id.ToLower().Contains("fabric")))
  273. returnString.Append(" --gameDir " + "\"" + Path.GetDirectoryName(Settings.minecraftForlderPath) + "\"");
  274. else
  275. returnString.Append(" --gameDir " + "\"" + Path.GetDirectoryName(Settings.minecraftForlderPath + "versions/" + version.Id + "/") + "\"");
  276. break;
  277. case "--assetsDir":
  278. //for forge
  279. if (version.InheritsFrom is null)
  280. returnString.Append(" --assetsDir " + "\"" + Path.GetDirectoryName(Settings.minecraftForlderPath + "assets/" + version.Assets + "/") + "\"");
  281. else if (inheritsFrom is not null)
  282. returnString.Append(" --assetsDir " + "\"" + Path.GetDirectoryName(Settings.minecraftForlderPath + "assets/" + inheritsFrom.Assets + "/") + "\"");
  283. break;
  284. case "--assetIndex":
  285. //for forge
  286. if (version.InheritsFrom is null)
  287. returnString.Append(" --assetIndex " + version.Assets);
  288. else if (inheritsFrom is not null)
  289. returnString.Append(" --assetIndex " + inheritsFrom.Assets);
  290. break;
  291. case "--uuid":
  292. returnString.Append(" --uuid sample_token");
  293. break;
  294. case "--accessToken":
  295. returnString.Append(" --accessToken sample_token");
  296. break;
  297. case "--userType":
  298. returnString.Append(" --userType offline");
  299. break;
  300. case "--userProperties":
  301. returnString.Append(" --userProperties " + "{\"veloelauncher\":[\"wtfisthis\"]}");
  302. break;
  303. case "--versionType":
  304. returnString.Append(" --versionType " + version.Type);
  305. break;
  306. case "--tweakClass":
  307. returnString.Append(" --tweakClass");
  308. if (argsValues[i] is not null)
  309. returnString.Append(" " + argsValues[i]);
  310. break;
  311. //for new forge
  312. default:
  313. if (argsValues[i] is not null && !argsValues[i].Contains("${"))
  314. {
  315. returnString.Append($" {args[i]} {argsValues[i]}");
  316. }
  317. break;
  318. }
  319. }
  320. return returnString.ToString();
  321. }
  322. public static string GetLibPathFromName(string name, bool extention = false)
  323. {
  324. Debug.WriteLine($"GameLibPathFromName: {name}");
  325. var dirs = name.Split(':');
  326. dirs[0] = dirs[0].Replace('.', '/');
  327. var libPath = String.Empty;
  328. foreach (var dir in dirs)
  329. {
  330. libPath += dir + "/";
  331. }
  332. libPath += dirs[dirs.Length - 2] + "-" + dirs[dirs.Length - 1];
  333. if (extention)
  334. libPath += ".jar";
  335. if (File.Exists(Settings.minecraftForlderPath + "libraries/" + libPath))
  336. Debug.WriteLine($"Lib exists: {Settings.minecraftForlderPath + "libraries/" + libPath}");
  337. else
  338. Debug.WriteLine($"Lib not exists: {Settings.minecraftForlderPath + "libraries/" + libPath}");
  339. return libPath;
  340. }
  341. }