DataBundle의 로드/언로드를 관리하는 GameInstance 서브시스템.
더 자세히 ...
#include <DataBundleRegistry.h>
|
| virtual void | Initialize (FSubsystemCollectionBase &Collection) override |
| | 서브시스템 초기화. 번들 스캔 및 PreLoad 정책 번들 로드를 수행합니다.
|
| |
| virtual void | Deinitialize () override |
| | 서브시스템 종료. 모든 StreamableHandle을 해제하고 상태를 정리합니다.
|
| |
| void | RequestLoad (FGameplayTag BundleTag, TFunction< void()> OnReady=nullptr) |
| | 번들을 비동기 로드합니다. 로드 완료 시 OnReady 콜백을 호출합니다.
|
| |
| void | RequestLoad (const TArray< FGameplayTag > &BundleTags, TFunction< void()> OnAllReady) |
| | 여러 번들을 비동기 로드합니다. 모든 번들 로드 완료 시 OnAllReady 콜백을 호출합니다.
|
| |
| void | Release (FGameplayTag BundleTag) |
| | 번들을 언로드합니다 (bPersistent 번들 제외).
|
| |
| void | ForceRelease (FGameplayTag BundleTag) |
| | bPersistent 여부와 관계없이 번들을 강제 언로드합니다.
|
| |
| EDataBundleState | GetState (FGameplayTag BundleTag) const |
| | 번들의 현재 로드 상태를 반환합니다.
|
| |
| bool | IsLoaded (FGameplayTag BundleTag) const |
| | 번들이 로드 완료 상태인지 여부를 반환합니다.
|
| |
| TArray< FGameplayTag > | GetLoadedBundles () const |
| | 현재 로드 완료 상태인 모든 번들의 태그 목록을 반환합니다.
|
| |
| void | ReleaseUnusedBundles (const TArray< FGameplayTag > &RequiredTags) |
| | 로드된 번들 중 RequiredTags에 없는 번들을 해제합니다.
|
| |
| template<typename T > |
| T * | GetBundleAsset (FGameplayTag BundleTag, const TSoftObjectPtr< T > &AssetPtr) const |
| | 로드된 번들에서 특정 에셋을 동기적으로 반환합니다.
|
| |
| template<typename T > |
| void | RequestBundleAsset (FGameplayTag BundleTag, const TSoftObjectPtr< T > &AssetPtr, TFunction< void(T *)> OnReady) |
| | 번들을 비동기 로드한 뒤 에셋 포인터를 콜백으로 전달합니다.
|
| |
DataBundle의 로드/언로드를 관리하는 GameInstance 서브시스템.
특징:
- 이미 로드된 번들에 RequestLoad 시 콜백만 즉시 실행 (중복 로드 없음)
- 로딩 중 중복 요청: 콜백만 큐에 추가, 로드 완료 시 일괄 실행
- 로드할 번들은 ULevelStreamingData::UsingBundlesTag로 지정
DefaultGame.ini에 DataBundle PrimaryAssetType 등록 필요 (DataBundleDefinition.h 참조)
◆ Deinitialize()
| void UDataBundleRegistry::Deinitialize |
( |
| ) |
|
|
overridevirtual |
서브시스템 종료. 모든 StreamableHandle을 해제하고 상태를 정리합니다.
25{
26
27 for (
auto& [Tag, Entry] :
Entries)
28 {
29 if (Entry.Handle.IsValid())
30 {
31 Entry.Handle->ReleaseHandle();
32 }
33 }
34
37
38 Super::Deinitialize();
39}
TMap< FGameplayTag, FBundleEntry > Entries
번들 태그 → 런타임 상태 맵.
Definition DataBundleRegistry.h:208
TMap< FGameplayTag, TObjectPtr< UDataBundleDefinition > > Definitions
번들 태그 → 정의 에셋 맵. UPROPERTY로 GC를 방지합니다.
Definition DataBundleRegistry.h:205
◆ FlushPendingCallbacks()
| void UDataBundleRegistry::FlushPendingCallbacks |
( |
FGameplayTag |
BundleTag | ) |
|
|
private |
누적된 PendingCallbacks를 모두 실행하고 큐를 비웁니다.
- 매개변수
-
| BundleTag | 콜백을 실행할 번들의 GameplayTag. |
251{
252 FBundleEntry* Entry =
Entries.Find(BundleTag);
253
254 if (Entry == nullptr)
255 {
256 return;
257 }
258
259
260 TArray<TFunction<void()>> Callbacks = MoveTemp(Entry->PendingCallbacks);
261
262 for (TFunction<void()>& CallbackFunc : Callbacks)
263 {
265 }
266}
#define TRY_CALL_FUNC(Func)
Definition DataBundleRegistry.cpp:11
◆ ForceRelease()
| void UDataBundleRegistry::ForceRelease |
( |
FGameplayTag |
BundleTag | ) |
|
bPersistent 여부와 관계없이 번들을 강제 언로드합니다.
- 매개변수
-
| BundleTag | 해제할 번들의 GameplayTag. |
303{
304 FBundleEntry* Entry =
Entries.Find(BundleTag);
305
306 if (Entry == nullptr || Entry->State != EDataBundleState::Loaded)
307 {
308 return;
309 }
310
311 if (Entry->Handle.IsValid())
312 {
313 TArray<UObject*> LoadedObjects;
314 Entry->Handle->GetLoadedAssets(LoadedObjects);
317
318 Entry->Handle->ReleaseHandle();
319 Entry->Handle.Reset();
320 }
321
322 Entry->State = EDataBundleState::Unloaded;
323
324 LOG_SCREEN(
"번들 강제 언로드: %s", *BundleTag.ToString());
325}
#define LOG_SCREEN(Format,...)
Definition CK_UE.h:41
static void UnregisterBundleAssets(const TArray< UObject * > &InAssets)
번들 언로드 시 GC 방지 풀에서 에셋들을 제거합니다.
Definition DataAssetManager.cpp:214
void NotifyBundleReleasedToAssets(const TArray< UObject * > &Assets, FGameplayTag BundleTag)
Definition DataBundleRegistry.cpp:418
◆ GetBundleAsset()
template<typename T >
| T * UDataBundleRegistry::GetBundleAsset |
( |
FGameplayTag |
BundleTag, |
|
|
const TSoftObjectPtr< T > & |
AssetPtr |
|
) |
| const |
로드된 번들에서 특정 에셋을 동기적으로 반환합니다.
번들이 로드되지 않은 경우 nullptr을 반환합니다. 비동기 접근이 필요하면 RequestBundleAsset을 사용하세요.
- 템플릿 파라메터
-
- 매개변수
-
| BundleTag | 조회할 번들 태그. |
| AssetPtr | 반환할 에셋의 소프트 포인터. |
- 반환값
- 번들이 로드 상태면 T*, 아니면 nullptr.
216{
218 {
219 LOG_WARNING(LogCKAsset,
"번들 '%s'이 로드되지 않은 상태에서 GetBundleAsset 호출됨.", *BundleTag.ToString());
220 return nullptr;
221 }
222
223 T* Asset = AssetPtr.Get();
224
225 if (Asset == nullptr)
226 {
227 LOG_WARNING(LogCKAsset,
"번들 '%s'의 에셋 '%s'이 메모리에 없습니다.", *BundleTag.ToString(), *AssetPtr.ToString());
228 }
229
230 return Asset;
231}
#define LOG_WARNING(Category, Format,...)
Definition CK_UE.h:31
bool IsLoaded(FGameplayTag BundleTag) const
번들이 로드 완료 상태인지 여부를 반환합니다.
Definition DataBundleRegistry.cpp:341
◆ GetLoadedBundles()
| TArray< FGameplayTag > UDataBundleRegistry::GetLoadedBundles |
( |
| ) |
const |
현재 로드 완료 상태인 모든 번들의 태그 목록을 반환합니다.
- 반환값
- Loaded 상태인 번들 태그 배열.
355{
356 TArray<FGameplayTag> Result;
357
358 for (
const auto& [Tag, Entry] :
Entries)
359 {
360 if (Entry.State == EDataBundleState::Loaded)
361 {
362 Result.Add(Tag);
363 }
364 }
365
366 return Result;
367}
◆ GetState()
번들의 현재 로드 상태를 반환합니다.
- 매개변수
-
| BundleTag | 조회할 번들의 GameplayTag. |
- 반환값
- 해당 번들의 EDataBundleState. 등록되지 않은 경우 Unloaded 반환.
329{
330 if (
const FBundleEntry* Entry =
Entries.Find(BundleTag))
331 {
332 return Entry->State;
333 }
334 else
335 {
336 return EDataBundleState::Unloaded;
337 }
338}
◆ Initialize()
| void UDataBundleRegistry::Initialize |
( |
FSubsystemCollectionBase & |
Collection | ) |
|
|
overridevirtual |
서브시스템 초기화. 번들 스캔 및 PreLoad 정책 번들 로드를 수행합니다.
17{
18 Super::Initialize(Collection);
21}
void PreLoadBundles()
LoadPolicy가 PreLoad인 번들을 게임 시작 시 자동 로드합니다.
Definition DataBundleRegistry.cpp:88
void ScanAndRegisterBundles()
AssetManager에서 DataBundle 타입 에셋을 스캔해 Definitions에 등록합니다.
Definition DataBundleRegistry.cpp:42
◆ IsLoaded()
| bool UDataBundleRegistry::IsLoaded |
( |
FGameplayTag |
BundleTag | ) |
const |
번들이 로드 완료 상태인지 여부를 반환합니다.
- 매개변수
-
| BundleTag | 조회할 번들의 GameplayTag. |
- 반환값
- 로드 완료 상태이면 true.
342{
343 if (
GetState(BundleTag) == EDataBundleState::Loaded)
344 {
345 return true;
346 }
347 else
348 {
349 return false;
350 }
351}
EDataBundleState GetState(FGameplayTag BundleTag) const
번들의 현재 로드 상태를 반환합니다.
Definition DataBundleRegistry.cpp:328
◆ NotifyBundleLoadedToAssets()
| void UDataBundleRegistry::NotifyBundleLoadedToAssets |
( |
const TArray< UObject * > & |
Assets, |
|
|
FGameplayTag |
BundleTag |
|
) |
| |
|
private |
407{
408 for (UObject* Asset : Assets)
409 {
411 {
412 IBundleEventInterface::Execute_OnBundleLoaded(Asset, BundleTag);
413 }
414 }
415}
Definition BundleEventInterface.h:13
◆ NotifyBundleReleasedToAssets()
| void UDataBundleRegistry::NotifyBundleReleasedToAssets |
( |
const TArray< UObject * > & |
Assets, |
|
|
FGameplayTag |
BundleTag |
|
) |
| |
|
private |
419{
420 for (UObject* Asset : Assets)
421 {
423 {
424 IBundleEventInterface::Execute_OnBundleReleased(Asset, BundleTag);
425 }
426 }
427}
◆ OnAllDependenciesReady()
| void UDataBundleRegistry::OnAllDependenciesReady |
( |
FGameplayTag |
BundleTag | ) |
|
|
private |
의존 번들이 모두 로드됐을 때 호출됩니다. 본 번들의 에셋 스트리밍을 시작합니다.
- 매개변수
-
| BundleTag | 에셋 스트리밍을 시작할 번들의 GameplayTag. |
184{
186
187 if (Def == nullptr)
188 {
189 return;
190 }
191
193
194
195 if (AssetPaths.IsEmpty())
196 {
198 return;
199 }
200
201 FStreamableManager& Manager = UAssetManager::Get().GetStreamableManager();
202
203 auto AssetsLoadedLambda = FStreamableDelegate::CreateWeakLambda(this, [this, BundleTag]()
204 {
206 });
207
208 TSharedPtr<FStreamableHandle> Handle = Manager.RequestAsyncLoad(AssetPaths, AssetsLoadedLambda);
209
210
211 if (FBundleEntry* Entry =
Entries.Find(BundleTag))
212 {
213 Entry->Handle = Handle;
214 }
215}
Definition DataBundleDefinition.h:28
TArray< FSoftObjectPath > GetAssetPaths() const
Definition DataBundleDefinition.cpp:13
void OnAssetsLoaded(FGameplayTag BundleTag)
에셋 스트리밍 완료 시 호출됩니다. 상태를 Loaded로 전환하고 콜백을 실행합니다.
Definition DataBundleRegistry.cpp:218
◆ OnAssetsLoaded()
| void UDataBundleRegistry::OnAssetsLoaded |
( |
FGameplayTag |
BundleTag | ) |
|
|
private |
에셋 스트리밍 완료 시 호출됩니다. 상태를 Loaded로 전환하고 콜백을 실행합니다.
로드 완료 전 이미 Release된 경우 bPersistent 여부에 따라 즉시 언로드합니다.
- 매개변수
-
| BundleTag | 로드가 완료된 번들의 GameplayTag. |
219{
220 FBundleEntry* Entry =
Entries.Find(BundleTag);
221
222 if (Entry == nullptr)
223 {
224 return;
225 }
226
227 Entry->State = EDataBundleState::Loaded;
228
229
230 if (Entry->Handle.IsValid())
231 {
232 TArray<UObject*> LoadedObjects;
233 Entry->Handle->GetLoadedAssets(LoadedObjects);
235 }
236
237 LOG_SCREEN(
"번들 로드 완료: %s", *BundleTag.ToString());
238
239 if (Entry->Handle.IsValid())
240 {
241 TArray<UObject*> LoadedObjects;
242 Entry->Handle->GetLoadedAssets(LoadedObjects);
244 }
245
247}
static void RegisterBundleAssets(const TArray< UObject * > &InAssets)
번들 로드 완료 후 에셋들을 GC 방지 풀에 등록합니다.
Definition DataAssetManager.cpp:196
void FlushPendingCallbacks(FGameplayTag BundleTag)
누적된 PendingCallbacks를 모두 실행하고 큐를 비웁니다.
Definition DataBundleRegistry.cpp:250
void NotifyBundleLoadedToAssets(const TArray< UObject * > &Assets, FGameplayTag BundleTag)
Definition DataBundleRegistry.cpp:406
◆ PreLoadBundles()
| void UDataBundleRegistry::PreLoadBundles |
( |
| ) |
|
|
private |
LoadPolicy가 PreLoad인 번들을 게임 시작 시 자동 로드합니다.
89{
90 int32 PreLoadCount = 0;
91
93 {
94 if (Def == nullptr)
95 {
96 continue;
97 }
98
99
100 if (Def->LoadPolicy != EBundleLoadPolicy::PreLoad)
101 {
102 continue;
103 }
104
106 PreLoadCount++;
107
108 LOG_INFO(LogCKAsset,
"번들 PreLoad 요청: %s", *Tag.ToString());
109 }
110
111 LOG_INFO(LogCKAsset,
"PreLoad 정책 번들 %d개 로드 요청 완료", PreLoadCount);
112}
#define LOG_INFO(Category, Format,...)
Definition CK_UE.h:30
void RequestLoad(FGameplayTag BundleTag, TFunction< void()> OnReady=nullptr)
번들을 비동기 로드합니다. 로드 완료 시 OnReady 콜백을 호출합니다.
Definition DataBundleRegistry.cpp:141
◆ Release()
| void UDataBundleRegistry::Release |
( |
FGameplayTag |
BundleTag | ) |
|
번들을 언로드합니다 (bPersistent 번들 제외).
- 매개변수
-
| BundleTag | 해제할 번들의 GameplayTag. |
270{
271 FBundleEntry* Entry =
Entries.Find(BundleTag);
272
273 if (Entry == nullptr || Entry->State != EDataBundleState::Loaded)
274 {
275 return;
276 }
277
279
281 {
282 return;
283 }
284
285 if (Entry->Handle.IsValid())
286 {
287 TArray<UObject*> LoadedObjects;
288 Entry->Handle->GetLoadedAssets(LoadedObjects);
291
292 Entry->Handle->ReleaseHandle();
293 Entry->Handle.Reset();
294 }
295
296 Entry->State = EDataBundleState::Unloaded;
297
298 LOG_SCREEN(
"번들 언로드: %s", *BundleTag.ToString());
299}
bool bPersistent
Definition DataBundleDefinition.h:43
◆ ReleaseUnusedBundles()
| void UDataBundleRegistry::ReleaseUnusedBundles |
( |
const TArray< FGameplayTag > & |
RequiredTags | ) |
|
로드된 번들 중 RequiredTags에 없는 번들을 해제합니다.
bPersistent 번들은 건너뜁니다.
- 매개변수
-
| RequiredTags | 유지할 번들 태그 목록. |
371{
372
373 TArray<FGameplayTag> TagsToRelease;
374
375 for (
const auto& [Tag, Entry] :
Entries)
376 {
377 if (Entry.State != EDataBundleState::Loaded)
378 {
379 continue;
380 }
381
382 if (RequiredTags.Contains(Tag))
383 {
384 continue;
385 }
386
388
390 {
391 continue;
392 }
393
394 TagsToRelease.Add(Tag);
395 }
396
397 LOG_INFO(LogCKAsset,
"[ReleaseUnused] 해제 대상: %d개", TagsToRelease.Num());
398
399 for (const FGameplayTag& Tag : TagsToRelease)
400 {
402 }
403}
void Release(FGameplayTag BundleTag)
번들을 언로드합니다 (bPersistent 번들 제외).
Definition DataBundleRegistry.cpp:269
◆ RequestBundleAsset()
template<typename T >
| void UDataBundleRegistry::RequestBundleAsset |
( |
FGameplayTag |
BundleTag, |
|
|
const TSoftObjectPtr< T > & |
AssetPtr, |
|
|
TFunction< void(T *)> |
OnReady |
|
) |
| |
번들을 비동기 로드한 뒤 에셋 포인터를 콜백으로 전달합니다.
번들이 이미 로드된 경우 콜백이 즉시 실행됩니다.
- 템플릿 파라메터
-
- 매개변수
-
| BundleTag | 로드할 번들 태그. |
| AssetPtr | 요청할 에셋의 소프트 포인터. |
| OnReady | 로드 완료 시 호출될 콜백 (T* 인자). |
236{
237 TSoftObjectPtr<T> AssetCapture = AssetPtr;
238
239 RequestLoad(BundleTag, [
this, BundleTag, AssetCapture, OnReady = MoveTemp(OnReady)]()
240 {
241 T* Asset = AssetCapture.Get();
242
243 if (Asset == nullptr)
244 {
245 LOG_WARNING(LogCKAsset,
"RequestBundleAsset: 번들 '%s' 로드 완료 후에도 에셋을 찾을 수 없습니다: %s", *BundleTag.ToString(), *AssetCapture.ToString());
246 }
247
248 if (OnReady)
249 {
250 OnReady(Asset);
251 }
252 });
253}
◆ RequestLoad() [1/2]
| void UDataBundleRegistry::RequestLoad |
( |
const TArray< FGameplayTag > & |
BundleTags, |
|
|
TFunction< void()> |
OnAllReady |
|
) |
| |
여러 번들을 비동기 로드합니다. 모든 번들 로드 완료 시 OnAllReady 콜백을 호출합니다.
빈 배열이 전달되면 OnAllReady가 즉시 호출됩니다.
- 매개변수
-
| BundleTags | 로드할 번들 태그 목록. |
| OnAllReady | 모든 번들 로드 완료 시 실행할 콜백. |
116{
117 if (BundleTags.IsEmpty())
118 {
120 return;
121 }
122
123 auto SharedCallback = MakeShared<TFunction<void()>>(MoveTemp(OnAllReady));
124 TSharedRef<int32> PendingCount = MakeShared<int32>(BundleTags.Num());
125
126 for (const FGameplayTag& Tag : BundleTags)
127 {
129 {
130 if (--(*PendingCount) > 0)
131 {
132 return;
133 }
134
136 });
137 }
138}
◆ RequestLoad() [2/2]
| void UDataBundleRegistry::RequestLoad |
( |
FGameplayTag |
BundleTag, |
|
|
TFunction< void()> |
OnReady = nullptr |
|
) |
| |
번들을 비동기 로드합니다. 로드 완료 시 OnReady 콜백을 호출합니다.
- 매개변수
-
| BundleTag | 로드할 번들의 GameplayTag. |
| OnReady | 번들 로드 완료 시 실행할 콜백. |
142{
143 bool bCanLoad = ensureMsgf(
Definitions.Contains(BundleTag), TEXT(
"등록되지 않은 번들: %s"), *BundleTag.ToString());
144
145 if (bCanLoad == false)
146 {
147
149 return;
150 }
151
152 FBundleEntry& Entry =
Entries.FindOrAdd(BundleTag);
153
154 switch (Entry.State)
155 {
156
157 case EDataBundleState::Unloaded:
158 {
159 Entry.State = EDataBundleState::Loading;
162 break;
163 }
164
165
166 case EDataBundleState::Loading:
167 {
169 break;
170 }
171
172
173 case EDataBundleState::Loaded:
174 {
176 break;
177 }
178 }
179}
#define TRY_REGISTER_CALLBACK(Func, Entry)
Definition DataBundleRegistry.cpp:13
void OnAllDependenciesReady(FGameplayTag BundleTag)
의존 번들이 모두 로드됐을 때 호출됩니다. 본 번들의 에셋 스트리밍을 시작합니다.
Definition DataBundleRegistry.cpp:183
◆ ScanAndRegisterBundles()
| void UDataBundleRegistry::ScanAndRegisterBundles |
( |
| ) |
|
|
private |
AssetManager에서 DataBundle 타입 에셋을 스캔해 Definitions에 등록합니다.
43{
44 UAssetManager& AssetManager = UAssetManager::Get();
45 TArray<FPrimaryAssetId> BundleIds;
46
47
48 AssetManager.GetPrimaryAssetIdList(FPrimaryAssetType(TEXT("DataBundle")), BundleIds);
49
50 for (const FPrimaryAssetId& AssetId : BundleIds)
51 {
52
53 UDataBundleDefinition* Def = Cast<UDataBundleDefinition>(AssetManager.GetPrimaryAssetObject(AssetId));
54
55 if (Def == nullptr)
56 {
57 FSoftObjectPath AssetPath = AssetManager.GetPrimaryAssetPath(AssetId);
58 Def = Cast<UDataBundleDefinition>(AssetPath.TryLoad());
59 }
60
61 if (Def == nullptr)
62 {
63 LOG_WARNING(LogCKAsset,
"DataBundleDefinition 로드 실패: %s", *AssetId.ToString());
64 continue;
65 }
66
68 {
69 LOG_WARNING(LogCKAsset,
"BundleTag가 유효하지 않습니다: %s", *AssetId.ToString());
70 continue;
71 }
72
74 {
76 }
77
80
82 }
83
85}
TArray< TSoftObjectPtr< UPrimaryDataAsset > > Assets
Definition DataBundleDefinition.h:51
FGameplayTag BundleTag
Definition DataBundleDefinition.h:39
◆ Definitions
번들 태그 → 정의 에셋 맵. UPROPERTY로 GC를 방지합니다.
◆ Entries
| TMap<FGameplayTag, FBundleEntry> UDataBundleRegistry::Entries |
|
private |
이 클래스에 대한 문서화 페이지는 다음의 파일들로부터 생성되었습니다.: