From 554361bea5e11d1e4ad6196cb4ca3dffa1bb0962 Mon Sep 17 00:00:00 2001 From: GMatrixGames Date: Tue, 25 May 2021 14:37:11 -0400 Subject: [PATCH 01/68] Remove Party Royale landmarks from map viewer --- FModel/ViewModels/MapViewerViewModel.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/FModel/ViewModels/MapViewerViewModel.cs b/FModel/ViewModels/MapViewerViewModel.cs index dc57dde4..f121190a 100644 --- a/FModel/ViewModels/MapViewerViewModel.cs +++ b/FModel/ViewModels/MapViewerViewModel.cs @@ -198,14 +198,16 @@ await _threadWorkerView.Begin(_ => _landmarksBitmap = new SKBitmap(_mapBitmap.Width, _mapBitmap.Height, SKColorType.Rgba8888, SKAlphaType.Premul); using var cities = new SKCanvas(_citiesBitmap); using var landmarks = new SKCanvas(_landmarksBitmap); - if (Utils.TryLoadObject("FortniteGame/Content/Quests/QuestIndicatorData", out UObject indicatorData) && + if (Utils.TryLoadObject("FortniteGame/Content/Quests/QuestIndicatorData.QuestIndicatorData", out UObject indicatorData) && indicatorData.TryGetValue(out FStructFallback[] challengeMapPoiData, "ChallengeMapPoiData")) { foreach (var poiData in challengeMapPoiData) { if (!poiData.TryGetValue(out FSoftObjectPath discoveryQuest, "DiscoveryQuest") || !poiData.TryGetValue(out FText text, "Text") || string.IsNullOrEmpty(text.Text) || - !poiData.TryGetValue(out FVector worldLocation, "WorldLocation")) continue; + !poiData.TryGetValue(out FVector worldLocation, "WorldLocation") || + !poiData.TryGetValue(out FName discoverBackend, "DiscoverObjectiveBackendName") || + discoverBackend.Text.Contains("papaya", StringComparison.OrdinalIgnoreCase)) continue; var shaper = new CustomSKShaper(_imagePaint.Typeface); var shapedText = shaper.Shape(text.Text, _imagePaint); From d5e33f1224cbd193db13721f4a069f434c49bf20 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Thu, 27 May 2021 21:51:57 +0200 Subject: [PATCH 02/68] fixed jump to asset folder --- FModel/Framework/ViewModelCommand.cs | 2 +- FModel/ViewModels/Commands/GoToCommand.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/FModel/Framework/ViewModelCommand.cs b/FModel/Framework/ViewModelCommand.cs index 1730984e..4d064f2e 100644 --- a/FModel/Framework/ViewModelCommand.cs +++ b/FModel/Framework/ViewModelCommand.cs @@ -27,7 +27,7 @@ private set protected ViewModelCommand(TContextViewModel contextViewModel) { - ContextViewModel = contextViewModel ?? throw new ArgumentNullException(nameof(contextViewModel)); + ContextViewModel = contextViewModel /*?? throw new ArgumentNullException(nameof(contextViewModel))*/; } public sealed override void Execute(object parameter) diff --git a/FModel/ViewModels/Commands/GoToCommand.cs b/FModel/ViewModels/Commands/GoToCommand.cs index 13ec2c66..1b9845c3 100644 --- a/FModel/ViewModels/Commands/GoToCommand.cs +++ b/FModel/ViewModels/Commands/GoToCommand.cs @@ -32,7 +32,8 @@ public TreeItem JumpTo(string directory) { foreach (var folder in root) { - if (!folder.Header.Equals(folders[i])) continue; + if (!folder.Header.Equals(folders[i], i == 0 ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) + continue; folder.IsExpanded = true; // folder found = expand From bfe648f06ccc6ad6374947960ac1df8f955d8ee1 Mon Sep 17 00:00:00 2001 From: GMatrixGames Date: Sat, 29 May 2021 11:00:14 -0400 Subject: [PATCH 03/68] Battle Breakers multiple directory support --- CUE4Parse | 2 +- FModel/MainWindow.xaml.cs | 2 +- FModel/Settings/UserSettings.cs | 2 +- FModel/ViewModels/CUE4ParseViewModel.cs | 16 +++++++++++++--- .../Converters/StringToGameConverter.cs | 7 ++++--- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 70d41700..aca9f9ba 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 70d417009d729260486d905eb5d10f45c78cfec7 +Subproject commit aca9f9ba95dd74ea1694fb483e798043f58fc3e2 diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index 1c9b1554..639b9bea 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Linq; using System.Windows; diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index 06b36fe9..583ee28f 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -205,7 +205,7 @@ public int ImageMergerMargin {FGame.Dungeons, EGame.GAME_UE4_LATEST}, {FGame.WorldExplorers, EGame.GAME_UE4_LATEST}, {FGame.g3, EGame.GAME_UE4_22}, - {FGame.StateOfDecay2, EGame.GAME_UE4_LATEST}, + {FGame.StateOfDecay2, EGame.GAME_UE4_13}, {FGame.Prospect, EGame.GAME_UE4_LATEST}, {FGame.Indiana, EGame.GAME_UE4_LATEST}, {FGame.RogueCompany, EGame.GAME_UE4_LATEST}, diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 2e168471..f6d4bca3 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -82,8 +82,18 @@ public CUE4ParseViewModel(string gameDirectory) default: { Game = gameDirectory.SubstringBeforeLast("\\Content\\Paks").SubstringAfterLast("\\").ToEnum(FGame.Unknown); - Provider = new DefaultFileProvider(gameDirectory, SearchOption.TopDirectoryOnly, true, - UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]); + + if (Game == FGame.WorldExplorers) + { + Provider = new DefaultFileProvider(new DirectoryInfo(gameDirectory), new List {new(gameDirectory.SubstringBeforeLast('\\') + "\\EmbeddedPaks\\")}, + SearchOption.TopDirectoryOnly, true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]); + } + else + { + Provider = new DefaultFileProvider(gameDirectory, SearchOption.TopDirectoryOnly, true, + UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]); + } + break; } } @@ -202,7 +212,7 @@ await _threadWorkerView.Begin(cancellationToken => foreach (var file in GameDirectory.DirectoryFiles) { cancellationToken.ThrowIfCancellationRequested(); - if (!(Provider.MountedVfs.FirstOrDefault(x => x.Name == file.Name) is { } vfs)) + if (Provider.MountedVfs.FirstOrDefault(x => x.Name == file.Name) is not { } vfs) continue; file.IsEnabled = true; diff --git a/FModel/Views/Resources/Converters/StringToGameConverter.cs b/FModel/Views/Resources/Converters/StringToGameConverter.cs index e186d78b..c05033c9 100644 --- a/FModel/Views/Resources/Converters/StringToGameConverter.cs +++ b/FModel/Views/Resources/Converters/StringToGameConverter.cs @@ -12,14 +12,15 @@ public object Convert(object value, Type targetType, object parameter, CultureIn { return value switch { + "Newt" => "Spellbreak", "Fortnite" => "Fortnite", + "VALORANT" => "Valorant", "Pewee" => "Rogue Company", - "Rosemallow" => "The Outer Worlds", "Catnip" => "Borderlands 3", "AzaleaAlpha" => "The Cycle", + "Snoek" => "State of Decay 2", + "Rosemallow" => "The Outer Worlds", "WorldExplorersLive" => "Battle Breakers", - "Newt" => "Spellbreak", - "VALORANT" => "Valorant", "MinecraftDungeons" => "Minecraft Dungeons", "shoebill" => "Star Wars: Jedi Fallen Order", "a99769d95d8f400baad1f67ab5dfe508" => "Core", From 8349d2bb93e54c8cfb74e5b2ba997f6d2e732df9 Mon Sep 17 00:00:00 2001 From: Not Officer Date: Sat, 29 May 2021 23:46:29 +0200 Subject: [PATCH 04/68] upscale linear images --- FModel/ViewModels/CUE4ParseViewModel.cs | 50 +++++++++++++++++++------ 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index f6d4bca3..89013bf8 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -19,6 +19,7 @@ using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Assets.Exports.Wwise; using CUE4Parse.UE4.Localization; +using CUE4Parse.UE4.Objects.UObject; using CUE4Parse.UE4.Oodle.Objects; using CUE4Parse.UE4.Wwise; using CUE4Parse_Conversion.Materials; @@ -538,7 +539,8 @@ public void ExtractAndScroll(string fullPath, string objectName) { case UTexture2D texture: { - SetImage(texture.Decode()); + var filter = texture.GetOrDefault("Filter"); + SetImage(texture.Decode(), filter.IsNone ? null : filter.Text); return true; } case UAkMediaAssetData: @@ -587,17 +589,43 @@ public void ExtractAndScroll(string fullPath, string objectName) return false; } - private void SetImage(SKImage img) + private void SetImage(SKImage img, string filter = null) { - using var stream = img.Encode().AsStream(); - var image = new BitmapImage(); - image.BeginInit(); - image.CacheOption = BitmapCacheOption.OnLoad; - image.StreamSource = stream; - image.EndInit(); - image.Freeze(); - - TabControl.SelectedTab.Image = image; + const int UPSCALE_SIZE = 512; + SKData data; + + if (filter != null && img.Width < UPSCALE_SIZE && img.Height < UPSCALE_SIZE && filter.EndsWith("TF_Nearest", StringComparison.Ordinal)) + { + var width = img.Width; + var heigth = img.Height; + + while (width < UPSCALE_SIZE || heigth < UPSCALE_SIZE) + { + width *= 2; + heigth *= 2; + } + + using var bitmap = SKBitmap.FromImage(img); + using var resized = bitmap.Resize(new SKImageInfo(width, heigth), SKFilterQuality.None); + data = resized.Encode(SKEncodedImageFormat.Png, 100); // maybe dispose 'img' at this point? + } + else + { + data = img.Encode(SKEncodedImageFormat.Png, 100); + } + + using (data) + { + using var stream = data.AsStream(false); + var image = new BitmapImage(); + image.BeginInit(); + image.CacheOption = BitmapCacheOption.OnLoad; + image.StreamSource = stream; + image.EndInit(); + image.Freeze(); + TabControl.SelectedTab.Image = image; + } + if (UserSettings.Default.IsAutoSaveTextures) TabControl.SelectedTab.SaveImage(true); } From 5e334d82ca2c6ee137c13000c916e672cd68cf83 Mon Sep 17 00:00:00 2001 From: Not Officer Date: Sat, 29 May 2021 23:53:18 +0200 Subject: [PATCH 05/68] fixed bad statement --- FModel/ViewModels/CUE4ParseViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 89013bf8..fa25bdce 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -599,7 +599,7 @@ private void SetImage(SKImage img, string filter = null) var width = img.Width; var heigth = img.Height; - while (width < UPSCALE_SIZE || heigth < UPSCALE_SIZE) + while (width < UPSCALE_SIZE && heigth < UPSCALE_SIZE) { width *= 2; heigth *= 2; From 4f062fb58de1dc7275568becaf777942518c8929 Mon Sep 17 00:00:00 2001 From: Not Officer Date: Sun, 30 May 2021 00:53:02 +0200 Subject: [PATCH 06/68] another upscale case --- FModel/ViewModels/CUE4ParseViewModel.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index fa25bdce..fe99eb1a 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -540,7 +540,8 @@ public void ExtractAndScroll(string fullPath, string objectName) case UTexture2D texture: { var filter = texture.GetOrDefault("Filter"); - SetImage(texture.Decode(), filter.IsNone ? null : filter.Text); + var lodGroup = texture.GetOrDefault("LODGroup"); + SetImage(texture.Decode(), filter.IsNone ? null : filter.Text, lodGroup.IsNone ? null : lodGroup.Text); return true; } case UAkMediaAssetData: @@ -589,12 +590,14 @@ public void ExtractAndScroll(string fullPath, string objectName) return false; } - private void SetImage(SKImage img, string filter = null) + private void SetImage(SKImage img, string filter = null, string lodGroup = null) { const int UPSCALE_SIZE = 512; SKData data; - if (filter != null && img.Width < UPSCALE_SIZE && img.Height < UPSCALE_SIZE && filter.EndsWith("TF_Nearest", StringComparison.Ordinal)) + if ((filter != null && filter.EndsWith("TF_Nearest", StringComparison.Ordinal) || + lodGroup != null && lodGroup.EndsWith("TEXTUREGROUP_Pixels2D", StringComparison.Ordinal)) && + img.Width < UPSCALE_SIZE && img.Height < UPSCALE_SIZE) { var width = img.Width; var heigth = img.Height; From 1989a0f3865eda99264a89f449045803eef0dd10 Mon Sep 17 00:00:00 2001 From: Not Officer Date: Mon, 31 May 2021 14:46:53 +0200 Subject: [PATCH 07/68] Update CUE4Parse --- CUE4Parse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index aca9f9ba..70d41700 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit aca9f9ba95dd74ea1694fb483e798043f58fc3e2 +Subproject commit 70d417009d729260486d905eb5d10f45c78cfec7 From fc80857ea9583cc25615bfd06bae1415cd15f984 Mon Sep 17 00:00:00 2001 From: Not Officer Date: Mon, 31 May 2021 14:52:25 +0200 Subject: [PATCH 08/68] Update CUE4Parse --- CUE4Parse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index 70d41700..67141df1 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 70d417009d729260486d905eb5d10f45c78cfec7 +Subproject commit 67141df1d241f5747d9bf0274e2312c4f849a093 From 61d8efbaaae42a5699daf7db8d7b38a438ab9be4 Mon Sep 17 00:00:00 2001 From: Not Officer Date: Mon, 31 May 2021 15:14:34 +0200 Subject: [PATCH 09/68] fixed indexing root files --- CUE4Parse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index 67141df1..70d41700 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 67141df1d241f5747d9bf0274e2312c4f849a093 +Subproject commit 70d417009d729260486d905eb5d10f45c78cfec7 From d613ade489ec639ce7189053fd075de6b9c0421b Mon Sep 17 00:00:00 2001 From: Not Officer Date: Mon, 31 May 2021 15:16:36 +0200 Subject: [PATCH 10/68] fixed indexing root files (yes) --- CUE4Parse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index 70d41700..8bc1560a 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 70d417009d729260486d905eb5d10f45c78cfec7 +Subproject commit 8bc1560a8d168f84d1f97a86052b9367e2e7e5e3 From 6f63d53152d2397f603fef71dd6be29e4bff5991 Mon Sep 17 00:00:00 2001 From: Not Officer Date: Mon, 31 May 2021 20:20:35 +0200 Subject: [PATCH 11/68] fixed pak filepath concatination --- CUE4Parse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index 8bc1560a..bfc78f61 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 8bc1560a8d168f84d1f97a86052b9367e2e7e5e3 +Subproject commit bfc78f61b6e0dfcf8cba8e227eae21947c72f077 From 9a79bd608d8bcd01f5ce70ed1ed12ea428c71055 Mon Sep 17 00:00:00 2001 From: GMatrixGames Date: Mon, 31 May 2021 16:43:06 -0400 Subject: [PATCH 12/68] Fix certain items not displaying on quests. --- FModel/Creator/Bases/FN/BaseQuest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FModel/Creator/Bases/FN/BaseQuest.cs b/FModel/Creator/Bases/FN/BaseQuest.cs index 1baafaeb..b4a1df51 100644 --- a/FModel/Creator/Bases/FN/BaseQuest.cs +++ b/FModel/Creator/Bases/FN/BaseQuest.cs @@ -114,7 +114,7 @@ public override void ParseForInfo() } else if (!_unauthorizedReward.Contains(name.Text)) { - _reward = new Reward(quantity, primaryAssetName); + _reward = new Reward(quantity, $"{name}:{primaryAssetName}"); } } } @@ -256,4 +256,4 @@ private void DrawTexts(SKCanvas c, int y) _reward.DrawQuest(c, new SKRect(Height, outY + 25, Width - 20, y + Height - 25)); } } -} \ No newline at end of file +} From e575b5fb3bcc40f3643f8b86ea3f87afd8b564b3 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Tue, 1 Jun 2021 00:10:30 +0200 Subject: [PATCH 13/68] base map viewer v2 --- .github/workflows/main.yml | 1 - CUE4Parse | 2 +- FModel/MainWindow.xaml.cs | 4 +- FModel/ViewModels/ApiEndpoints/FModelApi.cs | 2 +- FModel/ViewModels/ApplicationViewModel.cs | 5 + FModel/ViewModels/CUE4ParseViewModel.cs | 52 +--- FModel/ViewModels/MapViewerViewModel.cs | 230 ++++-------------- FModel/Views/MapViewer.xaml | 92 +++++-- FModel/Views/MapViewer.xaml.cs | 17 ++ FModel/Views/Resources/Controls/Breadcrumb.cs | 7 + FModel/Views/Resources/Resources.xaml | 2 + FModel/Views/SettingsView.xaml.cs | 2 +- 12 files changed, 167 insertions(+), 249 deletions(-) create mode 100644 FModel/Views/Resources/Controls/Breadcrumb.cs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8c5302d2..b177e934 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,7 +12,6 @@ jobs: uses: actions/checkout@v2 with: submodules: 'true' - token: ${{ secrets.PAT_TOKEN }} - name: .NET 5 Setup uses: actions/setup-dotnet@v1 diff --git a/CUE4Parse b/CUE4Parse index bfc78f61..83465934 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit bfc78f61b6e0dfcf8cba8e227eae21947c72f077 +Subproject commit 83465934b69a1d4b339d05f0396ed1164ee77a6f diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index 639b9bea..6b9cb43b 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -57,8 +57,10 @@ private void OnClosing(object sender, CancelEventArgs e) private async void OnLoaded(object sender, RoutedEventArgs e) { +#if !DEBUG ApplicationService.ApiEndpointView.FModelApi.CheckForUpdates(UserSettings.Default.UpdateMode); - +#endif + switch (UserSettings.Default.AesReload) { case EAesReload.Always: diff --git a/FModel/ViewModels/ApiEndpoints/FModelApi.cs b/FModel/ViewModels/ApiEndpoints/FModelApi.cs index acff5a6e..5ba50e5a 100644 --- a/FModel/ViewModels/ApiEndpoints/FModelApi.cs +++ b/FModel/ViewModels/ApiEndpoints/FModelApi.cs @@ -109,7 +109,7 @@ private void CheckForUpdateEvent(UpdateInfoEventArgs args) { if (args != null) { - if (!args.IsUpdateAvailable) return; + if (new Version(args.CurrentVersion) == args.InstalledVersion) return; var messageBox = new MessageBoxModel { Text = $"FModel {args.CurrentVersion} is available. You are using version {args.InstalledVersion}. Do you want to update the application now?", diff --git a/FModel/ViewModels/ApplicationViewModel.cs b/FModel/ViewModels/ApplicationViewModel.cs index 38a2a71e..f2f3c699 100644 --- a/FModel/ViewModels/ApplicationViewModel.cs +++ b/FModel/ViewModels/ApplicationViewModel.cs @@ -105,6 +105,11 @@ public void AvoidEmptyGameDirectoryAndSetEGame(bool bAlreadyLaunched) UserSettings.Default.GameDirectory = gameLauncherViewModel.SelectedDetectedGame.GameDirectory; if (!bAlreadyLaunched || gameDirectory.Equals(gameLauncherViewModel.SelectedDetectedGame.GameDirectory)) return; + RestartWithWarning(); + } + + public void RestartWithWarning() + { MessageBox.Show("It looks like you just changed something.\nFModel will restart to apply your changes.", "Uh oh, a restart is needed", MessageBoxButton.OK, MessageBoxImage.Warning); Restart(); } diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index fe99eb1a..a160b863 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -539,9 +539,7 @@ public void ExtractAndScroll(string fullPath, string objectName) { case UTexture2D texture: { - var filter = texture.GetOrDefault("Filter"); - var lodGroup = texture.GetOrDefault("LODGroup"); - SetImage(texture.Decode(), filter.IsNone ? null : filter.Text, lodGroup.IsNone ? null : lodGroup.Text); + SetImage(texture.Decode()); return true; } case UAkMediaAssetData: @@ -590,45 +588,17 @@ public void ExtractAndScroll(string fullPath, string objectName) return false; } - private void SetImage(SKImage img, string filter = null, string lodGroup = null) + private void SetImage(SKImage img) { - const int UPSCALE_SIZE = 512; - SKData data; - - if ((filter != null && filter.EndsWith("TF_Nearest", StringComparison.Ordinal) || - lodGroup != null && lodGroup.EndsWith("TEXTUREGROUP_Pixels2D", StringComparison.Ordinal)) && - img.Width < UPSCALE_SIZE && img.Height < UPSCALE_SIZE) - { - var width = img.Width; - var heigth = img.Height; - - while (width < UPSCALE_SIZE && heigth < UPSCALE_SIZE) - { - width *= 2; - heigth *= 2; - } - - using var bitmap = SKBitmap.FromImage(img); - using var resized = bitmap.Resize(new SKImageInfo(width, heigth), SKFilterQuality.None); - data = resized.Encode(SKEncodedImageFormat.Png, 100); // maybe dispose 'img' at this point? - } - else - { - data = img.Encode(SKEncodedImageFormat.Png, 100); - } - - using (data) - { - using var stream = data.AsStream(false); - var image = new BitmapImage(); - image.BeginInit(); - image.CacheOption = BitmapCacheOption.OnLoad; - image.StreamSource = stream; - image.EndInit(); - image.Freeze(); - TabControl.SelectedTab.Image = image; - } - + using var stream = img.Encode().AsStream(); + var image = new BitmapImage(); + image.BeginInit(); + image.CacheOption = BitmapCacheOption.OnLoad; + image.StreamSource = stream; + image.EndInit(); + image.Freeze(); + + TabControl.SelectedTab.Image = image; if (UserSettings.Default.IsAutoSaveTextures) TabControl.SelectedTab.SaveImage(true); } diff --git a/FModel/ViewModels/MapViewerViewModel.cs b/FModel/ViewModels/MapViewerViewModel.cs index f121190a..13241050 100644 --- a/FModel/ViewModels/MapViewerViewModel.cs +++ b/FModel/ViewModels/MapViewerViewModel.cs @@ -1,20 +1,15 @@ -using System; +using System.Collections.Generic; using System.Threading.Tasks; -using System.Windows; using System.Windows.Media.Imaging; using CUE4Parse.UE4.Assets.Exports; +using CUE4Parse.UE4.Assets.Exports.Material; using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Assets.Objects; -using CUE4Parse.UE4.Objects.Core.i18N; using CUE4Parse.UE4.Objects.Core.Math; -using CUE4Parse.UE4.Objects.GameplayTags; -using CUE4Parse.UE4.Objects.UObject; using FModel.Creator; -using FModel.Extensions; using FModel.Framework; using FModel.Services; using SkiaSharp; -using SkiaSharp.HarfBuzz; namespace FModel.ViewModels { @@ -22,27 +17,31 @@ public class MapViewerViewModel : ViewModel { private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView; - private bool _showCities; - public bool ShowCities + private int _mapIndex = -1; + public int MapIndex // 0 is BR, 1 is PR { - get => _showCities; - set => SetProperty(ref _showCities, value, nameof(ShowCities)); - } - - private bool _showLandmarks; - public bool ShowLandmarks - { - get => _showLandmarks; - set => SetProperty(ref _showLandmarks, value, nameof(ShowLandmarks)); - } + get => _mapIndex; + set + { + switch (value) + { + case 0: + _mapRadius = 135000; + _mapImage = _brMiniMapImage; + break; + case 1: + _mapRadius = 51000; + _mapImage = _prMiniMapImage; + break; + } - private bool _showPatrolPaths; - public bool ShowPatrolPaths - { - get => _showPatrolPaths; - set => SetProperty(ref _showPatrolPaths, value, nameof(ShowPatrolPaths)); + SetProperty(ref _mapIndex, value); + } } + private int _mapRadius; + private BitmapImage _brMiniMapImage; + private BitmapImage _prMiniMapImage; private BitmapImage _mapImage; public BitmapImage MapImage { @@ -50,55 +49,30 @@ public BitmapImage MapImage set => SetProperty(ref _mapImage, value); } - private BitmapImage _citiesImage; - public BitmapImage CitiesImage - { - get => _citiesImage; - set => SetProperty(ref _citiesImage, value); - } - - private BitmapImage _landmarksImage; - public BitmapImage LandmarksImage - { - get => _landmarksImage; - set => SetProperty(ref _landmarksImage, value); - } - - private BitmapImage _patrolPathImage; - public BitmapImage PatrolPathImage - { - get => _patrolPathImage; - set => SetProperty(ref _patrolPathImage, value); - } - + private readonly List[] _bitmaps; // first bitmap is the displayed map, others are overlays of the map private readonly CUE4ParseViewModel _cue4Parse; public MapViewerViewModel(CUE4ParseViewModel cue4Parse) { + _bitmaps = new[] {new List(), new List()}; _cue4Parse = cue4Parse; } public async void Initialize() { Utils.Typefaces ??= new Typefaces(_cue4Parse); - if (MapImage == null && _mapBitmap == null) - { - await LoadMiniMap(); - } + await LoadBrMiniMap(); + await LoadPrMiniMap(); + MapIndex = 1; // don't forget br is selected by default + MapIndex = 0; // this will trigger the br map to be shown } public BitmapImage GetImageToSave() { - var ret = new SKBitmap(_mapBitmap.Width, _mapBitmap.Height, SKColorType.Rgba8888, SKAlphaType.Premul); + var ret = new SKBitmap(_bitmaps[MapIndex][0].Width, _bitmaps[MapIndex][0].Height, SKColorType.Rgba8888, SKAlphaType.Premul); using var c = new SKCanvas(ret); - c.DrawBitmap(_mapBitmap, 0, 0); - if (ShowCities) - c.DrawBitmap(_citiesBitmap, 0, 0); - if (ShowLandmarks) - c.DrawBitmap(_landmarksBitmap, 0, 0); - if (ShowPatrolPaths) - c.DrawBitmap(_patrolPathBitmap, 0, 0); + c.DrawBitmap(_bitmaps[MapIndex][0], 0, 0); return GetImageSource(ret); } @@ -114,21 +88,7 @@ private async void CheckForStuffToDraw(string propertyName = null) { switch (propertyName) { - case nameof(ShowCities) when _citiesBitmap == null && _landmarksBitmap == null && _mapBitmap != null: - { - await LoadCities(); - break; - } - case nameof(ShowLandmarks) when _landmarksBitmap == null && _citiesBitmap == null && _mapBitmap != null: - { - await LoadCities(); - break; - } - case nameof(ShowPatrolPaths) when _patrolPathBitmap == null && _mapBitmap != null: - { - await LoadPatrolPaths(); - break; - } + } } @@ -144,16 +104,7 @@ private BitmapImage GetImageSource(SKBitmap bitmap) image.Freeze(); return image; } - - private const int WorldRadius = 135000; - private SKBitmap _mapBitmap; - private SKBitmap _citiesBitmap; - private SKBitmap _landmarksBitmap; - private SKBitmap _patrolPathBitmap; - private readonly SKBitmap _pinBitmap = - SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/pin.png"))?.Stream); - private readonly SKBitmap _cityPinBitmap = - SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/city_pin.png"))?.Stream); + private readonly SKPaint _imagePaint = new() { IsAntialias = true, FilterQuality = SKFilterQuality.High, @@ -169,13 +120,14 @@ private BitmapImage GetImageSource(SKBitmap bitmap) private FVector2D GetMapPosition(FVector vector) { - var nx = (vector.Y + WorldRadius) / (WorldRadius * 2) * _mapBitmap.Width; - var ny = (1 - (vector.X + WorldRadius) / (WorldRadius * 2)) * _mapBitmap.Height; + var nx = (vector.Y + _mapRadius) / (_mapRadius * 2) * _bitmaps[MapIndex][0].Width; + var ny = (1 - (vector.X + _mapRadius) / (_mapRadius * 2)) * _bitmaps[MapIndex][0].Height; return new FVector2D(nx, ny); } - - private async Task LoadMiniMap() + + private async Task LoadBrMiniMap() { + if (_bitmaps[0].Count > 0) return; await _threadWorkerView.Begin(_ => { if (!Utils.TryLoadObject("FortniteGame/Content/UI/IngameMap/UIMapManagerBR.Default__UIMapManagerBR_C", out UObject mapManager) || @@ -183,109 +135,23 @@ await _threadWorkerView.Begin(_ => !mapMaterial.TryGetValue(out FStructFallback cachedExpressionData, "CachedExpressionData") || !cachedExpressionData.TryGetValue(out FStructFallback parameters, "Parameters") || !parameters.TryGetValue(out UTexture2D[] textureValues, "TextureValues")) return; - - _imagePaint.Typeface = Utils.Typefaces.Bottom ?? Utils.Typefaces.DisplayName; - _mapBitmap = Utils.GetBitmap(textureValues[0]); - MapImage = GetImageSource(_mapBitmap); + + _bitmaps[0].Add(Utils.GetBitmap(textureValues[0])); + _brMiniMapImage = GetImageSource(_bitmaps[0][0]); }); } - private async Task LoadCities() + private async Task LoadPrMiniMap() { + if (_bitmaps[1].Count > 0) return; await _threadWorkerView.Begin(_ => { - _citiesBitmap = new SKBitmap(_mapBitmap.Width, _mapBitmap.Height, SKColorType.Rgba8888, SKAlphaType.Premul); - _landmarksBitmap = new SKBitmap(_mapBitmap.Width, _mapBitmap.Height, SKColorType.Rgba8888, SKAlphaType.Premul); - using var cities = new SKCanvas(_citiesBitmap); - using var landmarks = new SKCanvas(_landmarksBitmap); - if (Utils.TryLoadObject("FortniteGame/Content/Quests/QuestIndicatorData.QuestIndicatorData", out UObject indicatorData) && - indicatorData.TryGetValue(out FStructFallback[] challengeMapPoiData, "ChallengeMapPoiData")) - { - foreach (var poiData in challengeMapPoiData) - { - if (!poiData.TryGetValue(out FSoftObjectPath discoveryQuest, "DiscoveryQuest") || - !poiData.TryGetValue(out FText text, "Text") || string.IsNullOrEmpty(text.Text) || - !poiData.TryGetValue(out FVector worldLocation, "WorldLocation") || - !poiData.TryGetValue(out FName discoverBackend, "DiscoverObjectiveBackendName") || - discoverBackend.Text.Contains("papaya", StringComparison.OrdinalIgnoreCase)) continue; - - var shaper = new CustomSKShaper(_imagePaint.Typeface); - var shapedText = shaper.Shape(text.Text, _imagePaint); - var vector = GetMapPosition(worldLocation); - - if (discoveryQuest.AssetPathName.Text.Contains("landmarks", StringComparison.OrdinalIgnoreCase)) - { - landmarks.DrawPoint(vector.X, vector.Y, _pathPaint); - landmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _imagePaint); - } - else - { - cities.DrawPoint(vector.X, vector.Y, _pathPaint); - cities.DrawBitmap(_cityPinBitmap, vector.X - 50, vector.Y - 90, _imagePaint); - cities.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _imagePaint); - } - } - } - - CitiesImage = GetImageSource(_citiesBitmap); - LandmarksImage = GetImageSource(_landmarksBitmap); - }); - } - - private async Task LoadPatrolPaths() - { - await _threadWorkerView.Begin(_ => - { - _patrolPathBitmap = new SKBitmap(_mapBitmap.Width, _mapBitmap.Height, SKColorType.Rgba8888, SKAlphaType.Premul); - using var c = new SKCanvas(_patrolPathBitmap); - - if (!Utils.TryLoadObject("FortniteGame/Plugins/GameFeatures/NPCLibrary/Content/GameFeatureData.GameFeatureData", out UObject gameFeatureData) || - !gameFeatureData.TryGetValue(out FPackageIndex levelOverlayConfig, "LevelOverlayConfig") || - !Utils.TryGetPackageIndexExport(levelOverlayConfig, out UObject npcLibrary) || - !npcLibrary.TryGetValue(out FStructFallback[] overlayList, "OverlayList")) - return; - - foreach (var overlay in overlayList) - { - if (!overlay.TryGetValue(out FSoftObjectPath overlayWorld, "OverlayWorld")) - continue; - - var exports = Utils.LoadExports(overlayWorld.AssetPathName.Text.SubstringBeforeLast(".")); - foreach (var export in exports) - { - if (!(export is UObject uObject)) continue; - if (!uObject.ExportType.Equals("FortAthenaPatrolPath", StringComparison.OrdinalIgnoreCase) || - !uObject.TryGetValue(out FGameplayTagContainer gameplayTags, "GameplayTags") || - !uObject.TryGetValue(out FPackageIndex[] patrolPoints, "PatrolPoints")) continue; - - if (!Utils.TryGetPackageIndexExport(patrolPoints[0], out uObject) || - !uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || - !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || - !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; - - var path = new SKPath(); - var vector = GetMapPosition(relativeLocation); - path.MoveTo(vector.X, vector.Y); - - for (var i = 1; i < patrolPoints.Length; i++) - { - if (!Utils.TryGetPackageIndexExport(patrolPoints[i], out uObject) || - !uObject.TryGetValue(out rootComponent, "RootComponent") || - !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || - !uObject.TryGetValue(out relativeLocation, "RelativeLocation")) continue; - - vector = GetMapPosition(relativeLocation); - path.LineTo(vector.X, vector.Y); - } - - path.Close(); - c.DrawPath(path, _pathPaint); - c.DrawBitmap(_pinBitmap, vector.X - 50, vector.Y - 90, _imagePaint); - c.DrawText(gameplayTags.GameplayTags[0].Text.SubstringAfterLast("."), vector.X, vector.Y - 12.5F, _imagePaint); - } - } + if (!Utils.TryLoadObject("FortniteGame/Content/UI/IngameMap/UIMapManagerPapaya.Default__UIMapManagerPapaya_C", out UObject mapManager) || + !mapManager.TryGetValue(out UMaterial mapMaterial, "MapMaterial") || + mapMaterial.ReferencedTextures.Count < 1) return; - PatrolPathImage = GetImageSource(_patrolPathBitmap); + _bitmaps[1].Add(Utils.GetBitmap(mapMaterial.ReferencedTextures[0] as UTexture2D)); + _prMiniMapImage = GetImageSource(_bitmaps[1][0]); }); } } diff --git a/FModel/Views/MapViewer.xaml b/FModel/Views/MapViewer.xaml index f21ef599..d31bee9a 100644 --- a/FModel/Views/MapViewer.xaml +++ b/FModel/Views/MapViewer.xaml @@ -5,9 +5,9 @@ xmlns:converters="clr-namespace:FModel.Views.Resources.Converters" xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI" xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI" - WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" + WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" SizeToContent="Width" ResizeMode="CanMinimize" Height="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.75'}" - Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.50'}"> + MinWidth="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.50'}"> diff --git a/FModel/ViewModels/ApplicationViewModel.cs b/FModel/ViewModels/ApplicationViewModel.cs index f2f3c699..bfc7aca2 100644 --- a/FModel/ViewModels/ApplicationViewModel.cs +++ b/FModel/ViewModels/ApplicationViewModel.cs @@ -44,7 +44,6 @@ public EStatusKind Status set { SetProperty(ref _status, value); - RaisePropertyChanged(nameof(TitleExtra)); IsReady = Status != EStatusKind.Loading && Status != EStatusKind.Stopping; } } diff --git a/FModel/ViewModels/MapViewerViewModel.cs b/FModel/ViewModels/MapViewerViewModel.cs index adee6a51..3dfaa8e7 100644 --- a/FModel/ViewModels/MapViewerViewModel.cs +++ b/FModel/ViewModels/MapViewerViewModel.cs @@ -1,16 +1,21 @@ -using System.Collections.Generic; -using System.Linq; +using System; +using System.Collections.Generic; using System.Threading.Tasks; using System.Windows.Media.Imaging; using CUE4Parse.UE4.Assets.Exports; using CUE4Parse.UE4.Assets.Exports.Material; using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Assets.Objects; +using CUE4Parse.UE4.Objects.Core.i18N; using CUE4Parse.UE4.Objects.Core.Math; +using CUE4Parse.UE4.Objects.GameplayTags; +using CUE4Parse.UE4.Objects.UObject; using FModel.Creator; +using FModel.Extensions; using FModel.Framework; using FModel.Services; using SkiaSharp; +using SkiaSharp.HarfBuzz; namespace FModel.ViewModels { @@ -22,32 +27,42 @@ public class MapLayer public class MapViewerViewModel : ViewModel { - private const string _FIRST_BITMAP = "mapBase"; private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView; - private int _mapIndex = -1; - public int MapIndex // 0 is BR, 1 is PR + #region BINDINGS + + private bool _poisCheck; + public bool PoisCheck { - get => _mapIndex; - set - { - switch (value) - { - case 0: - _mapRadius = 135000; - _mapImage = _brMiniMapImage; - break; - case 1: - _mapRadius = 51000; - _mapImage = _prMiniMapImage; - break; - } - - SetProperty(ref _mapIndex, value); - } + get => _poisCheck; + set => SetProperty(ref _poisCheck, value, "ApolloGameplay_MapPois"); + } + + private bool _brLandmarksCheck; + public bool BrLandmarksCheck + { + get => _brLandmarksCheck; + set => SetProperty(ref _brLandmarksCheck, value, "ApolloGameplay_MapLandmarks"); + } + + private bool _patrolsPathCheck; + public bool PatrolsPathCheck + { + get => _patrolsPathCheck; + set => SetProperty(ref _patrolsPathCheck, value, "ApolloGameplay_PatrolsPath"); + } + + private bool _prLandmarksCheck; + public bool PrLandmarksCheck + { + get => _prLandmarksCheck; + set => SetProperty(ref _prLandmarksCheck, value, "PapayaGameplay_MapLandmarks"); } - private int _mapRadius; + #endregion + + #region BITMAP IMAGES + private BitmapImage _brMiniMapImage; private BitmapImage _prMiniMapImage; private BitmapImage _mapImage; @@ -56,6 +71,9 @@ public BitmapImage MapImage get => _mapImage; set => SetProperty(ref _mapImage, value); } + + private BitmapImage _brLayerImage; + private BitmapImage _prLayerImage; private BitmapImage _layerImage; public BitmapImage LayerImage { @@ -63,6 +81,23 @@ public BitmapImage LayerImage set => SetProperty(ref _layerImage, value); } + private const int _widthHeight = 2048; + private const int _brRadius = 135000; + private const int _prRadius = 51000; + private int _mapIndex; + public int MapIndex // 0 is BR, 1 is PR + { + get => _mapIndex; + set + { + SetProperty(ref _mapIndex, value); + TriggerChange(); + } + } + + #endregion + + private const string _FIRST_BITMAP = "MapCheck"; private readonly Dictionary[] _bitmaps; // first bitmap is the displayed map, others are overlays of the map private readonly CUE4ParseViewModel _cue4Parse; @@ -79,43 +114,66 @@ public MapViewerViewModel(CUE4ParseViewModel cue4Parse) public async void Initialize() { Utils.Typefaces ??= new Typefaces(_cue4Parse); + _imagePaint.Typeface = Utils.Typefaces.Bottom ?? Utils.Typefaces.DisplayName; await LoadBrMiniMap(); await LoadPrMiniMap(); - MapIndex = 1; // don't forget br is selected by default - MapIndex = 0; // this will trigger the br map to be shown + TriggerChange(); } - public BitmapImage GetImageToSave() + public BitmapImage GetImageToSave() => GetImageSource(GetLayerBitmap(true)); + private SKBitmap GetLayerBitmap(bool withMap) { - var ret = new SKBitmap(_bitmaps[MapIndex][_FIRST_BITMAP].Layer.Width, _bitmaps[MapIndex][_FIRST_BITMAP].Layer.Height, SKColorType.Rgba8888, SKAlphaType.Premul); + var ret = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); using var c = new SKCanvas(ret); - foreach (var layer in _bitmaps[MapIndex].Values.Where(layer => layer.IsEnabled)) + foreach (var (key, value) in _bitmaps[MapIndex]) { - c.DrawBitmap(layer.Layer, 0, 0); + if (!value.IsEnabled || !withMap && key == _FIRST_BITMAP) continue; + c.DrawBitmap(value.Layer, new SKRect(0, 0, _widthHeight, _widthHeight)); } - return GetImageSource(ret); + return ret; } - public async Task GenericToggle(string key, bool enabled) + protected override bool SetProperty(ref T storage, T value, string propertyName = null) // don't delete, else nothing will update for some reason + { + var ret = base.SetProperty(ref storage, value, propertyName); + if (bool.TryParse(value.ToString(), out var b)) GenericToggle(propertyName, b); + return ret; + } + + private async void GenericToggle(string key, bool enabled) { if (_bitmaps[MapIndex].TryGetValue(key, out var layer) && layer.Layer != null) { layer.IsEnabled = enabled; } - else // load layer + else if (enabled) // load layer { switch (key) { - + case "ApolloGameplay_MapPois": + case "ApolloGameplay_MapLandmarks": + case "PapayaGameplay_MapLandmarks": + await LoadQuestIndicatorData(); + break; + case "ApolloGameplay_PatrolsPath": + await LoadPatrolsPath(); + break; } + _bitmaps[MapIndex][key].IsEnabled = true; } - } - protected override bool SetProperty(ref T storage, T value, string propertyName = null) // don't delete, else nothing will update for some reason - { - return base.SetProperty(ref storage, value, propertyName); + switch (MapIndex) + { + case 0: + _brLayerImage = GetImageSource(GetLayerBitmap(false)); + break; + case 1: + _prLayerImage = GetImageSource(GetLayerBitmap(false)); + break; + } + TriggerChange(); } private BitmapImage GetImageSource(SKBitmap bitmap) @@ -130,6 +188,24 @@ private BitmapImage GetImageSource(SKBitmap bitmap) image.Freeze(); return image; } + + private void TriggerChange() + { + switch (_mapIndex) + { + case 0: + _mapImage = _brMiniMapImage; + _layerImage = _brLayerImage; + break; + case 1: + _mapImage = _prMiniMapImage; + _layerImage = _prLayerImage; + break; + } + + RaisePropertyChanged(nameof(MapImage)); + RaisePropertyChanged(nameof(LayerImage)); + } private readonly SKPaint _imagePaint = new() { @@ -140,20 +216,22 @@ private BitmapImage GetImageSource(SKBitmap bitmap) private readonly SKPaint _pathPaint = new() { IsAntialias = true, FilterQuality = SKFilterQuality.High, IsStroke = true, - Style = SKPaintStyle.Stroke, StrokeWidth = 10, Color = SKColors.Red, + Style = SKPaintStyle.Stroke, StrokeWidth = 5, Color = SKColors.Red, ImageFilter = SKImageFilter.CreateDropShadow(4, 4, 8, 8, SKColors.Black) }; - private FVector2D GetMapPosition(FVector vector) + private FVector2D GetMapPosition(FVector vector, int mapRadius) { - var nx = (vector.Y + _mapRadius) / (_mapRadius * 2) * _bitmaps[MapIndex][_FIRST_BITMAP].Layer.Width; - var ny = (1 - (vector.X + _mapRadius) / (_mapRadius * 2)) * _bitmaps[MapIndex][_FIRST_BITMAP].Layer.Height; + var nx = (vector.Y + mapRadius) / (mapRadius * 2) * _widthHeight; + var ny = (1 - (vector.X + mapRadius) / (mapRadius * 2)) * _widthHeight; return new FVector2D(nx, ny); } private async Task LoadBrMiniMap() { - if (_bitmaps[0].TryGetValue(_FIRST_BITMAP, out var layer) && layer.Layer != null) return; + if (_bitmaps[0].TryGetValue(_FIRST_BITMAP, out var brMap) && brMap.Layer != null) + return; // if map already loaded + await _threadWorkerView.Begin(_ => { if (!Utils.TryLoadObject("FortniteGame/Content/UI/IngameMap/UIMapManagerBR.Default__UIMapManagerBR_C", out UObject mapManager) || @@ -169,7 +247,9 @@ await _threadWorkerView.Begin(_ => private async Task LoadPrMiniMap() { - if (_bitmaps[1].TryGetValue(_FIRST_BITMAP, out var layer) && layer.Layer != null) return; + if (_bitmaps[1].TryGetValue(_FIRST_BITMAP, out var prMap) && prMap.Layer != null) + return; // if map already loaded + await _threadWorkerView.Begin(_ => { if (!Utils.TryLoadObject("FortniteGame/Content/UI/IngameMap/UIMapManagerPapaya.Default__UIMapManagerPapaya_C", out UObject mapManager) || @@ -180,5 +260,112 @@ await _threadWorkerView.Begin(_ => _prMiniMapImage = GetImageSource(_bitmaps[1][_FIRST_BITMAP].Layer); }); } + + private async Task LoadQuestIndicatorData() + { + await _threadWorkerView.Begin(_ => + { + var poisBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + var brLandmarksBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + var prLandmarksBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var pois = new SKCanvas(poisBitmap); + using var brLandmarks = new SKCanvas(brLandmarksBitmap); + using var prLandmarks = new SKCanvas(prLandmarksBitmap); + + if (Utils.TryLoadObject("FortniteGame/Content/Quests/QuestIndicatorData", out UObject indicatorData) && + indicatorData.TryGetValue(out FStructFallback[] challengeMapPoiData, "ChallengeMapPoiData")) + { + foreach (var poiData in challengeMapPoiData) + { + if (!poiData.TryGetValue(out FSoftObjectPath discoveryQuest, "DiscoveryQuest") || + !poiData.TryGetValue(out FText text, "Text") || string.IsNullOrEmpty(text.Text) || + !poiData.TryGetValue(out FVector worldLocation, "WorldLocation") || + !poiData.TryGetValue(out FName discoverBackend, "DiscoverObjectiveBackendName")) continue; + + var shaper = new CustomSKShaper(_imagePaint.Typeface); + var shapedText = shaper.Shape(text.Text, _imagePaint); + + if (discoverBackend.Text.Contains("papaya", StringComparison.OrdinalIgnoreCase)) + { + var vector = GetMapPosition(worldLocation, _prRadius); + prLandmarks.DrawPoint(vector.X, vector.Y, _pathPaint); + prLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _imagePaint); + } + else if (discoveryQuest.AssetPathName.Text.Contains("landmarks", StringComparison.OrdinalIgnoreCase)) + { + var vector = GetMapPosition(worldLocation, _brRadius); + brLandmarks.DrawPoint(vector.X, vector.Y, _pathPaint); + brLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _imagePaint); + } + else + { + var vector = GetMapPosition(worldLocation, _brRadius); + pois.DrawPoint(vector.X, vector.Y, _pathPaint); + pois.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _imagePaint); + } + } + } + + _bitmaps[0]["ApolloGameplay_MapPois"] = new MapLayer {Layer = poisBitmap, IsEnabled = false}; + _bitmaps[0]["ApolloGameplay_MapLandmarks"] = new MapLayer {Layer = brLandmarksBitmap, IsEnabled = false}; + _bitmaps[1]["PapayaGameplay_MapLandmarks"] = new MapLayer {Layer = prLandmarksBitmap, IsEnabled = false}; + }); + } + + private async Task LoadPatrolsPath() + { + await _threadWorkerView.Begin(_ => + { + var patrolsPathBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(patrolsPathBitmap); + + if (!Utils.TryLoadObject("FortniteGame/Plugins/GameFeatures/NPCLibrary/Content/GameFeatureData.GameFeatureData", out UObject gameFeatureData) || + !gameFeatureData.TryGetValue(out FPackageIndex levelOverlayConfig, "LevelOverlayConfig") || + !Utils.TryGetPackageIndexExport(levelOverlayConfig, out UObject npcLibrary) || + !npcLibrary.TryGetValue(out FStructFallback[] overlayList, "OverlayList")) + return; + + foreach (var overlay in overlayList) + { + if (!overlay.TryGetValue(out FSoftObjectPath overlayWorld, "OverlayWorld")) + continue; + + var exports = Utils.LoadExports(overlayWorld.AssetPathName.Text.SubstringBeforeLast(".")); + foreach (var export in exports) + { + if (!(export is UObject uObject)) continue; + if (!uObject.ExportType.Equals("FortAthenaPatrolPath", StringComparison.OrdinalIgnoreCase) || + !uObject.TryGetValue(out FGameplayTagContainer gameplayTags, "GameplayTags") || + !uObject.TryGetValue(out FPackageIndex[] patrolPoints, "PatrolPoints")) continue; + + if (!Utils.TryGetPackageIndexExport(patrolPoints[0], out uObject) || + !uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || + !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + + var path = new SKPath(); + var vector = GetMapPosition(relativeLocation, _brRadius); + path.MoveTo(vector.X, vector.Y); + + for (var i = 1; i < patrolPoints.Length; i++) + { + if (!Utils.TryGetPackageIndexExport(patrolPoints[i], out uObject) || + !uObject.TryGetValue(out rootComponent, "RootComponent") || + !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || + !uObject.TryGetValue(out relativeLocation, "RelativeLocation")) continue; + + vector = GetMapPosition(relativeLocation, _brRadius); + path.LineTo(vector.X, vector.Y); + } + + path.Close(); + c.DrawPath(path, _pathPaint); + c.DrawText(gameplayTags.GameplayTags[0].Text.SubstringAfterLast("."), vector.X, vector.Y - 12.5F, _imagePaint); + } + } + + _bitmaps[0]["ApolloGameplay_PatrolsPath"] = new MapLayer {Layer = patrolsPathBitmap, IsEnabled = false}; + }); + } } } \ No newline at end of file diff --git a/FModel/Views/MapViewer.xaml b/FModel/Views/MapViewer.xaml index b3097de6..2f467041 100644 --- a/FModel/Views/MapViewer.xaml +++ b/FModel/Views/MapViewer.xaml @@ -1,6 +1,7 @@  - - - + + + - - - - - - - - - - + + + + + + + + + + + diff --git a/FModel/Views/MapViewer.xaml.cs b/FModel/Views/MapViewer.xaml.cs index 74507a26..16da3b4b 100644 --- a/FModel/Views/MapViewer.xaml.cs +++ b/FModel/Views/MapViewer.xaml.cs @@ -74,11 +74,5 @@ private void OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs break; } } - - private async void ToggleOnChange(object sender, RoutedEventArgs e) - { - if (sender is not CheckBox checkBox) return; - await _applicationView.MapViewer.GenericToggle(checkBox.Content.ToString(), checkBox.IsChecked ?? true); - } } } \ No newline at end of file From e9f308d028e3e1cde8025430cfe74f18e342ddd2 Mon Sep 17 00:00:00 2001 From: GMatrixGames Date: Fri, 4 Jun 2021 21:51:55 -0400 Subject: [PATCH 30/68] Add Days Gone as UnrealEngine game. --- CUE4Parse | 2 +- FModel/Creator/Bases/SOD2/BaseDecayIcon.cs | 9 +++++++- FModel/Enums.cs | 4 +++- FModel/ViewModels/CUE4ParseViewModel.cs | 22 +++++++++---------- FModel/ViewModels/GameSelectorViewModel.cs | 1 + .../Converters/StringToGameConverter.cs | 1 + 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index f17ea8bb..b4b18abd 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit f17ea8bbf946a8319758759118c1e46b863eab33 +Subproject commit b4b18abd31a049b2c408a1867520ca06e5c8b144 diff --git a/FModel/Creator/Bases/SOD2/BaseDecayIcon.cs b/FModel/Creator/Bases/SOD2/BaseDecayIcon.cs index b5518efb..3dbe6ced 100644 --- a/FModel/Creator/Bases/SOD2/BaseDecayIcon.cs +++ b/FModel/Creator/Bases/SOD2/BaseDecayIcon.cs @@ -23,7 +23,6 @@ public override void ParseForInfo() if (Object.TryGetValue(out FStructFallback stackingInfo, "StackingInfo") && stackingInfo.TryGetValue(out int maxStackCount, "MaxStackCount")) _maxStackCount = maxStackCount; - if (Object.Class.SuperStruct != null && Utils.TryGetPackageIndexExport(Object.Class.SuperStruct, out UObject t)) { @@ -61,6 +60,14 @@ public override SKImage Draw() return SKImage.FromBitmap(ret); } + private new void DrawPreview(SKCanvas c) + { + c.DrawBitmap(Preview ?? DefaultPreview, new SKRect(Margin, Margin, Width - Margin, Height - Margin), new SKPaint + { + // BlendMode = SKBlendMode.SrcATop -- Need Asval's assistance. + }); + } + private new void DrawBackground(SKCanvas c) { c.DrawRect(new SKRect(Margin, Margin, Width - Margin, Height - Margin), diff --git a/FModel/Enums.cs b/FModel/Enums.cs index 802d5839..58dca396 100644 --- a/FModel/Enums.cs +++ b/FModel/Enums.cs @@ -88,7 +88,9 @@ public enum FGame [Description("Star Wars: Jedi Fallen Order")] SwGame, [Description("Core")] - Platform + Platform, + [Description("Days Gone")] + BendGame } public enum ELoadingMode diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 7526f6a8..0a40e82f 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -83,17 +83,15 @@ public CUE4ParseViewModel(string gameDirectory) { Game = gameDirectory.SubstringBeforeLast("\\Content\\Paks").SubstringAfterLast("\\").ToEnum(FGame.Unknown); - if (Game == FGame.WorldExplorers) + Provider = Game switch { - Provider = new DefaultFileProvider(new DirectoryInfo(gameDirectory), new List {new(gameDirectory.SubstringBeforeLast('\\') + "\\EmbeddedPaks\\")}, - SearchOption.TopDirectoryOnly, true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]); - } - else - { - Provider = new DefaultFileProvider(gameDirectory, SearchOption.TopDirectoryOnly, true, - UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]); - } - + FGame.WorldExplorers => new DefaultFileProvider(new DirectoryInfo(gameDirectory), new List {new(gameDirectory.SubstringBeforeLast('\\') + "\\EmbeddedPaks\\")}, SearchOption.TopDirectoryOnly, + true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]), + FGame.BendGame => new DefaultFileProvider(new DirectoryInfo(gameDirectory), new List {new(gameDirectory.SubstringBeforeLast('\\') + "\\sfpaks\\")}, SearchOption.AllDirectories, + true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]), + _ => new DefaultFileProvider(gameDirectory, SearchOption.TopDirectoryOnly, true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]) + }; + break; } } @@ -480,7 +478,7 @@ public void Extract(string fullPath, bool addNewTab = false, bool bulkSave = fal var header = new FDictionaryHeader(archive); TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(header, Formatting.Indented), bulkSave); } - + break; } case "png": @@ -644,7 +642,7 @@ public void ExportData(string fullPath) Directory.CreateDirectory(path.SubstringBeforeLast('/')); File.WriteAllBytes(path, kvp.Value); } - + Log.Information("{FileName} successfully exported", fileName); FLogger.AppendInformation(); FLogger.AppendText($"Successfully exported '{fileName}'", Constants.WHITE, true); diff --git a/FModel/ViewModels/GameSelectorViewModel.cs b/FModel/ViewModels/GameSelectorViewModel.cs index 5385276b..90569632 100644 --- a/FModel/ViewModels/GameSelectorViewModel.cs +++ b/FModel/ViewModels/GameSelectorViewModel.cs @@ -60,6 +60,7 @@ private IEnumerable EnumerateDetectedGames() yield return GetUnrealEngineGame("shoebill", "\\SwGame\\Content\\Paks"); yield return GetUnrealEngineGame("Snoek", "\\StateOfDecay2\\Content\\Paks"); yield return GetUnrealEngineGame("a99769d95d8f400baad1f67ab5dfe508", "\\Core\\Platform\\Content\\Paks"); + yield return GetUnrealEngineGame("Nebula", "\\BendGame\\Content\\Paks"); 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 c05033c9..60322668 100644 --- a/FModel/Views/Resources/Converters/StringToGameConverter.cs +++ b/FModel/Views/Resources/Converters/StringToGameConverter.cs @@ -13,6 +13,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn return value switch { "Newt" => "Spellbreak", + "Nebula" => "Days Gone", "Fortnite" => "Fortnite", "VALORANT" => "Valorant", "Pewee" => "Rogue Company", From a58b212bec9d3b0c6294f7fd101ad1707a065ee2 Mon Sep 17 00:00:00 2001 From: GMatrixGames Date: Fri, 4 Jun 2021 22:13:10 -0400 Subject: [PATCH 31/68] Resolve error because I didn't set a default UE version --- FModel/Settings/UserSettings.cs | 9 ++++++--- FModel/ViewModels/CUE4ParseViewModel.cs | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index 583ee28f..1cc62682 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -210,7 +210,8 @@ public int ImageMergerMargin {FGame.Indiana, EGame.GAME_UE4_LATEST}, {FGame.RogueCompany, EGame.GAME_UE4_LATEST}, {FGame.SwGame, EGame.GAME_UE4_LATEST}, - {FGame.Platform, EGame.GAME_UE4_24} + {FGame.Platform, EGame.GAME_UE4_24}, + {FGame.BendGame, EGame.GAME_UE4_11} }; public IDictionary OverridedGame { @@ -233,7 +234,8 @@ public IDictionary OverridedGame {FGame.Indiana, UE4Version.VER_UE4_DETERMINE_BY_GAME}, {FGame.RogueCompany, UE4Version.VER_UE4_DETERMINE_BY_GAME}, {FGame.SwGame, UE4Version.VER_UE4_DETERMINE_BY_GAME}, - {FGame.Platform, UE4Version.VER_UE4_DETERMINE_BY_GAME} + {FGame.Platform, UE4Version.VER_UE4_DETERMINE_BY_GAME}, + {FGame.BendGame, UE4Version.VER_UE4_DETERMINE_BY_GAME} }; public IDictionary OverridedUEVersion { @@ -292,7 +294,8 @@ public IDictionary OverridedUEVersion {FGame.Indiana, new List()}, {FGame.RogueCompany, new List()}, {FGame.SwGame, new List()}, - {FGame.Platform, new List()} + {FGame.Platform, new List()}, + {FGame.BendGame, new List()} }; public IDictionary> CustomDirectories { diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 0a40e82f..c0c664cb 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -483,6 +483,7 @@ public void Extract(string fullPath, bool addNewTab = false, bool bulkSave = fal } case "png": case "jpg": + case "bmp": { if (Provider.TrySaveAsset(fullPath, out var data)) { @@ -497,6 +498,7 @@ public void Extract(string fullPath, bool addNewTab = false, bool bulkSave = fal FLogger.AppendText($"Export '{fullPath.SubstringAfterLast('/')}' and change its extension if you want it to be an installable font file", Constants.WHITE, true); break; case "ushaderbytecode": + case "ushadercode": TabControl.SelectedTab.Image = null; break; default: From 588baef4798f9c8e4121adcd08ea8e328f40f3fc Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sat, 5 Jun 2021 04:15:19 +0200 Subject: [PATCH 32/68] cannonball + skydive games --- FModel/ViewModels/CUE4ParseViewModel.cs | 13 +-- FModel/ViewModels/GameSelectorViewModel.cs | 4 +- FModel/ViewModels/MapViewerViewModel.cs | 108 +++++++++++++++++---- FModel/Views/MapViewer.xaml | 14 +-- 4 files changed, 103 insertions(+), 36 deletions(-) diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index c0c664cb..98895f34 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -81,17 +81,8 @@ public CUE4ParseViewModel(string gameDirectory) } default: { - Game = gameDirectory.SubstringBeforeLast("\\Content\\Paks").SubstringAfterLast("\\").ToEnum(FGame.Unknown); - - Provider = Game switch - { - FGame.WorldExplorers => new DefaultFileProvider(new DirectoryInfo(gameDirectory), new List {new(gameDirectory.SubstringBeforeLast('\\') + "\\EmbeddedPaks\\")}, SearchOption.TopDirectoryOnly, - true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]), - FGame.BendGame => new DefaultFileProvider(new DirectoryInfo(gameDirectory), new List {new(gameDirectory.SubstringBeforeLast('\\') + "\\sfpaks\\")}, SearchOption.AllDirectories, - true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]), - _ => new DefaultFileProvider(gameDirectory, SearchOption.TopDirectoryOnly, true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]) - }; - + Game = gameDirectory.SubstringBeforeLast("\\Content\\").SubstringAfterLast("\\").ToEnum(FGame.Unknown); + Provider = new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]); break; } } diff --git a/FModel/ViewModels/GameSelectorViewModel.cs b/FModel/ViewModels/GameSelectorViewModel.cs index 90569632..be2e0fb2 100644 --- a/FModel/ViewModels/GameSelectorViewModel.cs +++ b/FModel/ViewModels/GameSelectorViewModel.cs @@ -55,12 +55,12 @@ private IEnumerable EnumerateDetectedGames() yield return GetUnrealEngineGame("Rosemallow", "\\Indiana\\Content\\Paks"); yield return GetUnrealEngineGame("Catnip", "\\OakGame\\Content\\Paks"); yield return GetUnrealEngineGame("AzaleaAlpha", "\\Prospect\\Content\\Paks"); - yield return GetUnrealEngineGame("WorldExplorersLive", "\\WorldExplorers\\Content\\Paks"); + yield return GetUnrealEngineGame("WorldExplorersLive", "\\WorldExplorers\\Content"); yield return GetUnrealEngineGame("Newt", "\\g3\\Content\\Paks"); yield return GetUnrealEngineGame("shoebill", "\\SwGame\\Content\\Paks"); yield return GetUnrealEngineGame("Snoek", "\\StateOfDecay2\\Content\\Paks"); yield return GetUnrealEngineGame("a99769d95d8f400baad1f67ab5dfe508", "\\Core\\Platform\\Content\\Paks"); - yield return GetUnrealEngineGame("Nebula", "\\BendGame\\Content\\Paks"); + yield return GetUnrealEngineGame("Nebula", "\\BendGame\\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/ViewModels/MapViewerViewModel.cs b/FModel/ViewModels/MapViewerViewModel.cs index 3dfaa8e7..82e06330 100644 --- a/FModel/ViewModels/MapViewerViewModel.cs +++ b/FModel/ViewModels/MapViewerViewModel.cs @@ -31,32 +31,46 @@ public class MapViewerViewModel : ViewModel #region BINDINGS - private bool _poisCheck; - public bool PoisCheck + private bool _brPois; + public bool BrPois { - get => _poisCheck; - set => SetProperty(ref _poisCheck, value, "ApolloGameplay_MapPois"); + get => _brPois; + set => SetProperty(ref _brPois, value, "ApolloGameplay_MapPois"); } - private bool _brLandmarksCheck; - public bool BrLandmarksCheck + private bool _brLandmarks; + public bool BrLandmarks { - get => _brLandmarksCheck; - set => SetProperty(ref _brLandmarksCheck, value, "ApolloGameplay_MapLandmarks"); + get => _brLandmarks; + set => SetProperty(ref _brLandmarks, value, "ApolloGameplay_MapLandmarks"); } - private bool _patrolsPathCheck; - public bool PatrolsPathCheck + private bool _brPatrolsPath; + public bool BrPatrolsPath { - get => _patrolsPathCheck; - set => SetProperty(ref _patrolsPathCheck, value, "ApolloGameplay_PatrolsPath"); + get => _brPatrolsPath; + set => SetProperty(ref _brPatrolsPath, value, "ApolloGameplay_PatrolsPath"); } - private bool _prLandmarksCheck; - public bool PrLandmarksCheck + private bool _prLandmarks; + public bool PrLandmarks { - get => _prLandmarksCheck; - set => SetProperty(ref _prLandmarksCheck, value, "PapayaGameplay_MapLandmarks"); + get => _prLandmarks; + set => SetProperty(ref _prLandmarks, value, "PapayaGameplay_MapLandmarks"); + } + + private bool _prCannonball; + public bool PrCannonball + { + get => _prCannonball; + set => SetProperty(ref _prCannonball, value, "PapayaGameplay_CannonballGame"); + } + + private bool _prSkydive; + public bool PrSkydive + { + get => _prSkydive; + set => SetProperty(ref _prSkydive, value, "PapayaGameplay_SkydiveGame"); } #endregion @@ -160,6 +174,12 @@ private async void GenericToggle(string key, bool enabled) case "ApolloGameplay_PatrolsPath": await LoadPatrolsPath(); break; + case "PapayaGameplay_CannonballGame": + await LoadCannonballGame(); + break; + case "PapayaGameplay_SkydiveGame": + await LoadSkydiveGame(); + break; } _bitmaps[MapIndex][key].IsEnabled = true; } @@ -333,7 +353,7 @@ await _threadWorkerView.Begin(_ => var exports = Utils.LoadExports(overlayWorld.AssetPathName.Text.SubstringBeforeLast(".")); foreach (var export in exports) { - if (!(export is UObject uObject)) continue; + if (export is not { } uObject) continue; if (!uObject.ExportType.Equals("FortAthenaPatrolPath", StringComparison.OrdinalIgnoreCase) || !uObject.TryGetValue(out FGameplayTagContainer gameplayTags, "GameplayTags") || !uObject.TryGetValue(out FPackageIndex[] patrolPoints, "PatrolPoints")) continue; @@ -367,5 +387,59 @@ await _threadWorkerView.Begin(_ => _bitmaps[0]["ApolloGameplay_PatrolsPath"] = new MapLayer {Layer = patrolsPathBitmap, IsEnabled = false}; }); } + + private async Task LoadCannonballGame() + { + await _threadWorkerView.Begin(_ => + { + var cannonballBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(cannonballBitmap); + + var exports = Utils.LoadExports("/PapayaGameplay/LevelOverlays/PapayaGameplay_CannonballGame"); + foreach (var export in exports) + { + if (export is not { } uObject) continue; + if (!uObject.ExportType.Equals("BP_CannonballGame_Target_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("CannonballGame_VehicleSpawner_C", StringComparison.OrdinalIgnoreCase)) continue; + + if (!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || + !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + + var vector = GetMapPosition(relativeLocation, _prRadius); + c.DrawPoint(vector.X, vector.Y, _pathPaint); + c.DrawText(Utils.GetLocalizedResource("", "D998BEF44F051E0885C6C58565934BEA", "Cannonball"), vector.X, vector.Y - 12.5F, _imagePaint); + } + + _bitmaps[1]["PapayaGameplay_CannonballGame"] = new MapLayer {Layer = cannonballBitmap, IsEnabled = false}; + }); + } + + private async Task LoadSkydiveGame() + { + await _threadWorkerView.Begin(_ => + { + var skydiveBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(skydiveBitmap); + + var exports = Utils.LoadExports("/PapayaGameplay/LevelOverlays/PapayaGameplay_SkydiveGame"); + foreach (var export in exports) + { + if (export is not { } uObject) continue; + if (!uObject.ExportType.Equals("BP_Waypoint_Papaya_Skydive_Start_C", StringComparison.OrdinalIgnoreCase)) continue; + + if (!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + !uObject.TryGetValue(out FText minigameActivityName, "MinigameActivityName") || + !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || + !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + + var vector = GetMapPosition(relativeLocation, _prRadius); + c.DrawPoint(vector.X, vector.Y, _pathPaint); + c.DrawText(minigameActivityName.Text, vector.X, vector.Y - 12.5F, _imagePaint); + } + + _bitmaps[1]["PapayaGameplay_SkydiveGame"] = new MapLayer {Layer = skydiveBitmap, IsEnabled = false}; + }); + } } } \ No newline at end of file diff --git a/FModel/Views/MapViewer.xaml b/FModel/Views/MapViewer.xaml index 2f467041..d4ed246e 100644 --- a/FModel/Views/MapViewer.xaml +++ b/FModel/Views/MapViewer.xaml @@ -23,20 +23,22 @@ - - - - + + - - From 36fa636dab20b5fdfdeb9105237d247ef1d6dace Mon Sep 17 00:00:00 2001 From: GMatrixGames Date: Fri, 4 Jun 2021 22:50:31 -0400 Subject: [PATCH 33/68] Days Gone and Battle Breakers won't search recursive folders --- FModel/ViewModels/CUE4ParseViewModel.cs | 12 +++++++++++- FModel/Views/Resources/Resources.xaml | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 98895f34..705eacba 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -82,7 +82,17 @@ public CUE4ParseViewModel(string gameDirectory) default: { Game = gameDirectory.SubstringBeforeLast("\\Content\\").SubstringAfterLast("\\").ToEnum(FGame.Unknown); - Provider = new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]); + + if (Game == FGame.StateOfDecay2) + Provider = new DefaultFileProvider(new DirectoryInfo(gameDirectory), new List + { + new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\Paks"), + new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\DisabledPaks") + }, + SearchOption.AllDirectories, true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]); + else + Provider = new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, true, UserSettings.Default.OverridedGame[Game], UserSettings.Default.OverridedUEVersion[Game]); + break; } } diff --git a/FModel/Views/Resources/Resources.xaml b/FModel/Views/Resources/Resources.xaml index 317d8dd9..95653e2a 100644 --- a/FModel/Views/Resources/Resources.xaml +++ b/FModel/Views/Resources/Resources.xaml @@ -384,7 +384,7 @@ - + From 9a1501db4bbc8b553fc97b8bd8619298718dd69c Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sat, 5 Jun 2021 05:26:13 +0200 Subject: [PATCH 34/68] map viewer v2 done kinda --- FModel/ViewModels/MapViewerViewModel.cs | 208 ++++++++++++++++++++++++ FModel/Views/MapViewer.xaml | 18 +- 2 files changed, 218 insertions(+), 8 deletions(-) diff --git a/FModel/ViewModels/MapViewerViewModel.cs b/FModel/ViewModels/MapViewerViewModel.cs index 82e06330..432b6a6f 100644 --- a/FModel/ViewModels/MapViewerViewModel.cs +++ b/FModel/ViewModels/MapViewerViewModel.cs @@ -24,6 +24,12 @@ public class MapLayer public SKBitmap Layer; public bool IsEnabled; } + + public enum EWaypointType + { + Parkour, + TimeTrials + } public class MapViewerViewModel : ViewModel { @@ -72,6 +78,41 @@ public bool PrSkydive get => _prSkydive; set => SetProperty(ref _prSkydive, value, "PapayaGameplay_SkydiveGame"); } + + private bool _prShootingTargets; + public bool PrShootingTargets + { + get => _prShootingTargets; + set => SetProperty(ref _prShootingTargets, value, "PapayaGameplay_ShootingTargets"); + } + + private bool _prParkour; + public bool PrParkour + { + get => _prParkour; + set => SetProperty(ref _prParkour, value, "PapayaGameplay_ParkourGame"); + } + + private bool _prTimeTrials; + public bool PrTimeTrials + { + get => _prTimeTrials; + set => SetProperty(ref _prTimeTrials, value, "PapayaGameplay_TimeTrials"); + } + + private bool _prVendingMachines; + public bool PrVendingMachines + { + get => _prVendingMachines; + set => SetProperty(ref _prVendingMachines, value, "PapayaGameplay_VendingMachines"); + } + + private bool _prMusicBlocks; + public bool PrMusicBlocks + { + get => _prMusicBlocks; + set => SetProperty(ref _prMusicBlocks, value, "PapayaGameplay_MusicBlocks"); + } #endregion @@ -180,6 +221,21 @@ private async void GenericToggle(string key, bool enabled) case "PapayaGameplay_SkydiveGame": await LoadSkydiveGame(); break; + case "PapayaGameplay_ShootingTargets": + await LoadShootingTargets(); + break; + case "PapayaGameplay_ParkourGame": + await LoadWaypoint(EWaypointType.Parkour); + break; + case "PapayaGameplay_TimeTrials": + await LoadWaypoint(EWaypointType.TimeTrials); + break; + case "PapayaGameplay_VendingMachines": + await LoadVendingMachines(); + break; + case "PapayaGameplay_MusicBlocks": + await LoadMusicBlocks(); + break; } _bitmaps[MapIndex][key].IsEnabled = true; } @@ -441,5 +497,157 @@ await _threadWorkerView.Begin(_ => _bitmaps[1]["PapayaGameplay_SkydiveGame"] = new MapLayer {Layer = skydiveBitmap, IsEnabled = false}; }); } + + private async Task LoadShootingTargets() + { + await _threadWorkerView.Begin(_ => + { + var shootingTargetsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(shootingTargetsBitmap); + + var bDone = false; + var exports = Utils.LoadExports("/PapayaGameplay/LevelOverlays/PapayaGameplay_ShootingTargets"); + foreach (var export in exports) + { + if (export is not { } uObject) continue; + if (!uObject.ExportType.Equals("PapayaShootingTarget_C", StringComparison.OrdinalIgnoreCase)) continue; + + if (!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || + !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + + var vector = GetMapPosition(relativeLocation, _prRadius); + c.DrawPoint(vector.X, vector.Y, _pathPaint); + if (bDone) continue; + + bDone = true; + c.DrawText("Shooting Target", vector.X, vector.Y - 12.5F, _imagePaint); + } + + _bitmaps[1]["PapayaGameplay_ShootingTargets"] = new MapLayer {Layer = shootingTargetsBitmap, IsEnabled = false}; + }); + } + + private async Task LoadWaypoint(EWaypointType type) + { + await _threadWorkerView.Begin(_ => + { + var waypointBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(waypointBitmap); + + string file; + string name; + switch (type) + { + case EWaypointType.Parkour: + file = "PapayaGameplay_ParkourGame"; + name = "Parkour"; + break; + case EWaypointType.TimeTrials: + file = "PapayaGameplay_TimeTrials"; + name = "Time Trials"; + break; + default: + throw new ArgumentOutOfRangeException(nameof(type), type, null); + } + + var path = new SKPath(); + var exports = Utils.LoadExports($"/PapayaGameplay/LevelOverlays/{file}"); + foreach (var export in exports) + { + if (export is not { } uObject) continue; + if (!uObject.ExportType.Equals("BP_Waypoint_Parent_Papaya_C", StringComparison.OrdinalIgnoreCase)) continue; + + if (!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || + !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + + var vector = GetMapPosition(relativeLocation, _prRadius); + if (path.IsEmpty) + { + path.MoveTo(vector.X, vector.Y); + c.DrawText(name, vector.X, vector.Y - 12.5F, _imagePaint); + } + else path.LineTo(vector.X, vector.Y); + } + path.Close(); + c.DrawPath(path, _pathPaint); + + _bitmaps[1][file] = new MapLayer {Layer = waypointBitmap, IsEnabled = false}; + }); + } + + private async Task LoadVendingMachines() + { + await _threadWorkerView.Begin(_ => + { + var set = new HashSet(); + var timeTrialsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(timeTrialsBitmap); + + var exports = Utils.LoadExports("/PapayaGameplay/LevelOverlays/PapayaGameplay_VendingMachines"); + foreach (var export in exports) + { + if (export is not { } uObject) continue; + if (!uObject.ExportType.Equals("B_Papaya_VendingMachine_Boat_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_BoogieBomb_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_Burger_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_CrashPad_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_FishingPole_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_Grappler_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_Jetpack_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_PaintGrenade_Blue_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_PaintGrenade_Red_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_PaintLauncher_Blue_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_PaintLauncher_Red_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_PlungerBow_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_Quad_C", StringComparison.OrdinalIgnoreCase) && + !uObject.ExportType.Equals("B_Papaya_VendingMachine_Tomato_C", StringComparison.OrdinalIgnoreCase)) continue; + + if (!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + !Utils.TryGetPackageIndexExport(rootComponent, out UObject root) || + !root.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + + var name = uObject.ExportType.SubstringAfter("B_Papaya_VendingMachine_").SubstringBeforeLast("_C"); + var vector = GetMapPosition(relativeLocation, _prRadius); + c.DrawPoint(vector.X, vector.Y, _pathPaint); + if (!set.Add(name)) continue; + + c.DrawText(name, vector.X, vector.Y - 12.5F, _imagePaint); + } + + _bitmaps[1]["PapayaGameplay_VendingMachines"] = new MapLayer {Layer = timeTrialsBitmap, IsEnabled = false}; + }); + } + + private async Task LoadMusicBlocks() + { + await _threadWorkerView.Begin(_ => + { + var shootingTargetsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(shootingTargetsBitmap); + + var bDone = false; + var exports = Utils.LoadExports("/PapayaGameplay/LevelOverlays/PapayaGameplay_MusicBlocks"); + foreach (var export in exports) + { + if (export is not { } uObject) continue; + if (!uObject.ExportType.Equals("MusicBlock_Piano3_Papaya_C", StringComparison.OrdinalIgnoreCase)) continue; + + if (!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || + !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + + var vector = GetMapPosition(relativeLocation, _prRadius); + c.DrawPoint(vector.X, vector.Y, _pathPaint); + if (bDone) continue; + + bDone = true; + c.DrawText("Music Blocks", vector.X, vector.Y - 12.5F, _imagePaint); + } + + _bitmaps[1]["PapayaGameplay_MusicBlocks"] = new MapLayer {Layer = shootingTargetsBitmap, IsEnabled = false}; + }); + } } } \ No newline at end of file diff --git a/FModel/Views/MapViewer.xaml b/FModel/Views/MapViewer.xaml index d4ed246e..973771bc 100644 --- a/FModel/Views/MapViewer.xaml +++ b/FModel/Views/MapViewer.xaml @@ -39,14 +39,16 @@ DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.MapViewer}}}" IsEnabled="{Binding IsReady}" /> - - - - - - - - + + + + + From aba44d5ea571455c785104cdfa71f19168f73774 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sat, 5 Jun 2021 06:54:01 +0200 Subject: [PATCH 35/68] cue4parse update --- CUE4Parse | 2 +- FModel/Views/Resources/Controls/AvalonEditor.xaml.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index b4b18abd..af4b6353 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit b4b18abd31a049b2c408a1867520ca06e5c8b144 +Subproject commit af4b6353b173e18e7349e27bded6fecb3eca1242 diff --git a/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs b/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs index 79e98951..ce634d9a 100644 --- a/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs +++ b/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs @@ -95,9 +95,8 @@ private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e) { if (DataContext is not TabItem tabItem || Keyboard.Modifiers != ModifierKeys.Control) return; - + var fontSize = tabItem.FontSize + e.Delta / 50.0; - tabItem.FontSize = fontSize switch { < 6 => 6, From a42a3fc6fd90dc5ae0a0be1e0f7c8a082e627d82 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sat, 5 Jun 2021 08:06:44 +0200 Subject: [PATCH 36/68] should fix some issues with the settings at launch --- FModel/FModel.csproj | 5 +++-- FModel/Settings/UserSettings.cs | 2 +- README.md | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index 3c3dbaf5..b51b3f6c 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -6,13 +6,14 @@ true FModel.ico 4.0.0 - 4.0.0.1 - 4.0.0.1 + 4.0.0.2 + 4.0.0.2 false true win-x64 true true + FModel.App diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index 1cc62682..80dbed81 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -303,7 +303,7 @@ public IDictionary> CustomDirectories set => SetProperty(ref _customDirectories, value); } - private DateTime _lastAesReload = DateTime.Today; + private DateTime _lastAesReload = DateTime.Today.AddDays(-1); public DateTime LastAesReload { get => _lastAesReload; diff --git a/README.md b/README.md index 231c93e3..fa56266b 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ## Installation To use FModel, you need to have **[.NET 5](https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-desktop-5.0.6-windows-x64-installer)** installed on your computer -* **[Download](https://github.com/iAmAsval/FModel/releases/latest/download/FModel.zip)** the latest release. +* **[Download](https://github.com/iAmAsval/FModel/releases/download/4.0.0.1/FModel.zip)** the latest release. * **Extract FModel.exe** somewhere on your PC and launch it ## Authors From 3ce2fb1430903353fbafc2089e7b28d2b1e13dcd Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sat, 5 Jun 2021 08:49:51 +0200 Subject: [PATCH 37/68] fixed party royale time trials path --- FModel/ViewModels/MapViewerViewModel.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/FModel/ViewModels/MapViewerViewModel.cs b/FModel/ViewModels/MapViewerViewModel.cs index 432b6a6f..4996b74e 100644 --- a/FModel/ViewModels/MapViewerViewModel.cs +++ b/FModel/ViewModels/MapViewerViewModel.cs @@ -434,7 +434,6 @@ await _threadWorkerView.Begin(_ => path.LineTo(vector.X, vector.Y); } - path.Close(); c.DrawPath(path, _pathPaint); c.DrawText(gameplayTags.GameplayTags[0].Text.SubstringAfterLast("."), vector.X, vector.Y - 12.5F, _imagePaint); } @@ -559,19 +558,22 @@ await _threadWorkerView.Begin(_ => if (!uObject.ExportType.Equals("BP_Waypoint_Parent_Papaya_C", StringComparison.OrdinalIgnoreCase)) continue; if (!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || - !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || - !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; - + !Utils.TryGetPackageIndexExport(rootComponent, out UObject root) || + !root.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + var vector = GetMapPosition(relativeLocation, _prRadius); - if (path.IsEmpty) + if (path.IsEmpty || uObject.TryGetValue(out bool startsTrial, "StartsTrial") && startsTrial) { path.MoveTo(vector.X, vector.Y); c.DrawText(name, vector.X, vector.Y - 12.5F, _imagePaint); } + else if (uObject.TryGetValue(out bool endsTrial, "EndsTrial") && endsTrial) + { + c.DrawPath(path, _pathPaint); + path = new SKPath(); + } else path.LineTo(vector.X, vector.Y); } - path.Close(); - c.DrawPath(path, _pathPaint); _bitmaps[1][file] = new MapLayer {Layer = waypointBitmap, IsEnabled = false}; }); From 60e23373f3106ec1e8b484f004ce7344f4857d6f Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Mon, 7 Jun 2021 17:12:09 +0200 Subject: [PATCH 38/68] more discord rpc --- CUE4Parse | 2 +- FModel/Services/DiscordService.cs | 8 ++++---- FModel/ViewModels/AudioPlayerViewModel.cs | 3 +++ FModel/ViewModels/MapViewerViewModel.cs | 7 +++++++ FModel/Views/AudioPlayer.xaml.cs | 1 + FModel/Views/MapViewer.xaml | 2 +- FModel/Views/MapViewer.xaml.cs | 5 ++++- 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index af4b6353..46229801 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit af4b6353b173e18e7349e27bded6fecb3eca1242 +Subproject commit 462298018f5e0b148bde654ae96dd4275080d4ef diff --git a/FModel/Services/DiscordService.cs b/FModel/Services/DiscordService.cs index 0b1380b5..156a0422 100644 --- a/FModel/Services/DiscordService.cs +++ b/FModel/Services/DiscordService.cs @@ -38,7 +38,7 @@ public void Initialize(FGame game) Assets = _staticAssets, Timestamps = _timestamps, Buttons = _buttons, - State = $"{game.GetDescription()} - Idling" + Details = $"{game.GetDescription()} - Idling" }; _client.OnReady += (_, args) => Log.Information("{Username}#{Discriminator} ({UserId}) is now ready", args.User.Username, args.User.Discriminator, args.User.ID); @@ -60,7 +60,7 @@ public void UpdatePresence(string details, string state) _client.Invoke(); } - public void UpdateButDontSavePresence(string details, string state) + public void UpdateButDontSavePresence(string details = null, string state = null) { if (!_client.IsInitialized) return; _client.SetPresence(new RichPresence @@ -68,8 +68,8 @@ public void UpdateButDontSavePresence(string details, string state) Assets = _staticAssets, Timestamps = _timestamps, Buttons = _buttons, - Details = details, - State = state + Details = details ?? _currentPresence.Details, + State = state ?? _currentPresence.State }); _client.Invoke(); } diff --git a/FModel/ViewModels/AudioPlayerViewModel.cs b/FModel/ViewModels/AudioPlayerViewModel.cs index f4bb64ff..7d0c7ce6 100644 --- a/FModel/ViewModels/AudioPlayerViewModel.cs +++ b/FModel/ViewModels/AudioPlayerViewModel.cs @@ -15,6 +15,7 @@ using CSCore.CoreAudioAPI; using FModel.Extensions; using FModel.Framework; +using FModel.Services; using FModel.Settings; using FModel.ViewModels.Commands; using FModel.Views.Resources.Controls; @@ -154,6 +155,7 @@ public override string ToString() public class AudioPlayerViewModel : ViewModel, ISource, IDisposable { + private DiscordHandler _discordHandler => DiscordService.DiscordHandler; private static IWaveSource _waveSource; private static ISoundOut _soundOut; private Timer _sourceTimer; @@ -385,6 +387,7 @@ public void Previous() public void Play() { if (_soundOut == null || IsPlaying) return; + _discordHandler.UpdateButDontSavePresence(null, $"Audio Player: {PlayedFile.FileName} ({PlayedFile.Duration:g})"); _soundOut.Play(); } diff --git a/FModel/ViewModels/MapViewerViewModel.cs b/FModel/ViewModels/MapViewerViewModel.cs index 4996b74e..2b5adc77 100644 --- a/FModel/ViewModels/MapViewerViewModel.cs +++ b/FModel/ViewModels/MapViewerViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using System.Windows.Media.Imaging; using CUE4Parse.UE4.Assets.Exports; @@ -34,6 +35,7 @@ public enum EWaypointType public class MapViewerViewModel : ViewModel { private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView; + private DiscordHandler _discordHandler => DiscordService.DiscordHandler; #region BINDINGS @@ -267,13 +269,17 @@ private BitmapImage GetImageSource(SKBitmap bitmap) private void TriggerChange() { + var layerCount = _bitmaps[_mapIndex].Count(x => x.Value.IsEnabled); + var layerString = $"{layerCount} Layer{(layerCount > 1 ? "s" : "")}"; switch (_mapIndex) { case 0: + _discordHandler.UpdateButDontSavePresence(null, $"Map Viewer: Battle Royale ({layerString})"); _mapImage = _brMiniMapImage; _layerImage = _brLayerImage; break; case 1: + _discordHandler.UpdateButDontSavePresence(null, $"Map Viewer: Party Royale ({layerString})"); _mapImage = _prMiniMapImage; _layerImage = _prLayerImage; break; @@ -569,6 +575,7 @@ await _threadWorkerView.Begin(_ => } else if (uObject.TryGetValue(out bool endsTrial, "EndsTrial") && endsTrial) { + path.LineTo(vector.X, vector.Y); c.DrawPath(path, _pathPaint); path = new SKPath(); } diff --git a/FModel/Views/AudioPlayer.xaml.cs b/FModel/Views/AudioPlayer.xaml.cs index c2cad795..53da1f43 100644 --- a/FModel/Views/AudioPlayer.xaml.cs +++ b/FModel/Views/AudioPlayer.xaml.cs @@ -30,6 +30,7 @@ private void OnClosing(object sender, CancelEventArgs e) { _applicationView.AudioPlayer.Stop(); _applicationView.AudioPlayer.Dispose(); + DiscordService.DiscordHandler.UpdateToSavedPresence(); } private void OnDeviceSwap(object sender, SelectionChangedEventArgs e) diff --git a/FModel/Views/MapViewer.xaml b/FModel/Views/MapViewer.xaml index 973771bc..1f27cfc1 100644 --- a/FModel/Views/MapViewer.xaml +++ b/FModel/Views/MapViewer.xaml @@ -6,7 +6,7 @@ xmlns:converters="clr-namespace:FModel.Views.Resources.Converters" xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI" xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI" - WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" SizeToContent="Width" ResizeMode="CanMinimize" + WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" SizeToContent="Width" ResizeMode="CanMinimize" Closing="OnClosing" Height="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.75'}" MinWidth="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.50'}"> diff --git a/FModel/Views/MapViewer.xaml.cs b/FModel/Views/MapViewer.xaml.cs index 16da3b4b..80f888e4 100644 --- a/FModel/Views/MapViewer.xaml.cs +++ b/FModel/Views/MapViewer.xaml.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.ComponentModel; +using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; @@ -24,6 +25,8 @@ public MapViewer() InitializeComponent(); } + private void OnClosing(object sender, CancelEventArgs e) => DiscordService.DiscordHandler.UpdateToSavedPresence(); + private void OnClick(object sender, RoutedEventArgs e) { if (_applicationView.MapViewer.MapImage == null) return; From 5eaa6c5c922ccee3aaf1b94765e12362669eb7ca Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Tue, 8 Jun 2021 01:05:36 +0200 Subject: [PATCH 39/68] just testing --- CUE4Parse | 2 +- FModel/App.xaml.cs | 7 +++++++ FModel/FModel.csproj | 1 + FModel/MainWindow.xaml.cs | 2 ++ FModel/ViewModels/ThreadWorkerViewModel.cs | 3 +++ 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index 46229801..79d7ab43 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 462298018f5e0b148bde654ae96dd4275080d4ef +Subproject commit 79d7ab436fc91c072f8b0ddea1df37e097ca0fb4 diff --git a/FModel/App.xaml.cs b/FModel/App.xaml.cs index c0692264..7b72fa9c 100644 --- a/FModel/App.xaml.cs +++ b/FModel/App.xaml.cs @@ -11,6 +11,7 @@ using FModel.Services; using FModel.Settings; using Newtonsoft.Json; +using Sentry; using Serilog.Sinks.SystemConsole.Themes; using MessageBox = AdonisUI.Controls.MessageBox; using MessageBoxImage = AdonisUI.Controls.MessageBoxImage; @@ -26,6 +27,12 @@ public partial class App protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); + SentrySdk.Init(options => + { + options.Dsn = "https://2e872a5034c940e787015e5d07e7d82e@o811367.ingest.sentry.io/5805297"; + options.TracesSampleRate = 1.0; + options.AddExceptionFilterForType(); + }); try { diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index b51b3f6c..2714810b 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -111,6 +111,7 @@ + diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index 6b9cb43b..6da880e6 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -12,6 +12,7 @@ using FModel.Views; using FModel.Views.Resources.Controls; using ICSharpCode.AvalonEdit.Editing; +using Sentry; namespace FModel { @@ -53,6 +54,7 @@ private void OnClosing(object sender, CancelEventArgs e) { _applicationView.CustomDirectories.Save(); _discordHandler.Dispose(); + SentrySdk.Close(); } private async void OnLoaded(object sender, RoutedEventArgs e) diff --git a/FModel/ViewModels/ThreadWorkerViewModel.cs b/FModel/ViewModels/ThreadWorkerViewModel.cs index f1f7f5f0..f403e99c 100644 --- a/FModel/ViewModels/ThreadWorkerViewModel.cs +++ b/FModel/ViewModels/ThreadWorkerViewModel.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using FModel.Views.Resources.Controls; +using Sentry; using Serilog; namespace FModel.ViewModels @@ -96,6 +97,8 @@ private async Task ProcessQueues() CurrentCancellationTokenSource = null; // kill token Log.Error("{Exception}", e); + SentrySdk.CaptureException(e); + FLogger.AppendError(); FLogger.AppendText(e.Message, Constants.WHITE, true); return; From e9470242ebe56e27c5fd1000f25b8a080e1784c9 Mon Sep 17 00:00:00 2001 From: Alex Tusinean Date: Tue, 8 Jun 2021 11:00:46 +0300 Subject: [PATCH 40/68] this wasn't really needed but --- FModel/ViewModels/ApiEndpoints/FModelApi.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/FModel/ViewModels/ApiEndpoints/FModelApi.cs b/FModel/ViewModels/ApiEndpoints/FModelApi.cs index 5ba50e5a..5e6fa2c3 100644 --- a/FModel/ViewModels/ApiEndpoints/FModelApi.cs +++ b/FModel/ViewModels/ApiEndpoints/FModelApi.cs @@ -13,6 +13,7 @@ using MessageBoxButton = AdonisUI.Controls.MessageBoxButton; using MessageBoxImage = AdonisUI.Controls.MessageBoxImage; using MessageBoxResult = AdonisUI.Controls.MessageBoxResult; +using FModel.Settings; namespace FModel.ViewModels.ApiEndpoints { @@ -109,11 +110,14 @@ private void CheckForUpdateEvent(UpdateInfoEventArgs args) { if (args != null) { - if (new Version(args.CurrentVersion) == args.InstalledVersion) return; + Version currentVersion = new Version(args.CurrentVersion); + if (currentVersion == args.InstalledVersion) return; + + bool downgrade = currentVersion < args.InstalledVersion; var messageBox = new MessageBoxModel { - Text = $"FModel {args.CurrentVersion} is available. You are using version {args.InstalledVersion}. Do you want to update the application now?", - Caption = "Update Available", + Text = $"The latest version of FModel {UserSettings.Default.UpdateMode} is {args.CurrentVersion}. You are using version {args.InstalledVersion}. Do you want to {(downgrade ? "downgrade" : "update")} the application now?", + Caption = $"{(downgrade ? "Downgrade" : "Update")} Available", Icon = MessageBoxImage.Question, Buttons = MessageBoxButtons.YesNo(), IsSoundEnabled = false From 95d013e95e2a106e04e2157690b634376115f23b Mon Sep 17 00:00:00 2001 From: Alex Tusinean Date: Tue, 8 Jun 2021 11:03:30 +0300 Subject: [PATCH 41/68] move import --- FModel/ViewModels/ApiEndpoints/FModelApi.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FModel/ViewModels/ApiEndpoints/FModelApi.cs b/FModel/ViewModels/ApiEndpoints/FModelApi.cs index 5e6fa2c3..e80267dd 100644 --- a/FModel/ViewModels/ApiEndpoints/FModelApi.cs +++ b/FModel/ViewModels/ApiEndpoints/FModelApi.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using System.Windows; using AutoUpdaterDotNET; +using FModel.Settings; using FModel.ViewModels.ApiEndpoints.Models; using Newtonsoft.Json; using RestSharp; @@ -13,7 +14,6 @@ using MessageBoxButton = AdonisUI.Controls.MessageBoxButton; using MessageBoxImage = AdonisUI.Controls.MessageBoxImage; using MessageBoxResult = AdonisUI.Controls.MessageBoxResult; -using FModel.Settings; namespace FModel.ViewModels.ApiEndpoints { From 93866684f07b0dfe048bd740383836e714ca4991 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Tue, 8 Jun 2021 16:18:32 +0200 Subject: [PATCH 42/68] fixed season icons but will change --- CUE4Parse | 2 +- FModel/App.xaml.cs | 8 ++ FModel/Creator/Bases/FN/BaseSeason.cs | 111 +++++++++----------- FModel/ViewModels/ApiEndpoints/FModelApi.cs | 6 +- 4 files changed, 63 insertions(+), 64 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 79d7ab43..6399d6a7 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 79d7ab436fc91c072f8b0ddea1df37e097ca0fb4 +Subproject commit 6399d6a7c7b5cb07e2ebfee1687d56880d494aef diff --git a/FModel/App.xaml.cs b/FModel/App.xaml.cs index 7b72fa9c..1263cd5e 100644 --- a/FModel/App.xaml.cs +++ b/FModel/App.xaml.cs @@ -30,6 +30,13 @@ protected override void OnStartup(StartupEventArgs e) SentrySdk.Init(options => { options.Dsn = "https://2e872a5034c940e787015e5d07e7d82e@o811367.ingest.sentry.io/5805297"; +#if DEBUG + options.Environment = "dev"; +#elif RELEASE + options.Environment = "prod"; +#else + options.Environment = "what"; +#endif options.TracesSampleRate = 1.0; options.AddExceptionFilterForType(); }); @@ -79,6 +86,7 @@ private void AppExit(object sender, ExitEventArgs e) private void OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { Log.Error("{Exception}", e.Exception); + SentrySdk.CaptureException(e.Exception); var messageBox = new MessageBoxModel { diff --git a/FModel/Creator/Bases/FN/BaseSeason.cs b/FModel/Creator/Bases/FN/BaseSeason.cs index c39be25c..a4f9a3cd 100644 --- a/FModel/Creator/Bases/FN/BaseSeason.cs +++ b/FModel/Creator/Bases/FN/BaseSeason.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using System.Linq; using CUE4Parse.UE4.Assets.Exports; using CUE4Parse.UE4.Assets.Objects; using CUE4Parse.UE4.Objects.Core.i18N; @@ -10,10 +10,17 @@ namespace FModel.Creator.Bases.FN { + public class Page + { + public int LevelsNeededForUnlock; + public int RewardsNeededForUnlock; + public Reward[] RewardEntryList; + } + public class BaseSeason : UCreator { private Reward _firstWinReward; - private Dictionary> _bookXpSchedule; + private Page[] _bookXpSchedule; private const int _headerHeight = 150; // keep the list because rewards are ordered by least to most important // we only care about the most but we also have filters so we can't just take the last reward @@ -27,8 +34,8 @@ public BaseSeason(UObject uObject, EIconStyle style) : base(uObject, style) public override void ParseForInfo() { - _bookXpSchedule = new Dictionary>(); - + _bookXpSchedule = Array.Empty(); + if (Object.TryGetValue(out FText displayName, "DisplayName")) DisplayName = displayName.Text.ToUpperInvariant(); @@ -45,56 +52,48 @@ public override void ParseForInfo() } } - var freeLevels = Array.Empty(); - var paidLevels = Array.Empty(); - if (Object.TryGetValue(out FPackageIndex[] additionalSeasonData, "AdditionalSeasonData") && - additionalSeasonData.Length > 0 && Utils.TryGetPackageIndexExport(additionalSeasonData[0], out UObject data) && - data.TryGetValue(out FStructFallback battlePassXpScheduleFree, "BattlePassXpScheduleFree") && - battlePassXpScheduleFree.TryGetValue(out freeLevels, "Levels") && - data.TryGetValue(out FStructFallback battlePassXpSchedulePaid, "BattlePassXpSchedulePaid") && - battlePassXpSchedulePaid.TryGetValue(out paidLevels, "Levels")) + if (Object.TryGetValue(out FPackageIndex[] additionalSeasonData, "AdditionalSeasonData")) { - // we got them boys - } - else if (Object.TryGetValue(out FStructFallback bookXpScheduleFree, "BookXpScheduleFree") && - bookXpScheduleFree.TryGetValue(out freeLevels, "Levels") && - Object.TryGetValue(out FStructFallback bookXpSchedulePaid, "BookXpSchedulePaid") && - bookXpSchedulePaid.TryGetValue(out paidLevels, "Levels")) - { - // we got them boys - } - - for (var i = 0; i < freeLevels.Length; i++) - { - _bookXpSchedule[i] = new List(); - if (!freeLevels[i].TryGetValue(out rewards, "Rewards")) continue; - - foreach (var reward in rewards) + foreach (var data in additionalSeasonData) { - if (!reward.TryGetValue(out FSoftObjectPath itemDefinition, "ItemDefinition") || - itemDefinition.AssetPathName.Text.Contains("/Items/Tokens/") || - !Utils.TryLoadObject(itemDefinition.AssetPathName.Text, out UObject uObject)) continue; - - _bookXpSchedule[i].Add(new Reward(uObject)); - break; - } - } - - for (var i = 0; i < paidLevels.Length; i++) - { - if (!paidLevels[i].TryGetValue(out rewards, "Rewards")) continue; + if (!Utils.TryGetPackageIndexExport(data, out UObject packageIndex) || + !packageIndex.TryGetValue(out FStructFallback[] pageList, "PageList")) continue; + + var i = 0; + _bookXpSchedule = new Page[pageList.Length]; + foreach (var page in pageList) + { + if (!page.TryGetValue(out int levelsNeededForUnlock, "LevelsNeededForUnlock") || + !page.TryGetValue(out int rewardsNeededForUnlock, "RewardsNeededForUnlock") || + !page.TryGetValue(out FPackageIndex[] rewardEntryList, "RewardEntryList")) + continue; + + var p = new Page + { + LevelsNeededForUnlock = levelsNeededForUnlock, + RewardsNeededForUnlock = rewardsNeededForUnlock, + RewardEntryList = new Reward[rewardEntryList.Length] + }; + + for (var j = 0; j < p.RewardEntryList.Length; j++) + { + if (!Utils.TryGetPackageIndexExport(rewardEntryList[j], out packageIndex) || + !packageIndex.TryGetValue(out FStructFallback battlePassOffer, "BattlePassOffer") || + !battlePassOffer.TryGetValue(out FStructFallback rewardItem, "RewardItem") || + !rewardItem.TryGetValue(out FSoftObjectPath itemDefinition, "ItemDefinition") || + !Utils.TryLoadObject(itemDefinition.AssetPathName.Text, out UObject uObject)) continue; + + p.RewardEntryList[j] = new Reward(uObject); + } + + _bookXpSchedule[i++] = p; + } - foreach (var reward in rewards) - { - if (!reward.TryGetValue(out FSoftObjectPath itemDefinition, "ItemDefinition") || - !Utils.TryLoadObject(itemDefinition.AssetPathName.Text, out UObject uObject)) continue; - - _bookXpSchedule[i].Add(new Reward(uObject)); break; } } - Height += 100 * _bookXpSchedule.Count / 10; + Height += 100 * _bookXpSchedule.Sum(x => x.RewardEntryList.Length) / _bookXpSchedule.Length; } public override SKImage Draw() @@ -151,23 +150,15 @@ private void DrawBookSchedule(SKCanvas c) { var x = 20; var y = _headerHeight + 50; - foreach (var (index, reward) in _bookXpSchedule) + foreach (var page in _bookXpSchedule) { - if (index == 0 || reward.Count == 0 || !reward[0].HasReward()) - continue; - - c.DrawText(index.ToString(), new SKPoint(x + _DEFAULT_AREA_SIZE / 2, y - 5), _bookPaint); - reward[0].DrawSeason(c, x, y, _DEFAULT_AREA_SIZE); - - if (index != 1 && index % 10 == 0) - { - y += _DEFAULT_AREA_SIZE + 20; - x = 20; - } - else + foreach (var reward in page.RewardEntryList) { + reward.DrawSeason(c, x, y, _DEFAULT_AREA_SIZE); x += _DEFAULT_AREA_SIZE + 20; } + y += _DEFAULT_AREA_SIZE + 20; + x = 20; } } } diff --git a/FModel/ViewModels/ApiEndpoints/FModelApi.cs b/FModel/ViewModels/ApiEndpoints/FModelApi.cs index e80267dd..73041505 100644 --- a/FModel/ViewModels/ApiEndpoints/FModelApi.cs +++ b/FModel/ViewModels/ApiEndpoints/FModelApi.cs @@ -108,12 +108,12 @@ private void ParseUpdateInfoEvent(ParseUpdateInfoEventArgs args) private void CheckForUpdateEvent(UpdateInfoEventArgs args) { - if (args != null) + if (args is {CurrentVersion: { }}) { - Version currentVersion = new Version(args.CurrentVersion); + var currentVersion = new Version(args.CurrentVersion); if (currentVersion == args.InstalledVersion) return; - bool downgrade = currentVersion < args.InstalledVersion; + var downgrade = currentVersion < args.InstalledVersion; var messageBox = new MessageBoxModel { Text = $"The latest version of FModel {UserSettings.Default.UpdateMode} is {args.CurrentVersion}. You are using version {args.InstalledVersion}. Do you want to {(downgrade ? "downgrade" : "update")} the application now?", From 2bde70ff2db1171260d37201e608bb7817b2e9d7 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Wed, 9 Jun 2021 00:06:05 +0200 Subject: [PATCH 43/68] binded BitmapScalingMode --- CUE4Parse | 2 +- FModel/ViewModels/CUE4ParseViewModel.cs | 10 +++++++++- FModel/ViewModels/Commands/ImageCommand.cs | 7 +++++-- FModel/ViewModels/TabControlViewModel.cs | 8 ++++++++ FModel/Views/Resources/Resources.xaml | 2 +- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 6399d6a7..9b8b311b 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 6399d6a7c7b5cb07e2ebfee1687d56880d494aef +Subproject commit 9b8b311b7b253b4f54260e819596910c80008240 diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 705eacba..8a2c6140 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; +using System.Windows.Media; using System.Windows.Media.Imaging; using AdonisUI.Controls; using CUE4Parse.Encryption.Aes; @@ -19,6 +20,7 @@ using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Assets.Exports.Wwise; using CUE4Parse.UE4.Localization; +using CUE4Parse.UE4.Objects.UObject; using CUE4Parse.UE4.Oodle.Objects; using CUE4Parse.UE4.Wwise; using CUE4Parse_Conversion.Materials; @@ -540,7 +542,13 @@ public void ExtractAndScroll(string fullPath, string objectName) { case UTexture2D texture: { - SetImage(texture.Decode()); + var bNearest = false; + if (texture.TryGetValue(out FName trigger, "LODGroup", "Filter") && !trigger.IsNone) + bNearest = trigger.Text.EndsWith("TEXTUREGROUP_Pixels2D", StringComparison.OrdinalIgnoreCase) || + trigger.Text.EndsWith("TF_Nearest", StringComparison.OrdinalIgnoreCase); + + TabControl.SelectedTab.ImageRender = bNearest ? BitmapScalingMode.NearestNeighbor : BitmapScalingMode.Linear; + SetImage(texture.Decode(bNearest)); return true; } case UAkMediaAssetData: diff --git a/FModel/ViewModels/Commands/ImageCommand.cs b/FModel/ViewModels/Commands/ImageCommand.cs index 18b8c38d..59d7a5e7 100644 --- a/FModel/ViewModels/Commands/ImageCommand.cs +++ b/FModel/ViewModels/Commands/ImageCommand.cs @@ -1,4 +1,5 @@ using System.Windows; +using System.Windows.Media; using AdonisUI.Controls; using FModel.Framework; using FModel.Views.Resources.Controls; @@ -21,14 +22,16 @@ public override void Execute(TabItem contextViewModel, object parameter) { Helper.OpenWindow(contextViewModel.Header + " (Image)", () => { - new ImagePopout + var popout = new ImagePopout { Title = contextViewModel.Header + " (Image)", Width = contextViewModel.Image.Width, Height = contextViewModel.Image.Height, WindowState = contextViewModel.Image.Height > 1000 ? WindowState.Maximized : WindowState.Normal, ImageCtrl = {Source = contextViewModel.Image} - }.Show(); + }; + RenderOptions.SetBitmapScalingMode(popout.ImageCtrl, contextViewModel.ImageRender); + popout.Show(); }); break; } diff --git a/FModel/ViewModels/TabControlViewModel.cs b/FModel/ViewModels/TabControlViewModel.cs index 0b07f22c..458bec22 100644 --- a/FModel/ViewModels/TabControlViewModel.cs +++ b/FModel/ViewModels/TabControlViewModel.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Windows; +using System.Windows.Media; using System.Windows.Media.Imaging; using FModel.Extensions; using FModel.Settings; @@ -125,6 +126,13 @@ public BitmapImage Image } } + private BitmapScalingMode _imageRender = BitmapScalingMode.Linear; + public BitmapScalingMode ImageRender + { + get => _imageRender; + set => SetProperty(ref _imageRender, value); + } + public bool HasImage => Image != null; public bool ShouldScroll => !string.IsNullOrEmpty(ScrollTrigger); diff --git a/FModel/Views/Resources/Resources.xaml b/FModel/Views/Resources/Resources.xaml index 95653e2a..387a134c 100644 --- a/FModel/Views/Resources/Resources.xaml +++ b/FModel/Views/Resources/Resources.xaml @@ -647,7 +647,7 @@ + Source="{Binding SelectedItem.Image, ElementName=TabControlName}" RenderOptions.BitmapScalingMode="{Binding SelectedItem.ImageRender, ElementName=TabControlName}"> From d74f7b1372b7f898cec9513536ef9cf46359b876 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Wed, 9 Jun 2021 09:41:23 +0200 Subject: [PATCH 44/68] fixed a few aes problems --- FModel/ViewModels/AesManagerViewModel.cs | 43 +++++++++++-------- .../ApiEndpoints/Models/AesResponse.cs | 7 +-- FModel/ViewModels/CUE4ParseViewModel.cs | 2 +- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/FModel/ViewModels/AesManagerViewModel.cs b/FModel/ViewModels/AesManagerViewModel.cs index aeb1c9e5..c81ca5eb 100644 --- a/FModel/ViewModels/AesManagerViewModel.cs +++ b/FModel/ViewModels/AesManagerViewModel.cs @@ -64,28 +64,35 @@ private void AesKeysOnItemPropertyChanged(object sender, ItemPropertyChangedEven _keysFromSettings.MainKey = key; } - else + else if (!_keysFromSettings.HasDynamicKeys) { - if (!_keysFromSettings.HasDynamicKeys) + HasChange = true; + _keysFromSettings.DynamicKeys = new List { - HasChange = true; - _keysFromSettings.DynamicKeys = new[] + new() { - new DynamicKey - { - Key = key, - FileName = collection[e.CollectionIndex].Name, - Guid = collection[e.CollectionIndex].Guid.ToString() - } - }; - } - else if (_keysFromSettings.DynamicKeys.FirstOrDefault(x => x.Guid == collection[e.CollectionIndex].Guid.ToString()) is { } d) - { - if (!HasChange) - HasChange = FixKey(d.Key) != key; + Key = key, + FileName = collection[e.CollectionIndex].Name, + Guid = collection[e.CollectionIndex].Guid.ToString() + } + }; + } + else if (_keysFromSettings.DynamicKeys.FirstOrDefault(x => x.Guid == collection[e.CollectionIndex].Guid.ToString()) is { } d) + { + if (!HasChange) + HasChange = FixKey(d.Key) != key; - d.Key = key; - } + d.Key = key; + } + else + { + HasChange = true; + _keysFromSettings.DynamicKeys.Add(new DynamicKey + { + Key = key, + FileName = collection[e.CollectionIndex].Name, + Guid = collection[e.CollectionIndex].Guid.ToString() + }); } } diff --git a/FModel/ViewModels/ApiEndpoints/Models/AesResponse.cs b/FModel/ViewModels/ApiEndpoints/Models/AesResponse.cs index 5d1c9071..64b8e410 100644 --- a/FModel/ViewModels/ApiEndpoints/Models/AesResponse.cs +++ b/FModel/ViewModels/ApiEndpoints/Models/AesResponse.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System.Collections.Generic; +using System.Diagnostics; using J = Newtonsoft.Json.JsonPropertyAttribute; namespace FModel.ViewModels.ApiEndpoints.Models @@ -8,9 +9,9 @@ public class AesResponse { [J("version")] public string Version { get; private set; } [J("mainKey")] public string MainKey { get; set; } - [J("dynamicKeys")] public DynamicKey[] DynamicKeys { get; set; } + [J("dynamicKeys")] public List DynamicKeys { get; set; } - public bool HasDynamicKeys => DynamicKeys is {Length: > 0}; + public bool HasDynamicKeys => DynamicKeys is {Count: > 0}; } [DebuggerDisplay("{" + nameof(Key) + "}")] diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 8a2c6140..68702061 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -243,7 +243,7 @@ public async Task RefreshAes() await _threadWorkerView.Begin(cancellationToken => { var aes = _apiEndpointView.BenbotApi.GetAesKeys(cancellationToken); - if (aes == null) return; + if (aes?.MainKey == null && aes?.DynamicKeys == null && aes?.Version == null) return; UserSettings.Default.AesKeys[Game] = aes; }); From e98a113d13806ec39ac89f2bfd06da5ad911e1ab Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Wed, 9 Jun 2021 12:46:02 +0200 Subject: [PATCH 45/68] improved mapviewer readability --- FModel/ViewModels/MapViewerViewModel.cs | 66 ++++++++++++++++++------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/FModel/ViewModels/MapViewerViewModel.cs b/FModel/ViewModels/MapViewerViewModel.cs index 2b5adc77..c3843863 100644 --- a/FModel/ViewModels/MapViewerViewModel.cs +++ b/FModel/ViewModels/MapViewerViewModel.cs @@ -171,7 +171,7 @@ public MapViewerViewModel(CUE4ParseViewModel cue4Parse) public async void Initialize() { Utils.Typefaces ??= new Typefaces(_cue4Parse); - _imagePaint.Typeface = Utils.Typefaces.Bottom ?? Utils.Typefaces.DisplayName; + _textPaint.Typeface = _fillPaint.Typeface = Utils.Typefaces.Bottom ?? Utils.Typefaces.DisplayName; await LoadBrMiniMap(); await LoadPrMiniMap(); TriggerChange(); @@ -289,11 +289,16 @@ private void TriggerChange() RaisePropertyChanged(nameof(LayerImage)); } - private readonly SKPaint _imagePaint = new() + private readonly SKPaint _textPaint = new() { IsAntialias = true, FilterQuality = SKFilterQuality.High, - Color = SKColors.White, TextAlign = SKTextAlign.Center, TextSize = 25, - ImageFilter = SKImageFilter.CreateDropShadow(4, 4, 8, 8, SKColors.Black) + Color = SKColors.White, TextAlign = SKTextAlign.Center, TextSize = 26 + }; + private readonly SKPaint _fillPaint = new() + { + IsAntialias = true, FilterQuality = SKFilterQuality.High, + IsStroke = true, Color = SKColors.Black, TextSize = 26, + TextAlign = SKTextAlign.Center }; private readonly SKPaint _pathPaint = new() { @@ -364,26 +369,31 @@ await _threadWorkerView.Begin(_ => !poiData.TryGetValue(out FVector worldLocation, "WorldLocation") || !poiData.TryGetValue(out FName discoverBackend, "DiscoverObjectiveBackendName")) continue; - var shaper = new CustomSKShaper(_imagePaint.Typeface); - var shapedText = shaper.Shape(text.Text, _imagePaint); + var shaper = new CustomSKShaper(_textPaint.Typeface); + var shapedText = shaper.Shape(text.Text, _textPaint); if (discoverBackend.Text.Contains("papaya", StringComparison.OrdinalIgnoreCase)) { + _fillPaint.StrokeWidth = 5; var vector = GetMapPosition(worldLocation, _prRadius); prLandmarks.DrawPoint(vector.X, vector.Y, _pathPaint); - prLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _imagePaint); + prLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _fillPaint); + prLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _textPaint); } else if (discoveryQuest.AssetPathName.Text.Contains("landmarks", StringComparison.OrdinalIgnoreCase)) { + _fillPaint.StrokeWidth = 5; var vector = GetMapPosition(worldLocation, _brRadius); brLandmarks.DrawPoint(vector.X, vector.Y, _pathPaint); - brLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _imagePaint); + brLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _fillPaint); + brLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _textPaint); } else { + _fillPaint.StrokeWidth = 10; var vector = GetMapPosition(worldLocation, _brRadius); - pois.DrawPoint(vector.X, vector.Y, _pathPaint); - pois.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _imagePaint); + pois.DrawShapedText(shaper, text.Text.ToUpperInvariant(), vector.X - shapedText.Points[^1].X / 2, vector.Y, _fillPaint); + pois.DrawShapedText(shaper, text.Text.ToUpperInvariant(), vector.X - shapedText.Points[^1].X / 2, vector.Y, _textPaint); } } } @@ -398,6 +408,7 @@ private async Task LoadPatrolsPath() { await _threadWorkerView.Begin(_ => { + _fillPaint.StrokeWidth = 5; var patrolsPathBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); using var c = new SKCanvas(patrolsPathBitmap); @@ -420,6 +431,9 @@ await _threadWorkerView.Begin(_ => !uObject.TryGetValue(out FGameplayTagContainer gameplayTags, "GameplayTags") || !uObject.TryGetValue(out FPackageIndex[] patrolPoints, "PatrolPoints")) continue; + var displayName = gameplayTags.GameplayTags[0].Text.SubstringAfterLast("."); + if (displayName.Equals("Generic", StringComparison.OrdinalIgnoreCase)) continue; + if (!Utils.TryGetPackageIndexExport(patrolPoints[0], out uObject) || !uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || @@ -439,9 +453,10 @@ await _threadWorkerView.Begin(_ => vector = GetMapPosition(relativeLocation, _brRadius); path.LineTo(vector.X, vector.Y); } - + c.DrawPath(path, _pathPaint); - c.DrawText(gameplayTags.GameplayTags[0].Text.SubstringAfterLast("."), vector.X, vector.Y - 12.5F, _imagePaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint); } } @@ -453,6 +468,7 @@ private async Task LoadCannonballGame() { await _threadWorkerView.Begin(_ => { + _fillPaint.StrokeWidth = 5; var cannonballBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); using var c = new SKCanvas(cannonballBitmap); @@ -467,9 +483,12 @@ await _threadWorkerView.Begin(_ => !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + var displayName = Utils.GetLocalizedResource("", "D998BEF44F051E0885C6C58565934BEA", "Cannonball"); var vector = GetMapPosition(relativeLocation, _prRadius); + c.DrawPoint(vector.X, vector.Y, _pathPaint); - c.DrawText(Utils.GetLocalizedResource("", "D998BEF44F051E0885C6C58565934BEA", "Cannonball"), vector.X, vector.Y - 12.5F, _imagePaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint); } _bitmaps[1]["PapayaGameplay_CannonballGame"] = new MapLayer {Layer = cannonballBitmap, IsEnabled = false}; @@ -480,6 +499,7 @@ private async Task LoadSkydiveGame() { await _threadWorkerView.Begin(_ => { + _fillPaint.StrokeWidth = 5; var skydiveBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); using var c = new SKCanvas(skydiveBitmap); @@ -495,8 +515,10 @@ await _threadWorkerView.Begin(_ => !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; var vector = GetMapPosition(relativeLocation, _prRadius); + c.DrawPoint(vector.X, vector.Y, _pathPaint); - c.DrawText(minigameActivityName.Text, vector.X, vector.Y - 12.5F, _imagePaint); + c.DrawText(minigameActivityName.Text, vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText(minigameActivityName.Text, vector.X, vector.Y - 12.5F, _textPaint); } _bitmaps[1]["PapayaGameplay_SkydiveGame"] = new MapLayer {Layer = skydiveBitmap, IsEnabled = false}; @@ -507,6 +529,7 @@ private async Task LoadShootingTargets() { await _threadWorkerView.Begin(_ => { + _fillPaint.StrokeWidth = 5; var shootingTargetsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); using var c = new SKCanvas(shootingTargetsBitmap); @@ -526,7 +549,8 @@ await _threadWorkerView.Begin(_ => if (bDone) continue; bDone = true; - c.DrawText("Shooting Target", vector.X, vector.Y - 12.5F, _imagePaint); + c.DrawText("Shooting Target", vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText("Shooting Target", vector.X, vector.Y - 12.5F, _textPaint); } _bitmaps[1]["PapayaGameplay_ShootingTargets"] = new MapLayer {Layer = shootingTargetsBitmap, IsEnabled = false}; @@ -537,6 +561,7 @@ private async Task LoadWaypoint(EWaypointType type) { await _threadWorkerView.Begin(_ => { + _fillPaint.StrokeWidth = 5; var waypointBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); using var c = new SKCanvas(waypointBitmap); @@ -571,7 +596,8 @@ await _threadWorkerView.Begin(_ => if (path.IsEmpty || uObject.TryGetValue(out bool startsTrial, "StartsTrial") && startsTrial) { path.MoveTo(vector.X, vector.Y); - c.DrawText(name, vector.X, vector.Y - 12.5F, _imagePaint); + c.DrawText(name, vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText(name, vector.X, vector.Y - 12.5F, _textPaint); } else if (uObject.TryGetValue(out bool endsTrial, "EndsTrial") && endsTrial) { @@ -590,6 +616,7 @@ private async Task LoadVendingMachines() { await _threadWorkerView.Begin(_ => { + _fillPaint.StrokeWidth = 5; var set = new HashSet(); var timeTrialsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); using var c = new SKCanvas(timeTrialsBitmap); @@ -622,7 +649,8 @@ await _threadWorkerView.Begin(_ => c.DrawPoint(vector.X, vector.Y, _pathPaint); if (!set.Add(name)) continue; - c.DrawText(name, vector.X, vector.Y - 12.5F, _imagePaint); + c.DrawText(name, vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText(name, vector.X, vector.Y - 12.5F, _textPaint); } _bitmaps[1]["PapayaGameplay_VendingMachines"] = new MapLayer {Layer = timeTrialsBitmap, IsEnabled = false}; @@ -633,6 +661,7 @@ private async Task LoadMusicBlocks() { await _threadWorkerView.Begin(_ => { + _fillPaint.StrokeWidth = 5; var shootingTargetsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); using var c = new SKCanvas(shootingTargetsBitmap); @@ -652,7 +681,8 @@ await _threadWorkerView.Begin(_ => if (bDone) continue; bDone = true; - c.DrawText("Music Blocks", vector.X, vector.Y - 12.5F, _imagePaint); + c.DrawText("Music Blocks", vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText("Music Blocks", vector.X, vector.Y - 12.5F, _textPaint); } _bitmaps[1]["PapayaGameplay_MusicBlocks"] = new MapLayer {Layer = shootingTargetsBitmap, IsEnabled = false}; From be257d02cb8485cd116b3e29ba588949ce8a1836 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Thu, 10 Jun 2021 16:52:36 +0200 Subject: [PATCH 46/68] really important update --- FModel/Creator/Bases/FN/Reward.cs | 4 +- FModel/Creator/CreatorPackage.cs | 3 +- FModel/Views/BackupManager.xaml | 122 ++++++++++++++---------------- 3 files changed, 61 insertions(+), 68 deletions(-) diff --git a/FModel/Creator/Bases/FN/Reward.cs b/FModel/Creator/Bases/FN/Reward.cs index cef0b920..0b2b287d 100644 --- a/FModel/Creator/Bases/FN/Reward.cs +++ b/FModel/Creator/Bases/FN/Reward.cs @@ -120,13 +120,13 @@ private void GetReward(string trigger) _theReward = new BaseIcon(null, EIconStyle.Default); _theReward.Border[0] = SKColor.Parse("FFDB67"); _theReward.Background[0] = SKColor.Parse("8F4A20"); - _theReward.Preview = Utils.GetBitmap("FortniteGame/Content/UI/Foundation/Textures/Icons/Items/T-FNBR-BattlePoints.T-FNBR-BattlePoints"); + _theReward.Preview = Utils.GetBitmap("FortniteGame/Content/Athena/UI/Frontend/Art/T_UI_BP_BattleStar_L.T_UI_BP_BattleStar_L"); break; case "athenaseasonalxp": _theReward = new BaseIcon(null, EIconStyle.Default); _theReward.Border[0] = SKColor.Parse("E6FDB1"); _theReward.Background[0] = SKColor.Parse("51830F"); - _theReward.Preview = Utils.GetBitmap("FortniteGame/Content/UI/Foundation/Textures/Icons/Items/T-FNBR-XPMedium.T-FNBR-XPMedium"); + _theReward.Preview = Utils.GetBitmap("FortniteGame/Content/UI/Foundation/Textures/Icons/Items/T-FNBR-XPUncommon-L.T-FNBR-XPUncommon-L"); break; case "mtxgiveaway": _theReward = new BaseIcon(null, EIconStyle.Default); diff --git a/FModel/Creator/CreatorPackage.cs b/FModel/Creator/CreatorPackage.cs index 08bba5a4..6ac1382b 100644 --- a/FModel/Creator/CreatorPackage.cs +++ b/FModel/Creator/CreatorPackage.cs @@ -126,7 +126,8 @@ public bool TryConstructCreator(out UCreator creator) case "MaterialInstanceConstant" when _object.Owner != null && (_object.Owner.Name.EndsWith($"/MI_OfferImages/{_object.Name}") || - _object.Owner.Name.EndsWith($"/RenderSwitch_Materials/{_object.Name}")): + _object.Owner.Name.EndsWith($"/RenderSwitch_Materials/{_object.Name}") || + _object.Owner.Name.EndsWith($"/MI_BPTile/{_object.Name}")): creator = new BaseMaterialInstance(_object, _style); return true; case "FortMtxOfferData": diff --git a/FModel/Views/BackupManager.xaml b/FModel/Views/BackupManager.xaml index e6d9dee7..298f3eb8 100644 --- a/FModel/Views/BackupManager.xaml +++ b/FModel/Views/BackupManager.xaml @@ -6,7 +6,7 @@ xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI" xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" IconVisibility="Collapsed" SizeToContent="Height" Loaded="OnLoaded" - Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.35'}"> + Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.225'}"> - - - - - - + + + + + + + + + + + + + + + + + + + + From 7f18d0e80fc5222c32a5a5436ccf734b7e712553 Mon Sep 17 00:00:00 2001 From: XTigerHyperX Date: Fri, 11 Jun 2021 23:32:42 +0100 Subject: [PATCH 47/68] i hope they understand man --- FModel/Views/BackupManager.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FModel/Views/BackupManager.xaml b/FModel/Views/BackupManager.xaml index 298f3eb8..9e4ce38b 100644 --- a/FModel/Views/BackupManager.xaml +++ b/FModel/Views/BackupManager.xaml @@ -6,7 +6,7 @@ xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI" xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" IconVisibility="Collapsed" SizeToContent="Height" Loaded="OnLoaded" - Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.225'}"> + Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.27'}"> - + + \ No newline at end of file From 648f7c728a9dd7763bc4627ce5c38ca22d25fd71 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Thu, 24 Jun 2021 17:11:21 +0200 Subject: [PATCH 56/68] code folding doesn't like tabs --- FModel/Views/Resources/Controls/AvalonEditor.xaml.cs | 5 +---- FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs | 3 +++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs b/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs index 73e5fe1a..6887e68d 100644 --- a/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs +++ b/FModel/Views/Resources/Controls/AvalonEditor.xaml.cs @@ -20,7 +20,6 @@ public partial class AvalonEditor private readonly Regex _hexColorRegex = new("\"Hex\": \"(?'target'[0-9A-Fa-f]{3,8})\"$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); private readonly System.Windows.Controls.ToolTip _toolTip = new(); - private JsonFoldingStrategies _manager; public AvalonEditor() { @@ -82,9 +81,7 @@ private void OnTextChanged(object sender, EventArgs e) if (sender is not TextEditor avalonEditor || DataContext is not TabItem tabItem || avalonEditor.Document == null || string.IsNullOrEmpty(avalonEditor.Document.Text)) return; - - _manager ??= new JsonFoldingStrategies(avalonEditor); - _manager.UpdateFoldings(tabItem.Document); + avalonEditor.Document.FileName = tabItem.Directory + '/' + tabItem.Header.SubstringBeforeLast('.'); if (!tabItem.ShouldScroll) return; diff --git a/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs b/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs index b31a4e42..e253a9f6 100644 --- a/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs +++ b/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs @@ -15,6 +15,7 @@ public partial class PropertiesPopout private readonly Regex _hexColorRegex = new("\"Hex\": \"(?'target'[0-9A-Fa-f]{3,8})\"$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); private readonly System.Windows.Controls.ToolTip _toolTip = new(); + private JsonFoldingStrategies _manager; public PropertiesPopout(TabItem contextViewModel) { @@ -30,6 +31,8 @@ public PropertiesPopout(TabItem contextViewModel) MyAvalonEditor.ScrollToVerticalOffset(contextViewModel.ScrollPosition); MyAvalonEditor.TextArea.TextView.ElementGenerators.Add(new GamePathElementGenerator()); MyAvalonEditor.TextArea.TextView.ElementGenerators.Add(new HexColorElementGenerator()); + _manager = new JsonFoldingStrategies(MyAvalonEditor); + _manager.UpdateFoldings(MyAvalonEditor.Document); } private void OnMouseHover(object sender, MouseEventArgs e) From 40c16c1c5c2499c9350e3320d03ae9270d5809a7 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sat, 26 Jun 2021 18:25:48 +0200 Subject: [PATCH 57/68] added Upgrade Benches, Phonebooths, and Alien Artifacts --- FModel/ViewModels/MapViewerViewModel.cs | 194 +++++++++++++++++------- FModel/Views/MapViewer.xaml | 6 + 2 files changed, 149 insertions(+), 51 deletions(-) diff --git a/FModel/ViewModels/MapViewerViewModel.cs b/FModel/ViewModels/MapViewerViewModel.cs index 3c7cb001..5ae43cff 100644 --- a/FModel/ViewModels/MapViewerViewModel.cs +++ b/FModel/ViewModels/MapViewerViewModel.cs @@ -60,6 +60,27 @@ public bool BrPatrolsPath set => SetProperty(ref _brPatrolsPath, value, "ApolloGameplay_PatrolsPath"); } + private bool _brUpgradeBenches; + public bool BrUpgradeBenches + { + get => _brUpgradeBenches; + set => SetProperty(ref _brUpgradeBenches, value, "ApolloGameplay_UpgradeBenches"); + } + + private bool _brPhonebooths; + public bool BrPhonebooths + { + get => _brPhonebooths; + set => SetProperty(ref _brPhonebooths, value, "ApolloGameplay_Phonebooths"); + } + + private bool _brAlienArtifacts; + public bool BrAlienArtifacts + { + get => _brAlienArtifacts; + set => SetProperty(ref _brAlienArtifacts, value, "ApolloGameplay_AlienArtifacts"); + } + private bool _prLandmarks; public bool PrLandmarks { @@ -217,6 +238,15 @@ private async void GenericToggle(string key, bool enabled) case "ApolloGameplay_PatrolsPath": await LoadPatrolsPath(); break; + case "ApolloGameplay_UpgradeBenches": + await LoadUpgradeBenches(); + break; + case "ApolloGameplay_Phonebooths": + await LoadPhonebooths(); + break; + case "ApolloGameplay_AlienArtifacts": + await LoadAlienArtifacts(); + break; case "PapayaGameplay_CannonballGame": await LoadCannonballGame(); break; @@ -412,65 +442,40 @@ await _threadWorkerView.Begin(_ => var patrolsPathBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); using var c = new SKCanvas(patrolsPathBitmap); - var gameFeatureDatas = new List - { - "FortniteGame/Plugins/GameFeatures/NPCLibrary/Content/GameFeatureData.GameFeatureData", - "FortniteGame/Plugins/GameFeatures/BattlepassS17/Content/GameFeatureData.GameFeatureData" - }; - - var overlays = new List(); - - foreach (var path in gameFeatureDatas) + var exports = Utils.LoadExports("/NPCLibrary/LevelOverlays/Apollo_Terrain_NPCLibraryS17_Overlay"); + foreach (var export in exports) { - if (!Utils.TryLoadObject(path, out UObject gameFeatureData) || - !gameFeatureData.TryGetValue(out FPackageIndex levelOverlayConfig, "LevelOverlayConfig") || - !Utils.TryGetPackageIndexExport(levelOverlayConfig, out UObject npcLibrary) || - !npcLibrary.TryGetValue(out FStructFallback[] overlayList, "OverlayList")) - return; - - overlays.AddRange(overlayList); - } + if (export is not { } uObject) continue; + if (!uObject.ExportType.Equals("FortAthenaPatrolPath", StringComparison.OrdinalIgnoreCase) || + !uObject.TryGetValue(out FGameplayTagContainer gameplayTags, "GameplayTags") || + !uObject.TryGetValue(out FPackageIndex[] patrolPoints, "PatrolPoints")) continue; - foreach (var overlay in overlays) - { - if (!overlay.TryGetValue(out FSoftObjectPath overlayWorld, "OverlayWorld")) - continue; + var displayName = gameplayTags.GameplayTags[0].Text.SubstringAfterLast("."); + if (displayName.Equals("Generic", StringComparison.OrdinalIgnoreCase)) continue; - var exports = Utils.LoadExports(overlayWorld.AssetPathName.Text.SubstringBeforeLast(".")); - foreach (var export in exports) - { - if (export is not { } uObject) continue; - if (!uObject.ExportType.Equals("FortAthenaPatrolPath", StringComparison.OrdinalIgnoreCase) || - !uObject.TryGetValue(out FGameplayTagContainer gameplayTags, "GameplayTags") || - !uObject.TryGetValue(out FPackageIndex[] patrolPoints, "PatrolPoints")) continue; + if (!Utils.TryGetPackageIndexExport(patrolPoints[0], out uObject) || + !uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || + !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; - var displayName = gameplayTags.GameplayTags[0].Text.SubstringAfterLast("."); - if (displayName.Equals("Generic", StringComparison.OrdinalIgnoreCase)) continue; + var path = new SKPath(); + var vector = GetMapPosition(relativeLocation, _brRadius); + path.MoveTo(vector.X, vector.Y); - if (!Utils.TryGetPackageIndexExport(patrolPoints[0], out uObject) || - !uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + for (var i = 1; i < patrolPoints.Length; i++) + { + if (!Utils.TryGetPackageIndexExport(patrolPoints[i], out uObject) || + !uObject.TryGetValue(out rootComponent, "RootComponent") || !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || - !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + !uObject.TryGetValue(out relativeLocation, "RelativeLocation")) continue; - var path = new SKPath(); - var vector = GetMapPosition(relativeLocation, _brRadius); - path.MoveTo(vector.X, vector.Y); - - for (var i = 1; i < patrolPoints.Length; i++) - { - if (!Utils.TryGetPackageIndexExport(patrolPoints[i], out uObject) || - !uObject.TryGetValue(out rootComponent, "RootComponent") || - !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || - !uObject.TryGetValue(out relativeLocation, "RelativeLocation")) continue; - - vector = GetMapPosition(relativeLocation, _brRadius); - path.LineTo(vector.X, vector.Y); - } - - c.DrawPath(path, _pathPaint); - c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint); - c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint); + vector = GetMapPosition(relativeLocation, _brRadius); + path.LineTo(vector.X, vector.Y); } + + c.DrawPath(path, _pathPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint); } _bitmaps[0]["ApolloGameplay_PatrolsPath"] = new MapLayer {Layer = patrolsPathBitmap, IsEnabled = false}; @@ -701,5 +706,92 @@ await _threadWorkerView.Begin(_ => _bitmaps[1]["PapayaGameplay_MusicBlocks"] = new MapLayer {Layer = shootingTargetsBitmap, IsEnabled = false}; }); } + + private async Task LoadUpgradeBenches() + { + await _threadWorkerView.Begin(_ => + { + _fillPaint.StrokeWidth = 5; + var upgradeBenchesBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(upgradeBenchesBitmap); + + var exports = Utils.LoadExports("/NPCLibrary/LevelOverlays/Apollo_Terrain_NPCLibrary_Stations_UpgradeBenches"); + foreach (var export in exports) + { + if (export is not { } uObject) continue; + if (!uObject.ExportType.Equals("B_Athena_Spawner_UpgradeStation_C", StringComparison.OrdinalIgnoreCase)) continue; + var displayName = uObject.Name["B_Athena_Spawner_".Length..]; + + if (!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || + !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + + var vector = GetMapPosition(relativeLocation, _brRadius); + c.DrawPoint(vector.X, vector.Y, _pathPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint); + } + + _bitmaps[0]["ApolloGameplay_UpgradeBenches"] = new MapLayer {Layer = upgradeBenchesBitmap, IsEnabled = false}; + }); + } + + private async Task LoadPhonebooths() + { + await _threadWorkerView.Begin(_ => + { + _fillPaint.StrokeWidth = 5; + var phoneboothsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(phoneboothsBitmap); + + var exports = Utils.LoadExports("/NPCLibrary/LevelOverlays/Apollo_Terrain_NPCLibrary_Stations_Phonebooths"); + foreach (var export in exports) + { + if (export is not { } uObject) continue; + if (!uObject.ExportType.Equals("B_Athena_Spawner_Payphone_C", StringComparison.OrdinalIgnoreCase)) continue; + var displayName = uObject.Name["B_Athena_Spawner_".Length..]; + + if (!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || + !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + + var vector = GetMapPosition(relativeLocation, _brRadius); + c.DrawPoint(vector.X, vector.Y, _pathPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint); + } + + _bitmaps[0]["ApolloGameplay_Phonebooths"] = new MapLayer {Layer = phoneboothsBitmap, IsEnabled = false}; + }); + } + + private async Task LoadAlienArtifacts() + { + await _threadWorkerView.Begin(_ => + { + _fillPaint.StrokeWidth = 5; + var alienArtifactsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(alienArtifactsBitmap); + + var exports = Utils.LoadExports("/BattlepassS17/Maps/Apollo_ItemCollect_S17_Overlay"); + foreach (var export in exports) + { + if (export is not { } uObject) continue; + if (!uObject.ExportType.Equals("BP_S17_AlienArtifact_Variant1_C", StringComparison.OrdinalIgnoreCase)) continue; + var displayName = uObject.Name; + + if (!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") || + !Utils.TryGetPackageIndexExport(rootComponent, out uObject) || + !uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue; + + var vector = GetMapPosition(relativeLocation, _brRadius); + c.DrawPoint(vector.X, vector.Y, _pathPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint); + } + + _bitmaps[0]["ApolloGameplay_AlienArtifacts"] = new MapLayer {Layer = alienArtifactsBitmap, IsEnabled = false}; + }); + } } } diff --git a/FModel/Views/MapViewer.xaml b/FModel/Views/MapViewer.xaml index 1f27cfc1..2b3bc6af 100644 --- a/FModel/Views/MapViewer.xaml +++ b/FModel/Views/MapViewer.xaml @@ -29,6 +29,12 @@ DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.MapViewer}}}" IsEnabled="{Binding IsReady}" /> + + + From ed5dfe0a0a9cf35697480bd2350480a8318c1515 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sun, 27 Jun 2021 00:12:06 +0200 Subject: [PATCH 58/68] added Tags Location --- CUE4Parse | 2 +- FModel/Settings/UserSettings.cs | 2 +- FModel/ViewModels/Commands/LoadCommand.cs | 1 + FModel/ViewModels/GameDirectoryViewModel.cs | 1 + FModel/ViewModels/MapViewerViewModel.cs | 44 +++++++++++++++++++++ FModel/Views/MapViewer.xaml | 2 + 6 files changed, 50 insertions(+), 2 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 62a11913..045e3f69 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 62a11913e10409e540b34e0286a734f98d6af3c7 +Subproject commit 045e3f69e6a1d44861fe36e2223e113b8ba0ca16 diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index 377bed14..5bcf565f 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -205,7 +205,7 @@ public int ImageMergerMargin {FGame.Dungeons, EGame.GAME_UE4_LATEST}, {FGame.WorldExplorers, EGame.GAME_UE4_LATEST}, {FGame.g3, EGame.GAME_UE4_22}, - {FGame.StateOfDecay2, EGame.GAME_UE4_13}, + {FGame.StateOfDecay2, EGame.GAME_SOD2}, {FGame.Prospect, EGame.GAME_UE4_LATEST}, {FGame.Indiana, EGame.GAME_UE4_LATEST}, {FGame.RogueCompany, EGame.GAME_UE4_LATEST}, diff --git a/FModel/ViewModels/Commands/LoadCommand.cs b/FModel/ViewModels/Commands/LoadCommand.cs index 461da185..2391cbb5 100644 --- a/FModel/ViewModels/Commands/LoadCommand.cs +++ b/FModel/ViewModels/Commands/LoadCommand.cs @@ -38,6 +38,7 @@ public LoadCommand(LoadingModesViewModel contextViewModel) : base(contextViewMod public override async void Execute(LoadingModesViewModel contextViewModel, object parameter) { + if (_applicationView.CUE4Parse.GameDirectory.HasNoFile) return; #if DEBUG var loadingTime = Stopwatch.StartNew(); #endif diff --git a/FModel/ViewModels/GameDirectoryViewModel.cs b/FModel/ViewModels/GameDirectoryViewModel.cs index a606edd1..220d8ab0 100644 --- a/FModel/ViewModels/GameDirectoryViewModel.cs +++ b/FModel/ViewModels/GameDirectoryViewModel.cs @@ -80,6 +80,7 @@ public override string ToString() public class GameDirectoryViewModel : ViewModel { + public bool HasNoFile => DirectoryFiles.Count < 1; public readonly ObservableCollection DirectoryFiles; public ICollectionView DirectoryFilesView { get; } diff --git a/FModel/ViewModels/MapViewerViewModel.cs b/FModel/ViewModels/MapViewerViewModel.cs index 5ae43cff..e85b0064 100644 --- a/FModel/ViewModels/MapViewerViewModel.cs +++ b/FModel/ViewModels/MapViewerViewModel.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using System.Windows.Media.Imaging; using CUE4Parse.UE4.Assets.Exports; +using CUE4Parse.UE4.Assets.Exports.Engine; using CUE4Parse.UE4.Assets.Exports.Material; using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Assets.Objects; @@ -73,6 +74,13 @@ public bool BrPhonebooths get => _brPhonebooths; set => SetProperty(ref _brPhonebooths, value, "ApolloGameplay_Phonebooths"); } + + private bool _brTagsLocation; + public bool BrTagsLocation + { + get => _brTagsLocation; + set => SetProperty(ref _brTagsLocation, value, "ApolloGameplay_TagsLocation"); + } private bool _brAlienArtifacts; public bool BrAlienArtifacts @@ -247,6 +255,9 @@ private async void GenericToggle(string key, bool enabled) case "ApolloGameplay_AlienArtifacts": await LoadAlienArtifacts(); break; + case "ApolloGameplay_TagsLocation": + await LoadTagsLocation(); + break; case "PapayaGameplay_CannonballGame": await LoadCannonballGame(); break; @@ -793,5 +804,38 @@ await _threadWorkerView.Begin(_ => _bitmaps[0]["ApolloGameplay_AlienArtifacts"] = new MapLayer {Layer = alienArtifactsBitmap, IsEnabled = false}; }); } + + private async Task LoadTagsLocation() + { + await _threadWorkerView.Begin(_ => + { + _fillPaint.StrokeWidth = 5; + var tagsLocationBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul); + using var c = new SKCanvas(tagsLocationBitmap); + + if (!Utils.TryLoadObject("FortniteGame/Content/Quests/QuestTagToLocationDataRows.QuestTagToLocationDataRows", out UDataTable locationData)) + return; + + foreach (var (key, uObject) in locationData.RowMap) + { + if (key.Text.StartsWith("Athena.Location.POI", StringComparison.OrdinalIgnoreCase) || + key.Text.StartsWith("Athena.Location.Unnamed", StringComparison.OrdinalIgnoreCase) || + key.Text.Contains(".Tandem.", StringComparison.OrdinalIgnoreCase) || + !uObject.TryGetValue(out FVector worldLocation, "WorldLocation")) continue; + + var parts = key.Text.Split('.'); + var displayName = parts[^2]; + if (!int.TryParse(parts[^1], out var _)) + displayName += " " + parts[^1]; + + var vector = GetMapPosition(worldLocation, _brRadius); + c.DrawPoint(vector.X, vector.Y, _pathPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint); + c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint); + } + + _bitmaps[0]["ApolloGameplay_TagsLocation"] = new MapLayer {Layer = tagsLocationBitmap, IsEnabled = false}; + }); + } } } diff --git a/FModel/Views/MapViewer.xaml b/FModel/Views/MapViewer.xaml index 2b3bc6af..428d4797 100644 --- a/FModel/Views/MapViewer.xaml +++ b/FModel/Views/MapViewer.xaml @@ -35,6 +35,8 @@ DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.MapViewer}}}" IsEnabled="{Binding IsReady}" /> + From 721f543d99115e400f5dddbfa527110cd19f1511 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sun, 27 Jun 2021 02:37:58 +0200 Subject: [PATCH 59/68] kinda useful folding shortcuts --- .../Controls/Aed/BraceFoldingStrategy.cs | 120 ++++++++---------- .../Resources/Controls/PropertiesPopout.xaml | 2 +- .../Controls/PropertiesPopout.xaml.cs | 16 +++ 3 files changed, 68 insertions(+), 70 deletions(-) diff --git a/FModel/Views/Resources/Controls/Aed/BraceFoldingStrategy.cs b/FModel/Views/Resources/Controls/Aed/BraceFoldingStrategy.cs index 033970db..54d72e17 100644 --- a/FModel/Views/Resources/Controls/Aed/BraceFoldingStrategy.cs +++ b/FModel/Views/Resources/Controls/Aed/BraceFoldingStrategy.cs @@ -5,135 +5,117 @@ namespace FModel.Views.Resources.Controls { - /// - /// https://github.com/JTranOrg/JTranEdit/blob/master/JTranEdit/Classes/BraceFoldingStrategy.cs - /// - public interface IFoldingStrategy + public class JsonFoldingStrategies { - IEnumerable UpdateFoldings(TextDocument document); - void CollapseAll(); - void ExpandAll(); - } - - public class JsonFoldingStrategies : IFoldingStrategy - { - private readonly List _strategies = new(); + private readonly BraceFoldingStrategy _strategy; private readonly FoldingManager _foldingManager; - private readonly IComparer _comparer = new FoldingComparer(); public JsonFoldingStrategies(TextEditor avalonEditor) { _foldingManager = FoldingManager.Install(avalonEditor.TextArea); - _strategies.Add(new BraceFoldingStrategy(avalonEditor, '{', '}')); - _strategies.Add(new BraceFoldingStrategy(avalonEditor, '[', ']')); + _strategy = new BraceFoldingStrategy(avalonEditor); } - public IEnumerable UpdateFoldings(TextDocument document) + public void UpdateFoldings(TextDocument document) { - var foldings = new List(); - foreach (var strategy in _strategies) - { - foldings.AddRange(strategy.UpdateFoldings(document)); - } - - foldings.Sort(_comparer); - _foldingManager.UpdateFoldings(foldings, -1); - - return foldings; + _foldingManager.UpdateFoldings(_strategy.UpdateFoldings(document), -1); } - public void CollapseAll() + public void UnfoldAll() { if (_foldingManager.AllFoldings == null) return; foreach (var folding in _foldingManager.AllFoldings) { - folding.IsFolded = true; + folding.IsFolded = false; } - - // Unfold the first fold (if any) to give a useful overview on content - var foldSection = _foldingManager.GetNextFolding(0); - if (foldSection != null) - foldSection.IsFolded = false; } - - public void ExpandAll() + + public void FoldToggle(int offset) { if (_foldingManager.AllFoldings == null) return; - foreach (var folding in _foldingManager.AllFoldings) - { - folding.IsFolded = false; - } + var foldSection = _foldingManager.GetFoldingsContaining(offset); + if (foldSection.Count > 0) + foldSection[^1].IsFolded = !foldSection[^1].IsFolded; } - private class FoldingComparer : IComparer + public void FoldAtLevel(int level = 0) { - public int Compare(NewFolding x, NewFolding y) + if (_foldingManager.AllFoldings == null) + return; + + foreach (var folding in _foldingManager.AllFoldings) { - return x.StartOffset.CompareTo(y.StartOffset); + if (folding.Tag is not CustomNewFolding realFolding) continue; + if (realFolding.Level == level) folding.IsFolded = true; } } } - public class BraceFoldingStrategy : IFoldingStrategy + public class BraceFoldingStrategy { - private readonly char _opening; - private readonly char _closing; - - public BraceFoldingStrategy(TextEditor editor, char o, char c) + public BraceFoldingStrategy(TextEditor editor) { - _opening = o; - _closing = c; UpdateFoldings(editor.Document); } - public IEnumerable UpdateFoldings(TextDocument document) + public IEnumerable UpdateFoldings(TextDocument document) { return CreateNewFoldings(document); } - public IEnumerable CreateNewFoldings(ITextSource document) + public IEnumerable CreateNewFoldings(ITextSource document) { - var newFoldings = new List(); + var newFoldings = new List(); var startOffsets = new Stack(); var lastNewLineOffset = 0; + var level = -1; for (var i = 0; i < document.TextLength; i++) { var c = document.GetCharAt(i); - if (c == _opening) - { - startOffsets.Push(i); - } - else if (c == _closing && startOffsets.Count > 0) + switch (c) { - var startOffset = startOffsets.Pop(); - if (startOffset < lastNewLineOffset) + case '{' or '[': + level++; + startOffsets.Push(i); + break; + case '}' or ']' when startOffsets.Count > 0: { - newFoldings.Add(new NewFolding(startOffset, i + 1)); + var startOffset = startOffsets.Pop(); + if (startOffset < lastNewLineOffset) + { + newFoldings.Add(new CustomNewFolding(startOffset, i + 1, level)); + } + level--; + break; } - } - else if (c is '\n' or '\r') - { - lastNewLineOffset = i + 1; + case '\n' or '\r': + lastNewLineOffset = i + 1; + break; } } newFoldings.Sort((a, b) => a.StartOffset.CompareTo(b.StartOffset)); return newFoldings; } + } - public void CollapseAll() + public class CustomNewFolding : NewFolding + { + public int Level { get; } + + public CustomNewFolding(int start, int end, int level) : base(start, end) { - throw new System.NotImplementedException(); + Level = level; } - public void ExpandAll() + public override string ToString() { - throw new System.NotImplementedException(); + return $"[{Level}] {StartOffset} -> {EndOffset}"; } - } + } } \ No newline at end of file diff --git a/FModel/Views/Resources/Controls/PropertiesPopout.xaml b/FModel/Views/Resources/Controls/PropertiesPopout.xaml index 717bdad8..36ed70af 100644 --- a/FModel/Views/Resources/Controls/PropertiesPopout.xaml +++ b/FModel/Views/Resources/Controls/PropertiesPopout.xaml @@ -5,7 +5,7 @@ xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI" xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit" xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI" - WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" + WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" PreviewKeyDown="OnPreviewKeyDown" Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.40'}"> diff --git a/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs b/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs index e253a9f6..c6fbe181 100644 --- a/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs +++ b/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs @@ -67,6 +67,22 @@ private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e) _ => fontSize }; } + + private void OnPreviewKeyDown(object sender, KeyEventArgs e) + { + switch (e.Key) + { + case Key.J when Keyboard.IsKeyDown(Key.K) && Keyboard.Modifiers.HasFlag(ModifierKeys.Control): + _manager.UnfoldAll(); + break; + case Key.L when Keyboard.IsKeyDown(Key.K) && Keyboard.Modifiers.HasFlag(ModifierKeys.Control): + _manager.FoldToggle(MyAvalonEditor.CaretOffset); + break; + case >= Key.D0 and <= Key.D9 when Keyboard.IsKeyDown(Key.K) && Keyboard.Modifiers.HasFlag(ModifierKeys.Control): + _manager.FoldAtLevel(int.Parse(e.Key.ToString()[1].ToString())); + break; + } + } private void OnMouseHoverStopped(object sender, MouseEventArgs e) { From 3a1613195479c218d72ebfa91b01a6d7a4af1294 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sun, 27 Jun 2021 02:47:24 +0200 Subject: [PATCH 60/68] Fold Toggle At Level --- FModel/Views/Resources/Controls/Aed/BraceFoldingStrategy.cs | 4 ++-- FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/FModel/Views/Resources/Controls/Aed/BraceFoldingStrategy.cs b/FModel/Views/Resources/Controls/Aed/BraceFoldingStrategy.cs index 54d72e17..127090cb 100644 --- a/FModel/Views/Resources/Controls/Aed/BraceFoldingStrategy.cs +++ b/FModel/Views/Resources/Controls/Aed/BraceFoldingStrategy.cs @@ -42,7 +42,7 @@ public void FoldToggle(int offset) foldSection[^1].IsFolded = !foldSection[^1].IsFolded; } - public void FoldAtLevel(int level = 0) + public void FoldToggleAtLevel(int level = 0) { if (_foldingManager.AllFoldings == null) return; @@ -50,7 +50,7 @@ public void FoldAtLevel(int level = 0) foreach (var folding in _foldingManager.AllFoldings) { if (folding.Tag is not CustomNewFolding realFolding) continue; - if (realFolding.Level == level) folding.IsFolded = true; + if (realFolding.Level == level) folding.IsFolded = !folding.IsFolded; } } } diff --git a/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs b/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs index c6fbe181..5eec8649 100644 --- a/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs +++ b/FModel/Views/Resources/Controls/PropertiesPopout.xaml.cs @@ -79,7 +79,7 @@ private void OnPreviewKeyDown(object sender, KeyEventArgs e) _manager.FoldToggle(MyAvalonEditor.CaretOffset); break; case >= Key.D0 and <= Key.D9 when Keyboard.IsKeyDown(Key.K) && Keyboard.Modifiers.HasFlag(ModifierKeys.Control): - _manager.FoldAtLevel(int.Parse(e.Key.ToString()[1].ToString())); + _manager.FoldToggleAtLevel(int.Parse(e.Key.ToString()[1].ToString())); break; } } From 586d221573a41aa580870a473b731957362a2765 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sat, 3 Jul 2021 12:14:39 +0200 Subject: [PATCH 61/68] console is back --- CUE4Parse | 2 +- FModel/App.xaml.cs | 19 +++-------- FModel/Constants.cs | 39 +--------------------- FModel/FModel.csproj | 1 - FModel/MainWindow.xaml.cs | 2 -- FModel/Services/DiscordService.cs | 2 +- FModel/ViewModels/Commands/LoadCommand.cs | 6 ++++ FModel/ViewModels/ThreadWorkerViewModel.cs | 2 -- FModel/Views/MapViewer.xaml | 2 +- FModel/Views/SearchView.xaml.cs | 1 - 10 files changed, 14 insertions(+), 62 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 045e3f69..6507993e 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 045e3f69e6a1d44861fe36e2223e113b8ba0ca16 +Subproject commit 6507993eaea053dfea289bb1e852e7bbf0d13a9e diff --git a/FModel/App.xaml.cs b/FModel/App.xaml.cs index 1263cd5e..8821f155 100644 --- a/FModel/App.xaml.cs +++ b/FModel/App.xaml.cs @@ -11,7 +11,6 @@ using FModel.Services; using FModel.Settings; using Newtonsoft.Json; -using Sentry; using Serilog.Sinks.SystemConsole.Themes; using MessageBox = AdonisUI.Controls.MessageBox; using MessageBoxImage = AdonisUI.Controls.MessageBoxImage; @@ -24,22 +23,13 @@ namespace FModel /// public partial class App { + [DllImport("kernel32.dll")] + private static extern bool AttachConsole(int dwProcessId); + protected override void OnStartup(StartupEventArgs e) { + AttachConsole(-1); base.OnStartup(e); - SentrySdk.Init(options => - { - options.Dsn = "https://2e872a5034c940e787015e5d07e7d82e@o811367.ingest.sentry.io/5805297"; -#if DEBUG - options.Environment = "dev"; -#elif RELEASE - options.Environment = "prod"; -#else - options.Environment = "what"; -#endif - options.TracesSampleRate = 1.0; - options.AddExceptionFilterForType(); - }); try { @@ -86,7 +76,6 @@ private void AppExit(object sender, ExitEventArgs e) private void OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { Log.Error("{Exception}", e.Exception); - SentrySdk.CaptureException(e.Exception); var messageBox = new MessageBoxModel { diff --git a/FModel/Constants.cs b/FModel/Constants.cs index 2a4603da..a33827d5 100644 --- a/FModel/Constants.cs +++ b/FModel/Constants.cs @@ -1,5 +1,4 @@ -using System; -using System.Reflection; +using System.Reflection; using CUE4Parse.UE4.Objects.Core.Misc; namespace FModel @@ -23,41 +22,5 @@ public static class Constants public const string _FN_LIVE_TRIGGER = "fortnite-live.manifest"; public const string _VAL_LIVE_TRIGGER = "valorant-live.manifest"; - - public static string GetRandomColor() - { - return _randomColors[_random.Next(0, 255)]; - } - - private static readonly Random _random = new(Environment.TickCount); - private static readonly string[] _randomColors = - { - "F44336", "FFEBEE", "FFCDD2", "EF9A9A", "E57373", "EF5350", "E53935", "D32F2F", "C62828", "B71C1C", - "FF8A80", "FF5252", "FF1744", "D50000", "FCE4EC", "F8BBD0", "F48FB1", "F06292", "EC407A", "E91E63", - "D81B60", "C2185B", "AD1457", "880E4F", "FF80AB", "FF4081", "F50057", "C51162", "F3E5F5", "E1BEE7", - "CE93D8", "BA68C8", "AB47BC", "9C27B0", "8E24AA", "7B1FA2", "6A1B9A", "4A148C", "EA80FC", "E040FB", - "D500F9", "AA00FF", "EDE7F6", "D1C4E9", "B39DDB", "9575CD", "7E57C2", "673AB7", "5E35B1", "512DA8", - "4527A0", "311B92", "B388FF", "7C4DFF", "651FFF", "6200EA", "E8EAF6", "C5CAE9", "9FA8DA", "7986CB", - "5C6BC0", "3F51B5", "3949AB", "303F9F", "283593", "1A237E", "8C9EFF", "536DFE", "3D5AFE", "304FFE", - "E3F2FD", "BBDEFB", "90CAF9", "64B5F6", "42A5F5", "2196F3", "1E88E5", "1976D2", "1565C0", "0D47A1", - "82B1FF", "448AFF", "2979FF", "2962FF", "E1F5FE", "B3E5FC", "81D4FA", "4FC3F7", "29B6F6", "03A9F4", - "039BE5", "0288D1", "0277BD", "01579B", "80D8FF", "40C4FF", "00B0FF", "0091EA", "E0F7FA", "B2EBF2", - "80DEEA", "4DD0E1", "26C6DA", "00BCD4", "00ACC1", "0097A7", "00838F", "006064", "84FFFF", "18FFFF", - "00E5FF", "00B8D4", "E0F2F1", "B2DFDB", "80CBC4", "4DB6AC", "26A69A", "009688", "00897B", "00796B", - "00695C", "004D40", "A7FFEB", "64FFDA", "1DE9B6", "00BFA5", "E8F5E9", "C8E6C9", "A5D6A7", "81C784", - "66BB6A", "4CAF50", "43A047", "388E3C", "2E7D32", "1B5E20", "B9F6CA", "69F0AE", "00E676", "00C853", - "F1F8E9", "DCEDC8", "C5E1A5", "AED581", "9CCC65", "8BC34A", "7CB342", "689F38", "558B2F", "33691E", - "CCFF90", "B2FF59", "76FF03", "64DD17", "F9FBE7", "F0F4C3", "E6EE9C", "DCE775", "D4E157", "CDDC39", - "C0CA33", "AFB42B", "9E9D24", "827717", "F4FF81", "EEFF41", "C6FF00", "AEEA00", "FFFDE7", "FFF9C4", - "FFF59D", "FFF176", "FFEE58", "FFEB3B", "FDD835", "FBC02D", "F9A825", "F57F17", "FFFF8D", "FFFF00", - "FFEA00", "FFD600", "FFF8E1", "FFECB3", "FFE082", "FFD54F", "FFCA28", "FFC107", "FFB300", "FFA000", - "FF8F00", "FF6F00", "FFE57F", "FFD740", "FFC400", "FFAB00", "FFF3E0", "FFE0B2", "FFCC80", "FFB74D", - "FFA726", "FF9800", "FB8C00", "F57C00", "EF6C00", "E65100", "FFD180", "FFAB40", "FF9100", "FF6D00", - "FBE9E7", "FFCCBC", "FFAB91", "FF8A65", "FF7043", "FF5722", "F4511E", "E64A19", "D84315", "BF360C", - "FF9E80", "FF6E40", "FF3D00", "DD2C00", "EFEBE9", "D7CCC8", "BCAAA4", "A1887F", "8D6E63", "795548", - "6D4C41", "5D4037", "4E342E", "3E2723", "FAFAFA", "F5F5F5", "EEEEEE", "E0E0E0", "BDBDBD", "9E9E9E", - "757575", "616161", "424242", "212121", "ECEFF1", "CFD8DC", "B0BEC5", "90A4AE", "78909C", "607D8B", - "546E7A", "455A64", "37474F", "263238", "000000", - }; } } \ No newline at end of file diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index 2714810b..b51b3f6c 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -111,7 +111,6 @@ - diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index 3968bb69..1219d593 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -12,7 +12,6 @@ using FModel.Views; using FModel.Views.Resources.Controls; using ICSharpCode.AvalonEdit.Editing; -using Sentry; namespace FModel { @@ -54,7 +53,6 @@ private void OnClosing(object sender, CancelEventArgs e) { _applicationView.CustomDirectories.Save(); _discordHandler.Dispose(); - SentrySdk.Close(); } private async void OnLoaded(object sender, RoutedEventArgs e) diff --git a/FModel/Services/DiscordService.cs b/FModel/Services/DiscordService.cs index 156a0422..d28a8273 100644 --- a/FModel/Services/DiscordService.cs +++ b/FModel/Services/DiscordService.cs @@ -22,7 +22,7 @@ public class DiscordHandler private readonly Assets _staticAssets = new() { - LargeImageKey = "official_logo", SmallImageKey = "verified", SmallImageText = $"v{Constants.APP_VERSION[..5]}" + LargeImageKey = "official_logo", SmallImageKey = "verified", SmallImageText = $"v{Constants.APP_VERSION}" }; private readonly Button[] _buttons = diff --git a/FModel/ViewModels/Commands/LoadCommand.cs b/FModel/ViewModels/Commands/LoadCommand.cs index 2391cbb5..86ca6251 100644 --- a/FModel/ViewModels/Commands/LoadCommand.cs +++ b/FModel/ViewModels/Commands/LoadCommand.cs @@ -39,6 +39,12 @@ public LoadCommand(LoadingModesViewModel contextViewModel) : base(contextViewMod public override async void Execute(LoadingModesViewModel contextViewModel, object parameter) { if (_applicationView.CUE4Parse.GameDirectory.HasNoFile) return; + if (_applicationView.CUE4Parse.Game == FGame.FortniteGame && + _applicationView.CUE4Parse.Provider.MappingsContainer == null) + { + FLogger.AppendError(); + FLogger.AppendText("Mappings could not get pulled, extracting assets might not work properly. If so, press F12 or please restart.", Constants.WHITE, true); + } #if DEBUG var loadingTime = Stopwatch.StartNew(); #endif diff --git a/FModel/ViewModels/ThreadWorkerViewModel.cs b/FModel/ViewModels/ThreadWorkerViewModel.cs index f403e99c..dc7f2e21 100644 --- a/FModel/ViewModels/ThreadWorkerViewModel.cs +++ b/FModel/ViewModels/ThreadWorkerViewModel.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; using FModel.Views.Resources.Controls; -using Sentry; using Serilog; namespace FModel.ViewModels @@ -97,7 +96,6 @@ private async Task ProcessQueues() CurrentCancellationTokenSource = null; // kill token Log.Error("{Exception}", e); - SentrySdk.CaptureException(e); FLogger.AppendError(); FLogger.AppendText(e.Message, Constants.WHITE, true); diff --git a/FModel/Views/MapViewer.xaml b/FModel/Views/MapViewer.xaml index 428d4797..b68d3f7f 100644 --- a/FModel/Views/MapViewer.xaml +++ b/FModel/Views/MapViewer.xaml @@ -22,7 +22,7 @@ - + Date: Sun, 4 Jul 2021 17:31:51 +0200 Subject: [PATCH 62/68] mesh export poc --- CUE4Parse | 2 +- FModel/App.xaml.cs | 2 ++ FModel/MainWindow.xaml | 6 +++--- FModel/ViewModels/CUE4ParseViewModel.cs | 24 ++++++++++++++++++++++++ FModel/Views/SettingsView.xaml | 10 +++++----- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 6507993e..e4791960 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 6507993eaea053dfea289bb1e852e7bbf0d13a9e +Subproject commit e479196098533761dadd601500369fcecc1baaef diff --git a/FModel/App.xaml.cs b/FModel/App.xaml.cs index 8821f155..6d8751ec 100644 --- a/FModel/App.xaml.cs +++ b/FModel/App.xaml.cs @@ -28,7 +28,9 @@ public partial class App protected override void OnStartup(StartupEventArgs e) { +#if DEBUG AttachConsole(-1); +#endif base.OnStartup(e); try diff --git a/FModel/MainWindow.xaml b/FModel/MainWindow.xaml index 4cdcd8d3..9a0ef621 100644 --- a/FModel/MainWindow.xaml +++ b/FModel/MainWindow.xaml @@ -129,12 +129,12 @@ - + diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 68702061..23247719 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -17,6 +17,7 @@ using CUE4Parse.UE4.Assets.Exports; using CUE4Parse.UE4.Assets.Exports.Material; using CUE4Parse.UE4.Assets.Exports.Sound; +using CUE4Parse.UE4.Assets.Exports.StaticMesh; using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Assets.Exports.Wwise; using CUE4Parse.UE4.Localization; @@ -24,6 +25,7 @@ using CUE4Parse.UE4.Oodle.Objects; using CUE4Parse.UE4.Wwise; using CUE4Parse_Conversion.Materials; +using CUE4Parse_Conversion.Meshes; using CUE4Parse_Conversion.Sounds; using CUE4Parse_Conversion.Textures; using EpicManifestParser.Objects; @@ -583,6 +585,28 @@ public void ExtractAndScroll(string fullPath, string objectName) return false; } + case UStaticMesh mesh when UserSettings.Default.IsAutoSaveMeshes: + { + var msh = new MeshExporter(mesh.Convert(), true); + foreach (var staticMesh in msh.StaticMeshes) + { + if (staticMesh.TryWriteTo( + Path.Combine(UserSettings.Default.OutputDirectory, "Saves"), out var savedFileName)) + { + Log.Information("{FileName} successfully saved", savedFileName); + FLogger.AppendInformation(); + FLogger.AppendText($"Successfully saved '{savedFileName}'", Constants.WHITE, true); + } + else + { + Log.Error("{FileName} could not be saved", savedFileName); + FLogger.AppendError(); + FLogger.AppendText($"Could not saved '{savedFileName}'", Constants.WHITE, true); + } + } + + return false; + } default: { using var package = new CreatorPackage(export, UserSettings.Default.CosmeticStyle); diff --git a/FModel/Views/SettingsView.xaml b/FModel/Views/SettingsView.xaml index 1642df58..86019044 100644 --- a/FModel/Views/SettingsView.xaml +++ b/FModel/Views/SettingsView.xaml @@ -290,12 +290,12 @@ - - - - - + + + From 73e2211cca56ec3a4a8f0c7d6e9af70d427bf14b Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Tue, 6 Jul 2021 19:55:57 +0200 Subject: [PATCH 63/68] generic exporter --- CUE4Parse | 2 +- FModel/ViewModels/CUE4ParseViewModel.cs | 38 ++++++------------------- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index e4791960..98a4232f 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit e479196098533761dadd601500369fcecc1baaef +Subproject commit 98a4232fbff2528a85e2e0d836948ebbe86699ea diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 23247719..73de3ee2 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -16,6 +16,7 @@ using CUE4Parse.UE4.AssetRegistry; using CUE4Parse.UE4.Assets.Exports; using CUE4Parse.UE4.Assets.Exports.Material; +using CUE4Parse.UE4.Assets.Exports.SkeletalMesh; using CUE4Parse.UE4.Assets.Exports.Sound; using CUE4Parse.UE4.Assets.Exports.StaticMesh; using CUE4Parse.UE4.Assets.Exports.Texture; @@ -24,6 +25,7 @@ using CUE4Parse.UE4.Objects.UObject; using CUE4Parse.UE4.Oodle.Objects; using CUE4Parse.UE4.Wwise; +using CUE4Parse_Conversion; using CUE4Parse_Conversion.Materials; using CUE4Parse_Conversion.Meshes; using CUE4Parse_Conversion.Sounds; @@ -564,13 +566,13 @@ public void ExtractAndScroll(string fullPath, string objectName) SaveAndPlaySound(Path.Combine(TabControl.SelectedTab.Directory, TabControl.SelectedTab.Header.SubstringBeforeLast('.')).Replace('\\', '/'), audioFormat, data); return false; } - case UMaterialInterface material when UserSettings.Default.IsAutoSaveMaterials: + case UMaterialInterface when UserSettings.Default.IsAutoSaveMaterials: + case UStaticMesh when UserSettings.Default.IsAutoSaveMeshes: + case USkeletalMesh when UserSettings.Default.IsAutoSaveMeshes: { - var mat = new MaterialExporter(material); - if (mat.TryWriteTo( - Path.Combine(UserSettings.Default.OutputDirectory, "Saves"), - Path.Combine(UserSettings.Default.OutputDirectory, "Textures"), - out var savedFileName)) + var toSave = new Exporter(export); + var toSaveDirectory = new DirectoryInfo(Path.Combine(UserSettings.Default.OutputDirectory, "Saves")); + if (toSave.TryWriteToDir(toSaveDirectory, out var savedFileName)) { Log.Information("{FileName} successfully saved", savedFileName); FLogger.AppendInformation(); @@ -580,29 +582,7 @@ public void ExtractAndScroll(string fullPath, string objectName) { Log.Error("{FileName} could not be saved", savedFileName); FLogger.AppendError(); - FLogger.AppendText($"Could not saved '{savedFileName}'", Constants.WHITE, true); - } - - return false; - } - case UStaticMesh mesh when UserSettings.Default.IsAutoSaveMeshes: - { - var msh = new MeshExporter(mesh.Convert(), true); - foreach (var staticMesh in msh.StaticMeshes) - { - if (staticMesh.TryWriteTo( - Path.Combine(UserSettings.Default.OutputDirectory, "Saves"), out var savedFileName)) - { - Log.Information("{FileName} successfully saved", savedFileName); - FLogger.AppendInformation(); - FLogger.AppendText($"Successfully saved '{savedFileName}'", Constants.WHITE, true); - } - else - { - Log.Error("{FileName} could not be saved", savedFileName); - FLogger.AppendError(); - FLogger.AppendText($"Could not saved '{savedFileName}'", Constants.WHITE, true); - } + FLogger.AppendText($"Could not save '{savedFileName}'", Constants.WHITE, true); } return false; From 8d263b6f84a23034b72fc778dc5f15c326a4b5a4 Mon Sep 17 00:00:00 2001 From: GMatrixGames Date: Wed, 7 Jul 2021 19:50:46 -0400 Subject: [PATCH 64/68] AshtonBoardwalk MI fix --- CUE4Parse | 2 +- FModel/Creator/Bases/FN/BaseMaterialInstance.cs | 5 +++++ FModel/ViewModels/CUE4ParseViewModel.cs | 14 ++++++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 98a4232f..32c5a34d 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 98a4232fbff2528a85e2e0d836948ebbe86699ea +Subproject commit 32c5a34d1ce89f657508e53eb3535bfd9a37396d diff --git a/FModel/Creator/Bases/FN/BaseMaterialInstance.cs b/FModel/Creator/Bases/FN/BaseMaterialInstance.cs index 1578d40b..50b332a8 100644 --- a/FModel/Creator/Bases/FN/BaseMaterialInstance.cs +++ b/FModel/Creator/Bases/FN/BaseMaterialInstance.cs @@ -19,6 +19,8 @@ public override void ParseForInfo() { if (Object is not UMaterialInstanceConstant material) return; + // MY ONLY GOTO + texture_finding: foreach (var textureParameter in material.TextureParameterValues) // get texture from base material { if (textureParameter.ParameterValue is not UTexture2D texture || Preview != null) continue; @@ -45,6 +47,9 @@ public override void ParseForInfo() if (material == null) return; } + if (Preview == null) + goto texture_finding; + foreach (var vectorParameter in material.VectorParameterValues) { if (vectorParameter.ParameterValue == null) continue; diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 73de3ee2..7db6b30b 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -24,6 +24,7 @@ using CUE4Parse.UE4.Localization; using CUE4Parse.UE4.Objects.UObject; using CUE4Parse.UE4.Oodle.Objects; +using CUE4Parse.UE4.Shaders; using CUE4Parse.UE4.Wwise; using CUE4Parse_Conversion; using CUE4Parse_Conversion.Materials; @@ -87,7 +88,7 @@ public CUE4ParseViewModel(string gameDirectory) } default: { - Game = gameDirectory.SubstringBeforeLast("\\Content\\").SubstringAfterLast("\\").ToEnum(FGame.Unknown); + Game = gameDirectory.SubstringBeforeLast("\\Content").SubstringAfterLast("\\").ToEnum(FGame.Unknown); if (Game == FGame.StateOfDecay2) Provider = new DefaultFileProvider(new DirectoryInfo(gameDirectory), new List @@ -482,7 +483,7 @@ public void Extract(string fullPath, bool addNewTab = false, bool bulkSave = fal TabControl.SelectedTab.Image = null; if (Provider.TryCreateReader(fullPath, out var archive)) { - var header = new FDictionaryHeader(archive); + var header = new FOodleDictionaryArchive(archive).Header; TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(header, Formatting.Indented), bulkSave); } @@ -506,8 +507,17 @@ public void Extract(string fullPath, bool addNewTab = false, bool bulkSave = fal break; case "ushaderbytecode": case "ushadercode": + { TabControl.SelectedTab.Image = null; + + if (Provider.TryCreateReader(fullPath, out var archive)) + { + var ar = new FShaderCodeArchive(archive); + TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(ar, Formatting.Indented), bulkSave); + } + break; + } default: { var exports = Provider.LoadObjectExports(fullPath); From f4e7eeb6ae2f14ec155630281abdcb8a23e1b90f Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sat, 10 Jul 2021 01:59:46 +0200 Subject: [PATCH 65/68] mesh export settings --- CUE4Parse | 2 +- .../Creator/Bases/FN/BaseMaterialInstance.cs | 1 - FModel/Settings/UserSettings.cs | 23 +++++++ FModel/ViewModels/CUE4ParseViewModel.cs | 6 +- FModel/ViewModels/Commands/MenuCommand.cs | 2 - FModel/ViewModels/SettingsViewModel.cs | 44 ++++++++++++ FModel/Views/SettingsView.xaml | 68 +++++++++++++++++++ 7 files changed, 139 insertions(+), 7 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 32c5a34d..a30473bb 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 32c5a34d1ce89f657508e53eb3535bfd9a37396d +Subproject commit a30473bbfe73f759365572409b95381e94adc9a9 diff --git a/FModel/Creator/Bases/FN/BaseMaterialInstance.cs b/FModel/Creator/Bases/FN/BaseMaterialInstance.cs index 50b332a8..31f211ae 100644 --- a/FModel/Creator/Bases/FN/BaseMaterialInstance.cs +++ b/FModel/Creator/Bases/FN/BaseMaterialInstance.cs @@ -19,7 +19,6 @@ public override void ParseForInfo() { if (Object is not UMaterialInstanceConstant material) return; - // MY ONLY GOTO texture_finding: foreach (var textureParameter in material.TextureParameterValues) // get texture from base material { diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index 5bcf565f..2c619a77 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -3,6 +3,8 @@ using System.IO; using System.Windows.Input; using CUE4Parse.UE4.Versions; +using CUE4Parse_Conversion.Meshes; +using CUE4Parse_Conversion.Textures; using FModel.Framework; using FModel.ViewModels; using FModel.ViewModels.ApiEndpoints.Models; @@ -428,5 +430,26 @@ public Hotkey NextAudio get => _nextAudio; set => SetProperty(ref _nextAudio, value); } + + private EMeshFormat _meshExportFormat = EMeshFormat.ActorX; + public EMeshFormat MeshExportFormat + { + get => _meshExportFormat; + set => SetProperty(ref _meshExportFormat, value); + } + + private ELodFormat _lodExportFormat = ELodFormat.FirstLod; + public ELodFormat LodExportFormat + { + get => _lodExportFormat; + set => SetProperty(ref _lodExportFormat, value); + } + + private ETextureFormat _textureExportFormat = ETextureFormat.Png; + public ETextureFormat TextureExportFormat + { + get => _textureExportFormat; + set => SetProperty(ref _textureExportFormat, value); + } } } \ No newline at end of file diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 7db6b30b..eead9d3c 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -580,13 +580,13 @@ public void ExtractAndScroll(string fullPath, string objectName) case UStaticMesh when UserSettings.Default.IsAutoSaveMeshes: case USkeletalMesh when UserSettings.Default.IsAutoSaveMeshes: { - var toSave = new Exporter(export); + var toSave = new Exporter(export, UserSettings.Default.TextureExportFormat, UserSettings.Default.LodExportFormat); var toSaveDirectory = new DirectoryInfo(Path.Combine(UserSettings.Default.OutputDirectory, "Saves")); if (toSave.TryWriteToDir(toSaveDirectory, out var savedFileName)) { - Log.Information("{FileName} successfully saved", savedFileName); + Log.Information("Successfully saved {FileName}", savedFileName); FLogger.AppendInformation(); - FLogger.AppendText($"Successfully saved '{savedFileName}'", Constants.WHITE, true); + FLogger.AppendText($"Successfully saved {savedFileName}", Constants.WHITE, true); } else { diff --git a/FModel/ViewModels/Commands/MenuCommand.cs b/FModel/ViewModels/Commands/MenuCommand.cs index 7528761b..237f386c 100644 --- a/FModel/ViewModels/Commands/MenuCommand.cs +++ b/FModel/ViewModels/Commands/MenuCommand.cs @@ -1,7 +1,5 @@ using System.Diagnostics; -using System.Threading.Tasks; using AdonisUI.Controls; -using FModel.Extensions; using FModel.Framework; using FModel.Settings; using FModel.Views; diff --git a/FModel/ViewModels/SettingsViewModel.cs b/FModel/ViewModels/SettingsViewModel.cs index 1bec79be..ba4de94e 100644 --- a/FModel/ViewModels/SettingsViewModel.cs +++ b/FModel/ViewModels/SettingsViewModel.cs @@ -3,6 +3,8 @@ using System.Collections.ObjectModel; using System.Linq; using CUE4Parse.UE4.Versions; +using CUE4Parse_Conversion.Meshes; +using CUE4Parse_Conversion.Textures; using FModel.Framework; using FModel.Services; using FModel.Settings; @@ -82,6 +84,27 @@ public EEnabledDisabled SelectedCosmeticDisplayAsset get => _selectedCosmeticDisplayAsset; set => SetProperty(ref _selectedCosmeticDisplayAsset, value); } + + private EMeshFormat _selectedMeshExportFormat; + public EMeshFormat SelectedMeshExportFormat + { + get => _selectedMeshExportFormat; + set => SetProperty(ref _selectedMeshExportFormat, value); + } + + private ELodFormat _selectedLodExportFormat; + public ELodFormat SelectedLodExportFormat + { + get => _selectedLodExportFormat; + set => SetProperty(ref _selectedLodExportFormat, value); + } + + private ETextureFormat _selectedTextureExportFormat; + public ETextureFormat SelectedTextureExportFormat + { + get => _selectedTextureExportFormat; + set => SetProperty(ref _selectedTextureExportFormat, value); + } public ReadOnlyObservableCollection UpdateModes { get; private set; } public ReadOnlyObservableCollection UeGames { get; private set; } @@ -93,6 +116,9 @@ public EEnabledDisabled SelectedCosmeticDisplayAsset public ReadOnlyObservableCollection CompressedAudios { get; private set; } public ReadOnlyObservableCollection CosmeticStyles { get; private set; } public ReadOnlyObservableCollection CosmeticDisplayAssets { get; private set; } + public ReadOnlyObservableCollection MeshExportFormats { get; private set; } + public ReadOnlyObservableCollection LodExportFormats { get; private set; } + public ReadOnlyObservableCollection TextureExportFormats { get; private set; } private readonly FGame _game; private string _outputSnapshot; @@ -105,6 +131,9 @@ public EEnabledDisabled SelectedCosmeticDisplayAsset private ECompressedAudio _compressedAudioSnapshot; private EIconStyle _cosmeticStyleSnapshot; private EEnabledDisabled _cosmeticDisplayAssetSnapshot; + private EMeshFormat _meshExportFormatSnapshot; + private ELodFormat _lodExportFormatSnapshot; + private ETextureFormat _textureExportFormatSnapshot; public SettingsViewModel(FGame game) { @@ -123,6 +152,9 @@ public void Initialize() _compressedAudioSnapshot = UserSettings.Default.CompressedAudioMode; _cosmeticStyleSnapshot = UserSettings.Default.CosmeticStyle; _cosmeticDisplayAssetSnapshot = UserSettings.Default.CosmeticDisplayAsset; + _meshExportFormatSnapshot = UserSettings.Default.MeshExportFormat; + _lodExportFormatSnapshot = UserSettings.Default.LodExportFormat; + _textureExportFormatSnapshot = UserSettings.Default.TextureExportFormat; SelectedUpdateMode = _updateModeSnapshot; SelectedUeGame = _ueGameSnapshot; @@ -132,6 +164,9 @@ public void Initialize() SelectedCompressedAudio = _compressedAudioSnapshot; SelectedCosmeticStyle = _cosmeticStyleSnapshot; SelectedCosmeticDisplayAsset = _cosmeticDisplayAssetSnapshot; + SelectedMeshExportFormat = _meshExportFormatSnapshot; + SelectedLodExportFormat = _lodExportFormatSnapshot; + SelectedTextureExportFormat = _textureExportFormatSnapshot; SelectedAesReload = UserSettings.Default.AesReload; SelectedDiscordRpc = UserSettings.Default.DiscordRpc; @@ -145,6 +180,9 @@ public void Initialize() CompressedAudios = new ReadOnlyObservableCollection(new ObservableCollection(EnumerateCompressedAudios())); CosmeticStyles = new ReadOnlyObservableCollection(new ObservableCollection(EnumerateCosmeticStyles())); CosmeticDisplayAssets = new ReadOnlyObservableCollection(new ObservableCollection(EnumerateEnabledDisabled())); + MeshExportFormats = new ReadOnlyObservableCollection(new ObservableCollection(EnumerateMeshExportFormat())); + LodExportFormats = new ReadOnlyObservableCollection(new ObservableCollection(EnumerateLodExportFormat())); + TextureExportFormats = new ReadOnlyObservableCollection(new ObservableCollection(EnumerateTextureExportFormat())); } public SettingsOut Save() @@ -167,6 +205,9 @@ public SettingsOut Save() UserSettings.Default.CompressedAudioMode = SelectedCompressedAudio; UserSettings.Default.CosmeticStyle = SelectedCosmeticStyle; UserSettings.Default.CosmeticDisplayAsset = SelectedCosmeticDisplayAsset; + UserSettings.Default.MeshExportFormat = SelectedMeshExportFormat; + UserSettings.Default.LodExportFormat = SelectedLodExportFormat; + UserSettings.Default.TextureExportFormat = SelectedTextureExportFormat; UserSettings.Default.AesReload = SelectedAesReload; UserSettings.Default.DiscordRpc = SelectedDiscordRpc; @@ -185,5 +226,8 @@ public SettingsOut Save() private IEnumerable EnumerateCompressedAudios() => Enum.GetValues(SelectedCompressedAudio.GetType()).Cast(); private IEnumerable EnumerateCosmeticStyles() => Enum.GetValues(SelectedCosmeticStyle.GetType()).Cast(); private IEnumerable EnumerateEnabledDisabled() => Enum.GetValues(SelectedCosmeticDisplayAsset.GetType()).Cast(); + private IEnumerable EnumerateMeshExportFormat() => Enum.GetValues(SelectedMeshExportFormat.GetType()).Cast(); + private IEnumerable EnumerateLodExportFormat() => Enum.GetValues(SelectedLodExportFormat.GetType()).Cast(); + private IEnumerable EnumerateTextureExportFormat() => Enum.GetValues(SelectedTextureExportFormat.GetType()).Cast(); } } \ No newline at end of file diff --git a/FModel/Views/SettingsView.xaml b/FModel/Views/SettingsView.xaml index 86019044..c0dbd8c5 100644 --- a/FModel/Views/SettingsView.xaml +++ b/FModel/Views/SettingsView.xaml @@ -228,6 +228,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -365,6 +417,22 @@ + + + + + + + + + + + + + + + + From 277bee902ed24498ac4d1ae10b5667b5db6f3452 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sat, 10 Jul 2021 14:46:46 +0200 Subject: [PATCH 66/68] full mesh support --- CUE4Parse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CUE4Parse b/CUE4Parse index a30473bb..898545a5 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit a30473bbfe73f759365572409b95381e94adc9a9 +Subproject commit 898545a54a7910293698b3c73e53ce50a1ffb2ea From e878d2b2ee872180f0dd69275bc2c9d2773768c9 Mon Sep 17 00:00:00 2001 From: GMatrixGames Date: Sat, 10 Jul 2021 22:01:56 -0400 Subject: [PATCH 67/68] Core is 4.25, not 4.24 --- FModel/Settings/UserSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FModel/Settings/UserSettings.cs b/FModel/Settings/UserSettings.cs index 2c619a77..759796e8 100644 --- a/FModel/Settings/UserSettings.cs +++ b/FModel/Settings/UserSettings.cs @@ -212,7 +212,7 @@ public int ImageMergerMargin {FGame.Indiana, EGame.GAME_UE4_LATEST}, {FGame.RogueCompany, EGame.GAME_UE4_LATEST}, {FGame.SwGame, EGame.GAME_UE4_LATEST}, - {FGame.Platform, EGame.GAME_UE4_24}, + {FGame.Platform, EGame.GAME_UE4_25}, {FGame.BendGame, EGame.GAME_UE4_11} }; public IDictionary OverridedGame From d66b832b89b52aa3ac4dad1ccc840a2e70acc913 Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Sun, 11 Jul 2021 13:51:54 +0200 Subject: [PATCH 68/68] FModel v4.0.1 --- CUE4Parse | 2 +- FModel/FModel.csproj | 4 ++-- FModel/Views/About.xaml | 3 ++- FModel/Views/BackupManager.xaml | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CUE4Parse b/CUE4Parse index 898545a5..a520ada3 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit 898545a54a7910293698b3c73e53ce50a1ffb2ea +Subproject commit a520ada39b9736d06db1df3321c7695873b23c44 diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index b51b3f6c..01cc0e98 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -6,8 +6,8 @@ true FModel.ico 4.0.0 - 4.0.0.2 - 4.0.0.2 + 4.0.1.0 + 4.0.1.0 false true win-x64 diff --git a/FModel/Views/About.xaml b/FModel/Views/About.xaml index 794eaef4..d0187ebf 100644 --- a/FModel/Views/About.xaml +++ b/FModel/Views/About.xaml @@ -1,6 +1,7 @@  @@ -18,7 +19,7 @@ - + diff --git a/FModel/Views/BackupManager.xaml b/FModel/Views/BackupManager.xaml index 9d8b5157..8c3af476 100644 --- a/FModel/Views/BackupManager.xaml +++ b/FModel/Views/BackupManager.xaml @@ -36,7 +36,7 @@ + Text="Because it looks like it's pretty hard to understand, you don't load backups, you load your files and compare them with the backup. Also, by clicking the download button you don't create your own backup you download a pre-made one. Kinda crazy we have to explain this, who will even read anyway..." />