DataTable import texture does not work

I think import process has bug.

If you follow sample you provided, it does not work for Texture2D.

structure is following

USTRUCT(Blueprintable)
struct FKObjectDefinitionStruct : public FTableRowBase
{
	GENERATED_USTRUCT_BODY()

	/**
	 * @brief  object icon.
	 *
	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ObjectDefinition)
	TAssetPtr<UTexture> Icon;

	/**
	* @brief  object title.
	*
	*/
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ObjectDefinition)
	FText Title;

	/**
	* @brief  object description.
	*
	*/
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ObjectDefinition)
	FText Description;

	/**
	* @brief  AKPickupObject.
	*
	*/
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ObjectDefinition)
	TAssetPtr<AKPickupObject> Object;

	/**
	* @brief Default struct constructor.
	*
	*/
	FKObjectDefinitionStruct()
	{
	}
};

csv for testing is following

Name,Icon,Title,Description,Object
000001,"""Texture2D'/Game/GameObjects/Weapons/Guns/Icons/WeaponGun'""","Weapon Gun","This is a gun",""
000002,"""Texture2D'/Game/GameObjects/Weapons/Guns/Icons/WeaponLauncher'""","Weapon Launcher","This is a launcher",""
000003,"""Texture2D'/Game/GameObjects/Weapons/Guns/Icons/WeaponGun'""","Weapon Gun","This is a gun",""
000004,"""Texture2D'/Game/GameObjects/Weapons/Guns/Icons/WeaponLauncher'""","Weapon Launcher","This is a launcher",""

When you import csv, Data Table is shown as follow.
And Texture are not imported.

Some rows start with /Game/GameObjects…
and other with Texture2D’ /Game/GameObjects…

And when you display reference on Data Table, no reference on texture.

D.

Hi domzorg,

Thanks for your report! We have a bug report in our system for this behavior (UE-11024), and we recently bumped up its priority. I’ll let you know as soon as I see any update on it.

For now, there’s a workaround that only works while editor is open. If editor is closed and re-opened, workaround must be done again:

  1. Close DataTable in UE4
  2. In Content Browser, right-click on datatable and reimport asset
  3. Right-click on datatable again and save it
  4. Open DataTable in UE4

Hope that helps!

Try this, instead:

  1. Close DataTable in UE4
  2. Select textures in Content Browser
  3. Right-click on selected textures and choose Copy Reference option
  4. Open DataTable in UE4

See if that works and let us know. Thanks!

Thank you very much for your prompt answer.

Ok, I’ve tried and effectively it fix all items with Texture2D’ /Game/GameObjects…

But when I used View References, it does not point to texture.
And my Help class return nullptr when I use Data->Icon.Get();

Normally, should it automatically load texture ?

D.

I’ve copied all references from object and change csv.
Then I close DataTable.
Select texture i’m testing.
Right click to select Texture of first record.
Import again.
Open DataTable.

Debug.

UTexture* UKObjectManager::FindPickupObjectIcon(FString UID)
{
	if (ObjectLookupTable)
	{
		const FKObjectDefinitionStruct* Data = ObjectLookupTable->FindRow<FKObjectDefinitionStruct>(*UID, TEXT(""));
		if (Data)
		{
			UTexture* obj = Data->Icon.Get();
			return obj;
		}
	}
	return NULL;
}

And now, WeakPtr of Data->Icon is not anymore NULL.

But for last row, which is a blueprint derived C++ class, it does not work.
In my csv I put reference from Copy Reference command.

Name,Icon,Title,Description,Object
000001,"""Texture2D'/Game/GameObjects/Weapons/Guns/Icons/WeaponGun.WeaponGun'""","Weapon Gun","This is a gun","""Blueprint'/Game/GameObjects/Weapons/Guns/Blueprints/WeaponGun.WeaponGun'"""
000002,"""Texture2D'/Game/GameObjects/Weapons/Guns/Icons/WeaponLauncher.WeaponLauncher'""","Weapon Launcher","This is a launcher","""Blueprint'/Game/GameObjects/Weapons/Guns/Blueprints/WeaponLauncher.WeaponLauncher'"""

Blueprint has following hierarchy.

AKPickupObject
– AKEquipObject
– AKWeapon
– AKWeapon_Bullet
– AKWeapon_Projectile
– WeaponLauncher

From method :

AKPickupObject* UKObjectManager::FindPickupObject(FString UID)
{
	if (ObjectLookupTable)
	{
		const FKObjectDefinitionStruct* Data = ObjectLookupTable->FindRow<FKObjectDefinitionStruct>(*UID, TEXT(""));
		if (Data)
		{
			AKPickupObject* obj = dynamic_cast<AKPickupObject*>(Data->Object.Get());
			return obj;
		}
	}
	return NULL;
}

As you can see for Icon (Texture), WeakPtr is valid but not for blueprint Object.

Have a nice day.
D.

Thanks for additional information! I’ve added a link to this post to bug report.

Very good !!!
I appreciate your support and precious help.

Have a nice day.
D.

Hi domzorg,

Please take a look at my answer over on this thread:

I think possibly issue is a result of misunderstanding operation of TAssetPtr. very reason to use it over a simple UTexture2D* in table row struct is that it doesn’t force an additional asset loading dependency on object; instead it is left to user code to load referenced asset when it’s required. I posted some code which does this over on other thread.

If, on other hand, you’d prefer referenced assets to be picked up as dependencies and loaded automatically, best approach would simply be to change your TAssetPtr<>s in your table row struct to be simple UTexture* and AKPickupObject* properties. Be aware that this can cause increasingly large load dependencies, and require far more resources than necessary to be loaded up-front.

Thank you so much.
Effectively I did not understood document. I’ve assumed DataTable was loading all objects.
With code you’ve provided it’s working fine.

I still have small problem with cast.

As mentionned before, hierarchy for PickupObjects is following:

AKPickupObject
– AKEquipObject
– AKWeapon
– AKWeapon_Projectile
– WeaponLauncher

blueprint WeaponLauncher is derived from AKWeapon_Projectile c++ class.

AKPickupObject* UKObjectManager::GetPickupObject(FString UID)
{
	if (ObjectLookupTable)
	{
		const FKObjectDefinitionStruct* Data = ObjectLookupTable->FindRow<FKObjectDefinitionStruct>(*UID, TEXT(""));
		if (Data)
		{
			if (Data->Object.IsPending())
			{
				UObject* Asset = Data->Object.ToStringReference().TryLoad();
				if (Asset == nullptr)
				{
					UE_LOG(LogKSGM, Log, TEXT("UKObjectManager::GetPickupObject: Still couldn't load Data->Object"));
				}
			}
			AKPickupObject* obj = dynamic_cast<AKPickupObject*>(Data->Object.Get());
			return obj;
		}
	}
	return NULL;
}

In csv object is defined like this and no problem since he found object.
Blueprint’/Game/GameObjects/Weapons/Guns/WeaponLauncher.WeaponLauncher’

But cast :
AKPickupObject* obj = dynamic_cast(Data->Object.Get());

always returns nullptr. Apparently, when I debug UE4 code blueprint does not derive from :
AKWeapon_Projectile → AKWeapon → AKEquipObject ->AKPickupObject

In fact function IsA() return always false.

bool UObjectBaseUtility::IsA( const UClass* SomeBase ) const
{
	UE_CLOG(!SomeBase, LogObj, Fatal, TEXT("IsA(NULL) cannot yield meaningful results"));

	for ( UClass* TempClass=GetClass(); TempClass; TempClass=TempClass->GetSuperClass() )
	{
		if ( TempClass == SomeBase )
		{
			return true;
		}
	}
	return false;
}

Do you have any idea why ?

Have a nice day,
D.

In addition, when debugging, TempClass contains:

  • Blueprint
  • BlueprintCore
  • Object

But never classes Blueprint is derived from.

What exactly are you expecting this to give you? Class Default Object for blueprint? Obviously it can’t return you a specific instance.

If you have a UBlueprint* and you wish to instance it, you can do so with:

check(Blueprint->GeneratedClass->IsChildOf(AKPickupObject::StaticClass());
AKPickupObject* Instance = NewObject<AKPickupObject>(YourOuter, Blueprint->GeneratedClass);

Does that help at all?

method GetPickupObject() is supposed to return an object based on AKPickupObject class. For a weapon based on AKWeapon_Projectile class I would like to have pointer based on object, and for another type of object, an helm, I would like to have pointer also. Since all these objects are based on AKPickupObject, I’ve chosen this base class.
But in blueprints, I should be able to cast object against AKEquipObject or AKWeapon class type.
Therefore, if I create a new object instance with :
AKPickupObject* Instance = NewObject(YourOuter, Blueprint->GeneratedClass);
will new instance still be derived from original object class ?

I’ll try and let you know.

D.

In fact it does not work.
problem still same.

IsChildOf will return false always since object, which is a blueprint, is not recognized as a AKPickupObject.
Struct object pointer in loop is :

  • Blueprint

  • BlueprintCore

  • Object

    bool IsChildOf( const UStruct* SomeBase ) const
    {
    for (const UStruct* Struct = this; Struct; Struct = Struct->GetSuperStruct())
    {
    if (Struct == SomeBase)
    return true;
    }

      	return false;
      }
    

Is there a method, for blueprints, to get classes derived from ?
And not :

  • Blueprint
  • BlueprintCore
  • Object

Have a nice day.
D.

Hi domzorg,

Sorry for delay in getting back to you. I just tried this for myself, and here’s my solution. First off, you need to hold a TAssetPtr in your DataTable, since that’s asset type you’re declaring in your imported data.

I then added UDataTable asset as a property of my test actor, and added following method to it:

	virtual void OnConstruction(const FTransform& Transform) override
	{
		Super::OnConstruction(Transform);

		if (DataTable != nullptr)
		{
			TArray<FName> RowNames = DataTable->GetRowNames();
			for (const FName& RowName : RowNames)
			{
				FNeedLookupTable* Row = DataTable->FindRow<FNeedLookupTable>(RowName, TEXT("Test"));

				if (Row->Object.IsPending())
				{
					UObject* Asset = Row->Object.ToStringReference().TryLoad();
					if (Asset == nullptr)
					{
						UE_LOG(LogTemp, Log, TEXT("Still couldn't load blueprint"));
					}
				}

				UBlueprint* Blueprint = Row->Object.Get();
				if (Blueprint)
				{
					check(Blueprint->GeneratedClass->IsChildOf(AQAProjectile::StaticClass()));
					UClass* Class = Blueprint->GeneratedClass;
					AQAProjectile* Instance = GetWorld()->SpawnActor<AQAProjectile>(Class, GetActorLocation(), GetActorRotation());
				}
			}
		}
	}

Let me know if this is a workable solution for you.

Hi Richard,

To better explain my problem I’ve attached source code I used.
KObjectManager.cpp and .h is utility class derived from UBlueprintFunctionLibrary. KStructs.h is structures definition files. FKObjectDefinitionStruct structure is used in relation with table row base.

Objects.pdf is an UML class diagram for objects. As you can see, below AKPickupObject you have several classes. idea is to get right object based on right class in blueprint. I made several blueprints based on AKEquipObject, ie for helmet, boots, …, and several blueprints based on AKWeapon, ie. for axes, guns, …
Based on EKEquipmentType, I knew what kind of object it is.

static function AKPickupObject* UKObjectManager::GetPickupObject(FString UID) is supposed to return right object class if I want to cast object based on its class.

I cannot use GetWorld() function in this static helper method.
And idea is not to create object itself, but to have access to its information. object creation will be done when player equip object from its inventory. I’m thinking creating real object using blueprints.

In FKObjectDefinitionStruct I’ve defined TAssetPtr Object;
Since it is a blueprint derived from AKPickupObject test
if (Data->Object.Get() == nullptr)
returns null since isa does not recognize blueprint class derived from AKPickupObject.

I think I have to defined Object in my struct as UBlueprint. But therefore how to cast this object to AKPickupObject ?

Again, thank you for taking time to help me.
Have a nice day.
Dominique. link text

link text

Hi Dominique,

I’ve just noticed that markdown swallowed my angle brackets in my comment above, so what it should have said was:

First off, you need to hold a TAssetPtr<UBlueprint> in your DataTable, since that’s asset type you’re declaring in your imported data.

If you’re not interested in spawning an instance of Blueprint, but would just like to be able to read out default properties for archetype, you should also be able to do that by replacing final block of code in my example with following:

                 UBlueprint* Blueprint = Row->Object.Get();
                 if (Blueprint)
                 {
                     check(Blueprint->GeneratedClass->IsChildOf(AQAProjectile::StaticClass()));
                     UClass* Class = Blueprint->GeneratedClass;
                     AQAProjectile* DefaultObject = CastChecked<AQAProjectile>(Class->GetDefaultObject());
                 }

Let me know if that helps you.

Unfortunately it doesn’t work.

code :

UBlueprint* Blueprint = Data->Object.Get();
			if (Blueprint)
			{
				check(Blueprint->GetClass()->IsChildOf(AKPickupObject::StaticClass()));

gives an exception with check(…)

Assertion failed: Blueprint->GetClass()->IsChildOf(AKPickupObject::StaticClass()) [File:D:\KadeoGames\UDK\KSGM\Source\KSGM\Objects\KObjectManager.cpp] [Line: 53] 

IsChildOf() function cannot find AKPickupObject class since blueprint object derives from :

  • Blueprint
  • BlueprintCore
  • Object

and not AKPickupObject.

But in debugger, you can see that

ParentClass is KEquipObject which is correct.

D.

Have you changed DataTable property to be a TAssetPtr<UBlueprint> instead of a TAssetPtr<AKPickupObject>?

Also, you need Blueprint->GeneratedClass, not Blueprint->GetClass() (as per my code snippet!)

yes I do.