private void GenerateCodeForEnum(UnrealModuleInfo module, CSharpTextBuilder builder, UEnum unrealEnum) { bool isBlueprintType = unrealEnum.IsA <UUserDefinedEnum>(); AppendDocComment(builder, unrealEnum, isBlueprintType); AppendAttribute(builder, unrealEnum, module); // Set the underlying enum type if this enum is tagged as a BlueprintType string enumUnderlyingType = string.Empty; if (unrealEnum.HasMetaData(MDEnum.BlueprintType)) { enumUnderlyingType = " : byte"; } builder.AppendLine("public enum " + GetTypeName(unrealEnum) + enumUnderlyingType); builder.OpenBrace(); // TODO: Blueprint value bitflags // According to issue UE-32816 "enum values are currently assumed to be flag indices and not actual flag mask values" List <EnumValueInfo> enumValues = GetEnumValues(unrealEnum, true); int lastEnumIndex = enumValues.Count; foreach (EnumValueInfo enumValue in enumValues) { AppendDocComment(builder, enumValue.DocCommentSummary); if (isBlueprintType) { builder.AppendLine("[EnumValueName(\"" + enumValue.Name + "\")]"); } builder.AppendLine(string.Format("{0}={1}{2}", isBlueprintType ? enumValue.DisplayName : enumValue.Name, enumValue.Value, --lastEnumIndex > 0 ? "," : string.Empty)); } builder.CloseBrace(); }
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); }