How to get current world?

I’ve been fighting with this for the last two days. I have a static function and I want to fetch the currently active world from it (ie. the world current instance is playing in).

How does one do that consistently in editor? When I say consistently, I want the method to work in editor for standalone, single client, multiple clients and uncooked client.

Help.

This is what currently works, but there’s got to be a better way:

/*static*/
UWorld* UWorldStatics::GetActiveWorld()
{
	UWorld* world = nullptr;
#if WITH_EDITOR
	if (GIsEditor)
	{
		if (GPlayInEditorID == -1)
		{
			FWorldContext* worldContext = GEditor->GetPIEWorldContext(1);
			if (worldContext == nullptr)
			{
				if (UGameViewportClient* viewport = GEngine->GameViewport)
				{
					world = viewport->GetWorld();
				}
			}
			else
			{
				world = worldContext->World();
			}
		}
		else
		{
			FWorldContext* worldContext = GEditor->GetPIEWorldContext(GPlayInEditorID);
			if (worldContext == nullptr)
			{
				return nullptr;
			}
			world = worldContext->World();
		}
	}
	else
	{
		world = GEngine->GetCurrentPlayWorld(nullptr);
	}
#else
	world = GEngine->GetCurrentPlayWorld(nullptr);
#endif
	return world;
}
2 Likes

I’m pretty sure you want to retrieve it from a specific Actor … the “current world” has no meaning in a static function, without a world actor to provide context.

I’m well aware of that, but it’s a statoc function that doesn’t have a reference to any actor. Each instance of the game (PIE client, standalone, uncooked, release build) should have a (global, static) reference to currently active world. I’m looking for a simpler way to get it than what I’m currently doing.

doesn’t have a reference to any actor

and without that reference, how are you going to tell the engine which world you want?

currently active world

There is the possibility of multiple World instances existing at the same time. You need something to provide the context for which World instance you want. There isn’t a “currently active World”.

There’s GEngine->GetWorldFromContextObject() to retrieve the World from static, but without a UObject that clearly exists in a specific World instance, you’re not able to use that. And with your solution, you’re not necessarily guaranteed to get the World instance that you want. (other than PIE, I’m not sure what other conditions can cause there to be multiple Worlds, but it is possible)

This is usually resolved by passing in the ‘this’ of whatever is making the call, as the context object for GetWorldFromContextObject.

2 Likes

Well, some level currently has to be loaded. And that level has to be a part of some world, no? There has to be a world that is currently being used in an instance.

I got the GPlayInEditorID that is unique for every instance, but that seems to be unreliable for standalone and for the first client (it’s -1 sometimes), so I had to do some nasty stuff to make it work, as you can see above.

I can’t believe that the editor engine doesn’t somehow >reliably< differentiante between multiple instances of clients (or standalones for that matter).

There has to be some kind of ID or something I can use to get the world context in a static way for current, relevant, world.

No, there is not a current, relevant, World. There can be multiple Worlds instanced simultaneously.

The World context is only relevant to objects contained within that World, so you have to have something in that World to be able to get at the pointer to that World.

Where are you calling this static function from? If something inside a world, use that as your context reference. Ultimately, some piece of code that is actually loaded somewhere in the World has to be in the chain somewhere.

2 Likes
FWorldContext* world = GEngine->GetWorldContextFromGameViewport(GEngine->GameViewport);

world->World();
9 Likes

That assumes you have a GameViewport. What if you don’t have one of those?

You need to do it in the context of the code you are running.

Following the code in GameplayStatics:GetGameState

they use BlueprintPure, with meta=(WorldContext=“WorldContextObject”)

So, the Context is automatically supplied by blueprints and the node is a pure node with no inputs (Even though it is declared as an argument in the function signature… which would usually create 1 input, this does not create the input with the WorldContext meta option)

	UFUNCTION(BlueprintPure, Category="Game", meta=(WorldContext="WorldContextObject"))
	static class AGameStateBase* GetGameState(const UObject* WorldContextObject);

and the impl looks like

UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
	return World ? World->GetGameState() : nullptr;

where they use GEngine->GetWorldFromContextObject, and using the argument supplied automatically by blueprints to find the World.

In what situation would we not have a viewport though? I feel like if there’s no viewport then we have bigger problems.

Two words: Dedicated servers.

In that case,

FWorldContext* world =
IsRunningDedicatedServer() ? GEngine->GetWorldContextFromGameViewport(GEngine->GameViewport) : nullptr;

world->World();

You would still need a world context though, I’m sure.

Generally, I’d do something like this. Universal function but you still need context

static UWorld* UWorldStatics::GetActiveWorld(UObject* InContext)
{
        if(AGameStateBase* LocGameState = UGameplayStatics::GetGameState(InContext))
        {
                return LocGameState->GetWorld();
        }

        return nullptr;
}