560 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			560 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Tencent is pleased to support the open source community by making UnLua available.
 | 
						|
// 
 | 
						|
// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
 | 
						|
//
 | 
						|
// Licensed under the MIT License (the "License"); 
 | 
						|
// you may not use this file except in compliance with the License. You may obtain a copy of the License at
 | 
						|
//
 | 
						|
// http://opensource.org/licenses/MIT
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, 
 | 
						|
// software distributed under the License is distributed on an "AS IS" BASIS, 
 | 
						|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 | 
						|
// See the License for the specific language governing permissions and limitations under the License.
 | 
						|
 | 
						|
#include "UnLuaIntelliSense.h"
 | 
						|
 | 
						|
#include "Binding.h"
 | 
						|
#include "ObjectEditorUtils.h"
 | 
						|
#include "UnLuaInterface.h"
 | 
						|
 | 
						|
namespace UnLua
 | 
						|
{
 | 
						|
    namespace IntelliSense
 | 
						|
    {
 | 
						|
        static const FName NAME_ToolTip(TEXT("ToolTip")); // key of ToolTip meta data
 | 
						|
        static const FName NAME_LatentInfo = TEXT("LatentInfo"); // tag of latent function
 | 
						|
        static FString LuaKeywords[] = {TEXT("local"), TEXT("function"), TEXT("end")};
 | 
						|
 | 
						|
        static FString GetCommentBlock(const UField* Field)
 | 
						|
        {
 | 
						|
            const FString ToolTip = Field->GetMetaData(NAME_ToolTip);
 | 
						|
            if (ToolTip.IsEmpty())
 | 
						|
                return "";
 | 
						|
            return "---" + EscapeComments(ToolTip, false) + "\r\n";
 | 
						|
        }
 | 
						|
 | 
						|
        FString Get(const UBlueprint* Blueprint)
 | 
						|
        {
 | 
						|
            return Get(Blueprint->GeneratedClass);
 | 
						|
        }
 | 
						|
 | 
						|
        FString Get(const UField* Field)
 | 
						|
        {
 | 
						|
            const UStruct* Struct = Cast<UStruct>(Field);
 | 
						|
            if (Struct)
 | 
						|
                return Get(Struct);
 | 
						|
 | 
						|
            const UEnum* Enum = Cast<UEnum>(Field);
 | 
						|
            if (Enum)
 | 
						|
                return Get(Enum);
 | 
						|
 | 
						|
            return "";
 | 
						|
        }
 | 
						|
 | 
						|
        FString Get(const UEnum* Enum)
 | 
						|
        {
 | 
						|
            FString Ret = GetCommentBlock(Enum);
 | 
						|
 | 
						|
            FString TypeName = GetTypeName(Enum);
 | 
						|
            Ret += FString::Printf(TEXT("---@class %s"), *TypeName);
 | 
						|
 | 
						|
            // fields
 | 
						|
            const int32 Num = Enum->NumEnums();
 | 
						|
            for (int32 i = 0; i < Num; ++i)
 | 
						|
            {
 | 
						|
                Ret += FString::Printf(TEXT("\r\n---@field %s %s %s"), TEXT("public"), *Enum->GetNameStringByIndex(i), TEXT("integer"));
 | 
						|
            }
 | 
						|
 | 
						|
            // declaration
 | 
						|
            Ret += FString::Printf(TEXT("\r\nlocal %s = {}\r\n"), *EscapeSymbolName(TypeName));
 | 
						|
 | 
						|
            return Ret;
 | 
						|
        }
 | 
						|
 | 
						|
        FString Get(const UStruct* Struct)
 | 
						|
        {
 | 
						|
            const UClass* Class = Cast<UClass>(Struct);
 | 
						|
            if (Class)
 | 
						|
                return Get(Class);
 | 
						|
 | 
						|
            const UScriptStruct* ScriptStruct = Cast<UScriptStruct>(Struct);
 | 
						|
            if (ScriptStruct)
 | 
						|
                return Get(ScriptStruct);
 | 
						|
 | 
						|
            const UFunction* Function = Cast<UFunction>(Struct);
 | 
						|
            if (Function)
 | 
						|
                return Get(Function);
 | 
						|
 | 
						|
            return "";
 | 
						|
        }
 | 
						|
 | 
						|
        FString Get(const UScriptStruct* ScriptStruct)
 | 
						|
        {
 | 
						|
            FString Ret = GetCommentBlock(ScriptStruct);
 | 
						|
 | 
						|
            FString TypeName = GetTypeName(ScriptStruct);
 | 
						|
            Ret += "---@class " + TypeName;
 | 
						|
            UStruct* SuperStruct = ScriptStruct->GetSuperStruct();
 | 
						|
            if (SuperStruct)
 | 
						|
                Ret += " : " + GetTypeName(SuperStruct);
 | 
						|
            Ret += "\r\n";
 | 
						|
 | 
						|
            // fields
 | 
						|
            for (TFieldIterator<FProperty> It(ScriptStruct, EFieldIteratorFlags::ExcludeSuper, EFieldIteratorFlags::ExcludeDeprecated); It; ++It)
 | 
						|
            {
 | 
						|
                const FProperty* Property = *It;
 | 
						|
                Ret += Get(Property) += "\r\n";
 | 
						|
            }
 | 
						|
 | 
						|
            // declaration
 | 
						|
            Ret += FString::Printf(TEXT("local %s = {}\r\n"), *EscapeSymbolName(TypeName));
 | 
						|
 | 
						|
            // exported functions
 | 
						|
            const auto Exported = GetExportedReflectedClasses().Find(TypeName);
 | 
						|
            if (Exported)
 | 
						|
            {
 | 
						|
                TArray<IExportedFunction*> ExportedFunctions;
 | 
						|
                (*Exported)->GetFunctions(ExportedFunctions);
 | 
						|
                for (const auto Function : ExportedFunctions)
 | 
						|
                    Function->GenerateIntelliSense(Ret);
 | 
						|
            }
 | 
						|
            return Ret;
 | 
						|
        }
 | 
						|
 | 
						|
        FString Get(const UClass* Class)
 | 
						|
        {
 | 
						|
            FString Ret = GetCommentBlock(Class);
 | 
						|
 | 
						|
            const FString TypeName = GetTypeName(Class);
 | 
						|
            Ret += "---@class " + TypeName;
 | 
						|
            UStruct* SuperStruct = Class->GetSuperStruct();
 | 
						|
            if (SuperStruct)
 | 
						|
                Ret += " : " + GetTypeName(SuperStruct);
 | 
						|
            Ret += "\r\n";
 | 
						|
 | 
						|
            // fields
 | 
						|
            for (TFieldIterator<FProperty> It(Class, EFieldIteratorFlags::ExcludeSuper, EFieldIteratorFlags::ExcludeDeprecated); It; ++It)
 | 
						|
            {
 | 
						|
                const FProperty* Property = *It;
 | 
						|
                Ret += Get(Property) += "\r\n";
 | 
						|
            }
 | 
						|
 | 
						|
            // declaration
 | 
						|
            const auto EscapedClassName = EscapeSymbolName(TypeName);
 | 
						|
            Ret += FString::Printf(TEXT("local %s = {}\r\n\r\n"), *EscapedClassName);
 | 
						|
 | 
						|
            TArray<FString> GenFunctionNames;
 | 
						|
 | 
						|
            // functions
 | 
						|
            for (TFieldIterator<UFunction> FunctionIt(Class, EFieldIteratorFlags::ExcludeSuper, EFieldIteratorFlags::ExcludeDeprecated, EFieldIteratorFlags::ExcludeInterfaces); FunctionIt; ++FunctionIt)
 | 
						|
            {
 | 
						|
                const UFunction* Function = *FunctionIt;
 | 
						|
                if (!IsValid(Function))
 | 
						|
                    continue;
 | 
						|
                if (FObjectEditorUtils::IsFunctionHiddenFromClass(Function, Class))
 | 
						|
                    continue;
 | 
						|
                Ret += Get(Function) + "\r\n";
 | 
						|
                GenFunctionNames.Add(Function->GetName());
 | 
						|
            }
 | 
						|
 | 
						|
            // interface functions
 | 
						|
            for (TFieldIterator<UFunction> FunctionIt(Class, EFieldIteratorFlags::IncludeSuper, EFieldIteratorFlags::ExcludeDeprecated, EFieldIteratorFlags::IncludeInterfaces); FunctionIt; ++FunctionIt)
 | 
						|
            {
 | 
						|
                const UFunction* Function = *FunctionIt;
 | 
						|
                if (!Function->GetOwnerClass()->IsChildOf(UInterface::StaticClass()))
 | 
						|
                    continue;
 | 
						|
                if (!IsValid(Function))
 | 
						|
                    continue;
 | 
						|
                if (FObjectEditorUtils::IsFunctionHiddenFromClass(Function, Class))
 | 
						|
                    continue;
 | 
						|
                if (GenFunctionNames.Contains(Function->GetName()))
 | 
						|
                    continue;
 | 
						|
                Ret += Get(Function, EscapedClassName) + "\r\n";
 | 
						|
            }
 | 
						|
 | 
						|
            // exported functions
 | 
						|
            const auto Exported = GetExportedReflectedClasses().Find(TypeName);
 | 
						|
            if (Exported)
 | 
						|
            {
 | 
						|
                TArray<IExportedFunction*> ExportedFunctions;
 | 
						|
                (*Exported)->GetFunctions(ExportedFunctions);
 | 
						|
                for (const auto Function : ExportedFunctions)
 | 
						|
                    Function->GenerateIntelliSense(Ret);
 | 
						|
            }
 | 
						|
            return Ret;
 | 
						|
        }
 | 
						|
 | 
						|
        FString Get(const UFunction* Function, FString ForceClassName)
 | 
						|
        {
 | 
						|
            FString Ret = GetCommentBlock(Function);
 | 
						|
            FString Properties;
 | 
						|
 | 
						|
            for (TFieldIterator<FProperty> It(Function); It && (It->PropertyFlags & CPF_Parm); ++It)
 | 
						|
            {
 | 
						|
                const FProperty* Property = *It;
 | 
						|
                if (Property->GetFName() == NAME_LatentInfo)
 | 
						|
                    continue;
 | 
						|
 | 
						|
                FString TypeName = EscapeSymbolName(GetTypeName(Property));
 | 
						|
                const FString& PropertyComment = Property->GetMetaData(NAME_ToolTip);
 | 
						|
                FString ExtraDesc;
 | 
						|
 | 
						|
                if (Property->HasAnyPropertyFlags(CPF_ReturnParm))
 | 
						|
                {
 | 
						|
                    Ret += FString::Printf(TEXT("---@return %s"), *TypeName); // return parameter
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    FString PropertyName = EscapeSymbolName(*Property->GetName());
 | 
						|
                    if (Properties.IsEmpty())
 | 
						|
                        Properties = PropertyName;
 | 
						|
                    else
 | 
						|
                        Properties += FString::Printf(TEXT(", %s"), *PropertyName);
 | 
						|
 | 
						|
                    FName KeyName = FName(*FString::Printf(TEXT("CPP_Default_%s"), *Property->GetName()));
 | 
						|
                    const FString& Value = Function->GetMetaData(KeyName);
 | 
						|
                    if (!Value.IsEmpty())
 | 
						|
                    {
 | 
						|
                        ExtraDesc = TEXT("[opt]"); // default parameter
 | 
						|
                    }
 | 
						|
                    else if (Property->HasAnyPropertyFlags(CPF_OutParm) && !Property->HasAnyPropertyFlags(CPF_ConstParm))
 | 
						|
                    {
 | 
						|
                        ExtraDesc = TEXT("[out]"); // non-const reference
 | 
						|
                    }
 | 
						|
                    Ret += FString::Printf(TEXT("---@param %s %s"), *PropertyName, *TypeName);
 | 
						|
                }
 | 
						|
 | 
						|
                if (ExtraDesc.Len() > 0 || PropertyComment.Len() > 0)
 | 
						|
                {
 | 
						|
                    Ret += TEXT(" @");
 | 
						|
                    if (ExtraDesc.Len() > 0)
 | 
						|
                        Ret += FString::Printf(TEXT("%s "), *ExtraDesc);
 | 
						|
                }
 | 
						|
 | 
						|
                Ret += TEXT("\r\n");
 | 
						|
            }
 | 
						|
 | 
						|
            const auto ClassName = ForceClassName.IsEmpty() ? EscapeSymbolName(GetTypeName(Function->GetOwnerClass())) : ForceClassName;
 | 
						|
            const auto FunctionName = Function->GetName();
 | 
						|
            const auto bIsStatic = Function->HasAnyFunctionFlags(FUNC_Static);
 | 
						|
            if (IsValidFunctionName(FunctionName))
 | 
						|
            {
 | 
						|
                Ret += FString::Printf(TEXT("function %s%s%s(%s) end\r\n"), *ClassName, bIsStatic ? TEXT(".") : TEXT(":"), *FunctionName, *Properties);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                const auto Self = bIsStatic ? TEXT("") : TEXT("self");
 | 
						|
                const auto Comma = bIsStatic || Properties.IsEmpty() ? TEXT("") : TEXT(", ");
 | 
						|
                Ret += FString::Printf(TEXT("%s[\"%s\"] = function(%s%s%s) end\r\n"), *ClassName, *FunctionName, Self, Comma, *Properties);
 | 
						|
            }
 | 
						|
            return Ret;
 | 
						|
        }
 | 
						|
 | 
						|
        FString Get(const FProperty* Property)
 | 
						|
        {
 | 
						|
            FString Ret;
 | 
						|
 | 
						|
            const UStruct* Struct = Property->GetOwnerStruct();
 | 
						|
 | 
						|
            // access level
 | 
						|
            FString AccessLevel;
 | 
						|
            if (Property->HasAnyPropertyFlags(CPF_NativeAccessSpecifierPublic))
 | 
						|
                AccessLevel = TEXT("public");
 | 
						|
            else if (Property->HasAllPropertyFlags(CPF_NativeAccessSpecifierProtected))
 | 
						|
                AccessLevel = TEXT("protected");
 | 
						|
            else if (Property->HasAllPropertyFlags(CPF_NativeAccessSpecifierPrivate))
 | 
						|
                AccessLevel = TEXT("private");
 | 
						|
            else
 | 
						|
                AccessLevel = Struct->IsNative() ? "private" : "public";
 | 
						|
 | 
						|
            FString TypeName = IntelliSense::GetTypeName(Property);
 | 
						|
            Ret += FString::Printf(TEXT("---@field %s %s %s"), *AccessLevel, *Property->GetName(), *TypeName);
 | 
						|
 | 
						|
            // comment
 | 
						|
            const FString& ToolTip = Property->GetMetaData(NAME_ToolTip);
 | 
						|
            if (!ToolTip.IsEmpty())
 | 
						|
                Ret += " @" + EscapeComments(ToolTip, true);
 | 
						|
 | 
						|
            return Ret;
 | 
						|
        }
 | 
						|
 | 
						|
        FString GetUE(const TArray<const UField*> AllTypes)
 | 
						|
        {
 | 
						|
            FString Content = "UE = {";
 | 
						|
 | 
						|
            for (const auto Type : AllTypes)
 | 
						|
            {
 | 
						|
                if (!Type->IsNative())
 | 
						|
                    continue;
 | 
						|
 | 
						|
                const auto Name = GetTypeName(Type);
 | 
						|
                Content += FString::Printf(TEXT("\r\n    ---@type %s\r\n"), *Name);
 | 
						|
                Content += FString::Printf(TEXT("    %s = nil,\r\n"), *Name);
 | 
						|
            }
 | 
						|
 | 
						|
            Content += "}\r\n";
 | 
						|
            return Content;
 | 
						|
        }
 | 
						|
 | 
						|
        FString GetTypeName(const UObject* Field)
 | 
						|
        {
 | 
						|
            if (!Field)
 | 
						|
                return "";
 | 
						|
            if (!Field->IsNative() && Field->GetName().EndsWith("_C"))
 | 
						|
                return Field->GetName();
 | 
						|
            const UStruct* Struct = Cast<UStruct>(Field);
 | 
						|
            if (Struct)
 | 
						|
                return Struct->GetPrefixCPP() + Struct->GetName();
 | 
						|
            return Field->GetName();
 | 
						|
        }
 | 
						|
 | 
						|
        FString GetTypeName(const FProperty* Property)
 | 
						|
        {
 | 
						|
            if (!Property)
 | 
						|
                return "Unknown";
 | 
						|
 | 
						|
            if (CastField<FByteProperty>(Property))
 | 
						|
                return "integer";
 | 
						|
 | 
						|
            if (CastField<FInt8Property>(Property))
 | 
						|
                return "integer";
 | 
						|
 | 
						|
            if (CastField<FInt16Property>(Property))
 | 
						|
                return "integer";
 | 
						|
 | 
						|
            if (CastField<FIntProperty>(Property))
 | 
						|
                return "integer";
 | 
						|
 | 
						|
            if (CastField<FInt64Property>(Property))
 | 
						|
                return "integer";
 | 
						|
 | 
						|
            if (CastField<FUInt16Property>(Property))
 | 
						|
                return "integer";
 | 
						|
 | 
						|
            if (CastField<FUInt32Property>(Property))
 | 
						|
                return "integer";
 | 
						|
 | 
						|
            if (CastField<FUInt64Property>(Property))
 | 
						|
                return "integer";
 | 
						|
 | 
						|
            if (CastField<FFloatProperty>(Property))
 | 
						|
                return "number";
 | 
						|
 | 
						|
            if (CastField<FDoubleProperty>(Property))
 | 
						|
                return "number";
 | 
						|
 | 
						|
            if (CastField<FEnumProperty>(Property))
 | 
						|
                return ((FEnumProperty*)Property)->GetEnum()->GetName();
 | 
						|
 | 
						|
            if (CastField<FBoolProperty>(Property))
 | 
						|
                return TEXT("boolean");
 | 
						|
 | 
						|
            if (CastField<FClassProperty>(Property))
 | 
						|
            {
 | 
						|
                const UClass* Class = ((FClassProperty*)Property)->MetaClass;
 | 
						|
                return FString::Printf(TEXT("TSubclassOf<%s%s>"), Class->GetPrefixCPP(), *Class->GetName());
 | 
						|
            }
 | 
						|
 | 
						|
            if (CastField<FSoftObjectProperty>(Property))
 | 
						|
            {
 | 
						|
                if (((FSoftObjectProperty*)Property)->PropertyClass->IsChildOf(UClass::StaticClass()))
 | 
						|
                {
 | 
						|
                    const UClass* Class = ((FSoftClassProperty*)Property)->MetaClass;
 | 
						|
                    return FString::Printf(TEXT("TSoftClassPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName());
 | 
						|
                }
 | 
						|
                const UClass* Class = ((FSoftObjectProperty*)Property)->PropertyClass;
 | 
						|
                return FString::Printf(TEXT("TSoftObjectPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName());
 | 
						|
            }
 | 
						|
 | 
						|
            if (CastField<FObjectProperty>(Property))
 | 
						|
            {
 | 
						|
                const UClass* Class = ((FObjectProperty*)Property)->PropertyClass;
 | 
						|
                if (Cast<UBlueprintGeneratedClass>(Class))
 | 
						|
                {
 | 
						|
                    return FString::Printf(TEXT("%s"), *Class->GetName());
 | 
						|
                }
 | 
						|
                return FString::Printf(TEXT("%s%s"), Class->GetPrefixCPP(), *Class->GetName());
 | 
						|
            }
 | 
						|
 | 
						|
            if (CastField<FWeakObjectProperty>(Property))
 | 
						|
            {
 | 
						|
                const UClass* Class = ((FWeakObjectProperty*)Property)->PropertyClass;
 | 
						|
                return FString::Printf(TEXT("TWeakObjectPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName());
 | 
						|
            }
 | 
						|
 | 
						|
            if (CastField<FLazyObjectProperty>(Property))
 | 
						|
            {
 | 
						|
                const UClass* Class = ((FLazyObjectProperty*)Property)->PropertyClass;
 | 
						|
                return FString::Printf(TEXT("TLazyObjectPtr<%s%s>"), Class->GetPrefixCPP(), *Class->GetName());
 | 
						|
            }
 | 
						|
 | 
						|
            if (CastField<FInterfaceProperty>(Property))
 | 
						|
            {
 | 
						|
                const UClass* Class = ((FInterfaceProperty*)Property)->InterfaceClass;
 | 
						|
                return FString::Printf(TEXT("TScriptInterface<%s%s>"), Class->GetPrefixCPP(), *Class->GetName());
 | 
						|
            }
 | 
						|
 | 
						|
            if (CastField<FNameProperty>(Property))
 | 
						|
                return "string";
 | 
						|
 | 
						|
            if (CastField<FStrProperty>(Property))
 | 
						|
                return "string";
 | 
						|
 | 
						|
            if (CastField<FTextProperty>(Property))
 | 
						|
                return "string";
 | 
						|
 | 
						|
            if (CastField<FArrayProperty>(Property))
 | 
						|
            {
 | 
						|
                const FProperty* Inner = ((FArrayProperty*)Property)->Inner;
 | 
						|
                return FString::Printf(TEXT("TArray<%s>"), *GetTypeName(Inner));
 | 
						|
            }
 | 
						|
 | 
						|
            if (CastField<FMapProperty>(Property))
 | 
						|
            {
 | 
						|
                const FProperty* KeyProp = ((FMapProperty*)Property)->KeyProp;
 | 
						|
                const FProperty* ValueProp = ((FMapProperty*)Property)->ValueProp;
 | 
						|
                return FString::Printf(TEXT("TMap<%s, %s>"), *GetTypeName(KeyProp), *GetTypeName(ValueProp));
 | 
						|
            }
 | 
						|
 | 
						|
            if (CastField<FSetProperty>(Property))
 | 
						|
            {
 | 
						|
                const FProperty* ElementProp = ((FSetProperty*)Property)->ElementProp;
 | 
						|
                return FString::Printf(TEXT("TSet<%s>"), *GetTypeName(ElementProp));
 | 
						|
            }
 | 
						|
 | 
						|
            if (CastField<FStructProperty>(Property))
 | 
						|
                return ((FStructProperty*)Property)->Struct->GetStructCPPName();
 | 
						|
 | 
						|
            if (CastField<FDelegateProperty>(Property))
 | 
						|
                return "Delegate";
 | 
						|
 | 
						|
            if (CastField<FMulticastDelegateProperty>(Property))
 | 
						|
                return "MulticastDelegate";
 | 
						|
 | 
						|
            return "Unknown";
 | 
						|
        }
 | 
						|
 | 
						|
        FString EscapeComments(const FString Comments, const bool bSingleLine)
 | 
						|
        {
 | 
						|
            if (Comments.IsEmpty())
 | 
						|
                return Comments;
 | 
						|
 | 
						|
            auto Filter = [](const FString Prefix, const FString Line)
 | 
						|
            {
 | 
						|
                if (Line.StartsWith("@"))
 | 
						|
                    return FString();
 | 
						|
                return Prefix + Line;
 | 
						|
            };
 | 
						|
 | 
						|
            TArray<FString> Lines;
 | 
						|
            Comments.Replace(TEXT("@"), TEXT("@@")).ParseIntoArray(Lines, TEXT("\n"));
 | 
						|
 | 
						|
            FString Ret = Filter("", Lines[0]);
 | 
						|
            if (bSingleLine)
 | 
						|
            {
 | 
						|
                for (int i = 1; i < Lines.Num(); i++)
 | 
						|
                    Ret += Filter(" ", Lines[i]);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                for (int i = 1; i < Lines.Num(); i++)
 | 
						|
                    Ret += Filter("\r\n---", Lines[i]);
 | 
						|
            }
 | 
						|
 | 
						|
            return Ret;
 | 
						|
        }
 | 
						|
 | 
						|
        FString EscapeSymbolName(const FString InName)
 | 
						|
        {
 | 
						|
            FString Name = InName;
 | 
						|
 | 
						|
            // 和Lua关键字重名就加前缀
 | 
						|
            for (const auto& Keyword : LuaKeywords)
 | 
						|
            {
 | 
						|
                if (Name.Equals(Keyword, ESearchCase::CaseSensitive))
 | 
						|
                {
 | 
						|
                    Name = TEXT("_") + Name;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            // 替换掉除中文外的特殊字符
 | 
						|
            for (int32 Index = 0; Index < Name.Len(); Index++)
 | 
						|
            {
 | 
						|
                const auto Char = Name[Index];
 | 
						|
                if ((Char < '0' || Char > '9')
 | 
						|
                    && (Char < 'a' || Char > 'z')
 | 
						|
                    && (Char < 'A' || Char > 'Z')
 | 
						|
                    && Char != '_'
 | 
						|
                    && Char < 0x100)
 | 
						|
                {
 | 
						|
                    Name[Index] = TCHAR('_');
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            // 数字开头就加前缀
 | 
						|
            const auto PrefixChar = Name[0];
 | 
						|
            if (PrefixChar >= '0' && PrefixChar <= '9')
 | 
						|
            {
 | 
						|
                Name = TEXT("_") + Name;
 | 
						|
            }
 | 
						|
 | 
						|
            return Name;
 | 
						|
        }
 | 
						|
 | 
						|
        bool IsValid(const UFunction* Function)
 | 
						|
        {
 | 
						|
            if (!Function)
 | 
						|
                return false;
 | 
						|
 | 
						|
            if (Function->HasAnyFunctionFlags(FUNC_UbergraphFunction))
 | 
						|
                return false;
 | 
						|
 | 
						|
            // 这个会导致USubsystemBlueprintLibrary.GetWorldSubsystem之类的被过滤掉
 | 
						|
            // if (!UEdGraphSchema_K2::CanUserKismetCallFunction(Function))
 | 
						|
            //     return false;
 | 
						|
 | 
						|
            const FString Name = Function->GetName();
 | 
						|
            if (Name.IsEmpty())
 | 
						|
                return false;
 | 
						|
 | 
						|
            // 避免运行时生成智能提示,把覆写的函数也生成了
 | 
						|
            if (Name.EndsWith("__Overridden"))
 | 
						|
                return false;
 | 
						|
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        bool IsValidFunctionName(const FString Name)
 | 
						|
        {
 | 
						|
            if (Name.IsEmpty())
 | 
						|
                return false;
 | 
						|
 | 
						|
            // 不能有Lua关键字
 | 
						|
            for (const auto& Keyword : LuaKeywords)
 | 
						|
            {
 | 
						|
                if (Name.Equals(Keyword, ESearchCase::CaseSensitive))
 | 
						|
                    return false;
 | 
						|
            }
 | 
						|
 | 
						|
            // 不能有中文和特殊字符
 | 
						|
            for (const auto& Char : Name)
 | 
						|
            {
 | 
						|
                if ((Char < '0' || Char > '9')
 | 
						|
                    && (Char < 'a' || Char > 'z')
 | 
						|
                    && (Char < 'A' || Char > 'Z')
 | 
						|
                    && Char != '_')
 | 
						|
                    return false;
 | 
						|
            }
 | 
						|
 | 
						|
            // 不能以数字开头
 | 
						|
            const auto& PrefixChar = Name[0];
 | 
						|
            if (PrefixChar >= '0' && PrefixChar <= '9')
 | 
						|
                return false;
 | 
						|
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |