private static List <LocalMod> AssertSortSatisfied(List <LocalMod> list) { var sorted = ModOrganizer.Sort(list); var indexMap = sorted.ToDictionary(m => m.Name, sorted.IndexOf); foreach (var mod in list) { int index = indexMap[mod.Name]; foreach (var dep in mod.properties.sortAfter) { int i; if (indexMap.TryGetValue(dep, out i) && i > index) { Assert.Fail(mod.Name + " sorted after " + dep); } } foreach (var dep in mod.properties.sortBefore) { int i; if (indexMap.TryGetValue(dep, out i) && i < index) { Assert.Fail(mod.Name + " sorted before " + dep); } } } return(sorted); }
internal static void ServerModMenu() { bool exit = false; while (!exit) { Console.WriteLine("Terraria Server " + Main.versionNumber2 + " - " + ModLoader.versionedName); Console.WriteLine(); var mods = ModOrganizer.FindMods(); for (int k = 0; k < mods.Length; k++) { Console.Write((k + 1) + "\t\t" + mods[k].DisplayName); Console.WriteLine(" (" + (ModLoader.IsEnabled(mods[k].Name) ? "enabled" : "disabled") + ")"); } if (mods.Length == 0) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"No mods were found in: \"{ModLoader.ModPath}\"\nIf you are running a dedicated server, you may wish to use the 'modpath' command line switch or server config setting to specify a custom mods directory.\n"); Console.ResetColor(); } Console.WriteLine("e\t\tEnable All"); Console.WriteLine("d\t\tDisable All"); Console.WriteLine("r\t\tReload and return to world menu"); Console.WriteLine("Type a number to switch between enabled/disabled"); Console.WriteLine(); Console.WriteLine("Type a command: "); string command = Console.ReadLine(); if (command == null) { command = ""; } command = command.ToLower(); Console.Clear(); if (command == "e") { foreach (var mod in mods) { mod.Enabled = true; } } else if (command == "d") { foreach (var mod in mods) { mod.Enabled = false; } } else if (command == "r") { Console.WriteLine("Unloading mods..."); ModLoader.Unload(); ModLoader.Load(); exit = true; } else if (int.TryParse(command, out int value) && value > 0 && value <= mods.Length) { mods[value - 1].Enabled ^= true; } } }
private static bool CommandLineModPackOverride() { if (commandLineModPack == "") { return(true); } if (!commandLineModPack.EndsWith(".json")) { commandLineModPack += ".json"; } string filePath = Path.Combine(UI.UIModPacks.ModListSaveDirectory, commandLineModPack); try { Directory.CreateDirectory(UI.UIModPacks.ModListSaveDirectory); Console.WriteLine(Language.GetTextValue("tModLoader.LoadingSpecifiedModPack", commandLineModPack) + "\n"); var modSet = JsonConvert.DeserializeObject <HashSet <string> >(File.ReadAllText(filePath)); foreach (var mod in ModOrganizer.FindMods()) { ModLoader.SetModEnabled(mod.Name, modSet.Contains(mod.Name)); } return(true); } catch (Exception e) { string err; if (e is FileNotFoundException) { err = Language.GetTextValue("tModLoader.ModPackDoesNotExist", filePath) + "\n"; } else { err = Language.GetTextValue("tModLoader.ModPackDoesNotExist", commandLineModPack, e.Message) + "\n"; } if (Main.dedServ) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(err); Console.ResetColor(); } else { Main.menuMode = Interface.errorMessageID; Interface.errorMessage.SetMessage(err); } return(false); } finally { commandLineModPack = ""; } }
internal void BuildAll() { var modList = new List <LocalMod>(); foreach (var modFolder in FindModSources()) { modList.Add(ReadBuildInfo(modFolder)); } //figure out which of the installed mods are required for building var installedMods = ModOrganizer.FindMods().Where(mod => !modList.Exists(m => m.Name == mod.Name)).ToList(); var requiredFromInstall = new HashSet <LocalMod>(); void Require(LocalMod mod, bool includeWeak) { foreach (var dep in mod.properties.RefNames(includeWeak)) { var depMod = installedMods.SingleOrDefault(m => m.Name == dep); if (depMod != null && requiredFromInstall.Add(depMod)) { Require(depMod, false); } } } foreach (var mod in modList) { Require(mod, true); } modList.AddRange(requiredFromInstall); //sort and version check List <BuildingMod> modsToBuild; try { ModOrganizer.EnsureDependenciesExist(modList, true); ModOrganizer.EnsureTargetVersionsMet(modList); var sortedModList = ModOrganizer.Sort(modList); modsToBuild = sortedModList.OfType <BuildingMod>().ToList(); } catch (ModSortingException e) { throw new BuildException(e.Message); } //build int num = 0; foreach (var mod in modsToBuild) { status.SetProgress(num++, modsToBuild.Count); Build(mod); } }
// This method is split so that the local variables aren't held by the GC when reloading internal static bool SyncClientMods(BinaryReader reader, out bool needsReload) { AllowVanillaClients = reader.ReadBoolean(); Logging.tML.Info($"Server reports AllowVanillaClients set to {AllowVanillaClients}"); Main.statusText = Language.GetTextValue("tModLoader.MPSyncingMods"); var clientMods = ModLoader.Mods; var modFiles = ModOrganizer.FindMods(); needsReload = false; downloadQueue.Clear(); pendingConfigs.Clear(); var syncSet = new HashSet <string>(); var blockedList = new List <ModHeader>(); int n = reader.ReadInt32(); for (int i = 0; i < n; i++) { var header = new ModHeader(reader.ReadString(), new Version(reader.ReadString()), reader.ReadBytes(20), reader.ReadBoolean()); syncSet.Add(header.name); int configCount = reader.ReadInt32(); for (int c = 0; c < configCount; c++) { pendingConfigs.Add(new NetConfig(header.name, reader.ReadString(), reader.ReadString())); } var clientMod = clientMods.SingleOrDefault(m => m.Name == header.name); if (clientMod != null && header.Matches(clientMod.File)) { continue; } needsReload = true; var localVersions = modFiles.Where(m => m.Name == header.name).ToArray(); var matching = Array.Find(localVersions, mod => header.Matches(mod.modFile)); if (matching != null) { matching.Enabled = true; continue; } // overwrite an existing version of the mod if there is one if (localVersions.Length > 0) { header.path = localVersions[0].modFile.path; } if (downloadModsFromServers && (header.signed || !onlyDownloadSignedMods)) { downloadQueue.Enqueue(header); } else { blockedList.Add(header); } } foreach (var mod in clientMods) { if (mod.Side == ModSide.Both && !syncSet.Contains(mod.Name)) { ModLoader.DisableMod(mod.Name); needsReload = true; } } if (blockedList.Count > 0) { var msg = Language.GetTextValue("tModLoader.MPServerModsCantDownload"); msg += downloadModsFromServers ? Language.GetTextValue("tModLoader.MPServerModsCantDownloadReasonSigned") : Language.GetTextValue("tModLoader.MPServerModsCantDownloadReasonAutomaticDownloadDisabled"); msg += ".\n" + Language.GetTextValue("tModLoader.MPServerModsCantDownloadChangeSettingsHint") + "\n"; foreach (var mod in blockedList) { msg += "\n " + mod; } Logging.tML.Warn(msg); Interface.errorMessage.Show(msg, 0); return(false); } // ready to connect, apply configs. Config manager will apply the configs on reload automatically if (!needsReload) { foreach (var pendingConfig in pendingConfigs) { JsonConvert.PopulateObject(pendingConfig.json, ConfigManager.GetConfig(pendingConfig), ConfigManager.serializerSettingsCompact); } if (ConfigManager.AnyModNeedsReload()) { needsReload = true; } else { foreach (var pendingConfig in pendingConfigs) { ConfigManager.GetConfig(pendingConfig).OnChanged(); } } } return(true); }
internal static void SyncClientMods(BinaryReader reader) { AllowVanillaClients = reader.ReadBoolean(); Main.statusText = Language.GetTextValue("tModLoader.MPSyncingMods"); var clientMods = ModLoader.Mods; var modFiles = ModOrganizer.FindMods(); var needsReload = false; downloadQueue.Clear(); var syncSet = new HashSet <string>(); var blockedList = new List <ModHeader>(); int n = reader.ReadInt32(); for (int i = 0; i < n; i++) { var header = new ModHeader(reader.ReadString(), new Version(reader.ReadString()), reader.ReadBytes(20), reader.ReadBoolean()); syncSet.Add(header.name); var clientMod = clientMods.SingleOrDefault(m => m.Name == header.name); if (clientMod != null) { if (header.Matches(clientMod.File)) { continue; } header.path = clientMod.File.path; } else { var disabledVersions = modFiles.Where(m => m.Name == header.name).ToArray(); var matching = disabledVersions.FirstOrDefault(mod => header.Matches(mod.modFile)); if (matching != null) { matching.Enabled = true; needsReload = true; continue; } if (disabledVersions.Length > 0) { header.path = disabledVersions[0].modFile.path; } } if (downloadModsFromServers && (header.signed || !onlyDownloadSignedMods)) { downloadQueue.Enqueue(header); } else { blockedList.Add(header); } } foreach (var mod in clientMods) { if (mod.Side == ModSide.Both && !syncSet.Contains(mod.Name)) { ModLoader.DisableMod(mod.Name); needsReload = true; } } if (blockedList.Count > 0) { var msg = Language.GetTextValue("tModLoader.MPServerModsCantDownload"); msg += downloadModsFromServers ? Language.GetTextValue("tModLoader.MPServerModsCantDownloadReasonSigned") : Language.GetTextValue("tModLoader.MPServerModsCantDownloadReasonAutomaticDownloadDisabled"); msg += ".\n" + Language.GetTextValue("tModLoader.MPServerModsCantDownloadChangeSettingsHint") + "\n"; foreach (var mod in blockedList) { msg += "\n " + mod; } Logging.tML.Warn(msg); Interface.errorMessage.SetMessage(msg); Interface.errorMessage.SetGotoMenu(0); Main.gameMenu = true; Main.menuMode = Interface.errorMessageID; return; } if (downloadQueue.Count > 0) { DownloadNextMod(); } else { OnModsDownloaded(needsReload); } }
public void TestVersionRequirements() { //test version on missing mod var list1 = new List <LocalMod> { Make("A", refs: new[] { "[email protected]" }) }; ModOrganizer.EnsureTargetVersionsMet(list1); //test passed version check var list2 = new List <LocalMod> { Make("A", refs: new[] { "[email protected]" }), Make("B", version: "1.2") }; ModOrganizer.EnsureTargetVersionsMet(list2); //test failed version check var list3 = new List <LocalMod> { Make("A", refs: new[] { "[email protected]" }), Make("B") }; AssertModException( () => ModOrganizer.EnsureTargetVersionsMet(list3), new[] { "A" }, "A requires version 1.2+ of B but version 1.0.0.0 is installed"); //test one pass, two fail version check var list4 = new List <LocalMod> { Make("A"), Make("B", refs: new[] { "[email protected]" }), Make("C", refs: new[] { "[email protected]" }), Make("D", refs: new[] { "[email protected]" }) }; AssertModException( () => ModOrganizer.EnsureTargetVersionsMet(list4), new[] { "C", "D" }, "C requires version 1.1+ of A but version 1.0.0.0 is installed\r\n" + "D requires version 1.0.0.1+ of A but version 1.0.0.0 is installed"); //test weak version check (missing) var list5 = new List <LocalMod> { Make("A", weakRefs: new[] { "[email protected]" }) }; ModOrganizer.EnsureDependenciesExist(list5, false); ModOrganizer.EnsureTargetVersionsMet(list5); //test weak version check (too low) var list6 = new List <LocalMod> { Make("A", weakRefs: new[] { "[email protected]" }), Make("B") }; AssertModException( () => ModOrganizer.EnsureTargetVersionsMet(list6), new[] { "A" }, "A requires version 1.1+ of B but version 1.0.0.0 is installed"); }
public void TestDependenciesExist() { //test A -> B var list1 = new List <LocalMod> { Make("A", refs: new[] { "B" }), Make("B"), }; ModOrganizer.EnsureDependenciesExist(list1, false); //test A -> B (missing) var list2 = new List <LocalMod> { Make("A", refs: new[] { "B" }) }; AssertModException( () => ModOrganizer.EnsureDependenciesExist(list2, false), new[] { "A" }, "Missing mod: B required by A"); //test multi reference var list3 = new List <LocalMod> { Make("A", refs: new[] { "B" }), Make("B"), Make("C", refs: new[] { "A" }) }; ModOrganizer.EnsureDependenciesExist(list3, false); //test one missing reference var list4 = new List <LocalMod> { Make("A", refs: new[] { "B" }), Make("B", refs: new[] { "C" }) }; AssertModException( () => ModOrganizer.EnsureDependenciesExist(list4, false), new[] { "B" }, "Missing mod: C required by B"); //test weak reference (missing) var list5 = new List <LocalMod> { Make("A", weakRefs: new[] { "B" }) }; ModOrganizer.EnsureDependenciesExist(list5, false); AssertModException( () => ModOrganizer.EnsureDependenciesExist(list5, true), new[] { "A" }, "Missing mod: B required by A"); //test weak reference (found) var list6 = new List <LocalMod> { Make("A", weakRefs: new[] { "B" }), Make("B") }; ModOrganizer.EnsureDependenciesExist(list6, true); //test strong (found) and weak (missing) var list7 = new List <LocalMod> { Make("A", refs: new[] { "B" }), Make("B", weakRefs: new[] { "C" }) }; ModOrganizer.EnsureDependenciesExist(list7, false); AssertModException( () => ModOrganizer.EnsureDependenciesExist(list7, true), new[] { "B" }, "Missing mod: C required by B"); //multi test case (missing) var list8 = new List <LocalMod> { Make("A", refs: new[] { "X" }), Make("B", refs: new[] { "Y" }), Make("C", refs: new[] { "D" }), Make("D", weakRefs: new[] { "E" }), Make("E", weakRefs: new[] { "Z" }), Make("F", weakRefs: new[] { "Z" }) }; AssertModException( () => ModOrganizer.EnsureDependenciesExist(list8, false), new[] { "A", "B" }, "Missing mod: X required by A\r\n" + "Missing mod: Y required by B"); AssertModException( () => ModOrganizer.EnsureDependenciesExist(list8, true), new[] { "A", "B", "E", "F" }, "Missing mod: X required by A\r\n" + "Missing mod: Y required by B\r\n" + "Missing mod: Z required by E\r\n" + "Missing mod: Z required by F"); //multi test case (found) var list9 = new List <LocalMod> { Make("A", refs: new[] { "C" }), Make("B", refs: new[] { "C" }), Make("C", refs: new[] { "D" }), Make("D", weakRefs: new[] { "E" }), Make("E", weakRefs: new[] { "F" }), Make("F") }; ModOrganizer.EnsureDependenciesExist(list9, false); ModOrganizer.EnsureDependenciesExist(list9, true); }
internal bool BuildAll(string[] modFolders) { var modList = new List <LocalMod>(); //read mod sources folder foreach (var modFolder in modFolders) { var mod = ReadProperties(modFolder); if (mod == null) { return(false); } modList.Add(mod); } //figure out which of the installed mods are required for building var installedMods = ModOrganizer.FindMods().Where(mod => !modList.Exists(m => m.Name == mod.Name)).ToList(); var requiredFromInstall = new HashSet <LocalMod>(); void Require(LocalMod mod) { foreach (var dep in mod.properties.RefNames(true)) { var depMod = installedMods.SingleOrDefault(m => m.Name == dep); if (depMod != null && requiredFromInstall.Add(depMod)) { Require(depMod); } } } foreach (var mod in modList) { Require(mod); } modList.AddRange(requiredFromInstall); //sort and version check List <BuildingMod> modsToBuild; try { ModOrganizer.EnsureDependenciesExist(modList, true); ModOrganizer.EnsureTargetVersionsMet(modList); var sortedModList = ModOrganizer.Sort(modList); modsToBuild = sortedModList.OfType <BuildingMod>().ToList(); } catch (ModSortingException e) { status.LogError(null, e.Message); return(false); } //build int num = 0; foreach (var mod in modsToBuild) { status.SetProgress(num++, modsToBuild.Count); if (!Build(mod)) { return(false); } } return(true); }