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.
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.
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.
@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.
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:
UObject
s 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.