In my level I have several folders with sublevels like:
Persistent level
_Place1
___Floor1
___Floor2
_Place2
___Floor1
And for these sublevels I want to get full logical path like “Place1/Floor2”, but so far all I found is either how to get logical name (Floor1) or actual path (/Game/Maps/Place1_Floor2).
So is there any way of getting that subfolders hierarchy of Level?
I would create a chain of GetOuter()'s until you hit the PersistentLevel, using each ULevel to get further out (GetOuter Of ULevel)
Here’s the relevant code from my RamaSaveSystem Plugin (paid plugin on marketplace) to get you started!
You can pass in an actor that is inside your innermost level to initiate the chain, going outward, then switch to using each ULevel’s GetOuter and listing each package name along the way!
FString URamaSaveComponent::GetActorStreamingLevelPackageName()
{
AActor* Owner = GetOwner();
if(!Owner) return "No Owning Actor";
ULevel* Level = Owner->GetLevel();
if(!Level)
{
VSCREENMSG("Rama Save System, Level PTR BAD");
return "No level for Actor apparently! (should not ever see this unless actor pending delete perhaps)";
}
//Consistency if it is the persistent level
//! Causes crash if called right as a level is being hidden
if(Level->IsPersistentLevel())
{
//if(WITH_EDITOR) RS_LOG2(RamaSave,"Saved actor in", "PersistentLevel");
return "PersistentLevel";
}
//Rama Victory!!!
UObject* Package = Level->GetOuter();
if(!Package)
{
return "PersistentLevel";
}
//if(WITH_EDITOR) RS_LOG2(RamaSave,"Saved actor in", *Package->GetName());
return Package->GetName();
}
ooooh, so you’re saying you want the subfolders which you are creating in the Levels window?
very interesting! I wonder where that info is stored, if the actual levels have any association with that.
You might succeed at getting that info in an editor build, but I am not confident, yet, that it would ship with a packaged game.
If you really want this information in-game, I suggest you extend the Level Blueprint, create a custom variable, and track the folder that “Self” (each level) is in Yourself.
something like this:
/*
By Rama
*/
#pragma once
#include "Engine/LevelScriptActor.h"
#include "JoyLevel.generated.h"
UCLASS()
class AJoyLevel : public ALevelScriptActor
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Joy")
FString JoyfulFileName = "";
/** Set this to true when you want to use the copy from umap to data asset option */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Joy")
bool UseUMapWorldEnvSettings = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Joy")
FString WorldEnv;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Joy")
float LevelSettings_MagneticSparklesBrightnessMult = 1;
public:
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category="Joy Level")
void SetNewSkyActive(bool NewSky);
};
Open level blueprint of each sublevel
File → reparent → your custom class
Edit Class Defaults toolbar button (along top)
Enter the folder name for the sublevel
That will give you maximum control over this process you are doing, and give you Additional Benefits, because now you can store ANY INFO YOU WANT, per sublevel in your Levels window, and get that info ingame
Some interesting ideas there, thanks for the suggestions!
But actually I don’t care about packaged game, I just wanted to use this to clean up World Outliner while working in editor (put each actor to subfolder with name of the sublevel that actor is stored in).
So following the example from previous message result should look like this.
// Necessary includes
#include "WorldBrowserModule.h"
#include "Engine/WorldComposition.h"
#include "WorldBrowser/Private/LevelCollectionModel.h"
...
// Getting model which contains list of all SubLevels
FWorldBrowserModule& WorldBrowserModule = FModuleManager::GetModuleChecked<FWorldBrowserModule>("WorldBrowser");
TSharedPtr<FLevelCollectionModel> SharedWorldModel = WorldBrowserModule.SharedWorldModel(WorldContextObject->GetWorld());
...
// Now iterating by all SubLevels
for (TSharedPtr<FLevelModel> Child : SharedWorldModel->GetAllLevels())
{
if (Child.Get()->GetDisplayName() == "Persistent Level")
{
// Will return the name of the level - HierarchyTest from the example above
FString LevelName = WorldContextObject->GetWorld()->GetMapName();
}
else
{
// Will return HierarchyTest_Sublevel1 from the example above
FString SubLevelName = Child.Get()->GetDisplayName();
// Will return SubFolder1 from the example above
FName SubLevelPath = Child.Get()->GetFolderPath();
}
}
Now this is quite hacky way since it uses Private stuff of WorldBrowser, but it works well.
If anyone ever did care about packaged , they could use a Blueprint script (formerly blutility) with an editor trigger to do what you did, iterate through, and automatically assign to level script actor
Then, packaged game would be updated in 1 click no matter how the level evolves!