mirror of
https://github.com/4sval/FModel.git
synced 2026-09-30 13:09:31 -05:00
Merge remote-tracking branch 'origin/dev' into feature/new-viewer
# Conflicts: # CUE4Parse # FModel/MainWindow.xaml # FModel/ViewModels/CUE4ParseViewModel.cs # FModel/Views/Snooper/Animations/Skeleton.cs # FModel/Views/Snooper/Models/SkeletalModel.cs # FModel/Views/Snooper/Models/StaticModel.cs # FModel/Views/Snooper/Renderer.cs
This commit is contained in:
Submodule CUE4Parse updated: e69ae89739...ffd48e7719
@@ -32,6 +32,7 @@ public class BaseIcon : UCreator
|
|||||||
// rarity
|
// rarity
|
||||||
if (Object.TryGetValue(out FPackageIndex series, "Series")) GetSeries(series);
|
if (Object.TryGetValue(out FPackageIndex series, "Series")) GetSeries(series);
|
||||||
else if (Object.TryGetValue(out FStructFallback componentContainer, "ComponentContainer")) GetSeries(componentContainer);
|
else if (Object.TryGetValue(out FStructFallback componentContainer, "ComponentContainer")) GetSeries(componentContainer);
|
||||||
|
else if (Object.TryGetValue(out EFortRarity hackRarity, "HackRarity")) GetRarity(hackRarity);
|
||||||
else GetRarity(Object.GetOrDefault("Rarity", EFortRarity.Uncommon)); // default is uncommon
|
else GetRarity(Object.GetOrDefault("Rarity", EFortRarity.Uncommon)); // default is uncommon
|
||||||
|
|
||||||
if (Object.TryGetValue(out FInstancedStruct[] dataList, "DataList"))
|
if (Object.TryGetValue(out FInstancedStruct[] dataList, "DataList"))
|
||||||
@@ -48,7 +49,7 @@ public class BaseIcon : UCreator
|
|||||||
Preview = preview;
|
Preview = preview;
|
||||||
else if (Object.TryGetValue(out FPackageIndex itemDefinition, "HeroDefinition", "WeaponDefinition"))
|
else if (Object.TryGetValue(out FPackageIndex itemDefinition, "HeroDefinition", "WeaponDefinition"))
|
||||||
Preview = Utils.GetBitmap(itemDefinition);
|
Preview = Utils.GetBitmap(itemDefinition);
|
||||||
else if (Object.TryGetValue(out FSoftObjectPath largePreview, "LargePreviewImage", "EntryListIcon", "SmallPreviewImage", "BundleImage", "ItemDisplayAsset", "LargeIcon", "ToastIcon", "SmallIcon"))
|
else if (Object.TryGetValue(out FSoftObjectPath largePreview, "LargePreviewImage", "EntryListIcon", "SmallPreviewImage", "BundleImage", "ItemDisplayAsset", "LargeIcon", "ToastIcon", "SmallIcon", "CartridgeIcon", "EffectIcon"))
|
||||||
Preview = Utils.GetBitmap(largePreview);
|
Preview = Utils.GetBitmap(largePreview);
|
||||||
else if (Object.TryGetValue(out string s, "LargePreviewImage") && !string.IsNullOrEmpty(s))
|
else if (Object.TryGetValue(out string s, "LargePreviewImage") && !string.IsNullOrEmpty(s))
|
||||||
Preview = Utils.GetBitmap(s);
|
Preview = Utils.GetBitmap(s);
|
||||||
@@ -66,9 +67,9 @@ public class BaseIcon : UCreator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// text
|
// text
|
||||||
if (Object.TryGetValue(out FText displayName, "DisplayName", "ItemName", "BundleName", "DefaultHeaderText", "UIDisplayName", "EntryName", "EventCalloutTitle"))
|
if (Object.TryGetValue(out FText displayName, "DisplayName", "ItemName", "BundleName", "DefaultHeaderText", "UIDisplayName", "EntryName", "EventCalloutTitle", "KeyName", "HackDisplayName"))
|
||||||
DisplayName = displayName.Text;
|
DisplayName = displayName.Text;
|
||||||
if (Object.TryGetValue(out FText description, "Description", "ItemDescription", "SetDescription", "BundleDescription", "GeneralDescription", "DefaultBodyText", "UIDescription", "UIDisplayDescription", "EntryDescription", "EventCalloutDescription"))
|
if (Object.TryGetValue(out FText description, "Description", "ItemDescription", "SetDescription", "BundleDescription", "GeneralDescription", "DefaultBodyText", "UIDescription", "UIDisplayDescription", "EntryDescription", "EventCalloutDescription", "KeyDescription", "HackDescription"))
|
||||||
Description = description.Text;
|
Description = description.Text;
|
||||||
else if (Object.TryGetValue(out FText[] descriptions, "Description"))
|
else if (Object.TryGetValue(out FText[] descriptions, "Description"))
|
||||||
Description = string.Join('\n', descriptions.Select(x => x.Text));
|
Description = string.Join('\n', descriptions.Select(x => x.Text));
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ public class CreatorPackage : IDisposable
|
|||||||
case "AthenaEmojiItemDefinition":
|
case "AthenaEmojiItemDefinition":
|
||||||
case "AthenaItemWrapDefinition":
|
case "AthenaItemWrapDefinition":
|
||||||
case "AthenaToyItemDefinition":
|
case "AthenaToyItemDefinition":
|
||||||
|
case "FortHackData":
|
||||||
case "FortHeroType":
|
case "FortHeroType":
|
||||||
case "FortTokenType":
|
case "FortTokenType":
|
||||||
case "FortAbilityKit":
|
case "FortAbilityKit":
|
||||||
@@ -72,7 +73,9 @@ public class CreatorPackage : IDisposable
|
|||||||
case "FortMissionInfo":
|
case "FortMissionInfo":
|
||||||
case "RewardGraphToken":
|
case "RewardGraphToken":
|
||||||
case "JunoKnowledgeBundle":
|
case "JunoKnowledgeBundle":
|
||||||
|
case "FortHackDataMinimal":
|
||||||
case "FortBannerTokenType":
|
case "FortBannerTokenType":
|
||||||
|
case "FortHackKeyCoreData":
|
||||||
case "FortVariantTokenType":
|
case "FortVariantTokenType":
|
||||||
case "FortDecoItemDefinition":
|
case "FortDecoItemDefinition":
|
||||||
case "FortStatItemDefinition":
|
case "FortStatItemDefinition":
|
||||||
@@ -88,6 +91,7 @@ public class CreatorPackage : IDisposable
|
|||||||
case "SparksBassItemDefinition":
|
case "SparksBassItemDefinition":
|
||||||
case "FortGadgetItemDefinition":
|
case "FortGadgetItemDefinition":
|
||||||
case "AthenaCharmItemDefinition":
|
case "AthenaCharmItemDefinition":
|
||||||
|
case "FortHackKeyItemDefinition":
|
||||||
case "FortPlaysetItemDefinition":
|
case "FortPlaysetItemDefinition":
|
||||||
case "FortGiftBoxItemDefinition":
|
case "FortGiftBoxItemDefinition":
|
||||||
case "FortOutpostItemDefinition":
|
case "FortOutpostItemDefinition":
|
||||||
@@ -124,6 +128,7 @@ public class CreatorPackage : IDisposable
|
|||||||
case "JunoRecipeBundleItemDefinition":
|
case "JunoRecipeBundleItemDefinition":
|
||||||
case "FortHomebaseNodeItemDefinition":
|
case "FortHomebaseNodeItemDefinition":
|
||||||
case "FortNeverPersistItemDefinition":
|
case "FortNeverPersistItemDefinition":
|
||||||
|
case "FortHackCartridgeItemDefinition":
|
||||||
case "FortPlayerAugmentItemDefinition":
|
case "FortPlayerAugmentItemDefinition":
|
||||||
case "FortSmartBuildingItemDefinition":
|
case "FortSmartBuildingItemDefinition":
|
||||||
case "FortGiftBoxUnlockItemDefinition":
|
case "FortGiftBoxUnlockItemDefinition":
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ public enum EAssetCategory : uint
|
|||||||
CustomizableObject = Mesh + 3,
|
CustomizableObject = Mesh + 3,
|
||||||
NaniteDisplacedMesh = Mesh + 4,
|
NaniteDisplacedMesh = Mesh + 4,
|
||||||
GeometryCollection = Mesh + 5,
|
GeometryCollection = Mesh + 5,
|
||||||
|
ChaosClothAsset = Mesh + 6,
|
||||||
Texture = AssetCategoryExtensions.CategoryBase + (3 << 16),
|
Texture = AssetCategoryExtensions.CategoryBase + (3 << 16),
|
||||||
Materials = AssetCategoryExtensions.CategoryBase + (4 << 16),
|
Materials = AssetCategoryExtensions.CategoryBase + (4 << 16),
|
||||||
Material = Materials + 1,
|
Material = Materials + 1,
|
||||||
@@ -167,6 +168,15 @@ public enum EAssetCategory : uint
|
|||||||
DeltaForce = GameSpecific + 4,
|
DeltaForce = GameSpecific + 4,
|
||||||
LegoBatman = GameSpecific + 5,
|
LegoBatman = GameSpecific + 5,
|
||||||
ArcSys = GameSpecific + 6,
|
ArcSys = GameSpecific + 6,
|
||||||
|
GothamKnights = GameSpecific + 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EAssetFamily
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Criware,
|
||||||
|
Wwise,
|
||||||
|
FMod,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum EUnluacMode
|
public enum EUnluacMode
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ public static class VisualTreeExtensions
|
|||||||
{
|
{
|
||||||
if (current is T t)
|
if (current is T t)
|
||||||
return t;
|
return t;
|
||||||
current = VisualTreeHelper.GetParent(current);
|
current = current is FrameworkContentElement contentElement
|
||||||
|
? contentElement.Parent
|
||||||
|
: VisualTreeHelper.GetParent(current);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -820,6 +820,33 @@
|
|||||||
<TextBlock VerticalAlignment="Center" Text="{Binding PendingRequest.DisplayText, Source={x:Static viewModels:SnooperViewModel.Instance}, Mode=OneWay, StringFormat={}{0}: double-click one}" />
|
<TextBlock VerticalAlignment="Center" Text="{Binding PendingRequest.DisplayText, Source={x:Static viewModels:SnooperViewModel.Instance}, Mode=OneWay, StringFormat={}{0}: double-click one}" />
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
|
|
||||||
|
<StatusBarItem Margin="0 0 10 0"
|
||||||
|
Padding="0"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
VerticalContentAlignment="Stretch"
|
||||||
|
Visibility="{Binding IsUpdateAvailable, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||||
|
<Button HorizontalContentAlignment="Stretch"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
Style="{StaticResource StatusBarButton}"
|
||||||
|
Background="{DynamicResource {x:Static adonisUi:Brushes.AlertBrush}}"
|
||||||
|
ToolTip="A new version of FModel is available. Click to view it."
|
||||||
|
Command="{Binding MenuCommand}"
|
||||||
|
CommandParameter="Help_Releases">
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
VerticalAlignment="Center">
|
||||||
|
<Viewbox Width="16"
|
||||||
|
Height="16">
|
||||||
|
<Canvas Width="24"
|
||||||
|
Height="24">
|
||||||
|
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}"
|
||||||
|
Data="{StaticResource UpdateIcon}" />
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
|
<TextBlock Margin="10 0 0 0"
|
||||||
|
Text="Update Available" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</StatusBarItem>
|
||||||
<StatusBarItem Margin="0 0 10 0" Padding="0" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
|
<StatusBarItem Margin="0 0 10 0" Padding="0" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
|
||||||
<Button x:Name="ExportSessionButton"
|
<Button x:Name="ExportSessionButton"
|
||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ public class FModelApiEndpoint : AbstractApiProvider
|
|||||||
UserSettings.Default.LastUpdateCheck = DateTime.Now;
|
UserSettings.Default.LastUpdateCheck = DateTime.Now;
|
||||||
|
|
||||||
var targetHash = ((CustomMandatory) args.Mandatory).CommitHash;
|
var targetHash = ((CustomMandatory) args.Mandatory).CommitHash;
|
||||||
|
_applicationView.IsUpdateAvailable = targetHash != Constants.APP_COMMIT_ID;
|
||||||
if (targetHash == Constants.APP_COMMIT_ID)
|
if (targetHash == Constants.APP_COMMIT_ID)
|
||||||
{
|
{
|
||||||
if (UserSettings.Default.ShowChangelog)
|
if (UserSettings.Default.ShowChangelog)
|
||||||
|
|||||||
@@ -61,6 +61,13 @@ public class ApplicationViewModel : ViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _isUpdateAvailable;
|
||||||
|
public bool IsUpdateAvailable
|
||||||
|
{
|
||||||
|
get => _isUpdateAvailable;
|
||||||
|
internal set => SetProperty(ref _isUpdateAvailable, value);
|
||||||
|
}
|
||||||
|
|
||||||
private int _selectedLeftTabIndex;
|
private int _selectedLeftTabIndex;
|
||||||
public int SelectedLeftTabIndex
|
public int SelectedLeftTabIndex
|
||||||
{
|
{
|
||||||
@@ -139,7 +146,7 @@ public class ApplicationViewModel : ViewModel
|
|||||||
public DirectorySettings AvoidEmptyGameDirectory(bool bAlreadyLaunched)
|
public DirectorySettings AvoidEmptyGameDirectory(bool bAlreadyLaunched)
|
||||||
{
|
{
|
||||||
var gameDirectory = UserSettings.Default.GameDirectory;
|
var gameDirectory = UserSettings.Default.GameDirectory;
|
||||||
if (!bAlreadyLaunched && UserSettings.Default.PerDirectory.TryGetValue(gameDirectory, out var currentDir))
|
if (!bAlreadyLaunched && GameSelectorViewModel.IsGameDirectoryAvailable(gameDirectory) && UserSettings.Default.PerDirectory.TryGetValue(gameDirectory, out var currentDir))
|
||||||
return currentDir;
|
return currentDir;
|
||||||
|
|
||||||
Status.SetStatus(EStatusKind.Configuring);
|
Status.SetStatus(EStatusKind.Configuring);
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ using CSCore.CoreAudioAPI;
|
|||||||
using CSCore.DSP;
|
using CSCore.DSP;
|
||||||
using CSCore.SoundOut;
|
using CSCore.SoundOut;
|
||||||
using CSCore.Streams;
|
using CSCore.Streams;
|
||||||
using CUE4Parse.UE4.CriWare.Decoders;
|
using CUE4Parse.UE4.Criware.Decoders;
|
||||||
using CUE4Parse.UE4.CriWare.Decoders.ADX;
|
using CUE4Parse.UE4.Criware.Decoders.ADX;
|
||||||
using CUE4Parse.UE4.CriWare.Decoders.HCA;
|
using CUE4Parse.UE4.Criware.Decoders.HCA;
|
||||||
using CUE4Parse.Utils;
|
using CUE4Parse.Utils;
|
||||||
using FModel.Extensions;
|
using FModel.Extensions;
|
||||||
using FModel.Framework;
|
using FModel.Framework;
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ using System.Text.RegularExpressions;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AdonisUI.Controls;
|
using AdonisUI.Controls;
|
||||||
|
using CUE4Parse_Conversion.Exporters;
|
||||||
|
using CUE4Parse_Conversion.Sounds;
|
||||||
using CUE4Parse;
|
using CUE4Parse;
|
||||||
using CUE4Parse.Compression;
|
using CUE4Parse.Compression;
|
||||||
using CUE4Parse.Encryption.Aes;
|
using CUE4Parse.Encryption.Aes;
|
||||||
@@ -22,15 +24,17 @@ using CUE4Parse.GameTypes.AshEchoes.FileProvider;
|
|||||||
using CUE4Parse.GameTypes.Borderlands3.Assets.Exports;
|
using CUE4Parse.GameTypes.Borderlands3.Assets.Exports;
|
||||||
using CUE4Parse.GameTypes.Borderlands4.Assets.Exports;
|
using CUE4Parse.GameTypes.Borderlands4.Assets.Exports;
|
||||||
using CUE4Parse.GameTypes.Borderlands4.Wwise;
|
using CUE4Parse.GameTypes.Borderlands4.Wwise;
|
||||||
|
using CUE4Parse.GameTypes.Dawnwalker.Assets.Exports;
|
||||||
using CUE4Parse.GameTypes.DFHO.Assets.Objects;
|
using CUE4Parse.GameTypes.DFHO.Assets.Objects;
|
||||||
using CUE4Parse.GameTypes.HonorOfKings.FileProvider;
|
using CUE4Parse.GameTypes.HonorOfKings.FileProvider;
|
||||||
using CUE4Parse.GameTypes.KRD.Assets.Exports;
|
using CUE4Parse.GameTypes.KRD.Assets.Exports;
|
||||||
using CUE4Parse.GameTypes.LegoBatman.Assets;
|
using CUE4Parse.GameTypes.LegoBatman.Assets;
|
||||||
using CUE4Parse.GameTypes.LordOfMysteries.FileProvider;
|
using CUE4Parse.GameTypes.LordOfMysteries.FileProvider;
|
||||||
using CUE4Parse.GameTypes.RocoKingdomWorld.Assets.Objects;
|
using CUE4Parse.GameTypes.Tencent.RocoKingdomWorld.Assets.Objects;
|
||||||
using CUE4Parse.GameTypes.SMG.UE4.Assets.Exports.Wwise;
|
using CUE4Parse.GameTypes.SMG.UE4.Assets.Exports.Wwise;
|
||||||
using CUE4Parse.GameTypes.SquareEnix.UE4.Assets.Exports;
|
using CUE4Parse.GameTypes.SquareEnix.UE4.Assets.Exports;
|
||||||
using CUE4Parse.GameTypes.Theia.FileProvider;
|
using CUE4Parse.GameTypes.Theia.FileProvider;
|
||||||
|
using CUE4Parse.GameTypes.WarnerBros.GothamKnights.Assets.Exports.Wwise;
|
||||||
using CUE4Parse.MappingsProvider;
|
using CUE4Parse.MappingsProvider;
|
||||||
using CUE4Parse.MappingsProvider.Jmap;
|
using CUE4Parse.MappingsProvider.Jmap;
|
||||||
using CUE4Parse.MappingsProvider.Usmap;
|
using CUE4Parse.MappingsProvider.Usmap;
|
||||||
@@ -38,10 +42,11 @@ using CUE4Parse.UE4.AssetRegistry;
|
|||||||
using CUE4Parse.UE4.Assets;
|
using CUE4Parse.UE4.Assets;
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Animation;
|
using CUE4Parse.UE4.Assets.Exports.Animation;
|
||||||
using CUE4Parse.UE4.Assets.Exports.CriWare;
|
using CUE4Parse.UE4.Assets.Exports.Criware;
|
||||||
|
using CUE4Parse.UE4.Assets.Exports.Engine;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Fmod;
|
using CUE4Parse.UE4.Assets.Exports.Fmod;
|
||||||
|
using CUE4Parse.UE4.Assets.Exports.GeometryCollection;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports.Sound;
|
using CUE4Parse.UE4.Assets.Exports.Sound;
|
||||||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||||
@@ -49,8 +54,8 @@ using CUE4Parse.UE4.Assets.Exports.Verse;
|
|||||||
using CUE4Parse.UE4.Assets.Exports.Wwise;
|
using CUE4Parse.UE4.Assets.Exports.Wwise;
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
using CUE4Parse.UE4.Assets.Objects;
|
||||||
using CUE4Parse.UE4.BinaryConfig;
|
using CUE4Parse.UE4.BinaryConfig;
|
||||||
using CUE4Parse.UE4.CriWare;
|
using CUE4Parse.UE4.Criware;
|
||||||
using CUE4Parse.UE4.CriWare.Readers;
|
using CUE4Parse.UE4.Criware.Readers;
|
||||||
using CUE4Parse.UE4.FMod;
|
using CUE4Parse.UE4.FMod;
|
||||||
using CUE4Parse.UE4.GameFeatures;
|
using CUE4Parse.UE4.GameFeatures;
|
||||||
using CUE4Parse.UE4.IO;
|
using CUE4Parse.UE4.IO;
|
||||||
@@ -1300,6 +1305,11 @@ public class CUE4ParseViewModel : ViewModel
|
|||||||
TabControl.SelectedTab.AddImage(sourceFile.SubstringAfterLast('/'), false, bitmap, false, updateUi);
|
TabControl.SelectedTab.AddImage(sourceFile.SubstringAfterLast('/'), false, bitmap, false, updateUi);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
case UBiomesMaskTextureData when (isNone || saveTextures) && pointer.Object.Value is UBiomesMaskTextureData biomes && biomes.MaskData is { } maskData:
|
||||||
|
{
|
||||||
|
TabControl.SelectedTab.AddImage(biomes.Name, false, SKBitmap.Decode(maskData.Value), false, updateUi);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// Supermassive Games (for example - The Dark Pictures Anthology: House of Ashes etc.)
|
// Supermassive Games (for example - The Dark Pictures Anthology: House of Ashes etc.)
|
||||||
case UExternalSource when (isNone || saveAudio) && pointer.Object.Value is UExternalSource externalSource:
|
case UExternalSource when (isNone || saveAudio) && pointer.Object.Value is UExternalSource externalSource:
|
||||||
{
|
{
|
||||||
@@ -1506,12 +1516,37 @@ public class CUE4ParseViewModel : ViewModel
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// Gotham Knights
|
||||||
|
case UOrpheusBank when (isNone || saveAudio) && pointer.Object.Value is UOrpheusBank orpheusBank:
|
||||||
|
{
|
||||||
|
if (orpheusBank.SoundBank is null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var extractedSounds = WwiseProvider.ExtractBankSounds(orpheusBank.SoundBank);
|
||||||
|
foreach (var sound in extractedSounds)
|
||||||
|
{
|
||||||
|
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data?.GetData() ?? [], saveAudio, updateUi);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Gotham Knights
|
||||||
|
case UOrpheusEvent when (isNone || saveAudio) && pointer.Object.Value is UOrpheusEvent orpheusEvent:
|
||||||
|
{
|
||||||
|
var extractedSounds = WwiseProvider.ExtractGothamKnightsAudioEventSounds(orpheusEvent);
|
||||||
|
foreach (var sound in extractedSounds)
|
||||||
|
{
|
||||||
|
SaveAndPlaySound(cancellationToken, sound.OutputPath, sound.Extension, sound.Data?.GetData() ?? [], saveAudio, updateUi);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
case UWorld when isNone && UserSettings.Default.PreviewWorlds:
|
case UWorld when isNone && UserSettings.Default.PreviewWorlds:
|
||||||
case UBlueprintGeneratedClass when isNone && UserSettings.Default.PreviewWorlds:
|
case UBlueprintGeneratedClass when isNone && UserSettings.Default.PreviewWorlds:
|
||||||
// case UPaperSprite when isNone && UserSettings.Default.PreviewMaterials:
|
// case UPaperSprite when isNone && UserSettings.Default.PreviewMaterials:
|
||||||
case UStaticMesh when isNone && UserSettings.Default.PreviewStaticMeshes:
|
case UStaticMesh when isNone && UserSettings.Default.PreviewStaticMeshes:
|
||||||
case UGeometryCollection when isNone && UserSettings.Default.PreviewStaticMeshes:
|
case UGeometryCollection when isNone && UserSettings.Default.PreviewStaticMeshes:
|
||||||
case USkeletalMesh when isNone && UserSettings.Default.PreviewSkeletalMeshes:
|
case USkinnedAsset when isNone && UserSettings.Default.PreviewSkeletalMeshes:
|
||||||
case USkeleton when isNone && UserSettings.Default.SaveSkeletonAsMesh:
|
case USkeleton when isNone && UserSettings.Default.SaveSkeletonAsMesh:
|
||||||
case UAnimationAsset when isNone && UserSettings.Default.PreviewAnimations:
|
case UAnimationAsset when isNone && UserSettings.Default.PreviewAnimations:
|
||||||
// case UMaterialInstance when isNone && UserSettings.Default.PreviewMaterials &&
|
// case UMaterialInstance when isNone && UserSettings.Default.PreviewMaterials &&
|
||||||
@@ -1524,7 +1559,8 @@ public class CUE4ParseViewModel : ViewModel
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case UStaticMesh when HasFlag(bulk, EBulkType.Meshes):
|
case UStaticMesh when HasFlag(bulk, EBulkType.Meshes):
|
||||||
case USkeletalMesh when HasFlag(bulk, EBulkType.Meshes):
|
case UGeometryCollection when HasFlag(bulk, EBulkType.Meshes):
|
||||||
|
case USkinnedAsset when HasFlag(bulk, EBulkType.Meshes):
|
||||||
case USkeleton when UserSettings.Default.SaveSkeletonAsMesh && HasFlag(bulk, EBulkType.Meshes):
|
case USkeleton when UserSettings.Default.SaveSkeletonAsMesh && HasFlag(bulk, EBulkType.Meshes):
|
||||||
// case UMaterialInterface when HasFlag(bulk, EBulkType.Materials):
|
// case UMaterialInterface when HasFlag(bulk, EBulkType.Materials):
|
||||||
case UAnimationAsset when HasFlag(bulk, EBulkType.Animations):
|
case UAnimationAsset when HasFlag(bulk, EBulkType.Animations):
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ public class LoadCommand : ViewModelCommand<LoadingModesViewModel>
|
|||||||
{
|
{
|
||||||
entries.Add(asset);
|
entries.Add(asset);
|
||||||
}
|
}
|
||||||
else if (includeLooseFiles && asset is OsGameFile)
|
else if (includeLooseFiles && asset is not VfsEntry)
|
||||||
{
|
{
|
||||||
entries.Add(asset);
|
entries.Add(asset);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
using CUE4Parse_Conversion.Textures;
|
||||||
using CUE4Parse.FileProvider.Objects;
|
using CUE4Parse.FileProvider.Objects;
|
||||||
using CUE4Parse.GameTypes.Borderlands3.Assets.Exports;
|
using CUE4Parse.GameTypes.Borderlands3.Assets.Exports;
|
||||||
using CUE4Parse.GameTypes.Borderlands4.Assets.Exports;
|
using CUE4Parse.GameTypes.Borderlands4.Assets.Exports;
|
||||||
@@ -15,12 +15,15 @@ using CUE4Parse.GameTypes.RED.Assets.Exports;
|
|||||||
using CUE4Parse.GameTypes.SMG.UE4.Assets.Exports.Wwise;
|
using CUE4Parse.GameTypes.SMG.UE4.Assets.Exports.Wwise;
|
||||||
using CUE4Parse.GameTypes.SMG.UE4.Assets.Objects;
|
using CUE4Parse.GameTypes.SMG.UE4.Assets.Objects;
|
||||||
using CUE4Parse.GameTypes.SquareEnix.UE4.Assets.Exports;
|
using CUE4Parse.GameTypes.SquareEnix.UE4.Assets.Exports;
|
||||||
|
using CUE4Parse.GameTypes.WarnerBros.GothamKnights.Assets.Exports.Wwise;
|
||||||
using CUE4Parse.UE4.Assets;
|
using CUE4Parse.UE4.Assets;
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Animation;
|
using CUE4Parse.UE4.Assets.Exports.Animation;
|
||||||
using CUE4Parse.UE4.Assets.Exports.BuildData;
|
using CUE4Parse.UE4.Assets.Exports.BuildData;
|
||||||
|
using CUE4Parse.UE4.Assets.Exports.ChaosClothAsset;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Component;
|
using CUE4Parse.UE4.Assets.Exports.Component;
|
||||||
using CUE4Parse.UE4.Assets.Exports.CriWare;
|
using CUE4Parse.UE4.Assets.Exports.Criware;
|
||||||
|
using CUE4Parse.UE4.Assets.Exports.Criware.Media;
|
||||||
using CUE4Parse.UE4.Assets.Exports.CustomizableObject;
|
using CUE4Parse.UE4.Assets.Exports.CustomizableObject;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Engine;
|
using CUE4Parse.UE4.Assets.Exports.Engine;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Engine.Font;
|
using CUE4Parse.UE4.Assets.Exports.Engine.Font;
|
||||||
@@ -51,17 +54,11 @@ using CUE4Parse.UE4.Objects.UObject;
|
|||||||
using CUE4Parse.UE4.Objects.UObject.Editor;
|
using CUE4Parse.UE4.Objects.UObject.Editor;
|
||||||
using CUE4Parse.UE4.Versions;
|
using CUE4Parse.UE4.Versions;
|
||||||
using CUE4Parse.Utils;
|
using CUE4Parse.Utils;
|
||||||
|
|
||||||
using CUE4Parse_Conversion.Textures;
|
|
||||||
|
|
||||||
using FModel.Framework;
|
using FModel.Framework;
|
||||||
using FModel.Services;
|
using FModel.Services;
|
||||||
using FModel.Settings;
|
using FModel.Settings;
|
||||||
|
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
using Svg.Skia;
|
using Svg.Skia;
|
||||||
|
|
||||||
namespace FModel.ViewModels;
|
namespace FModel.ViewModels;
|
||||||
@@ -101,6 +98,13 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EAssetFamily _assetFamily = EAssetFamily.None;
|
||||||
|
public EAssetFamily AssetFamily
|
||||||
|
{
|
||||||
|
get => _assetFamily;
|
||||||
|
private set => SetProperty(ref _assetFamily, value);
|
||||||
|
}
|
||||||
|
|
||||||
private EBulkType _assetActions = EBulkType.None;
|
private EBulkType _assetActions = EBulkType.None;
|
||||||
public EBulkType AssetActions
|
public EBulkType AssetActions
|
||||||
{
|
{
|
||||||
@@ -204,6 +208,20 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||||||
var dummy = ((AbstractUePackage) pkg).ConstructObject(pointer.Class, pkg);
|
var dummy = ((AbstractUePackage) pkg).ConstructObject(pointer.Class, pkg);
|
||||||
ResolvedAssetType = dummy.ExportType;
|
ResolvedAssetType = dummy.ExportType;
|
||||||
|
|
||||||
|
AssetFamily = dummy switch
|
||||||
|
{
|
||||||
|
UAtomSoundBase or UAtomSoundBank or USoundAtomCue or USoundAtomCueSheet
|
||||||
|
or USoundAtomConfig or UAtomDspBusSetting or UAtomRackBase => EAssetFamily.Criware,
|
||||||
|
|
||||||
|
UAkAudioType or UAkAssetData or UAkAssetPlatformData or UAkMediaAssetData
|
||||||
|
or UAkMediaAsset or UWwiseAssetLibrary or UExternalSource or UExternalSourceBank => EAssetFamily.Wwise,
|
||||||
|
|
||||||
|
UFMODEvent or UFMODBank or UFMODBankLookup or UFMODBus
|
||||||
|
or UFMODSnapshot or UFMODSnapshotReverb or UFMODVCA => EAssetFamily.FMod,
|
||||||
|
|
||||||
|
_ => EAssetFamily.None,
|
||||||
|
};
|
||||||
|
|
||||||
(AssetCategory, AssetActions) = dummy switch
|
(AssetCategory, AssetActions) = dummy switch
|
||||||
{
|
{
|
||||||
URigVMBlueprintGeneratedClass => (EAssetCategory.RigVMBlueprintGeneratedClass, EBulkType.Code),
|
URigVMBlueprintGeneratedClass => (EAssetCategory.RigVMBlueprintGeneratedClass, EBulkType.Code),
|
||||||
@@ -217,9 +235,10 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||||||
|
|
||||||
UStaticMesh => (EAssetCategory.StaticMesh, EBulkType.Meshes),
|
UStaticMesh => (EAssetCategory.StaticMesh, EBulkType.Meshes),
|
||||||
USkeletalMesh => (EAssetCategory.SkeletalMesh, EBulkType.Meshes),
|
USkeletalMesh => (EAssetCategory.SkeletalMesh, EBulkType.Meshes),
|
||||||
|
UChaosClothAsset => (EAssetCategory.ChaosClothAsset, EBulkType.Meshes),
|
||||||
UCustomizableObject => (EAssetCategory.CustomizableObject, EBulkType.None),
|
UCustomizableObject => (EAssetCategory.CustomizableObject, EBulkType.None),
|
||||||
UNaniteDisplacedMesh => (EAssetCategory.NaniteDisplacedMesh, EBulkType.None),
|
UNaniteDisplacedMesh => (EAssetCategory.NaniteDisplacedMesh, EBulkType.None),
|
||||||
UGeometryCollection => (EAssetCategory.GeometryCollection, EBulkType.None),
|
UGeometryCollection => (EAssetCategory.GeometryCollection, EBulkType.Meshes),
|
||||||
|
|
||||||
UTexture => (EAssetCategory.Texture, EBulkType.Textures),
|
UTexture => (EAssetCategory.Texture, EBulkType.Textures),
|
||||||
|
|
||||||
@@ -245,18 +264,23 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||||||
UObjectRedirector => (EAssetCategory.ObjectRedirector, EBulkType.None),
|
UObjectRedirector => (EAssetCategory.ObjectRedirector, EBulkType.None),
|
||||||
UPhysicalMaterial => (EAssetCategory.PhysicalMaterial, EBulkType.None),
|
UPhysicalMaterial => (EAssetCategory.PhysicalMaterial, EBulkType.None),
|
||||||
|
|
||||||
USoundAtomCue or UAkAudioEvent or USoundCue or UFMODEvent
|
USoundAtomCue or UAtomSoundCue or UAkAudioEvent or USoundCue or UFMODEvent
|
||||||
or UAkAssetData or UAkAssetPlatformData => (EAssetCategory.AudioEvent, EBulkType.Audio),
|
or UAkAssetData or UAkAssetPlatformData => (EAssetCategory.AudioEvent, EBulkType.Audio),
|
||||||
|
|
||||||
UFMODBankLookup => (EAssetCategory.Data, EBulkType.None),
|
UFileManaMovie => (EAssetCategory.Video, EBulkType.None),
|
||||||
|
|
||||||
UFMODBus or UFMODSnapshot or UFMODSnapshotReverb or UFMODVCA or USQEXSEADSoundAttenuation => (EAssetCategory.Audio, EBulkType.None),
|
UFMODBankLookup or USoundAtomConfig or UFMODSnapshotReverb or UFMODBus or UFMODSnapshot
|
||||||
|
or UFMODVCA or UAtomDspBusSetting => (EAssetCategory.Data, EBulkType.None),
|
||||||
|
|
||||||
UFMODBank or UAkAudioBank or UAtomWaveBank or UAkInitBank or USQEXSEADSoundBank => (EAssetCategory.SoundBank, EBulkType.Audio),
|
USQEXSEADSoundAttenuation => (EAssetCategory.Audio, EBulkType.None),
|
||||||
|
|
||||||
UWwiseAssetLibrary or USoundBase or UAkMediaAssetData or UAtomCueSheet
|
UFMODBank or UAkAudioBank or UAtomSoundBank or USoundAtomCueSheet
|
||||||
or USoundAtomCueSheet or UAkAudioType or UExternalSource or UExternalSourceBank
|
or UAkInitBank or USQEXSEADSoundBank => (EAssetCategory.SoundBank, EBulkType.Audio),
|
||||||
or UAkMediaAsset => (EAssetCategory.Audio, EBulkType.Audio),
|
|
||||||
|
UWwiseAssetLibrary or UAtomSoundBase or USoundBase or UAkMediaAssetData
|
||||||
|
or UExternalSource or UExternalSourceBank or UAkMediaAsset => (EAssetCategory.Audio, EBulkType.Audio),
|
||||||
|
|
||||||
|
UAkAudioType => (EAssetCategory.Data, EBulkType.None),
|
||||||
|
|
||||||
UFileMediaSource => (EAssetCategory.Video, EBulkType.None),
|
UFileMediaSource => (EAssetCategory.Video, EBulkType.None),
|
||||||
UFont or UFontFace or USMGLocaleFontUMG => (EAssetCategory.Font, EBulkType.None),
|
UFont or UFontFace or USMGLocaleFontUMG => (EAssetCategory.Font, EBulkType.None),
|
||||||
@@ -269,6 +293,7 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||||||
UFaceFXAnimSet when GameVersion is EGame.GAME_Borderlands4 => (EAssetCategory.Borderlands, EBulkType.Audio), // Borderlands 4;
|
UFaceFXAnimSet when GameVersion is EGame.GAME_Borderlands4 => (EAssetCategory.Borderlands, EBulkType.Audio), // Borderlands 4;
|
||||||
UWubAudioEvent or UWubDialogueEvent when GameVersion is EGame.GAME_LEGOBatmanLegacyoftheDarkKnight => (EAssetCategory.LegoBatman, EBulkType.Audio), // Lego Batman: Legacy of the Dark Knight;
|
UWubAudioEvent or UWubDialogueEvent when GameVersion is EGame.GAME_LEGOBatmanLegacyoftheDarkKnight => (EAssetCategory.LegoBatman, EBulkType.Audio), // Lego Batman: Legacy of the Dark Knight;
|
||||||
UREDBinaryObject => (EAssetCategory.ArcSys, EBulkType.None), // Arc System Works games;
|
UREDBinaryObject => (EAssetCategory.ArcSys, EBulkType.None), // Arc System Works games;
|
||||||
|
UOrpheusBank or UOrpheusEvent => (EAssetCategory.GothamKnights, EBulkType.Audio), // Gotham Knights;
|
||||||
|
|
||||||
_ => (EAssetCategory.All, EBulkType.None),
|
_ => (EAssetCategory.All, EBulkType.None),
|
||||||
};
|
};
|
||||||
@@ -336,6 +361,15 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||||||
{
|
{
|
||||||
Resolved |= EResolveCompute.Preview;
|
Resolved |= EResolveCompute.Preview;
|
||||||
var lowercaseExtension = Asset.Extension.ToLowerInvariant();
|
var lowercaseExtension = Asset.Extension.ToLowerInvariant();
|
||||||
|
|
||||||
|
AssetFamily = lowercaseExtension switch
|
||||||
|
{
|
||||||
|
"acb" or "acf" or "adx" or "awb" or "hca" or "usm" => EAssetFamily.Criware,
|
||||||
|
"bnk" or "pck" or "wem" => EAssetFamily.Wwise,
|
||||||
|
"bank" or "fsb" => EAssetFamily.FMod,
|
||||||
|
_ => EAssetFamily.None,
|
||||||
|
};
|
||||||
|
|
||||||
switch (lowercaseExtension)
|
switch (lowercaseExtension)
|
||||||
{
|
{
|
||||||
case "uproject":
|
case "uproject":
|
||||||
@@ -365,6 +399,7 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||||||
case "sql":
|
case "sql":
|
||||||
case "py":
|
case "py":
|
||||||
case "cs":
|
case "cs":
|
||||||
|
case "acf":
|
||||||
AssetCategory = EAssetCategory.Data;
|
AssetCategory = EAssetCategory.Data;
|
||||||
break;
|
break;
|
||||||
case "stinfo":
|
case "stinfo":
|
||||||
@@ -375,6 +410,8 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||||||
break;
|
break;
|
||||||
case "wav":
|
case "wav":
|
||||||
case "awb": // This is technically soundbank and should be below but I want it to be distinguishable from "acb"
|
case "awb": // This is technically soundbank and should be below but I want it to be distinguishable from "acb"
|
||||||
|
case "adx":
|
||||||
|
case "hca":
|
||||||
case "xvag":
|
case "xvag":
|
||||||
case "flac":
|
case "flac":
|
||||||
case "at9":
|
case "at9":
|
||||||
@@ -385,6 +422,7 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||||||
break;
|
break;
|
||||||
case "acb":
|
case "acb":
|
||||||
case "bank":
|
case "bank":
|
||||||
|
case "fsb":
|
||||||
case "bnk":
|
case "bnk":
|
||||||
case "pck":
|
case "pck":
|
||||||
AssetCategory = EAssetCategory.SoundBank;
|
AssetCategory = EAssetCategory.SoundBank;
|
||||||
@@ -395,7 +433,9 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||||||
case "ttf":
|
case "ttf":
|
||||||
AssetCategory = EAssetCategory.Font;
|
AssetCategory = EAssetCategory.Font;
|
||||||
break;
|
break;
|
||||||
|
case "webm":
|
||||||
case "mp4":
|
case "mp4":
|
||||||
|
case "usm":
|
||||||
AssetCategory = EAssetCategory.Video;
|
AssetCategory = EAssetCategory.Video;
|
||||||
break;
|
break;
|
||||||
case "jpg":
|
case "jpg":
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public class GameSelectorViewModel : ViewModel
|
|||||||
|
|
||||||
if (DetectedDirectories.FirstOrDefault(x => x.GameDirectory == gameDirectory) is { } detectedGame)
|
if (DetectedDirectories.FirstOrDefault(x => x.GameDirectory == gameDirectory) is { } detectedGame)
|
||||||
SelectedDirectory = detectedGame;
|
SelectedDirectory = detectedGame;
|
||||||
else if (!string.IsNullOrEmpty(gameDirectory))
|
else if (IsGameDirectoryAvailable(gameDirectory))
|
||||||
AddUndetectedDir(gameDirectory);
|
AddUndetectedDir(gameDirectory);
|
||||||
else
|
else
|
||||||
SelectedDirectory = DetectedDirectories.FirstOrDefault();
|
SelectedDirectory = DetectedDirectories.FirstOrDefault();
|
||||||
@@ -189,6 +189,39 @@ public class GameSelectorViewModel : ViewModel
|
|||||||
SelectedDirectory = DetectedDirectories.Last();
|
SelectedDirectory = DetectedDirectories.Last();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int ClearMissingDirectories()
|
||||||
|
{
|
||||||
|
var removedDirectories = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
var missingDirectories = UserSettings.Default.PerDirectory
|
||||||
|
.Where(x => !IsGameDirectoryAvailable(x.Value.GameDirectory))
|
||||||
|
.Select(x => new KeyValuePair<string, string>(x.Key, x.Value.GameDirectory))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
foreach (var (key, gameDirectory) in missingDirectories)
|
||||||
|
{
|
||||||
|
UserSettings.Default.PerDirectory.Remove(key);
|
||||||
|
removedDirectories.Add(gameDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
var missingDetectedDirectories = _detectedDirectories
|
||||||
|
.Where(x => !IsGameDirectoryAvailable(x.GameDirectory))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
foreach (var directory in missingDetectedDirectories)
|
||||||
|
{
|
||||||
|
_detectedDirectories.Remove(directory);
|
||||||
|
removedDirectories.Add(directory.GameDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedDirectory is null || !_detectedDirectories.Contains(SelectedDirectory))
|
||||||
|
SelectedDirectory = DetectedDirectories.FirstOrDefault();
|
||||||
|
|
||||||
|
return removedDirectories.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsGameDirectoryAvailable(string gameDirectory)
|
||||||
|
=> gameDirectory is Constants._FN_LIVE_TRIGGER or Constants._VAL_LIVE_TRIGGER || Directory.Exists(gameDirectory);
|
||||||
|
|
||||||
private IEnumerable<EGame> EnumerateUeGames()
|
private IEnumerable<EGame> EnumerateUeGames()
|
||||||
=> Enum.GetValues<EGame>()
|
=> Enum.GetValues<EGame>()
|
||||||
.GroupBy(value => (int)value)
|
.GroupBy(value => (int)value)
|
||||||
@@ -196,8 +229,8 @@ public class GameSelectorViewModel : ViewModel
|
|||||||
.OrderBy(value => ((int)value & 0xFF) == 0);
|
.OrderBy(value => ((int)value & 0xFF) == 0);
|
||||||
private IEnumerable<DirectorySettings> EnumerateDetectedGames()
|
private IEnumerable<DirectorySettings> EnumerateDetectedGames()
|
||||||
{
|
{
|
||||||
yield return GetUnrealEngineGame("Fortnite", "\\FortniteGame\\Content\\Paks", EGame.GAME_UE5_8);
|
yield return GetUnrealEngineGame("Fortnite", "\\FortniteGame\\Content\\Paks", EGame.GAME_UE6_0);
|
||||||
yield return DirectorySettings.Default("Fortnite [LIVE]", Constants._FN_LIVE_TRIGGER, ue: EGame.GAME_UE5_8);
|
yield return DirectorySettings.Default("Fortnite [LIVE]", Constants._FN_LIVE_TRIGGER, ue: EGame.GAME_UE6_0);
|
||||||
yield return GetUnrealEngineGame("Pewee", "\\RogueCompany\\Content\\Paks", EGame.GAME_RogueCompany);
|
yield return GetUnrealEngineGame("Pewee", "\\RogueCompany\\Content\\Paks", EGame.GAME_RogueCompany);
|
||||||
yield return GetUnrealEngineGame("Rosemallow", "\\Indiana\\Content\\Paks", EGame.GAME_UE4_21);
|
yield return GetUnrealEngineGame("Rosemallow", "\\Indiana\\Content\\Paks", EGame.GAME_UE4_21);
|
||||||
yield return GetUnrealEngineGame("Catnip", "\\OakGame\\Content\\Paks", EGame.GAME_Borderlands3);
|
yield return GetUnrealEngineGame("Catnip", "\\OakGame\\Content\\Paks", EGame.GAME_Borderlands3);
|
||||||
|
|||||||
@@ -130,14 +130,18 @@
|
|||||||
adonisExtensions:LayerExtension.IncreaseLayer="True">
|
adonisExtensions:LayerExtension.IncreaseLayer="True">
|
||||||
<Grid Margin="30, 12, 6, 12">
|
<Grid Margin="30, 12, 6, 12">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Button Grid.Column="1" MinWidth="78" Margin="0 0 12 0" IsDefault="True" IsCancel="False"
|
<Button Grid.Column="0" MinWidth="78" Margin="0 0 12 0"
|
||||||
|
HorizontalAlignment="Left" VerticalAlignment="Bottom" Content="Clear"
|
||||||
|
ToolTip="Remove game directories that no longer exist" Click="OnClearDirectories" />
|
||||||
|
<Button Grid.Column="2" MinWidth="78" Margin="0 0 12 0" IsDefault="True" IsCancel="False"
|
||||||
HorizontalAlignment="Right" VerticalAlignment="Bottom" Content="OK" Click="OnClick" />
|
HorizontalAlignment="Right" VerticalAlignment="Bottom" Content="OK" Click="OnClick" />
|
||||||
<Button Grid.Column="2" MinWidth="78" Margin="0 0 12 0" IsDefault="False" IsCancel="True"
|
<Button Grid.Column="3" MinWidth="78" Margin="0 0 12 0" IsDefault="False" IsCancel="True"
|
||||||
HorizontalAlignment="Right" VerticalAlignment="Bottom" Content="Cancel" />
|
HorizontalAlignment="Right" VerticalAlignment="Bottom" Content="Cancel" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
using FModel.ViewModels;
|
using FModel.ViewModels;
|
||||||
|
using FModel.Views.Resources.Controls;
|
||||||
using Ookii.Dialogs.Wpf;
|
using Ookii.Dialogs.Wpf;
|
||||||
|
using Serilog;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using MessageBox = AdonisUI.Controls.MessageBox;
|
||||||
|
using MessageBoxButtons = AdonisUI.Controls.MessageBoxButtons;
|
||||||
|
using MessageBoxImage = AdonisUI.Controls.MessageBoxImage;
|
||||||
|
using MessageBoxModel = AdonisUI.Controls.MessageBoxModel;
|
||||||
|
using MessageBoxResult = AdonisUI.Controls.MessageBoxResult;
|
||||||
|
|
||||||
namespace FModel.Views;
|
namespace FModel.Views;
|
||||||
|
|
||||||
@@ -63,6 +70,37 @@ public partial class DirectorySelector
|
|||||||
gameLauncherViewModel.DeleteSelectedGame();
|
gameLauncherViewModel.DeleteSelectedGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnClearDirectories(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is not GameSelectorViewModel gameSelectorViewModel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var messageBox = new MessageBoxModel
|
||||||
|
{
|
||||||
|
Text = "Remove all saved game directories that no longer exist?",
|
||||||
|
Caption = "Clear Empty Directories",
|
||||||
|
Icon = MessageBoxImage.Question,
|
||||||
|
Buttons = MessageBoxButtons.YesNo(),
|
||||||
|
IsSoundEnabled = false
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageBox.Show(messageBox);
|
||||||
|
if (messageBox.Result != MessageBoxResult.Yes)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var removedCount = gameSelectorViewModel.ClearMissingDirectories();
|
||||||
|
var message = removedCount switch
|
||||||
|
{
|
||||||
|
0 => "No empty directories were found",
|
||||||
|
1 => "Removed 1 empty game directory",
|
||||||
|
_ => $"Removed {removedCount} empty game directories"
|
||||||
|
};
|
||||||
|
|
||||||
|
Log.Information("{Message}", message);
|
||||||
|
if (FLogger.Logger is not null) // When only directory selector is open, FLogger.Logger is null
|
||||||
|
FLogger.Append(ELog.Information, () => FLogger.Text(message, Constants.WHITE, true));
|
||||||
|
}
|
||||||
|
|
||||||
public void AddManualGame(string directory)
|
public void AddManualGame(string directory)
|
||||||
{
|
{
|
||||||
ManualGameExpander.IsExpanded = true;
|
ManualGameExpander.IsExpanded = true;
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
<SolidColorBrush x:Key="UserDefinedEnumBrush" Color="DarkGoldenrod" />
|
<SolidColorBrush x:Key="UserDefinedEnumBrush" Color="DarkGoldenrod" />
|
||||||
<SolidColorBrush x:Key="UserDefinedStructBrush" Color="Tan" />
|
<SolidColorBrush x:Key="UserDefinedStructBrush" Color="Tan" />
|
||||||
|
|
||||||
|
<SolidColorBrush x:Key="GroomAssetBrush" Color="RosyBrown " />
|
||||||
|
<SolidColorBrush x:Key="ChaosClothBrush" Color="LightSlateGray" />
|
||||||
<SolidColorBrush x:Key="CustomizableObjectBrush" Color="DarkRed" />
|
<SolidColorBrush x:Key="CustomizableObjectBrush" Color="DarkRed" />
|
||||||
<SolidColorBrush x:Key="NaniteDisplacedMeshBrush" Color="ForestGreen" />
|
<SolidColorBrush x:Key="NaniteDisplacedMeshBrush" Color="ForestGreen" />
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@
|
|||||||
<SolidColorBrush x:Key="BinaryBrush" Color="Yellow" />
|
<SolidColorBrush x:Key="BinaryBrush" Color="Yellow" />
|
||||||
<SolidColorBrush x:Key="TextureBrush" Color="MediumPurple" />
|
<SolidColorBrush x:Key="TextureBrush" Color="MediumPurple" />
|
||||||
<SolidColorBrush x:Key="ConfigBrush" Color="LightSlateGray" />
|
<SolidColorBrush x:Key="ConfigBrush" Color="LightSlateGray" />
|
||||||
|
|
||||||
<SolidColorBrush x:Key="AudioBrush" Color="MediumSeaGreen" />
|
<SolidColorBrush x:Key="AudioBrush" Color="MediumSeaGreen" />
|
||||||
<SolidColorBrush x:Key="SoundBankBrush" Color="DarkSeaGreen" />
|
<SolidColorBrush x:Key="SoundBankBrush" Color="DarkSeaGreen" />
|
||||||
<SolidColorBrush x:Key="AudioEventBrush" Color="LightSeaGreen" />
|
<SolidColorBrush x:Key="AudioEventBrush" Color="LightSeaGreen" />
|
||||||
@@ -52,6 +54,11 @@
|
|||||||
<SolidColorBrush x:Key="PythonBrush" Color="#3d77a8" />
|
<SolidColorBrush x:Key="PythonBrush" Color="#3d77a8" />
|
||||||
<SolidColorBrush x:Key="CSharpBrush" Color="#9e559a" />
|
<SolidColorBrush x:Key="CSharpBrush" Color="#9e559a" />
|
||||||
|
|
||||||
|
<!-- Asset family brushes -->
|
||||||
|
<SolidColorBrush x:Key="CriwareBrush" Color="#005bab" />
|
||||||
|
<SolidColorBrush x:Key="WwiseBrush" Color="#0152a1" />
|
||||||
|
<SolidColorBrush x:Key="FModBrush" Color="#00758f" />
|
||||||
|
|
||||||
<!-- For specific games -->
|
<!-- For specific games -->
|
||||||
<SolidColorBrush x:Key="BorderlandsBrush" Color="Yellow"></SolidColorBrush>
|
<SolidColorBrush x:Key="BorderlandsBrush" Color="Yellow"></SolidColorBrush>
|
||||||
<SolidColorBrush x:Key="AionBrush" Color="DeepSkyBlue"></SolidColorBrush>
|
<SolidColorBrush x:Key="AionBrush" Color="DeepSkyBlue"></SolidColorBrush>
|
||||||
|
|||||||
@@ -44,12 +44,14 @@
|
|||||||
<MultiBinding Converter="{x:Static converters:FileToGeometryConverter.Instance}">
|
<MultiBinding Converter="{x:Static converters:FileToGeometryConverter.Instance}">
|
||||||
<Binding Path="AssetCategory" />
|
<Binding Path="AssetCategory" />
|
||||||
<Binding Path="ResolvedAssetType" />
|
<Binding Path="ResolvedAssetType" />
|
||||||
|
<Binding Path="AssetFamily" />
|
||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</Path.Data>
|
</Path.Data>
|
||||||
<Path.Fill>
|
<Path.Fill>
|
||||||
<MultiBinding Converter="{x:Static converters:FileToGeometryConverter.Instance}">
|
<MultiBinding Converter="{x:Static converters:FileToGeometryConverter.Instance}">
|
||||||
<Binding Path="AssetCategory" />
|
<Binding Path="AssetCategory" />
|
||||||
<Binding Path="ResolvedAssetType" />
|
<Binding Path="ResolvedAssetType" />
|
||||||
|
<Binding Path="AssetFamily" />
|
||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</Path.Fill>
|
</Path.Fill>
|
||||||
</Path>
|
</Path>
|
||||||
|
|||||||
@@ -35,12 +35,14 @@
|
|||||||
<MultiBinding Converter="{x:Static converters:FileToGeometryConverter.Instance}">
|
<MultiBinding Converter="{x:Static converters:FileToGeometryConverter.Instance}">
|
||||||
<Binding Path="AssetCategory" />
|
<Binding Path="AssetCategory" />
|
||||||
<Binding Path="ResolvedAssetType" />
|
<Binding Path="ResolvedAssetType" />
|
||||||
|
<Binding Path="AssetFamily" />
|
||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</Path.Data>
|
</Path.Data>
|
||||||
<Path.Fill>
|
<Path.Fill>
|
||||||
<MultiBinding Converter="{x:Static converters:FileToGeometryConverter.Instance}">
|
<MultiBinding Converter="{x:Static converters:FileToGeometryConverter.Instance}">
|
||||||
<Binding Path="AssetCategory" />
|
<Binding Path="AssetCategory" />
|
||||||
<Binding Path="ResolvedAssetType" />
|
<Binding Path="ResolvedAssetType" />
|
||||||
|
<Binding Path="AssetFamily" />
|
||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</Path.Fill>
|
</Path.Fill>
|
||||||
</Path>
|
</Path>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Windows;
|
|||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
namespace FModel.Views.Resources.Controls;
|
namespace FModel.Views.Resources.Controls;
|
||||||
|
|
||||||
@@ -17,8 +18,9 @@ public class FilterableComboBox : ComboBox
|
|||||||
/// If true, on lost focus or enter key pressed, checks the text in the combobox. If the text is not present
|
/// If true, on lost focus or enter key pressed, checks the text in the combobox. If the text is not present
|
||||||
/// in the list, it leaves it blank.
|
/// in the list, it leaves it blank.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool OnlyValuesInList {
|
public bool OnlyValuesInList
|
||||||
get => (bool)GetValue(OnlyValuesInListProperty);
|
{
|
||||||
|
get => (bool) GetValue(OnlyValuesInListProperty);
|
||||||
set => SetValue(OnlyValuesInListProperty, value);
|
set => SetValue(OnlyValuesInListProperty, value);
|
||||||
}
|
}
|
||||||
public static readonly DependencyProperty OnlyValuesInListProperty =
|
public static readonly DependencyProperty OnlyValuesInListProperty =
|
||||||
@@ -27,8 +29,9 @@ public class FilterableComboBox : ComboBox
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Selected item, changes only on lost focus or enter key pressed
|
/// Selected item, changes only on lost focus or enter key pressed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object EffectivelySelectedItem {
|
public object EffectivelySelectedItem
|
||||||
get => (bool)GetValue(EffectivelySelectedItemProperty);
|
{
|
||||||
|
get => (bool) GetValue(EffectivelySelectedItemProperty);
|
||||||
set => SetValue(EffectivelySelectedItemProperty, value);
|
set => SetValue(EffectivelySelectedItemProperty, value);
|
||||||
}
|
}
|
||||||
public static readonly DependencyProperty EffectivelySelectedItemProperty =
|
public static readonly DependencyProperty EffectivelySelectedItemProperty =
|
||||||
@@ -38,6 +41,7 @@ public class FilterableComboBox : ComboBox
|
|||||||
private bool TextBoxFreezed;
|
private bool TextBoxFreezed;
|
||||||
protected TextBox EditableTextBox => GetTemplateChild("PART_EditableTextBox") as TextBox;
|
protected TextBox EditableTextBox => GetTemplateChild("PART_EditableTextBox") as TextBox;
|
||||||
private UserChange<bool> IsDropDownOpenUC;
|
private UserChange<bool> IsDropDownOpenUC;
|
||||||
|
private readonly DispatcherTimer FilterTimer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Triggers on lost focus or enter key pressed, if the selected item changed since the last time focus was lost or enter was pressed.
|
/// Triggers on lost focus or enter key pressed, if the selected item changed since the last time focus was lost or enter was pressed.
|
||||||
@@ -47,6 +51,15 @@ public class FilterableComboBox : ComboBox
|
|||||||
public FilterableComboBox()
|
public FilterableComboBox()
|
||||||
{
|
{
|
||||||
IsDropDownOpenUC = new UserChange<bool>(v => IsDropDownOpen = v);
|
IsDropDownOpenUC = new UserChange<bool>(v => IsDropDownOpen = v);
|
||||||
|
FilterTimer = new DispatcherTimer(DispatcherPriority.Background, Dispatcher)
|
||||||
|
{
|
||||||
|
Interval = TimeSpan.FromMilliseconds(125)
|
||||||
|
};
|
||||||
|
FilterTimer.Tick += (_, _) =>
|
||||||
|
{
|
||||||
|
FilterTimer.Stop();
|
||||||
|
RefreshFilter();
|
||||||
|
};
|
||||||
DropDownOpened += FilteredComboBox_DropDownOpened;
|
DropDownOpened += FilteredComboBox_DropDownOpened;
|
||||||
|
|
||||||
Focusable = true;
|
Focusable = true;
|
||||||
@@ -55,7 +68,8 @@ public class FilterableComboBox : ComboBox
|
|||||||
StaysOpenOnEdit = true;
|
StaysOpenOnEdit = true;
|
||||||
IsReadOnly = false;
|
IsReadOnly = false;
|
||||||
|
|
||||||
Loaded += (s, e) => {
|
Loaded += (s, e) =>
|
||||||
|
{
|
||||||
if (EditableTextBox != null)
|
if (EditableTextBox != null)
|
||||||
new TextBoxBaseUserChangeTracker(EditableTextBox).UserTextChanged += FilteredComboBox_UserTextChange;
|
new TextBoxBaseUserChangeTracker(EditableTextBox).UserTextChanged += FilteredComboBox_UserTextChange;
|
||||||
};
|
};
|
||||||
@@ -67,25 +81,53 @@ public class FilterableComboBox : ComboBox
|
|||||||
|
|
||||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (IsDropDownOpen && Keyboard.Modifiers == ModifierKeys.None && e.Key is Key.Up or Key.Down)
|
||||||
|
{
|
||||||
|
MoveSelection(e.Key);
|
||||||
|
e.Handled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
base.OnPreviewKeyDown(e);
|
base.OnPreviewKeyDown(e);
|
||||||
if (e.Key == Key.Down && !IsDropDownOpen) {
|
if (e.Key == Key.Down && !IsDropDownOpen)
|
||||||
|
{
|
||||||
|
ApplyPendingFilter();
|
||||||
IsDropDownOpen = true;
|
IsDropDownOpen = true;
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
else if (e.Key == Key.Escape) {
|
else if (e.Key == Key.Escape)
|
||||||
|
{
|
||||||
ClearFilter();
|
ClearFilter();
|
||||||
Text = "";
|
Text = "";
|
||||||
IsDropDownOpen = true;
|
IsDropDownOpen = true;
|
||||||
}
|
}
|
||||||
else if (e.Key == Key.Enter || e.Key == Key.Tab) {
|
else if (e.Key == Key.Enter || e.Key == Key.Tab)
|
||||||
|
{
|
||||||
|
ApplyPendingFilter();
|
||||||
CheckSelectedItem();
|
CheckSelectedItem();
|
||||||
TriggerSelectedItemChanged();
|
TriggerSelectedItemChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MoveSelection(Key key)
|
||||||
|
{
|
||||||
|
ApplyPendingFilter();
|
||||||
|
if (Items.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var index = SelectedItem == null ? -1 : Items.IndexOf(SelectedItem);
|
||||||
|
index = index < 0
|
||||||
|
? key == Key.Up ? Items.Count - 1 : 0
|
||||||
|
: Math.Clamp(index + (key == Key.Up ? -1 : 1), 0, Items.Count - 1);
|
||||||
|
|
||||||
|
SelectedItem = Items[index];
|
||||||
|
(ItemContainerGenerator.ContainerFromIndex(index) as ComboBoxItem)?.BringIntoView();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
|
protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnPreviewLostKeyboardFocus(e);
|
base.OnPreviewLostKeyboardFocus(e);
|
||||||
|
ApplyPendingFilter();
|
||||||
CheckSelectedItem();
|
CheckSelectedItem();
|
||||||
if ((e.OldFocus == this || e.OldFocus == EditableTextBox) && e.NewFocus != this && e.NewFocus != EditableTextBox)
|
if ((e.OldFocus == this || e.OldFocus == EditableTextBox) && e.NewFocus != this && e.NewFocus != EditableTextBox)
|
||||||
TriggerSelectedItemChanged();
|
TriggerSelectedItemChanged();
|
||||||
@@ -100,7 +142,8 @@ public class FilterableComboBox : ComboBox
|
|||||||
private bool shouldTriggerSelectedItemChanged = false;
|
private bool shouldTriggerSelectedItemChanged = false;
|
||||||
private void TriggerSelectedItemChanged()
|
private void TriggerSelectedItemChanged()
|
||||||
{
|
{
|
||||||
if (shouldTriggerSelectedItemChanged) {
|
if (shouldTriggerSelectedItemChanged)
|
||||||
|
{
|
||||||
SelectionEffectivelyChanged?.Invoke(this, SelectedItem);
|
SelectionEffectivelyChanged?.Invoke(this, SelectedItem);
|
||||||
shouldTriggerSelectedItemChanged = false;
|
shouldTriggerSelectedItemChanged = false;
|
||||||
}
|
}
|
||||||
@@ -108,9 +151,12 @@ public class FilterableComboBox : ComboBox
|
|||||||
|
|
||||||
public void ClearFilter()
|
public void ClearFilter()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(CurrentFilter)) return;
|
FilterTimer.Stop();
|
||||||
|
if (string.IsNullOrEmpty(CurrentFilter))
|
||||||
|
return;
|
||||||
CurrentFilter = "";
|
CurrentFilter = "";
|
||||||
CollectionViewSource.GetDefaultView(ItemsSource).Refresh();
|
if (ItemsSource != null)
|
||||||
|
CollectionViewSource.GetDefaultView(ItemsSource).Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FilteredComboBox_DropDownOpened(object sender, EventArgs e)
|
private void FilteredComboBox_DropDownOpened(object sender, EventArgs e)
|
||||||
@@ -121,47 +167,64 @@ public class FilterableComboBox : ComboBox
|
|||||||
|
|
||||||
private void FilteredComboBox_UserTextChange(object sender, EventArgs e)
|
private void FilteredComboBox_UserTextChange(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (TextBoxFreezed) return;
|
if (TextBoxFreezed)
|
||||||
|
return;
|
||||||
var tb = EditableTextBox;
|
var tb = EditableTextBox;
|
||||||
if (tb.SelectionStart + tb.SelectionLength == tb.Text.Length)
|
if (tb.SelectionStart + tb.SelectionLength == tb.Text.Length)
|
||||||
CurrentFilter = tb.Text.Substring(0, tb.SelectionStart).ToLower();
|
CurrentFilter = tb.Text.Substring(0, tb.SelectionStart);
|
||||||
else
|
else
|
||||||
CurrentFilter = tb.Text.ToLower();
|
CurrentFilter = tb.Text;
|
||||||
RefreshFilter();
|
|
||||||
|
FilterTimer.Stop();
|
||||||
|
FilterTimer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
|
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
|
||||||
{
|
{
|
||||||
if (newValue != null) {
|
FilterTimer.Stop();
|
||||||
|
|
||||||
|
if (newValue != null)
|
||||||
|
{
|
||||||
var view = CollectionViewSource.GetDefaultView(newValue);
|
var view = CollectionViewSource.GetDefaultView(newValue);
|
||||||
view.Filter += FilterItem;
|
view.Filter += FilterItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldValue != null) {
|
if (oldValue != null)
|
||||||
|
{
|
||||||
var view = CollectionViewSource.GetDefaultView(oldValue);
|
var view = CollectionViewSource.GetDefaultView(oldValue);
|
||||||
if (view != null) view.Filter -= FilterItem;
|
if (view != null)
|
||||||
|
view.Filter -= FilterItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnItemsSourceChanged(oldValue, newValue);
|
base.OnItemsSourceChanged(oldValue, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ApplyPendingFilter()
|
||||||
|
{
|
||||||
|
if (!FilterTimer.IsEnabled)
|
||||||
|
return;
|
||||||
|
FilterTimer.Stop();
|
||||||
|
RefreshFilter();
|
||||||
|
}
|
||||||
|
|
||||||
private void RefreshFilter()
|
private void RefreshFilter()
|
||||||
{
|
{
|
||||||
if (ItemsSource == null) return;
|
if (ItemsSource == null)
|
||||||
|
return;
|
||||||
|
|
||||||
var view = CollectionViewSource.GetDefaultView(ItemsSource);
|
var view = CollectionViewSource.GetDefaultView(ItemsSource);
|
||||||
FreezTextBoxState(() => {
|
FreezTextBoxState(() =>
|
||||||
var isDropDownOpen = IsDropDownOpen;
|
{
|
||||||
//always hide because showing it enables the user to pick with up and down keys, otherwise it's not working because of the glitch in view.Refresh()
|
|
||||||
IsDropDownOpenUC.Set(false);
|
|
||||||
view.Refresh();
|
view.Refresh();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(CurrentFilter) || isDropDownOpen)
|
if (!IsDropDownOpen && !string.IsNullOrEmpty(CurrentFilter))
|
||||||
IsDropDownOpenUC.Set(true);
|
IsDropDownOpenUC.Set(true);
|
||||||
|
|
||||||
if (SelectedItem == null) {
|
if (SelectedItem == null)
|
||||||
|
{
|
||||||
foreach (var itm in ItemsSource)
|
foreach (var itm in ItemsSource)
|
||||||
if (itm.ToString() == Text) {
|
if (itm.ToString() == Text)
|
||||||
|
{
|
||||||
SelectedItem = itm;
|
SelectedItem = itm;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -185,10 +248,16 @@ public class FilterableComboBox : ComboBox
|
|||||||
|
|
||||||
private bool FilterItem(object value)
|
private bool FilterItem(object value)
|
||||||
{
|
{
|
||||||
if (value == null) return false;
|
if (value == null)
|
||||||
if (CurrentFilter.Length == 0) return true;
|
return false;
|
||||||
|
if (CurrentFilter.Length == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
return value.ToString().ToLower().Contains(CurrentFilter);
|
var text = value.ToString();
|
||||||
|
if (text?.StartsWith("GAME_", StringComparison.OrdinalIgnoreCase) == true)
|
||||||
|
text = text[5..];
|
||||||
|
|
||||||
|
return text?.Contains(CurrentFilter, StringComparison.OrdinalIgnoreCase) == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TextBoxBaseUserChangeTracker
|
private class TextBoxBaseUserChangeTracker
|
||||||
@@ -205,11 +274,13 @@ public class FilterableComboBox : ComboBox
|
|||||||
TextBoxBase = textBoxBase;
|
TextBoxBase = textBoxBase;
|
||||||
LastText = TextBoxBase.ToString();
|
LastText = TextBoxBase.ToString();
|
||||||
|
|
||||||
textBoxBase.PreviewTextInput += (s, e) => {
|
textBoxBase.PreviewTextInput += (s, e) =>
|
||||||
|
{
|
||||||
IsTextInput = true;
|
IsTextInput = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
textBoxBase.TextChanged += (s, e) => {
|
textBoxBase.TextChanged += (s, e) =>
|
||||||
|
{
|
||||||
var isUserChange = PressedKeys.Count > 0 || IsTextInput || LastText == TextBoxBase.ToString();
|
var isUserChange = PressedKeys.Count > 0 || IsTextInput || LastText == TextBoxBase.ToString();
|
||||||
IsTextInput = false;
|
IsTextInput = false;
|
||||||
LastText = TextBoxBase.ToString();
|
LastText = TextBoxBase.ToString();
|
||||||
@@ -217,17 +288,21 @@ public class FilterableComboBox : ComboBox
|
|||||||
UserTextChanged?.Invoke(this, e);
|
UserTextChanged?.Invoke(this, e);
|
||||||
};
|
};
|
||||||
|
|
||||||
textBoxBase.PreviewKeyDown += (s, e) => {
|
textBoxBase.PreviewKeyDown += (s, e) =>
|
||||||
switch (e.Key) {
|
{
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
case Key.Back:
|
case Key.Back:
|
||||||
case Key.Space:
|
case Key.Space:
|
||||||
if (!PressedKeys.Contains(e.Key))
|
if (!PressedKeys.Contains(e.Key))
|
||||||
PressedKeys.Add(e.Key);
|
PressedKeys.Add(e.Key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (e.Key == Key.Back) {
|
if (e.Key == Key.Back)
|
||||||
|
{
|
||||||
var textBox = textBoxBase as TextBox;
|
var textBox = textBoxBase as TextBox;
|
||||||
if (textBox.SelectionStart > 0 && textBox.SelectionLength > 0 && (textBox.SelectionStart + textBox.SelectionLength) == textBox.Text.Length) {
|
if (textBox.SelectionStart > 0 && textBox.SelectionLength > 0 && (textBox.SelectionStart + textBox.SelectionLength) == textBox.Text.Length)
|
||||||
|
{
|
||||||
textBox.SelectionStart--;
|
textBox.SelectionStart--;
|
||||||
textBox.SelectionLength++;
|
textBox.SelectionLength++;
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
@@ -236,12 +311,14 @@ public class FilterableComboBox : ComboBox
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
textBoxBase.PreviewKeyUp += (s, e) => {
|
textBoxBase.PreviewKeyUp += (s, e) =>
|
||||||
|
{
|
||||||
if (PressedKeys.Contains(e.Key))
|
if (PressedKeys.Contains(e.Key))
|
||||||
PressedKeys.Remove(e.Key);
|
PressedKeys.Remove(e.Key);
|
||||||
};
|
};
|
||||||
|
|
||||||
textBoxBase.LostFocus += (s, e) => {
|
textBoxBase.LostFocus += (s, e) =>
|
||||||
|
{
|
||||||
PressedKeys.Clear();
|
PressedKeys.Clear();
|
||||||
IsTextInput = false;
|
IsTextInput = false;
|
||||||
};
|
};
|
||||||
@@ -261,11 +338,13 @@ public class FilterableComboBox : ComboBox
|
|||||||
|
|
||||||
public void Set(T val)
|
public void Set(T val)
|
||||||
{
|
{
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
IsUserChange = false;
|
IsUserChange = false;
|
||||||
action(val);
|
action(val);
|
||||||
}
|
}
|
||||||
finally {
|
finally
|
||||||
|
{
|
||||||
IsUserChange = true;
|
IsUserChange = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class FileToGeometryConverter : IMultiValueConverter
|
|||||||
|
|
||||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
if (values.Length < 2 || values[0] is not EAssetCategory category || values[1] is not string resolvedAssetType)
|
if (values.Length < 3 || values[0] is not EAssetCategory category || values[1] is not string resolvedAssetType || values[2] is not EAssetFamily family)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
resolvedAssetType = resolvedAssetType.ToLowerInvariant();
|
resolvedAssetType = resolvedAssetType.ToLowerInvariant();
|
||||||
@@ -32,6 +32,7 @@ public class FileToGeometryConverter : IMultiValueConverter
|
|||||||
|
|
||||||
EAssetCategory.StaticMesh => ("StaticMeshIconAlt", "NeutralBrush"),
|
EAssetCategory.StaticMesh => ("StaticMeshIconAlt", "NeutralBrush"),
|
||||||
EAssetCategory.SkeletalMesh => ("SkeletalMeshIconAlt", "NeutralBrush"),
|
EAssetCategory.SkeletalMesh => ("SkeletalMeshIconAlt", "NeutralBrush"),
|
||||||
|
EAssetCategory.ChaosClothAsset => ("ChaosClothIcon", "ChaosClothBrush"),
|
||||||
EAssetCategory.CustomizableObject => ("StaticMeshIconAlt", "CustomizableObjectBrush"),
|
EAssetCategory.CustomizableObject => ("StaticMeshIconAlt", "CustomizableObjectBrush"),
|
||||||
EAssetCategory.NaniteDisplacedMesh => ("StaticMeshIconAlt", "NaniteDisplacedMeshBrush"),
|
EAssetCategory.NaniteDisplacedMesh => ("StaticMeshIconAlt", "NaniteDisplacedMeshBrush"),
|
||||||
EAssetCategory.GeometryCollection => ("GeometryCollectionIcon", "NeutralBrush"),
|
EAssetCategory.GeometryCollection => ("GeometryCollectionIcon", "NeutralBrush"),
|
||||||
@@ -99,12 +100,26 @@ public class FileToGeometryConverter : IMultiValueConverter
|
|||||||
EAssetCategory.Aion2 => ("AionIcon", "AionBrush"),
|
EAssetCategory.Aion2 => ("AionIcon", "AionBrush"),
|
||||||
EAssetCategory.RocoKingdomWorld => ("RocoKingdomWorldIcon", "RocoKingdomWorldBrush"),
|
EAssetCategory.RocoKingdomWorld => ("RocoKingdomWorldIcon", "RocoKingdomWorldBrush"),
|
||||||
EAssetCategory.DeltaForce => ("DeltaForceIcon", "DeltaForceBrush"),
|
EAssetCategory.DeltaForce => ("DeltaForceIcon", "DeltaForceBrush"),
|
||||||
EAssetCategory.LegoBatman => ("BatmanIcon", "BatmanBrush"),
|
EAssetCategory.LegoBatman or EAssetCategory.GothamKnights => ("BatmanIcon", "BatmanBrush"),
|
||||||
EAssetCategory.ArcSys => ("ArcSysIcon", "ArcSysBrush"),
|
EAssetCategory.ArcSys => ("ArcSysIcon", "ArcSysBrush"),
|
||||||
|
|
||||||
_ => ("AssetIcon", "NeutralBrush")
|
_ => ("AssetIcon", "NeutralBrush")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(geometry, brush) = (family, category) switch
|
||||||
|
{
|
||||||
|
(EAssetFamily.Criware, EAssetCategory.Data) => ("CriwareIcon", "CriwareBrush"),
|
||||||
|
(EAssetFamily.Criware, _) => ("CriwareIcon", brush),
|
||||||
|
|
||||||
|
(EAssetFamily.Wwise, EAssetCategory.Data) => ("WwiseIcon", "WwiseBrush"),
|
||||||
|
(EAssetFamily.Wwise, _) => ("WwiseIcon", brush),
|
||||||
|
|
||||||
|
(EAssetFamily.FMod, EAssetCategory.Data) => ("FModIcon", "FModBrush"),
|
||||||
|
(EAssetFamily.FMod, _) => ("FModIcon", brush),
|
||||||
|
|
||||||
|
_ => (geometry, brush),
|
||||||
|
};
|
||||||
|
|
||||||
if (targetType == typeof(Geometry))
|
if (targetType == typeof(Geometry))
|
||||||
return Application.Current.FindResource(geometry) as Geometry;
|
return Application.Current.FindResource(geometry) as Geometry;
|
||||||
if (targetType == typeof(Brush))
|
if (targetType == typeof(Brush))
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1682,6 +1682,16 @@
|
|||||||
|
|
||||||
<Style x:Key="UComboBox" TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
|
<Style x:Key="UComboBox" TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
|
||||||
<Setter Property="adonisExtensions:WatermarkExtension.Watermark" Value="UE5 / UE4 / GameName..." />
|
<Setter Property="adonisExtensions:WatermarkExtension.Watermark" Value="UE5 / UE4 / GameName..." />
|
||||||
|
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
|
||||||
|
<Setter Property="VirtualizingPanel.IsVirtualizing" Value="True" />
|
||||||
|
<Setter Property="VirtualizingPanel.VirtualizationMode" Value="Recycling" />
|
||||||
|
<Setter Property="ItemsPanel">
|
||||||
|
<Setter.Value>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<VirtualizingStackPanel />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="ComboBox">
|
<ControlTemplate TargetType="ComboBox">
|
||||||
|
|||||||
Reference in New Issue
Block a user