Merge pull request #118 from NotOfficer/master

Playlist images support
This commit is contained in:
Valentin 2020-10-10 20:36:29 +02:00 committed by GitHub
commit 54d2ccf090
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 157 additions and 39 deletions

View File

@ -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<Statistic> 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<ObjectProperty>("Series") is ObjectProperty series)
if (export.GetExport<ObjectProperty>("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<EnumProperty>("Rarity")); // uncommon will be triggered by Rarity being null
else if (export.GetExport<EnumProperty>("Rarity") is EnumProperty rarity)
else if (export.GetExport<EnumProperty>("Rarity") is { } rarity)
Rarity.GetHardCodedRarity(this, rarity);
if (export.GetExport<ObjectProperty>("HeroDefinition", "WeaponDefinition") is ObjectProperty itemDef)
if (export.GetExport<ObjectProperty>("HeroDefinition", "WeaponDefinition") is { } itemDef)
LargeSmallImage.GetPreviewImage(this, itemDef, assetName, forceHR);
else if (export.GetExport<SoftObjectProperty>(forceHR ? "LargePreviewImage" : "SmallPreviewImage", forceHR ? "ItemDisplayAsset" : "SmallImage") is SoftObjectProperty previewImage)
else if (export.GetExport<SoftObjectProperty>(forceHR ? "LargePreviewImage" : "SmallPreviewImage", forceHR ? "ItemDisplayAsset" : "SmallImage") is { } previewImage)
LargeSmallImage.GetPreviewImage(this, previewImage);
else if (export.GetExport<ObjectProperty>("access_item") is ObjectProperty accessItem)
else if (export.GetExport<ObjectProperty>("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<TextProperty>("DisplayName", "DefaultHeaderText", "UIDisplayName") is TextProperty displayName)
if (export.GetExport<TextProperty>("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<ObjectProperty>("Series") is ObjectProperty series)
if (export.GetExport<ObjectProperty>("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<EnumProperty>("Rarity")); // uncommon will be triggered by Rarity being null
else if (export.GetExport<EnumProperty>("Rarity") is EnumProperty rarity)
else if (export.GetExport<EnumProperty>("Rarity") is { } rarity)
Rarity.GetHardCodedRarity(this, rarity);
// image
if (Properties.Settings.Default.UseItemShopIcon &&
if (Settings.Default.UseItemShopIcon &&
DisplayAssetImage.GetDisplayAssetImage(this, export.GetExport<SoftObjectProperty>("DisplayAssetPath"), ref assetName))
{ } // ^^^^ will return false if image not found, if so, we try to get the normal icon
else if (export.GetExport<ObjectProperty>("HeroDefinition", "WeaponDefinition") is ObjectProperty itemDef)
else if (export.GetExport<ObjectProperty>("HeroDefinition", "WeaponDefinition") is { } itemDef)
LargeSmallImage.GetPreviewImage(this, itemDef, assetName);
else if (export.GetExport<SoftObjectProperty>("LargePreviewImage", "SmallPreviewImage", "ItemDisplayAsset") is SoftObjectProperty previewImage)
else if (export.GetExport<SoftObjectProperty>("LargePreviewImage", "SmallPreviewImage", "ItemDisplayAsset") is { } previewImage)
LargeSmallImage.GetPreviewImage(this, previewImage);
else if (export.GetExport<ObjectProperty>("SmallPreviewImage") is ObjectProperty smallPreviewImage)
this.IconImage = Utils.GetObjectTexture(smallPreviewImage);
else if (export.GetExport<StructProperty>("IconBrush") is StructProperty iconBrush) // abilities
else if (export.GetExport<ObjectProperty>("SmallPreviewImage") is { } smallPreviewImage)
IconImage = Utils.GetObjectTexture(smallPreviewImage);
else if (export.GetExport<StructProperty>("IconBrush") is { } iconBrush) // abilities
LargeSmallImage.GetPreviewImage(this, iconBrush);
// text
if (export.GetExport<TextProperty>("DisplayName", "DefaultHeaderText", "UIDisplayName") is TextProperty displayName)
if (export.GetExport<TextProperty>("DisplayName", "DefaultHeaderText", "UIDisplayName") is { } displayName)
DisplayName = Text.GetTextPropertyBase(displayName);
if (export.GetExport<TextProperty>("Description", "DefaultBodyText", "UIDescription") is TextProperty description)
if (export.GetExport<TextProperty>("Description", "DefaultBodyText", "UIDescription") is { } description)
Description = Text.GetTextPropertyBase(description);
else if (export.GetExport<ArrayProperty>("Description") is ArrayProperty arrayDescription) // abilities
else if (export.GetExport<ArrayProperty>("Description") is { } arrayDescription) // abilities
Description = Text.GetTextPropertyBase(arrayDescription);
if (export.GetExport<StructProperty>("MaxStackSize") is StructProperty maxStackSize)
if (export.GetExport<StructProperty>("MaxStackSize") is { } maxStackSize)
ShortDescription = Text.GetMaxStackSize(maxStackSize);
else if (export.GetExport<StructProperty>("XpRewardAmount") is StructProperty xpRewardAmount)
else if (export.GetExport<StructProperty>("XpRewardAmount") is { } xpRewardAmount)
ShortDescription = Text.GetXpRewardAmount(xpRewardAmount);
else if (export.GetExport<TextProperty>("ShortDescription", "UIDisplaySubName") is TextProperty shortDescription)
else if (export.GetExport<TextProperty>("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<StructProperty>("GameplayTags") is StructProperty gameplayTags)
if (export.GetExport<StructProperty>("GameplayTags") is { } gameplayTags)
GameplayTag.GetGameplayTags(this, gameplayTags, exportType);
else if (export.GetExport<ObjectProperty>("cosmetic_item") is ObjectProperty cosmeticItem) // variants
else if (export.GetExport<ObjectProperty>("cosmetic_item") is { } cosmeticItem) // variants
CosmeticSource = cosmeticItem.Value.Resource.ObjectName.String;
if (Properties.Settings.Default.DrawStats && export.GetExport<SoftObjectProperty>("AmmoData") is SoftObjectProperty ammoData)
if (Settings.Default.DrawStats && export.GetExport<SoftObjectProperty>("AmmoData") is { } ammoData)
Statistics.GetAmmoData(this, ammoData);
if (Properties.Settings.Default.DrawStats && export.GetExport<StructProperty>("WeaponStatHandle") is StructProperty weaponStatHandle &&
if (Settings.Default.DrawStats && export.GetExport<StructProperty>("WeaponStatHandle") is { } weaponStatHandle &&
(exportType.Equals("FortWeaponMeleeItemDefinition") ||
(export.GetExport<SoftObjectProperty>("StatList") is SoftObjectProperty statList &&
(export.GetExport<SoftObjectProperty>("StatList") is { } statList &&
!statList.Value.AssetPathName.String.StartsWith("/Game/UI/Tooltips/NoTooltipStats"))))
{
Statistics.GetWeaponStats(this, weaponStatHandle);
}
if (Properties.Settings.Default.DrawStats && export.GetExport<ObjectProperty>("HeroGameplayDefinition") is ObjectProperty heroGameplayDefinition)
if (Settings.Default.DrawStats && export.GetExport<ObjectProperty>("HeroGameplayDefinition") is { } heroGameplayDefinition)
Statistics.GetHeroStats(this, heroGameplayDefinition);
/* Please do not add Schematics support because it takes way too much memory */

View File

@ -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<TextProperty>("UIDisplayName", "DisplayName") is { } displayName)
DisplayName = Text.GetTextPropertyBase(displayName);
if (export.GetExport<TextProperty>("UIDescription", "Description") is { } description)
Description = Text.GetTextPropertyBase(description);
Width = Height = 512;
if (export.GetExport<NameProperty>("PlaylistName") is { } playlistName && !playlistName.Value.IsNone)
{
ApiResponse<PlaylistV1> 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;
}
}
}
}
}
}

View File

@ -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);

View File

@ -137,6 +137,7 @@
<PackageReference Include="DotNetZip" Version="1.13.8" />
<PackageReference Include="EpicManifestParser" Version="1.2.0" />
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.0.1" />
<PackageReference Include="Fortnite-API-Wrapper" Version="2.1.0" />
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.2.6" />
<PackageReference Include="LZMA-SDK" Version="19.0.0" />
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.1" />

View File

@ -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<string> GetStringEndpoint(string url) => await GetStringEndpoint(url, string.Empty);
public static byte[] GetRawData(Uri uri) => GetRawDataAsync(uri).GetAwaiter().GetResult();
public static async Task<byte[]> 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<string> GetStringEndpoint(string url) => GetStringEndpoint(url, string.Empty);
public static async Task<string> 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<T> GetJsonEndpoint<T>(string url) => await GetJsonEndpoint<T>(url, string.Empty);
public static Task<T> GetJsonEndpoint<T>(string url) => GetJsonEndpoint<T>(url, string.Empty);
public static async Task<T> GetJsonEndpoint<T>(string url, string query)
{
if (url.Equals(BENBOT_HOTFIXES) && !string.IsNullOrEmpty(query))