C++ Custom class derived blueprint will not cast into base type

I have a type defined thus:


 
    UCLASS(Blueprintable)
class ROGUELIKE_API UAbility : public UObject
{ ..... 


With a series of properties and functions. In the editor, I have created a new blueprint derived from this class.

When I try to load a reference to this blueprint in C++, casting to UAbility always fails, despite it seemingly being a derived type.

The code I am using to load this type:


 
    FStringAssetReference chargeReference = "Blueprint'/Game/Content/Abilities/Charge/ChargeAbility.ChargeAbility'";
StaticLoadObject(UObject::StaticClass(), nullptr, *chargeReference.ToString());

UObject* chargeReferenceObj = chargeReference.ResolveObject();
UBlueprint* chargeAbilityBlueprint = Cast<UBlueprint>(chargeReferenceObj);

UAbility* chargeCast = Cast<UAbility>(chargeAbilityBlueprint);

In the above example, chargeAbilityBlueprint is a pointer to an actual object, but chargeCast is NULL. Trying to get a UAbility type by replacing UBlueprint with UAbility also results in a null object.

Any suggestions would be greatly appreciated!

UBlueprint class has no use for this. Try:



FStringAssetReference chargeReference = "/Game/Content/Abilities/Charge/ChargeAbility.ChargeAbility";

UObject* chargeReferenceObj = chargeReference.**TryLoad**();

if (chargeReferenceObj) {
   UAbility* chargeCast = Cast<UAbility>(chargeReferenceObj);
}


Pretty sure you need to get rid of the Blueprint’ in the path aswell, or at least it’s not needed, I don’t have anything like it in any of my code and it works fine.

Yes, I just copy/paste his url. Didn’t really read it :slight_smile:

Hey guys - thanks for the posts, sorry for late response. Sadly, it doesn’t work. chargeCast is a null object the line after the cast. Any ideas?

A picture of me inspecting the reference object at runtime, after it has been loaded. The type appears to be blueprint, which I suppose is correct, but it’s a blueprint with UAbility as a parent type…

Try this:


UAbility* Blah = LoadObject<UAbility>(nullptr, TEXT("/Game/Content/Abilities/Charge/ChargeAbility.ChargeAbility_C"));

Also has Blah being a NULL object. Really unsure as to where this is going wrong!

Interestingly, the object can cast into a Blueprint without throwing an error. The parent class is absolutely Ability, as shown in this screen from within the editor:

I’m fairly sure that Blueprints boil down to UClasses don’t they, not instances of a given type? That might be why it’s failing. If not, then Zeblote’s code should work but you should probably provide an outer or it’ll just get garbage-collected unless it’s strongly referenced anywhere.

To be honest it’s bad practice to use String Asset References in code (or any kind of hard reference to content for that matter) anyway. Use TSubclassOf or TAssetPtr instead and get or load the object from there.

Also if this asset is used during gameplay, you probably don’t want to be loading it during game time either - so use TSubclassOf and set the class in the editor:



UPROPERTY(EditAnywhere, Category = "My Classes")
TSubclassOf<UAbility> AbilityBlueprint;


Having an outer object prevents garbage collection? That’s news to me, but it makes so much sense…

A UBlueprint object contains the information for the Blueprint, it isn’t the final compiled class. You want Blueprint->GeneratedClass for that.

So, using the OP’s original code:



FStringAssetReference chargeReference = "Blueprint'/Game/Content/Abilities/Charge/ChargeAbility.ChargeAbility'";
StaticLoadObject(UObject::StaticClass(), nullptr, *chargeReference.ToString());
UObject* chargeReferenceObj = chargeReference.ResolveObject();

UBlueprint* chargeAbilityBlueprint = Cast<UBlueprint>(chargeReferenceObj);

UAbility* chargeCast = Cast<UAbility>(chargeAbilityBlueprint->GeneratedClass); // GeneratedClass should be valid as Blueprints get compiled at start up, but you can toss an if check if you want to be super safe.


Apologies for the late response. Strangely, that also doesn’t work. In the example provided, chargeCast is a NULL object. The generated class is not, so the cast must be failing. We can see that the chargeAbilityBlueprint is, at this point, is derived from ability:

Any other thoughts? This particular issue is driving me crazy

Ah, sorry. Just went and checked the code again and it should be the following:



StringAssetReference chargeReference = "Blueprint'/Game/Content/Abilities/Charge/ChargeAbility.ChargeAbility'";
StaticLoadObject(UObject::StaticClass(), nullptr, *chargeReference.ToString());
UObject* chargeReferenceObj = chargeReference.ResolveObject();
UBlueprint* chargeAbilityBlueprint = Cast<UBlueprint>(chargeReferenceObj);
UAbility* chargeCast = Cast<UAbility>(chargeAbilityBlueprint->GeneratedClass->**GetDefaultObject()**);


2 Likes

I think there are actually 2 problems here.

  1. UBlueprint does not exist in non-editor builds.
  2. Blueprints contain UClasses, you have to make an instance first.

Next try at getting that code correct:


UClass* AbilityClass = LoadObject<UClass>(nullptr, TEXT("/Game/Content/Abilities/Charge/ChargeAbility.ChargeAbility_C"));
UAbility* Ability = NewObject<UAbility>(nullptr, AbilityClass);

The suggested by ExtraLifeMatt seems to have worked, but the last suggestion, Zeblote, seems to cause a crash.

The default suggestion does create objects with strange “names” when debugging but seems to work. Many thanks!