ProjectM/Source/ProjectT/System/Core/Characters/CombatCharacter.cpp

259 lines
9.1 KiB
C++

#include "CombatCharacter.h"
#include "Components/CapsuleComponent.h"
#include "ProjectT/ProjectT.h"
#include "ProjectT/Data/Gen/GenerateEnumContentType.h"
#include "ProjectT/Data/Gen/GenerateEnumDataTableKey.h"
#include "ProjectT/Data/Gen/GenerateStructCharacterMeshSet.h"
#include "ProjectT/Data/Gen/GenerateStructEnemyNPC.h"
#include "ProjectT/Data/Gen/GenerateStructMeshList.h"
#include "ProjectT/Data/Gen/GenerateStructPlayerCharacter.h"
#include "ProjectT/Data/Gen/GenerateStructSocketList.h"
#include "ProjectT/System/Core/Common/AssetUtilsLibrary.h"
#include "ProjectT/System/Core/Common/GlobalUtilsLibrary.h"
class CharacterDataLoader
{
public:
static void From(const FName& RowName, FName& OutMeshRowName, FCharacterMeshSet& OutMeshList, const FTableRowBase*& OutContentData)
{
FName FoundMeshRowName;
EContentType NewContentType = UGlobalUtilsLibrary::GetContentTypeFromIndex(RowName);
UDataTable* DataTable = nullptr;
switch(NewContentType)
{
case EContentType::PlayerCharacter:
{
DataTable = UAssetUtilsLibrary::LoadDataTableByEnumKey(EDataTableKey::PlayerCharacter);
FPlayerCharacter* CharacterDataRow = DataTable->FindRow<FPlayerCharacter>(RowName, TEXT("Not Found FPlayerCharacter"));
if(!NMT_ENSURE(CharacterDataRow)) return;
FoundMeshRowName = FROM_INT(CharacterDataRow->iCharMeshSetId);
OutContentData = CharacterDataRow;
break;
}
case EContentType::EnemyNpc:
{
DataTable = UAssetUtilsLibrary::LoadDataTableByEnumKey(EDataTableKey::EnemyNpc);
FEnemyNpc* CharacterDataRow = DataTable->FindRow<FEnemyNpc>(RowName, TEXT("Not Found FEnemyNPC"));
if(!NMT_ENSURE(CharacterDataRow)) return;
FoundMeshRowName = FROM_INT(CharacterDataRow->iNpcMeshSetId);
OutContentData = CharacterDataRow;
break;
}
default: return;
}
DataTable = UAssetUtilsLibrary::LoadDataTableByEnumKey(EDataTableKey::CharacterMeshSet);
if(FCharacterMeshSet* RowData = DataTable->FindRow<FCharacterMeshSet>(FoundMeshRowName, TEXT("FCharacterMeshSet")))
{
OutMeshList = *RowData;
OutMeshRowName = FoundMeshRowName;
}
}
};
ACombatCharacter::ACombatCharacter() :
AccessoryMeshComponent(nullptr),
WeaponStaticComponent(nullptr),
WeaponDynamicComponent(nullptr),
DefaultBodyMesh(nullptr)
{
GetCapsuleComponent()->SetCapsuleHalfHeight(50.0f);
GetCapsuleComponent()->SetCapsuleRadius(20.0f);
GetMesh()->SetRelativeLocation(FVector(0.0f, 0.0f, -52.0f));
AccessoryMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("AccessoryMeshComponent"));
WeaponStaticComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("WeaponStaticComponent"));
WeaponDynamicComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("WeaponDynamicComponent"));
NMT_CHECKF(AccessoryMeshComponent && WeaponStaticComponent && WeaponDynamicComponent);
UGlobalUtilsLibrary::EnableComponent(AccessoryMeshComponent, false);
UGlobalUtilsLibrary::EnableComponent(WeaponStaticComponent, false);
UGlobalUtilsLibrary::EnableComponent(WeaponDynamicComponent, false);
}
void ACombatCharacter::PostLoad()
{
Super::PostLoad();
}
void ACombatCharacter::OnConstruction(const FTransform& Transform)
{
Super::OnConstruction(Transform);
#if WITH_EDITOR
const FString LabelRowName = *GetActorLabel();
if(LabelRowName.IsNumeric()) ApplyCharacterConfiguration(*LabelRowName);
#endif
}
EContentType ACombatCharacter::GetContentType_Implementation()
{
return IContentType::GetContentType_Implementation();
}
FString ACombatCharacter::GetContentTypeNumber_Implementation()
{
return IContentType::GetContentTypeNumber_Implementation();
}
void ACombatCharacter::BeginPlay()
{
Super::BeginPlay();
#if WITH_EDITOR
const FString LabelRowName = *GetActorLabel();
if(LabelRowName.IsNumeric()) ApplyCharacterConfiguration(*LabelRowName);
else if(!CharacterRowName.IsNone() && CharacterRowName.ToString().IsNumeric()) ApplyCharacterConfiguration(CharacterRowName);
#endif
GetCapsuleComponent()->OnClicked.AddUniqueDynamic(this, &ACombatCharacter::ExecuteClickedEvent);
GetCapsuleComponent()->OnBeginCursorOver.AddUniqueDynamic(this, &ACombatCharacter::ExecuteBeginCursorOverEvent);
GetCapsuleComponent()->OnEndCursorOver.AddUniqueDynamic(this, &ACombatCharacter::ExecuteEndCursorOverEvent);
}
#if WITH_EDITOR
void ACombatCharacter::ApplyCharacterConfiguration(const FName& RowName)
{
if(RowName.IsNone())
{
RestoreCharacterSet();
RestoreCharacterData();
return;
}
const EContentType NewContentType = UGlobalUtilsLibrary::GetContentTypeFromIndex(RowName);
if(EContentType::PlayerCharacter != NewContentType && EContentType::EnemyNpc != NewContentType)
{
RestoreCharacterSet();
RestoreCharacterData();
return;
}
FName MeshSetRowName;
FCharacterMeshSet NewMeshSet;
const FTableRowBase* CharacterData = nullptr;
CharacterDataLoader::From(RowName, MeshSetRowName, NewMeshSet, CharacterData);
if(MeshSetRowName.IsNone())
{
RestoreCharacterSet();
return;
}
if(ApplyCharacterSet(MeshSetRowName))
{
CurrentMeshSet = NewMeshSet;
CharacterRowName = RowName;
}
else RestoreCharacterSet();
if(CharacterData) ApplyCharacterData(CharacterData);
}
bool ACombatCharacter::ApplyCharacterSet(const FName& RowName)
{
UDataTable* CMSTable = UAssetUtilsLibrary::LoadDataTableByEnumKey(EDataTableKey::CharacterMeshSet);
FCharacterMeshSet* CMSData = CMSTable->FindRow<FCharacterMeshSet>(RowName, TEXT("FCharacterMeshSet"));
if(!CMSData) return false;
UDataTable* MLSTable = UAssetUtilsLibrary::LoadDataTableByEnumKey(EDataTableKey::MeshList);
FMeshList* BodyData = MLSTable->FindRow<FMeshList>(FROM_INT(CMSData->iBodyMeshId), TEXT("FMeshList"));
if(!BodyData) return false;
USkeletalMesh* BodyMesh = UAssetUtilsLibrary::GetSkeletalMeshFromPath(BodyData->sMeshPath);
if(!BodyMesh) return false;
GetMesh()->SetSkeletalMesh(BodyMesh);
FMeshList* WeaponData = nullptr;
if(CMSData->iWeaponMeshId != 0) WeaponData = MLSTable->FindRow<FMeshList>(FROM_INT(CMSData->iWeaponMeshId), TEXT("FMeshList"));
/**
* NOTE: Weapon Data는 항상 유효성을 보장하지 않음
*/
if(!WeaponData) return true;
if(!CHECK_FREE(WeaponData->sMeshPath))
{
UMeshComponent* WeaponComponent = nullptr;
FString ScriptType = UGlobalUtilsLibrary::GetScriptTypeByRefPath(WeaponData->sMeshPath);
if(ScriptType.Equals(TEXT("StaticMesh")))
{
UStaticMesh* WeaponMesh = UAssetUtilsLibrary::GetStaticMeshFromPath(WeaponData->sMeshPath);
WeaponStaticComponent->SetStaticMesh(WeaponMesh);
UGlobalUtilsLibrary::EnableComponent(WeaponStaticComponent, true);
WeaponComponent = WeaponStaticComponent;
}
else if(ScriptType.Equals(TEXT("SkeletalMesh")))
{
USkeletalMesh* WeaponMesh = UAssetUtilsLibrary::GetSkeletalMeshFromPath(WeaponData->sMeshPath);
WeaponDynamicComponent->SetSkeletalMesh(WeaponMesh);
UGlobalUtilsLibrary::EnableComponent(WeaponDynamicComponent, true);
WeaponComponent = WeaponDynamicComponent;
}
else NMT_MSG_CHECKF(0, "%s: type is not supported", *WeaponData->sMeshPath);
CMSData->iWeaponSocketId;
UDataTable* SocketTable = UAssetUtilsLibrary::LoadDataTableByEnumKey(EDataTableKey::SocketList);
FSocketList* SocketData = SocketTable->FindRow<FSocketList>(FROM_INT(CMSData->iWeaponSocketId), TEXT("FSocketList"));
if(CHECK_FREE(SocketData->sSocketName))
{
NMT_MSG_ENSURE(0, "Socket Name Is FREE [%s][%s]", FROM_INT(CMSData->iWeaponSocketId), *SocketData->sSocketName);
return true;
}
WeaponComponent->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, *SocketData->sSocketName);
}
return true;
}
void ACombatCharacter::ApplyCharacterData(const FTableRowBase* RowData)
{
NMT_MSG_ENSURE(0, "Function should be overridden in the child class.");
}
void ACombatCharacter::RestoreCharacterData()
{
ApplyCharacterData(nullptr);
}
void ACombatCharacter::RestoreCharacterSet()
{
AccessoryMeshComponent->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
UGlobalUtilsLibrary::EnableComponent(AccessoryMeshComponent, false);
WeaponStaticComponent->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
UGlobalUtilsLibrary::EnableComponent(WeaponStaticComponent, false);
WeaponDynamicComponent->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
UGlobalUtilsLibrary::EnableComponent(WeaponDynamicComponent, false);
FString LocDefaultSKMeshPath = "/Script/Engine.SkeletalMesh'/Game/Characters/Pyro/Assets/SK_Pyro_Invalid.SK_Pyro_Invalid'";
DefaultBodyMesh = UAssetUtilsLibrary::GetSkeletalMeshFromPath(LocDefaultSKMeshPath);
if(DefaultBodyMesh != nullptr)
{
GetMesh()->SetSkeletalMesh(DefaultBodyMesh);
}
CurrentMeshSet = FCharacterMeshSet();
CharacterRowName = TEXT("None");
}
#endif
void ACombatCharacter::Respawn()
{
NOT_IMPLEMENTED();
}
void ACombatCharacter::ExecuteClickedEvent(UPrimitiveComponent* InTouchedComponent, FKey InButtonPressed)
{
Super::ExecuteClickedEvent(InTouchedComponent, InButtonPressed);
}
void ACombatCharacter::ExecuteBeginCursorOverEvent(UPrimitiveComponent* InTouchedComponent)
{
Super::ExecuteBeginCursorOverEvent(InTouchedComponent);
}
void ACombatCharacter::ExecuteEndCursorOverEvent(UPrimitiveComponent* InTouchedComponent)
{
Super::ExecuteEndCursorOverEvent(InTouchedComponent);
}