mirror of
https://github.com/4sval/FModel.git
synced 2026-03-21 17:24:26 -05:00
This commit is contained in:
parent
a704612544
commit
3d0bdf05e1
|
|
@ -1 +1 @@
|
|||
Subproject commit 94dbeb7cd3232b6719120219ae7d2a63968e9036
|
||||
Subproject commit ab6dff8e98e94335916a549810466eb4571a072b
|
||||
|
|
@ -2,9 +2,8 @@
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using FModel.Extensions;
|
||||
using CUE4Parse.Utils;
|
||||
|
||||
namespace FModel;
|
||||
|
||||
|
|
@ -12,7 +11,7 @@ public static class Constants
|
|||
{
|
||||
public static readonly string APP_PATH = Path.GetFullPath(Environment.GetCommandLineArgs()[0]);
|
||||
public static readonly string APP_VERSION = FileVersionInfo.GetVersionInfo(APP_PATH).FileVersion;
|
||||
public static readonly string APP_COMMIT_ID = FileVersionInfo.GetVersionInfo(APP_PATH).ProductVersion.SubstringAfter('+');
|
||||
public static readonly string APP_COMMIT_ID = FileVersionInfo.GetVersionInfo(APP_PATH).ProductVersion?.SubstringAfter('+');
|
||||
public static readonly string APP_SHORT_COMMIT_ID = APP_COMMIT_ID[..7];
|
||||
|
||||
public const string ZERO_64_CHAR = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using CUE4Parse.UE4.Assets.Exports;
|
|||
using CUE4Parse.UE4.Assets.Objects;
|
||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using FModel.Extensions;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Framework;
|
||||
using SkiaSharp;
|
||||
using SkiaSharp.HarfBuzz;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using CUE4Parse.UE4.Assets.Exports.Texture;
|
|||
using CUE4Parse.UE4.Assets.Objects;
|
||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using FModel.Extensions;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Framework;
|
||||
using SkiaSharp;
|
||||
using SkiaSharp.HarfBuzz;
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public class Typefaces
|
|||
|
||||
Default = SKTypeface.FromStream(Application.GetResourceStream(_BURBANK_BIG_CONDENSED_BOLD)?.Stream);
|
||||
|
||||
switch (viewModel.Provider.InternalGameName.ToUpperInvariant())
|
||||
switch (viewModel.Provider.ProjectName.ToUpperInvariant())
|
||||
{
|
||||
case "FORTNITEGAME":
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using CUE4Parse.UE4.Objects.UObject;
|
|||
using CUE4Parse.UE4.Versions;
|
||||
using CUE4Parse_Conversion.Textures;
|
||||
using CUE4Parse.UE4.Assets.Objects;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Framework;
|
||||
using FModel.Extensions;
|
||||
using FModel.Services;
|
||||
|
|
@ -160,12 +161,7 @@ public static class Utils
|
|||
// fullpath must be either without any extension or with the export objectname
|
||||
public static bool TryLoadObject<T>(string fullPath, out T export) where T : UObject
|
||||
{
|
||||
return _applicationView.CUE4Parse.Provider.TryLoadObject(fullPath, out export);
|
||||
}
|
||||
|
||||
public static IEnumerable<UObject> LoadExports(string packagePath)
|
||||
{
|
||||
return _applicationView.CUE4Parse.Provider.LoadAllObjects(packagePath);
|
||||
return _applicationView.CUE4Parse.Provider.TryLoadPackageObject(fullPath, out export);
|
||||
}
|
||||
|
||||
public static float GetMaxFontSize(double sectorSize, SKTypeface typeface, string text, float degreeOfCertainty = 1f, float maxFont = 100f)
|
||||
|
|
@ -417,4 +413,4 @@ public static class Utils
|
|||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,76 +24,6 @@ public static class StringExtensions
|
|||
return $"{size:# ###.##} {sizes[order]}".TrimStart();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string SubstringBefore(this string s, char delimiter)
|
||||
{
|
||||
var index = s.IndexOf(delimiter);
|
||||
return index == -1 ? s : s[..index];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string SubstringBefore(this string s, string delimiter, StringComparison comparisonType = StringComparison.Ordinal)
|
||||
{
|
||||
var index = s.IndexOf(delimiter, comparisonType);
|
||||
return index == -1 ? s : s[..index];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string SubstringAfter(this string s, char delimiter)
|
||||
{
|
||||
var index = s.IndexOf(delimiter);
|
||||
return index == -1 ? s : s.Substring(index + 1, s.Length - index - 1);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string SubstringAfter(this string s, string delimiter, StringComparison comparisonType = StringComparison.Ordinal)
|
||||
{
|
||||
var index = s.IndexOf(delimiter, comparisonType);
|
||||
return index == -1 ? s : s.Substring(index + delimiter.Length, s.Length - index - delimiter.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string SubstringBeforeLast(this string s, char delimiter)
|
||||
{
|
||||
var index = s.LastIndexOf(delimiter);
|
||||
return index == -1 ? s : s[..index];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string SubstringBeforeLast(this string s, string delimiter, StringComparison comparisonType = StringComparison.Ordinal)
|
||||
{
|
||||
var index = s.LastIndexOf(delimiter, comparisonType);
|
||||
return index == -1 ? s : s[..index];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string SubstringBeforeWithLast(this string s, char delimiter)
|
||||
{
|
||||
var index = s.LastIndexOf(delimiter);
|
||||
return index == -1 ? s : s[..(index + 1)];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string SubstringBeforeWithLast(this string s, string delimiter, StringComparison comparisonType = StringComparison.Ordinal)
|
||||
{
|
||||
var index = s.LastIndexOf(delimiter, comparisonType);
|
||||
return index == -1 ? s : s[..(index + 1)];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string SubstringAfterLast(this string s, char delimiter)
|
||||
{
|
||||
var index = s.LastIndexOf(delimiter);
|
||||
return index == -1 ? s : s.Substring(index + 1, s.Length - index - 1);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string SubstringAfterLast(this string s, string delimiter, StringComparison comparisonType = StringComparison.Ordinal)
|
||||
{
|
||||
var index = s.LastIndexOf(delimiter, comparisonType);
|
||||
return index == -1 ? s : s.Substring(index + delimiter.Length, s.Length - index - delimiter.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int GetNameLineNumber(this string s, string lineToFind)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using System.Windows;
|
|||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using AdonisUI.Controls;
|
||||
using FModel.Extensions;
|
||||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
using FModel.ViewModels;
|
||||
|
|
@ -267,7 +266,7 @@ public partial class MainWindow
|
|||
return;
|
||||
|
||||
var filters = textBox.Text.Trim().Split(' ');
|
||||
folder.AssetsList.AssetsView.Filter = o => { return o is AssetItem assetItem && filters.All(x => assetItem.FullPath.SubstringAfterLast('/').Contains(x, StringComparison.OrdinalIgnoreCase)); };
|
||||
folder.AssetsList.AssetsView.Filter = o => { return o is AssetItem assetItem && filters.All(x => assetItem.FileName.Contains(x, StringComparison.OrdinalIgnoreCase)); };
|
||||
}
|
||||
|
||||
private void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace FModel.Services
|
|||
|
||||
public void UpdatePresence(CUE4ParseViewModel viewModel) =>
|
||||
UpdatePresence(
|
||||
$"{viewModel.Provider.GameDisplayName ?? viewModel.Provider.InternalGameName} - {viewModel.Provider.MountedVfs.Count}/{viewModel.Provider.MountedVfs.Count + viewModel.Provider.UnloadedVfs.Count} Packages",
|
||||
$"{viewModel.Provider.GameDisplayName ?? viewModel.Provider.ProjectName} - {viewModel.Provider.MountedVfs.Count}/{viewModel.Provider.MountedVfs.Count + viewModel.Provider.UnloadedVfs.Count} Packages",
|
||||
$"Mode: {UserSettings.Default.LoadingMode.GetDescription()} - {viewModel.SearchVm.ResultsCount:### ### ###} Loaded Assets".Trim());
|
||||
|
||||
public void UpdatePresence(string details, string state)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FModel.Extensions;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Framework;
|
||||
using FModel.ViewModels.ApiEndpoints.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using AutoUpdaterDotNET;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Extensions;
|
||||
using FModel.Framework;
|
||||
using FModel.Services;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.ComponentModel;
|
||||
using System.Windows.Data;
|
||||
using CUE4Parse.Compression;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Framework;
|
||||
|
||||
namespace FModel.ViewModels;
|
||||
|
|
@ -49,7 +50,33 @@ public class AssetItem : ViewModel
|
|||
private set => SetProperty(ref _compression, value);
|
||||
}
|
||||
|
||||
public AssetItem(string fullPath, bool isEncrypted, long offset, long size, string archive, CompressionMethod compression)
|
||||
private string _directory;
|
||||
public string Directory
|
||||
{
|
||||
get => _directory;
|
||||
private set => SetProperty(ref _directory, value);
|
||||
}
|
||||
|
||||
private string _fileName;
|
||||
public string FileName
|
||||
{
|
||||
get => _fileName;
|
||||
private set => SetProperty(ref _fileName, value);
|
||||
}
|
||||
|
||||
private string _extension;
|
||||
public string Extension
|
||||
{
|
||||
get => _extension;
|
||||
private set => SetProperty(ref _extension, value);
|
||||
}
|
||||
|
||||
public AssetItem(string titleExtra, AssetItem asset) : this(asset.FullPath, asset.IsEncrypted, asset.Offset, asset.Size, asset.Archive, asset.Compression)
|
||||
{
|
||||
FullPath += titleExtra;
|
||||
}
|
||||
|
||||
public AssetItem(string fullPath, bool isEncrypted = false, long offset = 0, long size = 0, string archive = "", CompressionMethod compression = CompressionMethod.None)
|
||||
{
|
||||
FullPath = fullPath;
|
||||
IsEncrypted = isEncrypted;
|
||||
|
|
@ -57,6 +84,10 @@ public class AssetItem : ViewModel
|
|||
Size = size;
|
||||
Archive = archive;
|
||||
Compression = compression;
|
||||
|
||||
Directory = FullPath.SubstringBeforeLast('/');
|
||||
FileName = FullPath.SubstringAfterLast('/');
|
||||
Extension = FullPath.SubstringAfterLast('.').ToLowerInvariant();
|
||||
}
|
||||
|
||||
public override string ToString() => FullPath;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ using System.Threading;
|
|||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using CSCore.CoreAudioAPI;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Extensions;
|
||||
using FModel.Framework;
|
||||
using FModel.Services;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using System.Threading.Tasks;
|
|||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using CUE4Parse.FileProvider.Objects;
|
||||
using CUE4Parse.UE4.VirtualFileSystem;
|
||||
using FModel.Framework;
|
||||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
|
|
|
|||
|
|
@ -9,9 +9,7 @@ using System.Text.RegularExpressions;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
using AdonisUI.Controls;
|
||||
|
||||
using CUE4Parse.Compression;
|
||||
using CUE4Parse.Encryption.Aes;
|
||||
using CUE4Parse.FileProvider;
|
||||
|
|
@ -37,15 +35,14 @@ using CUE4Parse.UE4.Readers;
|
|||
using CUE4Parse.UE4.Shaders;
|
||||
using CUE4Parse.UE4.Versions;
|
||||
using CUE4Parse.UE4.Wwise;
|
||||
|
||||
using CUE4Parse_Conversion;
|
||||
using CUE4Parse_Conversion.Sounds;
|
||||
using CUE4Parse.UE4.Assets;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using CUE4Parse.Utils;
|
||||
using EpicManifestParser;
|
||||
using EpicManifestParser.UE;
|
||||
using EpicManifestParser.ZlibngDotNetDecompressor;
|
||||
|
||||
using FModel.Creator;
|
||||
using FModel.Extensions;
|
||||
using FModel.Framework;
|
||||
|
|
@ -54,18 +51,12 @@ using FModel.Settings;
|
|||
using FModel.Views;
|
||||
using FModel.Views.Resources.Controls;
|
||||
using FModel.Views.Snooper;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using OpenTK.Windowing.Common;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
|
||||
using Serilog;
|
||||
|
||||
using SkiaSharp;
|
||||
|
||||
using UE4Config.Parsing;
|
||||
|
||||
using Application = System.Windows.Application;
|
||||
using FGuid = CUE4Parse.UE4.Objects.Core.Misc.FGuid;
|
||||
|
||||
|
|
@ -78,13 +69,6 @@ public class CUE4ParseViewModel : ViewModel
|
|||
private readonly Regex _fnLiveRegex = new(@"^FortniteGame[/\\]Content[/\\]Paks[/\\]",
|
||||
RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
|
||||
private string _internalGameName;
|
||||
public string InternalGameName
|
||||
{
|
||||
get => _internalGameName;
|
||||
set => SetProperty(ref _internalGameName, value);
|
||||
}
|
||||
|
||||
private bool _modelIsOverwritingMaterial;
|
||||
public bool ModelIsOverwritingMaterial
|
||||
{
|
||||
|
|
@ -153,20 +137,18 @@ public class CUE4ParseViewModel : ViewModel
|
|||
{
|
||||
case Constants._FN_LIVE_TRIGGER:
|
||||
{
|
||||
InternalGameName = "FortniteGame";
|
||||
Provider = new StreamedFileProvider("FortniteLive", true, versionContainer);
|
||||
break;
|
||||
}
|
||||
case Constants._VAL_LIVE_TRIGGER:
|
||||
{
|
||||
InternalGameName = "ShooterGame";
|
||||
Provider = new StreamedFileProvider("ValorantLive", true, versionContainer);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
InternalGameName = gameDirectory.SubstringBeforeLast(gameDirectory.Contains("eFootball") ? "\\pak" : "\\Content").SubstringAfterLast("\\");
|
||||
Provider = InternalGameName switch
|
||||
var project = gameDirectory.SubstringBeforeLast(gameDirectory.Contains("eFootball") ? "\\pak" : "\\Content").SubstringAfterLast("\\");
|
||||
Provider = project switch
|
||||
{
|
||||
"StateOfDecay2" => new DefaultFileProvider(new DirectoryInfo(gameDirectory),
|
||||
[
|
||||
|
|
@ -299,11 +281,10 @@ public class CUE4ParseViewModel : ViewModel
|
|||
{
|
||||
Provider.SubmitKeys(aesKeys);
|
||||
Provider.PostMount();
|
||||
InternalGameName = Provider.InternalGameName;
|
||||
|
||||
var aesMax = Provider.RequiredKeys.Count + Provider.Keys.Count;
|
||||
var archiveMax = Provider.UnloadedVfs.Count + Provider.MountedVfs.Count;
|
||||
Log.Information($"Project: {InternalGameName} | Mounted: {Provider.MountedVfs.Count}/{archiveMax} | AES: {Provider.Keys.Count}/{aesMax}");
|
||||
Log.Information($"Project: {Provider.ProjectName} | Mounted: {Provider.MountedVfs.Count}/{archiveMax} | AES: {Provider.Keys.Count}/{aesMax}");
|
||||
}
|
||||
|
||||
public void ClearProvider()
|
||||
|
|
@ -337,7 +318,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
{
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
var info = _apiEndpointView.FModelApi.GetNews(cancellationToken, Provider.InternalGameName);
|
||||
var info = _apiEndpointView.FModelApi.GetNews(cancellationToken, Provider.ProjectName);
|
||||
if (info == null) return;
|
||||
|
||||
FLogger.Append(ELog.None, () =>
|
||||
|
|
@ -420,7 +401,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
public Task VerifyOnDemandArchives()
|
||||
{
|
||||
// only local fortnite
|
||||
if (Provider is not DefaultFileProvider || !Provider.InternalGameName.Equals("FortniteGame", StringComparison.OrdinalIgnoreCase))
|
||||
if (Provider is not DefaultFileProvider || !Provider.ProjectName.Equals("FortniteGame", StringComparison.OrdinalIgnoreCase))
|
||||
return Task.CompletedTask;
|
||||
|
||||
// scuffed but working
|
||||
|
|
@ -477,7 +458,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
}
|
||||
private Task LoadHotfixedLocalizedResources()
|
||||
{
|
||||
if (!Provider.InternalGameName.Equals("fortnitegame", StringComparison.OrdinalIgnoreCase) || HotfixedResourcesDone) return Task.CompletedTask;
|
||||
if (!Provider.ProjectName.Equals("fortnitegame", StringComparison.OrdinalIgnoreCase) || HotfixedResourcesDone) return Task.CompletedTask;
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var hotfixes = ApplicationService.ApiEndpointView.CentralApi.GetHotfixes(default, Provider.GetLanguageCode(UserSettings.Default.AssetLanguage));
|
||||
|
|
@ -524,7 +505,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
{
|
||||
Thread.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
Extract(cancellationToken, asset.FullPath, TabControl.HasNoTabs);
|
||||
Extract(cancellationToken, asset, TabControl.HasNoTabs);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -552,48 +533,44 @@ public class CUE4ParseViewModel : ViewModel
|
|||
Parallel.ForEach(folder.AssetsList.Assets, asset =>
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ExportData(asset.FullPath, false);
|
||||
ExportData(asset, false);
|
||||
});
|
||||
|
||||
foreach (var f in folder.Folders) ExportFolder(cancellationToken, f);
|
||||
}
|
||||
|
||||
public void ExtractFolder(CancellationToken cancellationToken, TreeItem folder)
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset.FullPath, TabControl.HasNoTabs));
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs));
|
||||
|
||||
public void SaveFolder(CancellationToken cancellationToken, TreeItem folder)
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset.FullPath, TabControl.HasNoTabs, EBulkType.Properties | EBulkType.Auto));
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs, EBulkType.Properties | EBulkType.Auto));
|
||||
|
||||
public void TextureFolder(CancellationToken cancellationToken, TreeItem folder)
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset.FullPath, TabControl.HasNoTabs, EBulkType.Textures | EBulkType.Auto));
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs, EBulkType.Textures | EBulkType.Auto));
|
||||
|
||||
public void ModelFolder(CancellationToken cancellationToken, TreeItem folder)
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset.FullPath, TabControl.HasNoTabs, EBulkType.Meshes | EBulkType.Auto));
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs, EBulkType.Meshes | EBulkType.Auto));
|
||||
|
||||
public void AnimationFolder(CancellationToken cancellationToken, TreeItem folder)
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset.FullPath, TabControl.HasNoTabs, EBulkType.Animations | EBulkType.Auto));
|
||||
=> BulkFolder(cancellationToken, folder, asset => Extract(cancellationToken, asset, TabControl.HasNoTabs, EBulkType.Animations | EBulkType.Auto));
|
||||
|
||||
public void Extract(CancellationToken cancellationToken, string fullPath, bool addNewTab = false, EBulkType bulk = EBulkType.None)
|
||||
public void Extract(CancellationToken cancellationToken, AssetItem asset, bool addNewTab = false, EBulkType bulk = EBulkType.None)
|
||||
{
|
||||
Log.Information("User DOUBLE-CLICKED to extract '{FullPath}'", fullPath);
|
||||
Log.Information("User DOUBLE-CLICKED to extract '{FullPath}'", asset.FullPath);
|
||||
|
||||
var directory = fullPath.SubstringBeforeLast('/');
|
||||
var fileName = fullPath.SubstringAfterLast('/');
|
||||
var ext = fullPath.SubstringAfterLast('.').ToLower();
|
||||
|
||||
if (addNewTab && TabControl.CanAddTabs) TabControl.AddTab(fileName, directory);
|
||||
else TabControl.SelectedTab.SoftReset(fileName, directory);
|
||||
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(ext);
|
||||
if (addNewTab && TabControl.CanAddTabs) TabControl.AddTab(asset);
|
||||
else TabControl.SelectedTab.SoftReset(asset);
|
||||
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(asset.Extension);
|
||||
|
||||
var updateUi = !HasFlag(bulk, EBulkType.Auto);
|
||||
var saveProperties = HasFlag(bulk, EBulkType.Properties);
|
||||
var saveTextures = HasFlag(bulk, EBulkType.Textures);
|
||||
switch (ext)
|
||||
switch (asset.Extension)
|
||||
{
|
||||
case "uasset":
|
||||
case "umap":
|
||||
{
|
||||
var pkg = Provider.LoadPackage(fullPath);
|
||||
var pkg = Provider.LoadPackage(asset.FullPath, asset.Archive);
|
||||
if (saveProperties || updateUi)
|
||||
{
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(pkg.GetExports(), Formatting.Indented), saveProperties, updateUi);
|
||||
|
|
@ -637,85 +614,71 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case "po":
|
||||
case "h":
|
||||
{
|
||||
if (Provider.TrySaveAsset(fullPath, out var data))
|
||||
{
|
||||
using var stream = new MemoryStream(data) { Position = 0 };
|
||||
using var reader = new StreamReader(stream);
|
||||
var data = Provider.SaveAsset(asset.FullPath, asset.Archive);
|
||||
using var stream = new MemoryStream(data) { Position = 0 };
|
||||
using var reader = new StreamReader(stream);
|
||||
|
||||
TabControl.SelectedTab.SetDocumentText(reader.ReadToEnd(), saveProperties, updateUi);
|
||||
}
|
||||
TabControl.SelectedTab.SetDocumentText(reader.ReadToEnd(), saveProperties, updateUi);
|
||||
|
||||
break;
|
||||
}
|
||||
case "locmeta":
|
||||
{
|
||||
if (Provider.TryCreateReader(fullPath, out var archive))
|
||||
{
|
||||
var metadata = new FTextLocalizationMetaDataResource(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(metadata, Formatting.Indented), saveProperties, updateUi);
|
||||
}
|
||||
var archive = Provider.CreateReader(asset.FullPath, asset.Archive);
|
||||
var metadata = new FTextLocalizationMetaDataResource(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(metadata, Formatting.Indented), saveProperties, updateUi);
|
||||
|
||||
break;
|
||||
}
|
||||
case "locres":
|
||||
{
|
||||
if (Provider.TryCreateReader(fullPath, out var archive))
|
||||
{
|
||||
var locres = new FTextLocalizationResource(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(locres, Formatting.Indented), saveProperties, updateUi);
|
||||
}
|
||||
var archive = Provider.CreateReader(asset.FullPath, asset.Archive);
|
||||
var locres = new FTextLocalizationResource(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(locres, Formatting.Indented), saveProperties, updateUi);
|
||||
|
||||
break;
|
||||
}
|
||||
case "bin" when fileName.Contains("AssetRegistry", StringComparison.OrdinalIgnoreCase):
|
||||
case "bin" when asset.FileName.Contains("AssetRegistry", StringComparison.OrdinalIgnoreCase):
|
||||
{
|
||||
if (Provider.TryCreateReader(fullPath, out var archive))
|
||||
{
|
||||
var registry = new FAssetRegistryState(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(registry, Formatting.Indented), saveProperties, updateUi);
|
||||
}
|
||||
var archive = Provider.CreateReader(asset.FullPath, asset.Archive);
|
||||
var registry = new FAssetRegistryState(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(registry, Formatting.Indented), saveProperties, updateUi);
|
||||
|
||||
break;
|
||||
}
|
||||
case "bin" when fileName.Contains("GlobalShaderCache", StringComparison.OrdinalIgnoreCase):
|
||||
case "bin" when asset.FileName.Contains("GlobalShaderCache", StringComparison.OrdinalIgnoreCase):
|
||||
{
|
||||
if (Provider.TryCreateReader(fullPath, out var archive))
|
||||
{
|
||||
var registry = new FGlobalShaderCache(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(registry, Formatting.Indented), saveProperties, updateUi);
|
||||
}
|
||||
var archive = Provider.CreateReader(asset.FullPath, asset.Archive);
|
||||
var registry = new FGlobalShaderCache(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(registry, Formatting.Indented), saveProperties, updateUi);
|
||||
|
||||
break;
|
||||
}
|
||||
case "bnk":
|
||||
case "pck":
|
||||
{
|
||||
if (Provider.TryCreateReader(fullPath, out var archive))
|
||||
var archive = Provider.CreateReader(asset.FullPath, asset.Archive);
|
||||
var wwise = new WwiseReader(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(wwise, Formatting.Indented), saveProperties, updateUi);
|
||||
foreach (var (name, data) in wwise.WwiseEncodedMedias)
|
||||
{
|
||||
var wwise = new WwiseReader(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(wwise, Formatting.Indented), saveProperties, updateUi);
|
||||
foreach (var (name, data) in wwise.WwiseEncodedMedias)
|
||||
{
|
||||
SaveAndPlaySound(fullPath.SubstringBeforeWithLast("/") + name, "WEM", data);
|
||||
}
|
||||
SaveAndPlaySound(asset.FullPath.SubstringBeforeWithLast('/') + name, "WEM", data);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "wem":
|
||||
{
|
||||
if (Provider.TrySaveAsset(fullPath, out var input))
|
||||
SaveAndPlaySound(fullPath, "WEM", input);
|
||||
var data = Provider.SaveAsset(asset.FullPath, asset.Archive);
|
||||
SaveAndPlaySound(asset.FullPath, "WEM", data);
|
||||
|
||||
break;
|
||||
}
|
||||
case "udic":
|
||||
{
|
||||
if (Provider.TryCreateReader(fullPath, out var archive))
|
||||
{
|
||||
var header = new FOodleDictionaryArchive(archive).Header;
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(header, Formatting.Indented), saveProperties, updateUi);
|
||||
}
|
||||
var archive = Provider.CreateReader(asset.FullPath, asset.Archive);
|
||||
var header = new FOodleDictionaryArchive(archive).Header;
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(header, Formatting.Indented), saveProperties, updateUi);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -723,55 +686,49 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case "jpg":
|
||||
case "bmp":
|
||||
{
|
||||
if (Provider.TrySaveAsset(fullPath, out var data))
|
||||
{
|
||||
using var stream = new MemoryStream(data) { Position = 0 };
|
||||
TabControl.SelectedTab.AddImage(fileName.SubstringBeforeLast("."), false, SKBitmap.Decode(stream), saveTextures, updateUi);
|
||||
}
|
||||
var data = Provider.SaveAsset(asset.FullPath, asset.Archive);
|
||||
using var stream = new MemoryStream(data) { Position = 0 };
|
||||
TabControl.SelectedTab.AddImage(asset.FileName.SubstringBeforeLast("."), false, SKBitmap.Decode(stream), saveTextures, updateUi);
|
||||
|
||||
break;
|
||||
}
|
||||
case "svg":
|
||||
{
|
||||
if (Provider.TrySaveAsset(fullPath, out var data))
|
||||
var data = Provider.SaveAsset(asset.FullPath, asset.Archive);
|
||||
using var stream = new MemoryStream(data) { Position = 0 };
|
||||
var svg = new SkiaSharp.Extended.Svg.SKSvg(new SKSize(512, 512));
|
||||
svg.Load(stream);
|
||||
|
||||
var bitmap = new SKBitmap(512, 512);
|
||||
using (var canvas = new SKCanvas(bitmap))
|
||||
using (var paint = new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.Medium })
|
||||
{
|
||||
using var stream = new MemoryStream(data) { Position = 0 };
|
||||
var svg = new SkiaSharp.Extended.Svg.SKSvg(new SKSize(512, 512));
|
||||
svg.Load(stream);
|
||||
|
||||
var bitmap = new SKBitmap(512, 512);
|
||||
using (var canvas = new SKCanvas(bitmap))
|
||||
using (var paint = new SKPaint { IsAntialias = true, FilterQuality = SKFilterQuality.Medium })
|
||||
{
|
||||
canvas.DrawPicture(svg.Picture, paint);
|
||||
}
|
||||
|
||||
TabControl.SelectedTab.AddImage(fileName.SubstringBeforeLast("."), false, bitmap, saveTextures, updateUi);
|
||||
canvas.DrawPicture(svg.Picture, paint);
|
||||
}
|
||||
|
||||
TabControl.SelectedTab.AddImage(asset.FileName.SubstringBeforeLast("."), false, bitmap, saveTextures, updateUi);
|
||||
|
||||
break;
|
||||
}
|
||||
case "ufont":
|
||||
case "otf":
|
||||
case "ttf":
|
||||
FLogger.Append(ELog.Warning, () =>
|
||||
FLogger.Text($"Export '{fileName}' raw data and change its extension if you want it to be an installable font file", Constants.WHITE, true));
|
||||
FLogger.Text($"Export '{asset.FileName}' raw data and change its extension if you want it to be an installable font file", Constants.WHITE, true));
|
||||
break;
|
||||
case "ushaderbytecode":
|
||||
case "ushadercode":
|
||||
{
|
||||
if (Provider.TryCreateReader(fullPath, out var archive))
|
||||
{
|
||||
var ar = new FShaderCodeArchive(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(ar, Formatting.Indented), saveProperties, updateUi);
|
||||
}
|
||||
var archive = Provider.CreateReader(asset.FullPath, asset.Archive);
|
||||
var ar = new FShaderCodeArchive(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(ar, Formatting.Indented), saveProperties, updateUi);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
FLogger.Append(ELog.Warning, () =>
|
||||
FLogger.Text($"The package '{fileName}' is of an unknown type.", Constants.WHITE, true));
|
||||
FLogger.Text($"The package '{asset.FileName}' is of an unknown type.", Constants.WHITE, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -780,7 +737,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
public void ExtractAndScroll(CancellationToken cancellationToken, string fullPath, string objectName, string parentExportType)
|
||||
{
|
||||
Log.Information("User CTRL-CLICKED to extract '{FullPath}'", fullPath);
|
||||
TabControl.AddTab(fullPath.SubstringAfterLast('/'), fullPath.SubstringBeforeLast('/'), parentExportType);
|
||||
TabControl.AddTab(new AssetItem(fullPath), parentExportType);
|
||||
TabControl.SelectedTab.ScrollTrigger = objectName;
|
||||
|
||||
var pkg = Provider.LoadPackage(fullPath);
|
||||
|
|
@ -840,7 +797,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
{
|
||||
var fileName = sourceFile.SubstringAfterLast('/');
|
||||
var path = Path.Combine(UserSettings.Default.TextureDirectory,
|
||||
UserSettings.Default.KeepDirectoryStructure ? TabControl.SelectedTab.Directory : "", fileName!).Replace('\\', '/');
|
||||
UserSettings.Default.KeepDirectoryStructure ? TabControl.SelectedTab.Asset.Directory : "", fileName!).Replace('\\', '/');
|
||||
|
||||
Directory.CreateDirectory(path.SubstringBeforeLast('/'));
|
||||
|
||||
|
|
@ -881,7 +838,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
return false;
|
||||
}
|
||||
|
||||
SaveAndPlaySound(Path.Combine(TabControl.SelectedTab.Directory, TabControl.SelectedTab.Header.SubstringBeforeLast('.')).Replace('\\', '/'), audioFormat, data);
|
||||
SaveAndPlaySound(Path.Combine(TabControl.SelectedTab.Asset.FullPath.SubstringBeforeLast('.')).Replace('\\', '/'), audioFormat, data);
|
||||
return false;
|
||||
}
|
||||
case UWorld when isNone && UserSettings.Default.PreviewWorlds:
|
||||
|
|
@ -897,7 +854,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case USkeletalMesh when isNone && UserSettings.Default.PreviewSkeletalMeshes:
|
||||
case USkeleton when isNone && UserSettings.Default.SaveSkeletonAsMesh:
|
||||
case UMaterialInstance when isNone && UserSettings.Default.PreviewMaterials && !ModelIsOverwritingMaterial &&
|
||||
!(Provider.InternalGameName.Equals("FortniteGame", StringComparison.OrdinalIgnoreCase) &&
|
||||
!(Provider.ProjectName.Equals("FortniteGame", StringComparison.OrdinalIgnoreCase) &&
|
||||
(pkg.Name.Contains("/MI_OfferImages/", StringComparison.OrdinalIgnoreCase) ||
|
||||
pkg.Name.Contains("/RenderSwitch_Materials/", StringComparison.OrdinalIgnoreCase) ||
|
||||
pkg.Name.Contains("/MI_BPTile/", StringComparison.OrdinalIgnoreCase))):
|
||||
|
|
@ -943,15 +900,13 @@ public class CUE4ParseViewModel : ViewModel
|
|||
}
|
||||
}
|
||||
|
||||
public void ShowMetadata(string fullPath)
|
||||
public void ShowMetadata(AssetItem asset)
|
||||
{
|
||||
var package = Provider.LoadPackage(fullPath);
|
||||
var package = Provider.LoadPackage(asset.FullPath, asset.Archive);
|
||||
|
||||
var directory = fullPath.SubstringBeforeLast('/');
|
||||
var fileName = $"{fullPath.SubstringAfterLast('/')} (Metadata)";
|
||||
|
||||
if (TabControl.CanAddTabs) TabControl.AddTab(fileName, directory);
|
||||
else TabControl.SelectedTab.SoftReset(fileName, directory);
|
||||
var a = new AssetItem(" (Metadata)", asset);
|
||||
if (TabControl.CanAddTabs) TabControl.AddTab(a);
|
||||
else TabControl.SelectedTab.SoftReset(a);
|
||||
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("");
|
||||
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(package, Formatting.Indented), false, false);
|
||||
|
|
@ -1008,10 +963,11 @@ public class CUE4ParseViewModel : ViewModel
|
|||
}
|
||||
|
||||
private readonly object _rawData = new ();
|
||||
public void ExportData(string fullPath, bool updateUi = true)
|
||||
public void ExportData(AssetItem asset, bool updateUi = true)
|
||||
{
|
||||
var fileName = fullPath.SubstringAfterLast('/');
|
||||
if (Provider.TrySavePackage(fullPath, out var assets))
|
||||
// TODO: export by archive
|
||||
// is that even useful? if user doesn't rename manually it's gonna overwrite the file anyway
|
||||
if (Provider.TrySavePackage(asset.FullPath, out var assets))
|
||||
{
|
||||
string path = UserSettings.Default.RawDataDirectory;
|
||||
Parallel.ForEach(assets, kvp =>
|
||||
|
|
@ -1024,21 +980,21 @@ public class CUE4ParseViewModel : ViewModel
|
|||
}
|
||||
});
|
||||
|
||||
Log.Information("{FileName} successfully exported", fileName);
|
||||
Log.Information("{FileName} successfully exported", asset.FileName);
|
||||
if (updateUi)
|
||||
{
|
||||
FLogger.Append(ELog.Information, () =>
|
||||
{
|
||||
FLogger.Text("Successfully exported ", Constants.WHITE);
|
||||
FLogger.Link(fileName, path, true);
|
||||
FLogger.Link(asset.FileName, path, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("{FileName} could not be exported", fileName);
|
||||
Log.Error("{FileName} could not be exported", asset.FileName);
|
||||
if (updateUi)
|
||||
FLogger.Append(ELog.Error, () => FLogger.Text($"Could not export '{fileName}'", Constants.WHITE, true));
|
||||
FLogger.Append(ELog.Error, () => FLogger.Text($"Could not export '{asset.FileName}'", Constants.WHITE, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using FModel.Extensions;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Framework;
|
||||
|
||||
namespace FModel.ViewModels.Commands;
|
||||
|
|
@ -43,4 +43,4 @@ public class CopyCommand : ViewModelCommand<ApplicationViewModel>
|
|||
|
||||
Clipboard.SetText(sb.ToString().TrimEnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ using System.Threading.Tasks;
|
|||
using AdonisUI.Controls;
|
||||
using CUE4Parse.UE4.Readers;
|
||||
using CUE4Parse.UE4.VirtualFileSystem;
|
||||
using FModel.Creator;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Extensions;
|
||||
using FModel.Framework;
|
||||
using FModel.Services;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public class MenuCommand : ViewModelCommand<ApplicationViewModel>
|
|||
Helper.OpenWindow<AdonisWindow>("AES Manager", () => new AesManager().Show());
|
||||
break;
|
||||
case "Directory_Backup":
|
||||
Helper.OpenWindow<AdonisWindow>("Backup Manager", () => new BackupManager(contextViewModel.CUE4Parse.Provider.InternalGameName).Show());
|
||||
Helper.OpenWindow<AdonisWindow>("Backup Manager", () => new BackupManager(contextViewModel.CUE4Parse.Provider.ProjectName).Show());
|
||||
break;
|
||||
case "Directory_ArchivesInfo":
|
||||
contextViewModel.CUE4Parse.TabControl.AddTab("Archives Info");
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
|
|||
{
|
||||
Thread.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, asset.FullPath, true);
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, asset, true);
|
||||
}
|
||||
break;
|
||||
case "Assets_Show_Metadata":
|
||||
|
|
@ -40,7 +40,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
|
|||
{
|
||||
Thread.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
contextViewModel.CUE4Parse.ShowMetadata(asset.FullPath);
|
||||
contextViewModel.CUE4Parse.ShowMetadata(asset);
|
||||
}
|
||||
break;
|
||||
case "Assets_Export_Data":
|
||||
|
|
@ -48,7 +48,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
|
|||
{
|
||||
Thread.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
contextViewModel.CUE4Parse.ExportData(asset.FullPath);
|
||||
contextViewModel.CUE4Parse.ExportData(asset);
|
||||
}
|
||||
break;
|
||||
case "Assets_Save_Properties":
|
||||
|
|
@ -56,7 +56,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
|
|||
{
|
||||
Thread.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, asset.FullPath, false, EBulkType.Properties | updateUi);
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, asset, false, EBulkType.Properties | updateUi);
|
||||
}
|
||||
break;
|
||||
case "Assets_Save_Textures":
|
||||
|
|
@ -64,7 +64,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
|
|||
{
|
||||
Thread.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, asset.FullPath, false, EBulkType.Textures | updateUi);
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, asset, false, EBulkType.Textures | updateUi);
|
||||
}
|
||||
break;
|
||||
case "Assets_Save_Models":
|
||||
|
|
@ -72,7 +72,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
|
|||
{
|
||||
Thread.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, asset.FullPath, false, EBulkType.Meshes | updateUi);
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, asset, false, EBulkType.Meshes | updateUi);
|
||||
}
|
||||
break;
|
||||
case "Assets_Save_Animations":
|
||||
|
|
@ -80,7 +80,7 @@ public class RightClickMenuCommand : ViewModelCommand<ApplicationViewModel>
|
|||
{
|
||||
Thread.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, asset.FullPath, false, EBulkType.Animations | updateUi);
|
||||
contextViewModel.CUE4Parse.Extract(cancellationToken, asset, false, EBulkType.Animations | updateUi);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,44 +32,44 @@ public class TabCommand : ViewModelCommand<TabItem>
|
|||
_applicationView.CUE4Parse.TabControl.RemoveOtherTabs(contextViewModel);
|
||||
break;
|
||||
case "Asset_Export_Data":
|
||||
await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.ExportData(contextViewModel.FullPath));
|
||||
await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.ExportData(contextViewModel.Asset));
|
||||
break;
|
||||
case "Asset_Save_Properties":
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.FullPath, false, EBulkType.Properties);
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Asset, false, EBulkType.Properties);
|
||||
});
|
||||
break;
|
||||
case "Asset_Save_Textures":
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.FullPath, false, EBulkType.Textures);
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Asset, false, EBulkType.Textures);
|
||||
});
|
||||
break;
|
||||
case "Asset_Save_Models":
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.FullPath, false, EBulkType.Meshes | EBulkType.Auto);
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Asset, false, EBulkType.Meshes);
|
||||
});
|
||||
break;
|
||||
case "Asset_Save_Animations":
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.FullPath, false, EBulkType.Animations | EBulkType.Auto);
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Asset, false, EBulkType.Animations);
|
||||
});
|
||||
break;
|
||||
case "Open_Properties":
|
||||
if (contextViewModel.Header == "New Tab" || contextViewModel.Document == null) return;
|
||||
Helper.OpenWindow<AdonisWindow>(contextViewModel.Header + " (Properties)", () =>
|
||||
if (contextViewModel.Asset.FileName == "New Tab" || contextViewModel.Document == null) return;
|
||||
Helper.OpenWindow<AdonisWindow>(contextViewModel.Asset.FileName + " (Properties)", () =>
|
||||
{
|
||||
new PropertiesPopout(contextViewModel)
|
||||
{
|
||||
Title = contextViewModel.Header + " (Properties)"
|
||||
Title = contextViewModel.Asset.FileName + " (Properties)"
|
||||
}.Show();
|
||||
});
|
||||
break;
|
||||
case "Copy_Asset_Path":
|
||||
Clipboard.SetText(contextViewModel.FullPath);
|
||||
Clipboard.SetText(contextViewModel.Asset.FullPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using FModel.Extensions;
|
||||
using FModel.Framework;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
|
|
@ -10,6 +9,7 @@ using System.Linq;
|
|||
using System.Text.RegularExpressions;
|
||||
using CUE4Parse.UE4.Objects.Core.Serialization;
|
||||
using CUE4Parse.UE4.Versions;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Settings;
|
||||
using FModel.ViewModels.ApiEndpoints.Models;
|
||||
using Microsoft.Win32;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ using System.Windows;
|
|||
using System.Windows.Media.Imaging;
|
||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using CUE4Parse_Conversion.Textures;
|
||||
using CUE4Parse.Utils;
|
||||
|
||||
namespace FModel.ViewModels;
|
||||
|
||||
|
|
@ -92,22 +93,13 @@ public class TabItem : ViewModel
|
|||
{
|
||||
public string ParentExportType { get; private set; }
|
||||
|
||||
private string _header;
|
||||
public string Header
|
||||
private AssetItem _asset;
|
||||
public AssetItem Asset
|
||||
{
|
||||
get => _header;
|
||||
set => SetProperty(ref _header, value);
|
||||
get => _asset;
|
||||
set => SetProperty(ref _asset, value);
|
||||
}
|
||||
|
||||
private string _directory;
|
||||
public string Directory
|
||||
{
|
||||
get => _directory;
|
||||
set => SetProperty(ref _directory, value);
|
||||
}
|
||||
|
||||
public string FullPath => this.Directory + "/" + this.Header.SubstringBeforeLast(" (");
|
||||
|
||||
private bool _hasSearchOpen;
|
||||
public bool HasSearchOpen
|
||||
{
|
||||
|
|
@ -217,18 +209,16 @@ public class TabItem : ViewModel
|
|||
private GoToCommand _goToCommand;
|
||||
public GoToCommand GoToCommand => _goToCommand ??= new GoToCommand(null);
|
||||
|
||||
public TabItem(string header, string directory, string parentExportType)
|
||||
public TabItem(AssetItem asset, string parentExportType)
|
||||
{
|
||||
Header = header;
|
||||
Directory = directory;
|
||||
Asset = asset;
|
||||
ParentExportType = parentExportType;
|
||||
_images = new ObservableCollection<TabImage>();
|
||||
}
|
||||
|
||||
public void SoftReset(string header, string directory)
|
||||
public void SoftReset(AssetItem asset)
|
||||
{
|
||||
Header = header;
|
||||
Directory = directory;
|
||||
Asset = asset;
|
||||
ParentExportType = string.Empty;
|
||||
ScrollTrigger = null;
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
|
|
@ -316,9 +306,9 @@ public class TabItem : ViewModel
|
|||
|
||||
var fileName = image.ExportName + ext;
|
||||
var path = Path.Combine(UserSettings.Default.TextureDirectory,
|
||||
UserSettings.Default.KeepDirectoryStructure ? Directory : "", fileName!).Replace('\\', '/');
|
||||
UserSettings.Default.KeepDirectoryStructure ? Asset.Directory : "", fileName!).Replace('\\', '/');
|
||||
|
||||
System.IO.Directory.CreateDirectory(path.SubstringBeforeLast('/'));
|
||||
Directory.CreateDirectory(path.SubstringBeforeLast('/'));
|
||||
|
||||
SaveImage(image, path, fileName, updateUi);
|
||||
}
|
||||
|
|
@ -337,11 +327,11 @@ public class TabItem : ViewModel
|
|||
|
||||
public void SaveProperty(bool updateUi)
|
||||
{
|
||||
var fileName = Path.ChangeExtension(Header, ".json");
|
||||
var fileName = Path.ChangeExtension(Asset.FileName, ".json");
|
||||
var directory = Path.Combine(UserSettings.Default.PropertiesDirectory,
|
||||
UserSettings.Default.KeepDirectoryStructure ? Directory : "", fileName).Replace('\\', '/');
|
||||
UserSettings.Default.KeepDirectoryStructure ? Asset.Directory : "", fileName).Replace('\\', '/');
|
||||
|
||||
System.IO.Directory.CreateDirectory(directory.SubstringBeforeLast('/'));
|
||||
Directory.CreateDirectory(directory.SubstringBeforeLast('/'));
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() => File.WriteAllText(directory, Document.Text));
|
||||
SaveCheck(directory, fileName, updateUi);
|
||||
|
|
@ -390,28 +380,27 @@ public class TabControlViewModel : ViewModel
|
|||
|
||||
public TabControlViewModel()
|
||||
{
|
||||
_tabItems = new ObservableCollection<TabItem>(EnumerateTabs());
|
||||
_tabItems = [];
|
||||
TabsItems = new ReadOnlyObservableCollection<TabItem>(_tabItems);
|
||||
SelectedTab = TabsItems.FirstOrDefault();
|
||||
AddTab();
|
||||
}
|
||||
|
||||
public void AddTab(string header = null, string directory = null, string parentExportType = null)
|
||||
public void AddTab() => AddTab("New Tab");
|
||||
public void AddTab(string title) => AddTab(new AssetItem(title));
|
||||
public void AddTab(AssetItem asset, string parentExportType = null)
|
||||
{
|
||||
if (!CanAddTabs) return;
|
||||
|
||||
var h = header ?? "New Tab";
|
||||
var d = directory ?? string.Empty;
|
||||
var p = parentExportType ?? string.Empty;
|
||||
if (SelectedTab is { Header : "New Tab" })
|
||||
if (SelectedTab?.Asset.FileName == "New Tab")
|
||||
{
|
||||
SelectedTab.Header = h;
|
||||
SelectedTab.Directory = d;
|
||||
SelectedTab.Asset = asset;
|
||||
return;
|
||||
}
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
_tabItems.Add(new TabItem(h, d, p));
|
||||
_tabItems.Add(new TabItem(asset, p));
|
||||
SelectedTab = _tabItems.Last();
|
||||
});
|
||||
}
|
||||
|
|
@ -470,9 +459,4 @@ public class TabControlViewModel : ViewModel
|
|||
_tabItems.Clear();
|
||||
});
|
||||
}
|
||||
|
||||
private static IEnumerable<TabItem> EnumerateTabs()
|
||||
{
|
||||
yield return new TabItem("New Tab", string.Empty, string.Empty);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using System.ComponentModel;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
using FModel.Extensions;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Framework;
|
||||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Text.RegularExpressions;
|
|||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.TextFormatting;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Extensions;
|
||||
using FModel.Services;
|
||||
using FModel.ViewModels;
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ public partial class AvalonEditor
|
|||
if (sender is not TextEditor avalonEditor || DataContext is not TabItem tabItem ||
|
||||
avalonEditor.Document == null || string.IsNullOrEmpty(avalonEditor.Document.Text))
|
||||
return;
|
||||
avalonEditor.Document.FileName = tabItem.Directory + '/' + StringExtensions.SubstringBeforeLast(tabItem.Header, '.');
|
||||
avalonEditor.Document.FileName = tabItem.Asset.FullPath.SubstringBeforeLast('.');
|
||||
|
||||
if (!_savedCarets.ContainsKey(avalonEditor.Document.FileName))
|
||||
_ignoreCaret = true;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using FModel.Extensions;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.ViewModels;
|
||||
using ICSharpCode.AvalonEdit;
|
||||
using ICSharpCode.AvalonEdit.Document;
|
||||
|
|
@ -24,7 +24,7 @@ public partial class PropertiesPopout
|
|||
MyAvalonEditor.Document = new TextDocument
|
||||
{
|
||||
Text = contextViewModel.Document.Text,
|
||||
FileName = contextViewModel.Directory + '/' + contextViewModel.Header.SubstringBeforeLast('.')
|
||||
FileName = contextViewModel.Asset.FullPath.SubstringBeforeLast('.')
|
||||
};
|
||||
MyAvalonEditor.FontSize = contextViewModel.FontSize;
|
||||
MyAvalonEditor.SyntaxHighlighting = contextViewModel.Highlighter;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using FModel.Extensions;
|
||||
using CUE4Parse.Utils;
|
||||
|
||||
namespace FModel.Views.Resources.Converters;
|
||||
|
||||
|
|
@ -18,4 +18,4 @@ public class FullPathToFileConverter : IValueConverter
|
|||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -651,7 +651,7 @@
|
|||
<MouseBinding MouseAction="MiddleClick" Command="{Binding SelectedItem.TabCommand, ElementName=TabControlName}" CommandParameter="{Binding}" />
|
||||
</DockPanel.InputBindings>
|
||||
|
||||
<TextBlock DockPanel.Dock="Left" Text="{Binding Header}" TextTrimming="CharacterEllipsis" ToolTip="{Binding Header}">
|
||||
<TextBlock DockPanel.Dock="Left" Text="{Binding Asset.FileName}" TextTrimming="CharacterEllipsis" ToolTip="{Binding Asset.FileName}">
|
||||
<TextBlock.Width>
|
||||
<MultiBinding Converter="{x:Static converters:TabSizeConverter.Instance}" ConverterParameter="6">
|
||||
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type TabControl}}" />
|
||||
|
|
@ -913,7 +913,7 @@
|
|||
</Viewbox>
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Jump to Package Folder" Command="{Binding GoToCommand}" CommandParameter="{Binding Directory}">
|
||||
<MenuItem Header="Jump to Package Folder" Command="{Binding GoToCommand}" CommandParameter="{Binding Asset.Directory}">
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
<Canvas Width="24" Height="24">
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using FModel.Extensions;
|
||||
using FModel.Services;
|
||||
using FModel.ViewModels;
|
||||
|
||||
|
|
@ -36,7 +35,7 @@ public partial class SearchView
|
|||
|
||||
WindowState = WindowState.Minimized;
|
||||
MainWindow.YesWeCats.AssetsListName.ItemsSource = null;
|
||||
var folder = _applicationView.CustomDirectories.GoToCommand.JumpTo(assetItem.FullPath.SubstringBeforeLast('/'));
|
||||
var folder = _applicationView.CustomDirectories.GoToCommand.JumpTo(assetItem.Directory);
|
||||
if (folder == null) return;
|
||||
|
||||
MainWindow.YesWeCats.Activate();
|
||||
|
|
@ -58,7 +57,7 @@ public partial class SearchView
|
|||
return;
|
||||
|
||||
WindowState = WindowState.Minimized;
|
||||
await _threadWorkerView.Begin(cancellationToken => _applicationView.CUE4Parse.Extract(cancellationToken, assetItem.FullPath, true));
|
||||
await _threadWorkerView.Begin(cancellationToken => _applicationView.CUE4Parse.Extract(cancellationToken, assetItem, true));
|
||||
|
||||
MainWindow.YesWeCats.Activate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -534,7 +534,7 @@
|
|||
<Style TargetType="TreeViewItem" BasedOn="{StaticResource TreeViewItemStyle}">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding CUE4Parse.InternalGameName, Converter={x:Static converters:CaseInsensitiveStringEqualsConverter.Instance}, ConverterParameter='FortniteGame'}" Value="True">
|
||||
<DataTrigger Binding="{Binding CUE4Parse.Provider.ProjectName, Converter={x:Static converters:CaseInsensitiveStringEqualsConverter.Instance}, ConverterParameter='FortniteGame'}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public class Options
|
|||
["tl_next"] = new ("tl_next"),
|
||||
};
|
||||
|
||||
_game = Services.ApplicationService.ApplicationView.CUE4Parse.Provider.InternalGameName.ToUpper();
|
||||
_game = Services.ApplicationService.ApplicationView.CUE4Parse.Provider.ProjectName.ToUpper();
|
||||
|
||||
SelectModel(Guid.Empty);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ using CUE4Parse.UE4.Objects.Core.Math;
|
|||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using CUE4Parse.UE4.Objects.Engine;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using CUE4Parse.Utils;
|
||||
using FModel.Creator;
|
||||
using FModel.Extensions;
|
||||
using FModel.Settings;
|
||||
using FModel.Views.Snooper.Animations;
|
||||
using FModel.Views.Snooper.Buffers;
|
||||
|
|
@ -430,7 +430,7 @@ public class Renderer : IDisposable
|
|||
return;
|
||||
|
||||
if (persistentLevel.TryGetValue(out FSoftObjectPath runtimeCell, "WorldPartitionRuntimeCell") &&
|
||||
Utils.TryLoadObject(runtimeCell.AssetPathName.Text.SubstringBeforeWithLast(".") + runtimeCell.SubPathString.SubstringAfterLast("."), out UObject worldPartition))
|
||||
runtimeCell.TryLoad(out UObject worldPartition))
|
||||
{
|
||||
var position = worldPartition.GetOrDefault("Position", FVector.ZeroVector) * Constants.SCALE_DOWN_RATIO;
|
||||
var box = worldPartition.GetOrDefault("ContentBounds", new FBox(FVector.ZeroVector, FVector.OneVector));
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user