private bool CanExportPropertyImpl(UProperty property, UStruct owner, bool isBlueprintType) { // There seem to be a lot of values which could potentially make a property visible from blueprint // TODO: Find all of the remaining values which we need to check // TODO: Make this stops the search? There shouldn't be any more owner properties once it reaches // the first non-owner owned property if (isBlueprintType && property.GetOwnerStruct() != owner) { return(false); } if (Settings.ExportAllProperties) { return(true); } if (property.HasAnyPropertyFlags(EPropertyFlags.Deprecated)) { return(false); } return(property.HasAnyPropertyFlags(EPropertyFlags.BlueprintVisible | EPropertyFlags.BlueprintAssignable) && (!property.HasAnyPropertyFlags(EPropertyFlags.NativeAccessSpecifierPrivate) || property.GetBoolMetaData(MDProp.AllowPrivateAccess)) && (!property.GetBoolMetaData(MDProp.BlueprintPrivate) || property.GetBoolMetaData(MDProp.AllowPrivateAccess))); //property.HasAnyPropertyFlags(EPropertyFlags.NativeAccessSpecifierPublic | EPropertyFlags.NativeAccessSpecifierProtected | EPropertyFlags.Protected); }
/// <summary> /// Sets function parameters which are tagged as "out" to default values to satisfy the compiler. This will insert /// a return statement if there is a return value. /// </summary> private void AppendFunctionBodyDefaultValues(CSharpTextBuilder builder, UFunction function, UProperty blueprintReturnProperty, bool asElseStatement, bool insertReturn, Dictionary <UProperty, string> paramNames, List <string> namespaces) { bool hasElse = false; string returnStr = null; foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReturnParm) || parameter == blueprintReturnProperty) { returnStr = "return " + GetPropertyMarshalerDefaultValue(parameter, namespaces) + ";"; } else if (parameter.HasAnyPropertyFlags(EPropertyFlags.OutParm) && !parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm)) { if (asElseStatement && !hasElse) { hasElse = true; builder.AppendLine("else"); builder.OpenBrace(); } builder.AppendLine(paramName + " = " + GetPropertyMarshalerDefaultValue(parameter, namespaces) + ";"); } } if (!string.IsNullOrEmpty(returnStr)) { if (asElseStatement && !hasElse) { hasElse = true; builder.AppendLine("else"); builder.OpenBrace(); } builder.AppendLine(returnStr); } else if (insertReturn) { builder.AppendLine("return;"); } if (hasElse) { builder.CloseBrace(); } }
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 void GenerateCodeForProperty(UnrealModuleInfo module, CSharpTextBuilder builder, CSharpTextBuilder offsetsBuilder, UProperty property, bool isBlueprintType, StructInfo structInfo, List <string> namespaces, string customName = null) { bool isOwnerStruct = structInfo != null && structInfo.IsStruct; bool isOwnerStructAsClass = structInfo != null && structInfo.StructAsClass; StringBuilder modifiers = new StringBuilder(); if ((// private (there is little point in allowing private code gen so make this protected instead?) (property.HasAnyPropertyFlags(EPropertyFlags.DisableEditOnInstance) && !property.GetBoolMetaData(MDProp.AllowPrivateAccess)) || // protected (!isOwnerStruct && property.HasAnyPropertyFlags(EPropertyFlags.NativeAccessSpecifierProtected | EPropertyFlags.Protected))) // If this is being force exported make it public instead of protected && !forceExportProperties.Contains(property.GetPathName())) { modifiers.Append("protected"); } else { modifiers.Append("public"); } if (modifiers.Length > 0) { modifiers.Append(" "); } string propertyName = GetMemberName(property, customName); string propertyTypeName = GetTypeName(property, namespaces); AppendGetterSetterOffsets(builder, offsetsBuilder, propertyName, property, namespaces); AppendDocComment(builder, property, isBlueprintType); AppendAttribute(builder, property, module); if (isOwnerStruct && !isOwnerStructAsClass) { if (structInfo.IsBlittable && (property is UObjectProperty) && Settings.UObjectAsBlittableType && property.PropertyType != EPropertyType.Class) { builder.AppendLine("private IntPtr " + propertyName + Settings.VarNames.UObjectBlittableName + ";"); builder.AppendLine(modifiers + propertyTypeName + " " + propertyName); builder.OpenBrace(); builder.AppendLine("get { return " + Names.GCHelper_Find + "<" + propertyTypeName + ">(" + propertyName + Settings.VarNames.UObjectBlittableName + "); }"); builder.AppendLine("set { " + propertyName + Settings.VarNames.UObjectBlittableName + " = value == null ? IntPtr.Zero : value." + Names.UObject_Address + "; }"); builder.CloseBrace(); } else { builder.AppendLine(modifiers + propertyTypeName + " " + propertyName + ";"); } } else { builder.AppendLine(modifiers + propertyTypeName + " " + propertyName); builder.OpenBrace(); AppendGetter(builder, propertyName, property, namespaces); if ((!property.HasAnyPropertyFlags(EPropertyFlags.BlueprintReadOnly) || forceExportProperties.Contains(property.GetPathName())) && !IsCollectionProperty(property) && !IsDelegateProperty(property) && !property.IsFixedSizeArray) { AppendSetter(builder, propertyName, property, namespaces); } builder.CloseBrace(); } builder.AppendLine(); }
private void AppendPropertyToFromNative(CSharpTextBuilder builder, UProperty property, string propertyName, string baseAddressName, string ownerName, string varName, string assignTo, bool isFunction, bool toNative, List <string> namespaces) { string marshalerName = GetMarshalerFromProperty(property, namespaces, isFunction); string propertyAddressVarName = propertyName + Settings.VarNames.PropertyAddress; string memberOffsetVarName = propertyName + Settings.VarNames.MemberOffset; // Some marshalers require UProperty as a parameter bool requresProp = MarshalerRequiresNativePropertyField(property); string toFromNativeCall = null; if (toNative) { if (Settings.MinimalMarshalingParams && !requresProp) { toFromNativeCall = ".ToNative(IntPtr.Add(" + baseAddressName + ", " + memberOffsetVarName + "), " + varName + ");"; } else { toFromNativeCall = ".ToNative(IntPtr.Add(" + baseAddressName + ", " + memberOffsetVarName + "), 0, " + (requresProp ? propertyAddressVarName + "." + Names.UObject_Address : "IntPtr.Zero") + ", " + varName + ");"; } } else { if (Settings.MinimalMarshalingParams && !requresProp) { toFromNativeCall = ".FromNative(IntPtr.Add(" + baseAddressName + ", " + memberOffsetVarName + "));"; } else { toFromNativeCall = ".FromNative(IntPtr.Add(" + baseAddressName + ", " + memberOffsetVarName + "), 0, " + (requresProp ? propertyAddressVarName + "." + Names.UObject_Address : "IntPtr.Zero") + ");"; } } if (string.IsNullOrEmpty(marshalerName)) { builder.AppendLine("throw new NotImplementedException(\"" + Names.EPropertyType + "." + property.PropertyType + "\");"); } else { List <UProperty> collectionInners = null; switch (property.PropertyType) { case EPropertyType.Array: { UArrayProperty arrayProperty = property as UArrayProperty; collectionInners = new List <UProperty>(); collectionInners.Add(arrayProperty.Inner); } break; case EPropertyType.Set: { USetProperty setProperty = property as USetProperty; collectionInners = new List <UProperty>(); collectionInners.Add(setProperty.ElementProp); } break; case EPropertyType.Map: { UMapProperty mapProperty = property as UMapProperty; collectionInners = new List <UProperty>(); collectionInners.Add(mapProperty.KeyProp); collectionInners.Add(mapProperty.ValueProp); } break; } bool isCollection = collectionInners != null; string collectionInstantiation = null; if (isCollection) { string[] collectionInnerMarshalers = new string[collectionInners.Count]; for (int i = 0; i < collectionInners.Count; i++) { collectionInnerMarshalers[i] = Names.CachedMarshalingDelegates + "<" + GetTypeName(collectionInners[i], namespaces) + ", " + GetMarshalerFromProperty(collectionInners[i], namespaces, isFunction) + ">"; } collectionInstantiation = " = new " + marshalerName + "(1, " + propertyAddressVarName + ", " + string.Join(", ", collectionInnerMarshalers.Select(x => x + ".FromNative, " + x + ".ToNative")) + ");"; } if (IsOwnerClassOrStructAsClass(property)) { if (property.IsFixedSizeArray) { string fixedSizeArrayVarName = propertyName + Settings.VarNames.FixedSizeArrayCached; // We don't actually need a ToNative/FromNative call as the fixed array type will handle it builder.AppendLine("if (" + fixedSizeArrayVarName + " == null)"); builder.OpenBrace(); builder.AppendLine(fixedSizeArrayVarName + " = new " + GetTypeName(property, namespaces) + "(IntPtr.Add(" + baseAddressName + ", " + memberOffsetVarName + "), " + propertyAddressVarName + ", " + ownerName + ");"); builder.CloseBrace(); builder.AppendLine(assignTo + fixedSizeArrayVarName + ";"); } if (property.PropertyType == EPropertyType.Struct && IsClassOrStructAsClass((property as UStructProperty).Struct)) { string cachedStructAsClassVarName = propertyName + Settings.VarNames.StructAsClassCached; builder.AppendLine("if (" + cachedStructAsClassVarName + " == null)"); builder.OpenBrace(); builder.AppendLine(cachedStructAsClassVarName + " = new " + GetTypeName(property, namespaces) + "();"); builder.AppendLine(cachedStructAsClassVarName + "." + Names.StructAsClass_Initialize + "(IntPtr.Add(" + Names.UObject_Address + ", " + memberOffsetVarName + "));"); builder.CloseBrace(); if (toNative) { builder.AppendLine(cachedStructAsClassVarName + "." + Names.StructAsClass_CopyFrom + "(" + varName + ");"); } else { builder.AppendLine(assignTo + cachedStructAsClassVarName + ";"); } } else if (isCollection) { string collectionVarName = propertyName + Settings.VarNames.CollectionMarshalerCached; builder.AppendLine("if (" + collectionVarName + " == null)"); builder.OpenBrace(); builder.AppendLine(collectionVarName + collectionInstantiation); builder.CloseBrace(); builder.AppendLine(assignTo + collectionVarName + toFromNativeCall); } else if (IsDelegateProperty(property)) { string delegateVarName = propertyName + Settings.VarNames.DelegateCached; builder.AppendLine("if (" + delegateVarName + " == null)"); builder.OpenBrace(); builder.AppendLine(delegateVarName + " = new " + GetTypeName(property, namespaces) + "();"); builder.AppendLine(delegateVarName + "." + Names.FDelegateBase_SetAddress + "(IntPtr.Add(" + Names.UObject_Address + ", " + memberOffsetVarName + "));"); builder.CloseBrace(); builder.AppendLine(assignTo + delegateVarName + ";"); } else if (property.PropertyType == EPropertyType.Text) { string textVarName = propertyName + Settings.VarNames.FTextCached; builder.AppendLine("if (" + textVarName + " == null)"); builder.OpenBrace(); builder.AppendLine(textVarName + " = new " + GetTypeName(property, namespaces) + "(IntPtr.Add(" + Names.UObject_Address + ", " + memberOffsetVarName + "), false);"); builder.CloseBrace(); if (toNative) { builder.AppendLine(textVarName + ".CopyFrom(value);"); } else { builder.AppendLine("return " + textVarName + ";"); } } else { builder.AppendLine(assignTo + marshalerName + toFromNativeCall); } } else { if (isCollection) { string collectionVarName = propertyName + Settings.VarNames.CollectionMarshaler; if (!property.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm) || property.HasAnyPropertyFlags(EPropertyFlags.ReturnParm) || toNative) { builder.AppendLine(marshalerName + " " + collectionVarName + collectionInstantiation); } builder.AppendLine(assignTo + collectionVarName + toFromNativeCall); } else { builder.AppendLine(assignTo + marshalerName + toFromNativeCall); } } } }
/// <summary> /// Appends static offset / address and other info relating to this property (arrays) /// </summary> private void AppendPropertyOffset(CSharpTextBuilder builder, string propertyName, UProperty property, bool isFunction, List <string> namespaces) { if (Settings.GenerateIsValidSafeguards) { builder.AppendLine("static bool " + propertyName + Settings.VarNames.IsValid + ";"); } if (RequiresNativePropertyField(property)) { // XXXX_PropertyAddress (address of the property) builder.AppendLine("static " + Names.UFieldAddress + " " + propertyName + Settings.VarNames.PropertyAddress + ";"); } // XXXX_Offset (offset of the property) builder.AppendLine("static int " + propertyName + Settings.VarNames.MemberOffset + ";"); if (property.IsFixedSizeArray && IsOwnerClassOrStructAsClass(property)) { builder.AppendLine(GetTypeName(property, namespaces) + " " + propertyName + Settings.VarNames.FixedSizeArrayCached + ";"); } switch (property.PropertyType) { case EPropertyType.Struct: if (IsClassOrStructAsClass((property as UStructProperty).Struct) && IsOwnerClassOrStructAsClass(property)) { // Create a cached version of the struct if it is a StructAsClass and the owner is a class or a StructAsClass builder.AppendLine(GetTypeName(property, namespaces) + " " + propertyName + Settings.VarNames.StructAsClassCached + ";"); } break; case EPropertyType.Delegate: case EPropertyType.MulticastDelegate: if (IsOwnerClassOrStructAsClass(property)) { builder.AppendLine(GetTypeName(property, namespaces) + " " + propertyName + Settings.VarNames.DelegateCached + ";"); } break; case EPropertyType.Text: if (IsOwnerClassOrStructAsClass(property)) { builder.AppendLine(GetTypeName(property, namespaces) + " " + propertyName + Settings.VarNames.FTextCached + ";"); } break; case EPropertyType.Array: if (IsOwnerClassOrStructAsClass(property)) { string arrayMarshalerName = Names.TArrayReadWriteMarshaler; if (property.HasAnyPropertyFlags(EPropertyFlags.BlueprintReadOnly)) { arrayMarshalerName = Names.TArrayReadOnlyMarshaler; } UArrayProperty arrayProperty = property as UArrayProperty; builder.AppendLine(arrayMarshalerName + "<" + GetTypeName(arrayProperty.Inner, namespaces) + "> " + propertyName + Settings.VarNames.CollectionMarshalerCached + ";"); } break; case EPropertyType.Set: if (IsOwnerClassOrStructAsClass(property)) { string setMarshalerName = Names.TSetReadWriteMarshaler; if (property.HasAnyPropertyFlags(EPropertyFlags.BlueprintReadOnly)) { setMarshalerName = Names.TSetReadOnlyMarshaler; } USetProperty setProperty = property as USetProperty; builder.AppendLine(setMarshalerName + "<" + GetTypeName(setProperty.ElementProp, namespaces) + "> " + propertyName + Settings.VarNames.CollectionMarshalerCached + ";"); } break; case EPropertyType.Map: if (IsOwnerClassOrStructAsClass(property)) { string mapMarshalerName = Names.TMapReadWriteMarshaler; if (property.HasAnyPropertyFlags(EPropertyFlags.BlueprintReadOnly)) { mapMarshalerName = Names.TMapReadOnlyMarshaler; } UMapProperty mapProperty = property as UMapProperty; builder.AppendLine(mapMarshalerName + "<" + GetTypeName(mapProperty.KeyProp, namespaces) + ", " + GetTypeName(mapProperty.ValueProp, namespaces) + "> " + propertyName + Settings.VarNames.CollectionMarshalerCached + ";"); } break; } }
private void GenerateCodeForProperty(UnrealModuleInfo module, CSharpTextBuilder builder, CSharpTextBuilder offsetsBuilder, CollapsedMember collapsedMember, bool isBlueprintType, List <string> namespaces) { StringBuilder modifiers = new StringBuilder(); if (collapsedMember.BackingProperty != null) { UProperty property = collapsedMember.BackingProperty; if (property.HasAnyPropertyFlags(EPropertyFlags.DisableEditOnInstance) && !property.GetBoolMetaData(MDProp.AllowPrivateAccess)) { modifiers.Append("private"); } else if (property.HasAnyPropertyFlags(EPropertyFlags.NativeAccessSpecifierProtected | EPropertyFlags.Protected)) { modifiers.Append("protected"); } else { modifiers.Append("public"); } } else { UFunction function = collapsedMember.Getter != null ? collapsedMember.Getter : collapsedMember.Setter; if (function.HasAnyFunctionFlags(EFunctionFlags.Protected)) { modifiers.Append("protected"); } else { modifiers.Append("public"); } } if (modifiers.Length > 0) { modifiers.Append(" "); } // Note: Potential issues with different categories/docs/attribute on BackingProperty/Getter/Setter UField field = collapsedMember.BackingProperty; if (field == null) { field = collapsedMember.Getter; if (field == null) { field = collapsedMember.Setter; } } // Use either the backing property or the getter function for the documentation UField fieldForDocumentation = collapsedMember.BackingProperty != null ? (UField)collapsedMember.BackingProperty : collapsedMember.Getter; string name = collapsedMember.ResolvedName != null ? collapsedMember.ResolvedName : collapsedMember.Name; string propertyName = GetName(field, name, Settings.MemberCasing, false, true); AppendGetterSetterOffsets(builder, offsetsBuilder, propertyName, collapsedMember.Getter == null || collapsedMember.Setter == null ? collapsedMember.BackingProperty : null, namespaces, collapsedMember.Getter, collapsedMember.Setter); AppendDocComment(builder, fieldForDocumentation, isBlueprintType); AppendAttribute(builder, field, module, true); builder.AppendLine(modifiers + GetTypeName(collapsedMember.Property, namespaces) + " " + propertyName); builder.OpenBrace(); if (collapsedMember.Getter != null) { AppendGetter(builder, propertyName, collapsedMember.Getter, namespaces); } else if (collapsedMember.BackingProperty != null) { AppendGetter(builder, propertyName, collapsedMember.BackingProperty, namespaces); } if (collapsedMember.Setter != null) { AppendSetter(builder, propertyName, collapsedMember.Setter, namespaces); } else if (collapsedMember.BackingProperty != null) { AppendSetter(builder, propertyName, collapsedMember.BackingProperty, namespaces); } builder.CloseBrace(); builder.AppendLine(); }
/// <summary> /// Dynamically invokes the function /// </summary> /// <param name="obj"></param> /// <param name="parameters"></param> /// <returns></returns> public object DynamicInvoke(UObject obj, params object[] parameters) { if (parameters == null) { parameters = new object[0]; } bool validParams = true; Dictionary <UProperty, Delegate> fromNativeParams = new Dictionary <UProperty, Delegate>(); Dictionary <UProperty, Delegate> toNativeParams = new Dictionary <UProperty, Delegate>(); UProperty returnValueProp = null; List <UProperty> paramProps = new List <UProperty>(); foreach (UProperty prop in GetProperties <UProperty>()) { if (prop.HasAnyPropertyFlags(EPropertyFlags.Parm)) { if (prop.HasAnyPropertyFlags(EPropertyFlags.ReturnParm)) { returnValueProp = prop; } else { paramProps.Add(prop); } Type paramType = UProperty.GetTypeFromProperty(prop); if (paramType == null) { validParams = false; break; } Delegate fromNative = MarshalingDelegateResolverSlow.GetFromNative(paramType); Delegate toNative = MarshalingDelegateResolverSlow.GetToNative(paramType); if (fromNative == null || toNative == null) { validParams = false; break; } fromNativeParams.Add(prop, fromNative); toNativeParams.Add(prop, toNative); } } if (parameters.Length != paramProps.Count) { validParams = false; } if (!validParams) { return(null); } // Sort the parameters by offset, this is assumingly the correct thing to do? // - Otherwise we need to take the param names into this function. Or just not sort at all? //paramProps.Sort((x, y) => x.GetOffset_ForUFunction().CompareTo(y.GetOffset_ForUFunction())); object result = null; unsafe { int paramsSize = ParmsSize; byte * paramsBufferAllocation = stackalloc byte[ParmsSize]; IntPtr paramsBuffer = new IntPtr(paramsBufferAllocation); FMemory.Memzero(paramsBuffer, paramsSize); // Initialize default values for all parameters foreach (UProperty prop in GetProperties <UProperty>()) { if (prop.HasAnyPropertyFlags(EPropertyFlags.Parm)) { Native.Native_UProperty.InitializeValue_InContainer(prop.Address, paramsBuffer); } } // Copy the managed parameters to the buffer for (int i = 0; i < parameters.Length; i++) { UProperty paramProp = paramProps[i]; object paramValue = parameters[i]; if (paramValue != null && (!paramProp.HasAnyPropertyFlags(EPropertyFlags.OutParm) || paramProp.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm))) { toNativeParams[paramProp].DynamicInvoke( paramsBuffer + paramProp.GetOffset_ForUFunction(), (int)0, paramProp.Address, paramValue); } } // Invoke the function NativeReflection.InvokeFunction(obj.Address, Address, paramsBuffer, paramsSize); // Copy parameters / return value from the buffer for (int i = 0; i < parameters.Length; i++) { UProperty paramProp = paramProps[i]; if (paramProp.HasAnyPropertyFlags(EPropertyFlags.OutParm)) { parameters[i] = fromNativeParams[paramProp].DynamicInvoke( paramsBuffer + paramProp.GetOffset_ForUFunction(), (int)0, paramProp.Address); } } if (returnValueProp != null) { result = fromNativeParams[returnValueProp].DynamicInvoke( paramsBuffer + returnValueProp.GetOffset_ForUFunction(), (int)0, returnValueProp.Address); } // Destroy the memory for all of the parameters foreach (UProperty prop in GetProperties <UProperty>()) { if (prop.HasAnyPropertyFlags(EPropertyFlags.Parm)) { Native.Native_UProperty.DestroyValue_InContainer(prop.Address, paramsBuffer); } } } return(result); }
public void ResolveCollapsedMembers() { if (IsInterface) { // Interface shouldn't have any C# properties, leave everything as functions ResolveNameConflicts(); return; } collapsedMembers.Clear(); collapsedMembersByFunction.Clear(); collapsedMembersByProperty.Clear(); var getters = new Dictionary <UFunction, CodeGeneratorSettings.CollapsedMemberSettings>(); var setters = new Dictionary <UFunction, CodeGeneratorSettings.CollapsedMemberSettings>(); // Conflicts aren't resolved at this point. May have multiple functions for a given name. // - If there are conflicts avoid collapsing those functions. Dictionary <string, List <UFunction> > gettersByName = new Dictionary <string, List <UFunction> >(); Dictionary <string, List <UFunction> > settersByName = new Dictionary <string, List <UFunction> >(); foreach (UFunction function in exportableFunctions) { string functionName = codeGenerator.GetFunctionName(function, false); // 1 param either as return value or parameter and no return if (function.NumParms == 1) { UProperty returnProperty = function.GetReturnProperty(); if (returnProperty != null) { // Getter foreach (var collapsedSetting in codeGenerator.Settings.CollapsedMembers) { if (!string.IsNullOrEmpty(collapsedSetting.GetPrefix) && functionName.StartsWith(collapsedSetting.GetPrefix) && (!collapsedSetting.RequiresBool || returnProperty.IsA <UBoolProperty>())) { getters.Add(function, collapsedSetting); string trimmedName = functionName.Substring(collapsedSetting.GetPrefix.Length); if (trimmedName.Length > 0) { List <UFunction> functions; if (!gettersByName.TryGetValue(trimmedName, out functions)) { gettersByName.Add(trimmedName, functions = new List <UFunction>()); } functions.Add(function); } break; } } } else { // Setter UProperty firstParam = function.GetFirstParam(); if (firstParam != null) { foreach (var collapsedSetting in codeGenerator.Settings.CollapsedMembers) { if (!string.IsNullOrEmpty(collapsedSetting.SetPrefix) && functionName.StartsWith(collapsedSetting.SetPrefix) && (!collapsedSetting.RequiresBool || firstParam.IsA <UBoolProperty>())) { setters.Add(function, collapsedSetting); string trimmedName = functionName.Substring(collapsedSetting.GetPrefix.Length); if (trimmedName.Length > 0) { List <UFunction> functions; if (!settersByName.TryGetValue(trimmedName, out functions)) { settersByName.Add(trimmedName, functions = new List <UFunction>()); } functions.Add(function); } break; } } } } } } for (int i = 0; i < 2; i++) { bool isGetter = i == 0; Dictionary <string, List <UFunction> > collection = isGetter ? gettersByName : settersByName; foreach (KeyValuePair <string, List <UFunction> > funcs in collection) { if (funcs.Value.Count != 1) { continue; } string name = funcs.Key; UFunction getter = isGetter ? funcs.Value[0] : null; UFunction setter = !isGetter ? funcs.Value[0] : null; CodeGeneratorSettings.CollapsedMemberSettings settings = null; UProperty paramOrRetValProperty = null; Dictionary <string, List <UFunction> > otherCollection = isGetter ? settersByName : gettersByName; List <UFunction> otherFuncs; if (otherCollection.TryGetValue(funcs.Key, out otherFuncs)) { if (otherFuncs.Count > 1) { // Other function has a conflict continue; } if (isGetter) { setter = otherFuncs[0]; } else { getter = otherFuncs[0]; } } if ((getter != null && collapsedMembersByFunction.ContainsKey(getter)) || (setter != null && collapsedMembersByFunction.ContainsKey(setter))) { continue; } if (getter != null && setter != null) { UProperty returnProperty = getter.GetReturnProperty(); UProperty firstParam = setter.GetFirstParam(); if (returnProperty != null && firstParam != null && !returnProperty.SameType(firstParam)) { // Property type mismatch on Get/Set functions continue; } } if (getter != null) { paramOrRetValProperty = getter.GetReturnProperty(); settings = getters[getter]; } else if (setter != null) { paramOrRetValProperty = setter.GetFirstParam(); settings = setters[setter]; } if (paramOrRetValProperty == null) { continue; } UProperty backingProperty = null; bool backingPropertyExportable = false; foreach (KeyValuePair <UProperty, string> property in exportableProperties) { if (name == codeGenerator.GetMemberName(property.Key, false, property.Value) && property.Key.SameType(paramOrRetValProperty)) { if (backingProperty != null) { // Skip conflicts continue; } backingProperty = property.Key; backingPropertyExportable = true; } } if (backingProperty == null) { foreach (KeyValuePair <UProperty, string> property in nonExportableProperties) { if (name == codeGenerator.GetMemberName(property.Key, false, property.Value) && property.Key.SameType(paramOrRetValProperty)) { if (backingProperty != null) { // Skip conflicts continue; } backingProperty = property.Key; backingPropertyExportable = false; } } } if (getter == null && setter != null) { // SetXXX exists but there isn't a backing property or the backing property isn't // exportable so there wouldn't be any way access the property. Leave the function // as it is rather than creating a setter-only C# property unless the getter is injected. if (backingProperty == null || (!backingPropertyExportable && !settings.InjectNonExportableProperty)) { continue; } if (settings.SetRequiresGet) { continue; } } else if (getter != null && setter == null) { if (settings.GetRequiresSet) { continue; } } if ((getter != null && getter.HasAllFunctionFlags(EFunctionFlags.BlueprintEvent)) || (setter != null && setter.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent))) { // Skip events as they need a normal method body continue; } string finalName = name; if (!settings.StripPrefix && (getter == null || setter == null)) { if (getter != null) { finalName = settings.GetPrefix + finalName; } else if (setter != null) { finalName = settings.SetPrefix + finalName; } } if (backingProperty != null && backingProperty.HasAnyPropertyFlags(EPropertyFlags.BlueprintReadOnly) && IsCollectionProperty(backingProperty) && setter != null) { // If there is a backing property which is a readonly collection and there is a setter method then // there will be type conflicts. Don't collapse them. continue; } // Some validation on bool properties { UBoolProperty getterReturn = getter == null ? null : getter.GetReturnProperty() as UBoolProperty; UBoolProperty setterParam = setter == null ? null : setter.GetFirstParam() as UBoolProperty; if (getterReturn != null && setterParam != null) { System.Diagnostics.Debug.Assert(getterReturn.ElementSize == setterParam.ElementSize, "Get/Set use different bool size"); } UBoolProperty backingBoolProperty = backingProperty as UBoolProperty; if (backingBoolProperty != null) { if (getter != null) { System.Diagnostics.Debug.Assert(backingBoolProperty.ElementSize == getterReturn.ElementSize, "BackingProperty/Get use different bool size"); } else if (setter != null) { System.Diagnostics.Debug.Assert(backingBoolProperty.ElementSize == setterParam.ElementSize, "BackingProperty/Set use different bool size"); } } } CollapsedMember collapsedMember = new CollapsedMember(settings); collapsedMember.BackingProperty = backingProperty; collapsedMember.IsBackingPropertyExportable = backingPropertyExportable; collapsedMember.Getter = getter; collapsedMember.Setter = setter; collapsedMember.Name = finalName; collapsedMember.Property = paramOrRetValProperty; collapsedMembers.Add(collapsedMember); if (getter != null) { collapsedMembersByFunction.Add(getter, collapsedMember); } if (setter != null) { collapsedMembersByFunction.Add(setter, collapsedMember); } if (backingPropertyExportable) { collapsedMembersByProperty.Add(backingProperty, collapsedMember); } } } ResolveNameConflicts(); }
private void AppendFunctionBody(CSharpTextBuilder builder, UFunction function, bool isGetter, bool isSetter, bool perInstanceFunctionAddress, List <string> namespaces) { string functionName = GetFunctionName(function); UProperty blueprintReturnProperty = function.GetBlueprintReturnProperty(); bool isDelegate = function.HasAnyFunctionFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate); bool isStatic = function.HasAnyFunctionFlags(EFunctionFlags.Static); string targetAddress = isStatic ? Settings.VarNames.ClassAddress : Names.UObject_Address; string ownerName = isDelegate || isStatic ? "null" : "this"; string invokeFunction = isStatic ? Names.NativeReflection_InvokeStaticFunction : Names.NativeReflection_InvokeFunction; if (isGetter) { functionName += "_getter"; } else if (isSetter) { functionName += "_setter"; } string functionAddressName = functionName + (perInstanceFunctionAddress ? Settings.VarNames.InstanceFunctionAddress : Settings.VarNames.FunctionAddress); Dictionary <UProperty, string> paramNames = GetParamNames(function); if (isSetter) { System.Diagnostics.Debug.Assert(paramNames.Count == 1); } if (Settings.CheckObjectDestroyed && !isStatic && !function.HasAnyFunctionFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate)) { builder.AppendLine(Names.UObject_CheckDestroyed + "();"); } if (Settings.GenerateIsValidSafeguards) { builder.AppendLine("if (!" + functionName + Settings.VarNames.IsValid + ")"); builder.OpenBrace(); builder.AppendLine(Names.NativeReflection_LogInvalidFunctionAccessed + "(\"" + function.GetPathName() + "\");"); AppendFunctionBodyDefaultValues(builder, function, blueprintReturnProperty, false, true, paramNames, namespaces); builder.CloseBrace(); } if (perInstanceFunctionAddress) { builder.AppendLine("if (" + functionAddressName + " == IntPtr.Zero)"); builder.OpenBrace(); builder.AppendLine(functionAddressName + " = " + Names.NativeReflection_GetFunctionFromInstance + "(" + targetAddress + ", \"" + function.GetName() + "\");"); builder.CloseBrace(); } if (isDelegate) { builder.AppendLine("if (IsBound)"); builder.OpenBrace(); } builder.AppendLine("unsafe"); builder.OpenBrace(); builder.AppendLine("byte* " + Settings.VarNames.ParamsBufferAllocation + " = stackalloc byte[" + functionName + Settings.VarNames.ParamsSize + "];"); builder.AppendLine("IntPtr " + Settings.VarNames.ParamsBuffer + " = new IntPtr(" + Settings.VarNames.ParamsBufferAllocation + ");"); if (Settings.LazyFunctionParamInitDestroy) { builder.AppendLine(Names.NativeReflection_InvokeFunction_InitAll + "(" + functionAddressName + ", " + Settings.VarNames.ParamsBuffer + ");"); } else if (Settings.MemzeroStackalloc || Settings.MemzeroStackallocOnlyIfOut) { bool requiresMemzero = Settings.MemzeroStackalloc; if (Settings.MemzeroStackallocOnlyIfOut) { foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; // Memzero only if there is a return value or a (non ref) out param which doesn't have a zero constructor. // (if the param can't be zero initialized it will be initialized with a call to InitializeValue anyway) if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReturnParm | EPropertyFlags.OutParm) && !parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm) && !parameter.HasAnyPropertyFlags(EPropertyFlags.ZeroConstructor)) { requiresMemzero = true; break; } } } if (requiresMemzero) { builder.AppendLine(Names.FMemory_Memzero + "(" + Settings.VarNames.ParamsBuffer + ", " + functionName + Settings.VarNames.ParamsSize + ");"); } } bool hasRefOrOutParam = false; bool hasReturn = false; bool hasParamWithDtor = false; foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReturnParm) || parameter == blueprintReturnProperty) { hasReturn = true; continue; } else if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm | EPropertyFlags.OutParm)) { hasRefOrOutParam = true; } if (!Settings.LazyFunctionParamInitDestroy) { if (!parameter.HasAnyPropertyFlags(EPropertyFlags.ZeroConstructor)) { // Initialize values which don't have a zero constructor (this is required even though we will follow this up by a call // to ToNative as some structs have vtables e.g. FSlateBrush has its dtor in the vtable) builder.AppendLine(Names.NativeReflection_InitializeValue_InContainer + "(" + functionName + "_" + paramName + Settings.VarNames.PropertyAddress + "." + Names.UFieldAddress_Address + ", " + Settings.VarNames.ParamsBuffer + ");"); } if (!parameter.HasAnyPropertyFlags(EPropertyFlags.NoDestructor)) { // Parameter requires destruction hasParamWithDtor = true; } } if (parameter.HasAnyPropertyFlags(EPropertyFlags.Parm) && (!parameter.HasAnyPropertyFlags(EPropertyFlags.OutParm) || parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm))) { AppendPropertyToNative(builder, parameter, functionName + "_" + paramName, Settings.VarNames.ParamsBuffer, ownerName, isSetter ? "value" : paramName, true, namespaces); } } builder.AppendLine(); if (isDelegate) { builder.AppendLine(Names.FDelegateBase_ProcessDelegate + "(" + Settings.VarNames.ParamsBuffer + ");"); } else { builder.AppendLine(invokeFunction + "(" + targetAddress + ", " + functionAddressName + ", " + Settings.VarNames.ParamsBuffer + ", " + functionName + Settings.VarNames.ParamsSize + ");"); } if (hasReturn || hasRefOrOutParam || hasParamWithDtor) { builder.AppendLine(); foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; // If this is function is collapsed into a setter property then we can skip the FromNative calls as there shouldn't be // anything we need to extract back out (if there is, then using a setter instead of a function is incorrect in that case) if (!isSetter) { if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReturnParm) || parameter == blueprintReturnProperty) { AppendPropertyFromNative(builder, parameter, functionName + "_" + paramName, Settings.VarNames.ParamsBuffer, GetTypeName(parameter, namespaces) + " " + Settings.VarNames.ReturnResult, ownerName, true, namespaces); } else if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm | EPropertyFlags.OutParm)) { AppendPropertyFromNative(builder, parameter, functionName + "_" + paramName, Settings.VarNames.ParamsBuffer, paramName, ownerName, true, namespaces); } } if (!Settings.LazyFunctionParamInitDestroy && !parameter.HasAnyPropertyFlags(EPropertyFlags.NoDestructor)) { // Parameter requires destruction builder.AppendLine(Names.NativeReflection_DestroyValue_InContainer + "(" + functionName + "_" + paramName + Settings.VarNames.PropertyAddress + "." + Names.UFieldAddress_Address + ", " + Settings.VarNames.ParamsBuffer + ");"); } } } if (Settings.LazyFunctionParamInitDestroy) { builder.AppendLine(Names.NativeReflection_InvokeFunction_DestroyAll + "(" + functionAddressName + ", " + Settings.VarNames.ParamsBuffer + ");"); } if (hasReturn) { builder.AppendLine("return " + Settings.VarNames.ReturnResult + ";"); } builder.CloseBrace(); if (isDelegate) { builder.CloseBrace(); AppendFunctionBodyDefaultValues(builder, function, blueprintReturnProperty, true, false, paramNames, namespaces); } }
private void AppendFunctionOffsets(CSharpTextBuilder builder, CSharpTextBuilder offsetsBuilder, UFunction function, bool isGetter, bool isSetter, List <string> namespaces) { bool isInterface = false; UClass owner = function.GetOwnerClass(); if (owner != null && owner.ClassFlags.HasFlag(EClassFlags.Interface)) { isInterface = true; } string functionName = GetFunctionName(function); if (isGetter) { functionName += "_getter"; } else if (isSetter) { functionName += "_setter"; } Dictionary <UProperty, string> paramNames = GetParamNames(function); if (Settings.GenerateIsValidSafeguards) { builder.AppendLine("static bool " + functionName + Settings.VarNames.IsValid + ";"); } if ((function.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent) && function.GetSuperFunction() == null) || isInterface) { builder.AppendLine("IntPtr " + functionName + Settings.VarNames.InstanceFunctionAddress + ";"); } 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); } offsetsBuilder.AppendLine(functionName + Settings.VarNames.FunctionAddress + " = " + Names.NativeReflectionCached_GetFunction + "(" + Settings.VarNames.ClassAddress + ", \"" + function.GetName() + "\");"); offsetsBuilder.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(offsetsBuilder, 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; } offsetsBuilder.AppendLine(functionName + Settings.VarNames.IsValid + " = " + functionName + Settings.VarNames.FunctionAddress + " != IntPtr.Zero" + paramsValid + ";"); offsetsBuilder.AppendLine(Names.NativeReflection_LogFunctionIsValid + "(\"" + function.GetPathName() + "\", " + functionName + Settings.VarNames.IsValid + ");"); } }
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 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)); }