private void GenerateCodeForEnum(UnrealModuleInfo module, UEnum unrealEnum) { UnrealModuleType moduleAssetType; string currentNamespace = GetModuleNamespace(unrealEnum, out moduleAssetType); List <string> namespaces = GetDefaultNamespaces(); CSharpTextBuilder builder = new CSharpTextBuilder(Settings.IndentType); if (!string.IsNullOrEmpty(currentNamespace)) { builder.AppendLine("namespace " + currentNamespace); builder.OpenBrace(); } GenerateCodeForEnum(module, builder, unrealEnum); if (!string.IsNullOrEmpty(currentNamespace)) { builder.CloseBrace(); } builder.InsertNamespaces(currentNamespace, namespaces, Settings.SortNamespaces); OnCodeGenerated(module, moduleAssetType, GetTypeName(unrealEnum), unrealEnum.GetPathName(), builder); }
private string GetEnumValuePrefix(UEnum unrealEnum) { string enumPrefix; if (enumValuePrefixCache.TryGetValue(unrealEnum.GetPathName(), out enumPrefix)) { return(enumPrefix); } GetEnumValues(unrealEnum, false); if (enumValuePrefixCache.TryGetValue(unrealEnum.GetPathName(), out enumPrefix)) { return(enumPrefix); } return(null); }
private bool IsBlueprintVisibleEnum(UEnum unrealEnum) { if (forceExportEnums.Contains(unrealEnum.GetPathName())) { return(true); } return(unrealEnum.GetBoolMetaData(MDEnum.BlueprintType)); }
private bool CanExportEnum(UEnum unrealEnum) { // Skip enums which are already defined in this project if (projectDefinedTypes.ContainsKey(unrealEnum.GetPathName())) { return(false); } return(true); }
private List <EnumValueInfo> GetEnumValues(UEnum unrealEnum, bool getDocumentation) { int valueCount = unrealEnum.NumEnums(); bool isBlueprintEnum = unrealEnum.IsA <UUserDefinedEnum>(); List <EnumValueInfo> enumValues = new List <EnumValueInfo>(valueCount); // Try to identify a common prefix of the form PRE_, so we can strip it from all values. // We'll only strip it if it's present on all values not explicitly skipped. string commonPrefix = null; int commonPrefixCount = 0; int skippedValueCount = 0; int numMax = 0; if (Settings.RemoveEnumMAX) { // Skip all ending "MAX" values (Some enums have duplicate MAX (DORN_MAX / ENetDormancy_MAX)) for (int i = valueCount - 1; i >= 0; --i) { string rawName = GetEnumValueName(unrealEnum, i); // Using case sensitive here to avoid removing genuine "Max" values (still may be removing genuine "MAX" values) if (rawName.EndsWith("MAX")) { ++numMax; ++skippedValueCount; // Duplicate MAX should be "XXX_MAX" for last value and "MAX" for second to last value if (i < valueCount - 1 || !rawName.EndsWith("_MAX")) { break; } } else { break; } } } //if (numMax > 1) //{ // FMessage.Log("Duplicate MAX in enum " + unrealEnum.GetPathName()); //} for (int i = 0; i < valueCount - numMax; ++i) { string rawName = GetEnumValueName(unrealEnum, i); EnumValueInfo enumValue = new EnumValueInfo(); enumValue.Index = i; enumValue.Value = unrealEnum.GetValueByIndex(i); enumValue.Name = rawName; enumValue.DisplayName = MakeValidName(unrealEnum.GetDisplayNameTextStringByIndex(i)); if (getDocumentation) { enumValue.DocCommentSummary = unrealEnum.GetToolTipByIndex(i); } enumValues.Add(enumValue); // We can skip all of the common prefix checks for enums that are already namespaced in C++. // In the cases where a namespaced enum does have a common prefix for its values, it doesn't // match the PRE_* pattern, and it's generally necessary for syntactic reasons, // i.e. Touch1, Touch2, and so on in ETouchIndex. if (unrealEnum.GetCppForm() == UEnum.ECppForm.Regular) { // A handful of enums have bad values named this way in C++. if (rawName.StartsWith("TEMP_BROKEN")) { ++skippedValueCount; } // UHT inserts spacers for sparse enums. Since we're omitting the _MAX value, we'll // still export these to ensure that C# reflection gives an accurate value count, but // don't hold them against the common prefix count. else if (rawName.StartsWith("UnusedSpacer_")) { ++skippedValueCount; } // Infer the prefix from the first unskipped value. else if (string.IsNullOrEmpty(commonPrefix)) { int underscorePos = rawName.IndexOf("_"); if (underscorePos >= 0) { commonPrefix = rawName.Substring(0, underscorePos + 1); ++commonPrefixCount; } } else if (rawName.StartsWith(commonPrefix)) { ++commonPrefixCount; } } } if (valueCount != (commonPrefixCount + skippedValueCount)) { //if (!string.IsNullOrEmpty(commonPrefix)) //{ // FMessage.Log(string.Format("Rejecting common prefix '{0}' for '{1}' ({2}). ValueCount={3}, CommonPrefixCount={4}, SkippedValueCount={5}", // commonPrefix, unrealEnum.GetName(), unrealEnum.GetFName().DisplayIndex, valueCount, commonPrefixCount, skippedValueCount)); //} commonPrefix = null; } foreach (EnumValueInfo enumValue in enumValues) { if (!string.IsNullOrEmpty(commonPrefix)) { enumValue.Name = enumValue.Name.RemoveFromStart(commonPrefix); } //one enum has a member called "float" which isn't valid in C#. That said, C# enum values should be PascalCase anyway, so just uppercase it. if (char.IsLower(enumValue.Name[0])) { enumValue.Name = char.ToUpperInvariant(enumValue.Name[0]) + enumValue.Name.Substring(1); } if (char.IsDigit(enumValue.Name[0])) { enumValue.Name = "_" + enumValue.Name; } } // Update the enum prefix cache for lookup with default function params enumValuePrefixCache[unrealEnum.GetPathName()] = commonPrefix; return(enumValues); }
// Move this somewhere else? Where would this be more appropriate? public static Type GetTypeFromProperty(UProperty prop) { if (prop == null) { return(null); } switch (prop.PropertyType) { case EPropertyType.Bool: return(typeof(bool)); case EPropertyType.Int8: return(typeof(sbyte)); case EPropertyType.Byte: return(typeof(byte)); case EPropertyType.Int16: return(typeof(short)); case EPropertyType.UInt16: return(typeof(ushort)); case EPropertyType.Int: return(typeof(int)); case EPropertyType.UInt32: return(typeof(uint)); case EPropertyType.Int64: return(typeof(long)); case EPropertyType.UInt64: return(typeof(ulong)); case EPropertyType.Float: return(typeof(float)); case EPropertyType.Double: return(typeof(double)); case EPropertyType.Enum: { UEnum unrealEnum = (prop as UEnumProperty).GetEnum(); if (unrealEnum == null) { return(null); } Type enumType; ManagedUnrealModuleInfo.AllKnownUnrealTypes.TryGetValue(unrealEnum.GetPathName(), out enumType); return(enumType); } case EPropertyType.Str: return(typeof(string)); case EPropertyType.Name: return(typeof(FName)); case EPropertyType.Text: return(typeof(FText)); case EPropertyType.Interface: { UClass unrealClassInterface = (prop as UInterfaceProperty).InterfaceClass; if (unrealClassInterface == null) { return(null); } Type interfaceType; ManagedUnrealModuleInfo.AllKnownUnrealTypes.TryGetValue(unrealClassInterface.GetPathName(), out interfaceType); return(interfaceType); } case EPropertyType.Struct: { UScriptStruct unrealStruct = (prop as UStructProperty).Struct; if (unrealStruct == null) { return(null); } Type structType; ManagedUnrealModuleInfo.AllKnownUnrealTypes.TryGetValue(unrealStruct.GetPathName(), out structType); return(structType); } case EPropertyType.Class: case EPropertyType.Object: case EPropertyType.LazyObject: case EPropertyType.WeakObject: case EPropertyType.SoftClass: case EPropertyType.SoftObject: { UClass objectClass = (prop as UObjectPropertyBase).PropertyClass; switch (prop.PropertyType) { case EPropertyType.Class: objectClass = (prop as UClassProperty).MetaClass; break; case EPropertyType.SoftClass: objectClass = (prop as USoftClassProperty).MetaClass; break; } Type type = null; if (objectClass != null) { // Could use UClass.GetType but using AllKnownUnrealTypes for slightly more coverage // UClass.GetType(objectClass) ManagedUnrealModuleInfo.AllKnownUnrealTypes.TryGetValue(objectClass.GetPathName(), out type); } if (type == null) { //classType = typeof(UObject);// Fall back to UObject? Return null? return(null); } switch (prop.PropertyType) { case EPropertyType.Class: return(typeof(TSubclassOf <>).MakeGenericType(type)); case EPropertyType.LazyObject: return(typeof(TLazyObject <>).MakeGenericType(type)); case EPropertyType.WeakObject: return(typeof(TWeakObject <>).MakeGenericType(type)); case EPropertyType.SoftClass: return(typeof(TSoftClass <>).MakeGenericType(type)); case EPropertyType.SoftObject: return(typeof(TSoftObject <>).MakeGenericType(type)); case EPropertyType.Object: return(type); } return(type); } case EPropertyType.Delegate: case EPropertyType.MulticastDelegate: Type delegateType = null; UFunction signatureFunc = null; if (prop.PropertyType == EPropertyType.Delegate) { signatureFunc = (prop as UDelegateProperty).SignatureFunction; } else if (prop.PropertyType == EPropertyType.MulticastDelegate) { signatureFunc = (prop as UMulticastDelegateProperty).SignatureFunction; } if (signatureFunc != null) { if (ManagedUnrealModuleInfo.AllKnownUnrealTypes.TryGetValue(signatureFunc.GetPathName(), out delegateType)) { if (prop.PropertyType == EPropertyType.Delegate) { if (!delegateType.IsSameOrSubclassOfGeneric(typeof(FDelegate <>))) { delegateType = null; } } else if (prop.PropertyType == EPropertyType.MulticastDelegate) { if (!delegateType.IsSameOrSubclassOfGeneric(typeof(FMulticastDelegate <>))) { delegateType = null; } } } } return(delegateType); case EPropertyType.Array: { UArrayProperty arrayProp = prop as UArrayProperty; Type innerType = GetTypeFromProperty(arrayProp.Inner); if (innerType != null) { // Possibly handle IReadOnlyList? return(typeof(IList <>).MakeGenericType(innerType)); } return(null); } case EPropertyType.Set: { USetProperty setProp = prop as USetProperty; Type innerType = GetTypeFromProperty(setProp.ElementProp); if (innerType != null) { return(typeof(ISet <>).MakeGenericType(innerType)); } return(null); } case EPropertyType.Map: { UMapProperty mapProp = prop as UMapProperty; Type keyType = GetTypeFromProperty(mapProp.KeyProp); Type valueType = GetTypeFromProperty(mapProp.ValueProp); if (keyType != null && valueType != null) { // Possibly handle IReadOnlyDictionary? return(typeof(IDictionary <,>).MakeGenericType(keyType, valueType)); } return(null); } } return(null); }