언리얼 에디터 내에서 Asset을 원하는 숫자만큼 한 번에 복제하는 툴 기능을 구현하였다. 만약 0이하의 숫자를 기입하는 경우, 경고 문구를 띄우고 복제가 진행되지 않는다. 해당 기능을 사용해서 좀 더 편리하게 언리얼 작업을 진행해보자.

 

목차

     

     


     

     

    Asset 복제 기능의 Editor 만들기

     


     

    Plugin 생성 후 .uplugin 설정 변경하기

     

    SWManager.uplugin

    (좌) 변경 전,  (우) 변경 후

     

    Game에는 영향을 안 주고 Editor에서만 영향을 주므로 Runtime이 아닌 Editor로 설정. 

    Plugin Module이 로드되는 시점 PreDefault로 변경


     

     

    QuickAssetAction 생성

     

     

    QuickAssetAction.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "AssetActionUtility.h"
    #include "QuickAssetAction.generated.h"
    
    UCLASS()
    class SWMANAGER_API UQuickAssetAction : public UAssetActionUtility
    {
    	GENERATED_BODY()
    
    public:
    	UFUNCTION(CallInEditor)
    	void TestFunc();
    };

     

    QuickAssetAction.cpp

    더보기
    #include "AssetActions/QuickAssetAction.h"
    
    void UQuickAssetAction::TestFunc()
    {
    	if (GEngine)
    	{
    		GEngine->AddOnScreenDebugMessage(-1, 8.f, FColor::Cyan, TEXT("Working"));
    	}
    }

     


     

    SWManager.Build.cs  수정

     

    SWManager.Build.cs

    더보기
    // Copyright Epic Games, Inc. All Rights Reserved.
    
    using UnrealBuildTool;
    
    public class SWManager : ModuleRules
    {
    	public SWManager(ReadOnlyTargetRules Target) : base(Target)
    	{
    		PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
    		
    		PublicIncludePaths.AddRange(
    			new string[] {
    				// ... add public include paths required here ...
    			}
    			);
    				
    		
    		PrivateIncludePaths.AddRange(
    			new string[] {
                    System.IO.Path.GetFullPath(Target.RelativeEnginePath) + "/Source/Editor/Blutility/Private"
    			}
    			);
    			
    		
    		PublicDependencyModuleNames.AddRange(
    			new string[]
    			{
    				"Core", "Blutility"
    				// ... add other public dependencies that you statically link with here ...
    			}
    			);
    			
    		
    		PrivateDependencyModuleNames.AddRange(
    			new string[]
    			{
    				"CoreUObject",
    				"Engine",
    				"Slate",
    				"SlateCore",
    				// ... add private dependencies that you statically link with here ...	
    			}
    			);
    		
    		
    		DynamicallyLoadedModuleNames.AddRange(
    			new string[]
    			{
    				// ... add any modules that your module loads dynamically here ...
    			}
    			);
    	}
    }

    PrivateIncludePaths.AddRange(
    new string[] {
                    System.IO.Path.GetFullPath(Target.RelativeEnginePath) + "/Source/Editor/Blutility/Private"} );

    PublicDependencyModuleNames.AddRange(
    new string[]{
    "Core", "Blutility"} );

     

    • 위의 것들을 추가하여 AssetActionUtility 를사용할 수 있게 해주기

     


     

    실행화면

     

     

     


     

     

     

     

    2 - Asset 복제하기 기능 만들기


     

    SWManager.Build.cs  수정

     

    SWManager.Build.cs

    더보기
    // Copyright Epic Games, Inc. All Rights Reserved.
    
    using UnrealBuildTool;
    
    public class SWManager : ModuleRules
    {
    	public SWManager(ReadOnlyTargetRules Target) : base(Target)
    	{
    		PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
    		
    		PrivateIncludePaths.AddRange(
    			new string[] {
                    System.IO.Path.GetFullPath(Target.RelativeEnginePath) + "/Source/Editor/Blutility/Private"
    			}
    			);
    			
    		
    		PublicDependencyModuleNames.AddRange(
    			new string[]
    			{
    				"Core", "Blutility", "EditorScriptingUtilities"
    				// ... add other public dependencies that you statically link with here ...
    			}
    			);
    			
    		
    		PrivateDependencyModuleNames.AddRange(
    			new string[]
    			{
    				"CoreUObject",
    				"Engine",
    				"Slate",
    				"SlateCore",
    			}
    			);
    	}
    }

    PublicDependencyModuleNames.AddRange

    • "EditorScriptingUtilities" 를 추가하여 UEditorAssetLibrary 사용할 수 있게 해주기
      • 이것을 추가함으로써 플러그인 내의 클래스들에서 #include "EditorUtilityLibrary.h", #include "EditorAssetLibrary.h"를 선언하고 그 기능들을 가져다가 쓸 수 있다.

     

     

     

    QuickAssetAction 수정

     

    QuickAssetAction.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "AssetActionUtility.h"
    #include "QuickAssetAction.generated.h"
    
    /** 우클릭 AssetAction에 새로운 기능 추가하기
     * 
     */
    UCLASS()
    class SWMANAGER_API UQuickAssetAction : public UAssetActionUtility
    {
    	GENERATED_BODY()
    
    public:
    	UFUNCTION(CallInEditor)
    	void DuplicateAssets(int32 NumOfDuplicates);
    };

     

    QuickAssetAction.cpp

    더보기
    #include "AssetActions/QuickAssetAction.h"
    #include "DebugHeader.h"
    #include "EditorUtilityLibrary.h"
    #include "EditorAssetLibrary.h"
    
    void UQuickAssetAction::DuplicateAssets(int32 NumOfDuplicates) // Asset 복제하기
    {
    	if (NumOfDuplicates <= 0) // 복사 개수가 0이하라면
    	{
    		// 잘못됬다는 문구를 띄우고 리턴한다
    		Print(TEXT("Please enter a VALID number"), FColor::Red);
    		return;
    	}
    
    	TArray<FAssetData> SelectedAssetsData = UEditorUtilityLibrary::GetSelectedAssetData();
    	uint32 Counter = 0;
    
    	for (const FAssetData& SelectedAssetData : SelectedAssetsData)
    	{
    		for (int32 i = 0; i < NumOfDuplicates; i++)
    		{
    			// Asset 경로, 이름짓기, 복제될 Asset의 경로
    			const FString SourceAssetPath = SelectedAssetData.ObjectPath.ToString();
    			const FString NewDuplicatedAssetName = SelectedAssetData.AssetName.ToString() + TEXT("_") + FString::FromInt(i + 1);
    			const FString NewPathName = FPaths::Combine(SelectedAssetData.PackagePath.ToString(), NewDuplicatedAssetName);
    
    			// SourceAssetPath경로에 있는 Asset을 NewPathName경로로 복제
    			if (UEditorAssetLibrary::DuplicateAsset(SourceAssetPath, NewPathName)) 
    			{
    				UEditorAssetLibrary::SaveAsset(NewPathName, false); // NewPathName경로에 Asset을 저장
    				++Counter;
    			}
    		}
    	}
    
    	if (Counter > 0) // 복제가 0 초과면 문구 띄우기
    	{
    		Print(TEXT("Successfully duplicated " + FString::FromInt(Counter) + " files"), FColor::Green);
    	}
    }

     

    실행화면

     


     

     

     

    3. FMessageDialog 띄우기


     

     

     

    FMessageDialog::Open()의 리턴타입은  EAppReturnType::Type

     

    FMessageDialog 관련 내용들은 Runtime\Core\Misc\MessageDialog.h.cpp에 정의되어 있다. 

    FMessageDialog::Open()의 리턴타입은  EAppReturnType::Type 이다.

     


     

     

     

    0미만의 숫자의 기입 했을때 MessageDialog 문구창 띄우기 

     

    QuickAssetAction.cpp

    더보기
    #include "AssetActions/QuickAssetAction.h"
    #include "DebugHeader.h"
    #include "EditorUtilityLibrary.h"
    #include "EditorAssetLibrary.h"
    #include "Misc/MessageDialog.h"
    
    void UQuickAssetAction::DuplicateAssets(int32 NumOfDuplicates) // Asset 복제하기
    {
    	if (NumOfDuplicates <= 0) // 복사 개수가 0이하라면
    	{
    		// 잘못됬다는 문구를 띄우고 리턴한다
    		FText MsgTitle = FText::FromString(TEXT("Warning"));
    		FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(TEXT("Please enter a VALID number")), &MsgTitle);
    		return;
    	}
    
    	TArray<FAssetData> SelectedAssetsData = UEditorUtilityLibrary::GetSelectedAssetData();
    	uint32 Counter = 0;
    
    	for (const FAssetData& SelectedAssetData : SelectedAssetsData)
    	{
    		for (int32 i = 0; i < NumOfDuplicates; i++)
    		{
    			// Asset 경로, 이름짓기, 복제될 Asset의 경로
    			const FString SourceAssetPath = SelectedAssetData.ObjectPath.ToString();
    			const FString NewDuplicatedAssetName = SelectedAssetData.AssetName.ToString() + TEXT("_") + FString::FromInt(i + 1);
    			const FString NewPathName = FPaths::Combine(SelectedAssetData.PackagePath.ToString(), NewDuplicatedAssetName);
    
    			// SourceAssetPath경로에 있는 Asset을 NewPathName경로로 복제
    			if (UEditorAssetLibrary::DuplicateAsset(SourceAssetPath, NewPathName)) 
    			{
    				UEditorAssetLibrary::SaveAsset(NewPathName, false); // NewPathName경로에 Asset을 저장
    				++Counter;
    			}
    		}
    	}
    
    	if (Counter > 0) // 복제가 0 초과면 문구 띄우기
    	{
    		Print(TEXT("Successfully duplicated " + FString::FromInt(Counter) + " files"), FColor::Green);
    	}
    }

    void UQuickAssetAction::DuplicateAssets(int32 NumOfDuplicates)

    • if (NumOfDuplicates <= 0) {
      // 잘못됬다는 문구를 띄우고 리턴한다
      FText MsgTitle = FText::FromString(TEXT("Warning"));
      FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(TEXT("Please enter a VALID number")), &MsgTitle);
      return; }

    실행화면

     


     

     

    코드 수정: 위에서 작업한 부분을 DebugHeader.h로 옮기고 함수를 콜하는 방식

     

    DebugHeader.h

    더보기
    #pragma once
    #include "Misc/MessageDialog.h"
    #include "Widgets/Notifications/SNotificationList.h"
    #include "Framework/Notifications/NotificationManager.h"
    
    void Print(const FString& Message, const FColor& Color)
    {
    	if (GEngine)
    	{
    		GEngine->AddOnScreenDebugMessage(-1, 8.f, Color, Message);
    	}
    }
    
    void PrintLog(const FString& Message)
    {
    	UE_LOG(LogTemp, Warning, TEXT("%s"), *Message);
    }
    
    EAppReturnType::Type ShowMsgDialog(EAppMsgType::Type MsgType, const FString& Message, bool bShowMsgAsWarning = true)
    {
    	if (bShowMsgAsWarning)
    	{
    		// Warning과 잘못됬다는 문구(Message)를 띄우고 리턴한다
    		FText MsgTitle = FText::FromString(TEXT("Warning"));
    
    		return FMessageDialog::Open(MsgType, FText::FromString(Message), &MsgTitle);
    	}
    	else
    	{	// 문구(Message)를 띄우고 리턴한다
    		return FMessageDialog::Open(MsgType, FText::FromString(Message));
    	}
    }
    
    void ShowNotifyInfo(const FString& Message)
    {
    	FNotificationInfo NotifyInfo(FText::FromString(Message));
    	NotifyInfo.bUseLargeFont = true;
    	NotifyInfo.FadeOutDuration = 7.0f; // NotifyInfo 메시지를 7초 동안 띄운다
    
    	FSlateNotificationManager::Get().AddNotification(NotifyInfo);
    }

     

     

    QuickAssetAction.cpp

    더보기
    #include "AssetActions/QuickAssetAction.h"
    #include "DebugHeader.h"
    #include "EditorUtilityLibrary.h"
    #include "EditorAssetLibrary.h"
    
    void UQuickAssetAction::DuplicateAssets(int32 NumOfDuplicates) // Asset 복제하기
    {
    	if (NumOfDuplicates <= 0) // 복사 개수가 0이하라면
    	{
    		// DebugHeader.h에 만든 ShowMsgDialog함수를 콜해 아래의 문구를 띄운다.
    		ShowMsgDialog(EAppMsgType::Ok, TEXT("Please enter a VALID number"));
    		return;
    	}
    
    	TArray<FAssetData> SelectedAssetsData = UEditorUtilityLibrary::GetSelectedAssetData();
    	uint32 Counter = 0;
    
    	for (const FAssetData& SelectedAssetData : SelectedAssetsData)
    	{
    		for (int32 i = 0; i < NumOfDuplicates; i++)
    		{
    			// Asset 경로, 이름짓기, 복제될 Asset의 경로
    			const FString SourceAssetPath = SelectedAssetData.ObjectPath.ToString();
    			const FString NewDuplicatedAssetName = SelectedAssetData.AssetName.ToString() + TEXT("_") + FString::FromInt(i + 1);
    			const FString NewPathName = FPaths::Combine(SelectedAssetData.PackagePath.ToString(), NewDuplicatedAssetName);
    
    			// SourceAssetPath경로에 있는 Asset을 NewPathName경로로 복제
    			if (UEditorAssetLibrary::DuplicateAsset(SourceAssetPath, NewPathName)) 
    			{
    				UEditorAssetLibrary::SaveAsset(NewPathName, false); // NewPathName경로에 Asset을 저장
    				++Counter;
    			}
    		}
    	}
    
    	if (Counter > 0) // 복제가 0 초과면 문구 띄우기
    	{
    		// DebugHeader.h에 만든 ShowNotifyInfo함수를 콜해 언리얼에디터 우측 하단에 아래의 문구를 띄운다.
    		ShowNotifyInfo(TEXT("Successfully duplicated " + FString::FromInt(Counter) + " files"));
    	}
    }

    DebugHeader.h에서

    • EAppReturnType::Type ShowMsgDialog(EAppMsgType::Type MsgType, const FString& Message, bool bShowMsgAsWarning = true)
    • void ShowNotifyInfo(const FString& Message)

    함수를 콜하여 문구를 띄우는 방식으로 코드 수정.


     

     

     

    실행화면