/// <summary> /// A simple constructor that initializes the object with the given values. /// </summary> /// <param name="p_atgTagger">The tagger to use to tag mods with metadata.</param> /// <param name="p_modMod">The mod to be tagged.</param> /// <param name="p_setSettings">The application and user settings.</param> /// <param name="p_thmTheme">The current theme to use for the views.</param> public ModTaggerVM(AutoTagger p_atgTagger, IMod p_modMod, ISettings p_setSettings, Theme p_thmTheme) { ModTagger = p_atgTagger; Mod = p_modMod; Settings = p_setSettings; CurrentTheme = p_thmTheme; m_mifCurrentTagOption = new ModInfo(Mod); ModInfoEditorVM = new ModInfoEditorVM(m_mifCurrentTagOption, p_setSettings); ModInfoEditorVM.EditedModInfoVM.LoadInfoValues(p_modMod); }
/// <summary> /// Updates the object's proerties to the values of the /// given <see cref="IModInfo"/>. /// </summary> /// <param name="p_mifInfo">The <see cref="IModInfo"/> whose values /// are to be used to update this object's properties.</param> /// <param name="p_booOverwriteAllValues">Whether to overwrite the current info values, /// or just the empty ones.</param> public void UpdateInfo(IModInfo p_mifInfo, bool p_booOverwriteAllValues) { SetAllInfo(p_booOverwriteAllValues, p_mifInfo.Id, p_mifInfo.ModName, p_mifInfo.HumanReadableVersion, p_mifInfo.LastKnownVersion, p_mifInfo.IsEndorsed, p_mifInfo.MachineVersion, p_mifInfo.Author, p_mifInfo.CategoryId, p_mifInfo.CustomCategoryId, p_mifInfo.Description, p_mifInfo.InstallDate, p_mifInfo.Website, p_mifInfo.Screenshot); }
/// <summary> /// Registers the specified mod, tagging it with the given info. /// </summary> /// <param name="p_strModPath">The path to the mod to register.</param> /// <param name="p_mifTagInfo">The info with which to tag the mod.</param> /// <returns>The mod that was registered, or <c>null</c> if the mod at the given path /// could not be registered.</returns> public IMod RegisterMod(string p_strModPath, IModInfo p_mifTagInfo) { Int32 intExistingIndex = -1; IMod modMod = null; for (intExistingIndex = 0; intExistingIndex < m_oclRegisteredMods.Count; intExistingIndex++) if (p_strModPath.Equals(m_oclRegisteredMods[intExistingIndex].Filename, StringComparison.OrdinalIgnoreCase)) break; modMod = CreateMod(p_strModPath, string.Empty, GameMode); if (p_mifTagInfo != null) modMod.UpdateInfo(p_mifTagInfo, false); if (modMod == null) return null; if (intExistingIndex < m_oclRegisteredMods.Count) m_oclRegisteredMods[intExistingIndex] = modMod; else m_oclRegisteredMods.Add(modMod); return modMod; }
/// <summary> /// Combines the given mod info and mod file info into one mod info. /// </summary> /// <param name="p_mifInfo">The mod info to combine.</param> /// <param name="p_mfiFileInfo">The mod file info to combine.</param> /// <returns>A mid info representing the information from both given info objects.</returns> public static IModInfo CombineInfo(IModInfo p_mifInfo, IModFileInfo p_mfiFileInfo) { Int32 intLineTracker = 0; ModInfo mifUpdatedInfo = null; try { if (p_mifInfo == null) { intLineTracker = 1; if (p_mfiFileInfo == null) return null; intLineTracker = 2; mifUpdatedInfo = new ModInfo(); intLineTracker = 3; } else { intLineTracker = 4; mifUpdatedInfo = new ModInfo(p_mifInfo); intLineTracker = 5; } intLineTracker = 6; if (p_mfiFileInfo != null) { intLineTracker = 7; if (!String.IsNullOrEmpty(p_mfiFileInfo.HumanReadableVersion)) { intLineTracker = 8; mifUpdatedInfo.HumanReadableVersion = p_mfiFileInfo.HumanReadableVersion; intLineTracker = 9; mifUpdatedInfo.MachineVersion = null; intLineTracker = 10; } intLineTracker = 11; if (!String.IsNullOrEmpty(p_mfiFileInfo.Name)) { intLineTracker = 12; mifUpdatedInfo.ModName = String.Format("{0} - {1}", mifUpdatedInfo.ModName, p_mfiFileInfo.Name); intLineTracker = 13; } intLineTracker = 14; } intLineTracker = 15; } catch (NullReferenceException) { Trace.TraceError("NullReferenceException in CombineInfo: LineTracker: {0}", intLineTracker); throw; } return mifUpdatedInfo; }
/// <summary> /// A simple constructor that initializes the view model with its depenedencies. /// </summary> /// <param name="p_mifModInfo">The <see cref="IModInfo"/> to edit.</param> /// <param name="p_setSettings">The application and user settings.</param> public ModInfoEditorVM(IModInfo p_mifModInfo, ISettings p_setSettings) { ModInfo = p_mifModInfo; Settings = p_setSettings; }
/// <summary> /// Updates the object's proerties to the values of the /// given <see cref="IModInfo"/>. /// </summary> /// <param name="p_mifInfo">The <see cref="IModInfo"/> whose values /// are to be used to update this object's properties.</param> /// <param name="p_booOverwriteAllValues">Whether to overwrite the current info values, /// or just the empty ones.</param> public void UpdateInfo(IModInfo p_mifInfo, bool?p_booOverwriteAllValues) { if ((p_booOverwriteAllValues == true) || String.IsNullOrEmpty(Id)) { Id = p_mifInfo.Id; } if ((p_booOverwriteAllValues == true) || String.IsNullOrEmpty(DownloadId)) { DownloadId = p_mifInfo.DownloadId; } if ((p_booOverwriteAllValues == true) || String.IsNullOrEmpty(ModName)) { ModName = p_mifInfo.ModName; } if ((p_booOverwriteAllValues == true) || String.IsNullOrEmpty(DownloadId)) { FileName = p_mifInfo.FileName; } if ((p_booOverwriteAllValues == true) || String.IsNullOrEmpty(HumanReadableVersion)) { HumanReadableVersion = p_mifInfo.HumanReadableVersion; } if ((p_booOverwriteAllValues == true) || String.IsNullOrEmpty(LastKnownVersion)) { LastKnownVersion = p_mifInfo.LastKnownVersion; } if ((p_booOverwriteAllValues == true) || (IsEndorsed != p_mifInfo.IsEndorsed)) { IsEndorsed = p_mifInfo.IsEndorsed; } if ((p_booOverwriteAllValues == true) || (MachineVersion == null)) { MachineVersion = p_mifInfo.MachineVersion; } if ((p_booOverwriteAllValues == true) || String.IsNullOrEmpty(Author)) { Author = p_mifInfo.Author; } if ((p_booOverwriteAllValues == true) || (CategoryId != p_mifInfo.CategoryId)) { CategoryId = p_mifInfo.CategoryId; } if ((p_booOverwriteAllValues == true) || (CustomCategoryId != p_mifInfo.CustomCategoryId)) { CustomCategoryId = p_mifInfo.CustomCategoryId; } if ((p_booOverwriteAllValues == true) || String.IsNullOrEmpty(Description)) { Description = p_mifInfo.Description; } if ((p_booOverwriteAllValues == true) || String.IsNullOrEmpty(InstallDate)) { InstallDate = p_mifInfo.InstallDate; } if ((p_booOverwriteAllValues == true) || (Website == null)) { Website = p_mifInfo.Website; } if ((p_booOverwriteAllValues == true) || (Screenshot == null)) { Screenshot = p_mifInfo.Screenshot; } }
/// <summary> /// A simple constructor that initializes the object with the given values. /// </summary> /// <param name="p_modMod">The mod for which the information was retrieved.</param> /// <param name="p_strNewestInfo">The newest info available for the mod.</param> public UpdateInfo(IMod p_modMod, IModInfo p_strNewestInfo) { Mod = p_modMod; NewestInfo = p_strNewestInfo; }
private void SetStableOverlays() { if (!Config.Water) { return; } seasonalVersion = SeasonalVersion.None; usingMyTextures = false; FilledTroughOverlay = null; if (Helper.ModRegistry.IsLoaded("sonreirblah.JBuildings")) { // seasonal overlays are assigned in LateDayStarted EmptyTroughOverlay = null; seasonalVersion = SeasonalVersion.Sonr; return; } if (Helper.ModRegistry.IsLoaded("Oklinq.CleanStable")) { EmptyTroughOverlay = new Lazy <Texture2D>(() => Helper.Content.Load <Texture2D>($"assets/overlay_empty.png", ContentSource.ModFolder)); return; } if (Helper.ModRegistry.IsLoaded("Elle.SeasonalBuildings")) { var data = Helper.ModRegistry.Get("Elle.SeasonalBuildings"); var path = data.GetType().GetProperty("DirectoryPath"); if (path != null && path.GetValue(data) != null) { var list = ReadConfigFile("config.json", path.GetValue(data) as string, new[] { "color palette", "stable" }, data.Manifest.Name); if (list["stable"] != "false") { EmptyTroughOverlay = new Lazy <Texture2D>(() => Helper.Content.Load <Texture2D>($"assets/elle/overlay_empty_{list["color palette"]}.png", ContentSource.ModFolder)); return; } } } if (Helper.ModRegistry.IsLoaded("Elle.SeasonalVanillaBuildings")) { var data = Helper.ModRegistry.Get("Elle.SeasonalVanillaBuildings"); var path = data.GetType().GetProperty("DirectoryPath"); if (path != null && path.GetValue(data) != null) { var list = ReadConfigFile("config.json", path.GetValue(data) as string, new[] { "stable" }, data.Manifest.Name); if (list["stable"] == "true") { FilledTroughOverlay = new Lazy <Texture2D>(() => Helper.Content.Load <Texture2D>($"assets/overlay_filled_tone.png", ContentSource.ModFolder)); EmptyTroughOverlay = new Lazy <Texture2D>(() => Helper.Content.Load <Texture2D>($"assets/overlay_empty_tone.png", ContentSource.ModFolder)); return; } } } if (Helper.ModRegistry.IsLoaded("Gweniaczek.Medieval_stables")) { IModInfo data = Helper.ModRegistry.Get("Gweniaczek.Medieval_stables"); var path = data.GetType().GetProperty("DirectoryPath"); if (path != null && path.GetValue(data) != null) { var dict = ReadConfigFile("config.json", path.GetValue(data) as string, new[] { "stableOption" }, data.Manifest.Name); SetupGwenTextures(dict); return; } } if (Helper.ModRegistry.IsLoaded("Gweniaczek.Medieval_buildings")) { var data = Helper.ModRegistry.Get("Gweniaczek.Medieval_buildings"); var path = data.GetType().GetProperty("DirectoryPath"); if (path != null && path.GetValue(data) != null) { var dict = ReadConfigFile("config.json", path.GetValue(data) as string, new[] { "buildingsReplaced", "stableOption" }, data.Manifest.Name); if (dict["buildingsReplaced"].Contains("stable")) { SetupGwenTextures(dict); return; } } } if (Helper.ModRegistry.IsLoaded("magimatica.SeasonalVanillaBuildings")) { EmptyTroughOverlay = new Lazy <Texture2D>(() => Helper.Content.Load <Texture2D>($"assets/overlay_empty_no_bucket.png", ContentSource.ModFolder)); return; } // no compatible texture mod found so we will use mine usingMyTextures = true; EmptyTroughOverlay = new Lazy <Texture2D>(() => Helper.Content.Load <Texture2D>($"assets/overlay_empty.png", ContentSource.ModFolder)); }
/// <summary> /// Tags the mod with the given values. /// </summary> /// <param name="p_modMod">The mod the tag.</param> /// <param name="p_mifModInfo">The values with which to tag the mod.</param> /// <param name="p_booOverwriteAllValues">Whether to overwrite the current info values, /// or just the empty ones.</param> public void Tag(IMod p_modMod, IModInfo p_mifModInfo, bool p_booOverwriteAllValues) { p_modMod.UpdateInfo(p_mifModInfo, p_booOverwriteAllValues); }
/// <summary> /// Gets a list of possible mod info tags which match the given mod. /// </summary> /// <param name="p_modMod">The mod for which to retrieve a list of possible tags.</param> /// <returns>A list of possible mod info tags which match the given mod.</returns> public IEnumerable <IModInfo> GetTagInfoCandidates(IMod p_modMod) { //get mod info List <IModInfo> lstMods = new List <IModInfo>(); IModInfo mifInfo = null; try { if (!String.IsNullOrEmpty(p_modMod.Id)) { mifInfo = ModRepository.GetModInfo(p_modMod.Id); } if (mifInfo == null) { mifInfo = ModRepository.GetModInfoForFile(p_modMod.Filename); } if (mifInfo == null) { //use heuristics to find info lstMods.AddRange(ModRepository.FindMods(p_modMod.ModName, true)); if (lstMods.Count == 0) { lstMods.AddRange(ModRepository.FindMods(Regex.Replace(p_modMod.ModName, "[^a-zA-Z0-9_. ]+", "", RegexOptions.Compiled), true)); } if ((lstMods.Count == 0) && (!String.IsNullOrEmpty(p_modMod.Author))) { lstMods.AddRange(ModRepository.FindMods(p_modMod.ModName, p_modMod.Author)); } if (lstMods.Count == 0) { lstMods.AddRange(ModRepository.FindMods(p_modMod.ModName, false)); } } else { lstMods.Add(mifInfo); } //if we don't know the mod Id, then we have no way of getting // the file-specific info, so only look if we have one mod info // candidate. if (lstMods.Count == 1) { mifInfo = lstMods[0]; lstMods.Clear(); //get file specific info IModFileInfo mfiFileInfo = ModRepository.GetFileInfoForFile(p_modMod.Filename); if (mfiFileInfo == null) { foreach (IModFileInfo mfiModFileInfo in ModRepository.GetModFileInfo(mifInfo.Id)) { lstMods.Add(CombineInfo(mifInfo, mfiModFileInfo)); } } else { lstMods.Add(CombineInfo(mifInfo, mfiFileInfo)); } if (lstMods.Count == 0) { lstMods.Add(mifInfo); } } } catch (RepositoryUnavailableException e) { TraceUtil.TraceException(e); //the repository is not available, so add a dummy value indicating such lstMods.Add(new ModInfo(null, String.Format("{0} is unavailable", ModRepository.Name), null, null, null, null, false, null, null, 0, -1, null, null, null, null, true, true)); } catch (NullReferenceException e) { TraceUtil.TraceException(e); //couldn't find any match, so add a dummy value indicating such lstMods.Add(new ModInfo(null, String.Format("{0}", e.Message), null, null, null, null, false, null, null, 0, -1, null, null, null, null, true, true)); } return(lstMods); }
public ModInfoChangedEvent(IModInfo modInfo) { ModInfo = modInfo; }
/// <summary>Checks whether a config file should be used with the currently loaded farm.</summary> /// <param name="config">The FarmConfig to be checked.</param> /// <param name="pack">The content pack associated with this file, if any.</param> /// <returns>True if the file should be used with the current farm; false otherwise.</returns> public static bool CheckFileConditions(FarmConfig config, IContentPack pack) { Monitor.Log("Checking file conditions...", LogLevel.Trace); //check "reset main data folder" flag //NOTE: it's preferable to do this as the first step; it's intended to be a one-off cleaning process, rather than a conditional effect if (config.File_Conditions.ResetMainDataFolder && MConfig.EnableContentPackFileChanges) //if "reset" is true and file changes are enabled { if (pack != null) //if this is part of a content pack { //attempt to load the content pack's global save data ContentPackSaveData packSave = null; try { packSave = pack.ReadJsonFile <ContentPackSaveData>(Path.Combine("data", "ContentPackSaveData.save")); //load the content pack's global save data (null if it doesn't exist) } catch (Exception ex) { Monitor.Log($"Warning: This content pack's save data could not be parsed correctly: {pack.Manifest.Name}", LogLevel.Warn); Monitor.Log($"Affected file: data/ContentPackSaveData.save", LogLevel.Warn); Monitor.Log($"Please delete the file and/or contact the mod's developer.", LogLevel.Warn); Monitor.Log($"The content pack will be skipped until this issue is fixed. The auto-generated error message is displayed below:", LogLevel.Warn); Monitor.Log($"----------", LogLevel.Warn); Monitor.Log($"{ex.Message}", LogLevel.Warn); return(false); //disable this content pack's config, since it may require this process to function } if (packSave == null) //no global save data exists for this content pack { packSave = new ContentPackSaveData(); } if (!packSave.MainDataFolderReset) //if this content pack has NOT reset the main data folder yet { Monitor.Log($"ResetMainDataFolder requested by content pack: {pack.Manifest.Name}", LogLevel.Debug); string dataPath = Path.Combine(Helper.DirectoryPath, "data"); //the path to this mod's data folder DirectoryInfo dataFolder = new DirectoryInfo(dataPath); //an object representing this mod's data directory if (dataFolder.Exists) //the data folder exists { Monitor.Log("Attempting to archive data folder...", LogLevel.Trace); try { string archivePath = Path.Combine(Helper.DirectoryPath, "data", "archive", DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss")); DirectoryInfo archiveFolder = Directory.CreateDirectory(archivePath); //create a timestamped archive folder foreach (FileInfo file in dataFolder.GetFiles()) //for each file in dataFolder { file.MoveTo(Path.Combine(archiveFolder.FullName, file.Name)); //move each file to archiveFolder } } catch (Exception ex) { Monitor.Log($"Warning: This content pack attempted to archive Farm Type Manager's data folder but failed: {pack.Manifest.Name}", LogLevel.Warn); Monitor.Log($"Please report this issue to Farm Type Manager's developer. This might also be fixed by manually removing your FarmTypeManager/data/ files.", LogLevel.Warn); Monitor.Log($"The content pack will be skipped until this issue is fixed. The auto-generated error message is displayed below:", LogLevel.Warn); Monitor.Log($"----------", LogLevel.Warn); Monitor.Log($"{ex.Message}", LogLevel.Warn); return(false); //disable this content pack's config, since it may require this process to function } } else //the data folder doesn't exist { Monitor.Log("Data folder not found; assuming it was deleted or not yet generated.", LogLevel.Trace); } packSave.MainDataFolderReset = true; //update save data } pack.WriteJsonFile(Path.Combine("data", "ContentPackSaveData.save"), packSave); //update the content pack's global save data file Monitor.Log("Data folder archive successful.", LogLevel.Trace); } else //if this is NOT part of a content pack { Monitor.Log("This farm's config file has ResetMainDataFolder = true, but this setting only works for content packs.", LogLevel.Info); } } //check farm type if (config.File_Conditions.FarmTypes != null && config.File_Conditions.FarmTypes.Length > 0) { Monitor.Log("Farm type condition(s) found. Checking...", LogLevel.Trace); bool validType = false; foreach (object obj in config.File_Conditions.FarmTypes) //for each listed farm type { int type = -1; //parse the farm type object into an integer (int type) if (obj is long || obj is int) //if the object is a readable integer { type = Convert.ToInt32(obj); //convert it to a 32-bit integer and use it } else if (obj is string name) //if the object is a string, cast it as one { if (name.Equals("All", StringComparison.OrdinalIgnoreCase) || name.Equals("Any", StringComparison.OrdinalIgnoreCase)) //if this is "all" or "any" { validType = true; break; //skip checking the rest of the farm types } else if (Enum.TryParse(name, true, out FarmTypes farmType)) //if this name can be parsed into a FarmTypes enum { type = (int)farmType; //use it as an integer } else //if this is a string, but not a recognized value { if (int.TryParse(name, out int parsed)) //if this string can be parsed as an integer { type = parsed; //use the parsed value } else //if this string cannot be parsed { Monitor.Log($"This setting in the Farm Types list could not be parsed: {name}", LogLevel.Debug); Monitor.Log($"The setting will be ignored. If it's intended to be a custom farm type, please use its ID number instead of its name.", LogLevel.Debug); continue; //skip to the next farm type condition } } } if (type == Game1.whichFarm) //if the parsed type matches the current farm type { validType = true; break; //skip checking the rest of the farm types } else if (Game1.whichFarm == 200) //if this may be a MTN farm type, handle compatibility (based on MTN 2.1.0-beta8) { //if MTN is installed, use reflection to access its "whichFarm" equivalent try { IModInfo modInfo = Helper.ModRegistry.Get("SgtPickles.MTN"); // get MTN info (null if it's not installed) if (modInfo == null) //if MTN isn't installed { continue; //skip to the next farm type check } object mod = modInfo.GetType().GetProperty("Mod", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)?.GetValue(modInfo); //get MTN's Mod instance if (mod == null) //if it couldn't be accessed { continue; //skip to the next farm type check } object customManager = mod.GetType().GetProperty("CustomManager", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)?.GetValue(mod); //get CustomManager instance if (customManager == null) //if it couldn't be accessed { continue; //skip to the next farm type check } object loadedFarm = customManager.GetType().GetProperty("LoadedFarm", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)?.GetValue(customManager); //get LoadedFarm instance if (loadedFarm == null) //if it couldn't be accessed { continue; //skip to the next farm type check } int farmID = (int)loadedFarm.GetType().GetProperty("ID", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)?.GetValue(loadedFarm); //get the loaded farm's ID if (type == farmID) //if MTN's custom farm ID matches the parsed type { Monitor.VerboseLog($"Farm type matches the loaded MTN farm type's ID: {type}"); validType = true; break; //skip checking the rest of the farm types } } catch (Exception) //if any exception is thrown while accessing MTN { Monitor.Log($"Error encountered while trying to check MTN farm type. This check may be obsolete or require updates.", LogLevel.Trace); continue; //skip to the next farm type check } } } if (validType) //if a valid farm type was listed { Monitor.Log("Farm type matched a setting. File allowed.", LogLevel.Trace); } else { Monitor.Log("Farm type did NOT match any settings. File disabled.", LogLevel.Trace); return(false); //prevent config use } } //check farmer name if (config.File_Conditions.FarmerNames != null && config.File_Conditions.FarmerNames.Length > 0) { Monitor.Log("Farmer name condition(s) found. Checking...", LogLevel.Trace); bool validName = false; foreach (string name in config.File_Conditions.FarmerNames) //for each listed name { if (name.Equals(Game1.player.Name, StringComparison.OrdinalIgnoreCase)) //if the name matches the current player's { validName = true; break; //skip the rest of these checks } } if (validName) //if a valid farmer name was listed { Monitor.Log("Farmer name matched a setting. File allowed.", LogLevel.Trace); } else { Monitor.Log("Farmer name did NOT match any settings. File disabled.", LogLevel.Trace); return(false); //prevent config use } } //check save file names (technically the save folder name) if (config.File_Conditions.SaveFileNames != null && config.File_Conditions.SaveFileNames.Length > 0) { Monitor.Log("Save file name condition(s) found. Checking...", LogLevel.Trace); bool validSave = false; foreach (string saveName in config.File_Conditions.SaveFileNames) //for each listed save name { if (saveName.Equals(Constants.SaveFolderName, StringComparison.OrdinalIgnoreCase)) //if the name matches the current player's save folder name { validSave = true; break; //skip the rest of these checks } } if (validSave) //if a valid save name was listed { Monitor.Log("Save file name matched a setting. File allowed.", LogLevel.Trace); } else { Monitor.Log("Save file name did NOT match any settings. File disabled.", LogLevel.Trace); return(false); //prevent config use } } //check whether other mods exist if (config.File_Conditions.OtherMods != null && config.File_Conditions.OtherMods.Count > 0) { Monitor.Log("Other mod condition(s) found. Checking...", LogLevel.Trace); bool validMods = true; //whether all entries are accurate (true by default, unlike most other settings) foreach (KeyValuePair <string, bool> entry in config.File_Conditions.OtherMods) //for each mod entry in OtherMods { bool validEntry = !(entry.Value); //whether the current entry is accurate (starts false if the mod should exist; starts true if the mod should NOT exist) foreach (IModInfo mod in Helper.ModRegistry.GetAll()) //for each mod currently loaded by SMAPI { if (entry.Value == true) //if the mod should exist { if (entry.Key.Equals(mod.Manifest.UniqueID, StringComparison.OrdinalIgnoreCase)) //if this mod's UniqueID matches the OtherMods entry { validEntry = true; //this entry is valid break; //skip the rest of these checks } } else //if the mod should NOT exist { if (entry.Key.Equals(mod.Manifest.UniqueID, StringComparison.OrdinalIgnoreCase)) //if this mod's UniqueID matches the OtherMods entry { validEntry = false; //this entry is invalid break; //skip the rest of these checks } } } if (validEntry) //if the current mod entry is valid { Monitor.Log($"Mod check successful: \"{entry.Key}\" {(entry.Value ? "does exist" : "does not exist")}.", LogLevel.Trace); } else //if the current mod entry is NOT valid { Monitor.Log($"Mod check failed: \"{entry.Key}\" {(entry.Value ? "does not exist" : "does exist")}.", LogLevel.Trace); validMods = false; break; //skip the rest of these checks } } if (validMods) //if all mod entries in the list are valid { Monitor.Log("The OtherMods list matches the player's mods. File allowed.", LogLevel.Trace); } else //if any entries were NOT valid { Monitor.Log("The OtherMods list does NOT match the player's mods. File disabled.", LogLevel.Trace); return(false); //prevent config use } } return(true); //all checks were successful; config should be used }
/// <summary> /// Updates the object's proerties to the values of the /// given <see cref="IModInfo"/>. /// </summary> /// <param name="p_mifInfo">The <see cref="IModInfo"/> whose values /// are to be used to update this object's properties.</param> /// <param name="p_booOverwriteAllValues">Whether to overwrite the current info values, /// or just the empty ones.</param> public void UpdateInfo(IModInfo p_mifInfo, bool p_booOverwriteAllValues) { if (p_booOverwriteAllValues || String.IsNullOrEmpty(Id)) Id = p_mifInfo.Id; if (p_booOverwriteAllValues || String.IsNullOrEmpty(ModName)) ModName = p_mifInfo.ModName; if (p_booOverwriteAllValues || String.IsNullOrEmpty(HumanReadableVersion)) HumanReadableVersion = p_mifInfo.HumanReadableVersion; if (p_booOverwriteAllValues || String.IsNullOrEmpty(LastKnownVersion)) LastKnownVersion = p_mifInfo.LastKnownVersion; if (p_booOverwriteAllValues || (IsEndorsed != p_mifInfo.IsEndorsed)) IsEndorsed = p_mifInfo.IsEndorsed; if (p_booOverwriteAllValues || (MachineVersion == null)) MachineVersion = p_mifInfo.MachineVersion; if (p_booOverwriteAllValues || String.IsNullOrEmpty(Author)) Author = p_mifInfo.Author; if (p_booOverwriteAllValues || (CategoryId != p_mifInfo.CategoryId)) CategoryId = p_mifInfo.CategoryId; if (p_booOverwriteAllValues || (CustomCategoryId != p_mifInfo.CustomCategoryId)) CustomCategoryId = p_mifInfo.CustomCategoryId; if (p_booOverwriteAllValues || String.IsNullOrEmpty(Description)) Description = p_mifInfo.Description; if (p_booOverwriteAllValues || String.IsNullOrEmpty(InstallDate)) InstallDate = p_mifInfo.InstallDate; if (p_booOverwriteAllValues || (Website == null)) Website = p_mifInfo.Website; if (p_booOverwriteAllValues || (Screenshot == null)) Screenshot = p_mifInfo.Screenshot; }
/// <summary> /// Updates the object's properties to the values of the /// given <see cref="IModInfo"/>. /// </summary> /// <param name="p_mifInfo">The <see cref="IModInfo"/> whose values /// are to be used to update this object's properties.</param> /// <param name="p_booOverwriteAllValues">Whether to overwrite the current info values, /// or just the empty ones.</param> public void UpdateInfo(IModInfo p_mifInfo, bool p_booOverwriteAllValues) { bool booChangedValue = false; if (p_booOverwriteAllValues || String.IsNullOrEmpty(Id)) { Id = p_mifInfo.Id; booChangedValue = true; } if ((p_booOverwriteAllValues || String.IsNullOrEmpty(ModName) || ModName.Equals(Path.GetFileNameWithoutExtension(m_strFilePath))) && !String.IsNullOrEmpty(p_mifInfo.ModName)) { ModName = p_mifInfo.ModName; booChangedValue = true; } if (p_booOverwriteAllValues || String.IsNullOrEmpty(HumanReadableVersion)) { HumanReadableVersion = p_mifInfo.HumanReadableVersion; booChangedValue = true; } if (p_booOverwriteAllValues || String.IsNullOrEmpty(LastKnownVersion) || (LastKnownVersion != p_mifInfo.LastKnownVersion)) { LastKnownVersion = p_mifInfo.LastKnownVersion; booChangedValue = true; } if ((p_booOverwriteAllValues) || (IsEndorsed != p_mifInfo.IsEndorsed)) { IsEndorsed = p_mifInfo.IsEndorsed; booChangedValue = true; } if (p_booOverwriteAllValues || (MachineVersion == null)) { MachineVersion = p_mifInfo.MachineVersion; booChangedValue = true; } if (p_booOverwriteAllValues || String.IsNullOrEmpty(Author)) { Author = p_mifInfo.Author; booChangedValue = true; } if (p_booOverwriteAllValues || (CategoryId != p_mifInfo.CategoryId)) { CategoryId = p_mifInfo.CategoryId; booChangedValue = true; } if (p_booOverwriteAllValues || (CustomCategoryId != p_mifInfo.CustomCategoryId)) { CustomCategoryId = p_mifInfo.CustomCategoryId; booChangedValue = true; } if (p_booOverwriteAllValues || String.IsNullOrEmpty(Description)) { Description = p_mifInfo.Description; booChangedValue = true; } if (p_booOverwriteAllValues || String.IsNullOrEmpty(InstallDate)) { InstallDate = p_mifInfo.InstallDate; booChangedValue = true; } if (p_booOverwriteAllValues || (Website == null)) { Website = p_mifInfo.Website; booChangedValue = true; } if ((p_booOverwriteAllValues) || (UpdateWarningEnabled != p_mifInfo.UpdateWarningEnabled)) { UpdateWarningEnabled = p_mifInfo.UpdateWarningEnabled; booChangedValue = true; } if (booChangedValue) { XmlDocument xmlInfo = new XmlDocument(); xmlInfo.AppendChild(SaveInfo(xmlInfo)); using (MemoryStream mstInfo = new MemoryStream()) { xmlInfo.Save(mstInfo); ReplaceFile("fomod/info.xml", mstInfo.ToArray()); } } if (p_booOverwriteAllValues || (Screenshot != p_mifInfo.Screenshot)) { if (p_mifInfo.Screenshot == null) { if ((Screenshot != null) && p_booOverwriteAllValues) { DeleteFile(m_strScreenshotPath); Screenshot = p_mifInfo.Screenshot; } } else { Screenshot = p_mifInfo.Screenshot; CreateOrReplaceFile(m_strScreenshotPath, Screenshot.Data); } } }
private void DiscoverBooks(IModInfo mod, bool owned) { string?path = null; // For our own Content Packs, books are located in Books/ rather than AlmanacBooks/ if (owned) { path = "Books"; } // For other mods, we need to detect an "Almanac:Books" key in their manifest before // we're willing to assume they have books. else if (mod.Manifest.ExtraFields != null && mod.Manifest.ExtraFields.TryGetValue("Almanac:Books", out object?value)) { // For a boolean value, use the default path. if (value is bool bv) { if (!bv) { return; } path = "AlmanacBooks"; // For a string value, use that path instead. } else if (value is string str) { path = str; } } // No path? No books. Leave! if (string.IsNullOrEmpty(path)) { return; } // Alright. Is this a ContentPack? IContentPack?pack = null; string root; if (mod.IsContentPack && mod.GetType().GetProperty("ContentPack", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)?.GetValue(mod) is IContentPack cp) { pack = cp; root = cp.DirectoryPath; } else if (mod.GetType().GetProperty("DirectoryPath", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(mod) is string str) { root = str; } else { Log($"Unable to locate root directory of mod {mod.Manifest.UniqueID}", LogLevel.Warn); return; } string booksRoot = Path.Join(root, PathUtilities.NormalizePath(path)); if (!Directory.Exists(booksRoot)) { Log($"Book subdirectory does not exist for mod {mod.Manifest.UniqueID}", owned ? LogLevel.Trace : LogLevel.Warn); return; } foreach (string bookDir in Directory.EnumerateDirectories(booksRoot)) { string id = Path.GetRelativePath(booksRoot, bookDir); string bookFile = Path.Join(bookDir, "book.json"); if (!File.Exists(bookFile)) { Log($"Book subdirectory \"{id}\" has no book.json file.", LogLevel.Warn); continue; } // At this point, we definitely have a book file. Make sure we have // an IContentPack for reading its data. if (pack == null) { pack = Mod.Helper.ContentPacks.CreateTemporary( directoryPath: root, id: $"{Mod.ModManifest.UniqueID}.books.{mod.Manifest.UniqueID}", name: mod.Manifest.Name, description: mod.Manifest.Description, author: mod.Manifest.Author, version: mod.Manifest.Version ); } string localBookFile = Path.Join(path, id, "book.json"); Log($"Loading book \"{id}\" from {bookFile}", LogLevel.Trace); Book?book; try { book = pack.ReadJsonFile <Book>(localBookFile); if (book is null) { throw new ArgumentNullException("book"); } } catch (Exception ex) { Log($"Error reading book file for \"{id}\" from {mod.Manifest.UniqueID}", LogLevel.Error, ex); continue; } // Set the book's ID based on its providing mod and folder, if an ID wasn't set. if (book.Id == null) { book.Id = new NamespaceId(mod.Manifest.UniqueID, id); } // Store the book. string bid = book.Id.ToString(); if (RawBooks !.ContainsKey(bid)) { Log($"Found duplicate book for key \"{bid}\" from {mod.Manifest.UniqueID}", LogLevel.Warn); }
/// <summary> /// Gets the file info for the specified download file. /// </summary> /// <param name="p_strFilename">The name of the file whose info is to be returned.</param> /// <param name="p_mifInfo">The mod info for the mod to which the specified file belongs.</param> /// <returns>The file info for the specified download file.</returns> /// <exception cref="RepositoryUnavailableException">Thrown if the repository cannot be reached.</exception> private NexusModFileInfo GetFileInfoForFile(string p_strFilename, out IModInfo p_mifInfo) { if (IsOffline) { p_mifInfo = null; return null; } string strModId = ParseModIdFromFilename(p_strFilename, out p_mifInfo); if (strModId == null) return null; string strFilename = Path.GetFileName(p_strFilename); try { using (IDisposable dspProxy = (IDisposable)GetProxyFactory().CreateChannel()) { INexusModRepositoryApi nmrApi = (INexusModRepositoryApi)dspProxy; List<NexusModFileInfo> mfiFiles = nmrApi.GetModFiles(strModId, m_intRemoteGameId); NexusModFileInfo mfiFileInfo = mfiFiles.Find(x => x.Filename.Equals(strFilename, StringComparison.OrdinalIgnoreCase)); if (mfiFileInfo == null) mfiFileInfo = mfiFiles.Find(x => x.Filename.Replace(' ', '_').Equals(strFilename, StringComparison.OrdinalIgnoreCase)); return mfiFileInfo; } } catch (TimeoutException e) { throw new RepositoryUnavailableException(String.Format("Cannot reach the {0} metadata server.", Name), e); } catch (CommunicationException e) { throw new RepositoryUnavailableException(String.Format("Cannot reach the {0} metadata server.", Name), e); } catch (SerializationException e) { throw new RepositoryUnavailableException(String.Format("Cannot reach the {0} metadata server.", Name), e); } }
/// <summary> /// A simple constructor that initializes the view model with the <see cref="IModInfo"/> /// that it will represent. /// </summary> /// <param name="p_mifInfo">The <see cref="IModInfo"/> being edited.</param> public ModInfoVM(IModInfo p_mifInfo) { Errors = new ErrorContainer(); ModInfo = p_mifInfo; Reset(); }
/// <summary> /// Parses out the mod id from the given mod file name. /// </summary> /// <param name="p_strFilename">The filename from which to parse the mod id.</param> /// <param name="p_mifInfo">The mod info for the mod identified by the parsed mod id.</param> /// <returns>The mod id, if one was found; <c>null</c> otherwise.</returns> protected string ParseModIdFromFilename(string p_strFilename, out IModInfo p_mifInfo) { Regex rgxModId = new Regex(@"-((\d+)[-\.])+"); string strFilename = Path.GetFileName(p_strFilename); Match mchModId = rgxModId.Match(strFilename); if (!mchModId.Success) { p_mifInfo = null; return null; } IModInfo mifInfo = null; string[] strFilenameWords = strFilename.Split(new char[] { ' ', '_', '-' }, StringSplitOptions.RemoveEmptyEntries); List<KeyValuePair<Int32, IModInfo>> lstCandidates = new List<KeyValuePair<Int32, IModInfo>>(); foreach (Capture cptMatch in mchModId.Groups[2].Captures) { string strId = cptMatch.Value; //get the mod info to make sure the id is valid, and not // just some random match from elsewhere in the filename IModInfo mifInfoCandidate = GetModInfo(strId); if (mifInfoCandidate != null) { IList<IModFileInfo> lstFiles = GetModFileInfo(strId); Int32 intBestFoundWordCount = 0; foreach (IModFileInfo mfiFile in lstFiles) { if (mfiFile.Filename.Equals(strFilename, StringComparison.OrdinalIgnoreCase) || mfiFile.Filename.Replace(' ', '_').Equals(strFilename, StringComparison.OrdinalIgnoreCase)) { mifInfo = mifInfoCandidate; break; } Int32 intFoundWordCount = 0; foreach (string strWord in strFilenameWords) { if (mfiFile.Filename.IndexOf(strWord, StringComparison.OrdinalIgnoreCase) > -1) intFoundWordCount++; } if (intFoundWordCount > intBestFoundWordCount) intBestFoundWordCount = intFoundWordCount; } if (mifInfo != null) break; if (intBestFoundWordCount > 0) lstCandidates.Add(new KeyValuePair<Int32, IModInfo>(intBestFoundWordCount, mifInfoCandidate)); } } if ((mifInfo == null) && !lstCandidates.IsNullOrEmpty()) { lstCandidates.Sort((x, y) => -x.Key.CompareTo(y.Key)); mifInfo = lstCandidates[0].Value; } p_mifInfo = mifInfo; return (mifInfo == null) ? null : mifInfo.Id; }
/// <summary> /// Updates the object's proerties to the values of the /// given <see cref="IModInfo"/>. /// </summary> /// <param name="p_mifInfo">The <see cref="IModInfo"/> whose values /// are to be used to update this object's properties.</param> /// <param name="p_booOverwriteAllValues">Whether to overwrite the current info values, /// or just the empty ones.</param> public void UpdateInfo(IModInfo p_mifInfo, bool?p_booOverwriteAllValues) { SetAllInfo((p_booOverwriteAllValues == true), p_mifInfo.Id, p_mifInfo.DownloadId, p_mifInfo.ModName, p_mifInfo.FileName, p_mifInfo.HumanReadableVersion, p_mifInfo.LastKnownVersion, p_mifInfo.IsEndorsed, p_mifInfo.MachineVersion, p_mifInfo.Author, p_mifInfo.CategoryId, p_mifInfo.CustomCategoryId, p_mifInfo.Description, p_mifInfo.InstallDate, p_mifInfo.Website, p_mifInfo.Screenshot, p_mifInfo.UpdateWarningEnabled, p_mifInfo.UpdateChecksEnabled); }
/// <summary> /// The method that is called to start the backgound task. /// </summary> /// <param name="p_objArgs">Arguments to for the task execution.</param> /// <returns>Always <c>null</c>.</returns> protected override object DoWork(object[] p_objArgs) { int intModLimit = 75; if (m_booMissingDownloadId != false) { intModLimit = 75; } List <string> ModList = new List <string>(); List <IMod> ModCheck = new List <IMod>(); ConfirmActionMethod camConfirm = (ConfirmActionMethod)p_objArgs[0]; OverallMessage = "Updating mods info: setup search.."; OverallProgress = 0; OverallProgressStepSize = 1; ShowItemProgress = true; ItemProgress = 0; ItemProgressStepSize = 1; ItemProgressMaximum = 1; OverallProgressMaximum = 1; OverallProgressMaximum = m_lstModList.Count * 2; ItemProgressMaximum = (m_lstModList.Count > intModLimit) ? intModLimit : m_lstModList.Count; for (int i = 0; i < m_lstModList.Count; i++) { IMod modCurrent = m_lstModList[i]; string modID = string.Empty; string modName = string.Empty; int isEndorsed = 0; ItemMessage = modCurrent.ModName; if (m_booCancel) { break; } modName = StripFileName(modCurrent.Filename, modCurrent.Id); if (!string.IsNullOrEmpty(modCurrent.Id)) { modID = modCurrent.Id; isEndorsed = modCurrent.IsEndorsed == true ? 1 : (modCurrent.IsEndorsed == false ? -1 : 0); } else { try { IModInfo mifInfo = ModRepository.GetModInfoForFile(modCurrent.Filename); if (mifInfo != null) { modCurrent.Id = mifInfo.Id; modID = mifInfo.Id; AutoUpdater.AddNewVersionNumberForMod(modCurrent, mifInfo); modName = StripFileName(modCurrent.Filename, mifInfo.Id); } } catch (RepositoryUnavailableException) { //the repository is not available, so don't bother } } //if (m_booMissingDownloadId) if ((m_booMissingDownloadId == null) || ((m_booMissingDownloadId == true) && (string.IsNullOrEmpty(modCurrent.DownloadId) || (modCurrent.DownloadId == "0") || (modCurrent.DownloadId == "-1")))) { ModList.Add(string.Format("{0}|{1}|{2}", modName, string.IsNullOrWhiteSpace(modID) ? "0" : modID, Path.GetFileName(modCurrent.Filename))); ModCheck.Add(modCurrent); } else if ((m_booMissingDownloadId == false) && !string.IsNullOrEmpty(modCurrent.DownloadId)) { if (m_booOverrideCategorySetup) { ModList.Add(string.Format("{0}", modCurrent.DownloadId)); } else { ModList.Add(string.Format("{0}|{1}|{2}|{3}|{4}", string.IsNullOrWhiteSpace(modCurrent.DownloadId) ? "0" : modCurrent.DownloadId, string.IsNullOrWhiteSpace(modID) ? "0" : modID, Path.GetFileName(modName), string.IsNullOrWhiteSpace(modCurrent.HumanReadableVersion) ? "0" : modCurrent.HumanReadableVersion, isEndorsed)); } ModCheck.Add(modCurrent); } if (ItemProgress < ItemProgressMaximum) { StepItemProgress(); } if (OverallProgress < OverallProgressMaximum) { StepOverallProgress(); } if (m_booCancel) { break; } // Prevents the repository request string from becoming too long. if (ModList.Count == intModLimit) { string strResult = CheckForModListUpdate(ModList, ModCheck); if (!string.IsNullOrEmpty(strResult)) { ModList.Clear(); return(strResult); } ModList.Clear(); OverallMessage = "Updating mods info: setup search.."; ItemProgress = 0; ItemProgressMaximum = (m_lstModList.Count == intModLimit) ? 1 : (m_lstModList.Count - (i + 1)); } } if (!m_booCancel && (ModList.Count > 0)) { string strResult = CheckForModListUpdate(ModList, ModCheck); if (!string.IsNullOrEmpty(strResult)) { m_lstModList.Clear(); return(strResult); } } m_lstModList.Clear(); return(FlagShare); }
/// <summary> /// Loads the values from the given <see cref="IModInfo"/> /// into the control. /// </summary> /// <remarks> /// This does not change which <see cref="IModInfo"/> /// is being edited, but simply loads the values into the view model. /// </remarks> /// <param name="p_mifModInfo">The <see cref="IModInfo"/> whose values are to be /// loaded into the view model.</param> public void LoadInfoValues(IModInfo p_mifModInfo) { if (p_mifModInfo != null) { Author = p_mifModInfo.Author; Description = p_mifModInfo.Description; HumanReadableVersion = p_mifModInfo.HumanReadableVersion; LastKnownVersion = p_mifModInfo.LastKnownVersion; MachineVersion = (p_mifModInfo.MachineVersion == null) ? null : p_mifModInfo.MachineVersion.ToString(); ModName = p_mifModInfo.ModName; InstallDate = p_mifModInfo.InstallDate; Website = (p_mifModInfo.Website == null) ? null : p_mifModInfo.Website.ToString(); Screenshot = p_mifModInfo.Screenshot; CategoryId = p_mifModInfo.CategoryId; IsEndorsed = p_mifModInfo.IsEndorsed; } }
/// <summary> /// Loads the values of the given tag option into the tag editor. /// </summary> /// <param name="p_mifInfo">The tag option whose values are to be displayed in the tag editor.</param> public void LoadTagOption(IModInfo p_mifInfo) { ModInfoEditorVM.EditedModInfoVM.LoadInfoValues(p_mifInfo); }
/// <summary> /// Adds the newest information for the given mod. /// </summary> /// <param name="p_modMod">The mod for which to add the newest info.</param> /// <param name="p_mifNewestInfo">The newest info to add for the given mod.</param> public void AddNewVersionNumberForMod(IMod p_modMod, IModInfo p_mifNewestInfo) { lock (m_oclNewInfo) { Int32 intExistingIndex = m_oclNewInfo.IndexOf(x => (x.Mod == p_modMod)); if (intExistingIndex < 0) m_oclNewInfo.Add(new UpdateInfo(p_modMod, p_mifNewestInfo)); else m_oclNewInfo[intExistingIndex] = new UpdateInfo(p_modMod, p_mifNewestInfo); } }
/// <summary> /// The copy cosntructor. /// </summary> /// <param name="p_mifCopy">The mod info to copy.</param> public ModInfo(IModInfo p_mifCopy) { if (p_mifCopy != null) SetAllInfo(true, p_mifCopy.Id, p_mifCopy.ModName, p_mifCopy.HumanReadableVersion, p_mifCopy.LastKnownVersion, p_mifCopy.IsEndorsed, p_mifCopy.MachineVersion, p_mifCopy.Author, p_mifCopy.CategoryId, p_mifCopy.CustomCategoryId, p_mifCopy.Description, p_mifCopy.InstallDate, p_mifCopy.Website, p_mifCopy.Screenshot); }
/// <summary> /// Updates the object's properties to the values of the /// given <see cref="IModInfo"/>. /// </summary> /// <param name="p_mifInfo">The <see cref="IModInfo"/> whose values /// are to be used to update this object's properties.</param> /// <param name="p_booOverwriteAllValues">Whether to overwrite the current info values, /// or just the empty ones.</param> public void UpdateInfo(IModInfo p_mifInfo, bool p_booOverwriteAllValues) { bool booChangedValue = false; if (p_booOverwriteAllValues || String.IsNullOrEmpty(Id)) { Id = p_mifInfo.Id; booChangedValue = true; } if (p_booOverwriteAllValues || String.IsNullOrEmpty(ModName)) { ModName = p_mifInfo.ModName; booChangedValue = true; } if (p_booOverwriteAllValues || String.IsNullOrEmpty(HumanReadableVersion)) { HumanReadableVersion = p_mifInfo.HumanReadableVersion; booChangedValue = true; } if (p_booOverwriteAllValues || String.IsNullOrEmpty(LastKnownVersion) || (LastKnownVersion != p_mifInfo.LastKnownVersion)) { LastKnownVersion = p_mifInfo.LastKnownVersion; booChangedValue = true; } if ((p_booOverwriteAllValues) || (IsEndorsed != p_mifInfo.IsEndorsed)) { IsEndorsed = p_mifInfo.IsEndorsed; booChangedValue = true; } if (p_booOverwriteAllValues || (MachineVersion == null)) { MachineVersion = p_mifInfo.MachineVersion; booChangedValue = true; } if (p_booOverwriteAllValues || String.IsNullOrEmpty(Author)) { Author = p_mifInfo.Author; booChangedValue = true; } if (p_booOverwriteAllValues || (CategoryId != p_mifInfo.CategoryId)) { CategoryId = p_mifInfo.CategoryId; booChangedValue = true; } if (p_booOverwriteAllValues || (CustomCategoryId != p_mifInfo.CustomCategoryId)) { CustomCategoryId = p_mifInfo.CustomCategoryId; booChangedValue = true; } if (p_booOverwriteAllValues || String.IsNullOrEmpty(Description)) { Description = p_mifInfo.Description; booChangedValue = true; } if (p_booOverwriteAllValues || String.IsNullOrEmpty(InstallDate)) { InstallDate = p_mifInfo.InstallDate; booChangedValue = true; } if (p_booOverwriteAllValues || (Website == null)) { Website = p_mifInfo.Website; booChangedValue = true; } if (booChangedValue) { byte[] bteInfo = SaveInfo(); ReplaceSpecialFile("config", bteInfo); } if (p_booOverwriteAllValues || (Screenshot == null)) { if (p_mifInfo.Screenshot == null) { if (m_booHasScreenshot) { DeleteSpecialFile(ScreenshotPath); Screenshot = p_mifInfo.Screenshot; } } else { Screenshot = p_mifInfo.Screenshot; ReplaceSpecialFile(ScreenshotPath, Screenshot.Data); } } }
/// <summary>Checks whether a config file should be used with the currently loaded farm.</summary> /// <param name="config">The FarmConfig to be checked.</param> /// <param name="pack">The content pack associated with this file, if any.</param> /// <returns>True if the file should be used with the current farm; false otherwise.</returns> public static bool CheckFileConditions(FarmConfig config, IContentPack pack) { Monitor.Log("Checking file conditions...", LogLevel.Trace); //check farm type if (config.File_Conditions.FarmTypes != null && config.File_Conditions.FarmTypes.Length > 0) { Monitor.Log("Farm type condition(s) found. Checking...", LogLevel.Trace); bool validType = false; foreach (object obj in config.File_Conditions.FarmTypes) //for each listed farm type { int type = -1; //parse the farm type object into an integer (int type) if (obj is long || obj is int) //if the object is a readable integer { type = Convert.ToInt32(obj); //convert it to a 32-bit integer and use it } else if (obj is string name) //if the object is a string, cast it as one { string farmTypeID = Helper.Reflection.GetMethod(typeof(Game1), "GetFarmTypeID", false)?.Invoke <string>(); //get the farm type ID string (null in SDV 1.5.4 or older) if (name.Equals("All", StringComparison.OrdinalIgnoreCase) || name.Equals("Any", StringComparison.OrdinalIgnoreCase)) //if this is "all" or "any" { validType = true; break; //skip checking the rest of the farm types } else if (name.Equals(farmTypeID, StringComparison.OrdinalIgnoreCase)) //if this is the name of the player's SDV-supported custom farm type (SDV 1.5.5 or newer) { validType = true; break; //skip checking the rest of the farm types } else if (Enum.TryParse(name, true, out FarmTypes farmType)) //if this name can be parsed into a FarmTypes enum { type = (int)farmType; //use it as an integer } else //if this is a string, but not a recognized value { if (int.TryParse(name, out int parsed)) //if this string can be parsed as an integer { type = parsed; //use the parsed value } else //if this string cannot be parsed { Monitor.Log($"This setting in the Farm Types list could not be parsed: {name}", LogLevel.Debug); Monitor.Log($"The setting will be ignored. If it's intended to be a custom farm type, please use its ID number instead of its name.", LogLevel.Debug); continue; //skip to the next farm type condition } } } if (type == Game1.whichFarm) //if the parsed type matches the current farm type { validType = true; break; //skip checking the rest of the farm types } else if (Game1.whichFarm == 200) //if this may be a MTN farm type, handle compatibility (based on MTN 2.1.0-beta8) { //if MTN is installed, use reflection to access its "whichFarm" equivalent try { IModInfo modInfo = Helper.ModRegistry.Get("SgtPickles.MTN"); // get MTN info (null if it's not installed) if (modInfo == null) //if MTN isn't installed { continue; //skip to the next farm type check } object mod = modInfo.GetType().GetProperty("Mod", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)?.GetValue(modInfo); //get MTN's Mod instance if (mod == null) //if it couldn't be accessed { continue; //skip to the next farm type check } object customManager = mod.GetType().GetProperty("CustomManager", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)?.GetValue(mod); //get CustomManager instance if (customManager == null) //if it couldn't be accessed { continue; //skip to the next farm type check } object loadedFarm = customManager.GetType().GetProperty("LoadedFarm", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)?.GetValue(customManager); //get LoadedFarm instance if (loadedFarm == null) //if it couldn't be accessed { continue; //skip to the next farm type check } int farmID = (int)loadedFarm.GetType().GetProperty("ID", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)?.GetValue(loadedFarm); //get the loaded farm's ID if (type == farmID) //if MTN's custom farm ID matches the parsed type { Monitor.VerboseLog($"Farm type matches the loaded MTN farm type's ID: {type}"); validType = true; break; //skip checking the rest of the farm types } } catch (Exception) //if any exception is thrown while accessing MTN { Monitor.Log($"Error encountered while trying to check MTN farm type. This check may be obsolete or require updates.", LogLevel.Trace); continue; //skip to the next farm type check } } } if (validType) //if a valid farm type was listed { Monitor.Log("Farm type matched a setting. File allowed.", LogLevel.Trace); } else { Monitor.Log("Farm type did NOT match any settings. File disabled.", LogLevel.Trace); return(false); //prevent config use } } //check farmer name if (config.File_Conditions.FarmerNames != null && config.File_Conditions.FarmerNames.Length > 0) { Monitor.Log("Farmer name condition(s) found. Checking...", LogLevel.Trace); bool validName = false; foreach (string name in config.File_Conditions.FarmerNames) //for each listed name { if (name.Equals(Game1.player.Name, StringComparison.OrdinalIgnoreCase)) //if the name matches the current player's { validName = true; break; //skip the rest of these checks } } if (validName) //if a valid farmer name was listed { Monitor.Log("Farmer name matched a setting. File allowed.", LogLevel.Trace); } else { Monitor.Log("Farmer name did NOT match any settings. File disabled.", LogLevel.Trace); return(false); //prevent config use } } //check save file names (technically the save folder name) if (config.File_Conditions.SaveFileNames != null && config.File_Conditions.SaveFileNames.Length > 0) { Monitor.Log("Save file name condition(s) found. Checking...", LogLevel.Trace); bool validSave = false; foreach (string saveName in config.File_Conditions.SaveFileNames) //for each listed save name { if (saveName.Equals(Constants.SaveFolderName, StringComparison.OrdinalIgnoreCase)) //if the name matches the current player's save folder name { validSave = true; break; //skip the rest of these checks } } if (validSave) //if a valid save name was listed { Monitor.Log("Save file name matched a setting. File allowed.", LogLevel.Trace); } else { Monitor.Log("Save file name did NOT match any settings. File disabled.", LogLevel.Trace); return(false); //prevent config use } } //check whether other mods exist if (config.File_Conditions.OtherMods != null && config.File_Conditions.OtherMods.Count > 0) { Monitor.Log("Other mod condition(s) found. Checking...", LogLevel.Trace); bool validMods = true; //whether all entries are accurate (true by default, unlike most other settings) foreach (KeyValuePair <string, bool> entry in config.File_Conditions.OtherMods) //for each mod entry in OtherMods { bool validEntry = !(entry.Value); //whether the current entry is accurate (starts false if the mod should exist; starts true if the mod should NOT exist) foreach (IModInfo mod in Helper.ModRegistry.GetAll()) //for each mod currently loaded by SMAPI { if (entry.Value == true) //if the mod should exist { if (entry.Key.Equals(mod.Manifest.UniqueID, StringComparison.OrdinalIgnoreCase)) //if this mod's UniqueID matches the OtherMods entry { validEntry = true; //this entry is valid break; //skip the rest of these checks } } else //if the mod should NOT exist { if (entry.Key.Equals(mod.Manifest.UniqueID, StringComparison.OrdinalIgnoreCase)) //if this mod's UniqueID matches the OtherMods entry { validEntry = false; //this entry is invalid break; //skip the rest of these checks } } } if (validEntry) //if the current mod entry is valid { Monitor.Log($"Mod check successful: \"{entry.Key}\" {(entry.Value ? "does exist" : "does not exist")}.", LogLevel.Trace); } else //if the current mod entry is NOT valid { Monitor.Log($"Mod check failed: \"{entry.Key}\" {(entry.Value ? "does not exist" : "does exist")}.", LogLevel.Trace); validMods = false; break; //skip the rest of these checks } } if (validMods) //if all mod entries in the list are valid { Monitor.Log("The OtherMods list matches the player's mods. File allowed.", LogLevel.Trace); } else //if any entries were NOT valid { Monitor.Log("The OtherMods list does NOT match the player's mods. File disabled.", LogLevel.Trace); return(false); //prevent config use } } return(true); //all checks were successful; config should be used }
/// <summary> /// The method that is called to start the backgound task. /// </summary> /// <param name="p_objArgs">Arguments to for the task execution.</param> /// <returns>Always <c>null</c>.</returns> protected override object DoWork(object[] p_objArgs) { int intModLimit = 100; if (m_booMissingDownloadId) { intModLimit = 100; } List <string> ModList = new List <string>(); ConfirmActionMethod camConfirm = (ConfirmActionMethod)p_objArgs[0]; OverallMessage = "Updating mods info: setup search..."; OverallProgress = 0; OverallProgressStepSize = 1; ShowItemProgress = true; ItemProgress = 0; ItemProgressStepSize = 1; ItemProgressMaximum = 1; OverallProgressMaximum = 1; OverallProgressMaximum = m_lstModList.Count * 2; ItemProgressMaximum = (m_lstModList.Count > intModLimit) ? intModLimit : m_lstModList.Count; for (int i = 0; i < m_lstModList.Count; i++) { string modID = String.Empty; Int32 isEndorsed = 0; string strLastVersion = String.Empty; ItemMessage = m_lstModList[i].ModName; if (m_booCancel) { break; } if (!String.IsNullOrEmpty(m_lstModList[i].Id)) { modID = m_lstModList[i].Id; isEndorsed = m_lstModList[i].IsEndorsed == true ? 1 : (m_lstModList[i].IsEndorsed == false ? -1 : 0); strLastVersion = m_lstModList[i].LastKnownVersion; } else { try { IModInfo mifInfo = ModRepository.GetModInfoForFile(m_lstModList[i].Filename); if (mifInfo != null) { modID = mifInfo.Id; m_lstModList[i].Id = modID; strLastVersion = m_lstModList[i].LastKnownVersion; AutoUpdater.AddNewVersionNumberForMod(m_lstModList[i], mifInfo); } } catch (RepositoryUnavailableException) { //the repository is not available, so don't bother } } if (!String.IsNullOrEmpty(modID)) { if (m_booMissingDownloadId) { ModList.Add(String.Format("{0}|{1}", modID, Path.GetFileName(m_lstModList[i].Filename))); } else if ((m_booOverrideCategorySetup) || (String.IsNullOrEmpty(strLastVersion))) { ModList.Add(String.Format("{0}", modID)); } else { ModList.Add(String.Format("{0}|{1}|{2}", modID, m_lstModList[i].HumanReadableVersion, isEndorsed)); } } if (ItemProgress < ItemProgressMaximum) { StepItemProgress(); } if (OverallProgress < OverallProgressMaximum) { StepOverallProgress(); } if (m_booCancel) { break; } // Prevents the repository request string from becoming too long. if (ModList.Count == intModLimit) { CheckForModListUpdate(ModList); ModList.Clear(); OverallMessage = "Updating mods info: setup search..."; ItemProgress = 0; ItemProgressMaximum = (m_lstModList.Count == intModLimit) ? 1 : (m_lstModList.Count - (i + 1)); } } if (!m_booCancel && (ModList.Count > 0)) { CheckForModListUpdate(ModList); } m_lstModList.Clear(); return(null); }