mirror of
https://github.com/4sval/FModel.git
synced 2026-03-21 17:24:26 -05:00
Merge pull request #549 from 4sval/pagination
Some checks are pending
FModel QA Builder / build (push) Waiting to run
Some checks are pending
FModel QA Builder / build (push) Waiting to run
Pagination
This commit is contained in:
commit
a97d773c64
|
|
@ -1 +1 @@
|
|||
Subproject commit 11a92870024a088888aae79c74d8ae0c6c8af3e5
|
||||
Subproject commit 2aed4da1ee440cd421222526bdc501031f685be6
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using FModel.Creator.Bases;
|
||||
|
|
@ -30,7 +31,7 @@ public class CreatorPackage : IDisposable
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryConstructCreator(out UCreator creator)
|
||||
public bool TryConstructCreator([MaybeNullWhen(false)] out UCreator creator)
|
||||
{
|
||||
switch (_exportType)
|
||||
{
|
||||
|
|
|
|||
70
FModel/Extensions/CUE4ParseExtensions.cs
Normal file
70
FModel/Extensions/CUE4ParseExtensions.cs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using CUE4Parse.FileProvider;
|
||||
using CUE4Parse.FileProvider.Objects;
|
||||
using CUE4Parse.UE4.Assets;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using FModel.Settings;
|
||||
|
||||
namespace FModel.Extensions;
|
||||
|
||||
public static class CUE4ParseExtensions
|
||||
{
|
||||
public class LoadPackageResult
|
||||
{
|
||||
// more than 1 export per page currently break the inner package navigation feature
|
||||
// if you have 1k exports per page, at page 2, you click on export index 932
|
||||
// it will find the export index 932 in the current page, which would realistically be 1932
|
||||
// fix would be to use InclusiveStart and ExclusiveEnd to determine the page the export index is in
|
||||
// giving the document access to this would fix the issue and we could re-use Package instead of reloading it but it's quite a bit of work atm
|
||||
|
||||
private const int PaginationThreshold = 5000;
|
||||
private const int MaxExportPerPage = 1;
|
||||
|
||||
public IPackage Package;
|
||||
public int RequestedIndex;
|
||||
|
||||
public bool IsPaginated => Package.ExportMapLength >= PaginationThreshold;
|
||||
|
||||
/// <summary>
|
||||
/// index of the first export on the current page
|
||||
/// this index is the starting point for additional data preview
|
||||
///
|
||||
/// it can be >0 even if <see cref="IsPaginated"/> is false if we want to focus data preview on a specific export
|
||||
/// in this case, we will display all exports but only the focused one will be checked for data preview
|
||||
/// </summary>
|
||||
public int InclusiveStart => Math.Max(0, RequestedIndex - RequestedIndex % MaxExportPerPage);
|
||||
/// <summary>
|
||||
/// last exclusive export index of the current page
|
||||
/// </summary>
|
||||
public int ExclusiveEnd => IsPaginated
|
||||
? Math.Min(InclusiveStart + MaxExportPerPage, Package.ExportMapLength)
|
||||
: Package.ExportMapLength;
|
||||
public int PageSize => ExclusiveEnd - InclusiveStart;
|
||||
|
||||
public string TabTitleExtra => IsPaginated ? $"Export{(PageSize > 1 ? "s" : "")} {InclusiveStart}{(PageSize > 1 ? $"-{ExclusiveEnd - 1}" : "")} of {Package.ExportMapLength - 1}" : null;
|
||||
|
||||
/// <summary>
|
||||
/// display all exports unless paginated
|
||||
/// </summary>
|
||||
/// <param name="save">if we save the data we will display all exports even if <see cref="IsPaginated"/> is true</param>
|
||||
/// <returns></returns>
|
||||
public object GetDisplayData(bool save = false) => !save && IsPaginated
|
||||
? Package.GetExports(InclusiveStart, PageSize)
|
||||
: Package.GetExports();
|
||||
}
|
||||
|
||||
public static LoadPackageResult GetLoadPackageResult(this IFileProvider provider, GameFile file, string objectName = null)
|
||||
{
|
||||
var result = new LoadPackageResult { Package = provider.LoadPackage(file) };
|
||||
if (result.IsPaginated || (result.Package.HasFlags(EPackageFlags.PKG_ContainsMap) && UserSettings.Default.PreviewWorlds)) // focus on UWorld if it's a map we want to preview
|
||||
{
|
||||
result.RequestedIndex = result.Package.GetExportIndex(file.NameWithoutExtension);
|
||||
if (objectName != null)
|
||||
{
|
||||
result.RequestedIndex = int.TryParse(objectName, out var index) ? index : result.Package.GetExportIndex(objectName);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,14 +6,14 @@ using ICSharpCode.AvalonEdit.Document;
|
|||
|
||||
namespace FModel.Extensions;
|
||||
|
||||
public static class StringExtensions
|
||||
public static partial class StringExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string GetReadableSize(double size)
|
||||
{
|
||||
if (size == 0) return "0 B";
|
||||
|
||||
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
|
||||
string[] sizes = ["B", "KB", "MB", "GB", "TB"];
|
||||
var order = 0;
|
||||
while (size >= 1024 && order < sizes.Length - 1)
|
||||
{
|
||||
|
|
@ -27,21 +27,22 @@ public static class StringExtensions
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int GetNameLineNumber(this string s, string lineToFind)
|
||||
{
|
||||
if (KismetRegex().IsMatch(lineToFind))
|
||||
return s.GetKismetLineNumber(lineToFind);
|
||||
if (int.TryParse(lineToFind, out var index))
|
||||
return s.GetLineNumber(index);
|
||||
|
||||
lineToFind = $" \"Name\": \"{lineToFind}\",";
|
||||
using var reader = new StringReader(s);
|
||||
var lineNum = 0;
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
while (reader.ReadLine() is { } line)
|
||||
{
|
||||
lineNum++;
|
||||
if (line.Equals(lineToFind, StringComparison.OrdinalIgnoreCase))
|
||||
return lineNum;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
|
@ -64,18 +65,17 @@ public static class StringExtensions
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int GetKismetLineNumber(this string s, string input)
|
||||
private static int GetKismetLineNumber(this string s, string input)
|
||||
{
|
||||
var match = Regex.Match(input, @"^(.+)\[(\d+)\]$");
|
||||
var match = KismetRegex().Match(input);
|
||||
var name = match.Groups[1].Value;
|
||||
int index = int.Parse(match.Groups[2].Value);
|
||||
var lineToFind = $" \"Name\": \"{name}\",";
|
||||
var offset = $"\"StatementIndex\": {index}";
|
||||
using var reader = new StringReader(s);
|
||||
var lineNum = 0;
|
||||
string line;
|
||||
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
while (reader.ReadLine() is { } line)
|
||||
{
|
||||
lineNum++;
|
||||
if (line.Equals(lineToFind, StringComparison.OrdinalIgnoreCase))
|
||||
|
|
@ -91,7 +91,7 @@ public static class StringExtensions
|
|||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
|
@ -99,8 +99,7 @@ public static class StringExtensions
|
|||
{
|
||||
using var reader = new StringReader(s);
|
||||
var lineNum = 0;
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
while (reader.ReadLine() is { } line)
|
||||
{
|
||||
lineNum++;
|
||||
if (line.Equals(" {"))
|
||||
|
|
@ -110,6 +109,9 @@ public static class StringExtensions
|
|||
return lineNum + 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"^(.+)\[(\d+)\]$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)]
|
||||
private static partial Regex KismetRegex();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@
|
|||
<MenuItem.Header>
|
||||
<TextBlock
|
||||
Text="{Binding DataContext.SelectedItem.Extension,
|
||||
FallbackValue='uasset',
|
||||
FallbackValue='Export Raw Data',
|
||||
StringFormat='Export Raw Data (.{0})',
|
||||
RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
|
||||
</MenuItem.Header>
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public partial class MainWindow
|
|||
#if DEBUG
|
||||
// await _threadWorkerView.Begin(cancellationToken =>
|
||||
// _applicationView.CUE4Parse.Extract(cancellationToken,
|
||||
// "Marvel/Content/Marvel/Characters/1016/1016501/Meshes/SK_1016_1016501.uasset"));
|
||||
// _applicationView.CUE4Parse.Provider["Marvel/Content/Marvel/Characters/1050/1050300/Meshes/SK_1050_1050300_Lobby.uasset"]));
|
||||
// await _threadWorkerView.Begin(cancellationToken =>
|
||||
// _applicationView.CUE4Parse.Extract(cancellationToken,
|
||||
// "RED/Content/Chara/ABA/Costume01/Animation/Charaselect/body/stand_body01.uasset"));
|
||||
|
|
|
|||
|
|
@ -133,17 +133,18 @@ public class CUE4ParseViewModel : ViewModel
|
|||
customVersions: new FCustomVersionContainer(currentDir.Versioning.CustomVersions),
|
||||
optionOverrides: currentDir.Versioning.Options,
|
||||
mapStructTypesOverrides: currentDir.Versioning.MapStructTypes);
|
||||
var pathComparer = StringComparer.OrdinalIgnoreCase;
|
||||
|
||||
switch (gameDirectory)
|
||||
{
|
||||
case Constants._FN_LIVE_TRIGGER:
|
||||
{
|
||||
Provider = new StreamedFileProvider("FortniteLive", true, versionContainer);
|
||||
Provider = new StreamedFileProvider("FortniteLive", versionContainer, pathComparer);
|
||||
break;
|
||||
}
|
||||
case Constants._VAL_LIVE_TRIGGER:
|
||||
{
|
||||
Provider = new StreamedFileProvider("ValorantLive", true, versionContainer);
|
||||
Provider = new StreamedFileProvider("ValorantLive", versionContainer, pathComparer);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -155,12 +156,12 @@ public class CUE4ParseViewModel : ViewModel
|
|||
[
|
||||
new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\Paks"),
|
||||
new(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\StateOfDecay2\\Saved\\DisabledPaks")
|
||||
], SearchOption.AllDirectories, true, versionContainer),
|
||||
], SearchOption.AllDirectories, versionContainer, pathComparer),
|
||||
"eFootball" => new DefaultFileProvider(new DirectoryInfo(gameDirectory),
|
||||
[
|
||||
new(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\KONAMI\\eFootball\\ST\\Download")
|
||||
], SearchOption.AllDirectories, true, versionContainer),
|
||||
_ => new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, true, versionContainer)
|
||||
], SearchOption.AllDirectories, versionContainer, pathComparer),
|
||||
_ => new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, versionContainer, pathComparer)
|
||||
};
|
||||
|
||||
break;
|
||||
|
|
@ -571,16 +572,18 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case "uasset":
|
||||
case "umap":
|
||||
{
|
||||
var pkg = Provider.LoadPackage(entry);
|
||||
var result = Provider.GetLoadPackageResult(entry);
|
||||
TabControl.SelectedTab.TitleExtra = result.TabTitleExtra;
|
||||
|
||||
if (saveProperties || updateUi)
|
||||
{
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(pkg.GetExports(), Formatting.Indented), saveProperties, updateUi);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(result.GetDisplayData(saveProperties), Formatting.Indented), saveProperties, updateUi);
|
||||
if (saveProperties) break; // do not search for viewable exports if we are dealing with jsons
|
||||
}
|
||||
|
||||
for (var i = 0; i < pkg.ExportMapLength; i++)
|
||||
for (var i = result.InclusiveStart; i < result.ExclusiveEnd; i++)
|
||||
{
|
||||
if (CheckExport(cancellationToken, pkg, i, bulk))
|
||||
if (CheckExport(cancellationToken, result.Package, i, bulk))
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -743,13 +746,15 @@ public class CUE4ParseViewModel : ViewModel
|
|||
TabControl.AddTab(entry, parentExportType);
|
||||
TabControl.SelectedTab.ScrollTrigger = objectName;
|
||||
|
||||
var pkg = Provider.LoadPackage(entry);
|
||||
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(""); // json
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(pkg.GetExports(), Formatting.Indented), false, false);
|
||||
var result = Provider.GetLoadPackageResult(entry, objectName);
|
||||
|
||||
for (var i = 0; i < pkg.ExportMapLength; i++)
|
||||
TabControl.SelectedTab.TitleExtra = result.TabTitleExtra;
|
||||
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(""); // json
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(result.GetDisplayData(), Formatting.Indented), false, false);
|
||||
|
||||
for (var i = result.InclusiveStart; i < result.ExclusiveEnd; i++)
|
||||
{
|
||||
if (CheckExport(cancellationToken, pkg, i))
|
||||
if (CheckExport(cancellationToken, result.Package, i))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -907,7 +912,10 @@ public class CUE4ParseViewModel : ViewModel
|
|||
{
|
||||
var package = Provider.LoadPackage(entry);
|
||||
|
||||
TabControl.AddTab($"{entry.Name} (Metadata)");
|
||||
if (TabControl.CanAddTabs) TabControl.AddTab(entry);
|
||||
else TabControl.SelectedTab.SoftReset(entry);
|
||||
|
||||
TabControl.SelectedTab.TitleExtra = "Metadata";
|
||||
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("");
|
||||
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(package, Formatting.Indented), false, false);
|
||||
|
|
|
|||
|
|
@ -14,34 +14,34 @@ public class ImageCommand : ViewModelCommand<TabItem>
|
|||
{
|
||||
}
|
||||
|
||||
public override void Execute(TabItem contextViewModel, object parameter)
|
||||
public override void Execute(TabItem tabViewModel, object parameter)
|
||||
{
|
||||
if (parameter == null || !contextViewModel.HasImage) return;
|
||||
if (parameter == null || !tabViewModel.HasImage) return;
|
||||
|
||||
switch (parameter)
|
||||
{
|
||||
case "Open":
|
||||
{
|
||||
Helper.OpenWindow<AdonisWindow>(contextViewModel.SelectedImage.ExportName + " (Image)", () =>
|
||||
Helper.OpenWindow<AdonisWindow>(tabViewModel.SelectedImage.ExportName + " (Image)", () =>
|
||||
{
|
||||
var popout = new ImagePopout
|
||||
{
|
||||
Title = contextViewModel.SelectedImage.ExportName + " (Image)",
|
||||
Width = contextViewModel.SelectedImage.Image.Width,
|
||||
Height = contextViewModel.SelectedImage.Image.Height,
|
||||
WindowState = contextViewModel.SelectedImage.Image.Height > 1000 ? WindowState.Maximized : WindowState.Normal,
|
||||
ImageCtrl = { Source = contextViewModel.SelectedImage.Image }
|
||||
Title = tabViewModel.SelectedImage.ExportName + " (Image)",
|
||||
Width = tabViewModel.SelectedImage.Image.Width,
|
||||
Height = tabViewModel.SelectedImage.Image.Height,
|
||||
WindowState = tabViewModel.SelectedImage.Image.Height > 1000 ? WindowState.Maximized : WindowState.Normal,
|
||||
ImageCtrl = { Source = tabViewModel.SelectedImage.Image }
|
||||
};
|
||||
RenderOptions.SetBitmapScalingMode(popout.ImageCtrl, BoolToRenderModeConverter.Instance.Convert(contextViewModel.SelectedImage.RenderNearestNeighbor));
|
||||
RenderOptions.SetBitmapScalingMode(popout.ImageCtrl, BoolToRenderModeConverter.Instance.Convert(tabViewModel.SelectedImage.RenderNearestNeighbor));
|
||||
popout.Show();
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "Copy":
|
||||
ClipboardExtensions.SetImage(contextViewModel.SelectedImage.ImageBuffer, $"{contextViewModel.SelectedImage.ExportName}.png");
|
||||
ClipboardExtensions.SetImage(tabViewModel.SelectedImage.ImageBuffer, $"{tabViewModel.SelectedImage.ExportName}.png");
|
||||
break;
|
||||
case "Save":
|
||||
contextViewModel.SaveImage();
|
||||
tabViewModel.SaveImage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public class TabCommand : ViewModelCommand<TabItem>
|
|||
{
|
||||
}
|
||||
|
||||
public override async void Execute(TabItem contextViewModel, object parameter)
|
||||
public override async void Execute(TabItem tabViewModel, object parameter)
|
||||
{
|
||||
switch (parameter)
|
||||
{
|
||||
|
|
@ -23,53 +23,53 @@ public class TabCommand : ViewModelCommand<TabItem>
|
|||
_applicationView.CUE4Parse.TabControl.RemoveTab(mdlClick);
|
||||
break;
|
||||
case "Close_Tab":
|
||||
_applicationView.CUE4Parse.TabControl.RemoveTab(contextViewModel);
|
||||
_applicationView.CUE4Parse.TabControl.RemoveTab(tabViewModel);
|
||||
break;
|
||||
case "Close_All_Tabs":
|
||||
_applicationView.CUE4Parse.TabControl.RemoveAllTabs();
|
||||
break;
|
||||
case "Close_Other_Tabs":
|
||||
_applicationView.CUE4Parse.TabControl.RemoveOtherTabs(contextViewModel);
|
||||
_applicationView.CUE4Parse.TabControl.RemoveOtherTabs(tabViewModel);
|
||||
break;
|
||||
case "Asset_Export_Data":
|
||||
await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.ExportData(contextViewModel.Entry));
|
||||
await _threadWorkerView.Begin(_ => _applicationView.CUE4Parse.ExportData(tabViewModel.Entry));
|
||||
break;
|
||||
case "Asset_Save_Properties":
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Properties);
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Properties);
|
||||
});
|
||||
break;
|
||||
case "Asset_Save_Textures":
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Textures);
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Textures);
|
||||
});
|
||||
break;
|
||||
case "Asset_Save_Models":
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Meshes);
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Meshes);
|
||||
});
|
||||
break;
|
||||
case "Asset_Save_Animations":
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, contextViewModel.Entry, false, EBulkType.Animations);
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken, tabViewModel.Entry, false, EBulkType.Animations);
|
||||
});
|
||||
break;
|
||||
case "Open_Properties":
|
||||
if (contextViewModel.Entry.Name == "New Tab" || contextViewModel.Document == null) return;
|
||||
Helper.OpenWindow<AdonisWindow>(contextViewModel.Entry.Name + " (Properties)", () =>
|
||||
if (tabViewModel.Header == "New Tab" || tabViewModel.Document == null) return;
|
||||
Helper.OpenWindow<AdonisWindow>(tabViewModel.Header + " (Properties)", () =>
|
||||
{
|
||||
new PropertiesPopout(contextViewModel)
|
||||
new PropertiesPopout(tabViewModel)
|
||||
{
|
||||
Title = contextViewModel.Entry.Name + " (Properties)"
|
||||
Title = tabViewModel.Header + " (Properties)"
|
||||
}.Show();
|
||||
});
|
||||
break;
|
||||
case "Copy_Asset_Path":
|
||||
Clipboard.SetText(contextViewModel.Entry.Path);
|
||||
Clipboard.SetText(tabViewModel.Entry.Path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,22 @@ public class TabItem : ViewModel
|
|||
public GameFile Entry
|
||||
{
|
||||
get => _entry;
|
||||
set => SetProperty(ref _entry, value);
|
||||
set
|
||||
{
|
||||
SetProperty(ref _entry, value);
|
||||
RaisePropertyChanged(nameof(Header));
|
||||
}
|
||||
}
|
||||
|
||||
private string _titleExtra;
|
||||
public string TitleExtra
|
||||
{
|
||||
get => _titleExtra;
|
||||
set
|
||||
{
|
||||
SetProperty(ref _titleExtra, value);
|
||||
RaisePropertyChanged(nameof(Header));
|
||||
}
|
||||
}
|
||||
|
||||
private bool _hasSearchOpen;
|
||||
|
|
@ -194,6 +209,8 @@ public class TabItem : ViewModel
|
|||
}
|
||||
}
|
||||
|
||||
public string Header => $"{Entry.Name}{(string.IsNullOrEmpty(TitleExtra) ? "" : $" ({TitleExtra})")}";
|
||||
|
||||
public bool HasImage => SelectedImage != null;
|
||||
public bool HasMultipleImages => _images.Count > 1;
|
||||
public string Page => $"{_images.IndexOf(_selectedImage) + 1} / {_images.Count}";
|
||||
|
|
@ -219,6 +236,7 @@ public class TabItem : ViewModel
|
|||
public void SoftReset(GameFile entry)
|
||||
{
|
||||
Entry = entry;
|
||||
TitleExtra = string.Empty;
|
||||
ParentExportType = string.Empty;
|
||||
ScrollTrigger = null;
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
|
|
@ -389,7 +407,7 @@ public class TabControlViewModel : ViewModel
|
|||
public void AddTab(string title) => AddTab(new FakeGameFile(title));
|
||||
public void AddTab(GameFile entry, string parentExportType = null)
|
||||
{
|
||||
if (SelectedTab?.Entry.Name == "New Tab")
|
||||
if (SelectedTab?.Header == "New Tab")
|
||||
{
|
||||
SelectedTab.Entry = entry;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -70,34 +70,24 @@ public class GamePathVisualLineText : VisualLineText
|
|||
{
|
||||
var obj = gamePath.SubstringAfterLast('.');
|
||||
var package = gamePath.SubstringBeforeLast('.');
|
||||
var fullPath = _applicationView.CUE4Parse.Provider.FixPath(package, StringComparison.Ordinal);
|
||||
var fullPath = _applicationView.CUE4Parse.Provider.FixPath(package);
|
||||
|
||||
var firstLine = a.ParentVisualLine.Document.GetLineByNumber(2);
|
||||
if (a.ParentVisualLine.Document.FileName.Equals(fullPath.SubstringBeforeLast('.'), StringComparison.OrdinalIgnoreCase) &&
|
||||
!a.ParentVisualLine.Document.GetText(firstLine.Offset, firstLine.Length).Equals(" \"Summary\": {")) // Show Metadata case
|
||||
{
|
||||
int lineNumber;
|
||||
DocumentLine line;
|
||||
|
||||
if (Regex.IsMatch(obj, @"^(.+)\[(\d+)\]$"))
|
||||
var lineNumber = a.ParentVisualLine.Document.Text.GetNameLineNumber(obj);
|
||||
if (lineNumber > -1)
|
||||
{
|
||||
lineNumber = a.ParentVisualLine.Document.Text.GetKismetLineNumber(obj);
|
||||
line = a.ParentVisualLine.Document.GetLineByNumber(lineNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
lineNumber = a.ParentVisualLine.Document.Text.GetNameLineNumber(obj);
|
||||
line = a.ParentVisualLine.Document.GetLineByNumber(lineNumber);
|
||||
var line = a.ParentVisualLine.Document.GetLineByNumber(lineNumber);
|
||||
AvalonEditor.YesWeEditor.Select(line.Offset, line.Length);
|
||||
AvalonEditor.YesWeEditor.ScrollToLine(lineNumber);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AvalonEditor.YesWeEditor.Select(line.Offset, line.Length);
|
||||
AvalonEditor.YesWeEditor.ScrollToLine(lineNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
_applicationView.CUE4Parse.ExtractAndScroll(cancellationToken, fullPath, obj, parentExportType));
|
||||
}
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
_applicationView.CUE4Parse.ExtractAndScroll(cancellationToken, fullPath, obj, parentExportType));
|
||||
};
|
||||
return a;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,8 @@ public partial class AvalonEditor
|
|||
if (!tabItem.ShouldScroll) return;
|
||||
|
||||
var lineNumber = avalonEditor.Document.Text.GetNameLineNumber(tabItem.ScrollTrigger);
|
||||
if (lineNumber == -1) lineNumber = 1;
|
||||
|
||||
var line = avalonEditor.Document.GetLineByNumber(lineNumber);
|
||||
avalonEditor.Select(line.Offset, line.Length);
|
||||
avalonEditor.ScrollToLine(lineNumber);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@
|
|||
<controls:MagnifierManager.Magnifier>
|
||||
<controls:Magnifier Radius="150" ZoomFactor=".7" />
|
||||
</controls:MagnifierManager.Magnifier>
|
||||
|
||||
<Image x:Name="ImageCtrl" UseLayoutRounding="True" />
|
||||
|
||||
<Border BorderBrush="#3b3d4a" BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Image x:Name="ImageCtrl" UseLayoutRounding="True" />
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</adonisControls:AdonisWindow>
|
||||
|
|
|
|||
|
|
@ -651,7 +651,7 @@
|
|||
<MouseBinding MouseAction="MiddleClick" Command="{Binding SelectedItem.TabCommand, ElementName=TabControlName}" CommandParameter="{Binding}" />
|
||||
</DockPanel.InputBindings>
|
||||
|
||||
<TextBlock DockPanel.Dock="Left" Text="{Binding Entry.Name}" TextTrimming="CharacterEllipsis" ToolTip="{Binding Entry.Name}">
|
||||
<TextBlock DockPanel.Dock="Left" Text="{Binding Header}" TextTrimming="CharacterEllipsis" ToolTip="{Binding Text, RelativeSource={RelativeSource Self}}">
|
||||
<TextBlock.Width>
|
||||
<MultiBinding Converter="{x:Static converters:TabSizeConverter.Instance}" ConverterParameter="6">
|
||||
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type TabControl}}" />
|
||||
|
|
@ -858,7 +858,7 @@
|
|||
<Separator />
|
||||
<MenuItem Command="{Binding TabCommand}" CommandParameter="Asset_Export_Data">
|
||||
<MenuItem.Header>
|
||||
<TextBlock Text="{Binding Entry.Extension, FallbackValue='uasset', StringFormat='Export Raw Data (.{0})'}" />
|
||||
<TextBlock Text="{Binding Entry.Extension, FallbackValue='Export Raw Data', StringFormat='Export Raw Data (.{0})'}" />
|
||||
</MenuItem.Header>
|
||||
<MenuItem.Icon>
|
||||
<Viewbox Width="16" Height="16">
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@
|
|||
<MenuItem.Header>
|
||||
<TextBlock
|
||||
Text="{Binding DataContext.SelectedItem.Extension,
|
||||
FallbackValue='uasset',
|
||||
FallbackValue='Export Raw Data',
|
||||
StringFormat='Export Raw Data (.{0})',
|
||||
RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
|
||||
</MenuItem.Header>
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@ public class Options
|
|||
{
|
||||
var guid = o.LightingGuid;
|
||||
if (Textures.TryGetValue(guid, out texture)) return texture != null;
|
||||
if (o.Format == EPixelFormat.PF_BC6H) return false; // BC6H is not supported by Decode thus randomly crashes the app
|
||||
|
||||
SKBitmap bitmap = o switch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ public class Material : IDisposable
|
|||
Normals = [new Texture(new FLinearColor(0.5f, 0.5f, 1f, 1f))];
|
||||
SpecularMasks = [new Texture(new FLinearColor(1f, 0.5f, 0.5f, 1f))];
|
||||
Emissive = new Texture[1];
|
||||
DiffuseColor = [Vector4.One];
|
||||
DiffuseColor = FillColors(1, Diffuse, CMaterialParams2.DiffuseColors, Vector4.One);
|
||||
EmissiveColor = [Vector4.One];
|
||||
}
|
||||
else
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user