Can I automatically reimport values into Data Tables?

Hi!

I’m currently experimenting with the data tables. Despite their limitations (enum/struct properties), they appear really powerful and are nowhere near as cumbersome to use as I expected.

Knowing our designers, they’re probably going to be busy tweaking numbers all the time. I’d like to make updating the game data even more convenient for them by having the reimport happen automatically. Either whenever the editor or (development version of the) game is loaded, or by way of a button in an editor extension that updates all tables with one click rather than the designer having to reimport each one manually. Or both, of course. :slight_smile:

I’m currently using Blueprints but I’ll happily switch to C++ (which is probably more efficient anyway) if that would make this possible.

Thanks in advance!

1 Like

Would also like to have this

Quick answer: yes, with C++

I still have to run some tests, but so far I’m pretty happy with what is possible. I’m going to post some code snippets once I’ve got some definite answers. Unfortunately, I don’t have my project here right now, so I can’t post my intermediate results.

I mostly built up on this post, though: How to load the CSV DataTable dynamically? - Community & Industry Discussion - Epic Developer Community Forums

Finally got around to this. It’s absolutely possible and even surprisingly easy using C++.

For the record, I’ve switched to 4.9.1 in the meantime, which could make a difference. (I don’t know.)

First, I defined a struct in one of my classes’ header files:

USTRUCT(BlueprintType)
struct FTestStruct : public FTableRowBase
{
	GENERATED_USTRUCT_BODY()

public:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	int32 testInt;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	FString testString;
};

Then I created a csv file with the necessary syntax, which I saved as Content/Data/testData.csv, and imported the csv file into the editor to create the data table, which I saved in the same folder.

Next, I added a reference to an object of type UDataTable table to MyProjectGameMode.h:

UCLASS()
class MYPROJECT_API AMyProjectGameMode : public AGameMode
{
	GENERATED_BODY()

	AMyProjectGameMode(); // C'tor

	// Called when the game starts
	virtual void BeginPlay() override;

	UDataTable* MyDataTable;	
};

The actual work gets done in MyProjectGameMode.cpp. In the constructor, I used FObjectFinder to grab the DataTable located at the known relative path. In BeginPlay, I then used the reference to the data table filled in the constructor and the fixed path to the csv file to actually fill the data table.

Credit goes to How to load the CSV DataTable dynamically? - Community & Industry Discussion - Epic Developer Community Forums from where I copied most of the code.

AMyProjectGameMode::AMyProjectGameMode()
{
	ConstructorHelpers::FObjectFinder<UDataTable> MyDataTableObj(TEXT("UDataTable'/Game/Data/testData.testData'"));
	if (MyDataTableObj.Succeeded())
	{
		MyDataTable = MyDataTableObj.Object;
		UE_LOG(LogTemp, Warning, TEXT("Data Table found"));
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("Data Table not found"));
	}
}

// Called when the game starts
void AMyProjectGameMode::BeginPlay()
{
	Super::BeginPlay();

	FString csvFile = FPaths::GameContentDir() + "Data\\TestData.csv";
	UE_LOG(LogTemp, Warning, TEXT("Attempting to read csv from path '%s'"), *csvFile);
	if (FPaths::FileExists(csvFile))
	{
		FString FileContent;
		//Read the csv file
		FFileHelper::LoadFileToString(FileContent, *csvFile);

		if (MyDataTable)
		{
			TArray<FString> problems = MyDataTable->CreateTableFromCSVString(FileContent);

			if (problems.Num() > 0)
			{
				for (int32 ProbIdx = 0; ProbIdx < problems.Num(); ProbIdx++)
				{
					//Log the errors
				}
				UE_LOG(LogTemp, Warning, TEXT("Data Table update failed"));
			}
			else
			{
				//Updated Successfully
				UE_LOG(LogTemp, Warning, TEXT("Data Table updated successfully"));
			}
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("Data Table not found"));
		}
	}
}

(Note that there’s probably a much better place for this than the GameMode, but it seemed like a good starting place when trying this out. It also looks like you can’t output log messages in the GameMode’s BeginPlay method.)

I expected this to be much more difficult and was pleasantly surprised with the results. I was amazed to learn that with the editor open, the data table gets updated on the fly and saved whenever the csv file changes. (It’s highly likely that at least this last bit of magic only works if the csv file is also located in the Content folder.)

Unfortunately, I was unable to get packaging to work, so I can’t say whether the autoimport would also work for packaged game (probably) and if so, at what point during the initialization.

On my TODO list:

  • extend the code to handle updating multiple data tables
  • replace the fixed paths with something more flexible

Well apparently the above mentioned function CreateTableFromCSVString() only works in the editor since it is compiled with #if WITH_EDITOR which means you can’t use it in a packaged build.