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();
        }
Example #2
0
        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);
        }