UnLua改進記錄


接上一回處理多個LUA狀態機問題,暫時無法解決單個虛幻狀態機對應多個LUA狀態機問題,故先擱置,轉而看看UnLua的設計,本文記錄對其改進過程。

UnLua里面有個非常便捷的功能,就是在藍圖編輯器界面可以直接生成LUA代碼模板,開始以為是基於反射生成的,看了下發現其實是從內置的LUA文件復制的,
非常不靈活,其內置了Actor,UserWidget等幾種常用類型,但是對於有些自己項目中的C++反射類沒法准確支持,只能機械地去復制Actor或UserWidget等父類LUA表。

改動很簡單,根據上一回的UClass相關描述,直接迭代UClass獲取UFunction及其參數即可。代碼如下:

// 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 "UnLuaPrivate.h"
#include "Misc/FileHelper.h"
#include "Engine/Blueprint.h"
#include "Blueprint/UserWidget.h"
#include "Animation/AnimInstance.h"
#include "GameFramework/Actor.h"
#include "Interfaces/IPluginManager.h"
#include "PlatformFilemanager.h"

void OpenLuaFileInTextEditor(FString InFileName);

bool CreateLuaTemplateFileEx(UBlueprint* Blueprint);

// create Lua template file for the selected blueprint
bool CreateLuaTemplateFile(UBlueprint *Blueprint)
{
    return CreateLuaTemplateFileEx(Blueprint);

    if (Blueprint)
    {
        UClass *Class = Blueprint->GeneratedClass;
        FString ClassName = Class->GetName();
        FString OuterPath = Class->GetPathName();
        int32 LastIndex;
        if (OuterPath.FindLastChar('/', LastIndex))
        {
            OuterPath = OuterPath.Left(LastIndex + 1);
        }
        OuterPath = OuterPath.RightChop(6);         // ignore "/Game/"
        FString FileName = FString::Printf(TEXT("%s%s%s.lua"), *GLuaSrcFullPath, *OuterPath, *ClassName);
        if (FPaths::FileExists(FileName))
        {
            UE_LOG(LogUnLua, Warning, TEXT("Lua file (%s) is already existed!"), *ClassName);
            return false;
        }

        static FString ContentDir = IPluginManager::Get().FindPlugin(TEXT("UnLua"))->GetContentDir();

        FString TemplateName;
        if (Class->IsChildOf(AActor::StaticClass()))
        {
            // default BlueprintEvents for Actor
            TemplateName = ContentDir + TEXT("/ActorTemplate.lua");
        }
        else if (Class->IsChildOf(UUserWidget::StaticClass()))
        {
            // default BlueprintEvents for UserWidget (UMG)
            TemplateName = ContentDir + TEXT("/UserWidgetTemplate.lua");
        }
        else if (Class->IsChildOf(UAnimInstance::StaticClass()))
        {
            // default BlueprintEvents for AnimInstance (animation blueprint)
            TemplateName = ContentDir + TEXT("/AnimInstanceTemplate.lua");
        }
        else if (Class->IsChildOf(UActorComponent::StaticClass()))
        {
            // default BlueprintEvents for ActorComponent
            TemplateName = ContentDir + TEXT("/ActorComponentTemplate.lua");
        }

        FString Content;
        FFileHelper::LoadFileToString(Content, *TemplateName);
        Content = Content.Replace(TEXT("TemplateName"), *ClassName);

        return FFileHelper::SaveStringToFile(Content, *FileName);
    }
    return false;
}


// create Lua template file for the selected blueprint
bool CreateLuaTemplateFileEx(UBlueprint* Blueprint)
{
	if (Blueprint)
	{
		UClass* Class = Blueprint->GeneratedClass;
		FString ClassName = Class->GetName();
		FString OuterPath = Class->GetPathName();
		int32 LastIndex;
		if (OuterPath.FindLastChar('/', LastIndex))
		{
			OuterPath = OuterPath.Left(LastIndex + 1);
		}
		OuterPath = OuterPath.RightChop(6);         // ignore "/Game/"
		FString FileName = FString::Printf(TEXT("%s%s%s.lua"), *GLuaSrcFullPath, *OuterPath, *ClassName);
		if (FPlatformFileManager::Get().GetPlatformFile().FileSize(*FileName) > 1)
		{
			UE_LOG(LogUnLua, Warning, TEXT("Lua file (%s) is already existed!"), *ClassName);
            OpenLuaFileInTextEditor(FileName);
			return false;
		}

		static FString ContentDir = IPluginManager::Get().FindPlugin(TEXT("UnLua"))->GetContentDir();
		FString Content;
        FString CurrentTime = FDateTime::Now().ToString();
        FString ComputerUserName = FPlatformProcess::UserName(true);
        FString HeaderStr = FString::Printf(TEXT("\r\n--Author:%s\r\n--Date:%s\r\n\nrequire('UnLua')\r\n\nlocal %s = Class()\r\n"), *ComputerUserName, *CurrentTime, *ClassName);
        Content += HeaderStr;
        for (TFieldIterator<UFunction> Func(Class); Func; ++Func)
        {
            if (!Func->HasAnyFunctionFlags(FUNC_BlueprintEvent))
            {
                continue;
            }

            FString ReturnType = FString("void");
            if (Func->GetReturnProperty())
            {
                ReturnType = Func->GetReturnProperty()->GetCPPType();
            }
            FString FuncName = Func->GetName();
            FString ParamTypeList;
            FString ParamList;
#if ENGINE_MINOR_VERSION < 25
            for (TFieldIterator<UProperty> Prop(*Func); Prop; ++Prop)
#else
            for (TFieldIterator<FProperty> Prop(*Func); Prop; ++Prop)
#endif
            {
                if (!Prop->HasAnyPropertyFlags(CPF_OutParm))
                {
                    if (ParamList.Len() > 0)
                    {
                        ParamList = ParamList + FString(", ") + Prop->GetName();
                        ParamTypeList = ParamTypeList + FString(", ") + Prop->GetCPPType();
                    }
                    else
                    {
                        ParamList = ParamList + Prop->GetName();
                        ParamTypeList = ParamTypeList + Prop->GetCPPType();
                    }
                }
            }

            FString FuncStr = FString::Printf(TEXT("--%s(%s)\r\n--function %s:%s(%s)\r\n--end"),*ReturnType, *ParamTypeList, *ClassName, *FuncName, *ParamList);
            Content = Content + FString("\r\n") + FuncStr + FString("\r\n");
        }

        FString EndStr = FString::Printf(TEXT("\r\nreturn %s"), *ClassName);
        Content = Content + EndStr;

		bool bValidFile = FFileHelper::SaveStringToFile(Content, *FileName);
        if (bValidFile)
        {
            OpenLuaFileInTextEditor(FileName);
        }
        return bValidFile;
	}
	return false;
}


void OpenLuaFileInTextEditor(FString InFileName)
{
#if PLATFORM_WINDOWS
	TArray<FString> TextEditorPathList;
	TextEditorPathList.Add(FString("C:\\Program Files\\Microsoft VS Code\\Code.exe"));
	TextEditorPathList.Add(FString("C:\\Program Files\\Notepad++\\notepad++.exe"));
	//fallback to windows notepad
	TextEditorPathList.Add(FString("C:\\Windows\\notepad.exe"));
	for (int32 Idx = 0; Idx < TextEditorPathList.Num(); ++Idx)
	{
		if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*TextEditorPathList[Idx]))
		{
			uint32 OutPID = 0;
			FPlatformProcess::CreateProc(*TextEditorPathList[Idx], *InFileName, true, false, false, &OutPID, 0, nullptr, nullptr);
			break;
		}
	}

#endif
}

修改點:
1.新增了bool CreateLuaTemplateFileEx(UBlueprint* Blueprint)函數自動生成LUA文件,而不是機械復制幾個固定的模板
2.在判斷目標文件已經存在時,改用判斷文件大小,方便在VSCode清空文本並重新生成LUA文件
3.目前只支持了BlueprintEvent標記的函數,包括BlueprintImplementation/BlueprintNativeEvent;可根據需要去掉限制
4.為LUA函數生成對應c++函數簽名,一眼便知函數返回值和各參數類型
5.若在Windows系統,生成成功后會調用文本編輯器打開LUA文件

效果如下:




--Author:UserNameOnComputer
--Date:2020.04.09-13.20.15

require('UnLua')

local BP_LuaCharacter_C = Class()

--void(float)
--function BP_LuaCharacter_C:OnWalkingOffLedge(TimeDelta)
--end

--void(FVector, bool, bool)
--function BP_LuaCharacter_C:OnLaunched(LaunchVelocity, bXYOverride, bZOverride)
--end

--void()
--function BP_LuaCharacter_C:OnLanded()
--end

--void()
--function BP_LuaCharacter_C:OnJumped()
--end

--void(float)
--function BP_LuaCharacter_C:K2_UpdateCustomMovement(DeltaTime)
--end

--void(float, float)
--function BP_LuaCharacter_C:K2_OnStartCrouch(HalfHeightAdjust, ScaledHalfHeightAdjust)
--end

--void(TEnumAsByte<EMovementMode>, TEnumAsByte<EMovementMode>, uint8, uint8)
--function BP_LuaCharacter_C:K2_OnMovementModeChanged(PrevMovementMode, NewMovementMode, PrevCustomMode, NewCustomMode)
--end

--void(float, float)
--function BP_LuaCharacter_C:K2_OnEndCrouch(HalfHeightAdjust, ScaledHalfHeightAdjust)
--end

--bool()
--function BP_LuaCharacter_C:CanJumpInternal()
--end

--void(AController*)
--function BP_LuaCharacter_C:ReceiveUnpossessed(OldController)
--end

--void(AController*)
--function BP_LuaCharacter_C:ReceivePossessed(NewController)
--end

--void()
--function BP_LuaCharacter_C:UserConstructionScript()
--end

--void(float)
--function BP_LuaCharacter_C:ReceiveTick(DeltaSeconds)
--end

--void(float, UDamageType*, FVector, AController*, AActor*)
--function BP_LuaCharacter_C:ReceiveRadialDamage(DamageReceived, DamageType, Origin, InstigatedBy, DamageCauser)
--end

--void(float, UDamageType*, FVector, FVector, UPrimitiveComponent*, FName, FVector, AController*, AActor*)
--function BP_LuaCharacter_C:ReceivePointDamage(Damage, DamageType, HitLocation, HitNormal, HitComponent, BoneName, ShotFromDirection, InstigatedBy, DamageCauser)
--end

--void(UPrimitiveComponent*, AActor*, UPrimitiveComponent*, bool, FVector, FVector, FVector)
--function BP_LuaCharacter_C:ReceiveHit(MyComp, Other, OtherComp, bSelfMoved, HitLocation, HitNormal, NormalImpulse)
--end

--void(TEnumAsByte<EEndPlayReason::Type>)
--function BP_LuaCharacter_C:ReceiveEndPlay(EndPlayReason)
--end

--void()
--function BP_LuaCharacter_C:ReceiveDestroyed()
--end

--void()
--function BP_LuaCharacter_C:ReceiveBeginPlay()
--end

--void(float, UDamageType*, AController*, AActor*)
--function BP_LuaCharacter_C:ReceiveAnyDamage(Damage, DamageType, InstigatedBy, DamageCauser)
--end

--void(FKey)
--function BP_LuaCharacter_C:ReceiveActorOnReleased(ButtonReleased)
--end

--void(TEnumAsByte<ETouchIndex::Type>)
--function BP_LuaCharacter_C:ReceiveActorOnInputTouchLeave(FingerIndex)
--end

--void(TEnumAsByte<ETouchIndex::Type>)
--function BP_LuaCharacter_C:ReceiveActorOnInputTouchEnter(FingerIndex)
--end

--void(TEnumAsByte<ETouchIndex::Type>)
--function BP_LuaCharacter_C:ReceiveActorOnInputTouchEnd(FingerIndex)
--end

--void(TEnumAsByte<ETouchIndex::Type>)
--function BP_LuaCharacter_C:ReceiveActorOnInputTouchBegin(FingerIndex)
--end

--void(FKey)
--function BP_LuaCharacter_C:ReceiveActorOnClicked(ButtonPressed)
--end

--void(AActor*)
--function BP_LuaCharacter_C:ReceiveActorEndOverlap(OtherActor)
--end

--void()
--function BP_LuaCharacter_C:ReceiveActorEndCursorOver()
--end

--void(AActor*)
--function BP_LuaCharacter_C:ReceiveActorBeginOverlap(OtherActor)
--end

--void()
--function BP_LuaCharacter_C:ReceiveActorBeginCursorOver()
--end

--void()
--function BP_LuaCharacter_C:K2_OnReset()
--end

--void(APlayerController*)
--function BP_LuaCharacter_C:K2_OnEndViewTarget(PC)
--end

--void(APlayerController*)
--function BP_LuaCharacter_C:K2_OnBecomeViewTarget(PC)
--end

--void(int32)
--function BP_LuaCharacter_C:ExecuteUbergraph(EntryPoint)
--end

return BP_LuaCharacter_C


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM