목차

     

     


     

     

     

     
    Plugins
     
      Weapon
     
        Resource
     
          Icon128.png
    weapon_thumbnail_icon.png
     
        Source
     
          Weapon  
          SWeaponCheckBoxes.h .cpp
    SWeaponDetailsView
    .h .cpp
    SWeaponDoActionData.h .cpp 생성
    SWeaponEquipmentData.h .cpp
    SWeaponLeftArea.h .cpp
    Weapon.Build.cs
    WeaponAssetEditor.h .cpp
    WeaponAssetFactory.h .cpp
    WeaponCommand.h .cpp 
    WeaponContextMenu.h .cpp
    WeaponModule.h .cpp
    WeaponStyle.h .cpp 
     
       

     

     

     

     

    DoAction Data 연동하기

     

     


     

    SWeaponCheckBoxes

     

    SWeaponCheckBoxes.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    
    class WEAPON_API SWeaponCheckBoxes
        : public TSharedFromThis<SWeaponCheckBoxes> // 직접적으로 상속받으면 주소가 일치하게된다.
    {
    public:
        //IPropertyHandle는 하나의 Property에 대한 식별자
        void AddProperties(TSharedPtr<IPropertyHandle> InHandle);
    
        //SNew에 최상의 부모가 SWidget이 된다. 레퍼런스를 사용하기 때문에 동일하게 쓰기위함
        TSharedRef<SWidget> Draw(bool bBackground = false);
    
        //해당 Properties를 그릴지 말지 결정
        void DrawProperties(TSharedRef<IPropertyHandle> InPropertyHandle, IDetailChildrenBuilder* InChildrenBuilder);
    
        //객체를 외부에서 받기위해,
        void SetUtilities(TSharedPtr<class IPropertyUtilities> InUtilities);
    
    private:
        //체크가 완료되었는지 
        void OnCheckStateChanged(ECheckBoxState InState, int32 InIndex);
    
    public:
        //InIndex에는 Property 번호가 InValue에는 값.
        void CheckDefaultObject(int32 InIndex, UObject* InValue);
        void CheckDefaultValue(int32 InIndex, float InValue);
        void CheckDefaultValue(int32 InIndex, bool InValue);
        void CheckDefaultValue(int32 InIndex, const FVector& InValue);
    
    private:
        //내부 구조체 생성, 관리를 위해 사용
        struct FInternalData
        {
            bool bChecked;//체크 되었는가
            FString Name;//이름
            TSharedPtr<IPropertyHandle> Handle;
    
            FInternalData(TSharedPtr<IPropertyHandle> InHandle)
            {
                bChecked = false;//기본값은 false로 설정.
                Handle = InHandle;
    
                Name = Handle->GetPropertyDisplayName().ToString();//핸들 내의 DisplayName을 출력이름으로 설정.
            }
        };
        TArray<FInternalData> InternalDatas;//구조체 Data 전부를 포괄한 배열변수
    
        TSharedPtr<class IPropertyUtilities> Utilities;//멤버 변수
    };

    함수 추가

    • void CheckDefaultObject(int32 InIndex, UObject* InValue);    
    • void CheckDefaultValue(int32 InIndex, float InValue);
    • void CheckDefaultValue(int32 InIndex, bool InValue);
    • void CheckDefaultValue(int32 InIndex, const FVector& InValue);
    • InIndex에는 Property 번호가 InValue에는 값이 들어간다.

     

     

     

    SWeaponCheckBoxes.cpp

    더보기
    #include "SWeaponCheckBoxes.h"
    #include "WeaponStyle.h"
    #include "SWeaponDetailsView.h"
    #include "Widgets/Layout/SUniformGridPanel.h"
    #include "IPropertyUtilities.h"
    #include "IDetailPropertyRow.h"
    #include "IDetailChildrenBuilder.h"
    #include "DetailWidgetRow.h"
    
    void SWeaponCheckBoxes::AddProperties(TSharedPtr<IPropertyHandle> InHandle)
    {
        uint32 number = 0;
        InHandle->GetNumChildren(number);//핸들 내의 자식 property가 몇 개 있는지 가져온다.
    
        for (uint32 i = 0; i < number; i++)
            InternalDatas.Add(FInternalData(InHandle->GetChildHandle(i)));
    }
    
    TSharedRef<SWidget> SWeaponCheckBoxes::Draw(bool bBackground)
    {
        TSharedPtr<SUniformGridPanel> panel;
        SAssignNew(panel, SUniformGridPanel);//SNew와 다르게 변수를 선언해 놓는 SAssignNew
        panel->SetMinDesiredSlotWidth(150);//최소폭 150으로 설정.
    
        for (int32 i = 0; i < InternalDatas.Num(); i++)
        {
            panel->AddSlot(i, 0)//한줄만 사용, 여러줄사용하려면 ex) i % 5
            [
                SNew(SCheckBox)//체크박스는 컨텐츠 영역을 가지고 있다.
                .IsChecked(InternalDatas[i].bChecked)//체크 여부 출력, 0과 1로만 판단
    	        .OnCheckStateChanged(this, &SWeaponCheckBoxes::OnCheckStateChanged, i)//체크 했는지 판단
    	        [
    	            SNew(STextBlock)
    	            .Text(FText::FromString(InternalDatas[i].Name))//InternalDatas의 이름들 출력
    	        ]
            ];
        }
    
        return panel.ToSharedRef();//추가를 하게되면, 추가된 그자체를 return
    
    }
    
    void SWeaponCheckBoxes::DrawProperties(TSharedRef<IPropertyHandle> InPropertyHandle, IDetailChildrenBuilder* InChildrenBuilder)
    {
        for (int32 i = 0; i < InternalDatas.Num(); i++)
        {
            // 체크박스에 체크를 바꾸게 되는지 확인, 바꾸지 안았다면 그릴 필요가 없다.
            if (InternalDatas[i].bChecked == false)//그릴 필요가 없는 경우
                continue;
            // 각 줄에 식별자
            TSharedPtr<IPropertyHandle> handle = InPropertyHandle->GetChildHandle(i);
            // 자식부분을 담당, 이 Handle이 기본모양을 추가해서 만들어준다. 커스텀 마이징도 가능하다
            IDetailPropertyRow& row = InChildrenBuilder->AddProperty(handle.ToSharedRef());
    
            FString name = FString("Name ") + FString::FromInt(i + 1);
    
            row.CustomWidget()
            .NameContent()
            [
                handle->CreatePropertyNameWidget()
            ]
            //줄이거나 늘렸을 때 Min 이하로는 고정. Max 이상으로는 고정.
            .ValueContent()
            .MinDesiredWidth(FWeaponStyle::Get()->DesiredWidth.X)
            .MaxDesiredWidth(FWeaponStyle::Get()->DesiredWidth.Y)
            [
                handle->CreatePropertyValueWidget()
            ];
        }
    }
    
    void SWeaponCheckBoxes::SetUtilities(TSharedPtr<IPropertyUtilities> InUtilities)
    {
        //외부 객체 받아오기
        Utilities = InUtilities;
    }
    
    void SWeaponCheckBoxes::OnCheckStateChanged(ECheckBoxState InState, int32 InIndex)
    {
        //상태를 바뀌는걸 확인했기때문에, 값을 뒤집어 줘서 다시 안그려지게 만들어준다.
        InternalDatas[InIndex].bChecked = !InternalDatas[InIndex].bChecked;
    
        SWeaponDetailsView::OnRefreshByCheckBoxes();
        {
            // ForceRefresh이 콜이되면 새로고침이 되면서 다시 그려진다.
            Utilities->ForceRefresh();
        }
        SWeaponDetailsView::OffRefreshByCheckBoxes();
    
    }
    
    void SWeaponCheckBoxes::CheckDefaultObject(int32 InIndex, UObject* InValue)
    {
        UObject* val = nullptr;//기본값
        InternalDatas[InIndex].Handle->GetValue(val);//해당 Property에 선택한 값
    
        if (!!val && InValue != val)//nullptr이거나 선택한 값이랑 기본값이 다르다면
            InternalDatas[InIndex].bChecked = true;
    }
    
    void SWeaponCheckBoxes::CheckDefaultValue(int32 InIndex, float InValue)
    {
        float val = 0.0f;//기본값
        InternalDatas[InIndex].Handle->GetValue(val);//해당 Property에 선택한 값
    
        if (InValue != val)//선택한 값이랑 기본값이 다르다면
            InternalDatas[InIndex].bChecked = true;
    }
    
    void SWeaponCheckBoxes::CheckDefaultValue(int32 InIndex, bool InValue)
    {
        bool val = false;//기본값
        InternalDatas[InIndex].Handle->GetValue(val);//해당 Property에 선택한 값
    
        if (InValue != val)//선택한 값이랑 기본값이 다르다면
            InternalDatas[InIndex].bChecked = true;
    }
    
    void SWeaponCheckBoxes::CheckDefaultValue(int32 InIndex, const FVector& InValue)
    {
        FVector val = FVector::ZeroVector;//기본값
        InternalDatas[InIndex].Handle->GetValue(val);//해당 Property에 선택한 값
    
        if (InValue != val)//선택한 값이랑 기본값이 다르다면
            InternalDatas[InIndex].bChecked = true;
    }

    헤더 추가

    • #include "WeaponStyle.h"

     

    함수 내용 추가

    • void SWeaponCheckBoxes::DrawProperties()
      • WeaponStyle.h에서 선언한 const FVector2D DesiredWidth = FVector2D(250, 1000); 변수 값을 가져다가 사용.
      • 해당 변수는 창의 너비와 높이의 최소, 최대값을 설정할 때 사용한다.
      • 수정 코드
        • .MinDesiredWidth(FWeaponStyle::Get()->DesiredWidth.X)
        • .MaxDesiredWidth(FWeaponStyle::Get()->DesiredWidth.Y)

     

    함수 정의

    • void SWeaponCheckBoxes::CheckDefaultObject(int32 InIndex, UObject* InValue)
    • void SWeaponCheckBoxes::CheckDefaultValue(int32 InIndex, float InValue)
    • void SWeaponCheckBoxes::CheckDefaultValue(int32 InIndex, bool InValue)
    • void SWeaponCheckBoxes::CheckDefaultValue(int32 InIndex, const FVector& InValue)

     


     

    WeaponStyle

     

    WeaponStyle.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    
    class WEAPON_API FWeaponStyle
    {
    public:
    	static TSharedRef<FWeaponStyle> Get();
    	static void Shutdown();
    
    private:
    	static TSharedPtr<FWeaponStyle> Instance;
    
    public:
    	FWeaponStyle();
    	~FWeaponStyle();
    
    private:
    	void RegisterIcon(const FString& InName, const FString& InPath, const FVector2D& InIconSize, FSlateIcon& OutSlateIcon);
    
    private:
    	static const FName StyleSetName;
    
    private:
    	TSharedPtr<class FSlateStyleSet> StyleSet;
    
    public:
    	FSlateIcon ToolBar_Icon;
    
    public:
    	const FVector2D DesiredWidth = FVector2D(250, 1000);
    };

    변수 추가

    • const FVector2D DesiredWidth = FVector2D(250, 1000);
      • SWeaponCheckBoxes.cppvoid SWeaponCheckBoxes::DrawProperties()에서 창의 너비와 높이 최소 최대값으로 사용한다.

     

     


     

    SWeaponDoActionData 생성

     

    새 C++ 클래스 - 없음 - SWeaponDoActionData 생성

     

     

    SWeaponDoActionData.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "IPropertyTypeCustomization.h"
    
    class WEAPON_API SWeaponDoActionData
    	: public IPropertyTypeCustomization
    {
    public:
    	static TSharedRef<IPropertyTypeCustomization> MakeInstance();
    	static TSharedPtr<class SWeaponCheckBoxes> AddCheckBoxes();
    	static void EmptyCheckBoxes();//한번에 비워주는 역할의 함수
    
    	void CustomizeHeader(TSharedRef<IPropertyHandle> InPropertyHandle, FDetailWidgetRow& InHeaderRow, IPropertyTypeCustomizationUtils& InCustomizationUtils) override;
    	void CustomizeChildren(TSharedRef<IPropertyHandle> InPropertyHandle, IDetailChildrenBuilder& InChildBuilder, IPropertyTypeCustomizationUtils& InCustomizationUtils) override;
    	
    private:
    	static TArray<TSharedPtr<class SWeaponCheckBoxes>> CheckBoxes;
    };

     

     

     

    SWeaponDoActionData.cpp

    더보기
    #include "SWeaponDoActionData.h"
    #include "IPropertyUtilities.h"
    #include "IDetailPropertyRow.h"
    #include "IDetailChildrenBuilder.h"
    #include "SWeaponCheckBoxes.h"
    #include "DetailWidgetRow.h"
    
    TArray<TSharedPtr<SWeaponCheckBoxes>> SWeaponDoActionData::CheckBoxes;
    
    TSharedRef<IPropertyTypeCustomization> SWeaponDoActionData::MakeInstance()
    {
    	//자신의 클래스 타입을 만들어서 return해준다.
    	return MakeShareable(new SWeaponDoActionData());
    }
    
    TSharedPtr<SWeaponCheckBoxes> SWeaponDoActionData::AddCheckBoxes()
    {
    	TSharedPtr<SWeaponCheckBoxes> checkBoxes = MakeShareable(new SWeaponCheckBoxes());
    	int32 index = CheckBoxes.Add(checkBoxes);
    
    	return CheckBoxes[index];
    }
    
    void SWeaponDoActionData::EmptyCheckBoxes()
    {
    	for (TSharedPtr<SWeaponCheckBoxes> ptr : CheckBoxes)
    	{
    		if (ptr.IsValid())
    			ptr.Reset();
    	}
    
    	CheckBoxes.Empty();
    }
    
    void SWeaponDoActionData::CustomizeHeader(TSharedRef<IPropertyHandle> InPropertyHandle, FDetailWidgetRow& InHeaderRow,
    	IPropertyTypeCustomizationUtils& InCustomizationUtils)
    {
    	GLog->Log("CustomizeHeader");
    }
    
    void SWeaponDoActionData::CustomizeChildren(TSharedRef<IPropertyHandle> InPropertyHandle,
    	IDetailChildrenBuilder& InChildBuilder, IPropertyTypeCustomizationUtils& InCustomizationUtils)
    {
    	GLog->Log("CustomizeChildren");
    }

     


     

    SWeaponDetailsView

     

    SWeaponDetailsView.h

    변동사항 없음

     

     

    SWeaponDetailsView.cpp

    더보기
    #include "SWeaponDetailsView.h"
    #include "SWeaponCheckBoxes.h"
    #include "SWeaponEquipmentData.h"
    #include "SWeaponDoActionData.h"
    #include "DetailLayoutBuilder.h"
    #include "DetailCategoryBuilder.h"
    #include "IDetailPropertyRow.h"
    #include "Weapons/CWeaponAsset.h"
    #include "Animation/AnimMontage.h"
    
    bool SWeaponDetailsView::bRefreshByCheckBoxes = false;//static 변수 초기화.
    
    TSharedRef<IDetailCustomization> SWeaponDetailsView::MakeInstance()
    {
    	//자신의 클래스 타입을 만들어서 return해준다.
    	return MakeShareable(new SWeaponDetailsView());
    }
    
    void SWeaponDetailsView::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
    {
    	UClass* type = UCWeaponAsset::StaticClass();//UClass 타입 하나를 받아온다.
    
    	DetailBuilder.HideCategory("CWeaponAsset");//CWeaponAsset 카테고리를 숨겨준다. 현재 작업의 편의를 위해 숨겨주고 추후에 보여주게 만들 예정이다. 
    
    	//Class Settings
    	{
    		//.EditCategory 해당 타입에 해당 카테고리가 있으면 그 카테고리를 return, 없으면 새로 만들어서 return
    		//ClassSettings는 없으므로 새로 만들어서 return
    		IDetailCategoryBuilder& category = DetailBuilder.EditCategory("ClassSettings", FText::FromString("Class Settings"));
    		//CWeaponAsset에서 직렬화된 변수들을 카테고리에 추가한다.
    		category.AddProperty("AttachmentClass", type);//CWeaponAsset의 AttachmentClass를 카테고리에 추가.
    		category.AddProperty("EquipmentClass", type);//CWeaponAsset의 EquipmentClass를 카테고리에 추가.
    		category.AddProperty("DoActionClass", type);//CWeaponAsset의 DoActionClass를 카테고리에 추가.
    	}
    
    	//EquipmentData
    	{
    		//.EditCategory 해당 타입에 해당 카테고리가 있으면 그 카테고리를 return, 없으면 새로 만들어서 return
    		IDetailCategoryBuilder& category = DetailBuilder.EditCategory("EquipmentData", FText::FromString("Equipment Data"));
    		IDetailPropertyRow& row = category.AddProperty("EquipmentData", type);
    
    		if (bRefreshByCheckBoxes == false)//새로고침이 아닐 때
    		{
    			TSharedPtr<SWeaponCheckBoxes> checkBoxes = SWeaponEquipmentData::CreateCheckBoxes();//카테고리가 처음에 만들어질 때 checkBox를 만든다.
    			checkBoxes->AddProperties(row.GetPropertyHandle());//checkBoxes에 실제로 가진 Handle를 추가
    
    			FEquipmentData data;//변수 선언한다. FEquipmentData의 변수 data 기본값을 아래에서 사용한다.
    
    			int32 index = 0;
    			checkBoxes->CheckDefaultObject(index++, data.Montage);
    			checkBoxes->CheckDefaultValue(index++, data.PlayRate);
    			checkBoxes->CheckDefaultValue(index++, data.bCanMove);
    			checkBoxes->CheckDefaultValue(index++, data.bUseControlRotation);
    		}
    	}
    
    	//DoActionData
    	{
    		//.EditCategory 해당 타입에 해당 카테고리가 있으면 그 카테고리를 return, 없으면 새로 만들어서 return
    		IDetailCategoryBuilder& category = DetailBuilder.EditCategory("DoActionData", FText::FromString("DoAction Data"));
    		IDetailPropertyRow& row = category.AddProperty("DoActionDatas", type);//변수 추가 //WeaponAsset에 있는 데이터명과 일치시킨다. DoActionDatas
    
    		if (bRefreshByCheckBoxes == false)
    		{
    			uint32 count = 0;
    			row.GetPropertyHandle()->GetNumChildren(count);
    
    			SWeaponDoActionData::EmptyCheckBoxes();//비워놓고 시작.
    
    			FDoActionData data;//기본값 사용할 변수
    			for (uint32 i =0; i < count; i++)
    			{
    				TSharedPtr<IPropertyHandle> handle = row.GetPropertyHandle()->GetChildHandle(i);//헤더의 handle
    
    				TSharedPtr<SWeaponCheckBoxes> checkBoxes = SWeaponDoActionData::AddCheckBoxes();//카테고리가 처음에 만들어질 때 checkBox를 만든다.
    				checkBoxes->AddProperties(handle);
    			}
    		}//if(bRefreshByCheckBoxes)
    	}
    }

    헤더 추가

    • #include "SWeaponDoActionData.h"
    • #include "Animation/AnimMontage.h"

     

    void SWeaponDetailsView::CustomizeDetails()에 Equipment Data 추가, DoActionData 추가

    • Equipment Data
      • FEquipmentData data;
      • int32 index = 0;
      • checkBoxes->CheckDefaultObject(index++, data.Montage);
      • checkBoxes->CheckDefaultValue(index++, data.PlayRate);
      • checkBoxes->CheckDefaultValue(index++, data.bCanMove);
      • checkBoxes->CheckDefaultValue(index++, data.bUseControlRotation);
    • DoAction Data
      • IDetailCategoryBuilder& category = DetailBuilder.EditCategory("DoActionData", FText::FromString("DoAction Data"));
      • IDetailPropertyRow& row = category.AddProperty("DoActionDatas", type);

     


     

    WeaponAssetEditor

     

    WeaponAssetEditor.cpp

    더보기
    #include "WeaponAssetEditor.h"
    #include "SWeaponLeftArea.h"
    #include "SWeaponDetailsView.h"
    #include "SWeaponEquipmentData.h"
    #include "SWeaponDoActionData.h"
    #include "Weapons/CWeaponAsset.h"
    
    //설정한 이름들
    const FName FWeaponAssetEditor::EditorName = "WeaponAssetEditor";
    const FName FWeaponAssetEditor::LeftAreaTabId = "LeftArea";
    const FName FWeaponAssetEditor::DetailTabId = "Details";
    
    TSharedPtr<FWeaponAssetEditor> FWeaponAssetEditor::Instance = nullptr;//헤더에서 선언한 static 외부 초기화.
    
    void FWeaponAssetEditor::OpenWindow(FString InAssetName)
    {
    	//아래의 코드 대신에 Shutdown()을 사용하면 안 된다! Shutdown()은 다른 곳에서도 콜이 되기 때문에 아래의 코드 대신에 사용하면 문제가 된다.
    	if (Instance.IsValid()) //창이 만들어졌다면
    	{
    		Instance->CloseWindow();//창을 닫는다.
    
    		Instance.Reset();
    		Instance = nullptr;
    	}
    
    	Instance = MakeShareable(new FWeaponAssetEditor());
    	Instance->Open(InAssetName);
    }
    
    void FWeaponAssetEditor::Shutdown()
    {
    	if (Instance.IsValid())
    	{
    		Instance->CloseWindow();
    
    		Instance.Reset();
    		Instance = nullptr;
    	}
    }
    
    void FWeaponAssetEditor::Open(FString InAssetName)
    {
    	LeftArea = SNew(SWeaponLeftArea)//SWeaponLeftArea에서 받은 자료형을 생성하여 넣어준다.
    		.OnSelectedItem(this, &FWeaponAssetEditor::OnListViewSelectedItem);//LeftArea에서 선택한 데이터
    
    	FPropertyEditorModule& prop = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
    
    	//DetailsView
    	{
    		FDetailsViewArgs args(false, false, true, FDetailsViewArgs::HideNameArea);//기본값 설정. ActorsUserNameArea, ObjectsUserNameArea, HideNameArea
    		args.ViewIdentifier = "WeaponAssetEditorDetailsView";//식별자 설정. 게임 Editor쪽에서 DetailView 접근시 이 식별자로 찾을 수 있다.
    		DetailsView = prop.CreateDetailView(args);//Detail 창 띄우기.
    
    		FOnGetDetailCustomizationInstance detailView;
    		detailView.BindStatic(&SWeaponDetailsView::MakeInstance);//Static은 객체가 필요없다. 그래서 함수 주소로 바로 연결한다.
    		DetailsView->SetGenericLayoutDetailsDelegate(detailView);//Delegate를 연결해준다.
    	}
    
    	//EquipmentData
    	{
    		FOnGetPropertyTypeCustomizationInstance instance;
    		instance.BindStatic(&SWeaponEquipmentData::MakeInstance);
    		prop.RegisterCustomPropertyTypeLayout("EquipmentData", instance);//instance를 delegate 등록
    	}
    
    	//DoActionData
    	{
    		FOnGetPropertyTypeCustomizationInstance instance;
    		instance.BindStatic(&SWeaponDoActionData::MakeInstance);
    		prop.RegisterCustomPropertyTypeLayout("DoActionData", instance);//instance를 delegate 등록
    
    	}
    	//Layout 설정
    	TSharedRef<FTabManager::FLayout> layout = FTabManager::NewLayout("WeaponAssetEditor_Layout")
    		->AddArea //전체화면의 메인 영역
    		(
    			FTabManager::NewPrimaryArea()->SetOrientation(Orient_Vertical)
    			->Split
    			(
    				FTabManager::NewStack()
    				->SetSizeCoefficient(0.1f)//10%만 사용하겠다.
    				->AddTab(GetToolbarTabId(), ETabState::OpenedTab)
    			)
    			->Split
    			(
    				FTabManager::NewSplitter()->SetOrientation(Orient_Horizontal)
    				->Split
    				(
    					FTabManager::NewStack()
    					->SetSizeCoefficient(0.175f)//왼쪽 17.5% 사용
    					->AddTab(LeftAreaTabId, ETabState::OpenedTab)//ListViewTabId
    					->SetHideTabWell(true)
    				)
    				->Split
    				(
    					FTabManager::NewStack()
    					->SetSizeCoefficient(0.725f)//오른쪽 72.5% 사용
    					->AddTab(DetailTabId, ETabState::OpenedTab)//DetailTabId
    					->SetHideTabWell(true)
    				)
    			)
    		);
    
    	UCWeaponAsset* asset = nullptr; 
    	asset = LeftArea->GetFirstDataPtr()->Asset;//LeftArea의 맨 위 첫번째 데이터 선택
    
    	FAssetEditorToolkit::InitAssetEditor(EToolkitMode::Standalone, TSharedPtr<IToolkitHost>(), EditorName, layout, true, true, asset);
    
    	//DetailsView->SetObject(asset);//어느 DetailView든 asset객체가 세팅된다. 창은 여러개지만 실제 관리는 내부적으로 하나로 관리한다. 그래서 창이 종료될 때 DetailsView가 해제 안 되어 있으면 터진다.
    	LeftArea->SelectDataPtr(asset);
    }
    
    bool FWeaponAssetEditor::OnRequestClose()
    {
    	if (!!DetailsView)
    	{
    		//AssetEditorSubsystem안에(=DetailView 안에)
    		//GetEditingObject()가 등록되어 있었다면 해제하고 Editor에 알린다.
    		if (!!GEditor && !!GEditor->GetEditorSubsystem<UAssetEditorSubsystem>())
    			GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->NotifyAssetClosed(GetEditingObject(), this);
    
    		//해당 모듈이 읽힌적이 있다면 해제.
    		if (FModuleManager::Get().IsModuleLoaded("PropertyEditor"))
    		{
    			FPropertyEditorModule& prop = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");//해당모듈을 가져온다.
    			prop.UnregisterCustomClassLayout("EquipmentData");//등록 해제
    			prop.UnregisterCustomClassLayout("DoActionData");//등록 해제
    		}
    	}
    
    	if (LeftArea.IsValid())
    		LeftArea.Reset();
    
    	if (DetailsView.IsValid())
    		DetailsView.Reset();
    
    	return true;
    	//false 리턴인 경우 창이 닫힐 수 없다는 것을 의미한다.
    }
    
    void FWeaponAssetEditor::RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager)
    {
    	FAssetEditorToolkit::RegisterTabSpawners(InTabManager);
    
    	FOnSpawnTab tab;
    	tab.BindSP(this, &FWeaponAssetEditor::Spawn_LeftAreaTab);
    	TabManager->RegisterTabSpawner(LeftAreaTabId, tab);
    
    	FOnSpawnTab tab2;
    	tab2.BindSP(this, &FWeaponAssetEditor::Spawn_DetailsViewTab);
    	TabManager->RegisterTabSpawner(DetailTabId, tab2);
    }
    
    TSharedRef<SDockTab> FWeaponAssetEditor::Spawn_LeftAreaTab(const FSpawnTabArgs& InArgs)
    {
    	//TSharedPtr<SDockTab> tab = SNew(SDockTab)
    	//[
    	//	SNew(SButton)
    	//	.OnClicked(this, &FWeaponAssetEditor::OnClicked)//OnClicked 함수 연결
    	//	[
    	//		SNew(STextBlock)
    	//		.Text(FText::FromString("Test"))
    	//	]
    	//];
    
    	//return tab.ToSharedRef();
    	
    	return SNew(SDockTab)
    	[
    		LeftArea.ToSharedRef()
    	];
    }
    
    TSharedRef<SDockTab> FWeaponAssetEditor::Spawn_DetailsViewTab(const FSpawnTabArgs& InArgs)
    {
    	return SNew(SDockTab)
    	[
    		DetailsView.ToSharedRef()
    	];
    }
    
    void FWeaponAssetEditor::OnListViewSelectedItem(FWeaponRowDataPtr InDataPtr)
    {
    	if (InDataPtr == nullptr)//LeftArea에서 선택한게 없다면(또는 빈 공간을 선택했다면)
    		return;
    
    	if (!!GetEditingObject())//편집하는 객체가 있다면
    		RemoveEditingObject(GetEditingObject());//현재 창에서 편집중인 애들 제거한다.
    
    	AddEditingObject(InDataPtr->Asset);//현재 창에 편집해줄 객체를 등록해준다.
    	DetailsView->SetObject(InDataPtr->Asset);//창 안의 DetailsView도 변경해준다.
    }
    
    FName FWeaponAssetEditor::GetToolkitFName() const
    {
    	return EditorName;//외부에서 어떤 에디터 이름을 쓸 지 정해준다.
    }
    
    FText FWeaponAssetEditor::GetBaseToolkitName() const
    {
    	return FText::FromName(EditorName);//외부에서 어떤 에디터 이름을 쓸 지 정해준다.
    }
    
    FString FWeaponAssetEditor::GetWorldCentricTabPrefix() const
    {
    	return EditorName.ToString();////외부에서 어떤 식별자를 쓸 지 정해준다.
    }
    
    FLinearColor FWeaponAssetEditor::GetWorldCentricTabColorScale() const
    {
    	return FLinearColor(0, 0, 1);//파란색으로 설정.
    }
    
    FReply FWeaponAssetEditor::OnClicked()
    {
    	GLog->Log("Test");
    
    	return FReply::Handled();//Handled()는 처리하고 끝낸다.
    }

    헤더 추가

    • #include "SWeaponDoActionData.h"

     

    void FWeaponAssetEditor::Open(FString InAssetName)에 DoActionData 추가

    • FOnGetPropertyTypeCustomizationInstance instance;
    • instance.BindStatic(&SWeaponDoActionData::MakeInstance);
    • prop.RegisterCustomPropertyTypeLayout("DoActionData", instance);//instance를 delegate 등록

     

    bool FWeaponAssetEditor::OnRequestClose()에 DoActionData 등록 해제 추가하기

    • prop.UnregisterCustomClassLayout("DoActionData");

     


     

     

    실행화면