Hi. I was wondering if there is an easy way to reset a level without reloading it. I know there is the AGameModeBase::ResetLevel method, but it seems I would then have to implement Reset() on all actors and track their initial states. I would like to avoid that at all costs. I also know I can do something like APlayerController::RestartLevel or this:
However, the problem with that method is in the packaged game, the textures seem to get unloaded when reloading the level and take a second to reload (for a second they are blurry). So, what I’m really asking is: “Is there a way to get the loaded assets to remain in memory when I reload the level”
I use Linux, and I can use C++ or Blueprints, whichever you like.
After digging around in the source code for a while, I found a solution.
Here’s what I found:
The textures are being unloaded because they are being deleted by the garbage collector
The garbage collector is deleting the textures from memory because they are temporarily unreferenced.
So my solution is this (C++):
Put an array of UObjects in my Game Instance.
Before reloading the level, find all texture objects in memory and add their pointers to the array in the Game Instance.
After the map has been reloaded remove the references from the array.
**Keeping a reference to the textures in the GameInstance keeps them from being unloaded, so they do not have to be reloaded when the level is reloaded **
Update to this post after a few years for those that are looking into the same issue. I’ve added the following functions to our GameInstance to shorten loading times from 20 sec to 7 secs on the Switch.
Can also be used to keep a separate level loaded in memory if you know it’s going to be reused soon without using async level loading.
// Static member variable defined in header.
TMap<FName, TArray<TStrongObjectPtr<UObject>>> UMyGameInstance::_keptLevels;
void UMyGameInstance::KeepReferenceToLevel(const FName levelName)
{
const auto* arr = _keptLevels.Find(levelName);
if (arr && arr->Num() > 0)
{
DropReferenceToLevel(levelName);
}
else
{
auto& levelArray = _keptLevels.FindOrAdd(levelName);
TArray<UObject*> outTextures;
GetObjectsOfClass(UTexture2D::StaticClass(), outTextures);
TArray<UObject*> outMeshes;
GetObjectsOfClass(UStaticMesh::StaticClass(), outMeshes);
TArray<UObject*> outSkeletalMeshes;
GetObjectsOfClass(USkeletalMesh::StaticClass(), outSkeletalMeshes);
TArray<UObject*> outAnimSequences;
GetObjectsOfClass(UAnimSequence::StaticClass(), outAnimSequences);
TArray<UObject*> outAnimMontages;
GetObjectsOfClass(UAnimMontage::StaticClass(), outAnimMontages);
TArray<UObject*> outAnimBp;
GetObjectsOfClass(UAnimBlueprint::StaticClass(), outAnimBp);
TArray<UObject*> outMats;
GetObjectsOfClass(UMaterial::StaticClass(), outMats);
TArray<UObject*> outBps;
GetObjectsOfClass(UMaterial::StaticClass(), outBps);
levelArray.Reserve(outTextures.Num() + outMeshes.Num() + outSkeletalMeshes.Num() + outAnimSequences.Num() + outAnimMontages.Num() + outAnimBp.Num() + outMats.Num() + outBps.Num());
for (size_t i = 0; i < outTextures.Num(); i++)
{
levelArray.Add(TStrongObjectPtr<UObject>(outTextures[i]));
}
for (size_t i = 0; i < outMeshes.Num(); i++)
{
levelArray.Add(TStrongObjectPtr<UObject>(outMeshes[i]));
}
for (size_t i = 0; i < outSkeletalMeshes.Num(); i++)
{
levelArray.Add(TStrongObjectPtr<UObject>(outSkeletalMeshes[i]));
}
for (size_t i = 0; i < outAnimSequences.Num(); i++)
{
levelArray.Add(TStrongObjectPtr<UObject>(outAnimSequences[i]));
}
for (size_t i = 0; i < outAnimMontages.Num(); i++)
{
levelArray.Add(TStrongObjectPtr<UObject>(outAnimMontages[i]));
}
for (size_t i = 0; i < outAnimBp.Num(); i++)
{
levelArray.Add(TStrongObjectPtr<UObject>(outAnimBp[i]));
}
for (size_t i = 0; i < outMats.Num(); i++)
{
levelArray.Add(TStrongObjectPtr<UObject>(outMats[i]));
}
for (size_t i = 0; i < outBps.Num(); i++)
{
levelArray.Add(TStrongObjectPtr<UObject>(outBps[i]));
}
}
}
void UMyGameInstance::DropReferenceToLevel(const FName levelName)
{
const auto* arr = _keptLevels.Find(levelName);
if (arr)
{
_keptLevels.Remove(levelName);
}
}
Note that this approach has caused my editor to crash at exit though so do with it what you will.