| Streamable Managers | 스트리밍을 관리하는 네이티브 구조체 |
|---|---|
| Primary Assets | 게임의 상태에 따라 직접 로드 및 언로드하는 주요 에셋 |
| Secondary Assets | 프라이머리 에셋에 의존해 자동 로드 및 언로드 하는 에셋 |
| Asset Bundles | 런타임에 함께 로드 될 수 있도록 이름 별로 묶은 논리적 에셋 그룹 |
| Asset Manager | 프라이머리 에셋과 에셋 번들 정보를 관리하는 싱글톤 |
비동기 로드 및 동기 로드 된 객체를 필요 없어질 때까지 메모리에 유지하는 네이티브 구조체
FStreamableHandle
FStreamableHandle::ReleaseHandle()
FStreamableHandle::CancelHandle()
FStreamableHandle::WaitUntilComplete()
RequestAsyncLoad
RequestSyncLoad
LoadSynchronous
bManageActiveHandle
예시
// 비동기 로드
FStreamableManger StreamableManager;
FStringAssetReference MeshRef(TEXT("Game/Meshes/SM_Sword.SM_Sword"));
TSharedPtr<FStreamableHandle> Handle = SteamableManagerRequestAsyncLoad(
MeshRef,
FStreamableDelegate::CreateLambda([MeshRef]()
{
UE_LOG(LogTemp, Log, TEXT("비동기 로드 완료"), *MeshRef.ToString());
});
Handle->WaitUntilComplete();
UObject* LoadedAsset = Handle->GetLoadedAsset();
// 동기 로드 RequestSyncLoad
TSharedPtr<FStreamableHandle> Handle = StreamableManager.RequestSyncLoad(MeshRef);
UObject* LoadedAsset = Handle->GetLaodedAsset();
// 동기 로드 LoadSynchronous
UStaticMesh* AxeMesh = StreamableManager.LoadSynchronous<UStaticMesh>(MeshRef);
런타임에 프라이머리 에셋을 로드하거나 스캔하는 기능을 제공하는 싱글톤 UObject
기존의 ObjectLibrary의 기능을 대체, 내부적으로 FStreamableManager를 감싸서 비동기 로딩 처리
Get()
ScanPathsForPrimaryAssets(Type,Paths,BaseClass)
GetPrimaryAssetPath(PrimaryAssetId)
GetPrimaryAssetIdForPath(StringReference)
예시
UAssetManager& AssetManager = UAssetManager::Get();
FPrimaryAssetId ItemId(TEXT("Item"), TEXT("Sword"));
FSoftObjectPath AssetPath = AssetManger.GetPrimaryAssetPath(ItemId);
UObject* LoadedAsset = AssetManager.GetStreamableManager().LoadSynchronous(AssetPath);
// 싱글톤 접근
UAssetManager& AssetManager = UAssetManager::Get();
// 에셋 타입의 프라이머리 에셋 ID를 IDList에 담음
AssetManager.GetPrimaryAssetIdList(WeaponItemType, WeaponIdList);
// 에셋 ID에 대응되는 FAssetData(메타데이터) 반환
AssetManager.GetPrimaryAssetData(WeaponIdList[0], AssetDataToParse);
// 프라이머리 에셋 로드
FPrimaryAssetId WeaponId = FPrimaryAssetId(WeaponItemType, WeaponName);
AssetManager.LoadPrimaryAsset(WeaponId, CurrentLoadState, DelegateFunction);
// 로드된 객체 가져오기
UWeaponItem* Weapon = AssetManger.GetPrimaryAssetObject<UWeaponItem>(WeaponId);
// 에셋 언로드
AssetManager.UnloadPrimaryAsset(WeaponId);
// 여러 에셋 미리 로드
Handle = AssetManger.PreloadPrimaryAssets(ListOfPrimaryAssetIds, CurrentLoadState, false);TSoftObjectPtr or FStringAssetReference 타입의 UObject로 생성UpdateAssetBundleData를 오버라이드런타임에 에셋 번들에 대한 참조가 변경 될 수 있는 경우 직접 번들을 구성
에디터나 런타임에서 에셋을 스캔할 때 자동으로 호출
virtual void UpdateAssetBundleData(FAssetBundleData& AssetBundleData) override
{
// "Model" 번들에 메쉬 추가
AssetBundleData.AddBundleAsset("Model", WeaponMesh.ToSoftObjectPath());
// "Sound" 번들에 사운드 추가
AssetBundleData.AddBundleAsset("Sound", SwingSound.ToSoftObjectPath());
// "UI" 번들에 텍스처 추가
AssetBundleData.AddBundleAsset("UI", IconTexture.ToSoftObjectPath());
}
ChangeBundleStateForPrimaryAssets특정 번들을 로드하거나 언로드할 때 사용
"Model", "Sound" 번들을 비동기로 로드하고, "UI" 번들은 해제
TArray<FPrimaryAssetId> WeaponAssets = { SwordId, AxeId };
TArray<FName> BundlesToLoad = { "Model", "Sound" };
TArray<FName> BundlesToUnload = { "UI" };
AssetManager.ChangeBundleStateForPrimaryAssets(
WeaponAssets,
BundlesToLoad,
BundlesToUnload,
false, // 비동기
FStreamableDelegate::CreateUObject(this, &UMyGameInstance::OnBundlesLoaded)
);
ChangeBundleStateForMatchingPrimaryAssets특정 타입으로 매칭된 모든 프라이머리 에셋에 대해 상태를 변경
모든 “WeaponItem” 타입의 무기 에셋에서 사운드 번들만 한번에 로드
AssetManager.ChangeBundleStateForMatchingPrimaryAssets(
FPrimaryAssetType("WeaponItem"),
{ "Sound" }, // AddBundles
{}, // RemoveBundles
false, // 비동기
FStreamableDelegate()
);
UCLASS()
class UAssetBundlesCharacterData : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultOnly, meta=(AssetBundles="Lobby"))
TSoftObjectPtr<UTexture2D> CharacterLobbyPortrait;
UPROPERTY(EditDefaultsOnly)
FText CharacterName;
UPROPERTY(EditDefaultsOnly, meta=(AssetBundles="Game"))
TSoftClassPtr<APawn> CharacterGamePawnClass;
} LoadPrimaryAssetWithType특정 프라이머리 에셋 타입에 속하면서 번들에 포함된 에셋을 모두 로드
TArray<FName>& AssetBundles = { "Game", "Lobby" };
UAssetManager& AssetManager = UAssetManager::Get();
CharacterDataHandle = AssetManger.LoadPrimaryAssetWithType(
PrimaryAssetType,
AssetBundles,
FStreamableDelegate::CreateLambda([this]()
{
TArray<FPrimaryAssetId> AsssetIds;
UAssetManger::Get().GetPrimaryAssetIdList(UAssetBundlesCharacterData::StaticClass()->GetFName(), AssetIds);)
if (const UAssetBundlesCharacterData* LoadedAsset = Cast<UAssetBundlesCharacterData>(
UAssetManager::Get().GetPrimaryAssetObject(AssetIds[0])))
{
...
}
}
);
Delegate 방식: 비동기 로드 완료 후 람다 실행 (이벤트 기반)
Preload 방식: 미리 로드해두고, 나중에 즉시 접근 (데이터 캐시 기반)
// Delegate 방식
AssetManager.LoadPrimaryAsset(AssetId, Bundles, OnLoadedDelegate);
// Preload 방식
Handle = AssetManager.PreloadPrimaryAssets(AssetIds, Bundles, false);
Asset Manager Explained | Inside Unreal
Unreal Engine - The Asset Manager, Primary Assets and Asset Bundles