UE6 / The Finals / Rogue Company fixes + UGeometryCollection preview/export + UEFormat v10

Co-authored-by: Asval <asval.contactme@gmail.com>
This commit is contained in:
Chompster86
2026-08-21 15:26:56 -04:00
committed by GitHub
parent 773bbd9dc3
commit 46ab528421
8 changed files with 55 additions and 9 deletions

View File

@@ -32,6 +32,7 @@ public class BaseIcon : UCreator
// rarity
if (Object.TryGetValue(out FPackageIndex series, "Series")) GetSeries(series);
else if (Object.TryGetValue(out FStructFallback componentContainer, "ComponentContainer")) GetSeries(componentContainer);
else if (Object.TryGetValue(out EFortRarity hackRarity, "HackRarity")) GetRarity(hackRarity);
else GetRarity(Object.GetOrDefault("Rarity", EFortRarity.Uncommon)); // default is uncommon
if (Object.TryGetValue(out FInstancedStruct[] dataList, "DataList"))
@@ -48,7 +49,7 @@ public class BaseIcon : UCreator
Preview = preview;
else if (Object.TryGetValue(out FPackageIndex itemDefinition, "HeroDefinition", "WeaponDefinition"))
Preview = Utils.GetBitmap(itemDefinition);
else if (Object.TryGetValue(out FSoftObjectPath largePreview, "LargePreviewImage", "EntryListIcon", "SmallPreviewImage", "BundleImage", "ItemDisplayAsset", "LargeIcon", "ToastIcon", "SmallIcon"))
else if (Object.TryGetValue(out FSoftObjectPath largePreview, "LargePreviewImage", "EntryListIcon", "SmallPreviewImage", "BundleImage", "ItemDisplayAsset", "LargeIcon", "ToastIcon", "SmallIcon", "CartridgeIcon", "EffectIcon"))
Preview = Utils.GetBitmap(largePreview);
else if (Object.TryGetValue(out string s, "LargePreviewImage") && !string.IsNullOrEmpty(s))
Preview = Utils.GetBitmap(s);
@@ -66,9 +67,9 @@ public class BaseIcon : UCreator
}
// text
if (Object.TryGetValue(out FText displayName, "DisplayName", "ItemName", "BundleName", "DefaultHeaderText", "UIDisplayName", "EntryName", "EventCalloutTitle"))
if (Object.TryGetValue(out FText displayName, "DisplayName", "ItemName", "BundleName", "DefaultHeaderText", "UIDisplayName", "EntryName", "EventCalloutTitle", "KeyName", "HackDisplayName"))
DisplayName = displayName.Text;
if (Object.TryGetValue(out FText description, "Description", "ItemDescription", "SetDescription", "BundleDescription", "GeneralDescription", "DefaultBodyText", "UIDescription", "UIDisplayDescription", "EntryDescription", "EventCalloutDescription"))
if (Object.TryGetValue(out FText description, "Description", "ItemDescription", "SetDescription", "BundleDescription", "GeneralDescription", "DefaultBodyText", "UIDescription", "UIDisplayDescription", "EntryDescription", "EventCalloutDescription", "KeyDescription", "HackDescription"))
Description = description.Text;
else if (Object.TryGetValue(out FText[] descriptions, "Description"))
Description = string.Join('\n', descriptions.Select(x => x.Text));

View File

@@ -65,6 +65,7 @@ public class CreatorPackage : IDisposable
case "AthenaEmojiItemDefinition":
case "AthenaItemWrapDefinition":
case "AthenaToyItemDefinition":
case "FortHackData":
case "FortHeroType":
case "FortTokenType":
case "FortAbilityKit":
@@ -72,7 +73,9 @@ public class CreatorPackage : IDisposable
case "FortMissionInfo":
case "RewardGraphToken":
case "JunoKnowledgeBundle":
case "FortHackDataMinimal":
case "FortBannerTokenType":
case "FortHackKeyCoreData":
case "FortVariantTokenType":
case "FortDecoItemDefinition":
case "FortStatItemDefinition":
@@ -88,6 +91,7 @@ public class CreatorPackage : IDisposable
case "SparksBassItemDefinition":
case "FortGadgetItemDefinition":
case "AthenaCharmItemDefinition":
case "FortHackKeyItemDefinition":
case "FortPlaysetItemDefinition":
case "FortGiftBoxItemDefinition":
case "FortOutpostItemDefinition":
@@ -124,6 +128,7 @@ public class CreatorPackage : IDisposable
case "JunoRecipeBundleItemDefinition":
case "FortHomebaseNodeItemDefinition":
case "FortNeverPersistItemDefinition":
case "FortHackCartridgeItemDefinition":
case "FortPlayerAugmentItemDefinition":
case "FortSmartBuildingItemDefinition":
case "FortGiftBoxUnlockItemDefinition":

View File

@@ -69,6 +69,7 @@ using CUE4Parse.UE4.Wwise;
using CUE4Parse.Utils;
using CUE4Parse_Conversion.Exporters;
using CUE4Parse_Conversion.Sounds;
using CUE4Parse.UE4.Assets.Exports.GeometryCollection;
using EpicManifestParser;
using EpicManifestParser.UE;
using FModel.Creator;
@@ -1561,6 +1562,7 @@ public class CUE4ParseViewModel : ViewModel
// }:
case UPaperSprite when isNone && UserSettings.Default.PreviewMaterials:
case UStaticMesh when isNone && UserSettings.Default.PreviewStaticMeshes:
case UGeometryCollection when isNone && UserSettings.Default.PreviewStaticMeshes:
case USkeletalMesh when isNone && UserSettings.Default.PreviewSkeletalMeshes:
case USkeleton when isNone && UserSettings.Default.SaveSkeletonAsMesh:
case UMaterialInstance when isNone && UserSettings.Default.PreviewMaterials && !ModelIsOverwritingMaterial &&
@@ -1587,6 +1589,7 @@ public class CUE4ParseViewModel : ViewModel
return true;
}
case UStaticMesh when HasFlag(bulk, EBulkType.Meshes):
case UGeometryCollection when HasFlag(bulk, EBulkType.Meshes):
case USkeletalMesh when HasFlag(bulk, EBulkType.Meshes):
case USkeleton when UserSettings.Default.SaveSkeletonAsMesh && HasFlag(bulk, EBulkType.Meshes):
// case UMaterialInterface when HasFlag(bulk, EBulkType.Materials):

View File

@@ -219,7 +219,7 @@ public class GameFileViewModel(GameFile asset) : ViewModel
USkeletalMesh => (EAssetCategory.SkeletalMesh, EBulkType.Meshes),
UCustomizableObject => (EAssetCategory.CustomizableObject, EBulkType.None),
UNaniteDisplacedMesh => (EAssetCategory.NaniteDisplacedMesh, EBulkType.None),
UGeometryCollection => (EAssetCategory.GeometryCollection, EBulkType.None),
UGeometryCollection => (EAssetCategory.GeometryCollection, EBulkType.Meshes),
UTexture => (EAssetCategory.Texture, EBulkType.Textures),

View File

@@ -196,8 +196,8 @@ public class GameSelectorViewModel : ViewModel
.OrderBy(value => ((int)value & 0xFF) == 0);
private IEnumerable<DirectorySettings> EnumerateDetectedGames()
{
yield return GetUnrealEngineGame("Fortnite", "\\FortniteGame\\Content\\Paks", EGame.GAME_UE5_8);
yield return DirectorySettings.Default("Fortnite [LIVE]", Constants._FN_LIVE_TRIGGER, ue: EGame.GAME_UE5_8);
yield return GetUnrealEngineGame("Fortnite", "\\FortniteGame\\Content\\Paks", EGame.GAME_UE6_0);
yield return DirectorySettings.Default("Fortnite [LIVE]", Constants._FN_LIVE_TRIGGER, ue: EGame.GAME_UE6_0);
yield return GetUnrealEngineGame("Pewee", "\\RogueCompany\\Content\\Paks", EGame.GAME_RogueCompany);
yield return GetUnrealEngineGame("Rosemallow", "\\Indiana\\Content\\Paks", EGame.GAME_UE4_21);
yield return GetUnrealEngineGame("Catnip", "\\OakGame\\Content\\Paks", EGame.GAME_Borderlands3);

View File

@@ -1,6 +1,7 @@
using System;
using System.Numerics;
using CUE4Parse_Conversion.Dto;
using CUE4Parse.UE4.Assets.Exports.GeometryCollection;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
using CUE4Parse.UE4.Assets.Exports.Texture;
@@ -143,6 +144,12 @@ public class StaticModel : UModel<MeshVertex>
}
}
public StaticModel(UGeometryCollection export, StaticMeshDto staticMesh, Transform transform = null)
: base(export, staticMesh.LODs[LodLevel], export.Materials, staticMesh.LODs[LodLevel].Vertices, staticMesh.LODs.Count, transform)
{
Box = staticMesh.Bounds * Constants.SCALE_DOWN_RATIO;
}
public override void RenderCollision(Shader shader)
{
base.RenderCollision(shader);

View File

@@ -5,6 +5,7 @@ using System.Numerics;
using System.Threading;
using System.Windows;
using CUE4Parse_Conversion.Animations;
using CUE4Parse_Conversion.Dto;
using CUE4Parse_Conversion.Meshes;
using CUE4Parse_Conversion.Options;
using CUE4Parse.UE4.Assets.Exports;
@@ -29,6 +30,7 @@ using FModel.Views.Snooper.Lights;
using FModel.Views.Snooper.Models;
using FModel.Views.Snooper.Shading;
using OpenTK.Windowing.GraphicsLibraryFramework;
using Serilog;
namespace FModel.Views.Snooper;
@@ -88,6 +90,9 @@ public class Renderer : IDisposable
case UStaticMesh when export.Value is UStaticMesh st:
LoadStaticMesh(st, UserSettings.Default.NaniteMeshExportFormat);
break;
case UGeometryCollection when export.Value is UGeometryCollection gc:
LoadStaticMesh(gc, UserSettings.Default.NaniteMeshExportFormat);
break;
case USkeletalMesh when export.Value is USkeletalMesh sk:
LoadSkeletalMesh(sk);
break;
@@ -132,7 +137,7 @@ public class Renderer : IDisposable
{
// do nothing, selected model has the correct skeleton for this animation
}
else */if (animBase.Skeleton.TryLoad(out USkeleton skeleton))
else */if (animBase.Skeleton?.TryLoad(out USkeleton skeleton) == true)
{
LoadSkeleton(skeleton);
}
@@ -144,7 +149,7 @@ public class Renderer : IDisposable
}
private void Animate(UObject anim, FGuid guid)
{
if (anim is not UAnimSequenceBase animBase || !animBase.Skeleton.TryLoad(out USkeleton skeleton) ||
if (anim is not UAnimSequenceBase animBase || animBase.Skeleton == null || !animBase.Skeleton.TryLoad(out USkeleton skeleton) ||
!Options.TryGetModel(guid, out var m) || m is not SkeletalModel model)
return;
@@ -361,6 +366,31 @@ public class Renderer : IDisposable
Options.SelectModel(guid);
}
private void LoadStaticMesh(UGeometryCollection original, ENaniteMeshFormat naniteFormat = ENaniteMeshFormat.NoNanite)
{
var guid = new FGuid((uint) original.GetFullName().GetHashCode());
if (Options.TryGetModel(guid, out var model))
{
model.AddInstance(Transform.Identity);
Application.Current.Dispatcher.Invoke(() => model.SetupInstances());
return;
}
StaticMeshDto mesh;
try
{
mesh = new StaticMeshDto(original, naniteFormat);
}
catch (Exception e)
{
Log.Error(e, "Failed to convert geometry collection");
return;
}
Options.Models[guid] = new StaticModel(original, mesh);
Options.SelectModel(guid);
}
private void LoadSkeletalMesh(USkeletalMesh original)
{
var guid = new FGuid((uint) original.GetFullName().GetHashCode());