GetWorld() returns null within a UWorldSubsystem

I have a subsystem that inherits from UWorldSubsystem call UMySubsystem. Within an actor, I grab the subsystem and call a member function like so

if(GetWorld()) {
  UMySubsystem* MySubsystem = GetWorld()->GetSubsystem<UMySubsystem>();

  if(MySubsystem) {
    MySubsystem->Callfunc();
  }
}

That member function attempts to GetWorld() which returns a nullptr

void UMySubsystem::CallFunc() {
  // GetWorld() returns null here?!
  if(!GetWorld()) {
    ...
  }
}

How is that possible? I just used GetWorld() in order to retrieve the subsystem but the subsystem itself doesn’t know about the world?

When are you calling your function? It needs to be around begin play for the world to exist.

.h

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/WorldSubsystem.h"
#include "MyWorldSubsystem.generated.h"

UCLASS()
class YOUR_API UMyWorldSubsystem : public UWorldSubsystem
{
	GENERATED_BODY()
public:
	UFUNCTION(BlueprintCallable)
	void CallFunc();
	
};

.cpp

#include "MyWorldSubsystem.h"

void UMyWorldSubsystem::CallFunc()
{
	// GetWorld() returns null here?!
	if(!GetWorld())
	{
		GEngine->AddOnScreenDebugMessage(1, 4, FColor::Red, "World is null");
	} else
	{
		GEngine->AddOnScreenDebugMessage(1, 4, FColor::Green, "World is ok");
	}
}

Tester class

.h

just basic actor header

.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "WorldTester.h"
#include "MyWorldSubsystem.h"

// important 

void AWorldTester::BeginPlay()
{
	Super::BeginPlay();

	UMyWorldSubsystem * ws = GetWorld()->GetSubsystem<UMyWorldSubsystem>();
	ws->CallFunc();
}

Gives info

image

Thanks for the detailed response. Let’s add a little more depth now…

There is no “BeginPlay” for my actor per say. The actor in question is a sub-class of AFunctionalTest as this is a functional unit test. StartTest is the function you override and put your test logic inside of. That’s where I’m retrieving the subsystem and calling its member function.

void UMyFunctionalTest::StartTest() {
  Super::StartTest();

  if(GetWorld()) {
    UMySubsystem* MySubsystem = GetWorld()->GetSubsystem<UMySubsystem>();

    if(MySubsystem) {
      MySubsystem->Callfunc();
    }
  }
}

I then have an instance of UMyFunctionalTest dropped into an empty map (with FTEST_ as the prefix) and the automatio system picks it up. I launch the test from the session/automation frontend

I would point out that the functional test has no problem getting the world in order to retrieve the subsystem. It doesn’t make sense that the subsystem would then get a nullptr from GetWorld().

Question: how are you triggering StartTest? It’s not firing by default if I inherit from AFunctionalTest
Tick is enabled and it looks like it should execute but I’m not getting anything on my end.

Ok just noticed the session/automation part. I’ll look into it.

You can get the world context and world from the viewport

just added an int32 key in header to keep track of separate messages.

void AWorldTester::StartTest()
{
	Super::StartTest();

	FWorldContext* WorldContext = GEngine->GetWorldContextFromGameViewport(GEngine->GameViewport);
	if (WorldContext)
	{;
		if (UWorld* World = WorldContext->World())
		{
			GEngine->AddOnScreenDebugMessage(key,2, FColor::Green,TEXT("World ok") + FString::FromInt(key));
			key++;
			UMyWorldSubsystem * WS = World->GetSubsystem<UMyWorldSubsystem>();
			if (WS)
			{
				GEngine->AddOnScreenDebugMessage(key,2, FColor::Green,TEXT("World subsystem is ok") + FString::FromInt(key));
				key++;
				WS->CallFunc();
			}
			
		}
	}
}

Upon triggering the test

Apologies for the late response and thanks again for the effort. Let’s clear one thing up and mark this done.

So I don’t have an issue with GetWorld() under the StartTest function. This works just fine…

void UMyFunctionalTest::StartTest() {
  Super::StartTest();

  if(GetWorld()) {  // This works just fine
    UMySubsystem* MySubsystem = GetWorld()->GetSubsystem<UMySubsystem>();

    if(MySubsystem) {
      MySubsystem->Callfunc();  // The issue is in here
    }
  }
}

The issue is with the CallFunc method. A call to GetWorld() in there is what fails for me.

void UMySubsystem::CallFunc() {
  if(GetWorld()) {  // This fails for me
    ...
  }
}

It’s as if the subsystem does not have an “Outer” from which to get the world from. I only see this during the functional test. Is this not what you’re seeing with yours?

It’s also possible that your calls to add the screen debug message is allowing some frames to pass such that everything is “caught up”. I’m only printing to a log file when GetWorld() fails. Maybe I’m just hitting an odd race condition.

I have no problems with my code. The test works as expected. The world is valid inside of callFunc while the test is running

WorldTester.h (607 Bytes)

WorldTester.cpp (1.3 KB)

MyWorldSubsystem.h (363 Bytes)

MyWorldSubsystem.cpp (366 Bytes)

Just swap the _API for tests

Please elaborate on what type of class UMyFunctionalTest is. Seeming you mention dropping it into the world is it inherited from a UActorComponent inside of an actor? Mine is directly an actor.
Both should have UWorld accessible either way.

The class to extend is AFunctionalTest so it’s based on an actor class not a component class or uobject based. (it’s spawnable in the world). There is no U prefix, hence my confusion about what you are trying to achieve.

The only way where you would have a problem is if it was a UBlueprintFunctionLibrary. You can’t place them in the world though and would need to pass world context objects in the functions called inside of it.