StartCommandBuilder.cs 15 KB

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