void FStreamableManager::AsyncLoadCallback(FStringAssetReference Request) { FStringAssetReference TargetName = Request; FStreamable* Existing = StreamableItems.FindRef(TargetName); UE_LOG(LogStreamableManager, Verbose, TEXT("Stream Complete callback %s"), *TargetName.AssetLongPathname); if (!Existing) { // hmm, maybe it was redirected by a consolidate TargetName = ResolveRedirects(TargetName); FStreamable* Existing = StreamableItems.FindRef(TargetName); } if (Existing && Existing->bAsyncLoadRequestOutstanding) { Existing->bAsyncLoadRequestOutstanding = false; if (!Existing->Target) { FindInMemory(TargetName, Existing); } CheckCompletedRequests(Request, Existing); } if (Existing->Target) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Found target %s"), *Existing->Target->GetFullName()); } else { // Async load failed to find the object Existing->bLoadFailed = true; UE_LOG(LogStreamableManager, Verbose, TEXT(" Failed async load."), *TargetName.AssetLongPathname); } }
struct FStreamable* FStreamableManager::StreamInternal(FStringAssetReference const& InTargetName) { check(IsInGameThread()); UE_LOG(LogStreamableManager, Verbose, TEXT("Asynchronous load %s"), *InTargetName.AssetLongPathname); if (FPackageName::IsShortPackageName(InTargetName.AssetLongPathname)) { UE_LOG(LogStreamableManager, Error, TEXT(" Can't load invalid package name %s"), *InTargetName.AssetLongPathname); return NULL; } FStringAssetReference TargetName = ResolveRedirects(InTargetName); FStreamable* Existing = StreamableItems.FindRef(TargetName); if (Existing) { if (Existing->bAsyncUnloadRequestOutstanding) { // It's valid to have a live pointer if an async loaded object was hard referenced later check(!Existing->bAsyncLoadRequestOutstanding); // we should not be both loading and unloading UE_LOG(LogStreamableManager, Verbose, TEXT(" Aborted unload for %s"), *TargetName.AssetLongPathname); Existing->bAsyncUnloadRequestOutstanding = false; check(Existing->Target || Existing->bLoadFailed); // should not be an unload request unless the target is valid return Existing; } if (Existing->bAsyncLoadRequestOutstanding) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Already in progress %s"), *TargetName.AssetLongPathname); check(!Existing->bAsyncUnloadRequestOutstanding); // we should not be both loading and unloading check(!Existing->Target); // should not be an load request unless the target is invalid return Existing; // already have one in process } if (Existing->Target) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Already Loaded %s"), *TargetName.AssetLongPathname); return Existing; } } else { Existing = StreamableItems.Add(TargetName, new FStreamable()); } FindInMemory(TargetName, Existing); if (!Existing->Target) { FString Package = TargetName.AssetLongPathname; int32 FirstDot = Package.Find(TEXT(".")); if (FirstDot != INDEX_NONE) { Package = Package.Left(FirstDot); } Existing->bAsyncLoadRequestOutstanding = true; LoadPackageAsync(Package, FLoadPackageAsyncDelegate::CreateStatic(&AsyncLoadCallbackWrapper, new FCallback(TargetName, this)) ); } return Existing; }
bool FStreamableManager::IsAsyncLoadComplete(FStringAssetReference const& InTargetName) { check(IsInGameThread()); FStringAssetReference TargetName = ResolveRedirects(InTargetName); FStreamable* Existing = StreamableItems.FindRef(TargetName); UE_LOG(LogStreamableManager, Verbose, TEXT("IsStreamComplete %s -> %d"), *TargetName.ToString(), !Existing || !Existing->bAsyncLoadRequestOutstanding); return !Existing || !Existing->bAsyncLoadRequestOutstanding; }
UObject* FStreamableManager::GetStreamed(FStringAssetReference const& InTargetName) { check(IsInGameThread()); FStringAssetReference TargetName = ResolveRedirects(InTargetName); FStreamable* Existing = StreamableItems.FindRef(TargetName); if (Existing && Existing->Target) { UE_LOG(LogStreamableManager, Verbose, TEXT("GetStreamed %s -> %s"), *TargetName.ToString(), *Existing->Target->GetFullName()); return Existing->Target; } UE_LOG(LogStreamableManager, Verbose, TEXT("GetStreamed %s -> NULL"), *TargetName.ToString()); return NULL; }
void FStreamableManager::Unload(FStringAssetReference const& InTargetName) { check(IsInGameThread()); FStringAssetReference TargetName = ResolveRedirects(InTargetName); FStreamable* Existing = StreamableItems.FindRef(TargetName); if (Existing) { UE_LOG(LogStreamableManager, Verbose, TEXT("Unload %s"), *TargetName.ToString()); Existing->bAsyncLoadRequestOutstanding = false; Existing->bAsyncUnloadRequestOutstanding = true; } else { UE_LOG(LogStreamableManager, Verbose, TEXT("Attempt to unload %s, but it isn't loaded"), *TargetName.ToString()); } }
UObject* FStreamableManager::SynchronousLoad(FStringAssetReference const& InTargetName) { UE_LOG(LogStreamableManager, Verbose, TEXT("Synchronous load %s"), *InTargetName.ToString()); if (FPackageName::IsShortPackageName(InTargetName.ToString())) { UE_LOG(LogStreamableManager, Error, TEXT(" Can't load invalid package name %s"), *InTargetName.ToString()); return NULL; } FStringAssetReference TargetName = ResolveRedirects(InTargetName); FStreamable* Existing = StreamableItems.FindRef(TargetName); while (Existing && Existing->bAsyncLoadRequestOutstanding) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Flushing async load for %s"), *TargetName.ToString()); check(!Existing->bAsyncUnloadRequestOutstanding); // we should not be both loading and unloading FlushAsyncLoading(); // the async request might have found a redirect and retried TargetName = ResolveRedirects(TargetName); Existing = StreamableItems.FindRef(TargetName); } if (!Existing) { Existing = StreamableItems.Add(TargetName, new FStreamable()); } check(!Existing->bAsyncLoadRequestOutstanding); // should have already dealt with this if (Existing->bAsyncUnloadRequestOutstanding) { check(!Existing->bAsyncLoadRequestOutstanding); // we should not be both loading and unloading UE_LOG(LogStreamableManager, Verbose, TEXT(" Aborted unload for %s"), *TargetName.ToString()); Existing->bAsyncUnloadRequestOutstanding = false; } check(!Existing->bAsyncUnloadRequestOutstanding); // should have already dealt with this check(!Existing->WeakTarget.Get()); // weak target is only valid during GC if (!Existing->Target) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Static loading %s"), *TargetName.ToString()); Existing->Target = StaticLoadObject(UObject::StaticClass(), NULL, *TargetName.ToString()); // need to manually detect redirectors because the above call only expects to load a UObject::StaticClass() type while (UObjectRedirector* Redirector = Cast<UObjectRedirector>(Existing->Target)) { Existing->Target = Redirector->DestinationObject; } if (Existing->Target) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Static loaded %s"), *Existing->Target->GetFullName()); FStringAssetReference PossiblyNewName(Existing->Target->GetPathName()); if (PossiblyNewName != TargetName) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Which redirected to %s"), *PossiblyNewName.ToString()); StreamableRedirects.Add(TargetName, PossiblyNewName); StreamableItems.Add(PossiblyNewName, Existing); StreamableItems.Remove(TargetName); TargetName = PossiblyNewName; // we are done with the old name } } else { Existing->bLoadFailed = true; UE_LOG(LogStreamableManager, Log, TEXT("Failed attempt to load %s"), *TargetName.ToString()); } } else { Existing->bLoadFailed = false; } return Existing->Target; }