From f5fa499905a0c9d0ca5a5f915a96e413e2a17f39 Mon Sep 17 00:00:00 2001 From: Not Officer Date: Sat, 10 Oct 2020 20:32:47 +0200 Subject: [PATCH] added playlist images support --- FModel/Creator/Bases/BaseIcon.cs | 80 +++++++++++++++------------- FModel/Creator/Bases/BasePlaylist.cs | 61 +++++++++++++++++++++ FModel/Creator/Creator.cs | 29 +++++++++- FModel/FModel.csproj | 1 + FModel/Utils/Endpoints.cs | 25 ++++++++- 5 files changed, 157 insertions(+), 39 deletions(-) create mode 100644 FModel/Creator/Bases/BasePlaylist.cs diff --git a/FModel/Creator/Bases/BaseIcon.cs b/FModel/Creator/Bases/BaseIcon.cs index 935b4c2d..2debe03a 100644 --- a/FModel/Creator/Bases/BaseIcon.cs +++ b/FModel/Creator/Bases/BaseIcon.cs @@ -1,15 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Windows; + using FModel.Creator.Icons; using FModel.Creator.Rarities; using FModel.Creator.Stats; using FModel.Creator.Texts; +using FModel.Properties; using FModel.Utils; + +using Fortnite_API.Objects; +using Fortnite_API.Objects.V1; + using PakReader.Pak; using PakReader.Parsers.Class; using PakReader.Parsers.PropertyTagData; + using SkiaSharp; -using System; -using System.Collections.Generic; -using System.Windows; namespace FModel.Creator.Bases { @@ -25,19 +33,19 @@ namespace FModel.Creator.Bases public string Description; public string ShortDescription; public string CosmeticSource; - public int Size = 512; // keep it 512 (or a multiple of 512) if you don't want blurry icons - public int AdditionalSize = 0; // must be increased if there are weapon stats, hero abilities or more to draw/show + public int Size = 512; // keep it 512 (or a multiple of 512) if you don't want blurry icons + public int AdditionalSize; // must be increased if there are weapon stats, hero abilities or more to draw/show public int Margin = 2; public List Stats; public BaseIcon() { - FallbackImage = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T_Placeholder_Item_Image.png")).Stream); + FallbackImage = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T_Placeholder_Item_Image.png"))?.Stream); IconImage = FallbackImage; RarityBackgroundImage = null; UserFacingFlags = null; - RarityBackgroundColors = new SKColor[2] { SKColor.Parse("5EBC36"), SKColor.Parse("305C15") }; - RarityBorderColor = new SKColor[2] { SKColor.Parse("74EF52"), SKColor.Parse("74EF52") }; + RarityBackgroundColors = new[] { SKColor.Parse("5EBC36"), SKColor.Parse("305C15") }; + RarityBorderColor = new[] { SKColor.Parse("74EF52"), SKColor.Parse("74EF52") }; DisplayName = ""; Description = ""; ShortDescription = ""; @@ -47,18 +55,18 @@ namespace FModel.Creator.Bases public BaseIcon(IUExport export, string assetName, bool forceHR) : this() { - if (export.GetExport("Series") is ObjectProperty series) + if (export.GetExport("Series") is { } series) Serie.GetRarity(this, series); - else if (Properties.Settings.Default.UseGameColors) // override default green + else if (Settings.Default.UseGameColors) // override default green Rarity.GetInGameRarity(this, export.GetExport("Rarity")); // uncommon will be triggered by Rarity being null - else if (export.GetExport("Rarity") is EnumProperty rarity) + else if (export.GetExport("Rarity") is { } rarity) Rarity.GetHardCodedRarity(this, rarity); - if (export.GetExport("HeroDefinition", "WeaponDefinition") is ObjectProperty itemDef) + if (export.GetExport("HeroDefinition", "WeaponDefinition") is { } itemDef) LargeSmallImage.GetPreviewImage(this, itemDef, assetName, forceHR); - else if (export.GetExport(forceHR ? "LargePreviewImage" : "SmallPreviewImage", forceHR ? "ItemDisplayAsset" : "SmallImage") is SoftObjectProperty previewImage) + else if (export.GetExport(forceHR ? "LargePreviewImage" : "SmallPreviewImage", forceHR ? "ItemDisplayAsset" : "SmallImage") is { } previewImage) LargeSmallImage.GetPreviewImage(this, previewImage); - else if (export.GetExport("access_item") is ObjectProperty accessItem) + else if (export.GetExport("access_item") is { } accessItem) { PakPackage p = Utils.GetPropertyPakPackage(accessItem.Value.Resource.OuterIndex.Resource.ObjectName.String); if (p.HasExport() && !p.Equals(default)) @@ -71,7 +79,7 @@ namespace FModel.Creator.Bases } } - if (export.GetExport("DisplayName", "DefaultHeaderText", "UIDisplayName") is TextProperty displayName) + if (export.GetExport("DisplayName", "DefaultHeaderText", "UIDisplayName") is { } displayName) DisplayName = Text.GetTextPropertyBase(displayName); } @@ -90,58 +98,58 @@ namespace FModel.Creator.Bases public BaseIcon(IUExport export, string exportType, ref string assetName) : this() { // rarity - if (export.GetExport("Series") is ObjectProperty series) + if (export.GetExport("Series") is { } series) Serie.GetRarity(this, series); - else if (Properties.Settings.Default.UseGameColors) // override default green + else if (Settings.Default.UseGameColors) // override default green Rarity.GetInGameRarity(this, export.GetExport("Rarity")); // uncommon will be triggered by Rarity being null - else if (export.GetExport("Rarity") is EnumProperty rarity) + else if (export.GetExport("Rarity") is { } rarity) Rarity.GetHardCodedRarity(this, rarity); // image - if (Properties.Settings.Default.UseItemShopIcon && + if (Settings.Default.UseItemShopIcon && DisplayAssetImage.GetDisplayAssetImage(this, export.GetExport("DisplayAssetPath"), ref assetName)) { } // ^^^^ will return false if image not found, if so, we try to get the normal icon - else if (export.GetExport("HeroDefinition", "WeaponDefinition") is ObjectProperty itemDef) + else if (export.GetExport("HeroDefinition", "WeaponDefinition") is { } itemDef) LargeSmallImage.GetPreviewImage(this, itemDef, assetName); - else if (export.GetExport("LargePreviewImage", "SmallPreviewImage", "ItemDisplayAsset") is SoftObjectProperty previewImage) + else if (export.GetExport("LargePreviewImage", "SmallPreviewImage", "ItemDisplayAsset") is { } previewImage) LargeSmallImage.GetPreviewImage(this, previewImage); - else if (export.GetExport("SmallPreviewImage") is ObjectProperty smallPreviewImage) - this.IconImage = Utils.GetObjectTexture(smallPreviewImage); - else if (export.GetExport("IconBrush") is StructProperty iconBrush) // abilities + else if (export.GetExport("SmallPreviewImage") is { } smallPreviewImage) + IconImage = Utils.GetObjectTexture(smallPreviewImage); + else if (export.GetExport("IconBrush") is { } iconBrush) // abilities LargeSmallImage.GetPreviewImage(this, iconBrush); // text - if (export.GetExport("DisplayName", "DefaultHeaderText", "UIDisplayName") is TextProperty displayName) + if (export.GetExport("DisplayName", "DefaultHeaderText", "UIDisplayName") is { } displayName) DisplayName = Text.GetTextPropertyBase(displayName); - if (export.GetExport("Description", "DefaultBodyText", "UIDescription") is TextProperty description) + if (export.GetExport("Description", "DefaultBodyText", "UIDescription") is { } description) Description = Text.GetTextPropertyBase(description); - else if (export.GetExport("Description") is ArrayProperty arrayDescription) // abilities + else if (export.GetExport("Description") is { } arrayDescription) // abilities Description = Text.GetTextPropertyBase(arrayDescription); - if (export.GetExport("MaxStackSize") is StructProperty maxStackSize) + if (export.GetExport("MaxStackSize") is { } maxStackSize) ShortDescription = Text.GetMaxStackSize(maxStackSize); - else if (export.GetExport("XpRewardAmount") is StructProperty xpRewardAmount) + else if (export.GetExport("XpRewardAmount") is { } xpRewardAmount) ShortDescription = Text.GetXpRewardAmount(xpRewardAmount); - else if (export.GetExport("ShortDescription", "UIDisplaySubName") is TextProperty shortDescription) + else if (export.GetExport("ShortDescription", "UIDisplaySubName") is { } shortDescription) ShortDescription = Text.GetTextPropertyBase(shortDescription); else if (exportType.Equals("AthenaItemWrapDefinition")) // if no ShortDescription it's most likely a wrap ShortDescription = Localizations.GetLocalization("Fort.Cosmetics", "ItemWrapShortDescription", "Wrap"); // gameplaytags - if (export.GetExport("GameplayTags") is StructProperty gameplayTags) + if (export.GetExport("GameplayTags") is { } gameplayTags) GameplayTag.GetGameplayTags(this, gameplayTags, exportType); - else if (export.GetExport("cosmetic_item") is ObjectProperty cosmeticItem) // variants + else if (export.GetExport("cosmetic_item") is { } cosmeticItem) // variants CosmeticSource = cosmeticItem.Value.Resource.ObjectName.String; - if (Properties.Settings.Default.DrawStats && export.GetExport("AmmoData") is SoftObjectProperty ammoData) + if (Settings.Default.DrawStats && export.GetExport("AmmoData") is { } ammoData) Statistics.GetAmmoData(this, ammoData); - if (Properties.Settings.Default.DrawStats && export.GetExport("WeaponStatHandle") is StructProperty weaponStatHandle && + if (Settings.Default.DrawStats && export.GetExport("WeaponStatHandle") is { } weaponStatHandle && (exportType.Equals("FortWeaponMeleeItemDefinition") || - (export.GetExport("StatList") is SoftObjectProperty statList && + (export.GetExport("StatList") is { } statList && !statList.Value.AssetPathName.String.StartsWith("/Game/UI/Tooltips/NoTooltipStats")))) { Statistics.GetWeaponStats(this, weaponStatHandle); } - if (Properties.Settings.Default.DrawStats && export.GetExport("HeroGameplayDefinition") is ObjectProperty heroGameplayDefinition) + if (Settings.Default.DrawStats && export.GetExport("HeroGameplayDefinition") is { } heroGameplayDefinition) Statistics.GetHeroStats(this, heroGameplayDefinition); /* Please do not add Schematics support because it takes way too much memory */ diff --git a/FModel/Creator/Bases/BasePlaylist.cs b/FModel/Creator/Bases/BasePlaylist.cs new file mode 100644 index 00000000..3022c21a --- /dev/null +++ b/FModel/Creator/Bases/BasePlaylist.cs @@ -0,0 +1,61 @@ +using System; +using System.Windows; + +using FModel.Creator.Texts; +using FModel.Utils; + +using Fortnite_API.Objects; +using Fortnite_API.Objects.V1; + +using PakReader.Parsers.Class; +using PakReader.Parsers.PropertyTagData; + +using SkiaSharp; + +namespace FModel.Creator.Bases +{ + public class BasePlaylist : IBase + { + public SKBitmap FallbackImage { get; } + public SKBitmap IconImage { get; } + public SKColor[] RarityBackgroundColors { get; } + public SKColor[] RarityBorderColor { get; } + public string DisplayName { get; } + public string Description { get; } + public int Width { get; } + public int Height { get; } + public int Margin { get; } = 2; + + public BasePlaylist(IUExport export) + { + FallbackImage = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T_Placeholder_Item_Image.png"))?.Stream); + IconImage = FallbackImage; + RarityBackgroundColors = new[] { SKColor.Parse("5EBC36"), SKColor.Parse("305C15") }; + RarityBorderColor = new[] { SKColor.Parse("74EF52"), SKColor.Parse("74EF52") }; + + if (export.GetExport("UIDisplayName", "DisplayName") is { } displayName) + DisplayName = Text.GetTextPropertyBase(displayName); + if (export.GetExport("UIDescription", "Description") is { } description) + Description = Text.GetTextPropertyBase(description); + + Width = Height = 512; + + if (export.GetExport("PlaylistName") is { } playlistName && !playlistName.Value.IsNone) + { + ApiResponse playlist = Endpoints.FortniteAPI.V1.Playlists.Get(playlistName.Value.String); + + if (playlist.IsSuccess && playlist.Data.Images.HasShowcase) + { + byte[] imageBytes = Endpoints.GetRawData(playlist.Data.Images.Showcase); + + if (imageBytes != null) + { + IconImage = SKBitmap.Decode(imageBytes); + Width = IconImage.Width; + Height = IconImage.Height; + } + } + } + } + } +} diff --git a/FModel/Creator/Creator.cs b/FModel/Creator/Creator.cs index c744b84a..54d71a29 100644 --- a/FModel/Creator/Creator.cs +++ b/FModel/Creator/Creator.cs @@ -52,7 +52,6 @@ namespace FModel.Creator case "FortAbilityKit": case "FortWorkerType": case "RewardGraphToken": - case "FortPlaylistAthena": case "FortBannerTokenType": case "FortVariantTokenType": case "FortDecoItemDefinition": @@ -142,6 +141,34 @@ namespace FModel.Creator } return true; } + case "FortPlaylistAthena": + { + BasePlaylist icon = new BasePlaylist(exports[index]); + using (var ret = new SKBitmap(icon.Width, icon.Height, SKColorType.Rgba8888, SKAlphaType.Premul)) + using (var c = new SKCanvas(ret)) + { + if ((EIconDesign)Properties.Settings.Default.AssetsIconDesign != EIconDesign.NoBackground) + { + Rarity.DrawRarity(c, icon); + } + + LargeSmallImage.DrawPreviewImage(c, icon); + + if ((EIconDesign)Properties.Settings.Default.AssetsIconDesign != EIconDesign.NoBackground) + { + if ((EIconDesign)Properties.Settings.Default.AssetsIconDesign != EIconDesign.NoText) + { + Text.DrawBackground(c, icon); + Text.DrawDisplayName(c, icon); + Text.DrawDescription(c, icon); + } + } + + Watermark.DrawWatermark(c); // watermark should only be applied on icons with width = 512 + ImageBoxVm.imageBoxViewModel.Set(ret, assetName); + } + return true; + } case "AthenaSeasonItemDefinition": { BaseSeason icon = new BaseSeason(exports[index], assetFolder); diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index 34dec3f6..70bfbb2b 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -137,6 +137,7 @@ + diff --git a/FModel/Utils/Endpoints.cs b/FModel/Utils/Endpoints.cs index 2021a158..aa325ad3 100644 --- a/FModel/Utils/Endpoints.cs +++ b/FModel/Utils/Endpoints.cs @@ -3,20 +3,41 @@ using Newtonsoft.Json; using System; using System.IO; using System.Net.Http; +using System.Reflection; using System.Text; using System.Threading.Tasks; +using Fortnite_API; + namespace FModel.Utils { static class Endpoints { + public static readonly FortniteApi FortniteAPI = new FortniteApi($"FModel/{Assembly.GetExecutingAssembly().GetName().Version}"); public const string BENBOT_AES = "https://benbotfn.tk/api/v1/aes"; public const string BENBOT_HOTFIXES = "https://benbotfn.tk/api/v1/hotfixes"; public const string FMODEL_JSON = "https://dl.dropbox.com/s/sxyaqo6zu1drlea/FModel.json?dl=0"; public const string OAUTH_URL = "https://account-public-service-prod03.ol.epicgames.com/account/api/oauth/token"; private const string _BASIC_FN_TOKEN = "basic MzQ0NmNkNzI2OTRjNGE0NDg1ZDgxYjc3YWRiYjIxNDE6OTIwOWQ0YTVlMjVhNDU3ZmI5YjA3NDg5ZDMxM2I0MWE="; - public static async Task GetStringEndpoint(string url) => await GetStringEndpoint(url, string.Empty); + public static byte[] GetRawData(Uri uri) => GetRawDataAsync(uri).GetAwaiter().GetResult(); + public static async Task GetRawDataAsync(Uri uri) + { + using (HttpClient client = new HttpClient { Timeout = TimeSpan.FromSeconds(2) }) + { + try + { + var data = await client.GetByteArrayAsync(uri).ConfigureAwait(false); + return data; + } + catch + { + return null; + } + } + } + + public static Task GetStringEndpoint(string url) => GetStringEndpoint(url, string.Empty); public static async Task GetStringEndpoint(string url, string token) { DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[Endpoints]", "[GET]", url); @@ -49,7 +70,7 @@ namespace FModel.Utils return string.Empty; } - public static async Task GetJsonEndpoint(string url) => await GetJsonEndpoint(url, string.Empty); + public static Task GetJsonEndpoint(string url) => GetJsonEndpoint(url, string.Empty); public static async Task GetJsonEndpoint(string url, string query) { if (url.Equals(BENBOT_HOTFIXES) && !string.IsNullOrEmpty(query))