오늘은 구축한 프리셋 데이터 구조를 바탕으로 실제 UI에서 프리셋 전환이 동작하도록 구현했음
핵심적으로는 프리셋 버튼 클릭 시 저장확인 팝업 표시, 세이브 파일 호환성 문제 해결, 그리고 최근 사용 프리셋 자동 로드 기능을 완성했음
특히 기존 LoadBoardConfig() 함수가 너무 많은 책임을 가지고 있어서 발생했던 버그들을 함수 분리를 통해 근본적으로 해결했음
기존 문제점
해결책: 팝업 기반 확인 시스템
// GS_ArcaneBoardWidget.h에 추가
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ArcaneBoard")
TSubclassOf<class UGS_CommonTwoBtnPopup> PresetSaveConfirmPopupClass;
UPROPERTY()
int32 PendingPresetIndex; // 사용자가 선택한 대기 중인 프리셋
// 프리셋 버튼 함수들 수정
void UGS_ArcaneBoardWidget::OnPresetButton1Clicked()
{
if (HasUnsavedChanges())
{
ShowPresetSaveConfirmPopup(1); // 저장확인 팝업 표시
}
else
{
SwitchToPreset(1); // 바로 전환
}
}
팝업 응답 처리
void UGS_ArcaneBoardWidget::OnPresetSaveYes()
{
// 현재 프리셋에 저장 후 새 프리셋으로 전환
ArcaneBoardLPS->ApplyBoardChanges();
SwitchToPreset(PendingPresetIndex);
}
void UGS_ArcaneBoardWidget::OnPresetSaveNo()
{
// 저장하지 않고 바로 전환
SwitchToPreset(PendingPresetIndex);
}
발생한 문제
LogClass: Warning: Struct Property SavedRunesByClass has a struct type mismatch
(tag RunePlacementData(/Script/GAS) != prop ArcaneBoardPresets(/Script/GAS))
기존 RunePlacementData 구조체로 저장된 파일과 새로운 FArcaneBoardPresets 구조체 간의 타입 불일치
임시 해결: 기존 세이브 파일 삭제
새로운 문제 발견: 기본 룬 없음
세이브 파일 삭제 후 테스트용 룬이 없어서 기능 테스트 불가
기본 룬 시스템 도입
void UGS_ArcaneBoardLPS::InitializeDefaultRunes()
{
OwnedRuneIDs.Empty();
// 모든 플레이어가 기본 룬 2개로 시작
OwnedRuneIDs.Add(1);
OwnedRuneIDs.Add(2);
UE_LOG(LogTemp, Log, TEXT("기본 룬 초기화 완료: 룬 ID 1, 2"));
}
기존 함수의 문제점
함수 분리를 통한 해결
// 1. 룬 인벤토리 초기화만 담당
void EnsureRuneInvenInit()
{
if (OwnedRuneIDs.Num() > 0) return; // 이미 초기화됨
// 세이브 파일에서 룬 데이터만 로드 시도
// 실패 시 기본 룬으로 초기화
}
// 2. 프리셋 데이터 로드만 담당
TArray<FPlacedRuneInfo> LoadPresetData(ECharacterClass CharClass, int32 PresetIndex)
{
// 모든 예외 상황에서 빈 배열 반환
// 크래시 방지를 위한 안전한 설계
}
// 3. 보드에 데이터 적용만 담당
void ApplyPresetToBoard(ECharacterClass CharClass, const TArray<FPlacedRuneInfo>& PresetData)
{
BoardManager->LoadSavedData(CharClass, PresetData);
BoardManager->bHasUnsavedChanges = false;
}
// 4. 전체 흐름 조율 (단순화된 메인 함수)
void LoadBoardConfig(int32 PresetIndex)
{
EnsureRuneInvenInit(); // 1단계
TargetPresetIndex = DeterminePresetIndex(); // 2단계
PresetData = LoadPresetData(); // 3단계
ApplyPresetToBoard(PresetData); // 4단계
}
단일 책임 원칙(SRP) 적용 효과
기존 문제
아케인보드 창을 열면 항상 프리셋 1이 로드됨. 사용자가 프리셋 2에서 작업했어도 다음에 다시 프리셋 1부터 시작해야 함
GetLastUsedPresetIndex 함수 구현
int32 UGS_ArcaneBoardLPS::GetLastUsedPresetIndex()
{
// 세이브 파일에서 LastUsedPresetIndex 값 읽기
const FArcaneBoardPresets& ClassPresets = LoadedSaveGame->SavedRunesByClass[CurrClass];
int32 LastUsedIndex = ClassPresets.LastUsedPresetIndex;
if (LastUsedIndex >= 1 && LastUsedIndex <= 3)
{
return LastUsedIndex;
}
else
{
return 1; // 기본값
}
}
LoadBoardConfig에서 최근 프리셋 우선 로드
void UGS_ArcaneBoardLPS::LoadBoardConfig(int32 PresetIndex)
{
int32 TargetPresetIndex;
if (PresetIndex == -1)
{
// 최근 사용 프리셋 로드
TargetPresetIndex = GetLastUsedPresetIndex();
}
else
{
// 지정된 프리셋 로드
TargetPresetIndex = PresetIndex;
}
// ...
}
Apply 시 최근 사용 프리셋 업데이트
void UGS_ArcaneBoardLPS::ApplyBoardChanges()
{
BoardManager->ApplyChanges();
// 현재 프리셋에 저장하면서 최근 사용 프리셋으로 기록
SaveBoardConfig(CurrentPresetIndex);
UE_LOG(LogTemp, Log, TEXT("변경사항을 프리셋 %d에 적용"), CurrentPresetIndex);
}