/// <summary> /// Performs the most low-level mod enable/disable functions, without saving the modlist, /// ergo this should only be called by functions which will handle saving the modlist after /// they're done performing all modlist operations. /// /// If the Index and modlist are provided, the actions are only applied to those cached entries, rather /// than to the live files. /// </summary> /// <param name="enable"></param> /// <param name="mod"></param> /// <returns></returns> public async Task <bool> ToggleModUnsafe(bool enable, Mod mod, bool includeInternal, bool updateCache, IndexFile cachedIndex = null, ModList cachedModlist = null) { if (mod == null) { return(false); } if (string.IsNullOrEmpty(mod.name)) { return(false); } if (string.IsNullOrEmpty(mod.fullPath)) { return(false); } if (mod.data.originalOffset <= 0 && !enable) { throw new Exception("Cannot disable mod with invalid original offset."); } if (enable && mod.data.modOffset <= 0) { throw new Exception("Cannot enable mod with invalid mod offset."); } if (mod.IsInternal() && !includeInternal) { // Don't allow toggling internal mods unless we were specifically told to. return(false); } var index = new Index(_gameDirectory); var dat = new Dat(_gameDirectory); // Added file. if (enable) { if (cachedIndex != null) { cachedIndex.SetDataOffset(mod.fullPath, mod.data.modOffset); } else { await index.UpdateDataOffset(mod.data.modOffset, mod.fullPath, false); } mod.enabled = true; if (cachedIndex == null) { // Check if we're re-enabling a metadata mod. var ext = Path.GetExtension(mod.fullPath); if (ext == ".meta") { var df = IOUtil.GetDataFileFromPath(mod.fullPath); // Retreive the uncompressed meta entry we just enabled. var data = await dat.GetType2Data(mod.data.modOffset, df); var meta = await ItemMetadata.Deserialize(data); meta.Validate(mod.fullPath); // And write that metadata to the actual constituent files. await ItemMetadata.ApplyMetadata(meta, cachedIndex, cachedModlist); } else if (ext == ".rgsp") { await CMP.ApplyRgspFile(mod.fullPath, cachedIndex, cachedModlist); } } } else if (!enable) { if (mod.IsCustomFile()) { // Delete file descriptor handles removing metadata as needed on its own. if (cachedIndex != null) { cachedIndex.SetDataOffset(mod.fullPath, 0); } else { await index.DeleteFileDescriptor(mod.fullPath, IOUtil.GetDataFileFromPath(mod.fullPath), false); } } else { if (cachedIndex != null) { cachedIndex.SetDataOffset(mod.fullPath, mod.data.originalOffset); } else { await index.UpdateDataOffset(mod.data.originalOffset, mod.fullPath, false); } } mod.enabled = false; } if (updateCache) { XivCache.QueueDependencyUpdate(mod.fullPath); } return(true); }