From b7c48c12c42460824aeec7fe385beaf79981a571 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Fri, 9 Oct 2020 22:58:04 +0200 Subject: [PATCH] added battle pass icon generation --- FModel/Creator/Bases/BaseIcon.cs | 3 + FModel/Creator/Bases/BaseSeason.cs | 267 ++++++++++++++++++++++ FModel/Creator/Bundles/Reward.cs | 27 ++- FModel/Creator/Creator.cs | 12 + FModel/Windows/Launcher/FLauncher.xaml | 2 +- FModel/Windows/Launcher/FLauncher.xaml.cs | 1 + 6 files changed, 308 insertions(+), 4 deletions(-) create mode 100644 FModel/Creator/Bases/BaseSeason.cs diff --git a/FModel/Creator/Bases/BaseIcon.cs b/FModel/Creator/Bases/BaseIcon.cs index e14ffa2a..935b4c2d 100644 --- a/FModel/Creator/Bases/BaseIcon.cs +++ b/FModel/Creator/Bases/BaseIcon.cs @@ -70,6 +70,9 @@ namespace FModel.Creator.Bases } } } + + if (export.GetExport("DisplayName", "DefaultHeaderText", "UIDisplayName") is TextProperty displayName) + DisplayName = Text.GetTextPropertyBase(displayName); } /// diff --git a/FModel/Creator/Bases/BaseSeason.cs b/FModel/Creator/Bases/BaseSeason.cs new file mode 100644 index 00000000..76a4e6c0 --- /dev/null +++ b/FModel/Creator/Bases/BaseSeason.cs @@ -0,0 +1,267 @@ +using FModel.Creator.Bundles; +using FModel.Creator.Texts; +using PakReader.Parsers.Class; +using PakReader.Parsers.PropertyTagData; +using SkiaSharp; +using System; +using System.Collections.Generic; + +namespace FModel.Creator.Bases +{ + public class BaseSeason + { + public string DisplayName; + public string FolderName; + public string Watermark; + public Reward FirstWinReward; + public Dictionary> BookXpSchedule; + public Header DisplayStyle; + public int Width = 1024; + public int HeaderHeight = 261; // height is the header basically + public int AdditionalSize = 50; // must be increased depending on the number of quests to draw + + public BaseSeason() + { + DisplayName = ""; + FolderName = ""; + Watermark = Properties.Settings.Default.ChallengeBannerWatermark; + FirstWinReward = null; + BookXpSchedule = new Dictionary>(); + DisplayStyle = new Header(); + } + + public BaseSeason(IUExport export, string assetFolder) : this() + { + if (export.GetExport("DisplayName") is TextProperty displayName) + DisplayName = Text.GetTextPropertyBase(displayName); + + if (export.GetExport("SeasonFirstWinRewards") is StructProperty s && s.Value is UObject seasonFirstWinRewards && + seasonFirstWinRewards.GetExport("Rewards") is ArrayProperty rewards) + { + foreach (StructProperty reward in rewards.Value) + { + if (reward.Value is UObject o && + o.GetExport("ItemDefinition") is SoftObjectProperty itemDefinition && + o.GetExport("Quantity") is IntProperty quantity) + { + FirstWinReward = new Reward(quantity, itemDefinition.Value); + } + } + } + + if (export.GetExport("BookXpScheduleFree") is StructProperty r2 && r2.Value is UObject bookXpScheduleFree && + bookXpScheduleFree.GetExport("Levels") is ArrayProperty levels2) + { + for (int i = 0; i < levels2.Value.Length; i++) + { + BookXpSchedule[i] = new List(); // init list for all reward index and once + if (levels2.Value[i] is StructProperty level && level.Value is UObject l && + l.GetExport("Rewards") is ArrayProperty elRewards && elRewards.Value.Length > 0) + { + foreach (StructProperty reward in elRewards.Value) + { + if (reward.Value is UObject o && + o.GetExport("ItemDefinition") is SoftObjectProperty itemDefinition && + //!itemDefinition.Value.AssetPathName.String.StartsWith("/Game/Athena/Items/ChallengeBundleSchedules/") && + o.GetExport("Quantity") is IntProperty quantity) + { + BookXpSchedule[i].Add(new Reward(quantity, itemDefinition.Value)); + } + } + } + } + } + + if (export.GetExport("BookXpSchedulePaid") is StructProperty r1 && r1.Value is UObject bookXpSchedulePaid && + bookXpSchedulePaid.GetExport("Levels") is ArrayProperty levels1) + { + for (int i = 0; i < levels1.Value.Length; i++) + { + if (levels1.Value[i] is StructProperty level && level.Value is UObject l && + l.GetExport("Rewards") is ArrayProperty elRewards && elRewards.Value.Length > 0) + { + foreach (StructProperty reward in elRewards.Value) + { + if (reward.Value is UObject o && + o.GetExport("ItemDefinition") is SoftObjectProperty itemDefinition && + //!itemDefinition.Value.AssetPathName.String.StartsWith("/Game/Athena/Items/ChallengeBundleSchedules/") && + o.GetExport("Quantity") is IntProperty quantity) + { + BookXpSchedule[i].Add(new Reward(quantity, itemDefinition.Value)); + } + } + } + } + } + + FolderName = assetFolder; + AdditionalSize += 100 * (BookXpSchedule.Count / 10); + } + + public void Draw(SKCanvas c) + { + DrawHeaderPaint(c); + DrawHeaderText(c); + + using SKPaint paint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + TextSize = 15, + Color = SKColors.White, + TextAlign = SKTextAlign.Center, + Typeface = Text.TypeFaces.BottomDefaultTypeface + }; + using SKPaint bg = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = SKColor.Parse("#0F5CAF"), + }; + using SKPaint rarity = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = SKColors.White, + }; + using SKPaint icon = new SKPaint + { + FilterQuality = SKFilterQuality.High, + IsAntialias = true + }; + + int y = HeaderHeight + 50; + int defaultSize = 80; + int x = 20; + foreach (var (index, reward) in BookXpSchedule) + { + if (index == 0) + continue; + + c.DrawText(index.ToString(), new SKPoint(x + (defaultSize / 2), y - 5), paint); + + rarity.Color = reward[0].TheReward.RarityBackgroundColors[0]; + c.DrawRect(new SKRect(x, y, x + defaultSize, y + defaultSize), bg); + c.DrawBitmap(reward[0].RewardIcon, new SKPoint(x, y), icon); + var pathBottom = new SKPath { FillType = SKPathFillType.EvenOdd }; + pathBottom.MoveTo(x, y + defaultSize); + pathBottom.LineTo(x, y + defaultSize - (defaultSize / 25 * 2.5f)); + pathBottom.LineTo(x + defaultSize, y + defaultSize - (defaultSize / 25 * 4.5f)); + pathBottom.LineTo(x + defaultSize, y + defaultSize); + pathBottom.Close(); + c.DrawPath(pathBottom, rarity); + + if (index != 1 && index % 10 == 0) + { + y += defaultSize + 20; + x = 20; + } + else + { + x += defaultSize + 20; + } + } + } + + private void DrawHeaderText(SKCanvas c) + { + using SKPaint paint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Typeface = Text.TypeFaces.BundleDisplayNameTypeface, + TextSize = 50, + Color = SKColors.White, + TextAlign = SKTextAlign.Left, + }; + + string text = DisplayName.ToUpper(); + int x = 300; + while (paint.MeasureText(text) > (Width - x)) + { + paint.TextSize -= 2; + } + c.DrawText(text, x, 155, paint); + + paint.Color = SKColors.White.WithAlpha(150); + paint.TextAlign = SKTextAlign.Right; + paint.TextSize = 23; + c.DrawText(Watermark + .Replace("{BundleName}", text) + .Replace("{Date}", DateTime.Now.ToString("dd/MM/yyyy")), + Width - 25, HeaderHeight - 40, paint); + + paint.Typeface = Text.TypeFaces.BundleDefaultTypeface; + paint.Color = DisplayStyle.SecondaryColor; + paint.TextAlign = SKTextAlign.Left; + paint.TextSize = 30; + c.DrawText(FolderName.ToUpper(), x, 95, paint); + } + + private void DrawHeaderPaint(SKCanvas c) + { + c.DrawRect(new SKRect(0, 0, Width, HeaderHeight), new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = DisplayStyle.PrimaryColor + }); + + if (DisplayStyle.CustomBackground != null && DisplayStyle.CustomBackground.Height != DisplayStyle.CustomBackground.Width) + { + var bgPaint = new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.High, BlendMode = SKBlendMode.Screen }; + if (Properties.Settings.Default.UseChallengeBanner) bgPaint.Color = SKColors.Transparent.WithAlpha((byte)Properties.Settings.Default.ChallengeBannerOpacity); + c.DrawBitmap(DisplayStyle.CustomBackground, new SKRect(0, 0, 1024, 256), bgPaint); + } + else if (DisplayStyle.DisplayImage != null) + { + if (DisplayStyle.CustomBackground != null && DisplayStyle.CustomBackground.Height == DisplayStyle.CustomBackground.Width) + c.DrawBitmap(DisplayStyle.CustomBackground, new SKRect(0, 0, HeaderHeight, HeaderHeight), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + BlendMode = SKBlendMode.Screen, + ImageFilter = SKImageFilter.CreateDropShadow(2.5F, 0, 20, 0, DisplayStyle.SecondaryColor.WithAlpha(25)) + }); + + c.DrawBitmap(DisplayStyle.DisplayImage, new SKRect(0, 0, HeaderHeight, HeaderHeight), + new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + ImageFilter = SKImageFilter.CreateDropShadow(-2.5F, 0, 20, 0, DisplayStyle.SecondaryColor.WithAlpha(50)) + }); + } + + c.DrawBitmap(FirstWinReward.TheReward.IconImage.Resize(HeaderHeight, HeaderHeight), new SKPoint(0, 0), new SKPaint + { + FilterQuality = SKFilterQuality.High, + IsAntialias = true + }); + + SKPath pathTop = new SKPath { FillType = SKPathFillType.EvenOdd }; + pathTop.MoveTo(0, HeaderHeight); + pathTop.LineTo(Width, HeaderHeight); + pathTop.LineTo(Width, HeaderHeight - 19); + pathTop.LineTo(Width / 2 + 7, HeaderHeight - 23); + pathTop.LineTo(Width / 2 + 13, HeaderHeight - 7); + pathTop.LineTo(0, HeaderHeight - 19); + pathTop.Close(); + c.DrawPath(pathTop, new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = DisplayStyle.SecondaryColor, + ImageFilter = SKImageFilter.CreateDropShadow(-5, -5, 0, 0, DisplayStyle.AccentColor.WithAlpha(75)) + }); + + c.DrawRect(new SKRect(0, HeaderHeight, Width, HeaderHeight + AdditionalSize), new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Color = DisplayStyle.PrimaryColor.WithAlpha(200) // default background is black, so i'm kinda lowering the brightness here and that's what i want + }); + } + } +} diff --git a/FModel/Creator/Bundles/Reward.cs b/FModel/Creator/Bundles/Reward.cs index ab3e2d22..be560c8b 100644 --- a/FModel/Creator/Bundles/Reward.cs +++ b/FModel/Creator/Bundles/Reward.cs @@ -1,6 +1,7 @@ using FModel.Creator.Bases; using PakReader.Pak; using PakReader.Parsers.Class; +using PakReader.Parsers.Objects; using PakReader.Parsers.PropertyTagData; using SkiaSharp; using System; @@ -11,6 +12,7 @@ namespace FModel.Creator.Bundles { public int RewardQuantity; public SKBitmap RewardIcon; + public BaseIcon TheReward; public string RewardFillColor; public string RewardBorderColor; public bool IsCountShifted; @@ -19,6 +21,7 @@ namespace FModel.Creator.Bundles { RewardQuantity = 0; RewardIcon = null; + TheReward = null; RewardFillColor = ""; RewardBorderColor = ""; IsCountShifted = false; @@ -39,7 +42,8 @@ namespace FModel.Creator.Bundles { if (p.GetExport() is UObject banner) { - RewardIcon = new BaseIcon(banner, $"{parts[1]}.uasset", false).IconImage.Resize(64, 64); + TheReward = new BaseIcon(banner, $"{parts[1]}.uasset", false); + RewardIcon = TheReward.IconImage.Resize(64, 64); } } } @@ -47,6 +51,21 @@ namespace FModel.Creator.Bundles } else GetReward(assetName); } + public Reward(IntProperty quantity, FSoftObjectPath itemFullPath) + { + RewardQuantity = quantity.Value; + PakPackage p = Utils.GetPropertyPakPackage(itemFullPath.AssetPathName.String); + if (p.HasExport() && !p.Equals(default)) + { + var d = p.GetExport(); + if (d != null) + { + int i = itemFullPath.AssetPathName.String.LastIndexOf('/'); + TheReward = new BaseIcon(d, itemFullPath.AssetPathName.String[(i > 0 ? i : 0)..] + ".uasset", false); + RewardIcon = TheReward.IconImage.Resize(80, 80); + } + } + } public Reward(IntProperty quantity, SoftObjectProperty itemDefinition) : this() { @@ -83,7 +102,8 @@ namespace FModel.Creator.Bundles break; default: IsCountShifted = false; - RewardIcon = new BaseIcon(d, itemDefinition.Value.AssetPathName.String.Substring(s1, s2) + ".uasset", false).IconImage.Resize(64, 64); + TheReward = new BaseIcon(d, itemDefinition.Value.AssetPathName.String.Substring(s1, s2) + ".uasset", false); + RewardIcon = TheReward.IconImage.Resize(64, 64); break; } } @@ -123,7 +143,8 @@ namespace FModel.Creator.Bundles { int i = path.LastIndexOf('/'); IsCountShifted = false; - RewardIcon = new BaseIcon(d, path.Substring(i > 0 ? i : 0) + ".uasset", false).IconImage.Resize(64, 64); + TheReward = new BaseIcon(d, path[(i > 0 ? i : 0)..] + ".uasset", false); + RewardIcon = TheReward.IconImage.Resize(64, 64); } } break; diff --git a/FModel/Creator/Creator.cs b/FModel/Creator/Creator.cs index 0e4c1617..c744b84a 100644 --- a/FModel/Creator/Creator.cs +++ b/FModel/Creator/Creator.cs @@ -142,6 +142,18 @@ namespace FModel.Creator } return true; } + case "AthenaSeasonItemDefinition": + { + BaseSeason icon = new BaseSeason(exports[index], assetFolder); + using (var ret = new SKBitmap(icon.Width, icon.HeaderHeight + icon.AdditionalSize, SKColorType.Rgba8888, SKAlphaType.Opaque)) + using (var c = new SKCanvas(ret)) + { + icon.Draw(c); + + ImageBoxVm.imageBoxViewModel.Set(ret, assetName); + } + return true; + } case "FortMtxOfferData": { BaseOffer icon = new BaseOffer(exports[index]); diff --git a/FModel/Windows/Launcher/FLauncher.xaml b/FModel/Windows/Launcher/FLauncher.xaml index 2d68f9ae..d6edddd3 100644 --- a/FModel/Windows/Launcher/FLauncher.xaml +++ b/FModel/Windows/Launcher/FLauncher.xaml @@ -64,7 +64,7 @@ HorizontalAlignment="Left" VerticalAlignment="Top"/> -