From 263c213dcc86b69cc0f3eed3149e28407f8485c4 Mon Sep 17 00:00:00 2001 From: 4sval Date: Tue, 2 Aug 2022 18:43:48 +0200 Subject: [PATCH] rip fonts --- CUE4Parse | 2 +- FModel/App.xaml.cs | 6 +- FModel/Creator/Bases/MV/BaseFighter.cs | 46 ++- .../Creator/Bases/MV/BaseMultiVersusIcon.cs | 98 ------ FModel/Creator/Bases/MV/BasePandaIcon.cs | 330 ++++++++++++++++++ FModel/Creator/Bases/MV/BasePerkGroup.cs | 45 +++ FModel/Creator/CreatorPackage.cs | 7 +- FModel/Creator/Typefaces.cs | 26 +- FModel/Creator/Utils.cs | 8 +- FModel/Enums.cs | 4 +- FModel/Settings/UserSettings.cs | 15 +- FModel/ViewModels/GameSelectorViewModel.cs | 1 - .../Converters/StringToGameConverter.cs | 2 +- 13 files changed, 440 insertions(+), 150 deletions(-) delete mode 100644 FModel/Creator/Bases/MV/BaseMultiVersusIcon.cs create mode 100644 FModel/Creator/Bases/MV/BasePandaIcon.cs create mode 100644 FModel/Creator/Bases/MV/BasePerkGroup.cs diff --git a/CUE4Parse b/CUE4Parse index 403599b4..061ad8f5 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 403599b4939e81cd7b4f3d3b201cf1018e02ece0 +Subproject commit 061ad8f578b7493b892d6391c4901dd05ca43a16 diff --git a/FModel/App.xaml.cs b/FModel/App.xaml.cs index e991c0ad..b09146f7 100644 --- a/FModel/App.xaml.cs +++ b/FModel/App.xaml.cs @@ -2,9 +2,9 @@ using Microsoft.Win32; using Serilog; using System; +using System.Globalization; using System.IO; using System.Runtime.InteropServices; -using System.Threading; using System.Windows; using System.Windows.Threading; using FModel.Framework; @@ -96,7 +96,7 @@ public partial class App Log.Information("Version {Version}", Constants.APP_VERSION); Log.Information("{OS}", GetOperatingSystemProductName()); Log.Information("{RuntimeVer}", RuntimeInformation.FrameworkDescription); - Log.Information("Culture {SysLang}", Thread.CurrentThread.CurrentUICulture); + Log.Information("Culture {SysLang}", CultureInfo.CurrentCulture); } private void AppExit(object sender, ExitEventArgs e) @@ -162,4 +162,4 @@ public partial class App return rk.GetValue(name, null) as string; return string.Empty; } -} \ No newline at end of file +} diff --git a/FModel/Creator/Bases/MV/BaseFighter.cs b/FModel/Creator/Bases/MV/BaseFighter.cs index fc5da665..4d8128a3 100644 --- a/FModel/Creator/Bases/MV/BaseFighter.cs +++ b/FModel/Creator/Bases/MV/BaseFighter.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Collections.Generic; +using System.ComponentModel; using CUE4Parse.UE4.Assets.Exports; using CUE4Parse.UE4.Assets.Exports.Engine; using CUE4Parse.UE4.Assets.Exports.Material; @@ -8,6 +9,7 @@ using CUE4Parse.UE4.Assets.Objects; using CUE4Parse.UE4.Objects.Core.i18N; using CUE4Parse.UE4.Objects.Core.Math; using CUE4Parse.UE4.Objects.UObject; +using FModel.Extensions; using SkiaSharp; namespace FModel.Creator.Bases.MV; @@ -31,15 +33,17 @@ public class BaseFighter : UCreator public BaseFighter(UObject uObject, EIconStyle style) : base(uObject, style) { Width = 1024; - DisplayNamePaint.TextAlign = SKTextAlign.Left; DisplayNamePaint.TextSize = 100; + DisplayNamePaint.TextAlign = SKTextAlign.Left; + DisplayNamePaint.Typeface = Utils.Typefaces.TandemDisplayName; DescriptionPaint.TextSize = 25; - DefaultPreview = Utils.GetBitmap("MultiVersus/Content/Panda_Main/UI/PreMatch/Images/DiamondPortraits/0010_Random.0010_Random"); + DescriptionPaint.Typeface = Utils.Typefaces.TandemGenDescription; + DefaultPreview = Utils.GetBitmap("/Game/Panda_Main/UI/PreMatch/Images/DiamondPortraits/0010_Random.0010_Random"); - _pattern = Utils.GetBitmap("MultiVersus/Content/Panda_Main/UI/Assets/UI_Textures/halftone_jagged.halftone_jagged"); - _perk = Utils.GetBitmap("MultiVersus/Content/Panda_Main/UI/Assets/Icons/ui_icons_perks.ui_icons_perks"); - _emote = Utils.GetBitmap("MultiVersus/Content/Panda_Main/UI/Assets/Icons/ui_icons_emote.ui_icons_emote"); - _skin = Utils.GetBitmap("MultiVersus/Content/Panda_Main/UI/Assets/Icons/ui_icons_skins.ui_icons_skins"); + _pattern = Utils.GetBitmap("/Game/Panda_Main/UI/Assets/UI_Textures/halftone_jagged.halftone_jagged"); + _perk = Utils.GetBitmap("/Game/Panda_Main/UI/Assets/Icons/ui_icons_perks.ui_icons_perks"); + _emote = Utils.GetBitmap("/Game/Panda_Main/UI/Assets/Icons/ui_icons_emote.ui_icons_emote"); + _skin = Utils.GetBitmap("/Game/Panda_Main/UI/Assets/Icons/ui_icons_skins.ui_icons_skins"); _fighterType.Item2 = new List(); _recommendedPerks = new List(); _availableTaunts = new List(); @@ -66,7 +70,7 @@ public class BaseFighter : UCreator DisplayName = displayName.Text; GetFighterClassInfo(Object.GetOrDefault("Class", EFighterClass.Support)); - _fighterType.Item2.Add(GetFighterType(Object.GetOrDefault("Type", EFighterType.Horizontal))); + _fighterType.Item2.Add(Utils.GetLocalizedResource(Object.GetOrDefault("Type", EFighterType.Horizontal))); if (Object.TryGetValue(out FText property, "Property")) _fighterType.Item2.Add(property.Text); @@ -126,7 +130,7 @@ public class BaseFighter : UCreator private void GetFighterClassInfo(EFighterClass clas) { - if (!Utils.TryLoadObject("MultiVersus/Content/Panda_Main/UI/In-Game/Data/UICharacterClassInfo_Datatable.UICharacterClassInfo_Datatable", out UDataTable dataTable)) + if (!Utils.TryLoadObject("/Game/Panda_Main/UI/In-Game/Data/UICharacterClassInfo_Datatable.UICharacterClassInfo_Datatable", out UDataTable dataTable)) return; var row = dataTable.RowMap.ElementAt((int) clas).Value; @@ -138,17 +142,6 @@ public class BaseFighter : UCreator _fighterType.Item2.Add(displayName.Text); } - private string GetFighterType(EFighterType typ) - { - return typ switch - { - EFighterType.Horizontal => Utils.GetLocalizedResource("", "97A60DD54AA23D4B93D5B891F729BF5C", "Horizontal"), - EFighterType.Vertical => Utils.GetLocalizedResource("", "2C55443D47164019BE73A5ABDC670F36", "Vertical"), - EFighterType.Hybrid => Utils.GetLocalizedResource("", "B980C82D40FF37FD359C74A339CE1B3A", "Hybrid"), - _ => typ.ToString() - }; - } - private new void DrawBackground(SKCanvas c) { c.DrawRect(new SKRect(0, 0, Width, Height), @@ -167,16 +160,16 @@ public class BaseFighter : UCreator }); } - c.DrawBitmap(_pattern, new SKRect(0, 256, Width, 512), new SKPaint + c.DrawBitmap(_pattern, new SKRect(0, Height / 2, Width, Height), new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.High, BlendMode = SKBlendMode.SoftLight }); var path = new SKPath { FillType = SKPathFillType.EvenOdd }; - path.MoveTo(0, 512); - path.LineTo(0, 492); - path.LineTo(Width, 452); - path.LineTo(Width, 512); + path.MoveTo(0, Height); + path.LineTo(0, Height - 20); + path.LineTo(Width, Height - 60); + path.LineTo(Width, Height); path.Close(); c.DrawPath(path, new SKPaint { @@ -283,7 +276,12 @@ public enum EFighterClass : byte public enum EFighterType : byte { + [Description("B980C82D40FF37FD359C74A339CE1B3A")] Hybrid = 2, + + [Description("2C55443D47164019BE73A5ABDC670F36")] Vertical = 1, + + [Description("97A60DD54AA23D4B93D5B891F729BF5C")] Horizontal = 0 // Default } diff --git a/FModel/Creator/Bases/MV/BaseMultiVersusIcon.cs b/FModel/Creator/Bases/MV/BaseMultiVersusIcon.cs deleted file mode 100644 index 85cc1117..00000000 --- a/FModel/Creator/Bases/MV/BaseMultiVersusIcon.cs +++ /dev/null @@ -1,98 +0,0 @@ -using CUE4Parse.UE4.Assets.Exports; -using CUE4Parse.UE4.Objects.Core.i18N; -using CUE4Parse.UE4.Objects.Core.Math; -using CUE4Parse.UE4.Objects.UObject; -using FModel.Creator.Bases.FN; -using SkiaSharp; - -namespace FModel.Creator.Bases.MV; - -public class BaseMultiVersusIcon : BaseIcon -{ - public BaseMultiVersusIcon(UObject uObject, EIconStyle style) : base(uObject, style) - { - DefaultPreview = Utils.GetBitmap("MultiVersus/Content/Panda_Main/UI/PreMatch/Images/DiamondPortraits/0010_Random.0010_Random"); - } - - public override void ParseForInfo() - { - var rarity = Object.GetOrDefault("Rarity", new FName("ERewardRarity::None")); - Background = GetRarityBackground(rarity.ToString()); - Border = new[] { GetRarityBorder(rarity.ToString()) }; - - if (Object.TryGetValue(out FSoftObjectPath rewardThumbnail, "RewardThumbnail", "DisplayTextureRef")) - Preview = Utils.GetBitmap(rewardThumbnail); - else if (Object.TryGetValue(out FPackageIndex icon, "Icon")) - Preview = Utils.GetBitmap(icon); - - if (Object.TryGetValue(out FText displayName, "DisplayName")) - DisplayName = displayName.Text; - if (Object.TryGetValue(out FText description, "Description")) - Description = Utils.RemoveHtmlTags(description.Text); - - if (Object.TryGetValue(out int xpValue, "XPValue")) - DisplayName += $" (+{xpValue})"; - } - - // public override SKBitmap[] Draw() - // { - // // dedicated design here, use : UCreator - // throw new System.NotImplementedException(); - // } - - private SKColor[] GetRarityBackground(string rarity) - { - switch (rarity.Split("::")[1]) // the colors here are the base color and brighter color that the game uses for rarities from the "Rarity to Color" blueprint function - { - case "Common": - return new[] - { - SKColor.Parse(new FLinearColor(0.068478f, 0.651406f, 0.016807f, 1.000000f).Hex), - SKColor.Parse(new FLinearColor(0.081422f, 1.000000f, 0.000000f, 1.000000f).Hex) - }; - case "Rare": - return new[] - { - SKColor.Parse(new FLinearColor(0.035911f, 0.394246f, 0.900000f, 1.000000f).Hex), - SKColor.Parse(new FLinearColor(0.033333f, 0.434207f, 1.000000f, 1.000000f).Hex) - }; - case "Epic": - return new[] - { - SKColor.Parse(new FLinearColor(0.530391f, 0.060502f, 0.900000f, 1.000000f).Hex), - SKColor.Parse(new FLinearColor(0.579907f, 0.045833f, 1.000000f, 1.000000f).Hex) - }; - case "Legendary": - return new[] - { - SKColor.Parse(new FLinearColor(1.000000f, 0.223228f, 0.002428f, 1.000000f).Hex), - SKColor.Parse(new FLinearColor(1.000000f, 0.479320f, 0.030713f, 1.000000f).Hex) - }; - case "None": - default: - return new[] - { - SKColor.Parse(new FLinearColor(0.194618f, 0.651406f, 0.630757f, 1.000000f).Hex), - SKColor.Parse(new FLinearColor(0.273627f, 0.955208f, 0.914839f, 1.000000f).Hex) - }; - } - } - - private SKColor GetRarityBorder(string rarity) - { - switch (rarity.Split("::")[1]) // the colors here are the desaturated versions of the rarity colors - { - case "Common": - return SKColor.Parse(new FLinearColor(0.172713f, 0.651406f, 0.130281f, 1.000000f).Hex); - case "Rare": - return SKColor.Parse(new FLinearColor(0.198220f, 0.527026f, 0.991102f, 1.000000f).Hex); - case "Epic": - return SKColor.Parse(new FLinearColor(0.642017f, 0.198220f, 0.991102f, 1.000000f).Hex); - case "Legendary": - return SKColor.Parse(new FLinearColor(1.000000f, 0.328434f, 0.200000f, 1.000000f).Hex); - case "None": - default: - return SKColor.Parse(new FLinearColor(0.308843f, 0.571125f, 0.557810f, 1.000000f).Hex); - } - } -} diff --git a/FModel/Creator/Bases/MV/BasePandaIcon.cs b/FModel/Creator/Bases/MV/BasePandaIcon.cs new file mode 100644 index 00000000..14349cbe --- /dev/null +++ b/FModel/Creator/Bases/MV/BasePandaIcon.cs @@ -0,0 +1,330 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using CUE4Parse.UE4.Assets.Exports; +using CUE4Parse.UE4.Assets.Exports.Engine; +using CUE4Parse.UE4.Objects.Core.i18N; +using CUE4Parse.UE4.Objects.Core.Math; +using CUE4Parse.UE4.Objects.UObject; +using SkiaSharp; + +namespace FModel.Creator.Bases.MV; + +public class BasePandaIcon : UCreator +{ + private float _y_offset; + private ERewardRarity _rarity; + private string _type; + + private readonly List<(SKBitmap, string)> _pictos; + + public BasePandaIcon(UObject uObject, EIconStyle style) : base(uObject, style) + { + Width = 1024; + Margin = 30; + DisplayNamePaint.TextSize = 50; + DisplayNamePaint.TextAlign = SKTextAlign.Left; + DisplayNamePaint.Color = SKColor.Parse("#191C33"); + DescriptionPaint.TextSize = 25; + DefaultPreview = Utils.GetBitmap("/Game/Panda_Main/UI/PreMatch/Images/DiamondPortraits/0010_Random.0010_Random"); + + _y_offset = Height / 2 + DescriptionPaint.TextSize; + _pictos = new List<(SKBitmap, string)>(); + } + + public override void ParseForInfo() + { + _type = Object.ExportType; + var t = _type switch + { + // "CharacterData" => , + "StatTrackingBundleData" => EItemType.Badge, + "AnnouncerPackData" => EItemType.Announcer, + "CharacterGiftData" => EItemType.ExperiencePoints, + "ProfileIconData" => EItemType.ProfileIcon, + "RingOutVfxData" => EItemType.Ringout, + "BannerData" => EItemType.Banner, + "EmoteData" => EItemType.Sticker, + "TauntData" => EItemType.Emote, + "SkinData" => EItemType.Variant, + "PerkData" => EItemType.Perk, + _ => EItemType.Unknown + }; + + _rarity = Object.GetOrDefault("Rarity", ERewardRarity.None); + Background = GetRarityBackground(_rarity); + + if (Object.TryGetValue(out FSoftObjectPath rewardThumbnail, "RewardThumbnail", "DisplayTextureRef", "Texture")) + Preview = Utils.GetBitmap(rewardThumbnail); + else if (Object.TryGetValue(out FPackageIndex icon, "Icon")) + Preview = Utils.GetBitmap(icon); + + if (Object.TryGetValue(out FText displayName, "DisplayName")) + DisplayName = displayName.Text; + if (Object.TryGetValue(out FText description, "Description")) + Description = Utils.RemoveHtmlTags(description.Text); + + _pictos.Add(( + Utils.GetBitmap("/Game/Panda_Main/UI/Assets/Icons/ui_icons_unlocked.ui_icons_unlocked"), + Utils.GetLocalizedResource(Object.GetOrDefault("UnlockLocation", EUnlockLocation.None)))); + if (Object.TryGetValue(out string slug, "Slug")) + { + t = _type switch + { + "HydraSyncedDataAsset" when slug == "gold" => EItemType.Gold, + "HydraSyncedDataAsset" when slug == "match_toasts" => EItemType.Toast, + _ => t + }; + _pictos.Add((Utils.GetBitmap("/Game/Panda_Main/UI/Assets/Icons/ui_icons_link.ui_icons_link"), slug)); + } + + if (Object.TryGetValue(out int xpValue, "XPValue")) + DisplayName += $" (+{xpValue})"; + + if (Utils.TryLoadObject("/Game/Panda_Main/UI/Prototype/Foundation/Types/DT_EconomyGlossary.DT_EconomyGlossary", out UDataTable dataTable)) + { + if (t != EItemType.Unknown && + dataTable.RowMap.ElementAt((int) t).Value.TryGetValue(out FText name, "Name_14_7F75AD6047CBDEA7B252B1BD76EF84B9")) + _type = name.Text; + } + } + + public override SKBitmap[] Draw() + { + var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(ret); + + DrawBackground(c); + DrawPreview(c); + DrawDisplayName(c); + DrawDescription(c); + DrawPictos(c); + + return new[] { ret }; + } + + private SKColor[] GetRarityBackground(ERewardRarity rarity) + { + return rarity switch // the colors here are the base color and brighter color that the game uses for rarities from the "Rarity to Color" blueprint function + { + ERewardRarity.Common => new[] + { + SKColor.Parse(new FLinearColor(0.068478f, 0.651406f, 0.016807f, 1.000000f).Hex), + SKColor.Parse(new FLinearColor(0.081422f, 1.000000f, 0.000000f, 1.000000f).Hex) + }, + ERewardRarity.Rare => new[] + { + SKColor.Parse(new FLinearColor(0.035911f, 0.394246f, 0.900000f, 1.000000f).Hex), + SKColor.Parse(new FLinearColor(0.033333f, 0.434207f, 1.000000f, 1.000000f).Hex) + }, + ERewardRarity.Epic => new[] + { + SKColor.Parse(new FLinearColor(0.530391f, 0.060502f, 0.900000f, 1.000000f).Hex), + SKColor.Parse(new FLinearColor(0.579907f, 0.045833f, 1.000000f, 1.000000f).Hex) + }, + ERewardRarity.Legendary => new[] + { + SKColor.Parse(new FLinearColor(1.000000f, 0.223228f, 0.002428f, 1.000000f).Hex), + SKColor.Parse(new FLinearColor(1.000000f, 0.479320f, 0.030713f, 1.000000f).Hex) + }, + _ => new[] + { + SKColor.Parse(new FLinearColor(0.194618f, 0.651406f, 0.630757f, 1.000000f).Hex), + SKColor.Parse(new FLinearColor(0.273627f, 0.955208f, 0.914839f, 1.000000f).Hex) + } + }; + } + + private new void DrawBackground(SKCanvas c) + { + c.DrawRect(new SKRect(0, 0, Width, Height), + new SKPaint + { + IsAntialias = true, FilterQuality = SKFilterQuality.High, Color = SKColor.Parse("#F3FCF0") + }); + + var has_tr = _rarity != ERewardRarity.None; + var tr = Utils.GetLocalizedResource(_rarity); + var tr_paint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + TextAlign = SKTextAlign.Right, + TextSize = 35, + Color = SKColors.White, + Typeface = Utils.Typefaces.DisplayName + }; + + var path = new SKPath { FillType = SKPathFillType.EvenOdd }; + path.MoveTo(0, Height); + path.LineTo(14, Height); + path.LineTo(20, 20); + if (has_tr) + { + const int margin = 15; + var width = tr_paint.MeasureText(tr); + path.LineTo(Width - width - margin * 2, 15); + path.LineTo(Width - width - margin * 2.5f, 60); + path.LineTo(Width, 55); + } + else + { + path.LineTo(Width, 14); + } + path.LineTo(Width, 0); + path.LineTo(0, 0); + path.LineTo(0, Height); + path.Close(); + c.DrawPath(path, new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + Shader = SKShader.CreateLinearGradient( + new SKPoint(Width / 2, Height), new SKPoint(Width, Height / 4), Background, SKShaderTileMode.Clamp) + }); + + if (has_tr) + { + var x = Width - 20f; + foreach (var a in tr.Select(character => character.ToString()).Reverse()) + { + c.DrawText(a, x, 40, tr_paint); + x -= tr_paint.MeasureText(a) - 2; + } + } + } + + private new void DrawPreview(SKCanvas c) + { + const int size = 384; + var y = Height - size - Margin * 2; + c.DrawBitmap(Preview ?? DefaultPreview, new SKRect(Margin, y, size + Margin, y + size), ImagePaint); + } + + private new void DrawDisplayName(SKCanvas c) + { + if (string.IsNullOrWhiteSpace(DisplayName)) + return; + + var x = 450f; + var y = Height / 2 - DisplayNamePaint.TextSize / 4; + while (DisplayNamePaint.MeasureText(DisplayName) > Width - x) + { + DisplayNamePaint.TextSize -= 1; + } + + foreach (var a in DisplayName.Select(character => character.ToString())) + { + c.DrawText(a, x, y, DisplayNamePaint); + x += DisplayNamePaint.MeasureText(a) - 4; + } + } + + private new void DrawDescription(SKCanvas c) + { + const int x = 450; + DescriptionPaint.Color = Background[0]; + c.DrawText(_type.ToUpper(), x, 170, DescriptionPaint); + + if (string.IsNullOrWhiteSpace(Description)) return; + + DescriptionPaint.Color = SKColor.Parse("#191C33"); + Utils.DrawMultilineText(c, Description, Width - x, Margin, SKTextAlign.Left, + new SKRect(x, _y_offset, Width - Margin, Height - Margin), DescriptionPaint, out _y_offset); + } + + private void DrawPictos(SKCanvas c) + { + if (_pictos.Count < 1) return; + + const float x = 450f; + const int size = 24; + var color = SKColor.Parse("#495B6E"); + var paint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High, + TextSize = 27, + Color = color, + Typeface = Utils.Typefaces.Default + }; + + ImagePaint.ColorFilter = SKColorFilter.CreateBlendMode(color, SKBlendMode.SrcIn); + + foreach (var picto in _pictos) + { + c.DrawBitmap(picto.Item1, new SKRect(x, _y_offset + 10, x + size, _y_offset + 10 + size), ImagePaint); + c.DrawText(picto.Item2, x + size + 10, _y_offset + size + 6, paint); + _y_offset += size + 5; + } + } +} + +public enum ERewardRarity : byte +{ + [Description("0D4B15CE4FB6F2BC5E5F5FAA9E8B376C")] + None = 0, // Default + + [Description("0FCDEF47485E2C3D0D477988C481D8E3")] + Common = 1, + + [Description("18241CA7441AE16AAFB6EFAB499FF981")] + Rare = 2, + + [Description("D999D9CB4754D1078BF9A1B34A231005")] + Epic = 3, + + [Description("705AE967407D6EF8870E988A08C6900E")] + Legendary = 4 +} + +public enum EUnlockLocation : byte +{ + [Description("0D4B15CE4FB6F2BC5E5F5FAA9E8B376C")] + None = 0, // Default + + [Description("0AFBCE5F41D930D6E9B5138C8EBCFE87")] + Shop = 1, + + [Description("062F178B4EE74502C9AD9D878F3D7CEA")] + AccountLevel = 2, + + [Description("1AE7A5DF477B2B5F4B3CCC8DCD732884")] + CharacterMastery = 3, + + [Description("0B37731C49DC9AE1EAC566950C1A329D")] + Battlepass = 4, + + [Description("16F160084187479E5D471786190AE5B7")] + CharacterAffinity = 5, + + [Description("E5C1E35C406C585E83B5D18A817FA0B4")] + GuildBoss = 6, + + [Description("4A89F5DD432113750EF52D8B58977DCE")] + Tutorial = 7 +} + +public enum EItemType +{ + Unknown = -1, + Announcer, + Badge, + Banner, + BattlePassPoints, + Emote, + ExperiencePoints, + Gleamium, + Gold, + MasteryLevel, + Mission, + Perk, + PlayerLevel, + ProfileIcon, + Rested, + Ringout, + SignaturePerk, + Sticker, + Toast, + Variant +} diff --git a/FModel/Creator/Bases/MV/BasePerkGroup.cs b/FModel/Creator/Bases/MV/BasePerkGroup.cs new file mode 100644 index 00000000..e580c4cb --- /dev/null +++ b/FModel/Creator/Bases/MV/BasePerkGroup.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using CUE4Parse.UE4.Assets.Exports; +using CUE4Parse.UE4.Assets.Objects; +using CUE4Parse.UE4.Objects.UObject; +using SkiaSharp; + +namespace FModel.Creator.Bases.MV; + +public class BasePerkGroup : UCreator +{ + private readonly List _perks; + + public BasePerkGroup(UObject uObject, EIconStyle style) : base(uObject, style) + { + _perks = new List(); + } + + public override void ParseForInfo() + { + if (Object.TryGetValue(out UScriptSet perks, "Perks")) // PORCO DIO WB USE ARRAYS!!!!!! + { + foreach (var perk in perks.Properties) + { + if (perk.GenericValue is not FPackageIndex packageIndex || + !Utils.TryGetPackageIndexExport(packageIndex, out UObject export)) + continue; + + var icon = new BasePandaIcon(export, Style); + icon.ParseForInfo(); + _perks.Add(icon); + } + } + } + + public override SKBitmap[] Draw() + { + var ret = new SKBitmap[_perks.Count]; + for (var i = 0; i < ret.Length; i++) + { + ret[i] = _perks[i].Draw()[0]; + } + + return ret; + } +} diff --git a/FModel/Creator/CreatorPackage.cs b/FModel/Creator/CreatorPackage.cs index 678dee48..84e6fd4f 100644 --- a/FModel/Creator/CreatorPackage.cs +++ b/FModel/Creator/CreatorPackage.cs @@ -174,15 +174,16 @@ public class CreatorPackage : IDisposable case "PlaylistUserOptionCollisionProfileEnum": creator = new BaseUserControl(_object, _style); return true; - // Multiversus + // PandaGame case "CharacterData": creator = new BaseFighter(_object, _style); return true; case "PerkGroup": - creator = null; + creator = new BasePerkGroup(_object, _style); return true; case "StatTrackingBundleData": case "HydraSyncedDataAsset": + case "AnnouncerPackData": case "CharacterGiftData": case "ProfileIconData": case "RingOutVfxData": @@ -191,7 +192,7 @@ public class CreatorPackage : IDisposable case "TauntData": case "SkinData": case "PerkData": - creator = new BaseMultiVersusIcon(_object, _style); + creator = new BasePandaIcon(_object, _style); return true; // Battle Breakers case "WExpGenericAccountItemDefinition": diff --git a/FModel/Creator/Typefaces.cs b/FModel/Creator/Typefaces.cs index ef7afd25..bf5268c0 100644 --- a/FModel/Creator/Typefaces.cs +++ b/FModel/Creator/Typefaces.cs @@ -41,11 +41,12 @@ public class Typefaces private const string _BURBANK_SMALL_BLACK = "burbanksmall-black"; private const string _BURBANK_SMALL_BOLD = "burbanksmall-bold"; - // Multiversus - private const string _MULTIVERSUS_BASE_PATH = "/Game/Panda_Main/UI/Fonts/"; + // PandaGame + private const string _PANDAGAME_BASE_PATH = "/Game/Panda_Main/UI/Fonts/"; private const string _NORMS_STD_CONDENSED_BLACK = "Norms/TT_Norms_Std_Condensed_Black"; - private const string _XIANGHEHEI_SC_PRO_BLACK = "XiangHeHei_SC/MXiangHeHeiSCPro-Black"; + private const string _NORMS_PRO_BLACK_ITALIC = "Norms/TT_Norms_Pro_Black_Italic"; private const string _NORMS_STD_CONDENSED_BOLD = "Norms/TT_Norms_Std_Condensed_Bold"; + private const string _XIANGHEHEI_SC_PRO_BLACK = "XiangHeHei_SC/MXiangHeHeiSCPro-Black"; private const string _XIANGHEHEI_SC_PRO_HEAVY = "XiangHeHei_SC/MXiangHeHeiSCPro-Heavy"; // Spellbreak @@ -200,14 +201,27 @@ public class Typefaces Description = OnTheFly(_SPELLBREAK_BASE_PATH + _MONTSERRAT_SEMIBOLD + _EXT); break; } - case FGame.Multiversus: + case FGame.PandaGame: { - DisplayName = OnTheFly(_MULTIVERSUS_BASE_PATH + language switch + DisplayName = OnTheFly(_PANDAGAME_BASE_PATH + language switch + { + ELanguage.Chinese => _XIANGHEHEI_SC_PRO_HEAVY, + _ => _NORMS_PRO_BLACK_ITALIC + } + _EXT); + + Description = OnTheFly(_PANDAGAME_BASE_PATH + language switch + { + ELanguage.Chinese => _XIANGHEHEI_SC_PRO_BLACK, + _ => _NORMS_STD_CONDENSED_BOLD + } + _EXT); + + TandemDisplayName = OnTheFly(_PANDAGAME_BASE_PATH + language switch { ELanguage.Chinese => _XIANGHEHEI_SC_PRO_BLACK, _ => _NORMS_STD_CONDENSED_BLACK } + _EXT); - Description = OnTheFly(_MULTIVERSUS_BASE_PATH + language switch + + TandemGenDescription = OnTheFly(_PANDAGAME_BASE_PATH + language switch { ELanguage.Chinese => _XIANGHEHEI_SC_PRO_HEAVY, _ => _NORMS_STD_CONDENSED_BOLD diff --git a/FModel/Creator/Utils.cs b/FModel/Creator/Utils.cs index 216d7a02..8035f74d 100644 --- a/FModel/Creator/Utils.cs +++ b/FModel/Creator/Utils.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Text; @@ -9,9 +10,9 @@ using CUE4Parse.UE4.Assets.Exports.Material; using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Objects.UObject; using CUE4Parse.UE4.Versions; -using CUE4Parse.Utils; using CUE4Parse_Conversion.Textures; using FModel.Framework; +using FModel.Extensions; using FModel.Services; using FModel.Settings; using FModel.ViewModels; @@ -183,6 +184,11 @@ public static class Utils { return _applicationView.CUE4Parse.Provider.GetLocalizedString(@namespace, key, defaultValue); } + public static string GetLocalizedResource(T @enum) where T : Enum + { + var resource = _applicationView.CUE4Parse.Provider.GetLocalizedString("", @enum.GetDescription(), @enum.ToString()); + return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(resource.ToLower()); + } public static string GetFullPath(string partialPath) { diff --git a/FModel/Enums.cs b/FModel/Enums.cs index d40cf8a8..1b678fc1 100644 --- a/FModel/Enums.cs +++ b/FModel/Enums.cs @@ -92,8 +92,8 @@ public enum FGame Gameface, [Description("Sea of Thieves")] Athena, - [Description("Multiversus")] - Multiversus + [Description("That Banned Panda")] + PandaGame } public enum ELoadingMode diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index b84b34e5..82d238b1 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -287,7 +287,7 @@ namespace FModel.Settings {FGame.PortalWars, Constants._NO_PRESET_TRIGGER}, {FGame.Gameface, Constants._NO_PRESET_TRIGGER}, {FGame.Athena, Constants._NO_PRESET_TRIGGER}, - {FGame.Multiversus, Constants._NO_PRESET_TRIGGER} + {FGame.PandaGame, Constants._NO_PRESET_TRIGGER} }; public IDictionary Presets { @@ -316,7 +316,7 @@ namespace FModel.Settings {FGame.PortalWars, EGame.GAME_UE4_LATEST}, {FGame.Gameface, EGame.GAME_GTATheTrilogyDefinitiveEdition}, {FGame.Athena, EGame.GAME_SeaOfThieves}, - {FGame.Multiversus, EGame.GAME_UE4_26} + {FGame.PandaGame, EGame.GAME_UE4_26} }; public IDictionary OverridedGame { @@ -345,7 +345,7 @@ namespace FModel.Settings {FGame.PortalWars, null}, {FGame.Gameface, null}, {FGame.Athena, null}, - {FGame.Multiversus, null} + {FGame.PandaGame, null} }; public IDictionary> OverridedCustomVersions { @@ -374,7 +374,7 @@ namespace FModel.Settings {FGame.PortalWars, null}, {FGame.Gameface, null}, {FGame.Athena, null}, - {FGame.Multiversus, null} + {FGame.PandaGame, null} }; public IDictionary> OverridedOptions { @@ -439,12 +439,7 @@ namespace FModel.Settings new("Strings", "g3/Content/Localization/") } }, - { - FGame.Multiversus, new List() - { - new("Characters", "MultiVersus/Content/Panda_Main/Characters/") - } - }, + {FGame.PandaGame, new List()}, {FGame.StateOfDecay2, new List()}, {FGame.Prospect, new List()}, {FGame.Indiana, new List()}, diff --git a/FModel/ViewModels/GameSelectorViewModel.cs b/FModel/ViewModels/GameSelectorViewModel.cs index 966c14d1..62272ffb 100644 --- a/FModel/ViewModels/GameSelectorViewModel.cs +++ b/FModel/ViewModels/GameSelectorViewModel.cs @@ -109,7 +109,6 @@ public class GameSelectorViewModel : ViewModel yield return GetUnrealEngineGame("Snoek", "\\StateOfDecay2\\Content\\Paks"); yield return GetUnrealEngineGame("a99769d95d8f400baad1f67ab5dfe508", "\\Core\\Platform\\Content\\Paks"); yield return GetUnrealEngineGame("Nebula", "\\BendGame\\Content"); - yield return GetUnrealEngineGame("711c5e95dc094ca58e5f16bd48e751d6", "\\MultiVersus\\Content"); yield return GetRiotGame("VALORANT", "ShooterGame\\Content\\Paks"); yield return new DetectedGame { GameName = "Valorant [LIVE]", GameDirectory = Constants._VAL_LIVE_TRIGGER }; yield return GetMojangGame("MinecraftDungeons", "\\dungeons\\dungeons\\Dungeons\\Content\\Paks"); diff --git a/FModel/Views/Resources/Converters/StringToGameConverter.cs b/FModel/Views/Resources/Converters/StringToGameConverter.cs index bc856ef6..1fd44fe0 100644 --- a/FModel/Views/Resources/Converters/StringToGameConverter.cs +++ b/FModel/Views/Resources/Converters/StringToGameConverter.cs @@ -25,7 +25,7 @@ public class StringToGameConverter : IValueConverter "MinecraftDungeons" => "Minecraft Dungeons", "shoebill" => "Star Wars: Jedi Fallen Order", "a99769d95d8f400baad1f67ab5dfe508" => "Core", - "711c5e95dc094ca58e5f16bd48e751d6" => "MultiVersus", + "711c5e95dc094ca58e5f16bd48e751d6" => "That Banned Panda", 381210 => "Dead By Daylight", 578080 => "PLAYERUNKNOWN'S BATTLEGROUNDS", 677620 => "Splitgate",