Create Packed Level Actor via C++ or Python

`void UCarlFunctionsBPLibrary::CreatePackedLevelActorFromSelection()
{

UWorld* World = GEditor->GetEditorWorldContext().World();
if (!World)
    return;


TArray<AActor*> SelectedActors;
GEditor->GetSelectedActors()->GetSelectedObjects<AActor>(SelectedActors);


if (SelectedActors.Num() == 0)
    return;


UE_LOG(LogTemp, Log, TEXT("Create Packed Level Actor: %d"), SelectedActors.Num());`

Steps to Reproduce

Hi,

I want to run the “Create Packed Level Actor” functionality with C++ or maybe even with Python. The easier path would be probably C++ and from Python I can simply run that function from my library functions.

Like:

unreal.MyToolsBPLibrary.create_packed_level_actor_from_selection()

I tried out a lot to get the “Create Packed Level Actor” function to run but I could not get it really to work. So simple example would be enough here.

Unfortunately I cannot edit my code snippet from above anymore. I am not getting out of the code widget. The code simple collects the selected actors. These actors needs to be in the packed level actor. But as I said, I simply need that logic behind the “Create Packed Level Actor” running.

Additionally ii would be maybe good to bypass the save popups to define own paths to save.

Thanks a lot for the help!

Hi Jan,

You can find the logic behind the “Create Packed Level Actor” command on file [Engine\Source\Editor\LevelInstanceEditor\Private\LevelInstanceEditorModule.cpp] in function LevelInstanceMenuUtils::CreateLevelInstanceFromSelection(). This function is not exported, but it basically uses a dialog box to get some options from the user, then calls ULevelInstanceSubsystem::CreateLevelInstanceFrom() to do the actual work. Here’s a simple example implementation you can use as a starting point in your Blueprint Function Library:

`#include “Subsystems/EditorActorSubsystem.h”
include “Subsystems/UnrealEditorSubsystem.h”
include “LevelInstance/LevelInstanceSubsystem.h”
include “PackedLevelActor/PackedLevelActor.h”

APackedLevelActor* MyBPLibrary::CreatePackedLevelActorFromSelection(const FString& LevelPackageName)
{
UUnrealEditorSubsystem* UES = GEditor->GetEditorSubsystem();
UWorld* World = UES->GetEditorWorld();

UEditorActorSubsystem* EAS = GEditor->GetEditorSubsystem();
TArray<AActor*> SelectedActors = EAS->GetSelectedLevelActors();

FNewLevelInstanceParams Params;
Params.Type = ELevelInstanceCreationType::PackedLevelActor;
Params.PivotType = ELevelInstancePivotType::CenterMinZ;
Params.LevelInstanceClass = APackedLevelActor::StaticClass();
Params.SetForceExternalActors(World->IsPartitionedWorld());
if (!LevelPackageName.IsEmpty())
{
Params.bAlwaysShowDialog = false;
Params.LevelPackageName = LevelPackageName;
}

ULevelInstanceSubsystem* LIS = World->GetSubsystem();
ILevelInstanceInterface* LevelInstance = LIS->CreateLevelInstanceFrom(SelectedActors, Params);

return Cast(LevelInstance);
}`Note that Epic encourages using Subsystems for your scripting needs whenever possible, so in my snippet above I used UUnrealEditorSubsystem to get the editor world, UEditorActorSubsystem to get the selected actors, and ULevelInstanceSubsystem to create the Packed Level Actor.

Also note that the implementation of LevelInstanceMenuUtils::CreateLevelInstanceFromSelection() uses other non-exported classes like ULevelInstanceEditorPerProjectUserSettings, ULevelInstanceEditorSettings, and SNewLevelInstanceDialog. If you’d like to replicate its behavior completely, you’d have to edit the engine source code to export them, or implement your own UI to get options from the user.

Finally, I noticed that there is a bug when setting the following options to suppress the save popups:

Params.bAlwaysShowDialog = false; Params.LevelPackageName = LevelPackageName;Even with these options, “Params.LevelPackageName” will be ignored and a “save as” popup will still appear for the new level, and the new blueprint will be automatically saved with prefix “BPP_” followed by that same name. If you are able to edit the engine source code, the fix should be simple: in file [Engine\Source\Runtime\Engine\Private\LevelInstance\LevelInstanceSubsystem.cpp], line 1416, where structure EditorLevelUtils::FCreateNewStreamingLevelForWorldParams is being filled, the “bUseSaveAs” field should be:

CreateNewStreamingLevelParams.bUseSaveAs = LevelFilename.IsEmpty();I hope this is helpful. Please let me know if you need any further assistance.

Best regards,

Vitor

By the way, I created an internal bug report for the bug I mentione. Here’s the public bug tracker link: UE-309562. It should become available once the engine devs mark it as public.

Hi [mention removed]​,

the code and the engine fix works very good for me. Thanks for your help!