[SOLVED[ Getworld() from static function without pass an Object

Hi! I am slowly moving from Blueprint to C++ and I have a question:

I have a blueprint function library with a function were I give a couple float values and it returns another float result doing math with ‘time since creation’ of ‘playercontroller’

I am trying to do the same from a C++ function library but the only way I found of get world context is passing any object to the function so i can get world context of that object.

I want to do exactly the same I achieve with blueprints that means not passing any object to get the world contexts. I tried to use ‘this’ as reference but the engine dont allow because is a static function. Any help?

here is what i have working so far…i send a ‘Me’ object but i want to avoid sending any object.

float MyBPLibrary::WaveIt(AActor* Me, float TimeOffset , float Frequency, float Amplitude)
{
UObject* WorldContextObject = (UObject*)Me;
float TimeSinceCreation = WorldContextObject->GetWorld()->GetFirstPlayerController()->GetGameTimeSinceCreation();
return sin(FMath::DegreesToRadians((TimeSinceCreation+TimeOffset) * Frequency))*Amplitude;

}

Thanks!

1 Like

Solution:

float MyBPLibrary::WaveIt(float TimeOffset , float Frequency, float Amplitude)
{
UWorld* world = GEngine->GameViewport->GetWorld(); // ← this is the magic line!
float TimeSinceCreation = world->GetFirstPlayerController()->GetGameTimeSinceCreation();
return sin(FMath::DegreesToRadians((TimeSinceCreation + TimeOffset) * Frequency)) * Amplitude;
}

11 Likes

For those who have a hard time reading unformatted code:

Problem:

float MyBPLibrary::WaveIt(AActor* Me, float TimeOffset , float Frequency, float Amplitude)
{
    UObject* WorldContextObject = (UObject*)Me;
    float TimeSinceCreation = WorldContextObject->GetWorld()->GetFirstPlayerController()->GetGameTimeSinceCreation();

    return sin(FMath::DegreesToRadians((TimeSinceCreation + TimeOffset) * Frequency)) * Amplitude;

}

Solution:

float MyBPLibrary::WaveIt(float TimeOffset , float Frequency, float Amplitude)
{
    UWorld* world = GEngine->GameViewport->GetWorld(); // ← this is the magic line
    float TimeSinceCreation = world->GetFirstPlayerController()->GetGameTimeSinceCreation();

    return sin(FMath::DegreesToRadians((TimeSinceCreation + TimeOffset) * Frequency)) * Amplitude;
}
2 Likes

Your first solution was more correct. You shouldn’t be using GEngine for things like this, it can cause you no end of grief when working with PIE sessions, local multi-player instances or any potential editor tools.

The main change you should make is that your function signature should use UObject *WorldContextObject instead of AActor *Me. In blueprint you can make this parameter invisible with the WorldContextObject = "param_name" meta data, but in C++ you’ll always need to be passing something (usually there’s a convenient object or the local this pointer).

You can then get a UWorld from the Engine with GEngine->GetWorldFromContextObject.

This more closely matches the patterns established by similar engine functions that require getting data from an associated UWorld.

2 Likes

I have used my original WaveIT function with the GEngine approach A LOT since this solution in different scenarios (PIE, compiled, windows, android) and I have never had any problem.

Works perfect.

That is great! I hope that never changes.

I guess my point was to provide some context for anyone else finding this thread as this solution does have potential drawbacks.

  1. Use of global variables (even if engine provided) is a potential source of problems (not GEngine specifically, but members of it that you have no control over).
  2. If this were the best solution to the problem, Epic code would do this to avoid unnecessary passing of context variables. But they don’t.
  3. There are still circumstances where this can bite you. There is a comment on that variable that explicitly states that it could be null and that you should check it before use. So cases like unviewable processes like tools or dedicated servers that don’t need viewports probably don’t have one for you to access here.

Again, if it’s working for you that’s great. It’s not going to work for everyone and I thought it important that information was included for anyone else that comes upon this thread in the future. (of course I only saw it because of Willard necro’ing it with formatted code)

3 Likes
UFUNCTION(BlueprintCallable, meta=( WorldContext = "Context" ))
	static void StaticDoSomething(UObject* Context);
UMyBPLib::StaticDoSomething(UObject* Context)
{
    if ( IsValid(Context) )
    {
        Context->GetWorld(); // do stuff with World...
    }
}
5 Likes

I guess this would do.

    if (!IsValid(GEngine))
    {
        UE_LOG(LogTemp, Error, TEXT("UMessageBox::Show GEngine is NULL"));
	    return;
    }

where UMessageBox::Show is current class+method name or just function name.

Anyways in cases where you don’t have World (tools, server, etc.) you don’t want to call this function and it was an mistake.

My intention was to create helper to show “Message Box” to player. In case of some errors.