mirror of
https://github.com/4sval/FModel.git
synced 2026-03-21 17:24:26 -05:00
added links to some exceptions + auto detect ue version (#657)
Some checks failed
FModel QA Builder / build (push) Has been cancelled
Some checks failed
FModel QA Builder / build (push) Has been cancelled
Co-authored-by: Asval <asval.contactme@gmail.com> Co-authored-by: Krowe-moh <27891447+Krowe-moh@users.noreply.github.com>
This commit is contained in:
parent
c9542f1a91
commit
639f21e574
|
|
@ -1 +1 @@
|
|||
Subproject commit 7ed9bd5adf3daada4bd7d884f3a42d163a64247a
|
||||
Subproject commit 6d7157a29b08d583aef9887a56d70f27a2ff36d5
|
||||
|
|
@ -40,6 +40,12 @@ public static class Constants
|
|||
|
||||
public const string _NO_PRESET_TRIGGER = "Hand Made";
|
||||
|
||||
// Common issues
|
||||
public const string MAPPING_ISSUE_LINK = "https://github.com/4sval/FModel/discussions/418";
|
||||
public const string AUDIO_ISSUE_LINK = "https://github.com/4sval/FModel/discussions/658";
|
||||
public const string RADA_ISSUE_LINK = "https://github.com/4sval/FModel/discussions/422";
|
||||
public const string VERSION_ISSUE_LINK = "https://github.com/4sval/FModel/discussions/425";
|
||||
|
||||
public static int PALETTE_LENGTH => COLOR_PALETTE.Length;
|
||||
public static readonly Vector3[] COLOR_PALETTE =
|
||||
{
|
||||
|
|
|
|||
|
|
@ -252,13 +252,6 @@ namespace FModel.Settings
|
|||
set => SetProperty(ref _imageMergerMargin, value);
|
||||
}
|
||||
|
||||
private bool _canExportRawData;
|
||||
public bool CanExportRawData
|
||||
{
|
||||
get => _canExportRawData;
|
||||
set => SetProperty(ref _canExportRawData, value);
|
||||
}
|
||||
|
||||
private bool _readScriptData;
|
||||
public bool ReadScriptData
|
||||
{
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ public class ApplicationViewModel : ViewModel
|
|||
}
|
||||
else
|
||||
{
|
||||
FLogger.Append(ELog.Error, () => FLogger.Text("Could not download VgmStream", Constants.WHITE, true));
|
||||
FLogger.Append(ELog.Error, () => FLogger.Text("Could not download vgmstream", Constants.WHITE, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,13 +298,23 @@ public class AudioPlayerViewModel : ViewModel, ISource, IDisposable
|
|||
Save(a, true);
|
||||
}
|
||||
|
||||
FLogger.Append(ELog.Information, () =>
|
||||
{
|
||||
FLogger.Text("Successfully saved audio from ", Constants.WHITE);
|
||||
FLogger.Link(_audioFiles.First().FileName, _audioFiles.First().FilePath, true);
|
||||
});
|
||||
if (_audioFiles.Count > 1)
|
||||
FLogger.Append(ELog.Information, () => FLogger.Text($"Successfully saved {_audioFiles.Count} audio files", Constants.WHITE, true));
|
||||
{
|
||||
var dir = new DirectoryInfo(Path.GetDirectoryName(_audioFiles.First().FilePath));
|
||||
FLogger.Append(ELog.Information, () =>
|
||||
{
|
||||
FLogger.Text($"Successfully saved {_audioFiles.Count} audio files to ", Constants.WHITE);
|
||||
FLogger.Link(dir.Name, dir.FullName, true);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
FLogger.Append(ELog.Information, () =>
|
||||
{
|
||||
FLogger.Text("Successfully saved ", Constants.WHITE);
|
||||
FLogger.Link(_audioFiles.First().FileName, _audioFiles.First().FilePath, true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -654,15 +664,24 @@ public class AudioPlayerViewModel : ViewModel, ISource, IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private bool TryConvert(out string wavFilePath) => TryConvert(SelectedAudioFile.FilePath, SelectedAudioFile.Data, out wavFilePath);
|
||||
public static bool TryConvert(string inputFilePath, byte[] inputFileData, out string wavFilePath)
|
||||
private bool TryConvert(out string wavFilePath) => TryConvert(SelectedAudioFile.FilePath, SelectedAudioFile.Data, out wavFilePath, true);
|
||||
public static bool TryConvert(string inputFilePath, byte[] inputFileData, out string wavFilePath, bool updateUi = false)
|
||||
{
|
||||
wavFilePath = string.Empty;
|
||||
var vgmFilePath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", "test.exe");
|
||||
if (!File.Exists(vgmFilePath))
|
||||
{
|
||||
vgmFilePath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", "vgmstream-cli.exe");
|
||||
if (!File.Exists(vgmFilePath)) return false;
|
||||
if (!File.Exists(vgmFilePath))
|
||||
{
|
||||
Log.Error("Failed to convert {InputFilePath}, vgmstream is missing", inputFilePath);
|
||||
FLogger.Append(ELog.Error, () =>
|
||||
{
|
||||
FLogger.Text("Failed to convert audio because vgmstream is missing. See: ", Constants.WHITE);
|
||||
FLogger.Link("→ link ←", Constants.AUDIO_ISSUE_LINK, true);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(inputFilePath.SubstringBeforeLast("/"));
|
||||
|
|
@ -679,7 +698,22 @@ public class AudioPlayerViewModel : ViewModel, ISource, IDisposable
|
|||
vgmProcess?.WaitForExit(5000);
|
||||
|
||||
File.Delete(inputFilePath);
|
||||
return vgmProcess?.ExitCode == 0 && File.Exists(wavFilePath);
|
||||
|
||||
var success = vgmProcess?.ExitCode == 0 && File.Exists(wavFilePath);
|
||||
if (!success)
|
||||
{
|
||||
Log.Error("Failed to convert {InputFilePath} to .wav format", inputFilePath);
|
||||
if (updateUi)
|
||||
{
|
||||
FLogger.Append(ELog.Error, () =>
|
||||
{
|
||||
FLogger.Text("Failed to convert audio to .wav format. See: ", Constants.WHITE);
|
||||
FLogger.Link("→ link ←", Constants.AUDIO_ISSUE_LINK, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool TryDecode(string extension, out string rawFilePath)
|
||||
|
|
@ -688,6 +722,12 @@ public class AudioPlayerViewModel : ViewModel, ISource, IDisposable
|
|||
var decoderPath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", $"{extension}dec.exe");
|
||||
if (!File.Exists(decoderPath))
|
||||
{
|
||||
Log.Error("Failed to convert {FilePath}, rada decoder is missing", SelectedAudioFile.FilePath);
|
||||
FLogger.Append(ELog.Error, () =>
|
||||
{
|
||||
FLogger.Text("Failed to convert audio because rada decoder is missing. See: ", Constants.WHITE);
|
||||
FLogger.Link("→ link ←", Constants.RADA_ISSUE_LINK, true);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1179,7 +1179,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case USoundWave when isNone || saveAudio:
|
||||
{
|
||||
// If UAkMediaAsset exists in the same package it should be used to handle the audio instead (because it contains actual audio name)
|
||||
if (pointer.Object.Value is UAkMediaAssetData dataObj && dataObj.Outer is UAkMediaAsset)
|
||||
if (pointer.Object.Value is UAkMediaAssetData dataObj && dataObj.Outer.Object.Value is UAkMediaAsset)
|
||||
return false;
|
||||
|
||||
var shouldDecompress = UserSettings.Default.CompressedAudioMode == ECompressedAudio.PlayDecompressed;
|
||||
|
|
@ -1196,7 +1196,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
}
|
||||
case UAkMediaAsset when (isNone || saveAudio) && pointer.Object.Value is UAkMediaAsset akMediaAsset:
|
||||
{
|
||||
var audioName = akMediaAsset.MediaName;
|
||||
var audioName = akMediaAsset.MediaName ?? akMediaAsset.Name;
|
||||
if (akMediaAsset.CurrentMediaAssetData?.TryLoad<UAkMediaAssetData>(out var akMediaAssetData) is true)
|
||||
{
|
||||
var shouldDecompress = UserSettings.Default.CompressedAudioMode is ECompressedAudio.PlayDecompressed;
|
||||
|
|
@ -1416,25 +1416,15 @@ public class CUE4ParseViewModel : ViewModel
|
|||
writer.Flush();
|
||||
}
|
||||
|
||||
bool conversionSuccess = true;
|
||||
if (UserSettings.Default.ConvertAudioOnBulkExport)
|
||||
{
|
||||
AudioPlayerViewModel.TryConvert(savedAudioPath, data, out string wavFilePath);
|
||||
if (!string.IsNullOrEmpty(wavFilePath))
|
||||
{
|
||||
savedAudioPath = wavFilePath;
|
||||
}
|
||||
else if (updateUi)
|
||||
{
|
||||
FLogger.Append(ELog.Error, () =>
|
||||
{
|
||||
FLogger.Text("Failed to convert audio to WAV format, aborting extraction.", Constants.WHITE, true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
conversionSuccess = AudioPlayerViewModel.TryConvert(savedAudioPath, data, out string wavFilePath);
|
||||
if (conversionSuccess) savedAudioPath = wavFilePath;
|
||||
}
|
||||
|
||||
Log.Information("Successfully saved {FilePath}", savedAudioPath);
|
||||
if (updateUi)
|
||||
if (updateUi && conversionSuccess)
|
||||
{
|
||||
FLogger.Append(ELog.Information, () =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -356,6 +356,7 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||
case "csv":
|
||||
AssetCategory = EAssetCategory.Data;
|
||||
break;
|
||||
case "stinfo":
|
||||
case "ushaderbytecode":
|
||||
AssetCategory = EAssetCategory.ByteCode;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ using Serilog;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
|
@ -67,12 +69,103 @@ public class GameSelectorViewModel : ViewModel
|
|||
public void AddUndetectedDir(string gameDirectory) => AddUndetectedDir(gameDirectory.SubstringAfterLast('\\'), gameDirectory);
|
||||
public void AddUndetectedDir(string gameName, string gameDirectory)
|
||||
{
|
||||
var setting = DirectorySettings.Default(gameName, gameDirectory, true);
|
||||
if (TryDetectUeVersion(gameDirectory, out var ueVersion, out var newGameDirectory))
|
||||
{
|
||||
// gameDirectory = newGameDirectory; // directory was changed to point to the correct paks folder
|
||||
}
|
||||
|
||||
var setting = DirectorySettings.Default(gameName, gameDirectory, true, ueVersion);
|
||||
UserSettings.Default.PerDirectory[gameDirectory] = setting;
|
||||
_detectedDirectories.Add(setting);
|
||||
SelectedDirectory = DetectedDirectories.Last();
|
||||
}
|
||||
|
||||
private bool TryDetectUeVersion(string gameDirectory, out EGame ueVersion, [MaybeNullWhen(false)] out string newGameDirectory)
|
||||
{
|
||||
var targetGameDir = gameDirectory;
|
||||
if (!targetGameDir.EndsWith("Paks", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var dirs = Directory.GetDirectories(targetGameDir, "Paks", SearchOption.AllDirectories);
|
||||
var paksDir = dirs.Length == 1 ? dirs[0] : dirs.FirstOrDefault(x => !x.EndsWith("Engine\\Programs\\CrashReportClient\\Content\\Paks"));
|
||||
if (!string.IsNullOrEmpty(paksDir))
|
||||
{
|
||||
Log.Warning("Selected directory \"{GameDirectory}\" does not end with \"Paks\". Looking in \"{PaksDir}\" instead.", targetGameDir, paksDir);
|
||||
targetGameDir = paksDir;
|
||||
}
|
||||
|
||||
if (Directory.GetFiles(gameDirectory, "*.exe") is { Length: 1 } exe && TryGetUeVersionFromExe(exe[0], out ueVersion))
|
||||
{
|
||||
// we checked the exe in the original directory, the BootstrapPackagedGame one
|
||||
// but we still want c4p to use the paks folder as the game directory (if any), not the original one
|
||||
newGameDirectory = targetGameDir;
|
||||
Log.Information("Detected UE version {UeVersion} from \"{Exe}\"", ueVersion, exe[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// past this point, we assume targetGameDir is the correct Paks folder
|
||||
newGameDirectory = targetGameDir;
|
||||
var projectDir = Path.Combine(targetGameDir, "..", "..");
|
||||
|
||||
var projectBinariesDir = Path.Combine(projectDir, "Binaries", "Win64");
|
||||
if (Directory.Exists(projectBinariesDir))
|
||||
{
|
||||
if (Directory.GetFiles(projectBinariesDir, "*-Win64-Shipping.exe") is { Length: > 0 } shipping)
|
||||
{
|
||||
foreach (var exe in shipping)
|
||||
{
|
||||
if (TryGetUeVersionFromExe(exe, out ueVersion))
|
||||
{
|
||||
Log.Information("Detected UE version {UeVersion} from \"{Exe}\"", ueVersion, exe);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Directory.GetFiles(projectBinariesDir, "*.exe") is { Length: < 3 } exes)
|
||||
{
|
||||
foreach (var exe in exes)
|
||||
{
|
||||
if (TryGetUeVersionFromExe(exe, out ueVersion))
|
||||
{
|
||||
Log.Information("Detected UE version {UeVersion} from \"{Exe}\"", ueVersion, exe);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var crashReportClientExe = Path.Combine(projectDir, "..", "Engine", "Binaries", "Win64", "CrashReportClient.exe");
|
||||
if (File.Exists(crashReportClientExe) && TryGetUeVersionFromExe(crashReportClientExe, out ueVersion))
|
||||
{
|
||||
Log.Information("Detected UE version {UeVersion} from \"{Exe}\"", ueVersion, crashReportClientExe);
|
||||
return true;
|
||||
}
|
||||
|
||||
ueVersion = EGame.GAME_UE4_LATEST;
|
||||
Log.Warning("Failed to detect UE version for \"{GameDirectory}\".", gameDirectory);
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetUeVersionFromExe(string exePath, out EGame ueVersion)
|
||||
{
|
||||
ueVersion = EGame.GAME_UE4_LATEST;
|
||||
try
|
||||
{
|
||||
var info = FileVersionInfo.GetVersionInfo(exePath);
|
||||
ueVersion = info.FileMajorPart switch
|
||||
{
|
||||
4 => (EGame) Math.Min((uint)(GameUtils.GameUe4Base + (info.FileMinorPart << 16)), (uint) EGame.GAME_UE4_LATEST),
|
||||
5 => (EGame) Math.Min((uint)(GameUtils.GameUe5Base + (info.FileMinorPart << 16)), (uint) EGame.GAME_UE5_LATEST),
|
||||
_ => throw new InvalidOperationException($"Unsupported UE major version {info.FileMajorPart} detected from {exePath}")
|
||||
};
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteSelectedGame()
|
||||
{
|
||||
UserSettings.Default.PerDirectory.Remove(SelectedDirectory.GameDirectory); // should not be a problem
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CUE4Parse.UE4.Exceptions;
|
||||
using FModel.Framework;
|
||||
using FModel.Services;
|
||||
using FModel.Views.Resources.Controls;
|
||||
|
|
@ -100,7 +101,26 @@ public class ThreadWorkerViewModel : ViewModel
|
|||
CurrentCancellationTokenSource = null; // kill token
|
||||
|
||||
Log.Error("{Exception}", e);
|
||||
FLogger.Append(e);
|
||||
switch (e)
|
||||
{
|
||||
case MappingException:
|
||||
FLogger.Append(ELog.Error, () =>
|
||||
{
|
||||
FLogger.Text("Package has unversioned properties but mapping file (.usmap) is missing, can't serialize. See: ", Constants.WHITE);
|
||||
FLogger.Link("→ link ←", Constants.MAPPING_ISSUE_LINK, true);
|
||||
});
|
||||
break;
|
||||
case VersionException v: // Error might be unrelated to version, but it's usually the case
|
||||
FLogger.Append(ELog.Error, () =>
|
||||
{
|
||||
FLogger.Text(v.Message[..^1] + ", can't serialize. Make sure the correct UE version is configured. See: ", Constants.WHITE);
|
||||
FLogger.Link("→ link ←", Constants.VERSION_ISSUE_LINK, true);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
FLogger.Append(e);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@
|
|||
</MenuItem.Style>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Command="{Binding RightClickMenuCommand}"
|
||||
Visibility="{Binding CanExportRawData, Source={x:Static settings:UserSettings.Default}, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<MenuItem Command="{Binding RightClickMenuCommand}">
|
||||
<MenuItem.Header>
|
||||
<TextBlock
|
||||
Text="{Binding PlacementTarget.SelectedItem.Asset.Extension,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
|
||||
xmlns:settings="clr-namespace:FModel.Settings"
|
||||
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
|
||||
x:Class="FModel.Views.Resources.Controls.ContextMenus.FolderContextMenuDictionary">
|
||||
<ContextMenu x:Key="FolderContextMenu" x:Shared="False"
|
||||
Opened="FolderContextMenu_OnOpened">
|
||||
<MenuItem Header="Export Folder's Packages Raw Data (.uasset)"
|
||||
Command="{Binding RightClickMenuCommand}"
|
||||
Visibility="{Binding CanExportRawData, Source={x:Static settings:UserSettings.Default}, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
Command="{Binding RightClickMenuCommand}">
|
||||
<MenuItem.CommandParameter>
|
||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
||||
<Binding Source="Folders_Export_Data" />
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
|
@ -126,13 +126,40 @@ public class FLogger : ITextFormatter
|
|||
{
|
||||
NavigateUri = new Uri(url),
|
||||
OverridesDefaultStyle = true,
|
||||
Style = new Style(typeof(Hyperlink)) { Setters =
|
||||
Style = new Style(typeof(Hyperlink))
|
||||
{
|
||||
new Setter(FrameworkContentElement.CursorProperty, Cursors.Hand),
|
||||
new Setter(TextBlock.TextDecorationsProperty, TextDecorations.Underline),
|
||||
new Setter(TextElement.ForegroundProperty, Brushes.Cornsilk)
|
||||
}}
|
||||
}.Click += (sender, _) => Process.Start("explorer.exe", $"/select, \"{((Hyperlink)sender).NavigateUri.AbsoluteUri}\"");
|
||||
Setters =
|
||||
{
|
||||
new Setter(FrameworkContentElement.CursorProperty, Cursors.Hand),
|
||||
new Setter(TextElement.ForegroundProperty, Brushes.Goldenrod),
|
||||
new Setter(TextElement.FontWeightProperty, FontWeights.Bold)
|
||||
},
|
||||
Triggers =
|
||||
{
|
||||
new Trigger
|
||||
{
|
||||
Property = UIElement.IsMouseOverProperty,
|
||||
Value = true,
|
||||
Setters =
|
||||
{
|
||||
new Setter(TextElement.ForegroundProperty, Brushes.Gold),
|
||||
new Setter(TextBlock.TextDecorationsProperty, TextDecorations.Underline)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.Click += (sender, _) =>
|
||||
{
|
||||
var uri = ((Hyperlink) sender).NavigateUri;
|
||||
if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(uri.AbsoluteUri) { UseShellExecute = true });
|
||||
}
|
||||
else
|
||||
{
|
||||
Process.Start("explorer.exe", $"/select, \"{uri.AbsoluteUri}\"");
|
||||
}
|
||||
};
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
|
|
@ -926,8 +926,7 @@
|
|||
</MenuItem.IsEnabled>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Command="{Binding TabCommand}" CommandParameter="Asset_Export_Data"
|
||||
Visibility="{Binding CanExportRawData, Source={x:Static settings:UserSettings.Default}, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<MenuItem Command="{Binding TabCommand}" CommandParameter="Asset_Export_Data">
|
||||
<MenuItem.Header>
|
||||
<TextBlock Text="{Binding Entry.Extension, FallbackValue='Export Raw Data', StringFormat='Export Raw Data (.{0})'}" />
|
||||
</MenuItem.Header>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<adonisControls:AdonisWindow x:Class="FModel.Views.SearchView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:settings="clr-namespace:FModel.Settings"
|
||||
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
|
||||
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
|
||||
xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI"
|
||||
|
|
@ -210,8 +209,7 @@
|
|||
</MenuItem.IsEnabled>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Command="{Binding DataContext.mainApplication.RightClickMenuCommand}"
|
||||
Visibility="{Binding CanExportRawData, Source={x:Static settings:UserSettings.Default}, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<MenuItem Command="{Binding DataContext.mainApplication.RightClickMenuCommand}">
|
||||
<MenuItem.Header>
|
||||
<TextBlock Text="{Binding DataContext.SelectedItem.Extension, FallbackValue='Export Raw Data',
|
||||
StringFormat='Export Raw Data (.{0})', RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
|
||||
|
|
@ -556,8 +554,7 @@
|
|||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Command="{Binding DataContext.mainApplication.RightClickMenuCommand}"
|
||||
Visibility="{Binding CanExportRawData, Source={x:Static settings:UserSettings.Default}, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<MenuItem Command="{Binding DataContext.mainApplication.RightClickMenuCommand}">
|
||||
<MenuItem.Header>
|
||||
<TextBlock Text="{Binding DataContext.SelectedItem.Extension, FallbackValue='Export Raw Data',
|
||||
StringFormat='Export Raw Data (.{0})', RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
|
|
@ -223,51 +222,46 @@
|
|||
<Button Grid.Column="2" Content="Mapping" Click="OpenMappingEndpoint" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="16" Grid.Column="0" Text="Allow Raw Data Export (.uasset)" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<TextBlock Grid.Row="16" Grid.Column="0" Text="Serialize Script Bytecode" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<CheckBox Grid.Row="16" Grid.Column="2" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
IsChecked="{Binding CanExportRawData, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" Margin="0 5 0 10"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" />
|
||||
|
||||
<TextBlock Grid.Row="17" Grid.Column="0" Text="Serialize Script Bytecode" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<CheckBox Grid.Row="17" Grid.Column="2" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
IsChecked="{Binding ReadScriptData, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" Margin="0 5 0 10"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" />
|
||||
|
||||
<TextBlock Grid.Row="18" Grid.Column="0" Text="Serialize Inlined Shader Maps" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<CheckBox Grid.Row="18" Grid.Column="2" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
<TextBlock Grid.Row="17" Grid.Column="0" Text="Serialize Inlined Shader Maps" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<CheckBox Grid.Row="17" Grid.Column="2" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
IsChecked="{Binding ReadShaderMaps, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" Margin="0 5 0 10"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" />
|
||||
|
||||
<TextBlock Grid.Row="19" Grid.Column="0" Text="Decompile Blueprint to Pseudo C++" VerticalAlignment="Center" Margin="0 0 0 5" ToolTip="Adds a right click option to decompile UClass packages into a pseudo C++ friendly format" />
|
||||
<CheckBox Grid.Row="19" Grid.Column="2" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
<TextBlock Grid.Row="18" Grid.Column="0" Text="Decompile Blueprint to Pseudo C++" VerticalAlignment="Center" Margin="0 0 0 5" ToolTip="Adds a right click option to decompile UClass packages into a pseudo C++ friendly format" />
|
||||
<CheckBox Grid.Row="18" Grid.Column="2" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
IsChecked="{Binding ShowDecompileOption, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" Margin="0 5 0 10"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" />
|
||||
|
||||
<TextBlock Grid.Row="20"
|
||||
<TextBlock Grid.Row="19"
|
||||
Grid.Column="0"
|
||||
Text="Convert Audio During Export (.wav)"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 0 5" />
|
||||
<CheckBox Grid.Row="20"
|
||||
<CheckBox Grid.Row="19"
|
||||
Grid.Column="2"
|
||||
Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
IsChecked="{Binding ConvertAudioOnBulkExport, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"
|
||||
Margin="0 5 0 10"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" />
|
||||
|
||||
<TextBlock Grid.Row="21" Grid.Column="0" Text="Max Wwise Bank (.BNK) Prefetch" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<Slider Grid.Row="21" Grid.Column="2" Grid.ColumnSpan="5" TickPlacement="None" Minimum="0" Maximum="2048" Ticks="0,8,32,128,256,512,1024,2048"
|
||||
<TextBlock Grid.Row="20" Grid.Column="0" Text="Max Wwise Bank (.BNK) Prefetch" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<Slider Grid.Row="20" Grid.Column="2" Grid.ColumnSpan="5" TickPlacement="None" Minimum="0" Maximum="2048" Ticks="0,8,32,128,256,512,1024,2048"
|
||||
AutoToolTipPlacement="BottomRight" IsMoveToPointEnabled="True" IsSnapToTickEnabled="True" Margin="0 5 0 5"
|
||||
Value="{Binding WwiseMaxBnkPrefetch, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="22"
|
||||
<TextBlock Grid.Row="21"
|
||||
Grid.Column="0"
|
||||
Text="CRIWARE Decryption Key"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 0 10" />
|
||||
|
||||
<TextBox x:Name="CriwareKeyBox"
|
||||
Grid.Row="22"
|
||||
Grid.Row="21"
|
||||
Grid.Column="2"
|
||||
Grid.ColumnSpan="5"
|
||||
Margin="0 5 0 10"
|
||||
|
|
@ -398,6 +392,8 @@
|
|||
<ContentControl.Style>
|
||||
<Style TargetType="{x:Type ContentControl}">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
<EventSetter Event="Hyperlink.Click" Handler="OnHyperlinkClick" />
|
||||
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding DataContext.SettingsView.SelectedMeshExportFormat, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}" Value="{x:Static c4pMeshes:EMeshFormat.UEFormat}">
|
||||
<Setter Property="ContentTemplate">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
using FModel.ViewModels;
|
||||
|
|
@ -241,4 +243,12 @@ public partial class SettingsView
|
|||
out value
|
||||
);
|
||||
}
|
||||
|
||||
private void OnHyperlinkClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is not Hyperlink hyperlink)
|
||||
return;
|
||||
|
||||
Process.Start(new ProcessStartInfo(hyperlink.NavigateUri.AbsoluteUri) { UseShellExecute = true });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public abstract class UModel : IRenderableModel
|
|||
{
|
||||
_export = export;
|
||||
Path = _export.GetPathName();
|
||||
Name = Path.SubstringAfterLast('/').SubstringBefore('.');
|
||||
Name = export.Name;
|
||||
Type = export.ExportType;
|
||||
UvCount = 1;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user