diff --git a/FModel/Extensions/KismetExtensions.cs b/FModel/Extensions/KismetExtensions.cs index 0dde9710..c84f06ed 100644 --- a/FModel/Extensions/KismetExtensions.cs +++ b/FModel/Extensions/KismetExtensions.cs @@ -17,7 +17,7 @@ namespace FModel.Extensions; public static class KismetExtensions { - public static string GetPrefix(string type, string extra = "") + public static string GetPrefix(string type, string extra = "") // todo: implement better handling { return type switch { @@ -79,14 +79,18 @@ public static class KismetExtensions } public static string GetPropertyType(FProperty? property) { - if (property is null) - return "None"; + if (property is null) return "None"; + + bool isPointer(FProperty p) => + p.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || + property.PropertyFlags.HasFlag(EPropertyFlags.ReferenceParm) || + p.PropertyFlags.HasFlag(EPropertyFlags.ContainsInstancedReference); return property switch { - FSetProperty set => $"TSet<{GetPrefix(set.ElementProp.GetType().Name)}{GetPropertyType(set.ElementProp)}{(set.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || property.PropertyFlags.HasFlag(EPropertyFlags.ReferenceParm) || set.PropertyFlags.HasFlag(EPropertyFlags.ContainsInstancedReference) ? "*" : string.Empty)}>", - FMapProperty map => $"TMap<{GetPrefix(map.ValueProp.GetType().Name)}{GetPropertyType(map.KeyProp)}, {GetPrefix(map.ValueProp.GetType().Name)}{GetPropertyType(map.ValueProp)}{(map.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || property.PropertyFlags.HasFlag(EPropertyFlags.ReferenceParm) || map.PropertyFlags.HasFlag(EPropertyFlags.ContainsInstancedReference) ? "*" : string.Empty)}>", - FArrayProperty array => $"TArray<{GetPrefix(array.Inner.GetType().Name)}{GetPropertyType(array.Inner)}{(array.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || property.PropertyFlags.HasFlag(EPropertyFlags.ReferenceParm) || array.PropertyFlags.HasFlag(EPropertyFlags.ContainsInstancedReference) || GetPropertyProperty(array.Inner.GetType().Name) ? "*" : string.Empty)}>", + FSetProperty s => $"TSet<{GetPrefix(s.ElementProp.GetType().Name)}{GetPropertyType(s.ElementProp)}{(isPointer(s) ? "*" : "")}>", + FMapProperty m => $"TMap<{GetPrefix(m.KeyProp.GetType().Name)}{GetPropertyType(m.KeyProp)}, {GetPrefix(m.ValueProp.GetType().Name)}{GetPropertyType(m.ValueProp)}{(isPointer(m) ? "*" : "")}>", + FArrayProperty a => $"TArray<{GetPrefix(a.Inner.GetType().Name)}{GetPropertyType(a.Inner)}{(isPointer(a) || GetPropertyProperty(a.Inner.GetType().Name) ? "*" : "")}>", _ => GetPropertyType((object)property) }; } @@ -224,14 +228,7 @@ public static class KismetExtensions var destination = ProcessTextProperty(op.DestinationProperty, false); var variable = ProcessTextProperty(opp.Variable, false); - if (!isParameter) - { - outputBuilder.Append($"\t\t{(destination.Contains("K2Node_") ? $"UberGraphFrame->{destination}" : destination)} = {variable};\n\n"); // hardcoded but works - } - else - { - outputBuilder.Append($"\t\t{(destination.Contains("K2Node_") ? $"UberGraphFrame->{destination}" : destination)} = {variable}"); - } + outputBuilder.Append($"\t\t{(destination.Contains("K2Node_") ? "UberGraphFrame->" + destination : destination)} = {variable}{(!isParameter ? ";\n\n" : "")}"); // Hardcoded but works break; } case EExprToken.EX_LocalFinalFunction: @@ -366,7 +363,7 @@ public static class KismetExtensions } case EExprToken.EX_Cast: { - EX_Cast op = (EX_Cast) expression;// support CST_ObjectToInterface when I have an example of how it works + 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) { @@ -474,7 +471,7 @@ public static class KismetExtensions { 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 + ProcessExpression(element.Token, element, outputBuilder, jumpCodeOffsets); // sometimes the start of an array is a byte not a variable if (i < op.Elements.Length - 1) { @@ -499,7 +496,7 @@ public static class KismetExtensions { 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 + 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) { @@ -624,7 +621,7 @@ public static class KismetExtensions 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. + 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) @@ -638,8 +635,8 @@ public static class KismetExtensions } outputBuilder.Append(">(\""); var resolvedObject = op?.Value?.ResolvedObject; - var outerString = resolvedObject?.Outer?.ToString()?.Replace("'", "") ?? "UNKNOWN"; - var outerClassString = resolvedObject?.Class?.ToString()?.Replace("'", "") ?? "UNKNOWN"; + 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); @@ -866,7 +863,7 @@ public static class KismetExtensions } else { - outputBuilder.Append(op.Value); + outputBuilder.Append(op.Value); // impossible to reach? } } break; @@ -1024,6 +1021,7 @@ public static class KismetExtensions // 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 diff --git a/FModel/Resources/Cpp.xshd b/FModel/Resources/Cpp.xshd index 5c3cc352..f02e55c0 100644 --- a/FModel/Resources/Cpp.xshd +++ b/FModel/Resources/Cpp.xshd @@ -1,240 +1,147 @@ - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + - - + + - - BlueprintGeneratedClass - Class - FSoftObjectPath - UScriptArray - NavmeshGeneratorComponent - EndGameComponent - USceneComponent + + + + UCLASS + USTRUCT + UPROPERTY + UFUNCTION + GENERATED_BODY + GENERATED_USTRUCT_BODY + GENERATED_UCLASS_BODY - - bool - char - unsigned - union - virtual - double - float - short - signed - void - class - enum - struct - - - \b(BlueprintGeneratedClass|Class|FSoftObjectPath|UScriptArray|NavmeshGeneratorComponent|EndGameComponent|USceneComponent)\b - - ABP_[A-Za-z0-9_]+_C - - \bF[A-Z][A-Za-z0-9_]*\b - \bU[A-Z][A-Za-z0-9_]*\b - \bA[A-Z][A-Za-z0-9_]*\b - \bE[A-Z][A-Za-z0-9_]*\b - - Label_[0-9]+ - - CallFunc_[A-Za-z0-9_]+ - K2Node_[A-Za-z0-9_]+ - Temp_delegate_Variable(_[0-9]+)? - - ExecuteUbergraph_[A-Za-z0-9_]+ - UserConstructionScript - ReceiveBeginPlay - OnBeginFadeOut - .*__UpdateFunc - .*__FinishedFunc - - goto - nullptr - - FindObject<[A-Za-z0-9_]+> - - "[^"]*" - \b[0-9]+(\.[0-9]+)?\b - [\[\]\{\}] - - UKismetMathLibrary - UKismetSystemLibrary - - [?,.;()\[\]{}+\-/%*<>^=~!&]+ - - - __abstract - __box - __delegate - __gc - __identifier - __nogc - __pin - __property - __sealed - __try_cast - __typeof - __value - __event - __hook - __raise - __unhook - __interface - ref class - ref struct - value class - value struct - interface class - interface struct - enum class - enum struct - delegate - event - property - abstract - override - sealed - generic - where - finally - for each - gcnew - in - initonly - literal - nullptr - - - - this - - - and - and_eq - bitand - bitor - new - not - not_eq - or - or_eq - xor - xor_eq - - - using - namespace - - - friend - - - private - protected - public - const - volatile - static - - - true - false - NULL - - - break - case - catch - const_cast - continue - default - delete - dynamic_cast - else - explicit - export - extern - false - for - friend - goto - if - mutable - namespace - new - operator - private - protected - public - register - reinterpret_cast - return - sizeof - static_cast - template - throw - try - typedef - typeid - typename - using - virtual - volatile - while - - - do - for - while - break - continue - goto return throw - - try - catch - throw - finally - - + + + + void + int + Int8 + Int16 + Int32 + Int64 + uint + UInt16 + UInt32 + UInt64 + float + double + bool + return if else + for + while + do switch case - default break continue - return + namespace + using + typedef + sizeof + new + delete + class + struct + enum + template + typename + const + static + mutable + volatile + override + virtual + explicit + friend + inline + constexpr + + + nullptr + + + + true + True + false + False + NULL + + + + public + protected + private + + + + this + + + + (?<=[A-Za-z0-9_>&\]])&(?=\s*[A-Za-z_<]) + + \bLabel_\d+: + + + \b(0x[0-9a-fA-F]+|[0-9]+(\.[0-9]+)?)\b + + \bU[A-Z][A-Za-z0-9_]*\b(?=::) + [A-Za-z_][A-Za-z0-9_]*\s*(?=\() + + [\[\]\{\}] + + + \b[A-Za-z_][A-Za-z0-9_]*\b(?=<) + + + \b[A-Z][A-Za-z0-9_]*(?:<[^>]+>)?[*&]?(?=\s+[*&]?[A-Za-z_][A-Za-z0-9_]*\s*(=|;|\)|,)) + + + (?<=<)\s*[A-Z][A-Za-z0-9_]*(?:<[^>]+>)?[*&]?\s*(?=[>,]) + + + \b(?<=class\s)[A-Za-z_][A-Za-z0-9_]* + + + \b(?<=public\s)[A-Za-z_][A-Za-z0-9_]* + + + \b(?:T|F|U|E)[A-Z][A-Za-z0-9_]*(?:<[^>]+>)?[*&]?(?=\s+[*&]?[A-Za-z_][A-Za-z0-9_]*\s*(?:=|,|\))) + \b(?<=[,(]\s*const\s)(?:T|F|U)[A-Z][A-Za-z0-9_]*[*&]?(?=\s) + + + \b(?<=\()\s*[TUF][A-Z][A-Za-z0-9_]*(?=\s*<) + \b(?<=\()\s*[TUF][A-Z][A-Za-z0-9_]*[*&]?(?=\s) + \b(?<=\(\s*const\s)[TUF][A-Z][A-Za-z0-9_]*[*&]?(?=\s) + diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 638707c4..db0b099f 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -976,7 +976,7 @@ public class CUE4ParseViewModel : ViewModel continue; var dummy = ((AbstractUePackage) pkg).ConstructObject(pointer.Class?.Object?.Value as UStruct, pkg); - if (dummy is not UBlueprintGeneratedClass || pointer.Object.Value is not UBlueprintGeneratedClass blueprint) + if (dummy is not UClass || pointer.Object.Value is not UClass blueprint) continue; var typePrefix = KismetExtensions.GetPrefix(blueprint.GetType().Name); @@ -991,7 +991,7 @@ public class CUE4ParseViewModel : ViewModel var propertyName = property.Name.ToString(); var propertyValue = property.Tag?.GenericValue; strings.Add(propertyName); - string placeholder = $"{propertyName}placeholder"; + string placeholder = $"{propertyName}fmodelholder"; // spelling mistake is intended void ShouldAppend(string value) { @@ -1092,19 +1092,19 @@ public class CUE4ParseViewModel : ViewModel var type = KismetExtensions.GetPropertyType(property); var prefix = KismetExtensions.GetPrefix(property.GetType().Name); - string whatever; + string pointerIdentifier; if (property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || property.PropertyFlags.HasFlag(EPropertyFlags.ReferenceParm) || KismetExtensions.GetPropertyProperty(property)) { - whatever = "*"; + pointerIdentifier = "*"; } else { - whatever = string.Empty; + pointerIdentifier = string.Empty; } - outputBuilder.AppendLine($"\t{prefix}{type}{whatever} {propertyName} = {propertyName}placeholder;"); + outputBuilder.AppendLine($"\t{prefix}{type}{pointerIdentifier} {propertyName} = {propertyName}fmodelholder;"); } { @@ -1117,8 +1117,8 @@ public class CUE4ParseViewModel : ViewModel if (funcMapOrder != null) { var functionName = f.Name.ToString(); - int indexx = funcMapOrder.IndexOf(functionName); - return indexx >= 0 ? indexx : int.MaxValue; + int index = funcMapOrder.IndexOf(functionName); + return index >= 0 ? index : int.MaxValue; } return int.MaxValue; @@ -1171,8 +1171,6 @@ public class CUE4ParseViewModel : ViewModel } } - - foreach (var function in functions) { string argsList = ""; @@ -1181,21 +1179,28 @@ public class CUE4ParseViewModel : ViewModel { foreach (FProperty property in function.ChildProperties) { - if (property.Name.PlainText == "ReturnValue") + var name = property.Name.ToString(); + var plainName = property.Name.PlainText; + var prefix = KismetExtensions.GetPrefix(property.GetType().Name); + var type = KismetExtensions.GetPropertyType(property); + var isConst = property.PropertyFlags.HasFlag(EPropertyFlags.ConstParm); + var isOut = property.PropertyFlags.HasFlag(EPropertyFlags.OutParm); + var isInstanced = property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference); + var isEdit = property.PropertyFlags.HasFlag(EPropertyFlags.Edit); + + if (plainName == "ReturnValue") { - returnFunc = - $"{(property.PropertyFlags.HasFlag(EPropertyFlags.ConstParm) ? "const " : string.Empty)}{KismetExtensions.GetPrefix(property.GetType().Name)}{KismetExtensions.GetPropertyType(property)}{(property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || KismetExtensions.GetPrefix(property.GetType().Name) == "U" ? "*" : string.Empty)}"; - } - else if (!(property.Name.ToString().EndsWith("_ReturnValue") || - property.Name.ToString().StartsWith("CallFunc_") || - property.Name.ToString().StartsWith("K2Node_") || - property.Name.ToString() - .StartsWith("Temp_")) || // removes useless args - property.PropertyFlags.HasFlag(EPropertyFlags.Edit)) - { - argsList += - $"{(property.PropertyFlags.HasFlag(EPropertyFlags.ConstParm) ? "const " : string.Empty)}{KismetExtensions.GetPrefix(property.GetType().Name)}{KismetExtensions.GetPropertyType(property)}{(property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || KismetExtensions.GetPrefix(property.GetType().Name) == "U" ? "*" : string.Empty)}{(property.PropertyFlags.HasFlag(EPropertyFlags.OutParm) ? "&" : string.Empty)} {Regex.Replace(property.Name.ToString(), @"^__verse_0x[0-9A-Fa-f]+_", "")}, "; + returnFunc = $"{(isConst ? "const " : "")}{prefix}{type}{(isInstanced || prefix == "U" ? "*" : "")}"; + 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}{(isInstanced || prefix == "U" ? "*" : "")}{(isOut ? "&" : "")} {strippedVerseName}, "; } } argsList = argsList.TrimEnd(',', ' '); @@ -1211,7 +1216,7 @@ public class CUE4ParseViewModel : ViewModel } else { - outputBuilder.Append("\n\t // This function does not have Bytecode \n\n"); + outputBuilder.Append("\n\t // No Bytecode (Make sure \"Serialize Script Bytecode\" is enabled \n\n"); outputBuilder.Append("\t}\n"); } } @@ -1220,7 +1225,7 @@ public class CUE4ParseViewModel : ViewModel } } - var cpp = Regex.Replace(outputBuilder.ToString(), @"\w+placeholder", "nullptr"); + var cpp = Regex.Replace(outputBuilder.ToString(), @"\w+fmodelholder", "nullptr"); TabControl.SelectedTab.SetDocumentText(cpp, false, false); }