Can you use a Blueprint Function Library in an Object Class

I needed to do it like this to be able to use nodes like (SpawnAIFromClass, SetTimerByFunctionName), because the GetLevel() didn't work and threw a Warning 




UWorld* UWorldObject::GetWorld() const {
	// CDO objects do not belong to a world
	// If the actors outer is destroyed or unreachable we are shutting down and the world should be nullptr
	if (!HasAnyFlags(RF_ClassDefaultObject) && ensureMsgf(GetOuter(), TEXT("Actor: %s has a null OuterPrivate in AActor::GetWorld()"), *GetFullName())
		&& !GetOuter()->HasAnyFlags(RF_BeginDestroyed) && !GetOuter()->IsUnreachable())
	{
		return GetOuter()->GetWorld();
	}
	return nullptr;
}

Spider senses are tingling …

I need objects derived from UObject to access functions (SpawnAIFromClass, SetTimerByFunctionName), these objects are properties of my GameInstance implementation.

The code:

if (ULevel* Level = GetLevel())

It gives me an error since it does not find the level.

So if I do what it says above

GetOuter()->GetWorld();

will it give me an error?

It’s not about “giving an error” at compile time.

It’s about what the engine rules are at runtime. When you break those rules, you will end up with something between “random crash reports from users that you can’t reproduce locally” and “memory leaks that won’t go away.”

Ok, I understand, I’ll see what I do then, thanks for the warning!

You can do it like this:

Oh. I see quality of image is ■■■■.

From right to left : Blueprint function library, have function to compare my own struct - i want to use this in Database object at left.

Middle screen have gamemode bluepirnt, witch created data base object, and saved self reference in variable. In gamemode blueprint i created function that use blueprint function library function - this is important, to use this function, not create new one, so you have to change only one function, when you need to add something to function (in my example, structure growth, and need to compare more variables inside).

Database object use gamemode ref variable to call function that use
blueprint function library compare function.

Your Object needs its own “World Context”, This is how you can do that in c++

.h file

#pragma once

#include "CoreMinimal.h"
#include "UObject/Object.h"

#include "RRObject.generated.h"
/**
 * 
 */
UCLASS(BlueprintType, Blueprintable)
class IKEABR_SERVER_API URRObject : public UObject
{
	GENERATED_BODY()

protected:
	struct FWorldContext* WorldContext;


	UFUNCTION(BlueprintCallable)
		void SetWorldContext(UObject* NewWorldContext);

	UFUNCTION(BlueprintCallable)
		UObject* GetWorldContextObject();

	//~ Begin UObject Interface
	virtual class UWorld* GetWorld() const final;
	struct FWorldContext* GetWorldContext() const { return WorldContext; };
	
};

.cpp file

#include "RRObject.h"

void URRObject::SetWorldContext(UObject* NewWorldContext)
{
        WorldContext = new FWorldContext();
	WorldContext->SetCurrentWorld(NewWorldContext->GetWorld());
}

UObject* URRObject::GetWorldContextObject()
{
	return WorldContext->World();
}

class UWorld* URRObject::GetWorld() const
{
	return WorldContext ? WorldContext->World() : NULL;
}

Then set the world context object with “SetWorldContext” from somewhere else (like the game instance) and you can call blueprint function library functions within any child blueprints of this class.

2 Likes

Recently, it feels like I’m collecting this Blueprint bugs and limitations, lol
It’s a bump. This should not be a thing. But it is, for 6 years at least. Once again.

This worked beautifully, thanks!

The smallest solution I came up with is

UWorld* UMyClass::GetWorld() const
{
#if WITH_EDITOR
  if (IsTemplate()) 
  {
    return nullptr;
  } 
#endif
  
  return Super::GetWorld();
} 

The solution is to not call GetWorld on anything that doesn’t override it.
In the graph editor, IsTemplate() is true, so we return nullptr and avoid the call to Super::GetWorld(). While at runtime, with an instance of our class, we keep using the base class function to use some other outer object’s GetWorld, if there’s one.

I avoid the call to IsTemplate() on a packaged game because otherwise we’d traverse the chain of outer objects always twice.

4 Likes

You can also add "Meta=(ShowWorldContextPin) " to your custom UObject class and it will allow you to call BP Library functions without needing to implement the GetWorld() function.

There are cases where your UObject doesn’t actually belong to a world in which case you need to grab the world through some other context.

12 Likes

@Burnrate In this time of doubt and darkness, some people bring a little light into our daily lives. You are one of those people and I bless you for that.

1 Like

If it helps.
In my project I have a BPFL implemented in C++, with few static functions in it.
And I noticed that these functions are visible inside blueprints derived from UObject (even though, as the thread comfirms, blueprint-implemented BPFL functions aren’t).
Maybe it can lead someone to something useful.

p.s. @Burnrate’s solution worked for me, big thanks! Here is the code for anyone who needs it:

UCLASS(Blueprintable, Meta=(ShowWorldContextPin))
class YOUR_API UObjectWithContext : public UObject
{
	GENERATED_BODY()	
};

Is there a solution for this problem for those of us who don’t use C++? I’m a blueprint developer and would love to be able to access my function libraries from inside object classes.

Works like a charm & also makes sense! Thank you!

You can actually call it if you also override UObject::ImplementsGetWorld() (note that the method is guarded with #if WITH_EDITOR).

I’ll wrap the information out a bit as it’s all scattered across multiple posts and it’s a bit hard to follow right now:

UObjects have a safety mechanism that disallows you from using any function that uses a WorldContextObject internally, as it’s possible that the world is invalid in a UObject and that would cause a crash.

However, you may know what you’re doing and may be perfectly safe to do so.

In that case, you must override the UObject::GetWorld function. But be careful! Because depending on how you override it, you may still have the same problem.

The default UObject::GetWorld() sets a flag that identifies that method as the default method. So if you override GetWorld() with Super::GetWorld() you’re gonna have the same problem, because that flag will still be set. Same if you override it with GetOuter()->GetWorld() as that’s gonna use the default GetWorld() implementation of the outer object. Even if you expect your object’s outer to be an actor, the default object (which is the one you’ll be modifying in blueprint) won’t have that outer.

Then, there’s this other virtual method, UObject::ImplementsGetWorld():

#if WITH_EDITOR
bool UObject::ImplementsGetWorld() const
{
	bGetWorldOverridden = true;
	GetWorld();
	return bGetWorldOverridden;
}
#endif // #if WITH_EDITOR

So as you can see, it’s going to assume the GetWorld is overridden and then actually call the implementation. As the default method sets bGetWorldOverriden = false, ImplementsGetWorld will return false as the world hasn’t been overridden.

If you really have to, you can always override UObject::ImplementsGetWorld() to always return true. This way, you can still return the outer’s world & use static methods that require the WorldContextObject.

My suggestion though is implementing the method like this (based on the Actor’s implementation):

UWorld* UMyCustomObject::GetWorld() const
{
	// CDO objects do not have a world.
    // If the object outer is destroyed or unreachable we are likely shutting down and the world should be nullptr.

	if (UObject* Outer = GetOuter())
	{
		if (!HasAnyFlags(RF_ClassDefaultObject)
			&& !Outer->HasAnyFlags(RF_BeginDestroyed)
			&& !Outer->IsUnreachable())
		{
			return Outer->GetWorld();
		}
	}

	return nullptr;
}

This way we make sure that the default object doesn’t get in the way and we can still have the outer’s GetWorld() implementation (as if it’s an Actor, for example, the default implementation won’t set bGetWorldOverriden = false). As you can see it all depends a bit of your problem’s context.

Of course, this safety mechanism is there for a reason. Make sure that the world you’re returning exists and it’s consistent if you’re going to call these functions or otherwise you’ll be having a crashy engine.

For blueprint-only users though, I don’t think there’s a way around this. If all of this sounds way too advanced, maybe you can have your class inherit from AInfo instead which is a special kind of Actor that doesn’t have a physical representation. This way you can still modify the blueprint but you don’t have this limitation of uobjects, as actors are spawned into a world, unlike uobjects. That class is thought more for manager classes though, but maybe it works for you.

1 Like