Download

Placing an object from the ContentBrowser into the world in an Editor Plugin

Hello,

I am trying to build a plugin so that an XML file can be used to place Blueprints in the level. THis seems trivial enough but seems fraught with difficulty.

Having battled from Hamads plugin and got that working in 4.6.1 I can’t find a way of locating the Blueprint, from it’s name, in the content browser. I have tried calling this:


ConstructorHelpers::FObjectFinder<UBlueprint> MyBlueprint(TEXT("/UnityBP/Gen_Apple_A"));

Which leads to unresolved externals:


1>     Creating library C:\UDK\TMP\MAIN\Intermediate\Build\Win64\UDKRenderTestEditor\Development\Plugins\Dynamic\UE4Editor-HamadsPlugin.lib and object C:\UDK\TMP\MAIN\Intermediate\Build\Win64\UDKRenderTestEditor\Development\Plugins\Dynamic\UE4Editor-HamadsPlugin.exp
1>HamadsPlugin.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) class UObject * __cdecl StaticLoadObject(class UClass *,class UObject *,wchar_t const *,wchar_t const *,unsigned int,class UPackageMap *,bool)" (__imp_?StaticLoadObject@@YAPEAVUObject@@PEAVUClass@@PEAV1@PEB_W2IPEAVUPackageMap@@_N@Z) referenced in function "class UBlueprint * __cdecl ConstructorHelpersInternal::FindOrLoadObject<class UBlueprint>(class FString &)" (??$FindOrLoadObject@VUBlueprint@@@ConstructorHelpersInternal@@YAPEAVUBlueprint@@AEAVFString@@@Z)
1>HamadsPlugin.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: class UObject * __cdecl UClass::GetDefaultObject(bool)" (__imp_?GetDefaultObject@UClass@@QEAAPEAVUObject@@_N@Z) referenced in function "class UBlueprint * __cdecl ConstructorHelpersInternal::FindOrLoadObject<class UBlueprint>(class FString &)" (??$FindOrLoadObject@VUBlueprint@@@ConstructorHelpersInternal@@YAPEAVUBlueprint@@AEAVFString@@@Z)
1>HamadsPlugin.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: static void __cdecl ConstructorHelpers::StripObjectClass(class FString &,bool)" (__imp_?StripObjectClass@ConstructorHelpers@@SAXAEAVFString@@_N@Z) referenced in function "public: __cdecl ConstructorHelpers::FObjectFinder<class UBlueprint>::FObjectFinder<class UBlueprint>(wchar_t const *)" (??0?$FObjectFinder@VUBlueprint@@@ConstructorHelpers@@QEAA@PEB_W@Z)
1>HamadsPlugin.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) private: static void __cdecl ConstructorHelpers::ValidateObject(class UObject *,class FString const &,wchar_t const *)" (__imp_?ValidateObject@ConstructorHelpers@@CAXPEAVUObject@@AEBVFString@@PEB_W@Z) referenced in function "public: __cdecl ConstructorHelpers::FObjectFinder<class UBlueprint>::FObjectFinder<class UBlueprint>(wchar_t const *)" (??0?$FObjectFinder@VUBlueprint@@@ConstructorHelpers@@QEAA@PEB_W@Z)
1>HamadsPlugin.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) private: static void __cdecl ConstructorHelpers::CheckIfIsInConstructor(wchar_t const *)" (__imp_?CheckIfIsInConstructor@ConstructorHelpers@@CAXPEB_W@Z) referenced in function "public: __cdecl ConstructorHelpers::FObjectFinder<class UBlueprint>::FObjectFinder<class UBlueprint>(wchar_t const *)" (??0?$FObjectFinder@VUBlueprint@@@ConstructorHelpers@@QEAA@PEB_W@Z)
1>C:\UDK\TMP\MAIN\Plugins\HamadsPlugin\Binaries\Win64\UE4Editor-HamadsPlugin.dll : fatal error LNK1120: 5 unresolved externals


I’ve also read that this can only be called in an object’s constructor class, not during my button click event. How do I get a refernce to a Blueprint, from it’s name, in an editor plugin?

Secondly, once I have that, how do I spawn it into the current level? I’m presuming the basic SpawnActor call won’t work? Or will it?

Any help greatly appreciated because such a simple task is proving to be nightmarishly difficult!

The functions StaticLoadObject etc. are defined in the CoreUObject module. (See this question for a similar problem: Linking error (unresolved symbol) in BP Function Library class - UE4 AnswerHub)
You need to add CoreUObject to HamadsPlugin.Build.cs



PublicDependencyModuleNames.AddRange(new string] { "Engine", "Core", "CoreUObject", "LevelEditor", "Slate", "EditorStyle" });


Regarding loading of objects this may be interesting: https://forums.unrealengine.com/showthread.php?3803-How-to-spawn-dynamic-actor-without-using-ConstructorHelpers

Afaik the simple SpawnActor should work.

Thanks,

I’ve tried using the static object load functions but keep having it fail:

UBlueprint * BlueprintObj = Cast&lt;UBlueprint&gt;(StaticLoadObject(UBlueprint::StaticClass(), NULL, L"\\Game\\UnityBP\\Gen_Bowl_Large"));

[2015.02.18-13.49.26:945][600]LogUObjectGlobals:Warning: Failed to find object ‘Blueprint None.\Game\UnityBP\Gen_Bowl_Large’

Do I need to do something special to get these to work? Presumably it’s OK to run these in the editor and the fact the game’s not built isn’t a problem?

I’m not sure how it works but I think you need to specify it like this: e.g. TEXT("/Engine/EditorMaterials/LevelGridMaterial.LevelGridMaterial")
Maybe it works with the backslash.

Also you don’t load a UBlueprint class but a subclass of an actor in this case. So try casting to AActor. UBlueprint is afaik a class that is used to generate/manage blueprints but it is not the actual class in game.

I’m finding that if I query the content in my project, I find content is returned as a UBlueprint (If I query as an AActor then it doesn’t).

However it still fails to load which is bizarre given that I know it definitely exists:



	UObjectLibrary * ObjectLibrary = NULL; 
	bool bFullyLoad = true;

	if (!ObjectLibrary)
	{
		ObjectLibrary = UObjectLibrary::CreateLibrary(UBlueprint::StaticClass(), false, GIsEditor);
		ObjectLibrary->AddToRoot();
	}
	ObjectLibrary->LoadAssetDataFromPath(TEXT("/Game/UnityBP"));
	if (bFullyLoad)
	{
		ObjectLibrary->LoadAssetsFromAssetData();
	}

	TArray<FAssetData> AssetDatas;
	ObjectLibrary->GetAssetDataList(AssetDatas);

	for (int32 i = 0; i < AssetDatas.Num(); ++i)
	{
		FAssetData& AssetData = AssetDatas*;
	}

	FAssetData& someAssetData = AssetDatas[0];

	UBlueprint*	lNewBluePrint = Cast<UBlueprint>(StaticLoadObject(UBlueprint::StaticClass(), someAssetData.GetAsset(), *someAssetData.AssetName.ToString(), *someAssetData.GetFullName()));
	AActor*	lNewActor = Cast<AActor>(StaticLoadObject(AActor::StaticClass(), someAssetData.GetAsset(), *someAssetData.AssetName.ToString(), *someAssetData.GetFullName()));


Both lNewBluePrint & lNewActor return as null

To answer my own questions:

The following always fails:


UBlueprint * BlueprintObj = Cast<UBlueprint>(StaticLoadObject(UBlueprint::StaticClass(), NULL, L"\\Game\\UnityBP\\Gen_Bowl_Large"));

Because it should be forward slash but also UE4 appears to use a weird file system where by the file you want to load has to be referenced as filetoload.filetoload, i.e.


UBlueprint * BlueprintObj = Cast<UBlueprint>(StaticLoadObject(UBlueprint::StaticClass(), NULL, L"/Game/UnityBP/Gen_Bowl_Large.Gen_Bowl_Large"));

Will load the Blueprint.

Note you can’t then add that to the current world, you have a Blueprint and you need to spawn an actor. Rather confusingly if you attempt to load the Blueprint as an actor it will fail to load (despite the editor telling you the Blueprint inherits from Actor) so once you’ve loaded the Blueprint you generate an actor from it and then add it. I found this link which discusses it

It appears once you have the Blueprint you type this Voodoo in:



             FStringAssetReference itemRef = "Blueprint'/Game/Blueprints/Items/Chest/chestBlue.chestBlue'";
             UObject* itemObj = itemRef.ResolveObject();
             UBlueprint* gen = Cast<UBlueprint>(itemObj);
             AARArmor* item = GetWorld()->SpawnActor<AARArmor>(gen->GeneratedClass, SpawnInfo);


Now wtf ResolveObject or the GenertedClass is, well I dunno. Basically this works. It allows you to load something in and place it in the world.

UE4 not saying the learning curve is vertical but, wow, there’s plenty of gotcha’s strewn around the landscape :smiley:

This might be of interest: (Blueprint not available in game) https://forums.unrealengine.com/showthread.php?11658-Spawning-a-Blueprint-outside-of-the-Constructor-in-C-(Version-4-1-1)