/// <summary> /// Gets the custom property name (blueprint struct var names) /// </summary> public string GetPropertyName(UProperty property) { string propertyName; exportableProperties.TryGetValue(property, out propertyName); return(propertyName); }
private bool ArePropertiesTheSame(UProperty a, UProperty b, bool checkPropertiesNames) { if (a == b) { return(true); } if (a == null || b == null)// one of properties is null { return(false); } if (checkPropertiesNames && (a.GetFName() != b.GetFName())) { return(false); } if (a.GetSize() != b.GetSize()) { return(false); } if (a.GetOffset_ForGC() != b.GetOffset_ForGC()) { return(false); } if (!Native_UProperty.SameType(a.Address, b.Address)) { return(false); } return(true); }
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); }
public void AddProperty(UProperty property, string bpVarName, bool exportable) { // If the ScriptName metadata is set use that for the property name instead string scriptName = property.GetMetaData(MDProp.ScriptName); if (!string.IsNullOrEmpty(scriptName)) { bpVarName = scriptName; } allProperties.Add(property, bpVarName); if (exportable) { exportableProperties.Add(property, bpVarName); if (IsBlittable && (!codeGenerator.IsBlittablePropertyType(property) || property.IsFixedSizeArray)) { IsBlittable = false; } } else { nonExportableProperties.Add(property, bpVarName); // This property isn't being exported, our struct size wont match the real struct size IsBlittable = false; } }
/// <summary> /// Returns the string representation of the equivalent output of a marshaler on zeroed memory for the given UProperty. /// For most types this will be "default(XXXX)". /// </summary> private string GetPropertyMarshalerDefaultValue(UProperty property, List <string> namespaces) { string typeName = GetTypeName(property, namespaces); // NOTE: Most of this is pretty useless, just remove this and use default(XXXX); // TODO: Implement and return safe versions of TArray/TSet/TMap which wrap a regular collection type // so that code which normally wouldn't result in an error can execute normally if (property.IsFixedSizeArray) { return("default(" + typeName + ")"); } switch (property.PropertyType) { case EPropertyType.Delegate: case EPropertyType.MulticastDelegate: return("new " + typeName + "()"); case EPropertyType.Str: return(Names.FStringMarshaler_DefaultString); default: return("default(" + typeName + ")"); } }
/// <summary> /// Returns true if the marshaler requires the property address for marshaling (in the FromNative/ToNative methods) /// </summary> private bool MarshalerRequiresNativePropertyField(UProperty property) { if (IsCollectionProperty(property)) { // Collections need the property for creating the marshaler, but not for the actual marshaling itself return(false); } return(RequiresNativePropertyField(property)); }
public static UObject FindImportedObject(UProperty property, UObject ownerObject, UObject objectClass, UClass requiredMetaClass, string text, uint portFlags) { using (FStringUnsafe textUnsafe = new FStringUnsafe(text)) { return(GCHelper.Find(Native_UObjectPropertyBase.FindImportedObject( property == null ? IntPtr.Zero : property.Address, ownerObject == null ? IntPtr.Zero : ownerObject.Address, objectClass == null ? IntPtr.Zero : objectClass.Address, requiredMetaClass == null ? IntPtr.Zero : requiredMetaClass.Address, ref textUnsafe.Array, portFlags))); } }
private bool CanExportProperty(UProperty property, UStruct owner, bool isBlueprintType) { bool export = CanExportPropertyImpl(property, owner, isBlueprintType); if (!export && forceExportProperties.Contains(property.GetPathName())) { return(true); } if (export && forceHideProperties.Contains(property.GetPathName())) { return(false); } return(export); }
private void AppendPropertyFromNative(CSharpTextBuilder builder, UProperty property, string propertyName, string baseAddressName, string assignTo, string ownerName, bool isFunction, List <string> namespaces) { if (assignTo == null || assignTo.Trim() == "return") { assignTo = "return "; } else { assignTo = assignTo + " = "; } AppendPropertyToFromNative(builder, property, propertyName, baseAddressName, ownerName, null, assignTo, isFunction, false, namespaces); }
/// <summary> /// Reimplementation of UFunction::IsSignatureCompatibleWith for debugging purposes /// (the native function with engine symbols debugs badly) /// </summary> internal bool InternalIsSignatureCompatibleWith(UFunction otherFunction, EPropertyFlags ignoreFlags) { // Early out if they're exactly the same function if (this == otherFunction) { return(true); } // Run thru the parameter property chains to compare each property TFieldIterator <UProperty> iteratorA = new TFieldIterator <UProperty>(this); TFieldIterator <UProperty> iteratorB = new TFieldIterator <UProperty>(otherFunction); while (iteratorA.Current != null && (iteratorA.Current.PropertyFlags.HasFlag(EPropertyFlags.Parm))) { if (iteratorB.Current != null && (iteratorB.Current.PropertyFlags.HasFlag(EPropertyFlags.Parm))) { // Compare the two properties to make sure their types are identical // Note: currently this requires both to be strictly identical and wouldn't allow functions that differ only by how derived a class is, // which might be desirable when binding delegates, assuming there is directionality in the SignatureIsCompatibleWith call UProperty propA = iteratorA.Current; UProperty propB = iteratorB.Current; EPropertyFlags flags1 = propA.PropertyFlags; EPropertyFlags flags2 = propB.PropertyFlags; if (!ArePropertiesTheSame(propA, propB, false)) { // Type mismatch between an argument of A and B return(false); } // Check the flags as well EPropertyFlags propertyMash = propA.PropertyFlags ^ propB.PropertyFlags; if ((propertyMash & ~ignoreFlags) != 0) { return(false); } } else { // B ran out of arguments before A did return(false); } iteratorA.MoveNext(); iteratorB.MoveNext(); } // They matched all the way thru A's properties, but it could still be a mismatch if B has remaining parameters return(!(iteratorB.Current != null && (iteratorB.Current.PropertyFlags.HasFlag(EPropertyFlags.Parm)))); }
private void UpdateAvailableTypesProp(UProperty property) { UField field1 = null; UField field2 = null; GetStructEnumOrFuncFromProp(property, out field1, out field2); if (field1 != null) { UpdateAvailableTypes(field1); } if (field2 != null) { UpdateAvailableTypes(field2); } }
/// <summary> /// Parses a text buffer into an object reference. /// </summary> /// <param name="property">the property that the value is being importing to</param> /// <param name="ownerObject">the object that is importing the value; used for determining search scope.</param> /// <param name="requiredMetaClass">the meta-class for the object to find; if the object that is resolved is not of this class type, the result is NULL.</param> /// <param name="portFlags">bitmask of EPropertyPortFlags that can modify the behavior of the search</param> /// <param name="buffer">the text to parse; should point to a textual representation of an object reference. Can be just the object name (either fully /// fully qualified or not), or can be formatted as a const object reference (i.e. SomeClass'SomePackage.TheObject') /// When the function returns, Buffer will be pointing to the first character after the object value text in the input stream.</param> /// <param name="resolvedValue">receives the object that is resolved from the input text.</param> /// <returns>true if the text is successfully resolved into a valid object reference of the correct type, false otherwise.</returns> public static bool ParseObjectPropertyValue(UProperty property, UObject ownerObject, UClass requiredMetaClass, uint portFlags, string buffer, out UObject resolvedValue) { using (FStringUnsafe bufferUnsafe = new FStringUnsafe(buffer)) { IntPtr outResolvedValueAddress = IntPtr.Zero; bool result = Native_UObjectPropertyBase.ParseObjectPropertyValue( property == null ? IntPtr.Zero : property.Address, ownerObject == null ? IntPtr.Zero : ownerObject.Address, requiredMetaClass == null ? IntPtr.Zero : requiredMetaClass.Address, portFlags, ref bufferUnsafe.Array, ref outResolvedValueAddress); resolvedValue = GCHelper.Find(outResolvedValueAddress); return(result); } }
/// <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 void AppendGetterSetterOffsets(CSharpTextBuilder builder, CSharpTextBuilder offsetsBuilder, string propertyName, UProperty property, List <string> namespaces, UFunction getter = null, UFunction setter = null) { if (getter != null) { AppendFunctionOffsets(builder, offsetsBuilder, getter, true, false, namespaces); } if (setter != null) { AppendFunctionOffsets(builder, offsetsBuilder, setter, false, true, namespaces); } if (property != null) { AppendPropertyOffset(builder, propertyName, property, false, namespaces); AppendPropertyOffsetNativeTypeLoader(offsetsBuilder, propertyName, property, null); } }
public void AddProperty(UProperty property, string bpVarName, bool exportable) { allProperties.Add(property, bpVarName); if (exportable) { exportableProperties.Add(property, bpVarName); if (IsBlittable && (!codeGenerator.IsBlittablePropertyType(property) || property.IsFixedSizeArray)) { IsBlittable = false; } } else { nonExportableProperties.Add(property, bpVarName); // This property isn't being exported, our struct size wont match the real struct size IsBlittable = false; } }
private void AddMember(UField field, string name, bool isResolvedName) { CollapsedMember collapsedMember = null; UProperty property = field as UProperty; if (property != null) { structInfo.collapsedMembersByProperty.TryGetValue(property, out collapsedMember); } UFunction function = field as UFunction; if (function != null) { structInfo.collapsedMembersByFunction.TryGetValue(function, out collapsedMember); } if (collapsedMember != null) { if (isResolvedName) { collapsedMember.ResolvedName = name; } else { name = collapsedMember.Name; } } NameConflictFieldInfo fieldInfo; if (!MembersByName.TryGetValue(name, out fieldInfo)) { MembersByName.Add(name, fieldInfo = new NameConflictFieldInfo(name)); } fieldInfo.AddField(field, collapsedMember); }
/// <summary> /// Returns true if the property address is required by generated code /// </summary> private bool RequiresNativePropertyField(UProperty property) { if (!Settings.LazyFunctionParamInitDestroy && property.GetOwnerStruct().IsA <UFunction>()) { // We need the property address to call InitializeValue / DestroyValue if (!property.HasAllPropertyFlags(EPropertyFlags.ZeroConstructor | EPropertyFlags.NoDestructor)) { return(true); } return(true); } if (property.IsFixedSizeArray) { return(true); } switch (property.PropertyType) { case EPropertyType.Enum: case EPropertyType.Bool: case EPropertyType.Array: case EPropertyType.Set: case EPropertyType.Map: return(true); default: UNumericProperty numericProperty = property as UNumericProperty; if ((numericProperty != null && numericProperty.IsEnum && numericProperty.GetIntPropertyEnum() != null)) { return(true); } break; } return(false); }
private string GetBlittablePropertyTypeName(UProperty property, List <string> namespaces) { if (!IsBlittablePropertyType(property)) { return(null); } switch (property.PropertyType) { case EPropertyType.Name: return(Names.FName); case EPropertyType.Int8: return("sbyte"); case EPropertyType.Byte: return("byte"); case EPropertyType.Int16: return("short"); case EPropertyType.UInt16: return("ushort"); case EPropertyType.Int: return("int"); case EPropertyType.UInt32: return("uint"); case EPropertyType.Int64: return("long"); case EPropertyType.UInt64: return("ulong"); case EPropertyType.Float: return("float"); case EPropertyType.Double: return("double"); case EPropertyType.Struct: return(GetTypeName(property, namespaces)); default: return(null); } }
/// <summary> /// Blueprints will always have return values as out values. If there is a single out value treat it /// as the return value instead. /// </summary> internal UProperty GetBlueprintReturnProperty() { UClass owner = GetOwnerClass(); bool isBlueprintType = owner != null && owner.IsA <UBlueprintGeneratedClass>(); if (!isBlueprintType) { return(null); } if (GetReturnProperty() != null) { return(null); } UProperty returnProperty = null; foreach (UProperty parameter in GetFields <UProperty>()) { if (!parameter.HasAnyPropertyFlags(EPropertyFlags.Parm)) { continue; } if (parameter.HasAnyPropertyFlags(EPropertyFlags.OutParm) && !parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm)) { if (returnProperty != null) { return(null); } returnProperty = parameter; } } return(returnProperty); }
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 GetMarshalerFromProperty(UProperty property, List <string> namespaces, bool isFunction) { return(GetMarshalerFromProperty(property, namespaces, isFunction, false)); }
private void AppendPropertyDestroy(CSharpTextBuilder builder, UProperty property, string propertyName, string baseAddressName, List <string> namespaces) { throw new NotImplementedException(); }
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); } } } }
private void AppendAttribute(CSharpTextBuilder builder, UField field, UnrealModuleInfo module, bool isCollapsedMember) { UnrealModuleType moduleType; UnrealModuleType moduleAssetType; string moduleName = GetModuleName(field, out moduleType, out moduleAssetType); if (string.IsNullOrEmpty(moduleName)) { moduleName = module.Name; } List <string> attributes = new List <string>(); // TODO: Combine all of this into EPropertyType (add some TypeCode into UField?) bool isInterface = false; UEnum unrealEnum = field as UEnum; UClass unrealClass = field as UClass; UScriptStruct unrealStruct = field as UScriptStruct; UFunction unrealFunction = field as UFunction; if (unrealFunction != null) { if (unrealFunction.HasAnyFunctionFlags(EFunctionFlags.Delegate)) { attributes.Add("UDelegate"); } else { string additionalFunctionInfo = string.Empty; // TODO: Only get the script name for virtual functions / interface functions as we currently only need // this for finding the base function for hooking things up to the native base types. string scriptFunctionName; if (unrealFunction.GetScriptName(out scriptFunctionName)) { additionalFunctionInfo += ", OriginalName=\"" + unrealFunction.GetName() + "\""; } if (isCollapsedMember) { // The Flags here might not contain too useful information if there is both a get/set function. // Maybe include a second flags var? attributes.Add("UFunctionAsProp(Flags=0x" + ((uint)unrealFunction.FunctionFlags).ToString("X8") + additionalFunctionInfo + ")"); } else { attributes.Add("UFunction(Flags=0x" + ((uint)unrealFunction.FunctionFlags).ToString("X8") + additionalFunctionInfo + ")"); } } } UProperty unrealProperty = field as UProperty; if (unrealProperty != null) { attributes.Add("UProperty(Flags=(PropFlags)0x" + ((ulong)unrealProperty.PropertyFlags).ToString("X16") + ")"); } if (unrealStruct != null) { attributes.Add("UStruct(Flags=0x" + ((uint)unrealStruct.StructFlags).ToString("X8") + ")"); } else if (unrealClass != null) { // Abstract isn't really required but might help with code browsing to know what is abstract // and what isn't. Therefore put it at the start of the attributes list. if (unrealClass.HasAnyClassFlags(EClassFlags.Abstract)) { attributes.Add("Abstract"); } isInterface = unrealClass.IsChildOf <UInterface>(); if (isInterface) { attributes.Add("UInterface(Flags=0x" + ((uint)unrealClass.ClassFlags).ToString("X8") + ")"); } else { attributes.Add("UClass(Flags=(ClassFlags)0x" + ((uint)unrealClass.ClassFlags).ToString("X8") + ")"); } } if (unrealEnum != null) { attributes.Add("UEnum"); } if (unrealEnum != null || unrealClass != null || unrealStruct != null) { bool blueprintType = false; bool blueprintable = false; if (unrealEnum != null) { blueprintType = field.GetBoolMetaData(MDClass.BlueprintType); } else { GetBlueprintability(field as UStruct, out blueprintType, out blueprintable); } if (blueprintType) { attributes.Add(UMeta.GetKey(MDClass.BlueprintType)); } if (unrealClass != null && blueprintable) { attributes.Add(UMeta.GetKey(MDClass.Blueprintable)); } attributes.Add("UMetaPath(\"" + field.GetPathName() + "\"" + (isInterface ? ", InterfaceImpl=typeof(" + GetTypeName(unrealClass, null) + "Impl" + ")" : string.Empty) + ")"); } else { attributes.Add("UMetaPath(\"" + field.GetPathName() + "\")"); } if (attributes.Count > 0) { builder.AppendLine("[" + string.Join(", ", attributes) + "]"); } }
/// <summary> /// Appends property info in the native type info loader function used to get the offsets / addresses of members /// </summary> private void AppendPropertyOffsetNativeTypeLoader(CSharpTextBuilder offsetsBuilder, string propertyName, UProperty property, string functionName) { string ownerAddressName = null; if (!string.IsNullOrEmpty(functionName)) { ownerAddressName = functionName + Settings.VarNames.FunctionAddress; } else { ownerAddressName = Settings.VarNames.ClassAddress; } if (RequiresNativePropertyField(property)) { // XXXX_PropertyAddress (addres of the property) // NativeReflection.GetPropertyRef(ref XXXX_PropertyAddress, classAddress, "propertyName"); offsetsBuilder.AppendLine(Names.NativeReflectionCached_GetPropertyRef + "(ref " + propertyName + Settings.VarNames.PropertyAddress + ", " + ownerAddressName + ", \"" + property.GetName() + "\");"); } // XXXX_Offset (offset of the property) offsetsBuilder.AppendLine(propertyName + Settings.VarNames.MemberOffset + " = " + Names.NativeReflectionCached_GetPropertyOffset + "(" + ownerAddressName + ", \"" + property.GetName() + "\");"); if (Settings.GenerateIsValidSafeguards) { string propertyClassName; if (!NativeReflection.TryGetPropertyClassName(property.PropertyType, out propertyClassName)) { propertyClassName = "UNKNOWN"; } // XXXX_IsValid = NativeReflection.ValidatePropertyClass(classAddress, "propertyName", Classes.UXXXXProperty); offsetsBuilder.AppendLine(propertyName + Settings.VarNames.IsValid + " = " + Names.NativeReflectionCached_ValidatePropertyClass + "(" + ownerAddressName + ", \"" + property.GetName() + "\", " + Names.Classes + "." + propertyClassName + ");"); } }
/// <summary> /// Returns true if the owner of the given property is a UClass or a UScriptStruct which is being generated /// as a class in managed code /// </summary> private bool IsOwnerClassOrStructAsClass(UProperty property) { return(IsClassOrStructAsClass(property.GetOwnerStruct())); }
private void AppendPropertyToNative(CSharpTextBuilder builder, UProperty property, string propertyName, string baseAddressName, string ownerName, string varName, bool isFunction, List <string> namespaces) { AppendPropertyToFromNative(builder, property, propertyName, baseAddressName, ownerName, varName, null, isFunction, true, namespaces); }
/// <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(); }