From 51541e5ef9dc111464d9305f4eedb3da72c76327 Mon Sep 17 00:00:00 2001 From: Krowe Moh <27891447+Krowe-moh@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:36:38 +1000 Subject: [PATCH] Use Refactored blueprint decompilation (unfinished code) ignore the json var and GetLoadPackageResult, will be removed once the method is found Removed the KismetExtensions.cs file and refactored blueprint decompilation logic in CUE4ParseViewModel.cs to use a new DecompileBlueprintToPseudo method. Updated CUE4ParseExtensions.cs with GetLoadPackageResult helper. Improved C++ syntax highlighting in Cpp.xshd by adding 'default' keyword and enhanced comment rule. Minor formatting and code organization improvements across affected files. --- FModel/Extensions/CUE4ParseExtensions.cs | 16 + FModel/Extensions/KismetExtensions.cs | 1051 ---------------------- FModel/Resources/Cpp.xshd | 3 + FModel/ViewModels/CUE4ParseViewModel.cs | 280 +----- FModel/ViewModels/SearchViewModel.cs | 58 +- FModel/Views/Resources/Resources.xaml | 1 + FModel/Views/SearchView.xaml | 8 + FModel/Views/SearchView.xaml.cs | 5 +- 8 files changed, 114 insertions(+), 1308 deletions(-) delete mode 100644 FModel/Extensions/KismetExtensions.cs diff --git a/FModel/Extensions/CUE4ParseExtensions.cs b/FModel/Extensions/CUE4ParseExtensions.cs index 463a668e..3e3ac993 100644 --- a/FModel/Extensions/CUE4ParseExtensions.cs +++ b/FModel/Extensions/CUE4ParseExtensions.cs @@ -3,6 +3,7 @@ using CUE4Parse.FileProvider; using CUE4Parse.FileProvider.Objects; using CUE4Parse.UE4.Assets; using CUE4Parse.UE4.Objects.UObject; +using CUE4Parse.Utils; using FModel.Settings; namespace FModel.Extensions; @@ -67,4 +68,19 @@ public static class CUE4ParseExtensions return result; } + + public static LoadPackageResult GetLoadPackageResult(this IFileProvider provider, string 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.SubstringBeforeLast('.')); + if (objectName != null) + { + result.RequestedIndex = int.TryParse(objectName, out var index) ? index : result.Package.GetExportIndex(objectName); + } + } + + return result; + } } diff --git a/FModel/Extensions/KismetExtensions.cs b/FModel/Extensions/KismetExtensions.cs deleted file mode 100644 index 76562497..00000000 --- a/FModel/Extensions/KismetExtensions.cs +++ /dev/null @@ -1,1051 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using CUE4Parse.UE4.Assets.Objects.Properties; -using CUE4Parse.UE4.Assets.Objects; -using CUE4Parse.UE4.Kismet; -using CUE4Parse.UE4.Objects.Core.Math; -using CUE4Parse.UE4.Objects.Core.Misc; -using CUE4Parse.UE4.Objects.Engine.Ai; -using CUE4Parse.UE4.Objects.Engine.GameFramework; -using CUE4Parse.UE4.Objects.GameplayTags; -using CUE4Parse.UE4.Objects.UObject; - -namespace FModel.Extensions; - -public static class KismetExtensions -{ - public static string GetPrefix(this UStruct val) - { - var ret = string.Empty; - var super = val; - - while (super is not null) - { - if (super.Name == "Actor") - { - ret += 'A'; - break; - } - - if (super.Name == "Interface") - { - ret += 'I'; - break; - } - - if (super.Name == "Object") - { - ret += 'U'; - break; - } - - super = super?.SuperStruct?.Load(); - } - - if (string.IsNullOrEmpty(ret)) - ret += 'U'; - - return ret; - } - - public static string GetPrefix(this string val) // todo: val.Contains("Struct") ? "F" findout - { - return val.Contains(".Actor") ? "A" : val.Contains("Interface") ? "I" : "U"; - } - - // GetUnknownFieldType and GetPropertyType from - // https://github.com/CrystalFerrai/UeBlueprintDumper/blob/main/UeBlueprintDumper/BlueprintDumper.cs#L352 - // nothing else is from UeBlueprintDumper - - public static string GetUnknownFieldType(object field) - { - string typeName = field.GetType().Name; - int suffixIndex = typeName.IndexOf("Property", StringComparison.Ordinal); - return suffixIndex < 0 ? typeName : typeName.Substring(1, suffixIndex - 1); - } - - public static string GetPropertyType(object? property) - { - if (property is null) - return "None"; - - return property switch - { - FIntProperty or int => "int", - FInt8Property or byte => "int8", - FInt16Property or short => "int16", - FInt64Property or long => "int64", - FUInt16Property or ushort => "uint16", - FUInt32Property or uint => "uint32", - FUInt64Property or ulong => "uint64", - FBoolProperty or bool => "bool", - FStrProperty or string => "FString", - FFloatProperty or float => "float", - FDoubleProperty or double => "double", - FObjectProperty objct => property switch - { - FClassProperty clss => $"{clss.MetaClass?.Name ?? "UKN_ObjectMetaClass"} Class", - FSoftClassProperty softClass => $"{softClass.MetaClass?.Name ?? "UKN_ObjectMetaClass"} Class (soft)", - _ => objct.PropertyClass?.Name ?? "UKN_ObjectPropertyClass" - }, - FPackageIndex pkg => pkg.ResolvedObject?.Class?.Name.ToString() ?? "Package", - FName fme => fme.PlainText.Contains("::") ? fme.PlainText.Split("::")[0] : fme.PlainText, - FEnumProperty enm => enm.Enum?.Name ?? "Enum", - FByteProperty bt => bt.Enum?.ResolvedObject?.Name.Text ?? "Byte", - FInterfaceProperty intrfc => $"{intrfc.InterfaceClass?.Name ?? "UKN_InterfaceClass"} interface", - FStructProperty strct => strct.Struct?.ResolvedObject?.Name.Text ?? "Struct", - FFieldPathProperty fieldPath => $"{fieldPath.PropertyClass.Text} field path", - FDelegateProperty dlgt => $"{dlgt.SignatureFunction?.Name ?? "UKN_SignatureFunction"} (Delegate)", - FMulticastDelegateProperty mdlgt => $"{mdlgt.SignatureFunction?.Name ?? "UKN_SignatureFunction"} (MulticastDelegateProperty)", - FMulticastInlineDelegateProperty midlgt => $"{midlgt.SignatureFunction?.Name ?? "UKN_SignatureFunction"} (MulticastInlineDelegateProperty)", - _ => GetUnknownFieldType(property) - }; - } - public static bool isPointer(FProperty p) => - p.PropertyFlags.HasFlag(EPropertyFlags.ReferenceParm) || - p.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || - p.PropertyFlags.HasFlag(EPropertyFlags.ContainsInstancedReference) || - p.GetType() == typeof(FObjectProperty); - - public static string GetPropertyType(FProperty property) - { - if (property is null) return "None"; - - return property switch - { - FSetProperty s => $"TSet<{s?.ElementProp.GetType().Name.GetPrefix()}{GetPropertyType(s.ElementProp)}{(isPointer(s) ? "*" : "")}>", - FMapProperty m => $"TMap<{m?.KeyProp.GetType().Name.GetPrefix()}{GetPropertyType(m.KeyProp)}, {m.ValueProp.GetType().Name.GetPrefix()}{GetPropertyType(m.ValueProp)}{(isPointer(m) ? "*" : "")}>", - FArrayProperty a => $"TArray<{a?.Inner.GetType().Name.GetPrefix()}{GetPropertyType(a.Inner)}{(isPointer(a) || a.Inner.GetType().Name == nameof(FObjectProperty) ? "*" : "")}>", - _ => GetPropertyType((object)property) - }; - } - - public static string FormatStructFallback(FStructFallback fallback) - { - if (fallback.Properties.Count == 0) - return "[]"; - - var tags = fallback.Properties.Select(tag => - { - string tagDataFormatted; - - switch (tag.Tag) - { - case TextProperty text: - tagDataFormatted = $"\"{text.Value.Text}\""; - break; - case NameProperty name: - tagDataFormatted = $"\"{name.Value.Text}\""; - break; - case ObjectProperty obj: - tagDataFormatted = $"\"{obj.Value}\""; - break; - default: - { - if (tag.Tag.GenericValue is FScriptStruct { StructType: FStructFallback nestedFallback }) - { - if (nestedFallback.Properties.Count > 0) - { - tagDataFormatted = "{ " + string.Join(", ", - nestedFallback.Properties.Select(nested => - { - string nestedVal = nested.Tag switch - { - TextProperty textProp => $"\"{textProp.Value.Text}\"", - NameProperty nameProp => $"\"{nameProp.Value.Text}\"", - _ => $"\"{nested.Tag.GenericValue}\"" - }; - - return $"\"{nested.Name}\": {nestedVal}"; - })) + " }"; - } - else - { - tagDataFormatted = "{}"; - } - } - else - { - tagDataFormatted = tag.Tag.GenericValue != null ? $"\"{tag.Tag.GenericValue}\"" : "{}"; - } - - break; - } - } - - return $"\t\t{{ \"{tag.Name}\": {tagDataFormatted} }}"; - }); - - return "[\n" + string.Join(",\n", tags) + "\n\t]"; - } - - public static string FormatGameplayTagContainer(FGameplayTagContainer container) - { - var tags = container.GameplayTags.ToList(); - return tags.Count switch - { - 0 => "[]", - 1 => $"\"{tags[0].TagName}\"", - _ => "[\n" + string.Join(",\n", tags.Select(tag => $"\t\t\"{tag.TagName}\"")) + "\n\t]" - }; - } - - public static string FormatStructType(object structType) - { - return structType switch - { - FVector vector => $"FVector({vector.X}, {vector.Y}, {vector.Z})", - FVector2D vector2D => $"FVector2D({vector2D.X}, {vector2D.Y})", - FRotator rotator => $"FRotator({rotator.Pitch}, {rotator.Yaw}, {rotator.Roll})", - FQuat quat => $"FQuat({quat.X}, {quat.Y}, {quat.Z}, {quat.W})", - FGuid guid => $"FGuid({guid.A}, {guid.B}, {guid.C}, {guid.D})", - FColor color => $"FColor({color.R}, {color.G}, {color.B}, {color.A})", - FLinearColor linearColor => $"FLinearColor({linearColor.R}, {linearColor.G}, {linearColor.B}, {linearColor.A})", - FSoftObjectPath path => $"FSoftObjectPath({path.AssetPathName})", - FUniqueNetIdRepl netId => $"FUniqueNetIdRepl({netId.UniqueNetId})", - FNavAgentSelector agent => $"FNavAgentSelector({agent.PackedBits})", - FBox box => $"FBox(FVector({box.Max.X}, {box.Max.Y}, {box.Max.Z}), FVector({box.Min.X}, {box.Min.Y}, {box.Min.Z}))", - FBox2D box2D => $"FBox2D(FVector2D({box2D.Max.X}, {box2D.Max.Y}), FVector2D({box2D.Min.X}, {box2D.Min.Y}))", - TIntVector3 intVec => $"FVector({intVec.X}, {intVec.Y}, {intVec.Z})", - TIntVector3 floatVec => $"FVector({floatVec.X}, {floatVec.Y}, {floatVec.Z})", - TIntVector2 floatVec2 => $"FVector2D({floatVec2.X}, {floatVec2.Y})", - FDateTime dateTime => $"FDateTime({dateTime})", - FStructFallback fallback => FormatStructFallback(fallback), - FGameplayTagContainer tagContainer => FormatGameplayTagContainer(tagContainer), - _ => structType?.ToString() ?? "Issue here" - }; - } - - private static string ProcessTextProperty(FKismetPropertyPointer property, bool temp) - { - if (property.New is null) - { - return property.Old?.Name ?? string.Empty; - } - return string.Join('.', property.New.Path.Select(n => n.Text)).Replace(" ", ""); - } - - public static void ProcessExpression(EExprToken token, KismetExpression expression, StringBuilder outputBuilder, List jumpCodeOffsets, bool isParameter = false) - { - if (jumpCodeOffsets.Contains(expression.StatementIndex)) - { - outputBuilder.Append("\t\tLabel_" + expression.StatementIndex + ":\n"); - } - - switch (token) - { - case EExprToken.EX_LetValueOnPersistentFrame: - { - EX_LetValueOnPersistentFrame op = (EX_LetValueOnPersistentFrame) expression; - EX_VariableBase opp = (EX_VariableBase) op.AssignmentExpression; - var destination = ProcessTextProperty(op.DestinationProperty, false); - var variable = ProcessTextProperty(opp.Variable, false); - - outputBuilder.Append($"\t\t{(destination.Contains("K2Node_") ? "UberGraphFrame->" + destination : destination)} = {variable}{(!isParameter ? ";\n\n" : "")}"); // Hardcoded but works - break; - } - case EExprToken.EX_LocalFinalFunction: - { - EX_FinalFunction op = (EX_FinalFunction) expression; - KismetExpression[] opp = op.Parameters; - if (isParameter) - { - outputBuilder.Append($"{op.StackNode.Name.Replace(" ", "")}("); - } - else if (opp.Length < 1) - { - outputBuilder.Append($"\t\t{op?.StackNode?.Name.Replace(" ", "")}("); - } - else - { - outputBuilder.Append($"\t\t{op?.StackNode?.ResolvedObject?.Outer?.GetType()?.Name.GetPrefix()}{op?.StackNode?.Name.Replace(" ", "")}("); - } - - for (int i = 0; i < opp.Length; i++) - { - if (opp.Length > 4) - outputBuilder.Append("\n\t\t"); - ProcessExpression(opp[i].Token, opp[i], outputBuilder, jumpCodeOffsets, true); - if (i < opp.Length - 1) - { - outputBuilder.Append(", "); - } - } - outputBuilder.Append(isParameter ? ")" : ");\n"); - break; - } - case EExprToken.EX_FinalFunction: - { - EX_FinalFunction op = (EX_FinalFunction) expression; - KismetExpression[] opp = op.Parameters; - if (isParameter) - { - outputBuilder.Append($"{op.StackNode.Name.Replace(" ", "")}("); - } - else if (opp.Length < 1) - { - outputBuilder.Append($"\t\t{op?.StackNode?.Name.Replace(" ", "")}("); - } - else - { - outputBuilder.Append($"\t\t{op?.StackNode?.Name.Replace(" ", "")}(");// maybe use GetPrefix(op?.StackNode?.ResolvedObject?.Outer?.GetType()?.Name)} - } - - for (int i = 0; i < opp.Length; i++) - { - if (opp.Length > 4) - outputBuilder.Append("\n\t\t"); - ProcessExpression(opp[i].Token, opp[i], outputBuilder, jumpCodeOffsets, true); - if (i < opp.Length - 1) - { - outputBuilder.Append(", "); - } - } - outputBuilder.Append(isParameter ? ")" : ");\n\n"); - break; - } - case EExprToken.EX_CallMath: - { - EX_FinalFunction op = (EX_FinalFunction) expression; - KismetExpression[] opp = op.Parameters; - outputBuilder.Append(isParameter ? string.Empty : "\t\t"); - outputBuilder.Append($"{op.StackNode.ResolvedObject.Outer.GetType().Name.GetPrefix()}{op.StackNode.ResolvedObject.Outer.Name.ToString().Replace(" ", "")}::{op.StackNode.Name}("); - - for (int i = 0; i < opp.Length; i++) - { - if (opp.Length > 4) - outputBuilder.Append("\n\t\t\t"); - ProcessExpression(opp[i].Token, opp[i], outputBuilder, jumpCodeOffsets, true); - if (i < opp.Length - 1) - { - outputBuilder.Append(", "); - } - } - outputBuilder.Append(isParameter ? ")" : ");\n\n"); - break; - } - case EExprToken.EX_LocalVirtualFunction: - case EExprToken.EX_VirtualFunction: - { - EX_VirtualFunction op = (EX_VirtualFunction) expression; - KismetExpression[] opp = op.Parameters; - if (isParameter) - { - outputBuilder.Append($"{op.VirtualFunctionName.PlainText.Replace(" ", "")}("); - } - else - { - outputBuilder.Append($"\t\t{op.VirtualFunctionName.PlainText.Replace(" ", "")}("); - } - for (int i = 0; i < opp.Length; i++) - { - if (opp.Length > 4) - outputBuilder.Append("\n\t\t"); - - ProcessExpression(opp[i].Token, opp[i], outputBuilder, jumpCodeOffsets, true); - if (i < opp.Length - 1) - { - outputBuilder.Append(", "); - } - } - outputBuilder.Append(isParameter ? ")" : ");\n\n"); - break; - } - case EExprToken.EX_ComputedJump: - { - EX_ComputedJump op = (EX_ComputedJump) expression; - if (op.CodeOffsetExpression is EX_VariableBase opp) - { - outputBuilder.AppendLine($"\t\tgoto {ProcessTextProperty(opp.Variable, false)};\n"); - } - else if (op.CodeOffsetExpression is EX_CallMath oppMath) - { - ProcessExpression(oppMath.Token, oppMath, outputBuilder, jumpCodeOffsets, true); - } - - break; - } - case EExprToken.EX_PopExecutionFlowIfNot: - { - EX_PopExecutionFlowIfNot op = (EX_PopExecutionFlowIfNot) expression; - outputBuilder.Append("\t\tif (!"); - ProcessExpression(op.BooleanExpression.Token, op.BooleanExpression, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append(") \r\n"); - outputBuilder.Append($"\t\t FlowStack.Pop();\n\n"); - break; - } - case EExprToken.EX_Cast: - { - EX_Cast op = (EX_Cast) expression; // support CST_ObjectToInterface when I have an example of how it works - - if (op.ConversionType is ECastToken.CST_ObjectToBool or ECastToken.CST_InterfaceToBool) - { - outputBuilder.Append("(bool)"); - } - if (ECastToken.CST_DoubleToFloat == op.ConversionType) - { - outputBuilder.Append("(float)"); - } - if (ECastToken.CST_FloatToDouble == op.ConversionType) - { - outputBuilder.Append("(double)"); - } - ProcessExpression(op.Target.Token, op.Target, outputBuilder, jumpCodeOffsets); - break; - } - case EExprToken.EX_InterfaceContext: - { - EX_InterfaceContext op = (EX_InterfaceContext) expression; - ProcessExpression(op.InterfaceValue.Token, op.InterfaceValue, outputBuilder, jumpCodeOffsets); - break; - } - case EExprToken.EX_ArrayConst: - { - EX_ArrayConst op = (EX_ArrayConst) expression; - outputBuilder.Append("TArray {"); - foreach (KismetExpression element in op.Elements) - { - outputBuilder.Append(' '); - ProcessExpression(element.Token, element, outputBuilder, jumpCodeOffsets); - } - outputBuilder.Append(op.Elements.Length < 1 ? " " : ' '); - - outputBuilder.Append('}'); - break; - } - case EExprToken.EX_SetArray: - { - EX_SetArray op = (EX_SetArray) expression; - outputBuilder.Append("\t\t"); - ProcessExpression(op.AssigningProperty.Token, op.AssigningProperty, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(" = "); - outputBuilder.Append("TArray {"); - for (int i = 0; i < op.Elements.Length; i++) - { - KismetExpression element = op.Elements[i]; - outputBuilder.Append(' '); - ProcessExpression(element.Token, element, outputBuilder, jumpCodeOffsets); - - outputBuilder.Append(i < op.Elements.Length - 1 ? "," : ""); - } - - outputBuilder.Append(op.Elements.Length < 1 ? " " : ' '); - - outputBuilder.Append("};\n\n"); - break; - } - case EExprToken.EX_SetSet: - { - EX_SetSet op = (EX_SetSet) expression; - outputBuilder.Append("\t\t"); - ProcessExpression(op.SetProperty.Token, op.SetProperty, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(" = "); - outputBuilder.Append("TArray {"); - for (int i = 0; i < op.Elements.Length; i++) - { - KismetExpression element = op.Elements[i]; - outputBuilder.Append(' '); - ProcessExpression(element.Token, element, outputBuilder, jumpCodeOffsets); - - outputBuilder.Append(i < op.Elements.Length - 1 ? "," : ""); - } - - outputBuilder.Append(op.Elements.Length < 1 ? " " : ' '); - - outputBuilder.Append("};\n\n"); - break; - } - case EExprToken.EX_SetConst: - { - EX_SetConst op = (EX_SetConst) expression; - outputBuilder.Append("TArray {"); - for (int i = 0; i < op.Elements.Length; i++) - { - KismetExpression element = op.Elements[i]; - outputBuilder.Append(' '); - ProcessExpression(element.Token, element, outputBuilder, jumpCodeOffsets, true); - - outputBuilder.Append(i < op.Elements.Length - 1 ? "," : ""); - } - - outputBuilder.Append(op.Elements.Length < 1 ? " " : ' '); - - outputBuilder.Append("};\n\n"); - break; - } - case EExprToken.EX_SetMap: - { - EX_SetMap op = (EX_SetMap) expression; - outputBuilder.Append("\t\t"); - ProcessExpression(op.MapProperty.Token, op.MapProperty, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(" = "); - outputBuilder.Append("TMap {"); - for (int i = 0; i < op.Elements.Length; i++) - { - var element = op.Elements[i]; - outputBuilder.Append(' '); - ProcessExpression(element.Token, element, outputBuilder, jumpCodeOffsets); // sometimes the start of an array is a byte not a variable - - if (i < op.Elements.Length - 1) - { - outputBuilder.Append(element.Token == EExprToken.EX_InstanceVariable ? ": " : ", "); - } - else - { - outputBuilder.Append(' '); - } - } - - if (op.Elements.Length < 1) - outputBuilder.Append(" "); - outputBuilder.Append("}\n"); - break; - } - case EExprToken.EX_MapConst: - { - EX_MapConst op = (EX_MapConst) expression; - outputBuilder.Append("TMap {"); - for (int i = 0; i < op.Elements.Length; i++) - { - var element = op.Elements[i]; - outputBuilder.Append(' '); - ProcessExpression(element.Token, element, outputBuilder, jumpCodeOffsets, true); // sometimes the start of an array is a byte not a variable - - if (i < op.Elements.Length - 1) - { - outputBuilder.Append(element.Token == EExprToken.EX_InstanceVariable ? ": " : ", "); - } - else - { - outputBuilder.Append(' '); - } - } - - if (op.Elements.Length < 1) - outputBuilder.Append(" "); - outputBuilder.Append("}\n"); - break; - } - case EExprToken.EX_SwitchValue: - { - EX_SwitchValue op = (EX_SwitchValue) expression; - - bool useTernary = op.Cases.Length <= 2 && - op.Cases.All(c => c.CaseIndexValueTerm.Token is EExprToken.EX_True or EExprToken.EX_False); - - if (useTernary) - { - ProcessExpression(op.IndexTerm.Token, op.IndexTerm, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(" ? "); - - bool isFirst = true; - foreach (var caseItem in op.Cases.Where(c => c.CaseIndexValueTerm.Token == EExprToken.EX_True)) - { - if (!isFirst) - outputBuilder.Append(" : "); - - ProcessExpression(caseItem.CaseTerm.Token, caseItem.CaseTerm, outputBuilder, jumpCodeOffsets, true); - isFirst = false; - } - - foreach (var caseItem in op.Cases.Where(c => c.CaseIndexValueTerm.Token == EExprToken.EX_False)) - { - if (!isFirst) - outputBuilder.Append(" : "); - - ProcessExpression(caseItem.CaseTerm.Token, caseItem.CaseTerm, outputBuilder, jumpCodeOffsets, true); - } - } - else - { - outputBuilder.Append("switch ("); - ProcessExpression(op.IndexTerm.Token, op.IndexTerm, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(")\n"); - outputBuilder.Append("\t\t{\n"); - - foreach (var caseItem in op.Cases) - { - if (caseItem.CaseIndexValueTerm.Token == EExprToken.EX_IntConst) - { - int caseValue = ((EX_IntConst) caseItem.CaseIndexValueTerm).Value; - outputBuilder.Append($"\t\t\tcase {caseValue}:\n"); - } - else - { - outputBuilder.Append("\t\t\tcase "); - ProcessExpression(caseItem.CaseIndexValueTerm.Token, caseItem.CaseIndexValueTerm, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(":\n"); - } - - outputBuilder.Append("\t\t\t{\n"); - outputBuilder.Append("\t\t\t "); - ProcessExpression(caseItem.CaseTerm.Token, caseItem.CaseTerm, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(";\n"); - outputBuilder.Append("\t\t\t break;\n"); - outputBuilder.Append("\t\t\t}\n"); - } - - outputBuilder.Append("\t\t\tdefault:\n"); - outputBuilder.Append("\t\t\t{\n"); - outputBuilder.Append("\t\t\t "); - ProcessExpression(op.DefaultTerm.Token, op.DefaultTerm, outputBuilder, jumpCodeOffsets); - outputBuilder.Append("\n\t\t\t}\n"); - - outputBuilder.Append("\t\t}"); - } - break; - } - case EExprToken.EX_ArrayGetByRef: // I assume get array with index - { - EX_ArrayGetByRef op = (EX_ArrayGetByRef) expression; // FortniteGame/Plugins/GameFeatures/FM/PilgrimCore/Content/Player/Components/BP_PilgrimPlayerControllerComponent.uasset - ProcessExpression(op.ArrayVariable.Token, op.ArrayVariable, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append('['); - ProcessExpression(op.ArrayIndex.Token, op.ArrayIndex, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(']'); - break; - } - case EExprToken.EX_MetaCast: - case EExprToken.EX_DynamicCast: - case EExprToken.EX_ObjToInterfaceCast: - case EExprToken.EX_CrossInterfaceCast: - case EExprToken.EX_InterfaceToObjCast: - { - EX_CastBase op = (EX_CastBase) expression; - outputBuilder.Append($"Cast(");// m? - ProcessExpression(op.Target.Token, op.Target, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append(')'); - break; - } - case EExprToken.EX_StructConst: - { - EX_StructConst op = (EX_StructConst) expression; - outputBuilder.Append($"{op.Struct.GetType().Name.GetPrefix()}{op.Struct.Name}"); - outputBuilder.Append('('); - for (int i = 0; i < op.Properties.Length; i++) - { - var property = op.Properties[i]; - ProcessExpression(property.Token, property, outputBuilder, jumpCodeOffsets); - if (i < op.Properties.Length - 1 && property.Token != EExprToken.EX_ArrayConst) - outputBuilder.Append(", "); - } - outputBuilder.Append(')'); - break; - } - case EExprToken.EX_ObjectConst: - { - EX_ObjectConst op = (EX_ObjectConst) expression; - outputBuilder.Append(!isParameter ? "\t\tFindObject<" : outputBuilder.ToString().EndsWith('\n') ? "\t\tFindObject<" : "FindObject<"); // please don't complain, I know this is bad but I MUST do it. - string classString = op.Value.ResolvedObject?.Class?.ToString().Replace("'", ""); - - if (classString?.Contains('.') == true) - { - - outputBuilder.Append(op?.Value?.ResolvedObject?.Class?.GetType().Name.GetPrefix() + classString.Split('.')[1]); - } - else - { - outputBuilder.Append(op?.Value?.ResolvedObject?.Class?.GetType().Name.GetPrefix() + classString); - } - outputBuilder.Append(">(\""); - var resolvedObject = op?.Value?.ResolvedObject; - var outerString = resolvedObject?.Outer?.ToString()?.Replace("'", "") ?? "outerUnknown"; - var outerClassString = resolvedObject?.Class?.ToString()?.Replace("'", "") ?? "outerClassUnknown"; - var name = op?.Value?.Name ?? string.Empty; - - outputBuilder.Append(outerString.Replace(outerClassString, "") + "." + name); - outputBuilder.Append("\")"); - break; - } - case EExprToken.EX_BindDelegate: - { - EX_BindDelegate op = (EX_BindDelegate) expression; - outputBuilder.Append("\t\t"); - ProcessExpression(op.Delegate.Token, op.Delegate, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(".BindUFunction("); - ProcessExpression(op.ObjectTerm.Token, op.ObjectTerm, outputBuilder, jumpCodeOffsets); - outputBuilder.Append($", \"{op.FunctionName}\""); - outputBuilder.Append(");\n\n"); - break; - } - // all the delegate functions suck - case EExprToken.EX_AddMulticastDelegate: - { - EX_AddMulticastDelegate op = (EX_AddMulticastDelegate) expression; - if (op.Delegate.Token is EExprToken.EX_LocalVariable or EExprToken.EX_InstanceVariable) - { - outputBuilder.Append("\t\t"); - ProcessExpression(op.Delegate.Token, op.Delegate, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append(".AddDelegate("); - ProcessExpression(op.DelegateToAdd.Token, op.DelegateToAdd, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(");\n\n"); - } - else if (op.Delegate.Token != EExprToken.EX_Context) - {} - else - { - //EX_Context opp = (EX_Context) op.Delegate; - outputBuilder.Append("\t\t"); - ProcessExpression(op.Delegate.Token, op.Delegate, outputBuilder, jumpCodeOffsets, true); - //outputBuilder.Append("->"); - //ProcessExpression(opp.ContextExpression.Token, opp.ContextExpression, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(".AddDelegate("); - ProcessExpression(op.DelegateToAdd.Token, op.DelegateToAdd, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(");\n\n"); - } - break; - } - case EExprToken.EX_RemoveMulticastDelegate: // everything here has been guessed not compared to actual UE but does work fine and displays all information - { - EX_RemoveMulticastDelegate op = (EX_RemoveMulticastDelegate) expression; - if (op.Delegate.Token is EExprToken.EX_LocalVariable or EExprToken.EX_InstanceVariable) - { - outputBuilder.Append("\t\t"); - ProcessExpression(op.Delegate.Token, op.Delegate, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append(".RemoveDelegate("); - ProcessExpression(op.DelegateToAdd.Token, op.DelegateToAdd, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(");\n\n"); - } - else if (op.Delegate.Token != EExprToken.EX_Context) - { - - } - else - { - EX_Context opp = (EX_Context) op.Delegate; - outputBuilder.Append("\t\t"); - ProcessExpression(op.Delegate.Token, op.Delegate, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append("->"); - ProcessExpression(opp.ContextExpression.Token, opp.ContextExpression, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(".RemoveDelegate("); - ProcessExpression(op.DelegateToAdd.Token, op.DelegateToAdd, outputBuilder, jumpCodeOffsets); - outputBuilder.Append(");\n\n"); - } - break; - } - case EExprToken.EX_ClearMulticastDelegate: // this also - { - EX_ClearMulticastDelegate op = (EX_ClearMulticastDelegate) expression; - outputBuilder.Append("\t\t"); - ProcessExpression(op.DelegateToClear.Token, op.DelegateToClear, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append(".Clear();\n\n"); - break; - } - case EExprToken.EX_CallMulticastDelegate: // this also - { - EX_CallMulticastDelegate op = (EX_CallMulticastDelegate) expression; - KismetExpression[] opp = op.Parameters; - if (op.Delegate.Token == EExprToken.EX_LocalVariable || op.Delegate.Token == EExprToken.EX_InstanceVariable) - { - outputBuilder.Append("\t\t"); - ProcessExpression(op.Delegate.Token, op.Delegate, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append(".Call("); - for (int i = 0; i < opp.Length; i++) - { - if (opp.Length > 4) - outputBuilder.Append("\n\t\t"); - ProcessExpression(opp[i].Token, opp[i], outputBuilder, jumpCodeOffsets, true); - if (i < opp.Length - 1) - { - outputBuilder.Append(", "); - } - } - outputBuilder.Append(");\n\n"); - } - else if (op.Delegate.Token != EExprToken.EX_Context) - { - - } - else - { - outputBuilder.Append("\t\t"); - ProcessExpression(op.Delegate.Token, op.Delegate, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append(".Call("); - for (int i = 0; i < opp.Length; i++) - { - if (opp.Length > 4) - outputBuilder.Append("\n\t\t"); - ProcessExpression(opp[i].Token, opp[i], outputBuilder, jumpCodeOffsets, true); - if (i < opp.Length - 1) - { - outputBuilder.Append(", "); - } - } - outputBuilder.Append(");\n\n"); - } - break; - } - case EExprToken.EX_ClassContext: - case EExprToken.EX_Context: - { - EX_Context op = (EX_Context) expression; - outputBuilder.Append(outputBuilder.ToString().EndsWith('\n') ? "\t\t" : ""); - ProcessExpression(op.ObjectExpression.Token, op.ObjectExpression, outputBuilder, jumpCodeOffsets, true); - - outputBuilder.Append("->"); - ProcessExpression(op.ContextExpression.Token, op.ContextExpression, outputBuilder, jumpCodeOffsets, true); - if (!isParameter) - { - outputBuilder.Append(";\n\n"); - } - break; - } - case EExprToken.EX_Context_FailSilent: - { - EX_Context op = (EX_Context) expression; - outputBuilder.Append("\t\t"); - ProcessExpression(op.ObjectExpression.Token, op.ObjectExpression, outputBuilder, jumpCodeOffsets, true); - if (!isParameter) - { - outputBuilder.Append("->"); - ProcessExpression(op.ContextExpression.Token, op.ContextExpression, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append(";\n\n"); - } - break; - } - case EExprToken.EX_Let: - { - EX_Let op = (EX_Let) expression; - if (!isParameter) - { - outputBuilder.Append("\t\t"); - } - ProcessExpression(op.Variable.Token, op.Variable, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append(" = "); - ProcessExpression(op.Assignment.Token, op.Assignment, outputBuilder, jumpCodeOffsets, true); - if (!isParameter) - { - outputBuilder.Append(";\n\n"); - } - break; - } - case EExprToken.EX_LetObj: - case EExprToken.EX_LetWeakObjPtr: - case EExprToken.EX_LetBool: - case EExprToken.EX_LetDelegate: - case EExprToken.EX_LetMulticastDelegate: - { - EX_LetBase op = (EX_LetBase) expression; - if (!isParameter) - { - outputBuilder.Append("\t\t"); - } - ProcessExpression(op.Variable.Token, op.Variable, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append(" = "); - ProcessExpression(op.Assignment.Token, op.Assignment, outputBuilder, jumpCodeOffsets, true); - if (!isParameter || op.Assignment.Token == EExprToken.EX_LocalFinalFunction || op.Assignment.Token == EExprToken.EX_FinalFunction || op.Assignment.Token == EExprToken.EX_CallMath) - { - outputBuilder.Append(";\n\n"); - } - else - { - outputBuilder.Append(';'); - } - break; - } - case EExprToken.EX_JumpIfNot: - { - EX_JumpIfNot op = (EX_JumpIfNot) expression; - outputBuilder.Append("\t\tif (!"); - ProcessExpression(op.BooleanExpression.Token, op.BooleanExpression, outputBuilder, jumpCodeOffsets, true); - outputBuilder.Append(") \r\n"); - outputBuilder.Append("\t\t goto Label_"); - outputBuilder.Append(op.CodeOffset); - outputBuilder.Append(";\n\n"); - break; - } - case EExprToken.EX_Jump: - { - EX_Jump op = (EX_Jump) expression; - outputBuilder.Append($"\t\tgoto Label_{op.CodeOffset};\n\n"); - break; - } - // Static expressions - - case EExprToken.EX_TextConst: - { - EX_TextConst op = (EX_TextConst) expression; - - if (op.Value is FScriptText scriptText) - { - if (scriptText.SourceString == null) - { - outputBuilder.Append("nullptr"); - } - else - ProcessExpression(scriptText.SourceString.Token, scriptText.SourceString, outputBuilder, jumpCodeOffsets, true); - } - else - { - outputBuilder.Append(op.Value); // impossible to reach? - } - } - break; - case EExprToken.EX_StructMemberContext: - { - EX_StructMemberContext op = (EX_StructMemberContext) expression; - ProcessExpression(op.StructExpression.Token, op.StructExpression, outputBuilder, jumpCodeOffsets); - outputBuilder.Append('.'); - outputBuilder.Append(ProcessTextProperty(op.Property, false)); - break; - } - case EExprToken.EX_Return: - { - EX_Return op = (EX_Return) expression; - bool check = op.ReturnExpression.Token == EExprToken.EX_Nothing; - outputBuilder.Append("\t\treturn"); - if (!check) - outputBuilder.Append(' '); - ProcessExpression(op.ReturnExpression.Token, op.ReturnExpression, outputBuilder, jumpCodeOffsets, true); - outputBuilder.AppendLine(";"); - break; - } - case EExprToken.EX_RotationConst: - { - EX_RotationConst op = (EX_RotationConst) expression; - FRotator value = op.Value; - outputBuilder.Append($"FRotator({value.Pitch}, {value.Yaw}, {value.Roll})"); - break; - } - case EExprToken.EX_VectorConst: - { - EX_VectorConst op = (EX_VectorConst) expression; - FVector value = op.Value; - outputBuilder.Append($"FVector({value.X}, {value.Y}, {value.Z})"); - break; - } - case EExprToken.EX_Vector3fConst: - { - EX_Vector3fConst op = (EX_Vector3fConst) expression; - FVector value = op.Value; - outputBuilder.Append($"FVector3f({value.X}, {value.Y}, {value.Z})"); - break; - } - case EExprToken.EX_TransformConst: - { - EX_TransformConst op = (EX_TransformConst) expression; - FTransform value = op.Value; - outputBuilder.Append($"FTransform(FQuat({value.Rotation.X}, {value.Rotation.Y}, {value.Rotation.Z}, {value.Rotation.W}), FVector({value.Translation.X}, {value.Translation.Y}, {value.Translation.Z}), FVector({value.Scale3D.X}, {value.Scale3D.Y}, {value.Scale3D.Z}))"); - break; - } - - - case EExprToken.EX_LocalVariable: - case EExprToken.EX_DefaultVariable: - case EExprToken.EX_LocalOutVariable: - case EExprToken.EX_ClassSparseDataVariable: - outputBuilder.Append(ProcessTextProperty(((EX_VariableBase) expression).Variable, false)); - break; - case EExprToken.EX_InstanceVariable: - outputBuilder.Append(ProcessTextProperty(((EX_VariableBase) expression).Variable, true)); - break; - - case EExprToken.EX_ByteConst: - case EExprToken.EX_IntConstByte: - outputBuilder.Append($"0x{((KismetExpression) expression).Value.ToString("X")}"); - break; - case EExprToken.EX_SoftObjectConst: - ProcessExpression(((EX_SoftObjectConst) expression).Value.Token, ((EX_SoftObjectConst) expression).Value, outputBuilder, jumpCodeOffsets); - break; - case EExprToken.EX_DoubleConst: - { - double value = ((EX_DoubleConst) expression).Value; - outputBuilder.Append(Math.Abs(value - Math.Floor(value)) < 1e-10 ? (int) value : value.ToString("R")); - break; - } - case EExprToken.EX_NameConst: - outputBuilder.Append($"\"{((EX_NameConst) expression).Value}\""); - break; - case EExprToken.EX_IntConst: - outputBuilder.Append(((EX_IntConst) expression).Value.ToString()); - break; - case EExprToken.EX_PropertyConst: - outputBuilder.Append(ProcessTextProperty(((EX_PropertyConst) expression).Property, false)); - break; - case EExprToken.EX_StringConst: - outputBuilder.Append($"\"{((EX_StringConst) expression).Value}\""); - break; - case EExprToken.EX_FieldPathConst: - ProcessExpression(((EX_FieldPathConst) expression).Value.Token, ((EX_FieldPathConst) expression).Value, outputBuilder, jumpCodeOffsets); - break; - case EExprToken.EX_Int64Const: - outputBuilder.Append(((EX_Int64Const) expression).Value.ToString()); - break; - case EExprToken.EX_UInt64Const: - outputBuilder.Append(((EX_UInt64Const) expression).Value.ToString()); - break; - case EExprToken.EX_SkipOffsetConst: - outputBuilder.Append(((EX_SkipOffsetConst) expression).Value.ToString()); - break; - case EExprToken.EX_FloatConst: - outputBuilder.Append(((EX_FloatConst) expression).Value.ToString(CultureInfo.GetCultureInfo("en-US"))); - break; - case EExprToken.EX_BitFieldConst: - outputBuilder.Append(((EX_BitFieldConst) expression).ConstValue); - break; - case EExprToken.EX_UnicodeStringConst: - outputBuilder.Append(((EX_UnicodeStringConst) expression).Value); - break; - case EExprToken.EX_InstanceDelegate: - outputBuilder.Append($"\"{((EX_InstanceDelegate) expression).FunctionName}\""); - break; - case EExprToken.EX_EndOfScript: - case EExprToken.EX_EndParmValue: - outputBuilder.Append("\t}\n"); - break; - case EExprToken.EX_NoObject: - case EExprToken.EX_NoInterface: - outputBuilder.Append("nullptr"); - break; - case EExprToken.EX_IntOne: - outputBuilder.Append(1); - break; - case EExprToken.EX_IntZero: - outputBuilder.Append(0); - break; - case EExprToken.EX_True: - outputBuilder.Append("true"); - break; - case EExprToken.EX_False: - outputBuilder.Append("false"); - break; - case EExprToken.EX_Self: - outputBuilder.Append("this"); - break; - - case EExprToken.EX_Nothing: - case EExprToken.EX_NothingInt32: - case EExprToken.EX_EndFunctionParms: - case EExprToken.EX_EndStructConst: - case EExprToken.EX_EndArray: - case EExprToken.EX_EndArrayConst: - case EExprToken.EX_EndSet: - case EExprToken.EX_EndMap: - case EExprToken.EX_EndMapConst: - case EExprToken.EX_EndSetConst: - case EExprToken.EX_PushExecutionFlow: - case EExprToken.EX_PopExecutionFlow: - case EExprToken.EX_DeprecatedOp4A: - case EExprToken.EX_WireTracepoint: - case EExprToken.EX_Tracepoint: - case EExprToken.EX_Breakpoint: - case EExprToken.EX_AutoRtfmStopTransact: - case EExprToken.EX_AutoRtfmTransact: - case EExprToken.EX_AutoRtfmAbortIfNot: - // some here are "useful" and unsupported - break; - /* - Todo: check what uses these, fortnite has none instances - EExprToken.EX_Assert - EExprToken.EX_Skip - EExprToken.EX_InstrumentationEvent - EExprToken.EX_FieldPathConst - */ - default: - outputBuilder.Append($"{token}"); - break; - } - } -} diff --git a/FModel/Resources/Cpp.xshd b/FModel/Resources/Cpp.xshd index f02e55c0..f61b1264 100644 --- a/FModel/Resources/Cpp.xshd +++ b/FModel/Resources/Cpp.xshd @@ -82,6 +82,7 @@ friend inline constexpr + default @@ -119,6 +120,8 @@ [\[\]\{\}] + (\/\/.*|\/\*[\s\S]*?\*\/) + \b[A-Za-z_][A-Za-z0-9_]*\b(?=<) diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 1b87ad79..2590b975 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -74,10 +74,12 @@ public class CUE4ParseViewModel : ViewModel { private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView; private ApiEndpointViewModel _apiEndpointView => ApplicationService.ApiEndpointView; + private readonly Regex _fnLiveRegex = new(@"^FortniteGame[/\\]Content[/\\]Paks[/\\]", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); private bool _modelIsOverwritingMaterial; + public bool ModelIsOverwritingMaterial { get => _modelIsOverwritingMaterial; @@ -86,6 +88,7 @@ public class CUE4ParseViewModel : ViewModel public bool IsSnooperOpen => _snooper is { Exists: true, IsVisible: true }; private Snooper _snooper; + public Snooper SnooperViewer { get @@ -445,6 +448,7 @@ public class CUE4ParseViewModel : ViewModel public int LocalizedResourcesCount { get; set; } public bool LocalResourcesDone { get; set; } public bool HotfixedResourcesDone { get; set; } + public async Task LoadLocalizedResources() { var snapshot = LocalizedResourcesCount; @@ -458,6 +462,7 @@ public class CUE4ParseViewModel : ViewModel Utils.Typefaces = new Typefaces(this); } } + private Task LoadGameLocalizedResources() { if (LocalResourcesDone) return Task.CompletedTask; @@ -466,6 +471,7 @@ public class CUE4ParseViewModel : ViewModel LocalResourcesDone = Provider.TryChangeCulture(Provider.GetLanguageCode(UserSettings.Default.AssetLanguage)); }); } + private Task LoadHotfixedLocalizedResources() { if (!Provider.ProjectName.Equals("fortnitegame", StringComparison.OrdinalIgnoreCase) || HotfixedResourcesDone) return Task.CompletedTask; @@ -480,6 +486,7 @@ public class CUE4ParseViewModel : ViewModel } private int _virtualPathCount { get; set; } + public Task LoadVirtualPaths() { if (_virtualPathCount > 0) return Task.CompletedTask; @@ -698,7 +705,7 @@ public class CUE4ParseViewModel : ViewModel case "wav": case "WAV": case "ogg": - // todo: CSCore.MediaFoundation.MediaFoundationException The byte stream type of the given URL is unsupported. case "aif": + // todo: CSCore.MediaFoundation.MediaFoundationException The byte stream type of the given URL is unsupported. case "aif": { var data = Provider.SaveAsset(entry); SaveAndPlaySound(entry.PathWithoutExtension, entry.Extension, data); @@ -988,271 +995,34 @@ public class CUE4ParseViewModel : ViewModel var pkg = Provider.LoadPackage(entry); - var outputBuilder = new StringBuilder(); + string mypathisapathrealwhathowPath = Path.Combine( + Path.GetDirectoryName(entry.Path)!, + $"{Path.GetFileNameWithoutExtension(entry.Path)}.o.uasset" + ); + + string idkhowtogetitwithoutthis = string.Empty; + try + { + var whatisthisforealreal = Provider.GetLoadPackageResult(mypathisapathrealwhathowPath); + idkhowtogetitwithoutthis = JsonConvert.SerializeObject(whatisthisforealreal.GetDisplayData(false), Formatting.Indented); + } + catch (Exception e) {} + + + var cpp = string.Empty; for (var i = 0; i < pkg.ExportMapLength; i++) { var pointer = new FPackageIndex(pkg, i + 1).ResolvedObject; - if (pointer?.Object is null) + if (pointer?.Object is null && pointer.Class?.Object?.Value is null) continue; var dummy = ((AbstractUePackage) pkg).ConstructObject(pointer.Class?.Object?.Value as UStruct, pkg); if (dummy is not UClass || pointer.Object.Value is not UClass blueprint) continue; - var typePrefix = blueprint?.SuperStruct.Load().GetPrefix(); - var modifierStr = blueprint.Flags.HasAnyFlags(EObjectFlags.RF_Public) ? "public" : "private"; - outputBuilder.AppendLine($"class {typePrefix}{blueprint.Name} : {modifierStr} {typePrefix}{blueprint?.SuperStruct?.Name ?? string.Empty}\n{{\n{modifierStr}:"); - - if (!blueprint.ClassDefaultObject.TryLoad(out var bpObject)) - continue; - - var strings = new List(); - foreach (var property in bpObject.Properties) - { - var propertyName = property.Name.ToString(); - var propertyValue = property.Tag?.GenericValue; - strings.Add(propertyName); - string placeholder = $"{propertyName}fmodelholder"; // spelling mistake is intended - - void ShouldAppend(string value) - { - if (outputBuilder.ToString().Contains(placeholder)) - { - outputBuilder.Replace(placeholder, value); - } - else - { - outputBuilder.AppendLine($"\t{KismetExtensions.GetPropertyType(propertyValue)} {propertyName.Replace(" ", "")} = {value};"); - } - } - - string GetLineOfText(object value) - { - string text = null; - switch (value) - { - case FScriptStruct structTag: - switch (structTag.StructType) - { - case FVector vector: - text = $"FVector({vector.X}, {vector.Y}, {vector.Z})"; - break; - case FGuid guid: - text = $"FGuid({guid.A}, {guid.B}, {guid.C}, {guid.D})"; - break; - case TIntVector3 vector3: - text = $"FVector({vector3.X}, {vector3.Y}, {vector3.Z})"; - break; - case TIntVector3 floatVector3: - text = $"FVector({floatVector3.X}, {floatVector3.Y}, {floatVector3.Z})"; - break; - case TIntVector2 floatVector2: - text = $"FVector2D({floatVector2.X}, {floatVector2.Y})"; - break; - case FVector2D vector2d: - text = $"FVector2D({vector2d.X}, {vector2d.Y})"; - break; - case FRotator rotator: - text = $"FRotator({rotator.Pitch}, {rotator.Yaw}, {rotator.Roll})"; - break; - case FLinearColor linearColor: - text = $"FLinearColor({linearColor.R}, {linearColor.G}, {linearColor.B}, {linearColor.A})"; - break; - case FGameplayTagContainer gTag: - text = gTag.GameplayTags.Length switch - { - > 1 => "[\n" + string.Join(",\n", gTag.GameplayTags.Select(tag => $"\t\t\"{tag.TagName}\"")) + "\n\t]", - > 0 => $"\"{gTag.GameplayTags[0].TagName}\"", - _ => "[]" - }; - break; - case FStructFallback fallback: - if (fallback.Properties.Count > 0) - { - text = "[\n" + string.Join(",\n", fallback.Properties.Select(p => $"\t\"{GetLineOfText(p)}\"")) + "\n\t]"; - } - else - { - text = "[]"; - } - break; - } - break; - case UScriptSet: - case UScriptMap: - case UScriptArray: - IEnumerable inner = value switch - { - UScriptSet set => set.Properties.Select(p => $"\t\"{p.GenericValue}\""), - UScriptMap map => map.Properties.Select(kvp => $"\t{{\n\t\t\"{kvp.Key}\": \"{kvp.Value}\"\n\t}}"), - UScriptArray array => array.Properties.Select(p => $"\t\"{GetLineOfText(p)}\""), - _ => throw new ArgumentOutOfRangeException(nameof(value), value, null) - }; - - text = "[\n" + string.Join(",\n", inner) + "\n\t]"; - break; - case FMulticastScriptDelegate multicast: - text = multicast.InvocationList.Length == 0 ? "[]" : $"[{string.Join(", ", multicast.InvocationList.Select(x => $"\"{x.FunctionName}\""))}]"; - break; - case bool: - text = value.ToString()?.ToLowerInvariant(); - break; - } - - return text ?? value.ToString(); - } - - ShouldAppend(GetLineOfText(propertyValue)); - } - - foreach (var field in blueprint.ChildProperties) - { - if (field is not FProperty property || strings.Contains(property.Name.Text)) continue; - - var propertyName = property.Name.ToString().Replace(" ", ""); - var type = KismetExtensions.GetPropertyType(property); - - var prefix = ""; - switch (property) - { - case FFieldPathProperty pathProp: - prefix = pathProp.PropertyClass.ToString().GetPrefix(); - break; - case FObjectProperty objectProp: - prefix = objectProp.PropertyClass.ToString().GetPrefix(); - break; - } - - outputBuilder.AppendLine($"\t{prefix}{type}{(KismetExtensions.isPointer(property) ? '*' : "")} {propertyName} = {propertyName}fmodelholder;"); - } - - { - var funcMapOrder = blueprint?.FuncMap?.Keys.Select(fname => fname.ToString()).ToList(); - var functions = pkg.ExportsLazy - .Where(e => e.Value is UFunction) - .Select(e => (UFunction) e.Value) - .OrderBy(f => - { - if (funcMapOrder != null) - { - var functionName = f.Name.ToString(); - int index = funcMapOrder.IndexOf(functionName); - return index >= 0 ? index : int.MaxValue; - } - - return int.MaxValue; - }) - .ThenBy(f => f.Name.ToString()) - .ToList(); - - var jumpCodeOffsetsMap = new Dictionary>(); - - foreach (var function in functions.AsEnumerable().Reverse()) - { - if (function?.ScriptBytecode == null) - continue; - - foreach (var property in function.ScriptBytecode) - { - string label = string.Empty; - int offset = 0; - - switch (property.Token) - { - case EExprToken.EX_JumpIfNot: - label = ((EX_JumpIfNot) property).ObjectPath?.ToString()?.Split('.').Last().Split('[')[0]; - offset = (int) ((EX_JumpIfNot) property).CodeOffset; - break; - - case EExprToken.EX_Jump: - label = ((EX_Jump) property).ObjectPath?.ToString()?.Split('.').Last().Split('[')[0]; - offset = (int) ((EX_Jump) property).CodeOffset; - break; - - case EExprToken.EX_LocalFinalFunction: - { - EX_FinalFunction op = (EX_FinalFunction) property; - label = op.StackNode?.Name?.Split('.').Last().Split('[')[0]; - - if (op is { Parameters: [EX_IntConst intConst] }) - offset = intConst.Value; - break; - } - } - - if (!string.IsNullOrEmpty(label)) - { - if (!jumpCodeOffsetsMap.TryGetValue(label, out var list)) - jumpCodeOffsetsMap[label] = list = new List(); - - list.Add(offset); - } - } - } - - foreach (var function in functions) - { - string argsList = ""; - string returnFunc = "void"; - if (function?.ChildProperties != null) - { - foreach (FProperty property in function.ChildProperties) - { - var name = property.Name.ToString(); - var plainName = property.Name.PlainText; - var prefix = ""; - switch (property) - { - case FFieldPathProperty pathProp: - prefix = pathProp.PropertyClass.ToString().GetPrefix(); - break; - case FObjectProperty objectProp: - prefix = objectProp.PropertyClass.ToString().GetPrefix(); - break; - } - var type = KismetExtensions.GetPropertyType(property); - var isConst = property.PropertyFlags.HasFlag(EPropertyFlags.ConstParm); - var isOut = property.PropertyFlags.HasFlag(EPropertyFlags.OutParm); - var isEdit = property.PropertyFlags.HasFlag(EPropertyFlags.Edit); - - if (plainName == "ReturnValue") - { - returnFunc = $"{(isConst ? "const " : "")}{prefix}{type}{(KismetExtensions.isPointer(property) ? '*' : "")}"; - continue; - } - - bool uselessIgnore = name.EndsWith("_ReturnValue") || name.StartsWith("CallFunc_") || name.StartsWith("K2Node_") || name.StartsWith("Temp_"); // read variable name - - if (uselessIgnore && !isEdit) - continue; - - var strippedVerseName = Regex.Replace(name, @"^__verse_0x[0-9A-Fa-f]+_", ""); - argsList += $"{(isConst ? "const " : "")}{prefix}{type}{(KismetExtensions.isPointer(property) ? '*' : "")}{(isOut ? '&' : "")} {strippedVerseName}, "; - } - } - argsList = argsList.TrimEnd(',', ' '); - - outputBuilder.AppendLine($"\n\t{returnFunc} {function.Name.Replace(" ", "")}({argsList})\n\t{{"); - if (function?.ScriptBytecode != null) - { - var jumpCodeOffsets = jumpCodeOffsetsMap.TryGetValue(function.Name, out var list) ? list : new List(); - foreach (KismetExpression property in function.ScriptBytecode) - { - KismetExtensions.ProcessExpression(property.Token, property, outputBuilder, jumpCodeOffsets); - } - } - else - { - outputBuilder.Append("\n\t // No Bytecode (Make sure \"Serialize Script Bytecode\" is enabled \n\n"); - outputBuilder.Append("\t}\n"); - } - } - - outputBuilder.Append("\n\n}"); - } + cpp += blueprint.DecompileBlueprintToPseudo(idkhowtogetitwithoutthis); } - var cpp = Regex.Replace(outputBuilder.ToString(), @"\w+fmodelholder", "nullptr"); TabControl.SelectedTab.SetDocumentText(cpp, false, false); } diff --git a/FModel/ViewModels/SearchViewModel.cs b/FModel/ViewModels/SearchViewModel.cs index 15585911..35cb9bc3 100644 --- a/FModel/ViewModels/SearchViewModel.cs +++ b/FModel/ViewModels/SearchViewModel.cs @@ -4,13 +4,38 @@ using System.ComponentModel; using System.Linq; using System.Text.RegularExpressions; using System.Windows.Data; +using System.Windows.Input; using CUE4Parse.FileProvider.Objects; using FModel.Framework; namespace FModel.ViewModels; +public class RelayCommand : ICommand +{ + private readonly Action _execute; + private readonly Func? _canExecute; + + public event EventHandler? CanExecuteChanged; + + public RelayCommand(Action execute, Func? canExecute = null) + { + _execute = execute ?? throw new ArgumentNullException(nameof(execute)); + _canExecute = canExecute; + } + public bool CanExecute(object? parameter) => _canExecute?.Invoke() ?? true; + public void Execute(object? parameter) => _execute(); + +} + public class SearchViewModel : ViewModel { + public enum ESortSizeMode + { + None, + Ascending, + Descending + } + private string _filterText; public string FilterText { @@ -32,6 +57,29 @@ public class SearchViewModel : ViewModel set => SetProperty(ref _hasMatchCaseEnabled, value); } + private ESortSizeMode _currentSortSizeMode = ESortSizeMode.None; + public ESortSizeMode CurrentSortSizeMode + { + get => _currentSortSizeMode; + set => SetProperty(ref _currentSortSizeMode, value); + } + + public void CycleSortSizeMode() + { + CurrentSortSizeMode = CurrentSortSizeMode switch + { + ESortSizeMode.None => ESortSizeMode.Ascending, + ESortSizeMode.Ascending => ESortSizeMode.Descending, + ESortSizeMode.Descending => ESortSizeMode.None, + _ => ESortSizeMode.None + }; + + RefreshFilter(); + } + + private RelayCommand? _sortSizeModeCommand; + public ICommand SortSizeModeCommand => _sortSizeModeCommand ??= new RelayCommand(CycleSortSizeMode); + public int ResultsCount => SearchResults?.Count ?? 0; public RangeObservableCollection SearchResults { get; } public ICollectionView SearchResultsView { get; } @@ -48,6 +96,14 @@ public class SearchViewModel : ViewModel SearchResultsView.Filter = e => ItemFilter(e, FilterText.Trim().Split(' ')); else SearchResultsView.Refresh(); + + SearchResultsView.SortDescriptions.Clear(); + + if (CurrentSortSizeMode != ESortSizeMode.None) + SearchResultsView.SortDescriptions.Add(new SortDescription(nameof(GameFile.Size), + CurrentSortSizeMode == ESortSizeMode.Ascending + ? ListSortDirection.Ascending + : ListSortDirection.Descending)); } private bool ItemFilter(object item, IEnumerable filters) @@ -62,4 +118,4 @@ public class SearchViewModel : ViewModel if (!HasMatchCaseEnabled) o |= RegexOptions.IgnoreCase; return new Regex(FilterText, o).Match(entry.Path).Success; } -} +} \ No newline at end of file diff --git a/FModel/Views/Resources/Resources.xaml b/FModel/Views/Resources/Resources.xaml index 1d1500ed..c42ee085 100644 --- a/FModel/Views/Resources/Resources.xaml +++ b/FModel/Views/Resources/Resources.xaml @@ -70,6 +70,7 @@ M1.8 6q-.525 0-.887-.35Q.55 5.3.55 4.8V4q0-1.425 1.012-2.438Q2.575.55 4 .55h.8q.5 0 .85.362.35.363.35.888 0 .5-.35.85T4.8 3H4q-.425 0-.712.287Q3 3.575 3 4v.8q0 .5-.35.85T1.8 6ZM4 23.45q-1.425 0-2.438-1.012Q.55 21.425.55 20v-.8q0-.5.363-.85.362-.35.887-.35.5 0 .85.35t.35.85v.8q0 .425.288.712Q3.575 21 4 21h.8q.5 0 .85.35t.35.85q0 .525-.35.887-.35.363-.85.363Zm15.2 0q-.5 0-.85-.363-.35-.362-.35-.887 0-.5.35-.85t.85-.35h.8q.425 0 .712-.288Q21 20.425 21 20v-.8q0-.5.35-.85t.85-.35q.525 0 .888.35.362.35.362.85v.8q0 1.425-1.012 2.438Q21.425 23.45 20 23.45ZM22.2 6q-.5 0-.85-.35T21 4.8V4q0-.425-.288-.713Q20.425 3 20 3h-.8q-.5 0-.85-.35T18 1.8q0-.525.35-.888.35-.362.85-.362h.8q1.425 0 2.438 1.012Q23.45 2.575 23.45 4v.8q0 .5-.362.85-.363.35-.888.35ZM12 17.35l1-.575v-4.1l3.55-2.075V9.425l-1-.575L12 10.925 8.45 8.85l-1 .575V10.6L11 12.675v4.1Zm-1.325 2.325-4.55-2.65q-.625-.35-.975-.963-.35-.612-.35-1.337V9.45q0-.725.35-1.337.35-.613.975-.963l4.55-2.65Q11.3 4.15 12 4.15t1.325.35l4.55 2.65q.625.35.975.963.35.612.35 1.337v5.275q0 .725-.35 1.337-.35.613-.975.963l-4.55 2.65q-.625.35-1.325.35t-1.325-.35Z M3.5 1.75v11.5c0 .09.048.173.126.217a.75.75 0 0 1-.752 1.298A1.748 1.748 0 0 1 2 13.25V1.75C2 .784 2.784 0 3.75 0h5.586c.464 0 .909.185 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0 1 12.25 15h-.5a.75.75 0 0 1 0-1.5h.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177L9.513 1.573a.25.25 0 0 0-.177-.073H7.25a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5h-3a.25.25 0 0 0-.25.25Zm3.75 8.75h.5c.966 0 1.75.784 1.75 1.75v3a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1-.75-.75v-3c0-.966.784-1.75 1.75-1.75ZM6 5.25a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 6 5.25Zm.75 2.25h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 6.75A.75.75 0 0 1 8.75 6h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 6.75ZM8.75 3h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM8 9.75A.75.75 0 0 1 8.75 9h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 8 9.75Zm-1 2.5v2.25h1v-2.25a.25.25 0 0 0-.25-.25h-.5a.25.25 0 0 0-.25.25Z M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z + M8 16H4l6 6V2H8zm6-11v17h2V8h4l-6-6z