mirror of
https://github.com/4sval/FModel.git
synced 2026-04-25 07:21:54 -05:00
juno building preview
This commit is contained in:
parent
eb49b3c853
commit
9781446aef
|
|
@ -1 +1 @@
|
||||||
Subproject commit 52292cb88d4de990fbcf6e07fac883e3a8d13d4f
|
Subproject commit 0c12be3c624d0e75b18b0a03915442610de54672
|
||||||
|
|
@ -112,6 +112,7 @@ public class CreatorPackage : IDisposable
|
||||||
case "FortConversionControlItemDefinition":
|
case "FortConversionControlItemDefinition":
|
||||||
case "FortAccountBuffCreditItemDefinition":
|
case "FortAccountBuffCreditItemDefinition":
|
||||||
case "JunoBuildInstructionsItemDefinition":
|
case "JunoBuildInstructionsItemDefinition":
|
||||||
|
case "JunoBuildingSetAccountItemDefinition":
|
||||||
case "FortEventCurrencyItemDefinitionRedir":
|
case "FortEventCurrencyItemDefinitionRedir":
|
||||||
case "FortPersistentResourceItemDefinition":
|
case "FortPersistentResourceItemDefinition":
|
||||||
case "FortWeaponMeleeOffhandItemDefinition":
|
case "FortWeaponMeleeOffhandItemDefinition":
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using ICSharpCode.AvalonEdit.Document;
|
||||||
|
|
||||||
namespace FModel.Extensions;
|
namespace FModel.Extensions;
|
||||||
|
|
||||||
|
|
@ -94,7 +95,7 @@ public static class StringExtensions
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int GetLineNumber(this string s, string lineToFind)
|
public static int GetNameLineNumber(this string s, string lineToFind)
|
||||||
{
|
{
|
||||||
if (int.TryParse(lineToFind, out var index))
|
if (int.TryParse(lineToFind, out var index))
|
||||||
return s.GetLineNumber(index);
|
return s.GetLineNumber(index);
|
||||||
|
|
@ -113,6 +114,24 @@ public static class StringExtensions
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static string GetParentExportType(this TextDocument doc, int startOffset)
|
||||||
|
{
|
||||||
|
var line = doc.GetLineByOffset(startOffset);
|
||||||
|
var lineNumber = line.LineNumber - 1;
|
||||||
|
|
||||||
|
while (doc.GetText(line.Offset, line.Length) is { } content)
|
||||||
|
{
|
||||||
|
if (content.StartsWith(" \"Type\": \"", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return content.Split("\"")[3];
|
||||||
|
|
||||||
|
lineNumber--;
|
||||||
|
line = doc.GetLineByNumber(lineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int GetKismetLineNumber(this string s, string input)
|
public static int GetKismetLineNumber(this string s, string input)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -95,5 +95,5 @@ void main()
|
||||||
fTangent = vec3(transpose(inverse(vInstanceMatrix)) * finalTangent);
|
fTangent = vec3(transpose(inverse(vInstanceMatrix)) * finalTangent);
|
||||||
fTexCoords = vTexCoords;
|
fTexCoords = vTexCoords;
|
||||||
fTexLayer = vTexLayer;
|
fTexLayer = vTexLayer;
|
||||||
fColor = unpackARGB(int(vColor));
|
fColor = unpackARGB(int(vColor)) / 255.0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -609,23 +609,13 @@ public class CUE4ParseViewModel : ViewModel
|
||||||
var fileName = fullPath.SubstringAfterLast('/');
|
var fileName = fullPath.SubstringAfterLast('/');
|
||||||
var ext = fullPath.SubstringAfterLast('.').ToLower();
|
var ext = fullPath.SubstringAfterLast('.').ToLower();
|
||||||
|
|
||||||
if (addNewTab && TabControl.CanAddTabs)
|
if (addNewTab && TabControl.CanAddTabs) TabControl.AddTab(fileName, directory);
|
||||||
{
|
else TabControl.SelectedTab.SoftReset(fileName, directory);
|
||||||
TabControl.AddTab(fileName, directory);
|
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(ext);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TabControl.SelectedTab.Header = fileName;
|
|
||||||
TabControl.SelectedTab.Directory = directory;
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateUi = !HasFlag(bulk, EBulkType.Auto);
|
var updateUi = !HasFlag(bulk, EBulkType.Auto);
|
||||||
var saveProperties = HasFlag(bulk, EBulkType.Properties);
|
var saveProperties = HasFlag(bulk, EBulkType.Properties);
|
||||||
var saveTextures = HasFlag(bulk, EBulkType.Textures);
|
var saveTextures = HasFlag(bulk, EBulkType.Textures);
|
||||||
TabControl.SelectedTab.ClearImages();
|
|
||||||
TabControl.SelectedTab.ResetDocumentText();
|
|
||||||
TabControl.SelectedTab.ScrollTrigger = null;
|
|
||||||
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector(ext);
|
|
||||||
switch (ext)
|
switch (ext)
|
||||||
{
|
{
|
||||||
case "uasset":
|
case "uasset":
|
||||||
|
|
@ -801,10 +791,10 @@ public class CUE4ParseViewModel : ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExtractAndScroll(CancellationToken cancellationToken, string fullPath, string objectName)
|
public void ExtractAndScroll(CancellationToken cancellationToken, string fullPath, string objectName, string parentExportType)
|
||||||
{
|
{
|
||||||
Log.Information("User CTRL-CLICKED to extract '{FullPath}'", fullPath);
|
Log.Information("User CTRL-CLICKED to extract '{FullPath}'", fullPath);
|
||||||
TabControl.AddTab(fullPath.SubstringAfterLast('/'), fullPath.SubstringBeforeLast('/'));
|
TabControl.AddTab(fullPath.SubstringAfterLast('/'), fullPath.SubstringBeforeLast('/'), parentExportType);
|
||||||
TabControl.SelectedTab.ScrollTrigger = objectName;
|
TabControl.SelectedTab.ScrollTrigger = objectName;
|
||||||
|
|
||||||
var exports = Provider.LoadAllObjects(fullPath);
|
var exports = Provider.LoadAllObjects(fullPath);
|
||||||
|
|
@ -855,6 +845,12 @@ public class CUE4ParseViewModel : ViewModel
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case UWorld when isNone && UserSettings.Default.PreviewWorlds:
|
case UWorld when isNone && UserSettings.Default.PreviewWorlds:
|
||||||
|
case UBlueprintGeneratedClass when isNone && UserSettings.Default.PreviewWorlds && TabControl.SelectedTab.ParentExportType switch
|
||||||
|
{
|
||||||
|
"JunoBuildInstructionsItemDefinition" => true,
|
||||||
|
"JunoBuildingSetAccountItemDefinition" => true,
|
||||||
|
_ => false
|
||||||
|
}:
|
||||||
case UAtomModel when isNone && UserSettings.Default.PreviewStaticMeshes:
|
case UAtomModel when isNone && UserSettings.Default.PreviewStaticMeshes:
|
||||||
case UStaticMesh when isNone && UserSettings.Default.PreviewStaticMeshes:
|
case UStaticMesh when isNone && UserSettings.Default.PreviewStaticMeshes:
|
||||||
case USkeletalMesh when isNone && UserSettings.Default.PreviewSkeletalMeshes:
|
case USkeletalMesh when isNone && UserSettings.Default.PreviewSkeletalMeshes:
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,8 @@ public class TabImage : ViewModel
|
||||||
|
|
||||||
public class TabItem : ViewModel
|
public class TabItem : ViewModel
|
||||||
{
|
{
|
||||||
|
public string ParentExportType { get; private set; }
|
||||||
|
|
||||||
private string _header;
|
private string _header;
|
||||||
public string Header
|
public string Header
|
||||||
{
|
{
|
||||||
|
|
@ -211,20 +213,28 @@ public class TabItem : ViewModel
|
||||||
private GoToCommand _goToCommand;
|
private GoToCommand _goToCommand;
|
||||||
public GoToCommand GoToCommand => _goToCommand ??= new GoToCommand(null);
|
public GoToCommand GoToCommand => _goToCommand ??= new GoToCommand(null);
|
||||||
|
|
||||||
public TabItem(string header, string directory)
|
public TabItem(string header, string directory, string parentExportType)
|
||||||
{
|
{
|
||||||
Header = header;
|
Header = header;
|
||||||
Directory = directory;
|
Directory = directory;
|
||||||
|
ParentExportType = parentExportType;
|
||||||
_images = new ObservableCollection<TabImage>();
|
_images = new ObservableCollection<TabImage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearImages()
|
public void SoftReset(string header, string directory)
|
||||||
{
|
{
|
||||||
|
Header = header;
|
||||||
|
Directory = directory;
|
||||||
|
ParentExportType = string.Empty;
|
||||||
|
ScrollTrigger = null;
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
_images.Clear();
|
_images.Clear();
|
||||||
SelectedImage = null;
|
SelectedImage = null;
|
||||||
RaisePropertyChanged("HasMultipleImages");
|
RaisePropertyChanged("HasMultipleImages");
|
||||||
|
|
||||||
|
Document ??= new TextDocument();
|
||||||
|
Document.Text = string.Empty;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -274,15 +284,6 @@ public class TabItem : ViewModel
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetDocumentText()
|
|
||||||
{
|
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
|
||||||
{
|
|
||||||
Document ??= new TextDocument();
|
|
||||||
Document.Text = string.Empty;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveImage() => SaveImage(SelectedImage, true);
|
public void SaveImage() => SaveImage(SelectedImage, true);
|
||||||
private void SaveImage(TabImage image, bool updateUi)
|
private void SaveImage(TabImage image, bool updateUi)
|
||||||
{
|
{
|
||||||
|
|
@ -368,12 +369,13 @@ public class TabControlViewModel : ViewModel
|
||||||
SelectedTab = TabsItems.FirstOrDefault();
|
SelectedTab = TabsItems.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddTab(string header = null, string directory = null)
|
public void AddTab(string header = null, string directory = null, string parentExportType = null)
|
||||||
{
|
{
|
||||||
if (!CanAddTabs) return;
|
if (!CanAddTabs) return;
|
||||||
|
|
||||||
var h = header ?? "New Tab";
|
var h = header ?? "New Tab";
|
||||||
var d = directory ?? string.Empty;
|
var d = directory ?? string.Empty;
|
||||||
|
var p = parentExportType ?? string.Empty;
|
||||||
if (SelectedTab is { Header : "New Tab" })
|
if (SelectedTab is { Header : "New Tab" })
|
||||||
{
|
{
|
||||||
SelectedTab.Header = h;
|
SelectedTab.Header = h;
|
||||||
|
|
@ -383,7 +385,7 @@ public class TabControlViewModel : ViewModel
|
||||||
|
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
_tabItems.Add(new TabItem(h, d));
|
_tabItems.Add(new TabItem(h, d, p));
|
||||||
SelectedTab = _tabItems.Last();
|
SelectedTab = _tabItems.Last();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -445,6 +447,6 @@ public class TabControlViewModel : ViewModel
|
||||||
|
|
||||||
private static IEnumerable<TabItem> EnumerateTabs()
|
private static IEnumerable<TabItem> EnumerateTabs()
|
||||||
{
|
{
|
||||||
yield return new TabItem("New Tab", string.Empty);
|
yield return new TabItem("New Tab", string.Empty, string.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using FModel.Extensions;
|
||||||
using ICSharpCode.AvalonEdit.Rendering;
|
using ICSharpCode.AvalonEdit.Rendering;
|
||||||
|
|
||||||
namespace FModel.Views.Resources.Controls;
|
namespace FModel.Views.Resources.Controls;
|
||||||
|
|
@ -29,8 +30,10 @@ public class GamePathElementGenerator : VisualLineElementGenerator
|
||||||
public override VisualLineElement ConstructElement(int offset)
|
public override VisualLineElement ConstructElement(int offset)
|
||||||
{
|
{
|
||||||
var m = FindMatch(offset);
|
var m = FindMatch(offset);
|
||||||
if (!m.Success || m.Index != 0) return null;
|
if (!m.Success || m.Index != 0 ||
|
||||||
|
!m.Groups.TryGetValue("target", out var g)) return null;
|
||||||
|
|
||||||
return m.Groups.TryGetValue("target", out var g) ? new GamePathVisualLineText(g.Value, CurrentContext.VisualLine, g.Length + g.Index + 1) : null;
|
var parentExportType = CurrentContext.Document.GetParentExportType(offset);
|
||||||
|
return new GamePathVisualLineText(g.Value, parentExportType, CurrentContext.VisualLine, g.Length + g.Index + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,16 @@ public class GamePathVisualLineText : VisualLineText
|
||||||
private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView;
|
private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView;
|
||||||
private ApplicationViewModel _applicationView => ApplicationService.ApplicationView;
|
private ApplicationViewModel _applicationView => ApplicationService.ApplicationView;
|
||||||
|
|
||||||
public delegate void GamePathOnClick(string gamePath);
|
public delegate void GamePathOnClick(string gamePath, string parentExportType);
|
||||||
|
|
||||||
public event GamePathOnClick OnGamePathClicked;
|
public event GamePathOnClick OnGamePathClicked;
|
||||||
private readonly string _gamePath;
|
private readonly string _gamePath;
|
||||||
|
private readonly string _parentExportType;
|
||||||
|
|
||||||
public GamePathVisualLineText(string gamePath, VisualLine parentVisualLine, int length) : base(parentVisualLine, length)
|
public GamePathVisualLineText(string gamePath, string parentExportType, VisualLine parentVisualLine, int length) : base(parentVisualLine, length)
|
||||||
{
|
{
|
||||||
_gamePath = gamePath;
|
_gamePath = gamePath;
|
||||||
|
_parentExportType = parentExportType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TextRun CreateTextRun(int startVisualColumn, ITextRunConstructionContext context)
|
public override TextRun CreateTextRun(int startVisualColumn, ITextRunConstructionContext context)
|
||||||
|
|
@ -56,14 +58,14 @@ public class GamePathVisualLineText : VisualLineText
|
||||||
if (e.Handled || OnGamePathClicked == null)
|
if (e.Handled || OnGamePathClicked == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OnGamePathClicked(_gamePath);
|
OnGamePathClicked(_gamePath, _parentExportType);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override VisualLineText CreateInstance(int length)
|
protected override VisualLineText CreateInstance(int length)
|
||||||
{
|
{
|
||||||
var a = new GamePathVisualLineText(_gamePath, ParentVisualLine, length);
|
var a = new GamePathVisualLineText(_gamePath, _parentExportType, ParentVisualLine, length);
|
||||||
a.OnGamePathClicked += async gamePath =>
|
a.OnGamePathClicked += async (gamePath, parentExportType) =>
|
||||||
{
|
{
|
||||||
var obj = gamePath.SubstringAfterLast('.');
|
var obj = gamePath.SubstringAfterLast('.');
|
||||||
var package = gamePath.SubstringBeforeLast('.');
|
var package = gamePath.SubstringBeforeLast('.');
|
||||||
|
|
@ -80,17 +82,17 @@ public class GamePathVisualLineText : VisualLineText
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lineNumber = a.ParentVisualLine.Document.Text.GetLineNumber(obj);
|
lineNumber = a.ParentVisualLine.Document.Text.GetNameLineNumber(obj);
|
||||||
line = a.ParentVisualLine.Document.GetLineByNumber(lineNumber);
|
line = a.ParentVisualLine.Document.GetLineByNumber(lineNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
AvalonEditor.YesWeEditor.Select(line.Offset, line.Length);
|
AvalonEditor.YesWeEditor.Select(line.Offset, line.Length);
|
||||||
AvalonEditor.YesWeEditor.ScrollToLine(lineNumber);
|
AvalonEditor.YesWeEditor.ScrollToLine(lineNumber);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _threadWorkerView.Begin(cancellationToken =>
|
await _threadWorkerView.Begin(cancellationToken =>
|
||||||
_applicationView.CUE4Parse.ExtractAndScroll(cancellationToken, fullPath, obj));
|
_applicationView.CUE4Parse.ExtractAndScroll(cancellationToken, fullPath, obj, parentExportType));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return a;
|
return a;
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ public partial class AvalonEditor
|
||||||
|
|
||||||
if (!tabItem.ShouldScroll) return;
|
if (!tabItem.ShouldScroll) return;
|
||||||
|
|
||||||
var lineNumber = avalonEditor.Document.Text.GetLineNumber(tabItem.ScrollTrigger);
|
var lineNumber = avalonEditor.Document.Text.GetNameLineNumber(tabItem.ScrollTrigger);
|
||||||
var line = avalonEditor.Document.GetLineByNumber(lineNumber);
|
var line = avalonEditor.Document.GetLineByNumber(lineNumber);
|
||||||
avalonEditor.Select(line.Offset, line.Length);
|
avalonEditor.Select(line.Offset, line.Length);
|
||||||
avalonEditor.ScrollToLine(lineNumber);
|
avalonEditor.ScrollToLine(lineNumber);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
@ -9,6 +10,7 @@ using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Animation;
|
using CUE4Parse.UE4.Assets.Exports.Animation;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Atom;
|
using CUE4Parse.UE4.Assets.Exports.Atom;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Component.StaticMesh;
|
using CUE4Parse.UE4.Assets.Exports.Component.StaticMesh;
|
||||||
|
using CUE4Parse.UE4.Assets.Exports.GeometryCollection;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
||||||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||||
|
|
@ -79,8 +81,8 @@ public class Renderer : IDisposable
|
||||||
public void Load(CancellationToken cancellationToken, UObject export)
|
public void Load(CancellationToken cancellationToken, UObject export)
|
||||||
{
|
{
|
||||||
ShowLights = false;
|
ShowLights = false;
|
||||||
_saveCameraMode = export is not UWorld;
|
Color = VertexColor.Default;
|
||||||
CameraOp.Mode = _saveCameraMode ? UserSettings.Default.CameraMode : Camera.WorldMode.FlyCam;
|
_saveCameraMode = export is not UWorld and not UBlueprintGeneratedClass;
|
||||||
switch (export)
|
switch (export)
|
||||||
{
|
{
|
||||||
case UStaticMesh st:
|
case UStaticMesh st:
|
||||||
|
|
@ -98,10 +100,15 @@ public class Renderer : IDisposable
|
||||||
case UWorld wd:
|
case UWorld wd:
|
||||||
LoadWorld(cancellationToken, wd, Transform.Identity);
|
LoadWorld(cancellationToken, wd, Transform.Identity);
|
||||||
break;
|
break;
|
||||||
|
case UBlueprintGeneratedClass bp:
|
||||||
|
LoadJunoWorld(cancellationToken, bp, Transform.Identity);
|
||||||
|
Color = VertexColor.Colors;
|
||||||
|
break;
|
||||||
case UAtomModel at:
|
case UAtomModel at:
|
||||||
LoadAtom(cancellationToken, at);
|
LoadAtom(cancellationToken, at);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
CameraOp.Mode = _saveCameraMode ? UserSettings.Default.CameraMode : Camera.WorldMode.FlyCam;
|
||||||
SetupCamera();
|
SetupCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -433,6 +440,49 @@ public class Renderer : IDisposable
|
||||||
Services.ApplicationService.ApplicationView.Status.UpdateStatusLabel($"{original.Name} ... {length}/{length}");
|
Services.ApplicationService.ApplicationView.Status.UpdateStatusLabel($"{original.Name} ... {length}/{length}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LoadJunoWorld(CancellationToken cancellationToken, UBlueprintGeneratedClass original, Transform transform)
|
||||||
|
{
|
||||||
|
CameraOp.Setup(new FBox(FVector.ZeroVector, new FVector(0, 10, 10)));
|
||||||
|
|
||||||
|
var length = 0;
|
||||||
|
FPackageIndex[] allNodes = [];
|
||||||
|
IPropertyHolder[] records = [];
|
||||||
|
if (original.TryGetValue(out FPackageIndex simpleConstructionScript, "SimpleConstructionScript") &&
|
||||||
|
simpleConstructionScript.TryLoad(out var scs) && scs.TryGetValue(out allNodes, "AllNodes"))
|
||||||
|
length = allNodes.Length;
|
||||||
|
else if (original.TryGetValue(out FPackageIndex inheritableComponentHandler, "InheritableComponentHandler") &&
|
||||||
|
inheritableComponentHandler.TryLoad(out var ich) && ich.TryGetValue(out records, "Records"))
|
||||||
|
length = records.Length;
|
||||||
|
|
||||||
|
for (var i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
IPropertyHolder actor;
|
||||||
|
if (allNodes is {Length: > 0} && allNodes[i].TryLoad(out UObject node))
|
||||||
|
{
|
||||||
|
actor = node;
|
||||||
|
}
|
||||||
|
else if (records is {Length: > 0})
|
||||||
|
{
|
||||||
|
actor = records[i];
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
|
||||||
|
Services.ApplicationService.ApplicationView.Status.UpdateStatusLabel($"{original.Name} ... {i}/{length}");
|
||||||
|
WorldMesh(actor, transform, true);
|
||||||
|
}
|
||||||
|
Services.ApplicationService.ApplicationView.Status.UpdateStatusLabel($"{original.Name} ... {length}/{length}");
|
||||||
|
|
||||||
|
if (Options.Models.Count == 1)
|
||||||
|
{
|
||||||
|
var (guid, model) = Options.Models.First();
|
||||||
|
Options.SelectModel(guid);
|
||||||
|
CameraOp.Setup(model.Box);
|
||||||
|
_saveCameraMode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void WorldCamera(UObject actor)
|
private void WorldCamera(UObject actor)
|
||||||
{
|
{
|
||||||
if (actor.ExportType != "LevelBounds" || !actor.TryGetValue(out FPackageIndex boxComponent, "BoxComponent") ||
|
if (actor.ExportType != "LevelBounds" || !actor.TryGetValue(out FPackageIndex boxComponent, "BoxComponent") ||
|
||||||
|
|
@ -463,7 +513,7 @@ public class Renderer : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WorldMesh(UObject actor, Transform transform)
|
private void WorldMesh(IPropertyHolder actor, Transform transform, bool forceShow = false)
|
||||||
{
|
{
|
||||||
if (actor.TryGetValue(out FPackageIndex[] instanceComponents, "InstanceComponents"))
|
if (actor.TryGetValue(out FPackageIndex[] instanceComponents, "InstanceComponents"))
|
||||||
{
|
{
|
||||||
|
|
@ -491,7 +541,24 @@ public class Renderer : IDisposable
|
||||||
else ProcessMesh(actor, staticMeshComp, m, CalculateTransform(staticMeshComp, transform));
|
else ProcessMesh(actor, staticMeshComp, m, CalculateTransform(staticMeshComp, transform));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (actor.TryGetValue(out FPackageIndex staticMeshComponent, "StaticMeshComponent", "StaticMesh", "Mesh", "LightMesh") &&
|
else if (actor.TryGetValue(out FPackageIndex componentTemplate, "ComponentTemplate") &&
|
||||||
|
componentTemplate.TryLoad(out UObject compTemplate))
|
||||||
|
{
|
||||||
|
UGeometryCollection geometryCollection = null;
|
||||||
|
if (!compTemplate.TryGetValue(out UStaticMesh m, "StaticMesh") &&
|
||||||
|
compTemplate.TryGetValue(out FPackageIndex restCollection, "RestCollection") &&
|
||||||
|
restCollection.TryLoad(out geometryCollection) && geometryCollection.RootProxyData is { ProxyMeshes.Length: > 0 } rootProxyData)
|
||||||
|
{
|
||||||
|
rootProxyData.ProxyMeshes[0].TryLoad(out m);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m is { Materials.Length: > 0 })
|
||||||
|
{
|
||||||
|
OverrideJunoVertexColors(m, geometryCollection);
|
||||||
|
ProcessMesh(actor, compTemplate, m, CalculateTransform(compTemplate, transform), forceShow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (actor.TryGetValue(out FPackageIndex staticMeshComponent, "StaticMeshComponent", "ComponentTemplate", "StaticMesh", "Mesh", "LightMesh") &&
|
||||||
staticMeshComponent.TryLoad(out UStaticMeshComponent staticMeshComp) &&
|
staticMeshComponent.TryLoad(out UStaticMeshComponent staticMeshComp) &&
|
||||||
staticMeshComp.GetStaticMesh().TryLoad(out UStaticMesh m) && m.Materials.Length > 0)
|
staticMeshComp.GetStaticMesh().TryLoad(out UStaticMesh m) && m.Materials.Length > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -499,11 +566,14 @@ public class Renderer : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessMesh(UObject actor, UStaticMeshComponent staticMeshComp, UStaticMesh m, Transform transform)
|
private void ProcessMesh(IPropertyHolder actor, UStaticMeshComponent staticMeshComp, UStaticMesh m, Transform transform)
|
||||||
|
{
|
||||||
|
OverrideVertexColors(staticMeshComp, m);
|
||||||
|
ProcessMesh(actor, staticMeshComp, m, transform, false);
|
||||||
|
}
|
||||||
|
private void ProcessMesh(IPropertyHolder actor, UObject staticMeshComp, UStaticMesh m, Transform transform, bool forceShow)
|
||||||
{
|
{
|
||||||
var guid = m.LightingGuid;
|
var guid = m.LightingGuid;
|
||||||
|
|
||||||
OverrideVertexColors(staticMeshComp, m);
|
|
||||||
if (Options.TryGetModel(guid, out var model))
|
if (Options.TryGetModel(guid, out var model))
|
||||||
{
|
{
|
||||||
model.AddInstance(transform);
|
model.AddInstance(transform);
|
||||||
|
|
@ -561,6 +631,13 @@ public class Renderer : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (forceShow)
|
||||||
|
{
|
||||||
|
foreach (var section in model.Sections)
|
||||||
|
{
|
||||||
|
section.Show = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Options.Models[guid] = model;
|
Options.Models[guid] = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -576,7 +653,7 @@ public class Renderer : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Transform CalculateTransform(UStaticMeshComponent staticMeshComp, Transform relation)
|
private Transform CalculateTransform(IPropertyHolder staticMeshComp, Transform relation)
|
||||||
{
|
{
|
||||||
return new Transform
|
return new Transform
|
||||||
{
|
{
|
||||||
|
|
@ -587,6 +664,60 @@ public class Renderer : IDisposable
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OverrideJunoVertexColors(UStaticMesh staticMesh, UGeometryCollection geometryCollection = null)
|
||||||
|
{
|
||||||
|
if (staticMesh.RenderData is not { LODs.Length: > 0 } || staticMesh.RenderData.LODs[0].ColorVertexBuffer == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var dico = new Dictionary<byte, FColor>();
|
||||||
|
if (geometryCollection?.Materials is not { Length: > 0 })
|
||||||
|
{
|
||||||
|
var distinctReds = new HashSet<byte>();
|
||||||
|
for (int i = 0; i < staticMesh.RenderData.LODs[0].ColorVertexBuffer.Data.Length; i++)
|
||||||
|
{
|
||||||
|
ref var vertexColor = ref staticMesh.RenderData.LODs[0].ColorVertexBuffer.Data[i];
|
||||||
|
var indexAsByte = vertexColor.R;
|
||||||
|
if (vertexColor.R == 255) indexAsByte = vertexColor.A;
|
||||||
|
distinctReds.Add(indexAsByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var indexAsByte in distinctReds)
|
||||||
|
{
|
||||||
|
var path = string.Concat("/JunoAtomAssets/Materials/MI_LegoStandard_", indexAsByte, ".MI_LegoStandard_", indexAsByte);
|
||||||
|
if (!Utils.TryLoadObject(path, out UMaterialInterface unrealMaterial))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var parameters = new CMaterialParams2();
|
||||||
|
unrealMaterial.GetParams(parameters, EMaterialFormat.FirstLayer);
|
||||||
|
|
||||||
|
if (!parameters.TryGetLinearColor(out var color, "Color"))
|
||||||
|
color = FLinearColor.Gray;
|
||||||
|
|
||||||
|
dico[indexAsByte] = color.ToFColor(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else foreach (var material in geometryCollection.Materials)
|
||||||
|
{
|
||||||
|
if (!material.TryLoad(out UMaterialInterface unrealMaterial)) continue;
|
||||||
|
|
||||||
|
var parameters = new CMaterialParams2();
|
||||||
|
unrealMaterial.GetParams(parameters, EMaterialFormat.FirstLayer);
|
||||||
|
|
||||||
|
if (!byte.TryParse(material.Name.SubstringAfterLast("_"), out var indexAsByte))
|
||||||
|
indexAsByte = byte.MaxValue;
|
||||||
|
if (!parameters.TryGetLinearColor(out var color, "Color"))
|
||||||
|
color = FLinearColor.Gray;
|
||||||
|
|
||||||
|
dico[indexAsByte] = color.ToFColor(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < staticMesh.RenderData.LODs[0].ColorVertexBuffer.Data.Length; i++)
|
||||||
|
{
|
||||||
|
ref var vertexColor = ref staticMesh.RenderData.LODs[0].ColorVertexBuffer.Data[i];
|
||||||
|
vertexColor = dico.TryGetValue(vertexColor.R, out var color) ? color : FColor.Gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OverrideVertexColors(UStaticMeshComponent staticMeshComp, UStaticMesh staticMesh)
|
private void OverrideVertexColors(UStaticMeshComponent staticMeshComp, UStaticMesh staticMesh)
|
||||||
{
|
{
|
||||||
if (staticMeshComp.LODData is not { Length: > 0 } || staticMesh.RenderData is not { LODs.Length: > 0 })
|
if (staticMeshComp.LODData is not { Length: > 0 } || staticMesh.RenderData is not { LODs.Length: > 0 })
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,8 @@ public class Material : IDisposable
|
||||||
|
|
||||||
if (uvCount < 1 || Parameters.IsNull)
|
if (uvCount < 1 || Parameters.IsNull)
|
||||||
{
|
{
|
||||||
Diffuse = [new Texture(new FLinearColor(.6f, .6f, .6f, 1f))];
|
Diffuse = [new Texture(FLinearColor.Gray)];
|
||||||
Normals = [new Texture(new FLinearColor(0.498f, 0.498f, 0.996f, 1f))];
|
Normals = [new Texture(new FLinearColor(0.5f, 0.5f, 1f, 1f))];
|
||||||
SpecularMasks = [new Texture(new FLinearColor(1f, 0.5f, 0.5f, 1f))];
|
SpecularMasks = [new Texture(new FLinearColor(1f, 0.5f, 0.5f, 1f))];
|
||||||
Emissive = new Texture[1];
|
Emissive = new Texture[1];
|
||||||
DiffuseColor = [Vector4.One];
|
DiffuseColor = [Vector4.One];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user