private void GenerateCodeForStruct(UnrealModuleInfo module, UStruct unrealStruct) { bool isBlueprintType = unrealStruct.IsA <UUserDefinedStruct>() || unrealStruct.IsA <UBlueprintGeneratedClass>(); StructInfo structInfo = GetStructInfo(unrealStruct, isBlueprintType); string typeName = GetTypeName(unrealStruct); UnrealModuleType moduleAssetType; string currentNamespace = GetModuleNamespace(unrealStruct, out moduleAssetType); List <string> namespaces = GetDefaultNamespaces(); CSharpTextBuilder builder = new CSharpTextBuilder(Settings.IndentType); if (!string.IsNullOrEmpty(currentNamespace)) { builder.AppendLine("namespace " + currentNamespace); builder.OpenBrace(); } string accessSpecifier = "public"; StringBuilder modifiers = new StringBuilder(accessSpecifier); if (Settings.UseAbstractTypes && structInfo.IsClass && structInfo.Class.HasAnyClassFlags(EClassFlags.Abstract)) { modifiers.Append(" abstract"); } StringBuilder baseTypeStr = new StringBuilder(); UStruct parentStruct = unrealStruct.GetSuperStruct(); if (parentStruct != null && parentStruct != UClass.GetClass <UInterface>() && unrealStruct != UClass.GetClass <UInterface>()) { baseTypeStr.Append(GetTypeName(parentStruct, namespaces)); } if (structInfo.IsClass) { foreach (FImplementedInterface implementedInterface in structInfo.Class.Interfaces) { if (baseTypeStr.Length > 0) { baseTypeStr.Append(", "); } baseTypeStr.Append(GetTypeName(implementedInterface.InterfaceClass, namespaces)); } } if (baseTypeStr.Length > 0) { baseTypeStr.Insert(0, " : "); } AppendDocComment(builder, unrealStruct, isBlueprintType); AppendAttribute(builder, unrealStruct, module, structInfo); if (structInfo.IsInterface) { System.Diagnostics.Debug.Assert(structInfo.Class.Interfaces.Length == 0, "TODO: Interfaces inheriting other interfaces"); string baseInterface = unrealStruct == UClass.GetClass <UInterface>() ? string.Empty : (baseTypeStr.Length == 0 ? " : " : ", ") + Names.IInterface; builder.AppendLine(modifiers + " interface " + typeName + baseTypeStr + baseInterface); } else if (structInfo.IsClass) { builder.AppendLine(modifiers + " partial class " + typeName + baseTypeStr); } else { if (structInfo.StructAsClass) { builder.AppendLine(modifiers + " partial class " + typeName + " : " + Names.StructAsClass); } else { if (structInfo.IsBlittable) { string structLayout = UpdateTypeNameNamespace("StructLayout", "System.Runtime.InteropServices", namespaces); string layoutKind = UpdateTypeNameNamespace("LayoutKind", "System.Runtime.InteropServices", namespaces); builder.AppendLine("[" + structLayout + "(" + layoutKind + ".Sequential)]"); } builder.AppendLine(modifiers + " partial struct " + typeName); } } builder.OpenBrace(); string typeNameEx = structInfo.IsInterface ? typeName + "Impl" : typeName; // Create a seperate builder for building the interface "Impl" class CSharpTextBuilder interfaceImplBuilder = null; if (structInfo.IsInterface) { interfaceImplBuilder = new CSharpTextBuilder(); interfaceImplBuilder.AppendLine(accessSpecifier + " sealed class " + typeNameEx + " : " + Names.IInterfaceImpl + ", " + typeName); interfaceImplBuilder.Indent(); // Move the indent to the same as builder for this point interfaceImplBuilder.OpenBrace(); // Open the class brace } // Create a seperate builder for properties which will be inserted into the native type info initializer CSharpTextBuilder offsetsBuilder = new CSharpTextBuilder(Settings.IndentType); offsetsBuilder.AppendLine("static " + typeNameEx + "()"); offsetsBuilder.IndentCount = builder.IndentCount;// Move the indent to the same as builder offsetsBuilder.OpenBrace(); offsetsBuilder.AppendLine("if (" + Names.UnrealTypes_CanLazyLoadNativeType + "(typeof(" + typeNameEx + ")))"); offsetsBuilder.OpenBrace(); offsetsBuilder.AppendLine(Settings.VarNames.LoadNativeType + "();"); offsetsBuilder.CloseBrace(); offsetsBuilder.AppendLine(Names.UnrealTypes_OnCCtorCalled + "(typeof(" + typeNameEx + "));"); offsetsBuilder.CloseBrace(); offsetsBuilder.AppendLine(); offsetsBuilder.AppendLine("static void " + Settings.VarNames.LoadNativeType + "()"); offsetsBuilder.OpenBrace(); if (structInfo.HasStaticFunction) { builder.AppendLine("static IntPtr " + Settings.VarNames.ClassAddress + ";"); offsetsBuilder.AppendLine(Settings.VarNames.ClassAddress + " = " + (structInfo.IsStruct ? Names.NativeReflection_GetStruct : Names.NativeReflection_GetClass) + "(\"" + unrealStruct.GetPathName() + "\");"); } else { offsetsBuilder.AppendLine("IntPtr " + Settings.VarNames.ClassAddress + " = " + (structInfo.IsStruct ? Names.NativeReflection_GetStruct : Names.NativeReflection_GetClass) + "(\"" + unrealStruct.GetPathName() + "\");"); } if (structInfo.StructAsClass) { offsetsBuilder.AppendLine(typeName + Settings.VarNames.StructAddress + " = " + Settings.VarNames.ClassAddress + ";"); } else if (structInfo.IsStruct) { offsetsBuilder.AppendLine(typeName + Settings.VarNames.StructSize + " = " + Names.NativeReflection_GetStructSize + "(" + Settings.VarNames.ClassAddress + ");"); } if (structInfo.IsStruct && parentStruct != null) { // Export base properties if (Settings.InlineBaseStruct || structInfo.StructAsClass) { UScriptStruct tempParentStruct = parentStruct as UScriptStruct; while (tempParentStruct != null) { StructInfo tempParentStructInfo = GetStructInfo(tempParentStruct); if (tempParentStructInfo != null) { foreach (UProperty property in tempParentStructInfo.GetProperties()) { if (!tempParentStructInfo.IsCollapsedProperty(property)) { GenerateCodeForProperty(module, builder, offsetsBuilder, property, tempParentStructInfo.IsBlueprintType, structInfo, namespaces, tempParentStructInfo.GetPropertyName(property)); } } } tempParentStruct = tempParentStruct.GetSuperStruct() as UScriptStruct; } } else { builder.AppendLine(GetTypeName(parentStruct, namespaces) + " Base;"); } } // Export properties foreach (UProperty property in structInfo.GetProperties()) { if (!structInfo.IsCollapsedProperty(property)) { GenerateCodeForProperty(module, builder, offsetsBuilder, property, isBlueprintType, structInfo, namespaces, structInfo.GetPropertyName(property)); } } foreach (CollapsedMember collapsedMember in structInfo.GetCollapsedMembers()) { GenerateCodeForProperty(module, builder, offsetsBuilder, collapsedMember, isBlueprintType, namespaces); } // Export functions List <ExtensionMethodInfo> extensionMethods = new List <ExtensionMethodInfo>(); foreach (UFunction function in structInfo.GetFunctions()) { if (!structInfo.IsCollapsedFunction(function)) { if (!structInfo.IsInterface) { // If this isn't an interface and the function can be made into an extension method then do so ExtensionMethodInfo extensionMethodInfo = ExtensionMethodInfo.Create(function); if (extensionMethodInfo != null) { extensionMethods.Add(extensionMethodInfo); } } if (function.HasAnyFunctionFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate)) { AppendDelegateSignature(module, builder, function, unrealStruct, isBlueprintType, namespaces); builder.AppendLine(); } else if (structInfo.IsInterface) { AppendFunctionOffsets(interfaceImplBuilder, offsetsBuilder, function, false, false, namespaces); AppendDocComment(builder, function, isBlueprintType); AppendAttribute(builder, function, module); builder.AppendLine(GetFunctionSignature(module, function, unrealStruct, namespaces) + ";"); builder.AppendLine(); // Always require a per-instance function address on the interfaces "Impl" class. // This isn't really required if the target function isn't an event but since we are working // with interfaces it is probably best to make sure functions are resolved properly. If we decide // to change this to not require a per-instance function address make sure to update AppendFunctionOffsets // which adds the per-instance function address to the class. Also update AssemblyRewriter.Interface.cs // Also update the "ResetInterface" code which always expects an per-instance address to reset. AppendAttribute(interfaceImplBuilder, function, module); interfaceImplBuilder.AppendLine(GetFunctionSignature(module, function, unrealStruct, null, "public", FunctionSigFlags.None, namespaces)); interfaceImplBuilder.OpenBrace(); AppendFunctionBody(interfaceImplBuilder, function, false, false, true, namespaces); interfaceImplBuilder.CloseBrace(); builder.AppendLine(); } else { AppendFunctionOffsets(builder, offsetsBuilder, function, false, false, namespaces); AppendDocComment(builder, function, isBlueprintType); AppendAttribute(builder, function, module); bool hasSuperFunction = function.GetSuperFunction() != null; if (function.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent) && !hasSuperFunction) { // Define the declaration method which will call the correct UFunction for the UObject instance builder.AppendLine(GetFunctionSignature(module, function, unrealStruct, namespaces)); builder.OpenBrace(); AppendFunctionBody(builder, function, false, false, true, namespaces); builder.CloseBrace(); builder.AppendLine(); } if (function.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent)) { if (!Settings.UseExplicitImplementationMethods) { // Used to hide the _Implementation method from being visible in intellisense builder.AppendLine("[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]"); } // Define the _Implementation method builder.AppendLine(GetFunctionSignatureImpl(module, function, unrealStruct, namespaces)); } else { builder.AppendLine(GetFunctionSignature(module, function, unrealStruct, namespaces)); } builder.OpenBrace(); AppendFunctionBody(builder, function, false, false, false, namespaces); builder.CloseBrace(); builder.AppendLine(); } } } if (structInfo.StructAsClass) { if (Settings.GenerateIsValidSafeguards) { builder.AppendLine("static bool " + typeName + Settings.VarNames.IsValid + ";"); // Append XXXX_IsValid = Prop1_IsValid && Prop2_IsValid && Prop3_IsValid...; AppendStructIsValid(offsetsBuilder, typeName, structInfo, parentStruct); } builder.AppendLine("static IntPtr " + typeName + Settings.VarNames.StructAddress + ";"); builder.AppendLine(); builder.AppendLine("protected override IntPtr GetStructAddress()"); builder.OpenBrace(); builder.AppendLine("return " + typeName + Settings.VarNames.StructAddress + ";"); builder.CloseBrace(); builder.AppendLine(); } else if (structInfo.IsStruct) { if (Settings.GenerateIsValidSafeguards && !structInfo.IsBlittable) { builder.AppendLine("static bool " + typeName + Settings.VarNames.IsValid + ";"); } builder.AppendLine("static int " + typeName + Settings.VarNames.StructSize + ";"); builder.AppendLine(); // Add the struct Copy() method (for non blittable structs) builder.AppendLine("public " + typeName + " " + Settings.VarNames.StructCopy + "()"); builder.OpenBrace(); builder.AppendLine(typeName + " result = this;"); foreach (UProperty property in structInfo.GetProperties()) { if (!structInfo.IsCollapsedProperty(property) && IsCollectionProperty(property)) { string propertyName = GetMemberName(property, structInfo.GetPropertyName(property)); builder.AppendLine("if (this." + propertyName + " != null)"); builder.OpenBrace(); UStructProperty structProperty = property as UStructProperty; StructInfo propertyStructInfo = structProperty == null || structProperty.Struct == null ? null : GetStructInfo(structProperty.Struct); if (propertyStructInfo != null && !propertyStructInfo.IsBlittable) { builder.AppendLine("result." + propertyName + " = new " + GetTypeName(property, namespaces) + "();"); builder.AppendLine("for (int i = 0; i < this." + propertyName + ".Count; ++i)"); builder.OpenBrace(); builder.AppendLine("result." + propertyName + ".Add(this." + propertyName + "[i]." + Settings.VarNames.StructCopy + "());"); builder.CloseBrace(); } else { builder.AppendLine("result." + propertyName + " = new " + GetTypeName(property, namespaces) + "(" + "this." + propertyName + ");"); } builder.CloseBrace(); } } if (Settings.InlineBaseStruct) { UScriptStruct tempParentStruct = parentStruct as UScriptStruct; while (tempParentStruct != null) { StructInfo tempParentStructInfo = GetStructInfo(tempParentStruct); if (tempParentStructInfo != null) { foreach (UProperty property in tempParentStructInfo.GetProperties()) { if (!tempParentStructInfo.IsCollapsedProperty(property) && IsCollectionProperty(property)) { string propertyName = GetMemberName(property, tempParentStructInfo.GetPropertyName(property)); builder.AppendLine("if (this." + propertyName + " != null)"); builder.OpenBrace(); builder.AppendLine("result." + propertyName + " = new " + GetTypeName(property, namespaces) + "(" + "this." + propertyName + ");"); builder.CloseBrace(); } } } tempParentStruct = tempParentStruct.GetSuperStruct() as UScriptStruct; } } builder.AppendLine("return result;"); builder.CloseBrace(); builder.AppendLine(); if (structInfo.IsBlittable) { // Validate the size of the blittable struct offsetsBuilder.AppendLine(Names.NativeReflection_ValidateBlittableStructSize + "(" + Settings.VarNames.ClassAddress + ", typeof(" + typeName + "));"); } else { if (Settings.GenerateIsValidSafeguards) { // Append XXXX_IsValid = Prop1_IsValid && Prop2_IsValid && Prop3_IsValid...; AppendStructIsValid(offsetsBuilder, typeName, structInfo, parentStruct); } builder.AppendLine("public static " + typeName + " FromNative(IntPtr nativeBuffer)"); builder.OpenBrace(); builder.AppendLine("return new " + typeName + "(nativeBuffer);"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public static void ToNative(IntPtr nativeBuffer, " + typeName + " value)"); builder.OpenBrace(); builder.AppendLine("value.ToNative(nativeBuffer);"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public static " + typeName + " FromNative(IntPtr nativeBuffer, int arrayIndex, IntPtr prop)"); builder.OpenBrace(); builder.AppendLine("return new " + typeName + "(nativeBuffer + (arrayIndex * " + typeName + Settings.VarNames.StructSize + "));"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public static void ToNative(IntPtr nativeBuffer, int arrayIndex, IntPtr prop, " + typeName + " value)"); builder.OpenBrace(); builder.AppendLine("value.ToNative(nativeBuffer + (arrayIndex * " + typeName + Settings.VarNames.StructSize + "));"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public void ToNative(IntPtr nativeStruct)"); builder.OpenBrace(); AppendStructMarshalerBody(builder, typeName, structInfo, parentStruct, true, namespaces); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public " + typeName + "(IntPtr nativeStruct)"); builder.OpenBrace(); /*if (Settings.UObjectAsBlittableType) * { * // UObject types will have an additional backing field which needs to be assigned before being able to * // assign the property * // - The alternative would be to modify the property assignment code to target the backing field instead of * // the property. This is probably the ideal way of doing it but we would need to use a different marshaler * // (BlittableTypeMarshaler<> instead of UObjectMarshaler<>) and ensure the marshaler change doesn't impact * // other generated code elsewhere. * foreach (UProperty property in structInfo.GetProperties()) * { * UObjectProperty objectProperty = property as UObjectProperty; * if (objectProperty != null) * { * string propertyName = GetMemberName(property, structInfo.GetPropertyName(property)); * builder.AppendLine(propertyName + Settings.VarNames.UObjectBlittableName + " = IntPtr.Zero;"); * } * } * }*/ AppendStructMarshalerBody(builder, typeName, structInfo, parentStruct, false, namespaces); builder.CloseBrace(); builder.AppendLine(); } } if (loadNativeTypeInjected.Contains(typeName)) { offsetsBuilder.AppendLine(Settings.VarNames.LoadNativeTypeInjected + "(" + Settings.VarNames.ClassAddress + ");"); } offsetsBuilder.CloseBrace(); // Add the offsets builder if it isn't empty (always required for structs due to struct size export) // Interfaces are built up seperately in a different class which must be added after the interface body. if (!structInfo.IsInterface && (structInfo.HasContent || structInfo.IsStruct)) { builder.AppendLine(offsetsBuilder.ToString()); builder.AppendLine(); } // Remove any trailing empty lines before adding the close brace builder.RemovePreviousEmptyLines(); builder.CloseBrace(); // Add the "Impl" wrapper class for interfaces. This is always required so that we have a default // interface implementation that we can call. if (structInfo.IsInterface) { if (structInfo.HasContent) { interfaceImplBuilder.AppendLine();// Whitespace // Add the ResetInterface method to reset the state of a pooled interface instance interfaceImplBuilder.AppendLine("public override void ResetInterface()"); interfaceImplBuilder.OpenBrace(); foreach (UFunction function in structInfo.GetFunctions()) { interfaceImplBuilder.AppendLine(GetFunctionName(function) + Settings.VarNames.InstanceFunctionAddress + " = IntPtr.Zero;"); } interfaceImplBuilder.CloseBrace(); interfaceImplBuilder.AppendLine(); // Whitespace } interfaceImplBuilder.AppendLine(offsetsBuilder.ToString()); // Add the offsets to the "Impl" class interfaceImplBuilder.CloseBrace(); // Add the close brace for the "Impl" class builder.AppendLine(); // Empty line between interface and "Impl" class builder.AppendLine(interfaceImplBuilder.ToString()); // Add the "Impl" class below the interface } if (!string.IsNullOrEmpty(currentNamespace)) { builder.CloseBrace(); } builder.InsertNamespaces(currentNamespace, namespaces, Settings.SortNamespaces); OnCodeGenerated(module, moduleAssetType, typeName, unrealStruct.GetPathName(), builder); if (extensionMethods.Count > 0) { GenerateCodeForExtensionMethods(module, unrealStruct, extensionMethods); } }
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 { 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 AppendStructMarshalerBody(CSharpTextBuilder builder, string structTypeName, StructInfo structInfo, UStruct parentStruct, bool toNative, List <string> namespaces) { if (Settings.GenerateIsValidSafeguards) { builder.AppendLine("if (!" + structTypeName + Settings.VarNames.IsValid + ")"); builder.OpenBrace(); builder.AppendLine(Names.NativeReflection_LogInvalidStructAccessed + "(\"" + structInfo.Struct.GetPathName() + "\");"); if (!toNative) { // Set default values for all properties AppendStructDefaultValuesOnInvalid(builder, structInfo, parentStruct, namespaces); } builder.AppendLine("return;"); builder.CloseBrace(); } foreach (UProperty property in structInfo.GetProperties()) { if (!structInfo.IsCollapsedProperty(property)) { string propertyName = GetMemberName(property, structInfo.GetPropertyName(property)); if (toNative) { AppendPropertyToNative(builder, property, propertyName, "nativeStruct", "null", propertyName, false, namespaces); } else { AppendPropertyFromNative(builder, property, propertyName, "nativeStruct", propertyName, "null", false, namespaces); } } } if (parentStruct != null) { if (Settings.InlineBaseStruct) { UScriptStruct tempParentStruct = parentStruct as UScriptStruct; while (tempParentStruct != null) { StructInfo tempParentStructInfo = GetStructInfo(tempParentStruct); if (tempParentStructInfo != null) { foreach (UProperty property in tempParentStructInfo.GetProperties()) { if (!tempParentStructInfo.IsCollapsedProperty(property)) { string propertyName = GetMemberName(property, tempParentStructInfo.GetPropertyName(property)); if (toNative) { AppendPropertyToNative(builder, property, propertyName, "nativeStruct", "null", propertyName, false, namespaces); } else { AppendPropertyFromNative(builder, property, propertyName, "nativeStruct", propertyName, "null", false, namespaces); } } } } tempParentStruct = tempParentStruct.GetSuperStruct() as UScriptStruct; } } else { if (toNative) { builder.AppendLine("Base.ToNative(nativeStruct);"); } else { builder.AppendLine("Base = new " + GetTypeName(parentStruct, namespaces) + "(nativeStruct);"); } } } }
/// <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: builder.AppendLine(GetTypeName(property, namespaces) + " " + propertyName + Settings.VarNames.DelegateCached + ";"); 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, 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 (property.HasAnyPropertyFlags(EPropertyFlags.DisableEditOnInstance) && !property.GetBoolMetaData(MDProp.AllowPrivateAccess)) { modifiers.Append("private"); } else if (!isOwnerStruct && property.HasAnyPropertyFlags(EPropertyFlags.NativeAccessSpecifierProtected | EPropertyFlags.Protected)) { 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) { UObjectProperty objectProperty = property as UObjectProperty; if (objectProperty != null && Settings.UObjectAsBlittableType) { 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) && !IsCollectionProperty(property) && !IsDelegateProperty(property) && !property.IsFixedSizeArray) { AppendSetter(builder, propertyName, property, namespaces); } builder.CloseBrace(); } builder.AppendLine(); }
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 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(); }
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 void AppendDocCommentSimple(CSharpTextBuilder builder, string summary) { string[] splitted = summary.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); List <StringBuilder> lines = new List <StringBuilder>(); foreach (string line in splitted) { lines.Add(new StringBuilder(line)); } // Trim the whitespace / '*' leading comment chars for (int i = lines.Count - 1; i >= 0; --i) { bool lineEmpty = true; StringBuilder line = lines[i]; for (int charIndex = 0; charIndex < line.Length; ++charIndex) { bool isWhiteSpace = char.IsWhiteSpace(line[charIndex]) || line[charIndex] == '*'; if (!isWhiteSpace) { lineEmpty = false; if (charIndex > 0) { line.Remove(0, charIndex); } DocTimTrailingChars(line); break; } } if (lineEmpty) { lines.RemoveAt(i); } } for (int i = 0; i < lines.Count; ++i) { StringBuilder line = lines[i]; if (i == 0) { if (lines.Count == 1) { builder.AppendLine("/// <summary>" + line.ToString() + "</summary>"); } else { builder.AppendLine("/// <summary>"); builder.AppendLine("/// " + line.ToString()); } } else { builder.AppendLine("/// " + line.ToString()); } } if (lines.Count > 1) { builder.AppendLine("/// </summary>"); } }
private void AppendDocCommentAndRename(CSharpTextBuilder builder, string summary) { if (Settings.SkipDocumentation || string.IsNullOrEmpty(summary)) { return; } string[] splitted = summary.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); List <StringBuilder> tempLines = new List <StringBuilder>(); foreach (string line in splitted) { tempLines.Add(new StringBuilder(line)); } bool injectReturnSummaryHeader = false;// An additional "Returns " header into injected summary int injectReturnSummaryIndex = -1; int returnSummaryStart = -1; DocSubSummary subSummaryType = DocSubSummary.None; Dictionary <int, DocSubSummary> beginSubSummaryLines = new Dictionary <int, DocSubSummary>(); int firstSubSummaryIndex = -1; List <StringBuilder> lines = new List <StringBuilder>(); int minMainSummaryTextOffset = int.MaxValue; // Get the sub summary lines and trim the whitespace / '*' leading comment chars for (int i = 0; i < tempLines.Count; i++) { StringBuilder line = tempLines[i]; int firstNonWhitespaceIndex = -1; int atIndex = -1;//'@' int startTagIndex = -1; int endTagIndex = -1; int startContentIndex = -1; for (int charIndex = 0; charIndex < line.Length; ++charIndex) { // Skip the whitespace / '*' leading comment chars bool isWhiteSpace = char.IsWhiteSpace(line[charIndex]) || line[charIndex] == '*'; if (firstNonWhitespaceIndex == -1 && !isWhiteSpace) { firstNonWhitespaceIndex = charIndex; if (firstSubSummaryIndex < 0) { minMainSummaryTextOffset = Math.Min(minMainSummaryTextOffset, firstNonWhitespaceIndex); } } // Treat '-' as whitespace when getting the tag if (line[charIndex] == '-') { isWhiteSpace = true; } if (atIndex == -1) { if (line[charIndex] == '@') { atIndex = charIndex; } } else if (startTagIndex == -1) { if (!isWhiteSpace) { startTagIndex = charIndex; } } else if (endTagIndex == -1) { if (isWhiteSpace) { endTagIndex = charIndex; } } else if (startContentIndex == -1) { if (!isWhiteSpace) { startContentIndex = charIndex; break; } } } DocSubSummary lineSubSummaryType = DocSubSummary.None; if (endTagIndex != -1) { string tag = line.ToString(startTagIndex, endTagIndex - startTagIndex); lineSubSummaryType = GetDocSubSummaryFromTag("@" + tag); } if (lineSubSummaryType != DocSubSummary.None) { // Remove any empty trailing lines which came before this sub summary for (int j = lines.Count - 1; j >= 0; j--) { if (lines[j].Length == 0) { lines.RemoveAt(j); } else { break; } } if (firstSubSummaryIndex == -1) { firstSubSummaryIndex = lines.Count; } beginSubSummaryLines[lines.Count] = lineSubSummaryType; if (startContentIndex <= 0) { line.Clear(); } else { line.Remove(0, startContentIndex); } lines.Add(line); } else { if (firstNonWhitespaceIndex < 0) { line.Clear(); } else if (firstNonWhitespaceIndex > 0) { // Trim the whitespace (if not using a common offset or this line isn't part of the main summary) if (!Settings.DocUseCommonSummaryTextOffset || firstSubSummaryIndex >= 0) { line.Remove(0, firstNonWhitespaceIndex); } } DocTimTrailingChars(line); lines.Add(line); } } if (Settings.DocUseCommonSummaryTextOffset && minMainSummaryTextOffset != int.MaxValue) { int mainSummaryEnd = Math.Min(lines.Count, firstSubSummaryIndex >= 0 ? firstSubSummaryIndex : int.MaxValue); for (int i = 0; i < mainSummaryEnd; i++) { StringBuilder line = lines[i]; if (line.Length >= minMainSummaryTextOffset) { line.Remove(0, minMainSummaryTextOffset); } } } // Remove any empty trailing lines for (int i = lines.Count - 1; i >= 0; --i) { if (lines[i].Length == 0 && !beginSubSummaryLines.ContainsKey(i)) { lines.RemoveAt(i); } else { break; } } for (int i = 0; i < lines.Count; ++i) { StringBuilder line = lines[i]; bool nextLineBeginSummary = beginSubSummaryLines.ContainsKey(i + 1) || i == lines.Count - 1; if (beginSubSummaryLines.ContainsKey(i)) { if (i == 0) { builder.AppendLine("/// <summary></summary>"); if (Settings.DocInjectReturnSummary) { foreach (KeyValuePair <int, DocSubSummary> lineSubSummary in beginSubSummaryLines) { if (lineSubSummary.Value == DocSubSummary.Return) { injectReturnSummaryIndex = builder.Length - ("</summary>".Length); break; } } } } else if (subSummaryType == DocSubSummary.None && i > 1) { builder.AppendLine("/// </summary>"); } subSummaryType = beginSubSummaryLines[i]; if (subSummaryType == DocSubSummary.Param || subSummaryType == DocSubSummary.Out || subSummaryType == DocSubSummary.outparam) { int paramNameEndIndex = -1; for (int charIndex = 0; charIndex < line.Length; ++charIndex) { if (char.IsWhiteSpace(line[charIndex])) { paramNameEndIndex = charIndex; break; } } if (paramNameEndIndex != -1) { int paramSummaryIndex = -1; for (int charIndex = paramNameEndIndex + 1; charIndex < line.Length; ++charIndex) { if (!char.IsWhiteSpace(line[charIndex]) && line[charIndex] != '-') { paramSummaryIndex = charIndex; break; } } string paramName = paramNameEndIndex == 0 ? string.Empty : line.ToString(0, paramNameEndIndex); if (Settings.DocUpdateParamCasing) { paramName = GetParamName(paramName); } string paramSummary = paramSummaryIndex <= 0 ? string.Empty : line.ToString(paramSummaryIndex, line.Length - paramSummaryIndex); if (nextLineBeginSummary) { paramSummary += "</param>"; } builder.AppendLine("/// <param name=\"" + paramName + "\">" + paramSummary); } } else if (subSummaryType == DocSubSummary.Return || subSummaryType == DocSubSummary.Note || subSummaryType == DocSubSummary.See) { string returnSummary = line.ToString(); if (nextLineBeginSummary) { returnSummary += GetDocSubSummaryTag(subSummaryType, true, false); } string openTag = GetDocSubSummaryTag(subSummaryType, true, true); if (injectReturnSummaryIndex != -1 && subSummaryType == DocSubSummary.Return) { injectReturnSummaryHeader = !line.ToString().StartsWith("return"); if (nextLineBeginSummary) { StringBuilder injectedSummary = new StringBuilder(line.ToString()); if (injectReturnSummaryHeader) { if (injectedSummary.Length > 0) { injectedSummary[0] = char.ToUpperInvariant(injectedSummary[0]); } injectedSummary.Insert(0, "Returns: "); } builder.Insert(injectReturnSummaryIndex, injectedSummary.ToString()); injectReturnSummaryIndex = -1; } else { // Skip newline, the indent, the comment and the tag returnSummaryStart = builder.Length + builder.GetNewLineLength() + builder.GetIndentLength() + ("/// ").Length + openTag.Length; } } builder.AppendLine("/// " + openTag + returnSummary); } } else if (nextLineBeginSummary && subSummaryType != DocSubSummary.None) { string closeTag = GetDocSubSummaryTag(subSummaryType, true, false); builder.AppendLine("/// " + line.ToString() + closeTag); if (injectReturnSummaryIndex != -1 && subSummaryType == DocSubSummary.Return) { // Skip the close tag int returnSummaryEnd = builder.Length - closeTag.Length; StringBuilder injectedSummary = new StringBuilder(builder.GetStringBetween(returnSummaryStart, returnSummaryEnd)); if (injectReturnSummaryHeader) { if (injectedSummary.Length > 0) { injectedSummary[0] = char.ToUpperInvariant(injectedSummary[0]); } injectedSummary.Insert(0, "Returns: "); } builder.Insert(injectReturnSummaryIndex, injectedSummary.ToString()); injectReturnSummaryIndex = -1; } } else if (subSummaryType != DocSubSummary.None) { // Multi-line sub summary (and also not the last line for this sub summary) builder.AppendLine("/// " + line.ToString()); } else { // Regular summary if (i == 0) { if (nextLineBeginSummary || lines.Count == 1) { builder.AppendLine("/// <summary>" + line.ToString() + "</summary>"); } else { builder.AppendLine("/// <summary>"); builder.AppendLine("/// " + line.ToString()); } } else { builder.AppendLine("/// " + line.ToString()); } } } if (subSummaryType == DocSubSummary.None && lines.Count > 1) { builder.AppendLine("/// </summary>"); } }
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 (property.HasAnyPropertyFlags(EPropertyFlags.NativeAccessSpecifierProtected | EPropertyFlags.Protected))) // If this is being force exported make it public instead of protected && !isOwnerStruct && !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 (!IsCollectionProperty(property) && !IsDelegateProperty(property) && !property.IsFixedSizeArray) { AppendSetter(builder, propertyName, property, namespaces); } builder.CloseBrace(); } builder.AppendLine(); }