Hey everyone!
I’ve been trying (in conjunction with some friends) to create a dialogue system similar to the ones found in Dragon Age and Mass Effect. I’ve created some container classes, an interactible Dialogue actor, and some external tools to author dialogue trees. These trees are stored as CSV files, and loaded into the engine as UDataTables. So far so good.
However, when trying to access/load these dynamically from the engine (i.e, selecting an asset from the browser and setting it in the actor’s defaults,) a number of issues crop up.
First of all, this is my header:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "UseableSkeletalActor.h"
#include "DialogueDataTable.h"
#include "DialogueInterface.h"
#include "DialogueActor.generated.h"
/**
* The DialogueActor derives from the UseableSkeletalActor, which gives it basic use functionality (outline and interaction)
*/
UCLASS()
class MYGAME_API ADialogueActor : public AUseableSkeletalActor, public IDialogueInterface
{
GENERATED_BODY()
public:
ADialogueActor(const class FObjectInitializer& ObjectInitializer);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue", meta = (DisplayName = "Dialogue Tree Asset-Ptr"))
TAssetPtr<UDataTable> DataTable;
UFUNCTION(BlueprintCallable, Category = "Dialogue")
virtual void LoadDialogueData(UDataTable* Table) override;
UFUNCTION(BlueprintCallable, Category = "Dialogue")
virtual UDataTable* GetLoadedDialogueData() override;
UFUNCTION(BlueprintCallable, Category = "Dialogue")
virtual TArray<UDialogueMenu*> GetDialogueMenus() override;
UFUNCTION(BlueprintCallable, Category = "Dialogue")
virtual UDialogueMenu* GetDialogueMenu(int32 TargetMenu) override;
UFUNCTION(BlueprintCallable, Category = "Dialogue")
virtual void BeginConversation(AActor* TargetActor) override;
};
This code allows me to boot up the editor, but does not give me a useable reference to the table. Instead, it returns null.
ADialogueActor::ADialogueActor(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
//load table from asset and call LoadDialogueData
static ConstructorHelpers::FObjectFinder<UDataTable> DataTable_BP(*DataTable.ToStringReference().ToString());
if (GEngine)
{
//GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("DataTable'/Game/Blueprints/DialogueObjects/Testing/DwarfInBarrel-en_GB.DwarfInBarrel-en_GB'"));
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, *DataTable.ToStringReference().ToString());
}
if (DataTable_BP.Object != NULL)
{
UDataTable* Table = DataTable_BP.Object;
LoadDialogueData(Table);
}
}
void ADialogueActor::LoadDialogueData(UDataTable* Table)
{
IDialogueInterface* Interface = Cast<IDialogueInterface>(this);
if (Interface)
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("Interface OK."));
}
if (Table != NULL)
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("Loading Table."));
}
Interface->LoadDialogueData(Table);
}
}
}
If I instead hardcode the asset path for testing purposes, like this:
ADialogueActor::ADialogueActor(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
//load table from asset and call LoadDialogueData
static ConstructorHelpers::FObjectFinder<UDataTable> DataTable_BP(TEXT("DataTable'/Game/Blueprints/DialogueObjects/Testing/DwarfInBarrel-en_GB.DwarfInBarrel-en_GB'"));
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("DataTable'/Game/Blueprints/DialogueObjects/Testing/DwarfInBarrel-en_GB.DwarfInBarrel-en_GB'"));
}
if (DataTable_BP.Object != NULL)
{
UDataTable* Table = DataTable_BP.Object;
LoadDialogueData(Table);
}
}
void ADialogueActor::LoadDialogueData(UDataTable* Table)
{
IDialogueInterface* Interface = Cast<IDialogueInterface>(this);
if (Interface)
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("Interface OK."));
}
if (Table != NULL)
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("Loading Table."));
}
Interface->LoadDialogueData(Table);
}
}
}
The editor crashes on startup with this error message at the first line of LoadDialogueData:
I’m stumped by this. I’ve tried using a direct UDataTable* pointer for my blueprint-exposed variable, hardcoding and dynamically loading, with AssetLongPathname instead of ToString() and convoluted asset loading with StaticLoadObject.
Any help will be greatly appreciated. This is a major (if not the most major feature) in our game, and I’m personally going figuratively insane from what would seem like a small problem