Child Actor Components crash resave commandlet

This question was created in reference to: [ResavePackages fixredirects commandlet crashes Assertion failed: [Content removed]

Hey, resurrecting an old thread here, but can we get an update on when Child Actor Components and the resave commandlets will work together

We’ve got a few usages of child actor components where we want to dynamically populate visual only actors along with functional actors.

We have pick ups which use a generic blueprint type which just apply different GAS effects, and we want to be able to spawn in different visuals for those without re-creating the visual logic per pickup type.

We also have a character customization setup which spawns in a visual character actor as a child of our Pawn, that visual actor is responsible for constructing the visual based on various player customization choices (We’re looking to port this over to use Mutable potentially)

Having these however, means we can’t use the resave packages commandlet to do things like cleanup redirectors, re-serialize assets to avoid bloating our CoreRedirects, or bake lighting in our CI builds, as these all run through the resavepackages commandlet

Thanks

[Attachment Removed]

Steps to Reproduce

  • Create a blueprint with ChildActorComponent
  • Add ChildActorComponent to level
  • Run resavepackages commandlet
  • commandlet crashes with error [Assertion failed: [Content removed]
    [Attachment Removed]

Hello!

I spent some time debugging and found that the problem was related to the Child Actors being part of the same external package than their Parent. This made it that the Parent’s external package was processed multiple times in the loop and causes the check to fire. The following code should help:

//Engine\Source\Editor\UnrealEd\Private\Commandlets\ContentCommandlets.cpp (line 1962-1977)
	// Load and Save Level's external packages
 	if (!bResaveWorldPartitionExternalPackages && bAllowExternalPackageResaves)
	{
		// Use a default GC frequency for external actors if GarbageCollectionFrequency is 0.
		TGuardValue<int32> ScopedGCFreq(GarbageCollectionFrequency, GarbageCollectionFrequency ? GarbageCollectionFrequency : DefaultExternalActorGCFreq);
 
		World->AddToRoot();
 
		//for (UPackage* Package : World->PersistentLevel->GetPackage()->GetExternalPackages())
 
//Bug Workaround: Make sure the list of packages contains unique entries to avoid resaving the same package multiple times. Child Actors (ChildActorComponent) are being saved in their Parent's external package which will cause the check to fail. 
		TSet<UPackage*> UniquePackages(World->PersistentLevel->GetPackage()->GetExternalPackages());
		for (UPackage* Package : UniquePackages)
		{
			++TotalPackagesForResave;
			const FString PackageFilename = Package->GetLoadedPath().GetLocalFullPath();
			check(FLinkerLoad::FindExistingLinkerForPackage(Package));
			LoadAndSaveOnePackage(PackageFilename);
		}
		World->RemoveFromRoot();
	}

The alternative would be to run the commandlet with the -NoExternalPackages argument to avoid resaving external packages during the commandlet and manually resave the affected levels from the Content Browser.

Regards,

Martin

[Attachment Removed]

Hello!

The engine team fixed the source of the problem so that GetExternalPackage returns an array of unique entries. You can integrate CL#51227171 or GH Commit.

Regards,

Martin

[Attachment Removed]

Thanks Martin,

Any chance this will be making it into an engine release?

I’d like this change so we can start to use the ResavePackages commandlet, but not wanting to put it in our repo as a divergence to get support for it

Thanks!

[Attachment Removed]