Merge branch 'dev' into wwise

# Conflicts:
#	CUE4Parse
#	FModel/ViewModels/CUE4ParseViewModel.cs
This commit is contained in:
Asval 2025-07-10 18:29:55 +02:00
commit 7598ae0a74
18 changed files with 174 additions and 38 deletions

View File

@ -59,7 +59,7 @@ public class BaseBundle : UCreator
foreach (var reward in rewards)
{
if (!reward.TryGetValue(out FSoftObjectPath itemDefinition, "ItemDefinition")) continue;
quest.AddCompletionRequest(itemDefinition);
quest.AddCompletionReward(itemDefinition);
}
_quests.Add(quest);
}

View File

@ -124,7 +124,14 @@ public class BaseCommunity : BaseIcon
if (!bShort) return base.GetCosmeticSeason(seasonNumber);
var s = seasonNumber["Cosmetics.Filter.Season.".Length..];
(int chapterIdx, int seasonIdx) = GetInternalSID(int.Parse(s));
return $"C{chapterIdx} S{seasonIdx}";
return s switch
{
"10" => $"C{chapterIdx} SX",
"27" => $"Fortnite: OG",
"32" => $"Fortnite: Remix",
"35" => $"C{chapterIdx} MS1",
_ => $"C{chapterIdx} S{seasonIdx}"
};
}
private new void DrawBackground(SKCanvas c)

View File

@ -257,12 +257,19 @@ public class BaseIcon : UCreator
var season = Utils.GetLocalizedResource("AthenaSeasonItemDefinitionInternal", "SeasonTextFormat", "Season {0}");
var introduced = Utils.GetLocalizedResource("Fort.Cosmetics", "CosmeticItemDescription_Season", "\nIntroduced in <SeasonText>{0}</>.");
if (s == "10") return Utils.RemoveHtmlTags(string.Format(introduced, string.Format(season, "X")));
if (initial <= 10) return Utils.RemoveHtmlTags(string.Format(introduced, string.Format(season, s)));
var chapter = Utils.GetLocalizedResource("AthenaSeasonItemDefinitionInternal", "ChapterTextFormat", "Chapter {0}");
var chapterFormat = Utils.GetLocalizedResource("AthenaSeasonItemDefinitionInternal", "ChapterSeasonTextFormat", "{0}, {1}");
var d = string.Format(chapterFormat, string.Format(chapter, chapterIdx), string.Format(season, seasonIdx));
return Utils.RemoveHtmlTags(string.Format(introduced, d));
return s switch
{
"27" => Utils.RemoveHtmlTags(string.Format(introduced, string.Format("Fortnite: OG"))),
"32" => Utils.RemoveHtmlTags(string.Format(introduced, string.Format("Fortnite: Remix"))),
"35" => Utils.RemoveHtmlTags(string.Format(introduced, string.Format(chapterFormat, string.Format(chapter, chapterIdx), string.Format("MS1")))),
_ => Utils.RemoveHtmlTags(string.Format(introduced, d))
};
}
protected void CheckGameplayTags(FInstancedStruct[] dataList)

View File

@ -84,44 +84,75 @@ public class BaseIconStats : BaseIcon
weaponStatHandle.TryGetValue(out UDataTable dataTable, "DataTable") &&
dataTable.TryGetDataTableRow(weaponRowName.Text, StringComparison.OrdinalIgnoreCase, out var weaponRowValue))
{
if (weaponRowValue.TryGetValue(out int bpc, "BulletsPerCartridge"))
weaponRowValue.TryGetValue(out float dmgPb, "DmgPB"); //Damage at point blank
weaponRowValue.TryGetValue(out float mdpc, "MaxDamagePerCartridge"); //Max damage a weapon can do in a single hit, usually used for shotguns
weaponRowValue.TryGetValue(out float dmgCritical, "DamageZone_Critical"); //Headshot multiplier
weaponRowValue.TryGetValue(out int clipSize, "ClipSize"); //Item magazine size
weaponRowValue.TryGetValue(out float firingRate, "FiringRate"); //Item firing rate, value is shots per second
weaponRowValue.TryGetValue(out float armTime, "ArmTime"); //Time it takes for traps to be able to be set off
weaponRowValue.TryGetValue(out float reloadTime, "ReloadTime"); //Time it takes for a weapon to reload
weaponRowValue.TryGetValue(out int bpc, "BulletsPerCartridge"); //Amount of pellets shot by a weapon at once, usually for shotguns
weaponRowValue.TryGetValue(out float heatMax, "OverheatingMaxValue"); //Maximum heat overheating weapons can hold before they need to cool off
weaponRowValue.TryGetValue(out float heatPerShot, "OverheatHeatingValue"); //Heat generated per shot on overheat weapons
weaponRowValue.TryGetValue(out float overheatCooldown, "OverheatedCooldownDelay"); //Cooldown after a weapon reaches its maximum heat capacity
weaponRowValue.TryGetValue(out int cartridgePerFire, "CartridgePerFire"); //Amount of bullets shot after pressing the fire button once
weaponRowValue.TryGetValue(out float burstFiringRate, "BurstFiringRate"); //Item firing rate during a burst, value is shots per second
{
var multiplier = bpc != 0f ? bpc : 1;
if (weaponRowValue.TryGetValue(out float dmgPb, "DmgPB") && dmgPb != 0f)
if (dmgPb != 0f)
{
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "35D04D1B45737BEA25B69686D9E085B9", "Damage"), dmgPb * multiplier, 200));
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "35D04D1B45737BEA25B69686D9E085B9", "Damage"), dmgPb * multiplier, 160));
}
if (weaponRowValue.TryGetValue(out float mdpc, "MaxDamagePerCartridge") && mdpc >= 0f)
if (mdpc > 0f && dmgPb * dmgCritical * multiplier > mdpc)
{
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "0DEF2455463B008C4499FEA03D149EDF", "Headshot Damage"), mdpc, 200));
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "0DEF2455463B008C4499FEA03D149EDF", "Headshot Damage"), mdpc, 160));
}
else if (weaponRowValue.TryGetValue(out float dmgCritical, "DamageZone_Critical"))
else if (dmgCritical != 0f && dmgCritical != 1f && dmgPb != 0f)
{
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "0DEF2455463B008C4499FEA03D149EDF", "Headshot Damage"), dmgPb * dmgCritical * multiplier, 200));
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "0DEF2455463B008C4499FEA03D149EDF", "Headshot Damage"), dmgPb * dmgCritical * multiplier, 160));
}
}
if (weaponRowValue.TryGetValue(out int clipSize, "ClipSize") && clipSize != 0)
if (clipSize > 999f || clipSize == 0f)
{
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "068239DD4327B36124498C9C5F61C038", "Magazine Size"), clipSize, 50));
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "068239DD4327B36124498C9C5F61C038", "Magazine Size"), Utils.GetLocalizedResource("", "0FAE8E5445029F2AA209ADB0FE49B23C", "Infinite"), -1));
}
if (weaponRowValue.TryGetValue(out float firingRate, "FiringRate") && firingRate != 0f)
else if (clipSize != 0f)
{
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "27B80BA44805ABD5A2D2BAB2902B250C", "Fire Rate"), firingRate, 15));
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "068239DD4327B36124498C9C5F61C038", "Magazine Size"), clipSize, 40));
}
if (weaponRowValue.TryGetValue(out float armTime, "ArmTime") && armTime != 0f)
var burstEquation = cartridgePerFire / (((cartridgePerFire - 1f) / burstFiringRate) + (1f / firingRate));
if (burstEquation != 0f)
{
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "3BFEB8BD41A677CC5F45B9A90D6EAD6F", "Arming Delay"), armTime, 125));
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "27B80BA44805ABD5A2D2BAB2902B250C", "Fire Rate"), burstEquation, 11));
}
else if (firingRate != 0f)
{
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "27B80BA44805ABD5A2D2BAB2902B250C", "Fire Rate"), firingRate, 11));
}
if (weaponRowValue.TryGetValue(out float reloadTime, "ReloadTime") && reloadTime != 0f)
if (armTime != 0f)
{
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "6EA26D1A4252034FBD869A90F9A6E49A", "Reload Time"), reloadTime, 15));
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "3BFEB8BD41A677CC5F45B9A90D6EAD6F", "Arming Delay"), armTime, 5));
}
if (reloadTime != 0f && clipSize < 999f && clipSize != 0f)
{
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "6EA26D1A4252034FBD869A90F9A6E49A", "Reload Time"), reloadTime, 10));
}
if (overheatCooldown != 0f && clipSize > 999f || overheatCooldown != 0f && clipSize == 0f)
{
_statistics.Add(new IconStat("Overheat Cooldown", overheatCooldown, 5));
}
if (heatMax != 0f && heatPerShot != 0f && clipSize > 999f || heatMax != 0f && heatPerShot != 0f && clipSize == 0f)
{
_statistics.Add(new IconStat("Shots to Overheat", Math.Ceiling(heatMax / heatPerShot), 80));
}
if ((Object.ExportType.Equals("FortContextTrapItemDefinition", StringComparison.OrdinalIgnoreCase) ||
Object.ExportType.Equals("FortTrapItemDefinition", StringComparison.OrdinalIgnoreCase)) &&
weaponRowValue.TryGetValue(out UDataTable durabilityTable, "Durability") &&
@ -285,6 +316,10 @@ public class IconStat
_statPaint.Color = SKColors.White;
c.DrawText(_value.ToString(), new SKPoint(width - 50, y + 10), _statPaint);
if (_maxValue == -1) //fill bar if max value is set to -1, for things that don't return a number here but should still be represented as the maximum value
{
c.DrawRect(new SKRect(height * 2, y, Math.Min(width - height, sliderRight), y + 5), _statPaint);
}
if (_maxValue < 1 || !float.TryParse(_value.ToString(), out var floatValue)) return;
if (floatValue < 0)
floatValue = 0;

View File

@ -44,12 +44,12 @@ public class BaseQuest : BaseIcon
DisplayName = ReformatString(description, completionCount.ToString(), completionCount < 0);
}
public void AddCompletionRequest(FSoftObjectPath itemDefinition)
public void AddCompletionReward(FSoftObjectPath itemDefinition)
{
_rewards.Add(itemDefinition.TryLoad(out UObject uObject) ? new Reward(uObject) : new Reward());
}
public void AddCompletionRequest(int quantity, string reward)
public void AddCompletionReward(int quantity, string reward)
{
_rewards.Add(new Reward(quantity, reward));
}

View File

@ -49,7 +49,8 @@ public class CreatorPackage : IDisposable
case "CosmeticShoesItemDefinition":
case "AthenaPickaxeItemDefinition":
case "AthenaGadgetItemDefinition":
case "AthenaGliderItemDefinition":
case "AthenaGliderItemDefinition":
case "AthenaHatItemDefinition":
case "AthenaSprayItemDefinition":
case "AthenaDanceItemDefinition":
case "AthenaEmojiItemDefinition":

View File

@ -60,7 +60,9 @@ public enum ELoadingMode
[Description("All (New)")]
AllButNew,
[Description("All (Modified)")]
AllButModified
AllButModified,
[Description("All (Except Patched Assets)")]
AllButPatched,
}
// public enum EUpdateMode

View File

@ -63,7 +63,6 @@ public partial class MainWindow
await ApplicationViewModel.InitOodle();
await ApplicationViewModel.InitZlib();
await ApplicationViewModel.InitDetex();
await _applicationView.CUE4Parse.Initialize();
await _applicationView.AesManager.InitAes();
await _applicationView.UpdateProvider(true);
@ -74,6 +73,7 @@ public partial class MainWindow
_applicationView.CUE4Parse.VerifyConsoleVariables(),
_applicationView.CUE4Parse.VerifyOnDemandArchives(),
_applicationView.CUE4Parse.InitMappings(),
ApplicationViewModel.InitDetex(),
ApplicationViewModel.InitVgmStream(),
ApplicationViewModel.InitImGuiSettings(newOrUpdated),
Task.Run(() =>

View File

@ -10,6 +10,7 @@ using CUE4Parse_Conversion.Meshes;
using CUE4Parse_Conversion.Textures;
using CUE4Parse_Conversion.UEFormat.Enums;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Assets.Exports.Nanite;
using FModel.Framework;
using FModel.ViewModels;
using FModel.ViewModels.ApiEndpoints.Models;
@ -60,6 +61,7 @@ namespace FModel.Settings
{
LodFormat = Default.LodExportFormat,
MeshFormat = Default.MeshExportFormat,
NaniteMeshFormat = Default.NaniteMeshExportFormat,
AnimFormat = Default.MeshExportFormat switch
{
EMeshFormat.UEFormat => EAnimFormat.UEFormat,
@ -367,6 +369,13 @@ namespace FModel.Settings
set => SetProperty(ref _meshExportFormat, value);
}
private ENaniteMeshFormat _naniteMeshExportFormat = ENaniteMeshFormat.OnlyNaniteLOD;
public ENaniteMeshFormat NaniteMeshExportFormat
{
get => _naniteMeshExportFormat;
set => SetProperty(ref _naniteMeshExportFormat, value);
}
private EMaterialFormat _materialExportFormat = EMaterialFormat.FirstLayer;
public EMaterialFormat MaterialExportFormat
{

View File

@ -106,7 +106,11 @@ public class FModelApiEndpoint : AbstractApiProvider
public void CheckForUpdates(bool launch = false)
{
if (DateTime.Now < UserSettings.Default.NextUpdateCheck) return;
if (DateTime.Now < UserSettings.Default.NextUpdateCheck)
{
Log.Warning("Updates have been silenced until {DateTime}", UserSettings.Default.NextUpdateCheck);
return;
}
if (launch)
{
@ -140,7 +144,8 @@ public class FModelApiEndpoint : AbstractApiProvider
{
UserSettings.Default.LastUpdateCheck = DateTime.Now;
if (((CustomMandatory)args.Mandatory).CommitHash == Constants.APP_COMMIT_ID)
var targetHash = ((CustomMandatory) args.Mandatory).CommitHash;
if (targetHash == Constants.APP_COMMIT_ID)
{
if (UserSettings.Default.ShowChangelog)
ShowChangelog(args);
@ -152,6 +157,7 @@ public class FModelApiEndpoint : AbstractApiProvider
UserSettings.Default.ShowChangelog = currentVersion != args.InstalledVersion;
const string message = "A new update is available!";
Log.Warning("{message} Version {CurrentVersion} ({Hash})", message, currentVersion, targetHash);
Helper.OpenWindow<AdonisWindow>(message, () => new UpdateView { Title = message, ResizeMode = ResizeMode.NoResize }.ShowDialog());
}
else

View File

@ -260,7 +260,7 @@ public class ApplicationViewModel : ViewModel
ZlibHelper.Initialize(zlibPath);
}
public static async ValueTask InitDetex()
public static async Task InitDetex()
{
var detexPath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", DetexHelper.DLL_NAME);
if (File.Exists(DetexHelper.DLL_NAME))

View File

@ -39,6 +39,8 @@ using CUE4Parse_Conversion;
using CUE4Parse_Conversion.Sounds;
using CUE4Parse.FileProvider.Objects;
using CUE4Parse.UE4.Assets;
using CUE4Parse.UE4.BinaryConfig;
using CUE4Parse.UE4.Objects.UObject;
using CUE4Parse.UE4.Objects.UObject;
using CUE4Parse.Utils;
using EpicManifestParser;
@ -165,6 +167,7 @@ public class CUE4ParseViewModel : ViewModel
Provider.ReadScriptData = UserSettings.Default.ReadScriptData;
Provider.ReadShaderMaps = UserSettings.Default.ReadShaderMaps;
Provider.ReadNaniteData = true;
GameDirectory = new GameDirectoryViewModel();
AssetsFolder = new AssetsFolderViewModel();
@ -195,7 +198,7 @@ public class CUE4ParseViewModel : ViewModel
{
ChunkCacheDirectory = cacheDir,
ManifestCacheDirectory = cacheDir,
ChunkBaseUrl = "http://epicgames-download1.akamaized.net/Builds/Fortnite/CloudDir/",
ChunkBaseUrl = "http://download.epicgames.com/Builds/Fortnite/CloudDir/",
Decompressor = ManifestZlibngDotNetDecompressor.Decompress,
DecompressorState = ZlibHelper.Instance,
CacheChunksAsIs = false
@ -208,7 +211,7 @@ public class CUE4ParseViewModel : ViewModel
{
(manifest, _) = manifestInfo.DownloadAndParseAsync(manifestOptions,
cancellationToken: cancellationToken,
elementManifestPredicate: static x => x.Uri.Host != "cloudflare.epicgamescdn.com"
elementManifestPredicate: static x => x.Uri.Host == "download.epicgames.com"
).GetAwaiter().GetResult();
}
catch (HttpRequestException ex)
@ -582,6 +585,16 @@ public class CUE4ParseViewModel : ViewModel
break;
}
case "ini" when entry.Name.Contains("BinaryConfig"):
{
var ar = entry.CreateReader();
var configCache = new FConfigCacheIni(ar);
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("json");
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(configCache, Formatting.Indented), saveProperties, updateUi);
break;
}
case "upluginmanifest":
case "uproject":
case "manifest":

View File

@ -87,6 +87,11 @@ public class LoadCommand : ViewModelCommand<LoadingModesViewModel>
FilterNewOrModifiedFilesToDisplay(cancellationToken);
break;
}
case ELoadingMode.AllButPatched:
{
FilterPacthedFilesToDisplay(cancellationToken);
break;
}
default: throw new ArgumentOutOfRangeException();
}
@ -273,4 +278,26 @@ public class LoadCommand : ViewModelCommand<LoadingModesViewModel>
entries.Add(asset);
}
private void FilterPacthedFilesToDisplay(CancellationToken cancellationToken)
{
var loaded = new Dictionary<string, GameFile>(_applicationView.CUE4Parse.Provider.PathComparer);
foreach (var (key, asset) in _applicationView.CUE4Parse.Provider.Files)
{
cancellationToken.ThrowIfCancellationRequested(); // cancel if needed
if (asset.IsUePackagePayload) continue;
if (asset is VfsEntry entry && loaded.TryGetValue(key, out var file) &&
file is VfsEntry existingEntry && entry.Vfs.ReadOrder < existingEntry.Vfs.ReadOrder)
{
continue;
}
loaded[key] = asset;
}
_applicationView.Status.UpdateStatusLabel($"{loaded.Count:### ### ###} Packages");
_applicationView.CUE4Parse.AssetsFolder.BulkPopulate(loaded.Values);
}
}

View File

@ -9,6 +9,7 @@ using CUE4Parse_Conversion.Meshes;
using CUE4Parse_Conversion.Textures;
using CUE4Parse_Conversion.UEFormat.Enums;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Assets.Exports.Nanite;
using FModel.Framework;
using FModel.Services;
using FModel.Settings;
@ -143,6 +144,13 @@ public class SettingsViewModel : ViewModel
set => SetProperty(ref _selectedLodExportFormat, value);
}
private ENaniteMeshFormat _selectedNaniteMeshExportFormat;
public ENaniteMeshFormat SelectedNaniteMeshExportFormat
{
get => _selectedNaniteMeshExportFormat;
set => SetProperty(ref _selectedNaniteMeshExportFormat, value);
}
private EMaterialFormat _selectedMaterialExportFormat;
public EMaterialFormat SelectedMaterialExportFormat
{
@ -170,6 +178,7 @@ public class SettingsViewModel : ViewModel
public ReadOnlyObservableCollection<ESocketFormat> SocketExportFormats { get; private set; }
public ReadOnlyObservableCollection<EFileCompressionFormat> CompressionFormats { get; private set; }
public ReadOnlyObservableCollection<ELodFormat> LodExportFormats { get; private set; }
public ReadOnlyObservableCollection<ENaniteMeshFormat> NaniteMeshExportFormats { get; private set; }
public ReadOnlyObservableCollection<EMaterialFormat> MaterialExportFormats { get; private set; }
public ReadOnlyObservableCollection<ETextureFormat> TextureExportFormats { get; private set; }
public ReadOnlyObservableCollection<ETexturePlatform> Platforms { get; private set; }
@ -193,6 +202,7 @@ public class SettingsViewModel : ViewModel
private ESocketFormat _socketExportFormatSnapshot;
private EFileCompressionFormat _compressionFormatSnapshot;
private ELodFormat _lodExportFormatSnapshot;
private ENaniteMeshFormat _naniteMeshExportFormatSnapshot;
private EMaterialFormat _materialExportFormatSnapshot;
private ETextureFormat _textureExportFormatSnapshot;
@ -233,6 +243,7 @@ public class SettingsViewModel : ViewModel
_socketExportFormatSnapshot = UserSettings.Default.SocketExportFormat;
_compressionFormatSnapshot = UserSettings.Default.CompressionFormat;
_lodExportFormatSnapshot = UserSettings.Default.LodExportFormat;
_naniteMeshExportFormatSnapshot = UserSettings.Default.NaniteMeshExportFormat;
_materialExportFormatSnapshot = UserSettings.Default.MaterialExportFormat;
_textureExportFormatSnapshot = UserSettings.Default.TextureExportFormat;
@ -248,6 +259,7 @@ public class SettingsViewModel : ViewModel
SelectedSocketExportFormat = _socketExportFormatSnapshot;
SelectedCompressionFormat = _selectedCompressionFormat;
SelectedLodExportFormat = _lodExportFormatSnapshot;
SelectedNaniteMeshExportFormat = _naniteMeshExportFormatSnapshot;
SelectedMaterialExportFormat = _materialExportFormatSnapshot;
SelectedTextureExportFormat = _textureExportFormatSnapshot;
SelectedAesReload = UserSettings.Default.AesReload;
@ -263,6 +275,7 @@ public class SettingsViewModel : ViewModel
SocketExportFormats = new ReadOnlyObservableCollection<ESocketFormat>(new ObservableCollection<ESocketFormat>(EnumerateSocketExportFormat()));
CompressionFormats = new ReadOnlyObservableCollection<EFileCompressionFormat>(new ObservableCollection<EFileCompressionFormat>(EnumerateCompressionFormat()));
LodExportFormats = new ReadOnlyObservableCollection<ELodFormat>(new ObservableCollection<ELodFormat>(EnumerateLodExportFormat()));
NaniteMeshExportFormats = new ReadOnlyObservableCollection<ENaniteMeshFormat>(new ObservableCollection<ENaniteMeshFormat>(EnumerateNaniteMeshExportFormat()));
MaterialExportFormats = new ReadOnlyObservableCollection<EMaterialFormat>(new ObservableCollection<EMaterialFormat>(EnumerateMaterialExportFormat()));
TextureExportFormats = new ReadOnlyObservableCollection<ETextureFormat>(new ObservableCollection<ETextureFormat>(EnumerateTextureExportFormat()));
Platforms = new ReadOnlyObservableCollection<ETexturePlatform>(new ObservableCollection<ETexturePlatform>(EnumerateUePlatforms()));
@ -303,6 +316,7 @@ public class SettingsViewModel : ViewModel
UserSettings.Default.SocketExportFormat = SelectedSocketExportFormat;
UserSettings.Default.CompressionFormat = SelectedCompressionFormat;
UserSettings.Default.LodExportFormat = SelectedLodExportFormat;
UserSettings.Default.NaniteMeshExportFormat = SelectedNaniteMeshExportFormat;
UserSettings.Default.MaterialExportFormat = SelectedMaterialExportFormat;
UserSettings.Default.TextureExportFormat = SelectedTextureExportFormat;
UserSettings.Default.AesReload = SelectedAesReload;
@ -328,6 +342,7 @@ public class SettingsViewModel : ViewModel
private IEnumerable<ESocketFormat> EnumerateSocketExportFormat() => Enum.GetValues<ESocketFormat>();
private IEnumerable<EFileCompressionFormat> EnumerateCompressionFormat() => Enum.GetValues<EFileCompressionFormat>();
private IEnumerable<ELodFormat> EnumerateLodExportFormat() => Enum.GetValues<ELodFormat>();
private IEnumerable<ENaniteMeshFormat> EnumerateNaniteMeshExportFormat() => Enum.GetValues<ENaniteMeshFormat>();
private IEnumerable<EMaterialFormat> EnumerateMaterialExportFormat() => Enum.GetValues<EMaterialFormat>();
private IEnumerable<ETextureFormat> EnumerateTextureExportFormat() => Enum.GetValues<ETextureFormat>();
private IEnumerable<ETexturePlatform> EnumerateUePlatforms() => Enum.GetValues<ETexturePlatform>();

View File

@ -6,6 +6,7 @@ using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
namespace FModel.Views.Resources.Controls;
@ -54,7 +55,7 @@ public class FLogger : ITextFormatter
}
job();
});
}, DispatcherPriority.Background);
}
public static void Text(string message, string color, bool newLine = false)

View File

@ -316,6 +316,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@ -459,8 +460,8 @@
<Separator Grid.Row="16" Grid.Column="0" Grid.ColumnSpan="5" Style="{StaticResource CustomSeparator}" />
<TextBlock Grid.Row="17" Grid.Column="0" Text="Material Format" VerticalAlignment="Center" Margin="0 0 0 5" />
<ComboBox Grid.Row="17" Grid.Column="2" Grid.ColumnSpan="3" ItemsSource="{Binding SettingsView.MaterialExportFormats}" SelectedItem="{Binding SettingsView.SelectedMaterialExportFormat, Mode=TwoWay}"
<TextBlock Grid.Row="17" Grid.Column="0" Text="Nanite Format" VerticalAlignment="Center" Margin="0 0 0 5" />
<ComboBox Grid.Row="17" Grid.Column="2" Grid.ColumnSpan="3" ItemsSource="{Binding SettingsView.NaniteMeshExportFormats}" SelectedItem="{Binding SettingsView.SelectedNaniteMeshExportFormat, Mode=TwoWay}"
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}" Margin="0 0 0 5">
<ComboBox.ItemTemplate>
<DataTemplate>
@ -469,8 +470,18 @@
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="18" Grid.Column="0" Text="Texture Format" VerticalAlignment="Center" Margin="0 0 0 5" />
<ComboBox Grid.Row="18" Grid.Column="2" Grid.ColumnSpan="3" ItemsSource="{Binding SettingsView.TextureExportFormats}" SelectedItem="{Binding SettingsView.SelectedTextureExportFormat, Mode=TwoWay}"
<TextBlock Grid.Row="18" Grid.Column="0" Text="Material Format" VerticalAlignment="Center" Margin="0 0 0 5" />
<ComboBox Grid.Row="18" Grid.Column="2" Grid.ColumnSpan="3" ItemsSource="{Binding SettingsView.MaterialExportFormats}" SelectedItem="{Binding SettingsView.SelectedMaterialExportFormat, Mode=TwoWay}"
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}" Margin="0 0 0 5">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={x:Static converters:EnumToStringConverter.Instance}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Grid.Row="19" Grid.Column="0" Text="Texture Format" VerticalAlignment="Center" Margin="0 0 0 5" />
<ComboBox Grid.Row="19" Grid.Column="2" Grid.ColumnSpan="3" ItemsSource="{Binding SettingsView.TextureExportFormats}" SelectedItem="{Binding SettingsView.SelectedTextureExportFormat, Mode=TwoWay}"
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}" Margin="0 0 0 5">
<ComboBox.ItemTemplate>
<DataTemplate>

View File

@ -12,6 +12,7 @@ using CUE4Parse.UE4.Assets.Exports.Component.SplineMesh;
using CUE4Parse.UE4.Assets.Exports.Component.StaticMesh;
using CUE4Parse.UE4.Assets.Exports.GeometryCollection;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Assets.Exports.Nanite;
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
using CUE4Parse.UE4.Assets.Exports.Texture;
@ -86,7 +87,7 @@ public class Renderer : IDisposable
switch (dummy)
{
case UStaticMesh when export.Value is UStaticMesh st:
LoadStaticMesh(st);
LoadStaticMesh(st, UserSettings.Default.NaniteMeshExportFormat);
break;
case USkeletalMesh when export.Value is USkeletalMesh sk:
LoadSkeletalMesh(sk);
@ -343,7 +344,7 @@ public class Renderer : IDisposable
wnd.WindowShouldClose(true, true);
}
private void LoadStaticMesh(UStaticMesh original)
private void LoadStaticMesh(UStaticMesh original, ENaniteMeshFormat naniteFormat = ENaniteMeshFormat.OnlyNormalLODs)
{
var guid = original.LightingGuid;
if (Options.TryGetModel(guid, out var model))
@ -353,7 +354,7 @@ public class Renderer : IDisposable
return;
}
if (!original.TryConvert(out var mesh))
if (!original.TryConvert(out var mesh, naniteFormat))
return;
Options.Models[guid] = new StaticModel(original, mesh);

View File

@ -130,7 +130,8 @@ public class Material : IDisposable
"EmissiveUVs_RG_UpperLeftCorner_BA_LowerRightCorner",
"Emissive Texture UVs RG_TopLeft BA_BottomRight",
"Emissive 2 UV Positioning (RG)UpperLeft (BA)LowerRight",
"EmissiveUVPositioning (RG)UpperLeft (BA)LowerRight"))
"EmissiveUVPositioning (RG)UpperLeft (BA)LowerRight",
"Emissive_CH"))
EmissiveRegion = new Vector4(EmissiveUVs.R, EmissiveUVs.G, EmissiveUVs.B, EmissiveUVs.A);
if ((Parameters.TryGetSwitch(out var swizzleRoughnessToGreen, "SwizzleRoughnessToGreen") && swizzleRoughnessToGreen) ||