private string ResolveNameConflict(UField field, string name) { UStruct unrealStruct = field.GetOwnerStruct(); if ((field as UFunction) != null) { // GetOwnerStruct will return itself if it is a UStruct (which is true for UFunction) unrealStruct = field.GetOwnerClass(); } if (unrealStruct != null) { StructInfo structInfo = GetStructInfo(unrealStruct); if (structInfo != null) { return(structInfo.ResolveNameConflict(field, name)); } } return(name); }
private bool IsBlittableStructProperty(UStructProperty property) { if (property == null) { return(false); } UStruct unrealStruct = property.Struct; if (unrealStruct != null) { StructInfo structInfo; if (structInfos.TryGetValue(unrealStruct, out structInfo)) { return(structInfo.IsBlittable); } structInfo = GetStructInfo(unrealStruct); return(structInfo.IsBlittable); } return(false); }
public StructInfo(CodeGenerator codeGenerator, UStruct unrealStruct, bool isBlueprintType) { this.codeGenerator = codeGenerator; IsBlueprintType = isBlueprintType; Struct = unrealStruct; ScriptStruct = unrealStruct as UScriptStruct; Class = unrealStruct as UClass; IsClass = Class != null; IsStruct = ScriptStruct != null; IsInterface = unrealStruct.IsChildOf <UInterface>(); if (IsStruct) { // Start with a IsPlainOldData check for initial IsBlittable state. Is this enough? Or too verbose? // - May need to take into account non-zero constructor / EForceInit constructor if IsBlittable state // is used for construction. However since IsBlittable is only currently used to determine marshaling // using FromNative / ToNative on existing memory the ctor check shouldn't be required. // - The user can use StructDefault<T>.Value if they want a new native default instance of a struct // which will use the UScriptStruct.IsPODZeroInit check. IsBlittable = ScriptStruct.StructFlags.HasFlag(EStructFlags.IsPlainOldData); if (codeGenerator.Settings.AlwaysGenerateStructsAsClasses) { StructAsClass = true; } else if (codeGenerator.Settings.StructsAsClassesByPath.Contains(unrealStruct.GetPathName().ToLower())) { StructAsClass = true; } if (StructAsClass) { // Can't use blittable functions if the struct is being generated as a class IsBlittable = false; } } }
/// <summary> /// Gets the UStruct/UClass for the given path (e.g. "/Script/Engine.HitResult") /// </summary> /// <param name="path">The path of the object/struct</param> /// <returns>The UStruct/UClass for the given path</returns> public static UStruct GetStructOrClass(string path) { UStruct foundStruct = UObject.FindObject <UStruct>(UObject.AnyPackage, path); if (foundStruct == null) { // Look for redirectors FName newPath = FLinkerLoad.FindNewNameForStruct(new FName(path)); if (newPath != FName.None) { foundStruct = UObject.FindObject <UStruct>(UObject.AnyPackage, newPath.ToString()); } if (foundStruct == null) { newPath = FLinkerLoad.FindNewNameForClass(new FName(path), false); if (newPath != FName.None) { foundStruct = UObject.FindObject <UClass>(UObject.AnyPackage, newPath.ToString()); } } } return(foundStruct); }
/// <summary> /// Sets the IsValid state for the given struct based on the state of all properties IsValid state /// (used when generating with safeguards enabled) /// </summary> private void AppendStructIsValid(CSharpTextBuilder builder, string structTypeName, StructInfo structInfo, UStruct parentStruct) { if (!Settings.GenerateIsValidSafeguards) { return; } List <UProperty> allProperties = new List <UProperty>(); foreach (UProperty property in structInfo.GetProperties()) { if (!structInfo.IsCollapsedProperty(property)) { allProperties.Add(property); } } if (parentStruct != null && (Settings.InlineBaseStruct || structInfo.StructAsClass)) { UScriptStruct tempParentStruct = parentStruct as UScriptStruct; while (tempParentStruct != null) { StructInfo tempParentStructInfo = GetStructInfo(tempParentStruct); if (tempParentStructInfo != null) { foreach (UProperty property in tempParentStructInfo.GetProperties()) { if (!tempParentStructInfo.IsCollapsedProperty(property)) { allProperties.Add(property); } } } tempParentStruct = tempParentStruct.GetSuperStruct() as UScriptStruct; } } StringBuilder isValidCheck = new StringBuilder(); isValidCheck.Append(Settings.VarNames.ClassAddress + " != IntPtr.Zero"); foreach (UProperty property in allProperties) { string propertyName = GetMemberName(property, structInfo.GetPropertyName(property)); isValidCheck.Append(" && " + propertyName + Settings.VarNames.IsValid); } isValidCheck.Insert(0, structTypeName + Settings.VarNames.IsValid + " = "); isValidCheck.Append(";"); builder.AppendLine(isValidCheck.ToString()); builder.AppendLine(Names.NativeReflection_LogStructIsValid + "(\"" + structInfo.Struct.GetPathName() + "\", " + structTypeName + Settings.VarNames.IsValid + ");"); }
private void GenerateCodeForStruct(UnrealModuleInfo module, UStruct unrealStruct) { bool isBlueprintType = unrealStruct.IsA <UUserDefinedStruct>() || unrealStruct.IsA <UBlueprintGeneratedClass>(); StructInfo structInfo = GetStructInfo(unrealStruct, isBlueprintType); string typeName = GetTypeName(unrealStruct); UnrealModuleType moduleAssetType; string currentNamespace = GetModuleNamespace(unrealStruct, out moduleAssetType); List <string> namespaces = GetDefaultNamespaces(); CSharpTextBuilder builder = new CSharpTextBuilder(Settings.IndentType); if (!string.IsNullOrEmpty(currentNamespace)) { builder.AppendLine("namespace " + currentNamespace); builder.OpenBrace(); } string accessSpecifier = "public"; StringBuilder modifiers = new StringBuilder(accessSpecifier); if (Settings.UseAbstractTypes && structInfo.IsClass && structInfo.Class.HasAnyClassFlags(EClassFlags.Abstract)) { modifiers.Append(" abstract"); } StringBuilder baseTypeStr = new StringBuilder(); UStruct parentStruct = unrealStruct.GetSuperStruct(); if (parentStruct != null && parentStruct != UClass.GetClass <UInterface>() && unrealStruct != UClass.GetClass <UInterface>()) { baseTypeStr.Append(GetTypeName(parentStruct, namespaces)); } if (structInfo.IsClass) { foreach (FImplementedInterface implementedInterface in structInfo.Class.Interfaces) { if (baseTypeStr.Length > 0) { baseTypeStr.Append(", "); } baseTypeStr.Append(GetTypeName(implementedInterface.InterfaceClass, namespaces)); } } if (baseTypeStr.Length > 0) { baseTypeStr.Insert(0, " : "); } AppendDocComment(builder, unrealStruct, isBlueprintType); AppendAttribute(builder, unrealStruct, module, structInfo); if (structInfo.IsInterface) { System.Diagnostics.Debug.Assert(structInfo.Class.Interfaces.Length == 0, "TODO: Interfaces inheriting other interfaces"); string baseInterface = unrealStruct == UClass.GetClass <UInterface>() ? string.Empty : (baseTypeStr.Length == 0 ? " : " : ", ") + Names.IInterface; builder.AppendLine(modifiers + " interface " + typeName + baseTypeStr + baseInterface); } else if (structInfo.IsClass) { builder.AppendLine(modifiers + " partial class " + typeName + baseTypeStr); } else { if (structInfo.StructAsClass) { builder.AppendLine(modifiers + " partial class " + typeName + " : " + Names.StructAsClass); } else { if (structInfo.IsBlittable) { string structLayout = UpdateTypeNameNamespace("StructLayout", "System.Runtime.InteropServices", namespaces); string layoutKind = UpdateTypeNameNamespace("LayoutKind", "System.Runtime.InteropServices", namespaces); builder.AppendLine("[" + structLayout + "(" + layoutKind + ".Sequential)]"); } builder.AppendLine(modifiers + " partial struct " + typeName); } } builder.OpenBrace(); string typeNameEx = structInfo.IsInterface ? typeName + "Impl" : typeName; // Create a seperate builder for building the interface "Impl" class CSharpTextBuilder interfaceImplBuilder = null; if (structInfo.IsInterface) { interfaceImplBuilder = new CSharpTextBuilder(); interfaceImplBuilder.AppendLine(accessSpecifier + " sealed class " + typeNameEx + " : " + Names.IInterfaceImpl + ", " + typeName); interfaceImplBuilder.Indent(); // Move the indent to the same as builder for this point interfaceImplBuilder.OpenBrace(); // Open the class brace } // Create a seperate builder for properties which will be inserted into the native type info initializer CSharpTextBuilder offsetsBuilder = new CSharpTextBuilder(Settings.IndentType); offsetsBuilder.AppendLine("static " + typeNameEx + "()"); offsetsBuilder.IndentCount = builder.IndentCount;// Move the indent to the same as builder offsetsBuilder.OpenBrace(); offsetsBuilder.AppendLine("if (" + Names.UnrealTypes_CanLazyLoadNativeType + "(typeof(" + typeNameEx + ")))"); offsetsBuilder.OpenBrace(); offsetsBuilder.AppendLine(Settings.VarNames.LoadNativeType + "();"); offsetsBuilder.CloseBrace(); offsetsBuilder.AppendLine(Names.UnrealTypes_OnCCtorCalled + "(typeof(" + typeNameEx + "));"); offsetsBuilder.CloseBrace(); offsetsBuilder.AppendLine(); offsetsBuilder.AppendLine("static void " + Settings.VarNames.LoadNativeType + "()"); offsetsBuilder.OpenBrace(); if (structInfo.HasStaticFunction) { builder.AppendLine("static IntPtr " + Settings.VarNames.ClassAddress + ";"); offsetsBuilder.AppendLine(Settings.VarNames.ClassAddress + " = " + (structInfo.IsStruct ? Names.NativeReflection_GetStruct : Names.NativeReflection_GetClass) + "(\"" + unrealStruct.GetPathName() + "\");"); } else { offsetsBuilder.AppendLine("IntPtr " + Settings.VarNames.ClassAddress + " = " + (structInfo.IsStruct ? Names.NativeReflection_GetStruct : Names.NativeReflection_GetClass) + "(\"" + unrealStruct.GetPathName() + "\");"); } if (structInfo.StructAsClass) { offsetsBuilder.AppendLine(typeName + Settings.VarNames.StructAddress + " = " + Settings.VarNames.ClassAddress + ";"); } else if (structInfo.IsStruct) { offsetsBuilder.AppendLine(typeName + Settings.VarNames.StructSize + " = " + Names.NativeReflection_GetStructSize + "(" + Settings.VarNames.ClassAddress + ");"); } if (structInfo.IsStruct && parentStruct != null) { // Export base properties if (Settings.InlineBaseStruct || structInfo.StructAsClass) { UScriptStruct tempParentStruct = parentStruct as UScriptStruct; while (tempParentStruct != null) { StructInfo tempParentStructInfo = GetStructInfo(tempParentStruct); if (tempParentStructInfo != null) { foreach (UProperty property in tempParentStructInfo.GetProperties()) { if (!tempParentStructInfo.IsCollapsedProperty(property)) { GenerateCodeForProperty(module, builder, offsetsBuilder, property, tempParentStructInfo.IsBlueprintType, structInfo, namespaces, tempParentStructInfo.GetPropertyName(property)); } } } tempParentStruct = tempParentStruct.GetSuperStruct() as UScriptStruct; } } else { builder.AppendLine(GetTypeName(parentStruct, namespaces) + " Base;"); } } // Export properties foreach (UProperty property in structInfo.GetProperties()) { if (!structInfo.IsCollapsedProperty(property)) { GenerateCodeForProperty(module, builder, offsetsBuilder, property, isBlueprintType, structInfo, namespaces, structInfo.GetPropertyName(property)); } } foreach (CollapsedMember collapsedMember in structInfo.GetCollapsedMembers()) { GenerateCodeForProperty(module, builder, offsetsBuilder, collapsedMember, isBlueprintType, namespaces); } // Export functions List <ExtensionMethodInfo> extensionMethods = new List <ExtensionMethodInfo>(); foreach (UFunction function in structInfo.GetFunctions()) { if (!structInfo.IsCollapsedFunction(function)) { if (!structInfo.IsInterface) { // If this isn't an interface and the function can be made into an extension method then do so ExtensionMethodInfo extensionMethodInfo = ExtensionMethodInfo.Create(function); if (extensionMethodInfo != null) { extensionMethods.Add(extensionMethodInfo); } } if (function.HasAnyFunctionFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate)) { AppendDelegateSignature(module, builder, function, unrealStruct, isBlueprintType, namespaces); builder.AppendLine(); } else if (structInfo.IsInterface) { AppendFunctionOffsets(interfaceImplBuilder, offsetsBuilder, function, false, false, namespaces); AppendDocComment(builder, function, isBlueprintType); AppendAttribute(builder, function, module); builder.AppendLine(GetFunctionSignature(module, function, unrealStruct, namespaces) + ";"); builder.AppendLine(); // Always require a per-instance function address on the interfaces "Impl" class. // This isn't really required if the target function isn't an event but since we are working // with interfaces it is probably best to make sure functions are resolved properly. If we decide // to change this to not require a per-instance function address make sure to update AppendFunctionOffsets // which adds the per-instance function address to the class. Also update AssemblyRewriter.Interface.cs // Also update the "ResetInterface" code which always expects an per-instance address to reset. AppendAttribute(interfaceImplBuilder, function, module); interfaceImplBuilder.AppendLine(GetFunctionSignature(module, function, unrealStruct, null, "public", FunctionSigFlags.None, namespaces)); interfaceImplBuilder.OpenBrace(); AppendFunctionBody(interfaceImplBuilder, function, false, false, true, namespaces); interfaceImplBuilder.CloseBrace(); builder.AppendLine(); } else { AppendFunctionOffsets(builder, offsetsBuilder, function, false, false, namespaces); AppendDocComment(builder, function, isBlueprintType); AppendAttribute(builder, function, module); bool hasSuperFunction = function.GetSuperFunction() != null; if (function.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent) && !hasSuperFunction) { // Define the declaration method which will call the correct UFunction for the UObject instance builder.AppendLine(GetFunctionSignature(module, function, unrealStruct, namespaces)); builder.OpenBrace(); AppendFunctionBody(builder, function, false, false, true, namespaces); builder.CloseBrace(); builder.AppendLine(); } if (function.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent)) { if (!Settings.UseExplicitImplementationMethods) { // Used to hide the _Implementation method from being visible in intellisense builder.AppendLine("[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]"); } // Define the _Implementation method builder.AppendLine(GetFunctionSignatureImpl(module, function, unrealStruct, namespaces)); } else { builder.AppendLine(GetFunctionSignature(module, function, unrealStruct, namespaces)); } builder.OpenBrace(); AppendFunctionBody(builder, function, false, false, false, namespaces); builder.CloseBrace(); builder.AppendLine(); } } } if (structInfo.StructAsClass) { if (Settings.GenerateIsValidSafeguards) { builder.AppendLine("static bool " + typeName + Settings.VarNames.IsValid + ";"); // Append XXXX_IsValid = Prop1_IsValid && Prop2_IsValid && Prop3_IsValid...; AppendStructIsValid(offsetsBuilder, typeName, structInfo, parentStruct); } builder.AppendLine("static IntPtr " + typeName + Settings.VarNames.StructAddress + ";"); builder.AppendLine(); builder.AppendLine("protected override IntPtr GetStructAddress()"); builder.OpenBrace(); builder.AppendLine("return " + typeName + Settings.VarNames.StructAddress + ";"); builder.CloseBrace(); builder.AppendLine(); } else if (structInfo.IsStruct) { if (Settings.GenerateIsValidSafeguards && !structInfo.IsBlittable) { builder.AppendLine("static bool " + typeName + Settings.VarNames.IsValid + ";"); } builder.AppendLine("static int " + typeName + Settings.VarNames.StructSize + ";"); builder.AppendLine(); // Add the struct Copy() method (for non blittable structs) builder.AppendLine("public " + typeName + " " + Settings.VarNames.StructCopy + "()"); builder.OpenBrace(); builder.AppendLine(typeName + " result = this;"); foreach (UProperty property in structInfo.GetProperties()) { if (!structInfo.IsCollapsedProperty(property) && IsCollectionProperty(property)) { string propertyName = GetMemberName(property, structInfo.GetPropertyName(property)); builder.AppendLine("if (this." + propertyName + " != null)"); builder.OpenBrace(); UStructProperty structProperty = property as UStructProperty; StructInfo propertyStructInfo = structProperty == null || structProperty.Struct == null ? null : GetStructInfo(structProperty.Struct); if (propertyStructInfo != null && !propertyStructInfo.IsBlittable) { builder.AppendLine("result." + propertyName + " = new " + GetTypeName(property, namespaces) + "();"); builder.AppendLine("for (int i = 0; i < this." + propertyName + ".Count; ++i)"); builder.OpenBrace(); builder.AppendLine("result." + propertyName + ".Add(this." + propertyName + "[i]." + Settings.VarNames.StructCopy + "());"); builder.CloseBrace(); } else { builder.AppendLine("result." + propertyName + " = new " + GetTypeName(property, namespaces) + "(" + "this." + propertyName + ");"); } builder.CloseBrace(); } } if (Settings.InlineBaseStruct) { UScriptStruct tempParentStruct = parentStruct as UScriptStruct; while (tempParentStruct != null) { StructInfo tempParentStructInfo = GetStructInfo(tempParentStruct); if (tempParentStructInfo != null) { foreach (UProperty property in tempParentStructInfo.GetProperties()) { if (!tempParentStructInfo.IsCollapsedProperty(property) && IsCollectionProperty(property)) { string propertyName = GetMemberName(property, tempParentStructInfo.GetPropertyName(property)); builder.AppendLine("if (this." + propertyName + " != null)"); builder.OpenBrace(); builder.AppendLine("result." + propertyName + " = new " + GetTypeName(property, namespaces) + "(" + "this." + propertyName + ");"); builder.CloseBrace(); } } } tempParentStruct = tempParentStruct.GetSuperStruct() as UScriptStruct; } } builder.AppendLine("return result;"); builder.CloseBrace(); builder.AppendLine(); if (structInfo.IsBlittable) { // Validate the size of the blittable struct offsetsBuilder.AppendLine(Names.NativeReflection_ValidateBlittableStructSize + "(" + Settings.VarNames.ClassAddress + ", typeof(" + typeName + "));"); } else { if (Settings.GenerateIsValidSafeguards) { // Append XXXX_IsValid = Prop1_IsValid && Prop2_IsValid && Prop3_IsValid...; AppendStructIsValid(offsetsBuilder, typeName, structInfo, parentStruct); } builder.AppendLine("public static " + typeName + " FromNative(IntPtr nativeBuffer)"); builder.OpenBrace(); builder.AppendLine("return new " + typeName + "(nativeBuffer);"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public static void ToNative(IntPtr nativeBuffer, " + typeName + " value)"); builder.OpenBrace(); builder.AppendLine("value.ToNative(nativeBuffer);"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public static " + typeName + " FromNative(IntPtr nativeBuffer, int arrayIndex, IntPtr prop)"); builder.OpenBrace(); builder.AppendLine("return new " + typeName + "(nativeBuffer + (arrayIndex * " + typeName + Settings.VarNames.StructSize + "));"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public static void ToNative(IntPtr nativeBuffer, int arrayIndex, IntPtr prop, " + typeName + " value)"); builder.OpenBrace(); builder.AppendLine("value.ToNative(nativeBuffer + (arrayIndex * " + typeName + Settings.VarNames.StructSize + "));"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public void ToNative(IntPtr nativeStruct)"); builder.OpenBrace(); AppendStructMarshalerBody(builder, typeName, structInfo, parentStruct, true, namespaces); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public " + typeName + "(IntPtr nativeStruct)"); builder.OpenBrace(); /*if (Settings.UObjectAsBlittableType) * { * // UObject types will have an additional backing field which needs to be assigned before being able to * // assign the property * // - The alternative would be to modify the property assignment code to target the backing field instead of * // the property. This is probably the ideal way of doing it but we would need to use a different marshaler * // (BlittableTypeMarshaler<> instead of UObjectMarshaler<>) and ensure the marshaler change doesn't impact * // other generated code elsewhere. * foreach (UProperty property in structInfo.GetProperties()) * { * UObjectProperty objectProperty = property as UObjectProperty; * if (objectProperty != null) * { * string propertyName = GetMemberName(property, structInfo.GetPropertyName(property)); * builder.AppendLine(propertyName + Settings.VarNames.UObjectBlittableName + " = IntPtr.Zero;"); * } * } * }*/ AppendStructMarshalerBody(builder, typeName, structInfo, parentStruct, false, namespaces); builder.CloseBrace(); builder.AppendLine(); } } if (loadNativeTypeInjected.Contains(typeName)) { offsetsBuilder.AppendLine(Settings.VarNames.LoadNativeTypeInjected + "(" + Settings.VarNames.ClassAddress + ");"); } offsetsBuilder.CloseBrace(); // Add the offsets builder if it isn't empty (always required for structs due to struct size export) // Interfaces are built up seperately in a different class which must be added after the interface body. if (!structInfo.IsInterface && (structInfo.HasContent || structInfo.IsStruct)) { builder.AppendLine(offsetsBuilder.ToString()); builder.AppendLine(); } // Remove any trailing empty lines before adding the close brace builder.RemovePreviousEmptyLines(); builder.CloseBrace(); // Add the "Impl" wrapper class for interfaces. This is always required so that we have a default // interface implementation that we can call. if (structInfo.IsInterface) { if (structInfo.HasContent) { interfaceImplBuilder.AppendLine();// Whitespace // Add the ResetInterface method to reset the state of a pooled interface instance interfaceImplBuilder.AppendLine("public override void ResetInterface()"); interfaceImplBuilder.OpenBrace(); foreach (UFunction function in structInfo.GetFunctions()) { interfaceImplBuilder.AppendLine(GetFunctionName(function) + Settings.VarNames.InstanceFunctionAddress + " = IntPtr.Zero;"); } interfaceImplBuilder.CloseBrace(); interfaceImplBuilder.AppendLine(); // Whitespace } interfaceImplBuilder.AppendLine(offsetsBuilder.ToString()); // Add the offsets to the "Impl" class interfaceImplBuilder.CloseBrace(); // Add the close brace for the "Impl" class builder.AppendLine(); // Empty line between interface and "Impl" class builder.AppendLine(interfaceImplBuilder.ToString()); // Add the "Impl" class below the interface } if (!string.IsNullOrEmpty(currentNamespace)) { builder.CloseBrace(); } builder.InsertNamespaces(currentNamespace, namespaces, Settings.SortNamespaces); OnCodeGenerated(module, moduleAssetType, typeName, unrealStruct.GetPathName(), builder); if (extensionMethods.Count > 0) { GenerateCodeForExtensionMethods(module, unrealStruct, extensionMethods); } }
/// <summary> /// Determines the "blueprintability" of the given UStruct (BlueprintType / Blueprintable) /// </summary> private void GetBlueprintability(UStruct unrealStruct, out bool blueprintType, out bool blueprintable) { blueprintType = false; blueprintable = false; // See UEdGraphSchema_K2::IsAllowableBlueprintVariableType() // Engine\Source\Editor\BlueprintGraph\Private\EdGraphSchema_K2.cpp // True but not useful for what we are doing //if (unrealStruct.Address == Classes.UObject) //{ // blueprintType = true; // blueprintable = true; // return; //} if (unrealStruct.IsA <UBlueprintFunctionLibrary>()) { // UBlueprintFunctionLibrary functions are always visible (even if marked NotBlueprintType) blueprintType = true; } bool notBlueprintType = false; bool notBlueprintable = false; while (unrealStruct != null) { if (!notBlueprintType && (unrealStruct.GetBoolMetaData(MDClass.BlueprintType) || unrealStruct.GetBoolMetaData(MDClass.BlueprintSpawnableComponent))) { blueprintType = true; if (blueprintable || notBlueprintable) { break; } } if (!notBlueprintable && !blueprintable && unrealStruct.HasMetaData(MDClass.IsBlueprintBase)) { if (unrealStruct.GetBoolMetaData(MDClass.IsBlueprintBase)) { blueprintable = true; } else { notBlueprintable = true; } if (blueprintType || notBlueprintType) { break; } } if (!notBlueprintable && unrealStruct.GetBoolMetaData(MDClass.Blueprintable)) { blueprintable = true; if (blueprintType || notBlueprintType) { break; } } if (!blueprintType && unrealStruct.GetBoolMetaData(MDClass.NotBlueprintType)) { notBlueprintType = true; if (blueprintable || notBlueprintable) { break; } } if (!blueprintable && unrealStruct.GetBoolMetaData(MDClass.NotBlueprintable)) { notBlueprintable = true; if (blueprintType || notBlueprintType) { break; } } unrealStruct = unrealStruct.GetSuperStruct(); } }
private void AppendDelegateSignature(UnrealModuleInfo module, CSharpTextBuilder builder, UFunction function, UStruct owner, bool isBlueprintType, List <string> namespaces) { AppendDocComment(builder, function, isBlueprintType); AppendAttribute(builder, function, module); string delegateBaseTypeName = function.HasAnyFunctionFlags(EFunctionFlags.MulticastDelegate) ? Names.FMulticastDelegate : Names.FDelegate; string delegateTypeName = GetTypeNameDelegate(function); builder.AppendLine("public class " + delegateTypeName + " : " + delegateBaseTypeName + "<" + delegateTypeName + "." + Settings.VarNames.DelegateSignature + ">"); builder.OpenBrace(); builder.AppendLine(GetFunctionSignature( module, function, owner, Settings.VarNames.DelegateSignature, "public delegate", false, false, namespaces)); builder.AppendLine(); builder.AppendLine("public override " + Settings.VarNames.DelegateSignature + " " + Names.FDelegateBase_GetInvoker + "()"); builder.OpenBrace(); builder.AppendLine("return " + Settings.VarNames.DelegateInvoker + ";"); builder.CloseBrace(); builder.AppendLine(); string functionName = GetFunctionName(function); Dictionary <UProperty, string> paramNames = GetParamNames(function); // Offsets if (Settings.GenerateIsValidSafeguards) { builder.AppendLine("static bool " + functionName + Settings.VarNames.IsValid + ";"); } builder.AppendLine("static IntPtr " + functionName + Settings.VarNames.FunctionAddress + ";"); builder.AppendLine("static int " + functionName + Settings.VarNames.ParamsSize + ";"); foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; if (!parameter.HasAnyPropertyFlags(EPropertyFlags.Parm)) { continue; } AppendPropertyOffset(builder, functionName + "_" + paramName, parameter, true, namespaces); } // Add the native type info initializer to get the offsets builder.AppendLine("static void " + Settings.VarNames.LoadNativeType + "()"); builder.OpenBrace(); builder.AppendLine(functionName + Settings.VarNames.FunctionAddress + " = " + Names.NativeReflection_GetFunction + "(\"" + function.GetPathName() + "\");"); builder.AppendLine(functionName + Settings.VarNames.ParamsSize + " = " + Names.NativeReflection_GetFunctionParamsSize + "(" + functionName + Settings.VarNames.FunctionAddress + ");"); foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; if (!parameter.HasAnyPropertyFlags(EPropertyFlags.Parm)) { continue; } AppendPropertyOffsetNativeTypeLoader(builder, functionName + "_" + paramName, parameter, functionName); } if (Settings.GenerateIsValidSafeguards) { // XXXX_IsValid = param1_IsValid && param2_IsValid && param3_IsValid; string paramsValid = string.Join(" && ", paramNames.Values.Select(x => functionName + "_" + x + Settings.VarNames.IsValid)); if (!string.IsNullOrEmpty(paramsValid)) { paramsValid = " && " + paramsValid; } builder.AppendLine(functionName + Settings.VarNames.IsValid + " = " + functionName + Settings.VarNames.FunctionAddress + " != IntPtr.Zero" + paramsValid + ";"); builder.AppendLine(Names.NativeReflection_LogFunctionIsValid + "(\"" + function.GetPathName() + "\", " + functionName + Settings.VarNames.IsValid + ");"); } builder.CloseBrace(); builder.AppendLine(); builder.AppendLine(GetFunctionSignature( module, function, owner, Settings.VarNames.DelegateInvoker, "private", true, false, namespaces)); builder.OpenBrace(); AppendFunctionBody(builder, function, false, false, false, namespaces); builder.CloseBrace(); builder.CloseBrace(); }
private string GetFunctionSignatureImpl(UnrealModuleInfo module, UFunction function, UStruct owner, List <string> namespaces) { return(GetFunctionSignature(module, function, owner, null, null, false, true, namespaces)); }
private StructInfo GetStructInfo(UStruct unrealStruct) { bool isBlueprintType = unrealStruct.IsA <UUserDefinedStruct>() || unrealStruct.IsA <UBlueprintGeneratedClass>(); return(GetStructInfo(unrealStruct, isBlueprintType)); }
private void UpdateAvailableTypes(UField field) { if (field == null) { return; } System.Diagnostics.Debug.Assert(!field.IsA <UProperty>(), "Shouldn't have UProperty here"); if (field.IsA <UStruct>() || field.IsA <UEnum>()) { bool isNewElement = availableTypes.Add(field); if (!isNewElement) { return; } } if (Settings.ExportMode != CodeGeneratorSettings.CodeExportMode.Referenced) { return; } // Get all of the references from this struct UStruct unrealStruct = field as UStruct; if (unrealStruct != null) { bool isBlueprintType = unrealStruct.IsA <UUserDefinedStruct>() || unrealStruct.IsA <UBlueprintGeneratedClass>(); // Get struct references from parent class chain UStruct parentStruct = unrealStruct.GetSuperStruct(); while (parentStruct != null) { UpdateAvailableTypes(parentStruct); parentStruct = parentStruct.GetSuperStruct(); } // Get references from interfaces UClass unrealClass = field as UClass; if (unrealClass != null) { foreach (FImplementedInterface implementedInterface in unrealClass.Interfaces) { UpdateAvailableTypes(implementedInterface.InterfaceClass); } } // Get struct references from members foreach (UProperty property in unrealStruct.GetFields <UProperty>(false)) { if (CanExportProperty(property, unrealStruct, isBlueprintType)) { UpdateAvailableTypesProp(property); } } // Get struct references from function params (and return type) foreach (UFunction unrealFunction in unrealStruct.GetFields <UFunction>(false)) { if (CanExportFunction(unrealFunction, isBlueprintType)) { foreach (UProperty parameter in unrealFunction.GetFields <UProperty>()) { UpdateAvailableTypesProp(parameter); } } } } // This should be for global functions only (delegates) UFunction function = field as UFunction; if (function != null) { if (CanExportFunction(function, false)) { UStruct functionOwner = function.GetOuter() as UStruct; if (functionOwner != null) { UpdateAvailableTypes(functionOwner); } foreach (UProperty parameter in function.GetFields <UProperty>()) { UpdateAvailableTypesProp(parameter); } } } }
/// <summary> /// See if the offset of this property is below the supplied container size /// </summary> /// <param name="containerClass"></param> /// <returns></returns> public bool IsInContainer(UStruct containerClass) { return(Native_UProperty.IsInContainerStruct(Address, containerClass.Address)); }
private void ProcessCommon(EExprToken opcode) { switch (opcode) { case EExprToken.EX_PrimitiveCast: { // A type conversion. byte conversionType = ReadByte(); output.AppendLine(FmtOpcodeIndent(opcode) + "PrimitiveCast of type " + conversionType); AddIndent(); output.AppendLine(indents + " Argument:"); ProcessCastByte(conversionType); //@TODO: //Ar.Logf(TEXT("%s Expression:"), *Indents); //SerializeExpr( ScriptIndex ); break; } case EExprToken.EX_SetSet: { output.AppendLine(FmtOpcodeIndent(opcode) + "set set"); SerializeExpr(); ReadInt32(); while (SerializeExpr() != EExprToken.EX_EndSet) { // Set contents } break; } case EExprToken.EX_EndSet: { output.AppendLine(FmtOpcodeIndent(opcode) + "EX_EndSet"); break; } case EExprToken.EX_SetConst: { UProperty innerProp = ReadPointer <UProperty>(); int num = ReadInt32(); output.AppendLine(FmtOpcodeIndent(opcode) + "set set const - elements number: " + num + ", inner property: " + UObject.GetNameSafe(innerProp)); while (SerializeExpr() != EExprToken.EX_EndSetConst) { // Set contents } break; } case EExprToken.EX_EndSetConst: { output.AppendLine(FmtOpcodeIndent(opcode) + "EX_EndSetConst"); break; } case EExprToken.EX_SetMap: { output.AppendLine(FmtOpcodeIndent(opcode) + "set map"); SerializeExpr(); ReadInt32(); while (SerializeExpr() != EExprToken.EX_EndMap) { // Map contents } break; } case EExprToken.EX_EndMap: { output.AppendLine(FmtOpcodeIndent(opcode) + "EX_EndMap"); break; } case EExprToken.EX_MapConst: { UProperty keyProp = ReadPointer <UProperty>(); UProperty valProp = ReadPointer <UProperty>(); int num = ReadInt32(); output.AppendLine(FmtOpcodeIndent(opcode) + "set map const - elements number: " + num + ", key property: " + UObject.GetNameSafe(keyProp) + ", val property: " + UObject.GetNameSafe(valProp)); while (SerializeExpr() != EExprToken.EX_EndMapConst) { // Map contents } break; } case EExprToken.EX_ObjToInterfaceCast: { // A conversion from an object variable to a native interface variable. // We use a different bytecode to avoid the branching each time we process a cast token // the interface class to convert to UClass interfaceClass = ReadPointer <UClass>(); output.AppendLine(FmtOpcodeIndent(opcode) + "ObjToInterfaceCast to " + interfaceClass.GetName()); SerializeExpr(); break; } case EExprToken.EX_CrossInterfaceCast: { // A conversion from one interface variable to a different interface variable. // We use a different bytecode to avoid the branching each time we process a cast token // the interface class to convert to UClass interfaceClass = ReadPointer <UClass>(); output.AppendLine(FmtOpcodeIndent(opcode) + "InterfaceToInterfaceCast to " + interfaceClass.GetName()); SerializeExpr(); break; } case EExprToken.EX_InterfaceToObjCast: { // A conversion from an interface variable to a object variable. // We use a different bytecode to avoid the branching each time we process a cast token // the interface class to convert to UClass objectClass = ReadPointer <UClass>(); output.AppendLine(FmtOpcodeIndent(opcode) + "InterfaceToObjCast to " + objectClass.GetName()); SerializeExpr(); break; } case EExprToken.EX_Let: { output.AppendLine(FmtOpcodeIndent(opcode) + "Let (Variable = Expression)"); AddIndent(); ReadPointer <UProperty>(); // Variable expr. output.AppendLine(indents + " Variable:"); SerializeExpr(); // Assignment expr. output.AppendLine(indents + " Expression:"); SerializeExpr(); DropIndent(); break; } case EExprToken.EX_LetObj: case EExprToken.EX_LetWeakObjPtr: { if (opcode == EExprToken.EX_LetObj) { output.AppendLine(FmtOpcodeIndent(opcode) + "Let Obj (Variable = Expression)"); } else { output.AppendLine(FmtOpcodeIndent(opcode) + "Let WeakObjPtr (Variable = Expression)"); } AddIndent(); // Variable expr. output.AppendLine(indents + " Variable:"); SerializeExpr(); // Assignment expr. output.AppendLine(indents + " Expression:"); SerializeExpr(); DropIndent(); break; } case EExprToken.EX_LetBool: { output.AppendLine(FmtOpcodeIndent(opcode) + "LetBool (Variable = Expression)"); AddIndent(); // Variable expr. output.AppendLine(indents + " Variable:"); SerializeExpr(); // Assignment expr. output.AppendLine(indents + " Expression:"); SerializeExpr(); DropIndent(); break; } case EExprToken.EX_LetValueOnPersistentFrame: { output.AppendLine(FmtOpcodeIndent(opcode) + "LetValueOnPersistentFrame"); AddIndent(); UProperty prop = ReadPointer <UProperty>(); output.AppendLine(indents + " Destination variable: " + UObject.GetNameSafe(prop) + ", offset: " + (prop != null ? prop.GetOffset_ForDebug() : 0)); output.AppendLine(indents + " Expression:"); SerializeExpr(); DropIndent(); break; } case EExprToken.EX_StructMemberContext: { output.AppendLine(FmtOpcodeIndent(opcode) + "Struct member context"); AddIndent(); UProperty prop = ReadPointer <UProperty>(); // although that isn't a UFunction, we are not going to indirect the props of a struct, so this should be fine output.AppendLine(indents + " Expression within struct " + prop.GetName() + ", offset " + prop.GetOffset_ForDebug()); output.AppendLine(indents + " Expression to struct:"); SerializeExpr(); DropIndent(); break; } case EExprToken.EX_LetDelegate: { output.AppendLine(FmtOpcodeIndent(opcode) + "LetDelegate (Variable = Expression)"); AddIndent(); // Variable expr. output.AppendLine(indents + " Variable:"); SerializeExpr(); // Assignment expr. output.AppendLine(indents + " Expression:"); SerializeExpr(); DropIndent(); break; } case EExprToken.EX_LetMulticastDelegate: { output.AppendLine(FmtOpcodeIndent(opcode) + "LetMulticastDelegate (Variable = Expression)"); AddIndent(); // Variable expr. output.AppendLine(indents + " Variable:"); SerializeExpr(); // Assignment expr. output.AppendLine(indents + " Expression:"); SerializeExpr(); DropIndent(); break; } case EExprToken.EX_ComputedJump: { output.AppendLine(FmtOpcodeIndent(opcode) + "Computed Jump, offset specified by expression:"); AddIndent(); SerializeExpr(); DropIndent(); break; } case EExprToken.EX_Jump: { uint skipCount = ReadSkipCount(); output.AppendLine(FmtOpcodeIndent(opcode) + "Jump to offset " + FmtSkipCount(skipCount)); break; } case EExprToken.EX_LocalVariable: { UProperty property = ReadPointer <UProperty>(); output.AppendLine(FmtOpcodeIndent(opcode) + "Local variable named " + FmtObjNameOrNull(property)); break; } case EExprToken.EX_DefaultVariable: { UProperty property = ReadPointer <UProperty>(); output.AppendLine(FmtOpcodeIndent(opcode) + "Default variable named " + FmtObjNameOrNull(property)); break; } case EExprToken.EX_InstanceVariable: { UProperty property = ReadPointer <UProperty>(); output.AppendLine(FmtOpcodeIndent(opcode) + "Instance variable named " + FmtObjNameOrNull(property)); break; } case EExprToken.EX_LocalOutVariable: { UProperty property = ReadPointer <UProperty>(); output.AppendLine(FmtOpcodeIndent(opcode) + "Local out variable named " + FmtObjNameOrNull(property)); break; } case EExprToken.EX_InterfaceContext: { output.AppendLine(FmtOpcodeIndent(opcode) + "EX_InterfaceContext:"); SerializeExpr(); break; } case EExprToken.EX_DeprecatedOp4A: { output.AppendLine(FmtOpcodeIndent(opcode) + "This opcode has been removed and does nothing."); break; } case EExprToken.EX_Nothing: case EExprToken.EX_EndOfScript: case EExprToken.EX_EndFunctionParms: case EExprToken.EX_EndStructConst: case EExprToken.EX_EndArray: case EExprToken.EX_EndArrayConst: case EExprToken.EX_IntZero: case EExprToken.EX_IntOne: case EExprToken.EX_True: case EExprToken.EX_False: case EExprToken.EX_NoObject: case EExprToken.EX_NoInterface: case EExprToken.EX_Self: case EExprToken.EX_EndParmValue: { output.AppendLine(FmtOpcodeIndent(opcode) + opcode.ToString()); break; } case EExprToken.EX_Return: { output.AppendLine(FmtOpcodeIndent(opcode) + opcode.ToString()); SerializeExpr(); // Return expression. break; } case EExprToken.EX_CallMath: { UStruct stackNode = ReadPointer <UStruct>(); output.AppendLine(FmtOpcodeIndent(opcode) + "Call Math (stack node " + UObject.GetNameSafe(stackNode != null ? stackNode.GetOuter() : null) + "::" + UObject.GetNameSafe(stackNode) + ")"); while (SerializeExpr() != EExprToken.EX_EndFunctionParms) { // Params } break; } case EExprToken.EX_FinalFunction: { UStruct stackNode = ReadPointer <UStruct>(); output.AppendLine(FmtOpcodeIndent(opcode) + "Final Function (stack node " + FmtObjOuterNameOrNull(stackNode) + "::" + FmtObjNameOrNull(stackNode) + ")"); while (SerializeExpr() != EExprToken.EX_EndFunctionParms) { // Params } break; } case EExprToken.EX_CallMulticastDelegate: { UStruct stackNode = ReadPointer <UStruct>(); output.AppendLine(FmtOpcodeIndent(opcode) + "CallMulticastDelegate (signature " + FmtObjOuterNameOrNull(stackNode) + "::" + FmtObjNameOrNull(stackNode) + ") delegate:"); SerializeExpr(); output.AppendLine(FmtOpcodeIndent(opcode) + "Params:"); while (SerializeExpr() != EExprToken.EX_EndFunctionParms) { // Params } break; } case EExprToken.EX_VirtualFunction: { string functionName = ReadName(); output.AppendLine(FmtOpcodeIndent(opcode) + "Virtual Function named " + functionName); while (SerializeExpr() != EExprToken.EX_EndFunctionParms) { } break; } case EExprToken.EX_ClassContext: case EExprToken.EX_Context: case EExprToken.EX_Context_FailSilent: { output.AppendLine(FmtOpcodeIndent(opcode) + (opcode == EExprToken.EX_ClassContext ? "Class Context" : "Context")); AddIndent(); // Object expression. output.AppendLine(indents + " ObjectExpression:"); SerializeExpr(); if (opcode == EExprToken.EX_Context_FailSilent) { output.AppendLine(indents + " Can fail silently on access none "); } // Code offset for NULL expressions. uint skipCount = ReadSkipCount(); output.AppendLine(indents + " Skip Bytes: " + FmtSkipCount(skipCount)); // Property corresponding to the r-value data, in case the l-value needs to be mem-zero'd UField field = ReadPointer <UField>(); output.AppendLine(indents + " R-Value Property: " + FmtObjNameOrNull(field)); // Context expression. output.AppendLine(indents + " ContextExpression:"); SerializeExpr(); DropIndent(); break; } case EExprToken.EX_IntConst: { int constValue = ReadInt32(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal int32 " + constValue); break; } case EExprToken.EX_SkipOffsetConst: { uint constValue = ReadSkipCount(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal CodeSkipSizeType " + FmtSkipCount(constValue)); break; } case EExprToken.EX_FloatConst: { float constValue = ReadFloat(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal float " + constValue); break; } case EExprToken.EX_StringConst: { string constValue = ReadString8(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal ansi string \"" + constValue + "\""); break; } case EExprToken.EX_UnicodeStringConst: { string constValue = ReadString16(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal unicode string \"" + constValue + "\""); break; } case EExprToken.EX_TextConst: { // What kind of text are we dealing with? EBlueprintTextLiteralType textLiteralType = (EBlueprintTextLiteralType)script[scriptIndex++]; switch (textLiteralType) { case EBlueprintTextLiteralType.Empty: { output.AppendLine(FmtOpcodeIndent(opcode) + "literal text - empty"); break; } case EBlueprintTextLiteralType.LocalizedText: { string sourceString = ReadString(); string keyString = ReadString(); string namespaceString = ReadString(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal text - localized text { namespace: \"" + namespaceString + "\", key: \"" + keyString + "\", source: \"" + sourceString + "\" }"); break; } case EBlueprintTextLiteralType.InvariantText: { string sourceString = ReadString(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal text - invariant text: \"" + sourceString + "\""); break; } case EBlueprintTextLiteralType.LiteralString: { string sourceString = ReadString(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal text - literal string: \"" + sourceString + "\""); break; } case EBlueprintTextLiteralType.StringTableEntry: { ReadPointer <UObject>(); // String Table asset (if any) string tableIdString = ReadString(); string keyString = ReadString(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal text - string table entry { tableid: \"" + tableIdString + "\", key: \"" + keyString + "\" }"); break; } default: throw new Exception("Unknown EBlueprintTextLiteralType! Please update ProcessCommon() to handle this type of text."); } break; } case EExprToken.EX_ObjectConst: { UObject pointer = ReadPointer <UObject>(); output.AppendLine(FmtOpcodeIndent(opcode) + "EX_ObjectConst (" + FmtPtr(pointer) + ":" + pointer.GetFullName()); break; } case EExprToken.EX_SoftObjectConst: { output.AppendLine(FmtOpcodeIndent(opcode) + "EX_SoftObjectConst"); SerializeExpr(); break; } case EExprToken.EX_NameConst: { string constValue = ReadName(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal name " + constValue); break; } case EExprToken.EX_RotationConst: { float pitch = ReadFloat(); float yaw = ReadFloat(); float roll = ReadFloat(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal rotation (" + pitch + "," + yaw + "," + roll + ")"); break; } case EExprToken.EX_VectorConst: { float x = ReadFloat(); float y = ReadFloat(); float z = ReadFloat(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal vector (" + x + "," + y + "," + z + ")"); break; } case EExprToken.EX_TransformConst: { float rotX = ReadFloat(); float rotY = ReadFloat(); float rotZ = ReadFloat(); float rotW = ReadFloat(); float transX = ReadFloat(); float transY = ReadFloat(); float transZ = ReadFloat(); float scaleX = ReadFloat(); float scaleY = ReadFloat(); float scaleZ = ReadFloat(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal transform " + "R(" + rotX + "," + rotY + "," + rotZ + "," + rotW + "," + ") " + "T(" + transX + "," + transY + "," + transZ + ") " + "T(" + scaleX + "," + scaleY + "," + scaleZ + ")"); break; } case EExprToken.EX_StructConst: { UScriptStruct unrealStruct = ReadPointer <UScriptStruct>(); int serializedSize = ReadInt32(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal struct " + unrealStruct.GetName() + " (serialized size: " + serializedSize + ")"); break; } case EExprToken.EX_SetArray: { output.AppendLine(FmtOpcodeIndent(opcode) + "set array"); SerializeExpr(); while (SerializeExpr() != EExprToken.EX_EndArray) { // Array contents } break; } case EExprToken.EX_ArrayConst: { UProperty innerProp = ReadPointer <UProperty>(); int num = ReadInt32(); output.AppendLine(FmtOpcodeIndent(opcode) + "set array const - elements number: " + num + ", inner property: " + UObject.GetNameSafe(innerProp)); break; } case EExprToken.EX_ByteConst: { byte constValue = ReadByte(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal byte " + constValue); break; } case EExprToken.EX_IntConstByte: { int constValue = ReadByte(); output.AppendLine(FmtOpcodeIndent(opcode) + "literal int " + constValue); break; } case EExprToken.EX_MetaCast: { UClass unrealClass = ReadPointer <UClass>(); output.AppendLine(FmtOpcodeIndent(opcode) + "MetaCast to " + unrealClass.GetName() + " of expr:"); SerializeExpr(); break; } case EExprToken.EX_DynamicCast: { UClass unrealClass = ReadPointer <UClass>(); output.AppendLine(FmtOpcodeIndent(opcode) + "DynamicCast to " + unrealClass.GetName() + " of expr:"); SerializeExpr(); break; } case EExprToken.EX_JumpIfNot: { // Code offset. uint skipCount = ReadSkipCount(); output.AppendLine(FmtOpcodeIndent(opcode) + "Jump to offset " + FmtSkipCount(skipCount) + " if not expr:"); // Boolean expr. SerializeExpr(); break; } case EExprToken.EX_Assert: { ushort lineNumber = ReadUInt16(); byte inDebugMode = ReadByte(); output.AppendLine(FmtOpcodeIndent(opcode) + "assert at line " + lineNumber + ", in debug mode = " + inDebugMode + " with expr:"); SerializeExpr(); // Assert expr. break; } case EExprToken.EX_Skip: { uint w = ReadSkipCount(); output.AppendLine(FmtOpcodeIndent(opcode) + "possibly skip " + FmtSkipCount(w) + " bytes of expr:"); // Expression to possibly skip. SerializeExpr(); break; } case EExprToken.EX_InstanceDelegate: { // the name of the function assigned to the delegate. string funcName = ReadName(); output.AppendLine(FmtOpcodeIndent(opcode) + "instance delegate function named " + funcName); break; } case EExprToken.EX_AddMulticastDelegate: { output.AppendLine(FmtOpcodeIndent(opcode) + "Add MC delegate"); SerializeExpr(); SerializeExpr(); break; } case EExprToken.EX_RemoveMulticastDelegate: { output.AppendLine(FmtOpcodeIndent(opcode) + "Remove MC delegate"); SerializeExpr(); SerializeExpr(); break; } case EExprToken.EX_ClearMulticastDelegate: { output.AppendLine(FmtOpcodeIndent(opcode) + "Clear MC delegate"); SerializeExpr(); break; } case EExprToken.EX_BindDelegate: { // the name of the function assigned to the delegate. string funcName = ReadName(); output.AppendLine(FmtOpcodeIndent(opcode) + "BindDelegate '" + funcName + "'"); output.AppendLine(indents + " Delegate:"); SerializeExpr(); output.AppendLine(indents + " Object:"); SerializeExpr(); break; } case EExprToken.EX_PushExecutionFlow: { uint skipCount = ReadSkipCount(); output.AppendLine(FmtOpcodeIndent(opcode) + "FlowStack.Push(" + FmtSkipCount(skipCount) + ");"); break; } case EExprToken.EX_PopExecutionFlow: { output.AppendLine(FmtOpcodeIndent(opcode) + "if (FlowStack.Num()) { jump to statement at FlowStack.Pop(); } else { ERROR!!! }"); break; } case EExprToken.EX_PopExecutionFlowIfNot: { output.AppendLine(FmtOpcodeIndent(opcode) + "if (!condition) { if (FlowStack.Num()) { jump to statement at FlowStack.Pop(); } else { ERROR!!! } }"); // Boolean expr. SerializeExpr(); break; } case EExprToken.EX_Breakpoint: { output.AppendLine(FmtOpcodeIndent(opcode) + "<<< BREAKPOINT >>>"); break; } case EExprToken.EX_WireTracepoint: { output.AppendLine(FmtOpcodeIndent(opcode) + ".. wire debug site .."); break; } case EExprToken.EX_InstrumentationEvent: { EScriptInstrumentation eventType = (EScriptInstrumentation)ReadByte(); switch (eventType) { case EScriptInstrumentation.InlineEvent: output.AppendLine(FmtOpcodeIndent(opcode) + ".. instrumented inline event .."); break; case EScriptInstrumentation.Stop: output.AppendLine(FmtOpcodeIndent(opcode) + ".. instrumented event stop .."); break; case EScriptInstrumentation.PureNodeEntry: output.AppendLine(FmtOpcodeIndent(opcode) + ".. instrumented pure node entry site .."); break; case EScriptInstrumentation.NodeDebugSite: output.AppendLine(FmtOpcodeIndent(opcode) + ".. instrumented debug site .."); break; case EScriptInstrumentation.NodeEntry: output.AppendLine(FmtOpcodeIndent(opcode) + ".. instrumented wire entry site .."); break; case EScriptInstrumentation.NodeExit: output.AppendLine(FmtOpcodeIndent(opcode) + ".. instrumented wire exit site .."); break; case EScriptInstrumentation.PushState: output.AppendLine(FmtOpcodeIndent(opcode) + ".. push execution state .."); break; case EScriptInstrumentation.RestoreState: output.AppendLine(FmtOpcodeIndent(opcode) + ".. restore execution state .."); break; case EScriptInstrumentation.ResetState: output.AppendLine(FmtOpcodeIndent(opcode) + ".. reset execution state .."); break; case EScriptInstrumentation.SuspendState: output.AppendLine(FmtOpcodeIndent(opcode) + ".. suspend execution state .."); break; case EScriptInstrumentation.PopState: output.AppendLine(FmtOpcodeIndent(opcode) + ".. pop execution state .."); break; case EScriptInstrumentation.TunnelEndOfThread: output.AppendLine(FmtOpcodeIndent(opcode) + ".. tunnel end of thread .."); break; } break; } case EExprToken.EX_Tracepoint: { output.AppendLine(FmtOpcodeIndent(opcode) + ".. debug site .."); break; } case EExprToken.EX_SwitchValue: { ushort numCases = ReadUInt16(); uint afterSkip = ReadSkipCount(); output.AppendLine(FmtOpcodeIndent(opcode) + "Switch Value " + numCases + " cases, end in " + FmtSkipCount(afterSkip)); AddIndent(); output.AppendLine(indents + " Index:"); SerializeExpr(); for (ushort caseIndex = 0; caseIndex < numCases; ++caseIndex) { output.AppendLine(indents + " [" + caseIndex + "] Case Index (label: " + FmtScriptIndex(scriptIndex) + ")"); SerializeExpr(); // case index value term uint offsetToNextCase = ReadSkipCount(); output.AppendLine(indents + " [" + caseIndex + "] Offset to the next case: " + FmtSkipCount(offsetToNextCase)); output.AppendLine(indents + " [" + caseIndex + "] Case Result:"); SerializeExpr(); // case term } output.AppendLine(indents + " Default result (label: " + FmtScriptIndex(scriptIndex) + ")"); SerializeExpr(); output.AppendLine(indents + " (label: " + FmtScriptIndex(scriptIndex) + ")"); DropIndent(); break; } case EExprToken.EX_ArrayGetByRef: { output.AppendLine(FmtOpcodeIndent(opcode) + "Array Get-by-Ref Index"); AddIndent(); SerializeExpr(); SerializeExpr(); DropIndent(); break; } default: { string error = "Unknown bytecode 0x" + ((byte)opcode).ToString("X2") + "; ignoring it"; output.AppendLine(FmtOpcodeIndent(opcode) + "!!!" + error); FMessage.Log(ELogVerbosity.Warning, error); } break; } }
public IntPtr ContainerPtrToValuePtrForDefaults(UStruct containerClass, IntPtr container, int arrayIndex = 0) { return(Native_UProperty.ContainerVoidPtrToValuePtrForDefaults(Address, containerClass.Address, container, arrayIndex)); }
public IntPtr ContainerPtrToValuePtrForDefaults(UStruct containerClass, UObject container, int arrayIndex = 0) { return(ContainerUObjectPtrToValuePtrForDefaults(containerClass, container.Address, 0)); }
public bool MoveNext() { if (first) { first = false; } else { field = field.Next; } UField currentField = field; UStruct currentStruct = unrealStruct; while (currentStruct != null) { while (currentField != null) { UClass fieldClass = currentField.GetClass(); if (fieldClass.HasAllCastFlags(typeClass.ClassCastFlags) && (includeDeprecated || !fieldClass.HasAllCastFlags(EClassCastFlags.UProperty) || !(currentField as UProperty).HasAllPropertyFlags(EPropertyFlags.Deprecated))) { unrealStruct = currentStruct; field = currentField; return(true); } currentField = currentField.Next; } if (includeInterface) { // We shouldn't be able to get here for non-classes UClass currentClass = currentStruct as UClass; ++interfaceIndex; FImplementedInterface[] interfaces = currentClass.Interfaces; if (interfaces != null && interfaceIndex < interfaces.Length) { UClass interfaceClass = interfaces[interfaceIndex].InterfaceClass; currentField = GetField(interfaceClass); continue; } } if (includeSuper) { currentStruct = currentStruct.GetInheritanceSuper(); if (currentStruct != null) { currentField = GetField(currentStruct); interfaceIndex = -1; continue; } } break; } unrealStruct = currentStruct; field = currentField; return(field != null); }
/// <summary> /// Sets all properties in the given struct to their default values within the struct constructor. /// (used when generating with safeguards enabled) /// </summary> private void AppendStructDefaultValuesOnInvalid(CSharpTextBuilder builder, StructInfo structInfo, UStruct parentStruct, List <string> namespaces) { if (!Settings.GenerateIsValidSafeguards) { return; } List <UProperty> allProperties = new List <UProperty>(); foreach (UProperty property in structInfo.GetProperties()) { if (!structInfo.IsCollapsedProperty(property)) { allProperties.Add(property); } } if (parentStruct != null && Settings.InlineBaseStruct) { UScriptStruct tempParentStruct = parentStruct as UScriptStruct; while (tempParentStruct != null) { StructInfo tempParentStructInfo = GetStructInfo(tempParentStruct); if (tempParentStructInfo != null) { foreach (UProperty property in tempParentStructInfo.GetProperties()) { if (!tempParentStructInfo.IsCollapsedProperty(property)) { allProperties.Add(property); } } } tempParentStruct = tempParentStruct.GetSuperStruct() as UScriptStruct; } } foreach (UProperty property in allProperties) { string propertyName = GetMemberName(property, structInfo.GetPropertyName(property)); builder.AppendLine(propertyName + " = " + GetPropertyMarshalerDefaultValue(property, namespaces) + ";"); } }
public static bool GeStringMetaDataHierarchical <TEnum>(this UStruct unrealStruct, TEnum key) where TEnum : struct { return(unrealStruct.GeStringMetaDataHierarchical(new FName(UMeta.GetKey(key)))); }
private void AppendStructMarshalerBody(CSharpTextBuilder builder, string structTypeName, StructInfo structInfo, UStruct parentStruct, bool toNative, List <string> namespaces) { if (Settings.GenerateIsValidSafeguards) { builder.AppendLine("if (!" + structTypeName + Settings.VarNames.IsValid + ")"); builder.OpenBrace(); builder.AppendLine(Names.NativeReflection_LogInvalidStructAccessed + "(\"" + structInfo.Struct.GetPathName() + "\");"); if (!toNative) { // Set default values for all properties AppendStructDefaultValuesOnInvalid(builder, structInfo, parentStruct, namespaces); } builder.AppendLine("return;"); builder.CloseBrace(); } foreach (UProperty property in structInfo.GetProperties()) { if (!structInfo.IsCollapsedProperty(property)) { string propertyName = GetMemberName(property, structInfo.GetPropertyName(property)); if (toNative) { AppendPropertyToNative(builder, property, propertyName, "nativeStruct", "null", propertyName, false, namespaces); } else { AppendPropertyFromNative(builder, property, propertyName, "nativeStruct", propertyName, "null", false, namespaces); } } } if (parentStruct != null) { if (Settings.InlineBaseStruct) { UScriptStruct tempParentStruct = parentStruct as UScriptStruct; while (tempParentStruct != null) { StructInfo tempParentStructInfo = GetStructInfo(tempParentStruct); if (tempParentStructInfo != null) { foreach (UProperty property in tempParentStructInfo.GetProperties()) { if (!tempParentStructInfo.IsCollapsedProperty(property)) { string propertyName = GetMemberName(property, tempParentStructInfo.GetPropertyName(property)); if (toNative) { AppendPropertyToNative(builder, property, propertyName, "nativeStruct", "null", propertyName, false, namespaces); } else { AppendPropertyFromNative(builder, property, propertyName, "nativeStruct", propertyName, "null", false, namespaces); } } } } tempParentStruct = tempParentStruct.GetSuperStruct() as UScriptStruct; } } else { if (toNative) { builder.AppendLine("Base.ToNative(nativeStruct);"); } else { builder.AppendLine("Base = new " + GetTypeName(parentStruct, namespaces) + "(nativeStruct);"); } } } }
private void ResolveNameConflicts() { List <NameConflictInfo> baseConflictInfos = new List <NameConflictInfo>(); UStruct parentStruct = Struct.GetSuperStruct(); if (parentStruct != null) { StructInfo parentInfo = codeGenerator.GetStructInfo(parentStruct); if (parentInfo != null && parentInfo.conflictInfo != null) { baseConflictInfos.Add(parentInfo.conflictInfo); } } if (Class != null) { foreach (FImplementedInterface implementedInterface in Class.Interfaces) { UClass interfaceClass = implementedInterface.InterfaceClass; if (interfaceClass != null) { StructInfo interfaceInfo = codeGenerator.GetStructInfo(interfaceClass); if (interfaceInfo != null && interfaceInfo.conflictInfo != null) { baseConflictInfos.Add(interfaceInfo.conflictInfo); } } } } conflictInfo = new NameConflictInfo(this); foreach (KeyValuePair <UProperty, string> property in exportableProperties) { conflictInfo.AddMember(property.Key, codeGenerator.GetMemberName(property.Key, false, property.Value)); } foreach (UFunction function in exportableFunctions) { // Functions are a special case. They can be redefined in the hierarchy but for name resolving // we want them to have the same name throughout. Therefore only resolve the base-most function // name (even if redefined later in the hierarchy). Then when we do a name conflict lookup find that // base-most function and use that name for all of the functions in the hierarchy with that name. // - This is lookup is done in ResolveNameConflict(). if (codeGenerator.GetOriginalFunctionOwner(function) == Class) { conflictInfo.AddMember(function, codeGenerator.GetFunctionName(function, false)); } } foreach (NameConflictInfo baseConflictInfo in baseConflictInfos) { foreach (KeyValuePair <string, NameConflictFieldInfo> baseMembersByName in baseConflictInfo.MembersByName) { NameConflictFieldInfo baseMembers; if (!conflictInfo.BaseMembersByName.TryGetValue(baseMembersByName.Key, out baseMembers)) { conflictInfo.BaseMembersByName.Add(baseMembersByName.Key, baseMembers = new NameConflictFieldInfo(baseMembersByName.Key)); } foreach (KeyValuePair <UField, CollapsedMember> baseMember in baseMembersByName.Value.Fields) { baseMembers.AddField(baseMember.Key, baseMember.Value); } } foreach (KeyValuePair <string, NameConflictFieldInfo> baseBaseMembersByName in baseConflictInfo.BaseMembersByName) { NameConflictFieldInfo baseBaseMembers; if (!conflictInfo.BaseMembersByName.TryGetValue(baseBaseMembersByName.Key, out baseBaseMembers)) { conflictInfo.BaseMembersByName.Add(baseBaseMembersByName.Key, baseBaseMembers = new NameConflictFieldInfo(baseBaseMembersByName.Key)); } foreach (KeyValuePair <UField, CollapsedMember> baseBaseMember in baseBaseMembersByName.Value.Fields) { baseBaseMembers.AddField(baseBaseMember.Key, baseBaseMember.Value); } } } var tempMembersByName = new Dictionary <string, NameConflictFieldInfo>(conflictInfo.MembersByName); foreach (KeyValuePair <string, NameConflictFieldInfo> membersByName in tempMembersByName) { // What about overridden functions? where do they appear? if (membersByName.Value.HasConflict() || conflictInfo.BaseMembersByName.ContainsKey(membersByName.Key)) { foreach (KeyValuePair <UField, CollapsedMember> field in membersByName.Value.Fields) { if (field.Value == null) { string hashedName = membersByName.Key + "_" + field.Key.GetPathName().GetHashCode().ToString("X8"); NameConflictResolved(field.Key, hashedName); } } foreach (KeyValuePair <CollapsedMember, List <UField> > collapsedMember in membersByName.Value.FieldsByCollapsedMember) { UField field = null; if (collapsedMember.Key.Getter != null) { field = collapsedMember.Key.Getter; } else if (collapsedMember.Key.Setter != null) { field = collapsedMember.Key.Setter; } else if (collapsedMember.Key.BackingProperty != null) { field = collapsedMember.Key.BackingProperty; } string hashedName = membersByName.Key + "_" + field.GetPathName().GetHashCode().ToString("X8"); if (collapsedMember.Key.Getter != null) { NameConflictResolved(collapsedMember.Key.Getter, hashedName); } if (collapsedMember.Key.Setter != null) { NameConflictResolved(collapsedMember.Key.Setter, hashedName); } if (collapsedMember.Key.BackingProperty != null) { NameConflictResolved(collapsedMember.Key.BackingProperty, hashedName); } } // All fields with this name should have been renamed. Remove the old name. conflictInfo.MembersByName.Remove(membersByName.Key); } } }
private string GetMarshalerFromProperty(UProperty property, List <string> namespaces, bool isFunction, bool fixedSizeArrayInnerMarshaler) { if (property.IsFixedSizeArray && !fixedSizeArrayInnerMarshaler) { if (IsOwnerClassOrStructAsClass(property)) { return(GetTypeName(property, namespaces)); } else { // Should expect either a UClass or a UScriptStruct. Fixed sized arrays aren't supported on functions in unreal. System.Diagnostics.Debug.Assert(property.GetOwnerStruct().IsA <UScriptStruct>()); return(Names.TFixedSizeArrayMarshaler + "<" + GetTypeName(property, namespaces) + ">"); //// FixedSizeArrayMarshaler<int, BlittableTypeMarshaler<int>> //return Names.FixedSizeArrayMarshaler + "<" + GetTypeName(property, namespaces) + ", " + // GetMarshalerFromProperty(property, namespaces, isFunction, true) + ">"; } } UNumericProperty numericProperty = property as UNumericProperty; if ((numericProperty != null && numericProperty.IsEnum && numericProperty.GetIntPropertyEnum() != null) || property.PropertyType == EPropertyType.Enum) { UEnum unrealEnum = null; if (property.PropertyType == EPropertyType.Enum) { unrealEnum = (property as UEnumProperty).GetEnum(); } else { unrealEnum = numericProperty.GetIntPropertyEnum(); } return(Names.EnumMarshaler + "<" + GetTypeName(unrealEnum, namespaces) + ">"); } string blittableTypeName = GetBlittablePropertyTypeName(property, namespaces); if (!string.IsNullOrEmpty(blittableTypeName)) { return(Names.BlittableTypeMarshaler + "<" + blittableTypeName + ">"); } switch (property.PropertyType) { case EPropertyType.Bool: return(Names.BoolMarshaler); case EPropertyType.Str: return(Names.FStringMarshaler); case EPropertyType.Text: return(Names.FTextMarshaler); case EPropertyType.Struct: { UStruct unrealStruct = (property as UStructProperty).Struct; if (IsClassOrStructAsClass(unrealStruct)) { return(Names.StructAsClassMarshaler + "<" + GetTypeName(property, namespaces) + ">"); } else { // Normal structs use their own type name and have static FromNative/ToNative methods return(GetTypeName(property, namespaces)); } } case EPropertyType.Delegate: { string delegateTypeName = GetTypeName(property, namespaces); return(Names.FDelegateMarshaler + "<" + delegateTypeName + ">"); } case EPropertyType.MulticastDelegate: { string delegateTypeName = GetTypeName(property, namespaces); return(Names.FMulticastDelegateMarshaler + "<" + delegateTypeName + ">"); } case EPropertyType.Array: { string arrayMarshalerName = Names.TArrayReadWriteMarshaler; if (IsOwnerClassOrStructAsClass(property)) { if (property.HasAnyPropertyFlags(EPropertyFlags.BlueprintReadOnly)) { arrayMarshalerName = Names.TArrayReadOnlyMarshaler; } } else { arrayMarshalerName = Names.TArrayCopyMarshaler; } UArrayProperty arrayProperty = property as UArrayProperty; return(arrayMarshalerName + "<" + GetTypeName(arrayProperty.Inner, namespaces) + ">"); } case EPropertyType.Set: { string setMarshalerName = Names.TSetReadWriteMarshaler; if (IsOwnerClassOrStructAsClass(property)) { if (property.HasAnyPropertyFlags(EPropertyFlags.BlueprintReadOnly)) { setMarshalerName = Names.TSetReadOnlyMarshaler; } } else { setMarshalerName = Names.TSetCopyMarshaler; } USetProperty setProperty = property as USetProperty; return(setMarshalerName + "<" + GetTypeName(setProperty.ElementProp, namespaces) + ">"); } case EPropertyType.Map: { string mapMarshalerName = Names.TMapReadWriteMarshaler; if (IsOwnerClassOrStructAsClass(property)) { if (property.HasAnyPropertyFlags(EPropertyFlags.BlueprintReadOnly)) { mapMarshalerName = Names.TMapReadOnlyMarshaler; } } else { mapMarshalerName = Names.TMapCopyMarshaler; } UMapProperty mapProperty = property as UMapProperty; return(mapMarshalerName + "<" + GetTypeName(mapProperty.KeyProp, namespaces) + ", " + GetTypeName(mapProperty.ValueProp, namespaces) + ">"); } case EPropertyType.Class: { UClass targetClass = (property as UClassProperty).MetaClass; string subclassOfMarshalerName = null; if (targetClass.ClassFlags.HasFlag(EClassFlags.Interface)) { subclassOfMarshalerName = Names.TSubclassOfInterfaceMarshaler; } else { subclassOfMarshalerName = Names.TSubclassOfMarshaler; } return(subclassOfMarshalerName + "<" + GetTypeName(targetClass, namespaces) + ">"); } case EPropertyType.Interface: return(Names.InterfaceMarshaler + "<" + GetTypeName((property as UInterfaceProperty).InterfaceClass, namespaces) + ">"); case EPropertyType.Object: return(Names.UObjectMarshaler + "<" + GetTypeName((property as UObjectProperty).PropertyClass, namespaces) + ">"); case EPropertyType.WeakObject: return(Names.TWeakObjectMarshaler + "<" + GetTypeName((property as UWeakObjectProperty).PropertyClass, namespaces) + ">"); case EPropertyType.LazyObject: return(Names.TLazyObjectMarshaler + "<" + GetTypeName((property as ULazyObjectProperty).PropertyClass, namespaces) + ">"); case EPropertyType.SoftClass: return(Names.TSoftClassMarshaler + "<" + GetTypeName((property as USoftClassProperty).MetaClass, namespaces) + ">"); case EPropertyType.SoftObject: return(Names.TSoftObjectMarshaler + "<" + GetTypeName((property as USoftObjectProperty).PropertyClass, namespaces) + ">"); default: return(null); } }
private string GetFunctionSignature(UnrealModuleInfo module, UFunction function, UStruct owner, string customFunctionName, string customModifiers, bool stripAdditionalText, bool isImplementationMethod, List <string> namespaces) { bool isInterface = owner != null && owner.IsChildOf <UInterface>(); bool isDelegate = function.HasAnyFunctionFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate); bool isStatic = function.HasAnyFunctionFlags(EFunctionFlags.Static); bool isBlueprintType = owner != null && owner.IsA <UBlueprintGeneratedClass>(); StringBuilder modifiers = new StringBuilder(); if (!string.IsNullOrEmpty(customModifiers)) { modifiers.Append(customModifiers); } else if (isInterface) { // Don't provide any modifiers for interfaces if there isn't one already provided } else { UFunction originalFunction; // NOTE: "isImplementationMethod" is talking about "_Implementation" methods. // "isInterfaceImplementation" is talking about regular methods which are implementations for a interface. bool isInterfaceImplementation; UClass originalOwner = GetOriginalFunctionOwner(function, out originalFunction, out isInterfaceImplementation); // All interface functions in the chain need to be public bool isInterfaceFunc = originalOwner != owner && originalOwner.HasAnyClassFlags(EClassFlags.Interface); if (isImplementationMethod || (function.HasAnyFunctionFlags(EFunctionFlags.Protected) && !isInterfaceFunc && !isDelegate)) { modifiers.Append("protected"); } else { modifiers.Append("public"); } if (isDelegate) { modifiers.Append(" delegate"); } if (isStatic) { modifiers.Append(" static"); } if (!isDelegate && !isStatic) { if (function.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent)) { UFunction superFunc = function.GetSuperFunction(); if (superFunc != null) { modifiers.Append(" override"); } else { // This have should been filtered out in CanExportFunction() Debug.Assert(originalOwner == owner || isInterfaceImplementation); // Explicit will have the _Implementation as virtual and the function declaration as // non-virtual (which is the same as C++) if (!Settings.UseExplicitImplementationMethods || isImplementationMethod) { modifiers.Append(" virtual"); } } } else { if (originalOwner != owner && !isInterfaceFunc) { // Add "new" if the parent class has a function with the same name but not BlueprintEvent. // (don't do this for interface functions as we are implementing the function not redefining it) modifiers.Append(" new"); } } } } string returnType = "void"; int numReturns = 0; StringBuilder parameters = new StringBuilder(); // index is the index into parameters string Dictionary <int, string> parameterDefaultsByIndex = new Dictionary <int, string>(); // Once this is true all parameters from that point should also have defaults bool hasDefaultParameters = false; // Blueprint can define ref/out parameters with default values, this can't be translated to code bool invalidDefaultParams = false; // Info so we can avoid param name conflicts Dictionary <UProperty, string> paramNames = GetParamNames(function); // Generic array parameters string[] arrayParamNames = function.GetCommaSeperatedMetaData("ArrayParam"); // Generic parameters depending on array type string[] arrayTypeDependentParamNames = function.GetCommaSeperatedMetaData("ArrayTypeDependentParams"); // AutoCreateRefTerm will force ref on given parameter names (comma seperated) string[] autoRefParamNames = function.GetCommaSeperatedMetaData("AutoCreateRefTerm"); // If this is a blueprint type try and getting the return value from the first out param (if there is only one out) UProperty blueprintReturnProperty = function.GetBlueprintReturnProperty(); bool firstParameter = true; foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; string rawParamName = parameter.GetName(); if (!parameter.HasAnyPropertyFlags(EPropertyFlags.Parm)) { continue; } if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReturnParm) || parameter == blueprintReturnProperty) { returnType = GetTypeName(parameter, namespaces); numReturns++; } else { if (firstParameter) { firstParameter = false; } else { parameters.Append(", "); } if (!parameter.HasAnyPropertyFlags(EPropertyFlags.ConstParm)) { if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm) || autoRefParamNames.Contains(rawParamName)) { parameters.Append("ref "); } else if (parameter.HasAnyPropertyFlags(EPropertyFlags.OutParm)) { parameters.Append("out "); } } string paramTypeName = GetTypeName(parameter, namespaces); if (arrayParamNames.Contains(rawParamName)) { int genericsIndex = paramTypeName.IndexOf('<'); if (genericsIndex >= 0) { paramTypeName = paramTypeName.Substring(0, genericsIndex) + "<T>"; } } else if (arrayTypeDependentParamNames.Contains(rawParamName)) { paramTypeName = "T"; } parameters.Append(paramTypeName + " " + paramName); if (!invalidDefaultParams) { string defaultValue = GetParamDefaultValue(function, parameter, paramTypeName, ref hasDefaultParameters, ref invalidDefaultParams); if (!string.IsNullOrEmpty(defaultValue) && !invalidDefaultParams) { if (isBlueprintType && (parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm | EPropertyFlags.OutParm) || autoRefParamNames.Contains(rawParamName))) { invalidDefaultParams = true; } else { if (!hasDefaultParameters) { hasDefaultParameters = true; } parameterDefaultsByIndex[parameters.Length] = " = " + defaultValue; } } } } } if (numReturns > 1) { FMessage.Log(ELogVerbosity.Error, "More than 1 return on function '" + function.GetPathName() + "'"); } // Insert the default parameters if they aren't invalid if (!invalidDefaultParams) { int offset = 0; foreach (KeyValuePair <int, string> parameterDefault in parameterDefaultsByIndex) { parameters.Insert(parameterDefault.Key + offset, parameterDefault.Value); offset += parameterDefault.Value.Length; } } string functionName = GetFunctionName(function); string additionalStr = string.Empty; if (isDelegate) { functionName = GetTypeNameDelegate(function); additionalStr = ";"; } //if (isInterface) //{ // additionalStr = ";"; //} if (isImplementationMethod) { functionName += Settings.VarNames.ImplementationMethod; } if (!string.IsNullOrEmpty(customFunctionName)) { functionName = customFunctionName; } if (stripAdditionalText) { additionalStr = string.Empty; } string generics = string.Empty; if (arrayParamNames.Length > 0 || arrayTypeDependentParamNames.Length > 0) { generics = "<T>"; } if (modifiers.Length > 0) { modifiers.Append(' '); } return(string.Format("{0}{1} {2}{3}({4}){5}", modifiers, returnType, functionName, generics, parameters, additionalStr)); }