언리얼 엔진은 패키지(UPackage)단위로 언리얼 오브젝트를 관리

// MyGameInstance.h
UCLASS()
class UNREALSERIALIZATION_API UMyGameInstance : public UGameInstance
{
/* 직전 포스트의 코드에서 계속 */
...
void SaveStudentPackage() const;
static const FString PackageName;
static const FString AssetName;
};
// MyGameInstance.cpp
#include "UObject/SavePackage.h"
const FString UMyGameInstance::PackageName = TEXT("/Game/Student");
const FString UMyGameInstance::AssetName = TEXT("TopStudent");
void SaveStudentPackage() const
{
UPackage* StudentPackage = CreatePackage(*PackageName);
EObjectFlags ObjectFlag = RF_Public|RF_Standalone; // 패키지 저장 옵션
// StudentPackage에 저장되도록 설정
UStudent* TopStudent = NewObject<UStudent>(StudentPackage, UStudent::StaticClass(), *AssetName, ObjectFlag);
TopStudent->SetName(TEXT("이득우"));
TopStudent->SetOrder(36);
// 서브 오브젝트 생성
const int32 NumofSubs = 10;
for (int32 ix = 1; ix <= NumofSubs; ++ix)
{
// TopStudent에 들어가도록 설정
FString SubObjectName = FString::Printf(Text("Student%d"), ix);
UStudent* SubStudent = NewObject<UStudent>(TopStudent, UStudent::StaticClass(), *SubObjectName, ObjectFlag);
SubStudent->SetName(FString::Printf(TEXT("학생%d"), ix));
SubStudent->SetOrder(ix);
}
const FString PackageFileName = FPackageName::LongPackageNameToFilename(PackageName, FPackageName::GetAssetPackageExtension());
FSavePackageArgs SaveArgs; // 저장 옵션
SaveArgs.TopLevelFlags = ObjectFlag;
// 패키지 저장
if (UPackage::SavePackage(StudentPackage, nullptr, *PackageFileName, SaveArgs))
{
UE_LOG(LogTemp, Log, TEXT("패키지가 성공적으로 저장되었습니다."));
// Content 폴더에 TopStudent 패키지가 저장됨
}
}

// MyGameInstance.h
UCLASS()
class UNREALSERIALIZATION_API UMyGameInstance : public UGameInstance
{
...
void LoadStudentPackage() const;
};
// MyGameInstance.cpp
void UMyGameInstance::LoadStudentPackage() const
{
// 패키지 정보는 없음, 패키지 이름과 기본 옵션으로 로딩
UPackage* StudentPackage = ::LoadPackage(nullptr, *PackageName, LOAD_NONE);
if (StudentPackage == nullptr)
{
UE_LOG(LogTemp, Warning, TEXT("패키지를 찾을 수 없습니다."));
return;
}
StudentPackage->FullyLoad(); // 찾은 패키지의 모든 애셋을 로딩
// StudentPackage에서 TopStudent 이름의 애셋 찾기
UStudent* TopStudent = FindObject<UStudent>(StudentPackage, *AssetName);
PrintStudentInfo(TopStudent, TEXT("FindObject Asset")); // 이득우 36
}
void UMyGameInstance::SaveStudentPackage() const
{
// 패키지 저장 전 이미 패키지가 있다면 먼저 로드하는게 안전
UPackage* StudentPackage = ::LoadPackage(nullptr, *PackageName, LOAD_NONE);
if (StudentPackage)
{
// 만약 있다면 모두 로딩
StudentPackage->FullyLoad();
}
/* 이후 패키지 저장에서 작성한 코드 */
...
}
{애셋클래스정보}'{패키지이름}.{애셋이름}'
애셋 클래스 정보는 생략 가능
{패키지이름}.{애셋이름}
// MyGameInstance.h
UCLASS()
class UNREALSERIALIZATION_API UMyGameInstance : public UGameInstance
{
...
void LoadStudentObject() const;
};
// MyGameInstance.cpp
void UMyGameInstance::LoadStudentObject() cons
{
const FString TopSoftObjectPath = FString::Printf(TEXT("%s.%s"), *PackageName, *AssetName);
// 패키지를 로딩하지 않기에 nullptr을 넣어줌
UStudent* TopStudent = LoadObject<UStudent>(nullptr, *TopSoftObjectPath);
PrintStudentInfo(TopStudent, TEXT("LoadObject Asset")); // 이득우 36
}
UMyGameInstance::UMyGameInstance()
{
const FString TopSoftObjectPath = FString::Printf(TEXT("%s.%s"), *PackageName, *AssetName);
static ConstructorHelpers::FObjectFinder<UStudent> UASSET_TopStudent(*TopSoftObjectPath);
if (UASSET_TopStudent.Succeeded())
{
PrintStudentInfo(UASSET_TopStudent.Object, TEXT("Constructor")); // 이득우 36
}
}
// MyGameInstance.h
#include "Engine/StreamableManager.h"
UCLASS()
class UNREALSERIALIZATION_API UMyGameInstance : public UGameInstance
{
...
FStreamableManager StreamableManager;
TSharedPtr<FStreamableHandle> Handle; // 스트리밍된 애셋을 관리할 핸들
};
// MyGameInstance.cpp
UMyGameInstance::Init()
{
...
const FString TopSoftObjectPath = FString::Printf(TEXT("%s.%s"), *PackageName, *AssetName);
Handle = StreamableManager.RequestAsyncLoad(TopSoftObjectPath,
[&]()
{
if (Handle.IsValid() && Handle->HasLoadCompleted())
{
// 핸들을 통해 애셋 로딩
UStudent* TopStudent = Cast<UStudent>(Handle->GetLoadedAsset());
if (TopStudent)
{
PrintStudentInfo(TopStudent, TEXT("AsyncLoad")); // 이득우 36
// 다 쓴 핸들 닫아줌
Handle->ReleaseHandle();
Handle.Reset();
}
}
}
);
}