Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions Source/P_RD/Actor/BoardActor/Obstacle/Gimmick/GimmickModel.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*****************************************************************//**
/*****************************************************************//**
* @file GimmickModel.cpp
* @brief 기믹 공통 모델 구현 파일
* @author 이문환
Expand Down Expand Up @@ -58,16 +58,15 @@ bool UGimmickModel::TryTriggerGimmick(const FTileIndex& AimedTileIndex, TSharedP
--mRemainingTriggerCount;
}

USRPGCombatModel* CombatModel = GetWorldSubsystemModel<USRPGCombatModel>(this);
checkf(CombatModel != nullptr, TEXT("전투 모델 nullptr"));
TSharedPtr<FPresentationBarrier> EndHoldBarrier = CombatModel->GetCurrentActionEndHoldBarrier();

// 장착된 스킬 강제 시전 (기믹은 행동력 개념이 없으므로 소모 검사 없이 시전)
FOnEndSkillUI EndCallback;
EndCallback.AddUObject(this, &UGimmickModel::OnGimmickSkillEnd);

// 배리어를 받았으면, 배리어 포인터를 캡처한 빈 람다를 종료 콜백에 추가
// 스킬이 끝나면 콜백이 정리되고, 람다가 사라지면서 캡처된 포인터도 함께 해제됨
if (PresentationBarrier.IsValid() == true)
{
EndCallback.AddLambda([PresentationBarrier](const FActiveSkillContext&, const UStaticSkillData*) {});
}
EndCallback.AddWeakLambda(this, [this, PresentationBarrier, EndHoldBarrier](const FActiveSkillContext& Context, const UStaticSkillData* SkillData) {
OnGimmickSkillEnd(Context, SkillData);
});

SkillComp->ForcedActivateSkill(GetTileMap(), mTriggerSkillIndex, AimedTileIndex, EndCallback);
return true;
Expand Down
10 changes: 10 additions & 0 deletions Source/P_RD/ObjectModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,13 @@ int32 UObjectModel::GetModelId() const
{
return mModelId;
}

bool UObjectModel::IsInitialized() const
{
return mIsInitialized;
}

bool UObjectModel::IsPendingDestroy() const
{
return mIsPendingDestroy;
}
3 changes: 3 additions & 0 deletions Source/P_RD/ObjectModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class P_RD_API UObjectModel : public UObject
IObjectView* GetView() const;
int32 GetModelId() const;

bool IsInitialized() const;
bool IsPendingDestroy() const;

protected:
TWeakObjectPtr<UObject> mView;

Expand Down
74 changes: 54 additions & 20 deletions Source/P_RD/SRPGFramework/SRPGAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,31 +73,50 @@ void USRPGAction::EndAction()

UE_LOG(LogSRPGCombat, Log, TEXT("액션 종료: %s"), *GetClass()->GetName());

// 액션 종료 로직
OnEndAction();
mEndHoldPresentationBarrier = FPresentationBarrier::Make(FOnFinishPresentation::CreateWeakLambda(this, [this]() {
// 액션 종료 로직
OnEndAction();

// 로그 작성
GetWorldEventLogger(this)->EndActionLog();

// 핸들러 등록 해제
USRPGCommandRouterModel* CommandRouterModel = GetWorldSubsystemModel<USRPGCommandRouterModel>(this);
checkf(CommandRouterModel != nullptr, TEXT("명령 라우터 모델 nullptr"));
CommandRouterModel->UnregisterCommandHandler(this);
// 로그 작성
GetWorldEventLogger(this)->EndActionLog();

// 전투 상태 평가
USRPGTurnContext* TurnContext = mParent.Get();
checkf(TurnContext != nullptr, TEXT("턴 객체 nullptr"));
USRPGCombatModel* CombatModel = TurnContext->GetParent();
checkf(CombatModel != nullptr, TEXT("전투 모델 nullptr"));
CombatModel->EvaluateCombatStates();
// 핸들러 등록 해제
USRPGCommandRouterModel* CommandRouterModel = GetWorldSubsystemModel<USRPGCommandRouterModel>(this);
checkf(CommandRouterModel != nullptr, TEXT("명령 라우터 모델 nullptr"));
CommandRouterModel->UnregisterCommandHandler(this);

// 종료 연출 시작
TSharedPtr<FPresentationBarrier> PresentationBarrier = FPresentationBarrier::Make(FOnFinishPresentation::CreateWeakLambda(this, [this]() {
// 전투 상태 평가
USRPGTurnContext* TurnContext = mParent.Get();
checkf(TurnContext != nullptr, TEXT("이미 제거된 턴에서 Action 종료 명령 오류"));
TurnContext->OnEndCurrentAction(this, mActionResult);
checkf(TurnContext != nullptr, TEXT("턴 객체 nullptr"));
USRPGCombatModel* CombatModel = TurnContext->GetParent();
checkf(CombatModel != nullptr, TEXT("전투 모델 nullptr"));
CombatModel->EvaluateCombatStates();

// 종료 연출 시작
TSharedPtr<FPresentationBarrier> PresentationBarrier = FPresentationBarrier::Make(FOnFinishPresentation::CreateWeakLambda(this, [this]() {

USRPGTurnContext* TurnContext = mParent.Get();
checkf(TurnContext != nullptr, TEXT("이미 제거된 턴에서 Action 종료 명령 오류"));
TurnContext->OnEndCurrentAction(this, mActionResult);
}));
OnEndActionUI.Broadcast(PresentationBarrier, this, mActionResult);
}));
OnEndActionUI.Broadcast(PresentationBarrier, this, mActionResult);

DecrementEndHoldCount();
}

void USRPGAction::IncrementEndHoldCount()
{
++mEndHoldCount;
}

void USRPGAction::DecrementEndHoldCount()
{
--mEndHoldCount;
if (mEndHoldCount == 0)
{
mEndHoldPresentationBarrier.Reset();
}
}

void USRPGAction::TryBeginAction()
Expand Down Expand Up @@ -179,6 +198,21 @@ void USRPGAction::ReserveInitializeCommand(TInstancedStruct<FSRPGCommand> Comman
mInitializeCommand = MoveTemp(Command);
}

TSharedPtr<FPresentationBarrier> USRPGAction::GetEndHoldBarrier()
{
if (mEndHoldCount <= 0)
{
return nullptr;
}

IncrementEndHoldCount();
TSharedPtr<FPresentationBarrier> HoldBarrier = FPresentationBarrier::Make(FOnFinishPresentation::CreateWeakLambda(this, [this]() {
DecrementEndHoldCount();
}));

return HoldBarrier;
}

TWeakObjectPtr<USRPGTurnContext> USRPGAction::GetParent() const
{
return mParent;
Expand Down
11 changes: 11 additions & 0 deletions Source/P_RD/SRPGFramework/SRPGAction.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ class USRPGAction : public UObject, public ISRPGCommandHandler
void TickAction(float DeltaTime);
void EndAction();

private:
void IncrementEndHoldCount();
void DecrementEndHoldCount();

protected:
/**
* 액션 상태를 확인하여 조건적으로 실행하는 함수
Expand Down Expand Up @@ -77,6 +81,9 @@ class USRPGAction : public UObject, public ISRPGCommandHandler
void ReserveInitializeCommand(TInstancedStruct<FSRPGCommand> Command);

/* 외부 API */
public:
TSharedPtr<FPresentationBarrier> GetEndHoldBarrier();

public:
TWeakObjectPtr<USRPGTurnContext> GetParent() const;
UUnitModel* GetInstigator() const;
Expand All @@ -87,6 +94,10 @@ class USRPGAction : public UObject, public ISRPGCommandHandler
FOnBeginActionUI OnBeginActionUI;
FOnEndActionUI OnEndActionUI;

protected:
int32 mEndHoldCount = 1;
TSharedPtr<FPresentationBarrier> mEndHoldPresentationBarrier = nullptr;

protected:
UPROPERTY(Category = Parent, VisibleAnywhere, BlueprintReadOnly, meta = (DisplayName = "Parent"))
TWeakObjectPtr<USRPGTurnContext> mParent;
Expand Down
12 changes: 11 additions & 1 deletion Source/P_RD/SRPGFramework/SRPGTurnContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ void USRPGTurnContext::OnHandleCommand(ESRPGCommandResult Result)
{
if (mTurnPhase == ESRPGTurnPhase::TurnPlay && mReservedActions.Num() > mHeadActionIndex)
{
USRPGAction* const CurrentAction = mReservedActions[mHeadActionIndex];
USRPGAction* CurrentAction = mReservedActions[mHeadActionIndex];
CurrentAction->TryBeginAction();

// TryBeginAction의 델리게이트가 새 커맨드를 동기 제출하면 현재 액션이 끝나 head가 이동할 수 있다.
Expand All @@ -398,6 +398,16 @@ void USRPGTurnContext::OnHandleCommand(ESRPGCommandResult Result)
}
}

TSharedPtr<FPresentationBarrier> USRPGTurnContext::GetCurrentActionEndHoldBarrier() const
{
if (mReservedActions.Num() > mHeadActionIndex)
{
USRPGAction* CurrentAction = mReservedActions[mHeadActionIndex];
return CurrentAction->GetEndHoldBarrier();
}
return nullptr;
}

USRPGCombatModel* USRPGTurnContext::GetParent() const
{
return mParent.Get();
Expand Down
3 changes: 3 additions & 0 deletions Source/P_RD/SRPGFramework/SRPGTurnContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ class USRPGTurnContext : public UObject
void OnHandleCommand(ESRPGCommandResult Result);

/* 외부 API */
public:
TSharedPtr<FPresentationBarrier> GetCurrentActionEndHoldBarrier() const;

public:
USRPGCombatModel* GetParent() const;
UUnitModel* GetOwner() const;
Expand Down
38 changes: 34 additions & 4 deletions Source/P_RD/Singleton/WorldSubsystem/SRPGCombatModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,25 @@ void USRPGCombatModel::Serialize(FArchive& Ar)
void USRPGCombatModel::Tick(float DeltaTime)
{
USRPGTurnContext* CurTurnContext = GetCurrentTurnContext();
if (mCombatPhase == ESRPGCombatRoomPhase::CombatPlay && CurTurnContext != nullptr)
if (mCombatPhase != ESRPGCombatRoomPhase::CombatEnd && CurTurnContext != nullptr)
{
CurTurnContext->TickTurn(DeltaTime);
}
}

bool USRPGCombatModel::IsTickable() const
ETickableTickType USRPGCombatModel::GetTickableTickType() const
{
return true;
if (IsTemplate() == true || IsInitialized() == false)
{
return ETickableTickType::Never;
}

return ETickableTickType::Conditional;
}

bool USRPGCombatModel::IsAllowedToTick() const
{
return IsInitialized();
}

TStatId USRPGCombatModel::GetStatId() const
Expand Down Expand Up @@ -710,6 +720,16 @@ bool USRPGCombatModel::UnregisterTurn(UUnitModel* Owner, bool IgnoreCurTurn)
return true;
}

int32 USRPGCombatModel::UnregisterAllTurn(UUnitModel* Owner, bool IncludeCurTurn)
{
int32 UnregisterCount = 0;
while (UnregisterTurn(Owner, IncludeCurTurn) == true)
{
++UnregisterCount;
}
return UnregisterCount;
}

bool USRPGCombatModel::EvaluateRound()
{
// A corrupted or stalled speed configuration must not block the game thread in Shipping.
Expand Down Expand Up @@ -1038,7 +1058,7 @@ void USRPGCombatModel::UnregisterUnitModel(UUnitModel* UnitModel)

/* 턴 제거 */

UnregisterTurn(UnitModel);
UnregisterAllTurn(UnitModel);

/* 제거 */

Expand Down Expand Up @@ -1196,6 +1216,16 @@ void USRPGCombatModel::ForcedBeginTurn()
CurTurnContext->BeginTurn();
}

TSharedPtr<FPresentationBarrier> USRPGCombatModel::GetCurrentActionEndHoldBarrier() const
{
if (HasAnyTurnContext() == true)
{
USRPGTurnContext* CurTurnContext = GetCurrentTurnContext();
return CurTurnContext->GetCurrentActionEndHoldBarrier();
}
return nullptr;
}

bool USRPGCombatModel::HasAnyTurnContext() const
{
return mTurnContextOrders.IsEmpty() == false;
Expand Down
10 changes: 8 additions & 2 deletions Source/P_RD/Singleton/WorldSubsystem/SRPGCombatModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,12 @@ class P_RD_API USRPGCombatModel : public UObjectModel, public FTickableGameObjec
/* UObjectModel 상속 */
public:
void Serialize(FArchive& Ar) override;

/* FTickableGameObject 상속 */
public:
void Tick(float DeltaTime) override;
bool IsTickable() const override;
ETickableTickType GetTickableTickType() const override;
bool IsAllowedToTick() const override final;
TStatId GetStatId() const override;

/* 생명 주기 함수 */
Expand Down Expand Up @@ -186,6 +187,7 @@ class P_RD_API USRPGCombatModel : public UObjectModel, public FTickableGameObjec
*/
bool UnregisterTurn(USRPGTurnContext* TurnContext, bool IgnoreCurTurn = true);
bool UnregisterTurn(UUnitModel* Owner, bool IncludeCurTurn = true);
int32 UnregisterAllTurn(UUnitModel* Owner, bool IncludeCurTurn = true);

protected:
bool EvaluateRound();
Expand Down Expand Up @@ -231,6 +233,10 @@ class P_RD_API USRPGCombatModel : public UObjectModel, public FTickableGameObjec
void ForcedBeginTurn();

/* 외부 API 함수 */
/* 외부 API */
public:
TSharedPtr<FPresentationBarrier> GetCurrentActionEndHoldBarrier() const;

public:
bool HasAnyTurnContext() const;
int32 GetTurnContextCount() const;
Expand Down
2 changes: 2 additions & 0 deletions Source/P_RDTests/Actor/BoardActor/GimmickModelTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -722,5 +722,7 @@ bool FPuddleRoundEndEventTests::RunTest(const FString& Parameters)
TestEqual(TEXT("[Case3] 유닛A 기절 3"), GetStunCount(UnitA), 3);
TestEqual(TEXT("[Case3] 장판C 수명 2 -> 1"), PuddleC->GetRemainingRoundCount(), 1);

CombatModel->Destroy();

return true;
}
6 changes: 5 additions & 1 deletion Source/P_RDTests/Singleton/RunCheckpointTests.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "P_RDTests.h"
#include "P_RDTests.h"
#include "Misc/AutomationTest.h"
#include "Singleton/RunCheckpointTestsHelper.h"
#include "SaveGame/SaveCheckpoint.h"
Expand Down Expand Up @@ -198,6 +198,10 @@ bool FCheckpointStalledRoundGuardTest::RunTest(const FString& Parameters)
AddExpectedError(TEXT("Combat speed cannot produce a turn"), EAutomationExpectedErrorFlags::Contains, 1);
TestFalse(TEXT("Empty combat returns instead of spinning in Shipping"), Model->EvaluateEmptyRound());
TestEqual(TEXT("Blocked combat reports once"), BlockedCount, 1);

Model->Destroy();
Preview->Destroy();

return true;
}

Expand Down
Loading