public ExternalMods() { sheetBuilder = new SheetBuilder(SheetType.BGRA, 256); // Several types of support directory types are available, depending on // how the player has installed and launched the game. // Read registration metadata from all of them var sources = Enum.GetValues(typeof(SupportDirType)) .Cast <SupportDirType>() .Select(t => Platform.GetSupportDir(t)) .Distinct(); foreach (var source in sources) { var metadataPath = Path.Combine(source, "ModMetadata"); if (!Directory.Exists(metadataPath)) { continue; } foreach (var path in Directory.GetFiles(metadataPath, "*.yaml")) { try { var yaml = MiniYaml.FromStream(File.OpenRead(path), path).First().Value; LoadMod(yaml, path); } catch (Exception e) { Log.Write("debug", "Failed to parse mod metadata file '{0}'", path); Log.Write("debug", e.ToString()); } } } }
internal void Unregister(Manifest mod, ModRegistration registration) { var sources = new List<string>(); if (registration.HasFlag(ModRegistration.System)) sources.Add(Platform.GetSupportDir(SupportDirType.System)); if (registration.HasFlag(ModRegistration.User)) { // User support dir may be using the modern or legacy value, or overridden by the user // Add all the possibilities and let the .Distinct() below ignore the duplicates sources.Add(Platform.GetSupportDir(SupportDirType.User)); sources.Add(Platform.GetSupportDir(SupportDirType.ModernUser)); sources.Add(Platform.GetSupportDir(SupportDirType.LegacyUser)); } var key = ExternalMod.MakeKey(mod); mods.Remove(key); foreach (var source in sources.Distinct()) { var path = Path.Combine(source, "ModMetadata", key + ".yaml"); try { if (File.Exists(path)) File.Delete(path); } catch (Exception e) { Log.Write("debug", "Failed to remove mod metadata file '{0}'", path); Log.Write("debug", e.ToString()); } } }
IEnumerable <string> GetSupportDirs(ModRegistration registration) { var sources = new HashSet <string>(4); if (registration.HasFlag(ModRegistration.System)) { sources.Add(Platform.GetSupportDir(SupportDirType.System)); } if (registration.HasFlag(ModRegistration.User)) { // User support dir may be using the modern or legacy value, or overridden by the user // Add all the possibilities and let the HashSet ignore the duplicates sources.Add(Platform.GetSupportDir(SupportDirType.User)); sources.Add(Platform.GetSupportDir(SupportDirType.ModernUser)); sources.Add(Platform.GetSupportDir(SupportDirType.LegacyUser)); } return(sources); }
/// <summary> /// Removes invalid mod registrations: /// * LaunchPath no longer exists /// * LaunchPath and mod id matches the active mod, but the version is different /// * Filename doesn't match internal key /// * Fails to parse as a mod registration /// </summary> internal void ClearInvalidRegistrations(ExternalMod activeMod, ModRegistration registration) { var sources = new List <string>(); if (registration.HasFlag(ModRegistration.System)) { sources.Add(Platform.GetSupportDir(SupportDirType.System)); } if (registration.HasFlag(ModRegistration.User)) { // User support dir may be using the modern or legacy value, or overridden by the user // Add all the possibilities and let the .Distinct() below ignore the duplicates sources.Add(Platform.GetSupportDir(SupportDirType.User)); sources.Add(Platform.GetSupportDir(SupportDirType.ModernUser)); sources.Add(Platform.GetSupportDir(SupportDirType.LegacyUser)); } var activeModKey = ExternalMod.MakeKey(activeMod); foreach (var source in sources.Distinct()) { var metadataPath = Path.Combine(source, "ModMetadata"); if (!Directory.Exists(metadataPath)) { continue; } foreach (var path in Directory.GetFiles(metadataPath, "*.yaml")) { string modKey = null; try { var yaml = MiniYaml.FromStream(File.OpenRead(path), path).First().Value; var m = FieldLoader.Load <ExternalMod>(yaml); modKey = ExternalMod.MakeKey(m); // Continue to the next entry if it is the active mod (even if the LaunchPath is bogus) if (modKey == activeModKey) { continue; } // Continue to the next entry if this one is valid if (File.Exists(m.LaunchPath) && Path.GetFileNameWithoutExtension(path) == modKey && !(activeMod != null && m.LaunchPath == activeMod.LaunchPath && m.Id == activeMod.Id && m.Version != activeMod.Version)) { continue; } } catch (Exception e) { Log.Write("debug", "Failed to parse mod metadata file '{0}'", path); Log.Write("debug", e.ToString()); } // Remove from the ingame mod switcher if (Path.GetFileNameWithoutExtension(path) == modKey) { mods.Remove(modKey); } // Remove stale or corrupted metadata try { File.Delete(path); Log.Write("debug", "Removed invalid mod metadata file '{0}'", path); } catch (Exception e) { Log.Write("debug", "Failed to remove mod metadata file '{0}'", path); Log.Write("debug", e.ToString()); } } } }
internal void Register(Manifest mod, string launchPath, IEnumerable <string> launchArgs, ModRegistration registration) { if (mod.Metadata.Hidden) { return; } var key = ExternalMod.MakeKey(mod); var yaml = new MiniYamlNode("Registration", new MiniYaml("", new List <MiniYamlNode>() { new MiniYamlNode("Id", mod.Id), new MiniYamlNode("Version", mod.Metadata.Version), new MiniYamlNode("Title", mod.Metadata.Title), new MiniYamlNode("LaunchPath", launchPath), new MiniYamlNode("LaunchArgs", new[] { "Game.Mod=" + mod.Id }.Concat(launchArgs).JoinWith(", ")) })); using (var stream = mod.Package.GetStream("icon.png")) if (stream != null) { yaml.Value.Nodes.Add(new MiniYamlNode("Icon", Convert.ToBase64String(stream.ReadAllBytes()))); } using (var stream = mod.Package.GetStream("icon-2x.png")) if (stream != null) { yaml.Value.Nodes.Add(new MiniYamlNode("Icon2x", Convert.ToBase64String(stream.ReadAllBytes()))); } using (var stream = mod.Package.GetStream("icon-3x.png")) if (stream != null) { yaml.Value.Nodes.Add(new MiniYamlNode("Icon3x", Convert.ToBase64String(stream.ReadAllBytes()))); } var sources = new List <string>(); if (registration.HasFlag(ModRegistration.System)) { sources.Add(Platform.GetSupportDir(SupportDirType.System)); } if (registration.HasFlag(ModRegistration.User)) { sources.Add(Platform.GetSupportDir(SupportDirType.User)); // If using the modern support dir we must also write the registration // to the legacy support dir for older engine versions, but ONLY if it exists var legacyPath = Platform.GetSupportDir(SupportDirType.LegacyUser); if (Directory.Exists(legacyPath)) { sources.Add(legacyPath); } } // Make sure the mod is available for this session, even if saving it fails LoadMod(yaml.Value, forceRegistration: true); var lines = new List <MiniYamlNode> { yaml }.ToLines().ToArray(); foreach (var source in sources.Distinct()) { var metadataPath = Path.Combine(source, "ModMetadata"); try { Directory.CreateDirectory(metadataPath); File.WriteAllLines(Path.Combine(metadataPath, key + ".yaml"), lines); } catch (Exception e) { Log.Write("debug", "Failed to register current mod metadata"); Log.Write("debug", e.ToString()); } } }