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 
 
   

 

 
Source
    Characters
    CAnimInstance.h .cpp
CEnemy.h .cpp 
CPlayer.h .cpp
ICharacter.h .cpp
    Components
    CMontagesComponent.h .cpp 
CMovementComponent.h .cpp 
CStateComponent.h .cpp 
CWeaponComponent.h .cpp 
    Notifies
    CAnimNotifyState_BeginAction.h .cpp 
CAnimNotify_CameraShake.h .cpp
CAnimNotifyState_EndAction.h .cpp
CAnimNotify_EndState.h .cpp
CAnimNotifyState_Collision.h .cpp 
CAnimNotifyState_Combo.h .cpp
CAnimNotifyState_Equip.h .cpp
    Utilities
    CHelper.h
CLog.h .cpp
    Weapons
    CDoAction_Combo.h .cpp
CAttachment.h .cpp
CDoAction.h .cpp
CEquipment.h .cpp
CWeaponAsset.h .cpp
CWeaponStructures.h .cpp
    Global.h
CGameMode.h .cpp
.Build.cs
    .uproject
 

 

 

 

 

DoAction Data 연동하기 II

 

 


 

'ProjectName'.Build.cs

 

'ProjectName'.Build.cs

더보기
using UnrealBuildTool;
public class U2212_06 : ModuleRules
{
public U2212_06(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.Add(ModuleDirectory);
PublicDependencyModuleNames.Add("Core");
PrivateDependencyModuleNames.Add("CoreUObject");
PrivateDependencyModuleNames.Add("Engine");
PrivateDependencyModuleNames.Add("InputCore");
PublicDependencyModuleNames.Add("Niagara");
}
}

Dependency Module 접근 범위 변경

  • 게임 프로젝트 뿐만 아니라 Plugin쪽에서도 Niagara 접근을 할 수 있도록 private을 public으로 변경한다.
  • 변경 전: PrivateDependencyModuleNames.Add("Niagara");
  • 변경 후: PublicDependencyModuleNames.Add("Niagara");

 


 

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 "WeaponStyle.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)
{
if (SWeaponCheckBoxes::CanDraw(InPropertyHandle, CheckBoxes.Num()) == false)
return;//CanDraw가 false면 그리지 않고 리턴.
int32 index = InPropertyHandle->GetIndexInArray();//GetIndexInArray()는 Array 안에서의 번호를 리턴.
CheckBoxes[index]->SetUtilities(InCustomizationUtils.GetPropertyUtilities());//Header,Children,Header,Children..순서로 콜된다.
FString name = InPropertyHandle->GetPropertyDisplayName().ToString();//0,1,2..표시하는 name
name = "DoAction Data - " + name;
InHeaderRow
.NameContent()
[
SNew(SBorder)//SBorder는 한 줄을 출력할 때 사용.
.BorderImage(FWeaponStyle::Get()->Array_Image.Get())
[
InPropertyHandle->CreatePropertyNameWidget(FText::FromString(name))
]
]
.ValueContent()
.MinDesiredWidth(FWeaponStyle::Get()->DesiredWidth.X)
.MaxDesiredWidth(FWeaponStyle::Get()->DesiredWidth.Y)
[
CheckBoxes[index]->Draw(true)//CheckBoxes를 그려준다(=생성한다).bBackground에 true값을 넣어주어 alpha값이 0.1f인 흰색 이미지가 겹쳐저 해당 줄이 띠처럼 보이게 만들어준다.
];
}
void SWeaponDoActionData::CustomizeChildren(TSharedRef<IPropertyHandle> InPropertyHandle,
IDetailChildrenBuilder& InChildBuilder, IPropertyTypeCustomizationUtils& InCustomizationUtils)
{
if (SWeaponCheckBoxes::CanDraw(InPropertyHandle, CheckBoxes.Num()) == false)
return;//CanDraw가 false면 그리지 않고 리턴.
int32 index = InPropertyHandle->GetIndexInArray();//GetIndexInArray()는 Array 안에서의 번호를 리턴.
CheckBoxes[index]->DrawProperties(InPropertyHandle, &InChildBuilder);
}

헤더 추가

  • #include "WeaponStyle.h"

 

함수 정의

  • void SWeaponDoActionData::CustomizeHeader(TSharedRef<IPropertyHandle> InPropertyHandle, FDetailWidgetRow& InHeaderRow, IPropertyTypeCustomizationUtils& InCustomizationUtils)
    • int32 index = InPropertyHandle->GetIndexInArray();
      • GetIndexInArray()는 Array 안에서의 번호를 리턴.
    • CheckBoxes[index]->SetUtilities(InCustomizationUtils.GetPropertyUtilities());
      • //Header, Children, Header, Children...순서로 콜된다.

 

 


 

SWeaponEquipmentData - 창의 너비와 폭의 최소 최대값 변경  

 

마이너한 변경사항.

 

SWeaponEquipmentData.h

변동사항 없음.

 

 

SWeaponEquipmentData.cpp

더보기
#include "SWeaponEquipmentData.h"
#include "WeaponStyle.h"
#include "IPropertyUtilities.h"
#include "IDetailPropertyRow.h"
#include "IDetailChildrenBuilder.h"
#include "SWeaponCheckBoxes.h"
#include "DetailWidgetRow.h"
TSharedPtr<SWeaponCheckBoxes> SWeaponEquipmentData::CheckBoxes;//초기화
TSharedRef<IPropertyTypeCustomization> SWeaponEquipmentData::MakeInstance()
{
//자신의 클래스 타입을 만들어서 return해준다.
return MakeShareable(new SWeaponEquipmentData());
}
TSharedPtr<SWeaponCheckBoxes> SWeaponEquipmentData::CreateCheckBoxes()
{
if (CheckBoxes.IsValid())
{
CheckBoxes.Reset();
CheckBoxes = nullptr;
}
return CheckBoxes = MakeShareable(new SWeaponCheckBoxes());
}
void SWeaponEquipmentData::CustomizeHeader(TSharedRef<IPropertyHandle> InPropertyHandle, FDetailWidgetRow& InHeaderRow, IPropertyTypeCustomizationUtils& InCustomizationUtils)
{
CheckBoxes->SetUtilities(InCustomizationUtils.GetPropertyUtilities());
InHeaderRow
.NameContent()
[
InPropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
.MinDesiredWidth(FWeaponStyle::Get()->DesiredWidth.X)
.MaxDesiredWidth(FWeaponStyle::Get()->DesiredWidth.Y)
[
CheckBoxes->Draw()//CheckBoxes를 그려준다(=생성한다).
];
}
void SWeaponEquipmentData::CustomizeChildren(TSharedRef<IPropertyHandle> InPropertyHandle, IDetailChildrenBuilder& InChildBuilder, IPropertyTypeCustomizationUtils& InCustomizationUtils)
{
CheckBoxes->DrawProperties(InPropertyHandle, &InChildBuilder);
}

헤더 추가

  • #include "WeaponStyle.h"

 

함수 내용수정

  •  창의 너비와 폭의 최소, 최대값을 설정. FWeaponStyle 내의 변수 DesiredWidth를 사용.
    • 변경 전: .MinDesiredWidth(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotWidth"))
                   .MaxDesiredWidth(FEditorStyle::GetFloat("StandardDialog.MaxDesiredSlotWidth"))
          
    • 변경 후: .MinDesiredWidth(FWeaponStyle::Get()->DesiredWidth.X)
                   .MaxDesiredWidth(FWeaponStyle::Get()->DesiredWidth.Y)

 

 


 

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;
TSharedPtr<struct FSlateImageBrush> Array_Image;
public:
const FVector2D DesiredWidth = FVector2D(250, 1000);
};

변수 추가

  • TSharedPtr<struct FSlateImageBrush> Array_Image;

 

 

 

WeaponStyle.cpp

더보기
#include "WeaponStyle.h"
#include "Styling/SlateStyle.h"
#include "Styling/SlateStyleRegistry.h"
const FName FWeaponStyle::StyleSetName = "WeaponStyle";
TSharedPtr<FWeaponStyle> FWeaponStyle::Instance = nullptr;
TSharedRef<FWeaponStyle> FWeaponStyle::Get()
{
if (Instance == nullptr)
Instance = MakeShareable(new FWeaponStyle());
return Instance.ToSharedRef();
}
void FWeaponStyle::Shutdown()
{
if (Instance.IsValid())
Instance.Reset();
}
FWeaponStyle::FWeaponStyle()
{
StyleSet = MakeShareable(new FSlateStyleSet(StyleSetName));
FString path = "";
path = FPaths::ProjectPluginsDir() / "Weapon" / "Resources";
RegisterIcon("ToolBar_Icon", path / "weapon_thumnail_icon.png", FVector2D(40, 40), ToolBar_Icon);
FSlateStyleRegistry::RegisterSlateStyle(*StyleSet.Get());
path = FPaths::EngineConfigDir() / "Editor" / "Slate" / "Common/Selection.png";//Engine이 설치된 Config 경로에 있는 해당 png 이미지의 파일 경로
Array_Image = MakeShareable(new FSlateImageBrush(path, FVector2D(8, 8), FLinearColor(1, 1, 1, 0.1f)));//path 경로의 이미지를 (8, 8)사이즈로 해당 색과 alpha값으로 생성한다.
}
FWeaponStyle::~FWeaponStyle()
{
if (Array_Image.IsValid())
Array_Image.Reset();
if (StyleSet.IsValid() == false) return;
FSlateStyleRegistry::UnRegisterSlateStyle(StyleSetName);
StyleSet.Reset();
}
void FWeaponStyle::RegisterIcon(const FString& InName, const FString& InPath, const FVector2D& InIconSize, FSlateIcon& OutSlateIcon)
{
FSlateImageBrush* brush = new FSlateImageBrush(InPath, InIconSize);
FString name = StyleSetName.ToString() + "." + InName;
StyleSet->Set(FName(name), brush);
OutSlateIcon = FSlateIcon(FName(StyleSetName), FName(name));
}

함수 내용 추가

  • FWeaponStyle::FWeaponStyle()
    •  path = FPaths::EngineConfigDir() / "Editor" / "Slate" / "Common/Selection.png";
      • Engine이 설치된 Config 경로를 적어준다.
      • 아래의 이미지가 경로에 있는 이미지. 
    • Array_Image = MakeShareable(new FSlateImageBrush(path, FVector2D(8, 8), FLinearColor(1, 1, 1, 0.1f)));
      • 이미지를 생성하여 넣어준다.
      • path는 가져오는 이미지 경로.
      • Opacity를 떨어뜨리기 위해 (1, 1, 1, 0.1f)로 alpha값을 10%로 설정해준다.

 

 

※ 참고) Engine\UE4.26\Engine\Content\Editor\Slate\Common 내의 아이콘 이미지 파일들


 

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);//디폴트 파라미터로 기본값을 false로 설정.
//해당 Properties를 그릴지 말지 결정
void DrawProperties(TSharedRef<IPropertyHandle> InPropertyHandle, IDetailChildrenBuilder* InChildrenBuilder);
//객체를 외부에서 받기위해,
void SetUtilities(TSharedPtr<class IPropertyUtilities> InUtilities);
private:
//체크가 완료되었는지
void OnCheckStateChanged(ECheckBoxState InState, int32 InIndex);
public:
static bool CanDraw(TSharedPtr<IPropertyHandle> InHandle, int InCount);//사용자가 체크한 InHandle이 들어와서 배열이 개수와 일치하는지 판단. 배열 범위를 벗어나면 그리지 않도록 false를 리턴.
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;//멤버 변수
};

변수 추가

  • TSharedRef<SWidget> Draw(bool bBackground = false);
    • 디폴트 파라미터로 기본값을 false로 설정.

 

static 함수 추가

  • static bool CanDraw(TSharedPtr<IPropertyHandle> InHandle, int InCount);
    • 사용자가 체크한 InHandle이 들어와서 배열이 개수와 일치하는지 판단. 배열 범위를 벗어나면 그리지 않도록 false를 리턴.

 

 

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의 이름들 출력
]
];
}
if(bBackground == false)
return panel.ToSharedRef();//추가를 하게되면, 추가된 그자체를 return
TSharedPtr<SBorder> border = SNew(SBorder)//한 줄 생성.
.BorderImage(FWeaponStyle::Get()->Array_Image.Get())
[
panel.ToSharedRef()//panel를 컨텐츠 영역으로 넣어준다.
];
return border.ToSharedRef();//border를 리턴.
}
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();
}
bool SWeaponCheckBoxes::CanDraw(TSharedPtr<IPropertyHandle> InHandle, int InCount)
{
bool bCheck = true;
bCheck &= InCount > 0;//배열의 개수 InCount가 0보다 큰지
int32 index = InHandle->GetIndexInArray();//InHandle에서 배열 인덱스번호를 가져온다.
bCheck &= index >= 0;
bCheck &= index < InCount;//인덱스가 InCount 배열의 개수보다 작은지//크면 범위를 벗어나서 그릴 수 없다.
return bCheck;
}
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;
}

함수 정의

  • TSharedRef<SWidget> SWeaponCheckBoxes::Draw(bool bBackground)
  • bool SWeaponCheckBoxes::CanDraw(TSharedPtr<IPropertyHandle> InHandle, int InCount)

 

 


 

 

실행화면

 

 

 


 

 

 

 

Source 파일 수정

 

 


 

WeaponAsset

 

WeaponAsset.h

더보기
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "Weapons/CWeaponStructures.h"
#include "CWeaponAsset.generated.h"
UCLASS()
class U2212_06_API UCWeaponAsset : public UDataAsset
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere)
TSubclassOf<class ACAttachment> AttachmentClass;
UPROPERTY(EditAnywhere)
FEquipmentData EquipmentData;
UPROPERTY(EditAnywhere)
TSubclassOf<class UCEquipment> EquipmentClass;
UPROPERTY(EditAnywhere)
TSubclassOf<class UCDoAction> DoActionClass;
UPROPERTY(EditAnywhere)
TArray<FDoActionData> DoActionDatas; //CWeaopnStructure내의 FDoActionData
UPROPERTY(EditAnywhere)
TArray<FHitData> HitDatas; //CWeaopnStructure내의 FHitData
public:
FORCEINLINE class ACAttachment* GetAttachment() { return Attachment; }//외부에 생성된 것을 리턴해줌.
FORCEINLINE class UCEquipment* GetEquipment() { return Equipment; }//외부에 생성된 것을 리턴해줌.
FORCEINLINE class UCDoAction* GetDoAction() { return DoAction; }//외부에 생성된 것을 리턴해줌.
public:
UCWeaponAsset();
void BeginPlay(class ACharacter* InOwner);
private:
//UPROPERTY를 붙여 가비지 콜렉터가 제거하기 전까지 물고 있게 만든다.
//UWeaponAsset은 UObject로부터 상속받아 Actor의 생성주기에 영향을 받지 않아 가비지 콜렉터에 영향을 받는다.
UPROPERTY()
class ACAttachment* Attachment;
UPROPERTY()
class UCEquipment* Equipment;
UPROPERTY()
class UCDoAction* DoAction;
#if WITH_EDITOR //Editor 내에서만 수행
void PostEditChangeChainProperty(struct FPropertyChangedChainEvent& PropertyChangedEvent) override;
#endif
};

함수 추가

  • void PostEditChangeChainProperty(struct FPropertyChangedChainEvent& PropertyChangedEvent) override;
    • UObject의 함수 오버라이드

 

※참고) Object.h의 void PostEditChangeProperty() 함수

  • property가 밖에서 바뀐 이후에 콜 된다.

 

 

 

WeaponAsset.cpp

더보기
#include "Weapons/CWeaponAsset.h"
#include "Global.h"
#include "CAttachment.h"
#include "CEquipment.h"
#include "CDoAction.h"
#include "GameFramework/Character.h"
UCWeaponAsset::UCWeaponAsset()
{
AttachmentClass = ACAttachment::StaticClass();//기본값
EquipmentClass = UCEquipment::StaticClass();//기본값
DoActionClass = UCDoAction::StaticClass();//기본값
}
void UCWeaponAsset::BeginPlay(ACharacter* InOwner)
{
if (!!AttachmentClass)//AttachmentClass가 선택되어 있다면
{
FActorSpawnParameters params;
params.Owner = InOwner;
Attachment = InOwner->GetWorld()->SpawnActor<ACAttachment>(AttachmentClass, params);
}
if (!!EquipmentClass)//EquipmentClass가 선택되어 있다면
{
Equipment = NewObject<UCEquipment>(this, EquipmentClass);
Equipment->BeginPlay(InOwner, EquipmentData);
if (!!Attachment)//Attachment가 있다면
{
Equipment->OnEquipmentBeginEquip.AddDynamic(Attachment, &ACAttachment::OnBeginEquip);
Equipment->OnEquipmentUnequip.AddDynamic(Attachment, &ACAttachment::OnUnequip);
}
}
if(!!DoActionClass)
{
DoAction = NewObject<UCDoAction>(this, DoActionClass);
DoAction->BeginPlay(Attachment, Equipment, InOwner, DoActionDatas, HitDatas);
if (!!Attachment)
{
Attachment->OnAttachmentBeginCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginCollision);
Attachment->OnAttachmentEndCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndCollision);
Attachment->OnAttachmentBeginOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginOverlap);
Attachment->OnAttachmentEndOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndOverlap);
}
}
}
#if WITH_EDITOR //Editor 내에서만 수행
void UCWeaponAsset::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)
{
Super::PostEditChangeChainProperty(PropertyChangedEvent);
CLog::Log(PropertyChangedEvent.GetPropertyName().ToString());//어떤 변수가 바뀌었는지
CLog::Log((int32)PropertyChangedEvent.ChangeType);//어떤 명령에 의해 바뀌었는지
}
#endif

함수 정의

  • void UCWeaponAsset::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)

 

 


 

__VTableCtorCaller

 

Editor에서 Hot Reloading이 일어나면 __VTableCtorCaller이 콜 된다.

UObject에 있는 함수다.

 

 


 

CDO

 

Hot Reload는 CDO를 다시 읽어주는 역할을 수행한다.