플러그인 모듈 생성 플러그인 모듈은 플러그인의 기능을 구현하는 C++ 코드다. 모듈은 모든 Unreal Engine 모듈과 동일한 방식으로 작동하며, 헤더 파일과 소스 파일로 구성된다. Unreal Editor에서 "Add New -> C++ Class"를 선택하고 "Module Class"를 선택하여 모듈 클래스를 만들 수 있다.

 

목차

     

     


     

     

     
    Plugins
      Example
        Example.Build.cs
    ExampleConsoleCommand.h .cpp 
    ExampleDebuggerCategory.h .cpp
    ExampleModule.h .cpp
    StaticMesh_Detail.h .cpp
    Source
        Utilities
        CHelper.h
    CLog.h .cpp
        Global.h
    CStaticMesh.h .cpp
    .Build.cs
        .uproject
     

     

     

     

     

    Plugin

     

    객체지향에서 설계상 용어로 멤버변수는 Property, 함수는 Method라고 부른다. 설계상 용어로 Procedure는 함수기반이라는 의미이다.

    언리얼의 Property은 Handle를 가지고 있다. 그래서 Property를 다룰때는 handle를 사용한다.

    Handle은 식별자이다.


     

     

     

    M_StaticMesh_Inst

     

    Color를 체크하여 외부에서 값 수정이 가능하게 만들어준다.

     


     

     

    StaticMesh_Detail.h .cpp

     

    StaticMesh_Detail.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "IDetailCustomization.h"
    
    class EXAMPLE_API FStaticMesh_Detail : public IDetailCustomization //IDetailCustomization로부터 상속받는다.
    {
    public:
    	static TSharedRef<IDetailCustomization> MakeInstance();
    
    public:
    	void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
    
    private:
    	FReply OnClicked_Paint();
    	FReply OnClicked_SaveMesh();
    
    private:
    	TArray<TWeakObjectPtr<UObject>> Objects;
    };

    함수 추가

    • FReply OnClicked_Paint() 
    • FReply OnClicked_SaveMesh()

     

     

    StaticMesh_Detail.cpp

    더보기
    #include "StaticMesh_Detail.h"
    #include "DetailLayoutBuilder.h"
    #include "DetailCategoryBuilder.h"
    #include "DetailWidgetRow.h"
    #include "Misc/MessageDialog.h"
    
    #include "U2212_05/CStaticMesh.h"
    
    TSharedRef<IDetailCustomization> FStaticMesh_Detail::MakeInstance()
    {
    	return MakeShareable(new FStaticMesh_Detail());
    }
    
    void FStaticMesh_Detail::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
    {
    	IDetailCategoryBuilder& actor = DetailBuilder.EditCategory("Actor");
    	//actor.SetCategoryVisibility(false); //actor 카테고리를 숨긴다.
    
    	TArray<TSharedRef<IPropertyHandle>> handles;
    	actor.GetDefaultProperties(handles);
    
    	for(TSharedRef<IPropertyHandle> handle : handles)
    	{
    		// GLog->Log(handle->GetProperty()->GetName());
    		// GLog->Log(handle->GetProperty()->GetPathName());
    		// GLog->Log(handle->GetProperty()->GetFullName());
    
    		if (handle->GetProperty()->GetName().Compare("bCanBeDamaged") == 0)
    			DetailBuilder.HideProperty(handle); //해당 조건이면 handle를 숨겨준다.(=actor에 있는 bCanBeDamaged를 숨겨준다.
    	}
    
    	IDetailCategoryBuilder& mesh = DetailBuilder.EditCategory("Mesh");
    
    	mesh.AddCustomRow(FText::FromString("Mesh"))
    	.NameContent()
    	[
    		SNew(STextBlock) //SNew는 Slate UI들을 동적할당 한다.
    		.Text(FText::FromString("Color"))
    	]
    	.ValueContent()
    	[
    		SNew(SButton)
    		.VAlign(VAlign_Center)
    		.HAlign(HAlign_Fill)
    		.OnClicked(this, &FStaticMesh_Detail::OnClicked_Paint)
    		//.Content()
    		[
    			SNew(STextBlock)
    			.Text(FText::FromString("Paint"))
    		]
    	];
    
    	mesh.AddCustomRow(FText::FromString("SaveMesh"))
    	.NameContent()
    	[
    		SNew(STextBlock) //SNew는 Slate UI들을 동적할당 한다.
    		.Text(FText::FromString("Mesh"))
    	]
    	.ValueContent()
    	[
    		SNew(SButton)
    		.VAlign(VAlign_Center)
    		.HAlign(HAlign_Fill)
    		.OnClicked(this, &FStaticMesh_Detail::OnClicked_SaveMesh)
    		//.Content()
    		[
    			SNew(STextBlock)
    			.Text(FText::FromString("SaveMesh"))
    		]
    	];
    
    	DetailBuilder.GetObjectsBeingCustomized(Objects);//TWeakObjectPtr의 Objcts를 사용하니 가비지 콜렉터에 의해 관리될 것이다.
    }
    
    FReply FStaticMesh_Detail::OnClicked_Paint()
    {
    	for(TWeakObjectPtr<UObject> obj : Objects)
    	{
    		ACStaticMesh* mesh = Cast<ACStaticMesh>(obj); //CStaticMesh 캐스팅한다.
    
    		if (!!mesh) //mesh가 있다면
    			mesh->Paint(); //mesh에 Paint()를 사용하여 색을 적용.
    	}
    	return FReply::Handled();
    }
    
    FReply FStaticMesh_Detail::OnClicked_SaveMesh()
    {
    	if(Objects[0]->GetWorld()->IsPlayInEditor()) //Objecs[0]이 Editor상에서 플레이 되었다면
    	{
    		FMessageDialog dialog;
    		dialog.Debugf(FText::FromString("In GameMode, it is not working."));
    
    		return FReply::Unhandled();//처리하지 못했기 때문에 다음으로 넘겨줘야 한다. 그래서 Unhandled()로 return
    	}
    
    	TArray<ACStaticMesh*> meshActors;
    	for (TWeakObjectPtr<UObject> obj : Objects)
    	{
    		ACStaticMesh* mesh = Cast<ACStaticMesh>(obj);
    		if (mesh == nullptr) continue; //캐스팅 실패 시에 저장할 자료형이 아니므로 continue로 패스
    
    		meshActors.Add(mesh);//캐스팅 성공 시에 mesh 추가
    	}
    
    	return FReply::Handled();
    }

    CustomizeDetail에 항목 추가

    • mesh.AddCustomRow(FTEXT::FromString("Mesh")) 추가
    • mesh.AddCustomRow(FTEXT::FromString("SaveMesh")) 추가

     

    함수 정의

    • FReply FStaticMesh_Detail::OnClicked_Paint() 
    • FReply FStaticMesh_Detail::OnClicked_SaveMesh()

     


     

     

    TWeakPtr 설명

     

     

    위의 Objects는 StaticMesh_Detail.h에서 만든 TArray<TWeakObjectPtr<UObject>> Objects;

     

    TWeakPtr는 서로간에 영향을 미치지 않는다.

    따라서 외부에서 자동으로 삭제되는 경우에 쓰기가 좋다. = 가비지 콜렉터에 의해 관리될 요소

     

     

       
    TWeakFieldPtr  UObject로부터 만들어진 멤버변수
    TWeakObjectPtr  UObject로부터 만들어진 지역변수

     

     


     

     

     

     

    Source

     

     


     

     

    CStaticMesh.h .cpp

     

    CStaticMesh.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "CStaticMesh.generated.h"
    
    UCLASS()
    class U2212_05_API ACStaticMesh : public AActor
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(VisibleAnywhere, Category = "Material")
    		class UMaterialInstanceConstant* Material;
    
    private:
    	UPROPERTY(VisibleAnywhere)
    		class UStaticMeshComponent* Mesh;
    
    public:	
    	ACStaticMesh();
    
    protected:
    	virtual void BeginPlay() override;
    
    #if WITH_EDITOR//Editor에서만 사용한다고 명시. Editor전용일때는 반드시 매크로를 명시해주어야 한다. 실제로 빌드하면 WITH_EDITOR부분이 빠진다.
    	//Editor에서만 실행될 함수
    public:
    	void Paint();
    #endif
    };

    #if WITH_EDITOR ~ #endif를 사용하여 void Paint()가 Editor가 실행될 때만 실행되게 만들어준다.

     

     

     

    CStaticMesh.cpp

    더보기
    #include "CStaticMesh.h"
    #include "Global.h"
    #include "Components/StaticMeshComponent.h"
    #include "Materials/MaterialInstanceConstant.h"
    
    ACStaticMesh::ACStaticMesh()
    {
    	CHelpers::CreateComponent<UStaticMeshComponent>(this, &Mesh, "Mesh");
    
    	UStaticMesh* mesh;
    	CHelpers::GetAsset<UStaticMesh>(&mesh, "StaticMesh'/Game/MatineeCam_SM.MatineeCam_SM'");
    	Mesh->SetStaticMesh(mesh);
    
    	CHelpers::GetAsset<UMaterialInstanceConstant>(&Material, "MaterialInstanceConstant'/Game/M_StaticMesh_Inst.M_StaticMesh_Inst'");
    	Mesh->SetMaterial(0, Material);
    
    #if WITH_EDITOR
    	GLog->Log(GetActorLabel()); //GetActorLabel은 BP의 DisplayName과 같다.
    #endif
    }
    
    void ACStaticMesh::BeginPlay()
    {
    	Super::BeginPlay();
    
    }
    
    #if WITH_EDITOR
    void ACStaticMesh::Paint()
    {
    	for (const FVectorParameterValue& value : Material->VectorParameterValues) 
    	{
    		if (value.ParameterInfo.Name.Compare("Color") == 0)
    			Material->SetVectorParameterValueEditorOnly(value.ParameterInfo, FLinearColor::MakeRandomColor()); //Editor전용 함수 사용.
    	}
    }
    #endif

     


     

     

    참고사항) NMAKE  vs.  CMAKE

     

    NMAKE느 빌드를 위한 요소이 CMAKE는 프로젝트(에 내장된 코드들)를 자동으로 만들어주는 요소이다.

     

     


     

     

    실행화면

     

     

     

     


     

     

     

    '⭐ Unreal Engine > UE Plugin - Basic' 카테고리의 다른 글

    [UE] Plugin (Save StaticMesh .csv)  (0) 2023.04.13
    [UE] Plugin (Save StaticMesh & RenderData, LOD)  (0) 2023.04.12
    [UE] StaticMesh  (0) 2023.04.06
    [UE] Console Command  (0) 2023.04.05
    [UE] Console, DrawDebugLine  (0) 2023.04.04