/// <summary>Get update check info about a mod.</summary> /// <param name="id">The mod ID.</param> public async Task <IModPage> GetModData(string id) { var page = new GenericModPage(this.SiteKey, id); if (!long.TryParse(id, out long parsedId)) { return(page.SetError(RemoteModStatus.DoesNotExist, $"The value '{id}' isn't a valid ModDrop mod ID, must be an integer ID.")); } // get raw data ModListModel response = await this.Client .PostAsync("") .WithBody(new { ModIDs = new[] { parsedId }, Files = true, Mods = true }) .As <ModListModel>(); ModModel mod = response.Mods[parsedId]; if (mod.Mod?.Title == null || mod.Mod.ErrorCode.HasValue) { return(null); } // get files var downloads = new List <IModDownload>(); foreach (FileDataModel file in mod.Files) { if (file.IsOld || file.IsDeleted || file.IsHidden) { continue; } downloads.Add( new GenericModDownload(file.Name, file.Description, file.Version) ); } // return info string name = mod.Mod?.Title; string url = string.Format(this.ModUrlFormat, id); return(page.SetInfo(name: name, version: null, url: url, downloads: downloads)); }
/********* ** Private methods *********/ /// <summary>Asynchronously fetch mod metadata from the wiki.</summary> public async Task <ModListModel> FetchDataAsync() { return(await this.Cache.GetOrCreateAsync($"{nameof(ModsController)}_mod_list", async entry => { WikiModList data = await new ModToolkit().GetWikiCompatibilityListAsync(); ModListModel model = new ModListModel( stableVersion: data.StableVersion, betaVersion: data.BetaVersion, mods: data .Mods .Select(mod => new ModModel(mod)) .OrderBy(p => Regex.Replace(p.Name.ToLower(), "[^a-z0-9]", "")) // ignore case, spaces, and special characters when sorting ); entry.AbsoluteExpiration = DateTimeOffset.UtcNow.AddMinutes(this.SuccessCacheMinutes); return model; })); }
public ModListModel ParseEntry(JsonEntry entry) { ModListModel mlm = new ModListModel(); string race, map, part, type; if (entry.fullPath.Contains("weapon") || entry.fullPath.Contains("accessory") || entry.fullPath.Contains("decal") || entry.fullPath.Contains("vfx") || entry.fullPath.Contains("ui/")) { race = Strings.All; } else if (entry.fullPath.Contains("monster") || entry.fullPath.Contains("demihuman")) { race = Strings.Monster; } else { race = entry.fullPath.Substring(entry.fullPath.LastIndexOf('/')); if ((entry.fullPath.Contains("_fac_") || entry.fullPath.Contains("_etc_") || entry.fullPath.Contains("_acc_")) && Properties.Settings.Default.DX_Ver.Equals(Strings.DX11)) { race = race.Substring(race.LastIndexOf("--c") + 3, 4); } else if (entry.fullPath.Contains("_fac_") || entry.fullPath.Contains("_etc_") || entry.fullPath.Contains("_acc_")) { race = race.Substring(race.LastIndexOf("/c") + 2, 4); } else if (entry.fullPath.Contains("_c_")) { race = race.Substring(race.IndexOf("_c") + 2, 4); } else { race = race.Substring(race.LastIndexOf('c') + 1, 4); } race = Info.IDRace[race]; } mlm.Race = race; if (entry.fullPath.Contains("_d.")) { map = Strings.Diffuse; } else if (entry.fullPath.Contains("_n.")) { map = Strings.Normal; } else if (entry.fullPath.Contains("_s.")) { map = Strings.Specular; } else if (entry.fullPath.Contains("material")) { map = Strings.ColorSet; } else if (entry.fullPath.Contains("model")) { map = "3D"; } else if (entry.fullPath.Contains("ui/")) { map = "UI"; } else { map = Strings.Mask; } mlm.Map = map; if (entry.fullPath.Contains("_b_")) { part = "b"; } else if (entry.fullPath.Contains("_c_")) { part = "c"; } else if (entry.fullPath.Contains("_d_")) { part = "d"; } else if (entry.fullPath.Contains("decal")) { part = entry.fullPath.Substring(entry.fullPath.LastIndexOf('_') + 1, entry.fullPath.LastIndexOf('.') - (entry.fullPath.LastIndexOf('_') + 1)); } else { part = "a"; } mlm.Part = part; if (entry.fullPath.Contains("_iri_")) { type = "Iris"; } else if (entry.fullPath.Contains("_etc_")) { type = "Etc."; } else if (entry.fullPath.Contains("_fac_")) { type = "Face"; } else if (entry.fullPath.Contains("_hir_")) { type = "Hair"; } else if (entry.fullPath.Contains("_acc_")) { type = "Accessory"; } else if (entry.fullPath.Contains("demihuman")) { type = entry.fullPath.Substring(entry.fullPath.LastIndexOf('_') - 3, 3); type = (Info.slotAbr).FirstOrDefault(x => x.Value == type).Key; } else { type = "-"; } mlm.Type = type; if (entry.fullPath.Contains("material")) { var info = MTRL.GetMTRLInfo(entry.modOffset, false); var bitmap = TEX.TextureToBitmap(info.ColorData, 9312, 4, 16); mlm.BMP = Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } else if (entry.fullPath.Contains("model")) { mlm.BMP = new BitmapImage(new Uri("pack://application:,,,/FFXIV TexTools 2;component/Resources/3DModel.png")); } else { TEXData texData; if (entry.fullPath.Contains("vfx")) { texData = TEX.GetVFX(entry.modOffset, entry.datFile); } else { if (entry.fullPath.Contains("icon")) { texData = TEX.GetTex(entry.modOffset, entry.datFile); } else { texData = TEX.GetTex(entry.modOffset, entry.datFile); } } mlm.BMP = Imaging.CreateBitmapSourceFromHBitmap(texData.BMP.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } var offset = Helper.GetDataOffset(FFCRC.GetHash(entry.fullPath.Substring(0, entry.fullPath.LastIndexOf("/"))), FFCRC.GetHash(Path.GetFileName(entry.fullPath)), entry.datFile); if (offset == entry.modOffset) { mlm.ActiveBorder = Brushes.Green; mlm.Active = Brushes.Transparent; mlm.ActiveOpacity = 1; } else if (offset == entry.originalOffset) { mlm.ActiveBorder = Brushes.Red; mlm.Active = Brushes.Gray; mlm.ActiveOpacity = 0.5f; } else { mlm.ActiveBorder = Brushes.Red; mlm.Active = Brushes.Red; mlm.ActiveOpacity = 1; } mlm.Entry = entry; return(mlm); }
public ModListModel ParseEntry(JsonEntry entry) { ModListModel mlm = new ModListModel(); string race, map, part, type; if (entry.fullPath.Contains("mt_")) { Debug.WriteLine(entry.fullPath); } if (entry.fullPath.Contains("weapon") || entry.fullPath.Contains("accessory") || entry.fullPath.Contains("decal") || entry.fullPath.Contains("vfx") || entry.fullPath.Contains("ui/")) { race = Strings.All; } else if (entry.fullPath.Contains("monster") || entry.fullPath.Contains("demihuman")) { race = Strings.Monster; } else { race = entry.fullPath.Substring(entry.fullPath.LastIndexOf('/')); if (entry.fullPath.Contains("mt_") && entry.fullPath.Contains("_acc_")) { race = race.Substring(race.IndexOf("_") + 2, 4); } else if ((entry.fullPath.Contains("_fac_") || entry.fullPath.Contains("_etc_") || entry.fullPath.Contains("_acc_")) && Properties.Settings.Default.DX_Ver.Equals(Strings.DX11)) { race = race.Substring(race.LastIndexOf("--c") + 3, 4); } else if (entry.fullPath.Contains("_fac_") || entry.fullPath.Contains("_etc_") || entry.fullPath.Contains("_acc_")) { race = race.Substring(race.LastIndexOf("/c") + 2, 4); } else if (entry.fullPath.Contains("_c_")) { race = race.Substring(race.IndexOf("_c") + 2, 4); } else { if (entry.fullPath.Contains(".mdl") && entry.fullPath.Contains("_fac")) { race = race.Substring(race.IndexOf('c') + 1, 4); } else { race = race.Substring(race.LastIndexOf('c') + 1, 4); } } if (entry.fullPath.Contains("mt_")) { Debug.WriteLine(race + "\n"); } race = Info.IDRace[race]; } mlm.Race = race; if (entry.fullPath.Contains("_d.")) { map = Strings.Diffuse; } else if (entry.fullPath.Contains("_n.")) { map = Strings.Normal; } else if (entry.fullPath.Contains("_s.")) { map = Strings.Specular; } else if (entry.fullPath.Contains("material")) { map = Strings.ColorSet; } else if (entry.fullPath.Contains("model")) { map = "3D"; } else if (entry.fullPath.Contains("ui/")) { map = "UI"; } else { map = Strings.Mask; } mlm.Map = map; if (entry.fullPath.Contains("_b_")) { part = "b"; } else if (entry.fullPath.Contains("_c_")) { part = "c"; } else if (entry.fullPath.Contains("_d_")) { part = "d"; } else if (entry.fullPath.Contains("decal")) { part = entry.fullPath.Substring(entry.fullPath.LastIndexOf('_') + 1, entry.fullPath.LastIndexOf('.') - (entry.fullPath.LastIndexOf('_') + 1)); } else { part = "a"; } mlm.Part = part; if (entry.fullPath.Contains("_iri_")) { type = "Iris"; } else if (entry.fullPath.Contains("_etc_")) { type = "Etc."; } else if (entry.fullPath.Contains("_fac_")) { type = "Face"; } else if (entry.fullPath.Contains("_hir_")) { type = "Hair"; } else if (entry.fullPath.Contains("_acc_")) { type = "Accessory"; } else if (entry.fullPath.Contains("demihuman")) { type = entry.fullPath.Substring(entry.fullPath.LastIndexOf('_') - 3, 3); type = (Info.slotAbr).FirstOrDefault(x => x.Value == type).Key; } else { type = "-"; } mlm.Type = type; if (entry.fullPath.Contains("material")) { var info = MTRL.GetMTRLInfo(entry.modOffset, false); using (var bitmap = TEX.ColorSetToBitmap(info.ColorData)) mlm.BMP = TexHelper.CreateBitmapSource(bitmap); mlm.BMP.Freeze(); } else if (entry.fullPath.Contains("model")) { mlm.BMP = new BitmapImage(new Uri("pack://application:,,,/FFXIV TexTools 2;component/Resources/3DModel.png")); } else { TEXData texData; if (entry.fullPath.Contains("vfx")) { texData = TEX.GetVFX(entry.modOffset, entry.datFile); } else { if (entry.fullPath.Contains("icon")) { texData = TEX.GetTex(entry.modOffset, entry.datFile); } else { texData = TEX.GetTex(entry.modOffset, entry.datFile); } } var scale = 1; if (texData.Width >= 4096 || texData.Height >= 4096) { scale = 16; } else if (texData.Width >= 2048 || texData.Height >= 2048) { scale = 8; } else if (texData.Width >= 1024 || texData.Height >= 1024) { scale = 4; } var nWidth = texData.Width / scale; var nHeight = texData.Height / scale; var resizedImage = TexHelper.CreateResizedImage(texData.BMPSouceNoAlpha, nWidth, nHeight); mlm.BMP = (BitmapSource)resizedImage; mlm.BMP.Freeze(); } var offset = Helper.GetDataOffset(FFCRC.GetHash(entry.fullPath.Substring(0, entry.fullPath.LastIndexOf("/"))), FFCRC.GetHash(Path.GetFileName(entry.fullPath)), entry.datFile); if (offset == entry.modOffset) { mlm.ActiveBorder = Brushes.Green; mlm.Active = Brushes.Transparent; mlm.ActiveOpacity = 1; } else if (offset == entry.originalOffset) { mlm.ActiveBorder = Brushes.Red; mlm.Active = Brushes.Gray; mlm.ActiveOpacity = 0.5f; } else { mlm.ActiveBorder = Brushes.Red; mlm.Active = Brushes.Red; mlm.ActiveOpacity = 1; } mlm.Entry = entry; return(mlm); }
/// <summary>Get metadata about a mod.</summary> /// <param name="id">The ModDrop mod ID.</param> /// <returns>Returns the mod info if found, else <c>null</c>.</returns> public async Task <ModDropMod> GetModAsync(long id) { // get raw data ModListModel response = await this.Client .PostAsync("") .WithBody(new { ModIDs = new[] { id }, Files = true, Mods = true }) .As <ModListModel>(); ModModel mod = response.Mods[id]; if (mod.Mod?.Title == null || mod.Mod.ErrorCode.HasValue) { return(null); } // get latest versions ISemanticVersion latest = null; ISemanticVersion optional = null; foreach (FileDataModel file in mod.Files) { if (file.IsOld || file.IsDeleted || file.IsHidden) { continue; } if (!SemanticVersion.TryParse(file.Version, out ISemanticVersion version)) { continue; } if (file.IsDefault) { if (latest == null || version.IsNewerThan(latest)) { latest = version; } } else if (optional == null || version.IsNewerThan(optional)) { optional = version; } } if (latest == null) { latest = optional; optional = null; } if (optional != null && latest.IsNewerThan(optional)) { optional = null; } // generate result return(new ModDropMod { Name = mod.Mod?.Title, LatestDefaultVersion = latest, LatestOptionalVersion = optional, Url = string.Format(this.ModUrlFormat, id) }); }