fopen with UnrealEngine

Hello everyone !

I’m currently working on a dialog system, so I write my dialogs in text files and I want to load them in my code using fopen function. Problem : I tried different paths for my file but fopen never find it… I tried relative and absolute paths, different locations, and it still doesn’t open. I did include “stdio.h” by the way.

Maybe I still didn’t find the good path ? I assumed that the C++ project directory was 'Intermediate\ProjectFiles".
Or maybe something about fopen slips out of me ?

Thanks for reading, regards !

PS : The current filepath I give to fopen : “…\Content\PtC_Content\Assets\Dialogs\ExempleDialogue.txt”

PSS : My code (Always debug printing “Being load”, then the path I wrote, then “FAILED”)

void DialogueProgress::LoadDialogue(const char* _filename)
	GEngine->AddOnScreenDebugMessage(-1, 0.2, FColor::Red, "Begin load");
	GEngine->AddOnScreenDebugMessage(-1, 0.2, FColor::Red, _filename);

	FILE* fp = fopen(_filename, "rb");

	if (fp)
		GEngine->AddOnScreenDebugMessage(-1, 0.2, FColor::Red, "Loading OK");

	else GEngine->AddOnScreenDebugMessage(-1, 0.2, FColor::Red, "FAILED");

Rama has a good wiki on reading/writing files:

As for the file path, it depends on what your project’s Working Directory is. Right click on your project in Visual Studio -> Properties -> Debugging, you’ll see the Working Directory there (it’s usually wherever your project file is).

Don’t try use standard library functions in UE4. While it is possible, UE4 already wraps all of them in order to transparent to whichever platform you’re building in. And even if you don’t plan on shipping to consoles, using the same functions as the engine does ensures you won’t have any issues pulling the wrong includes, the wrong libraries, or some such.

I took a quick look and the file access functions are provided through the IPlatformFile interface. Here’s a quick example of how to use it:

IPlatformFile& PlatformFile = IPlatformFile::GetPlatformPhysical();
IFileHandle* File = PlatformFile.OpenRead(*FullModulePath);

You can take a peek at the GenericPlatformFile.h containing the IPlatformFile and interfaces in order to figure out how to use them.

But I would discourage going that route altogether. Using plain text files and direct file access is not fully cross platform compatible and since it doesn’t go through the asset system, you’ll have to manually manage those text files in order for them to be properly included and loaded in a cooked build. Also, if you ever want to localize your game, then you’ll also have to manually handle text files instead of using UE4’s built-in localization system.

I would instead advise creating an asset type for this dialogue. If you’d rather avoid having to use the editor, there is a UDataTable asset type which you can use to import data such as dialogue through a CSV file instead. If you keep your data table asset simple enough, it will essentially be just like working in a text file.

Yep, so the Working Directory is actually the one I posted. Thanks for the link !

Thanks for all those precisions ! Indeed UDataTable sounds like a perfect use for me. I’m going to check that straightaway !

Well, I checked UDataTable and indeed, this class seems awesome and perfect for me.

BUT, unfortunately I have several compilation errors LNK2001 and LNK2019 with internal functions like FinishDestroy() and some others. Some guy mentions the same problem here and it seems that it’s an engine problem, a man from the staff posted a link to a fix, but it now leads to an “Error 404” : Trouble with UDataTable and GetDataTableRow - UE4 AnswerHub

If you know something about it, I’m really looking for an explanation… Otherwise I try the “PlatformFile / FileHandle” solution

Yeah, the data table is not very well documented, I had to dig around a bit to figure it out.

Unless I’m mistaken, you’re trying to subclass UDataTable? If so, that’s not how it works. The fix in the thread you linked has already been applied, if you’re up to 4.7. What you’re experiencing is insufficient linkage on UDataTable functions because they are not exported outside of the engine.

Instead, you create a struct type which represents the data you want contained in your csv file and have it inherit FTableRowBase. Here’s an example of how we define in-game tips:

struct FInGameTip : public FTableRowBase

	UPROPERTY( Category=InGameTip, EditAnywhere, BlueprintReadWrite )
	FText TipTitle;
	UPROPERTY( Category=InGameTip, EditAnywhere, BlueprintReadWrite )
	FText TipBody;

	UPROPERTY( Category=InGameTip, EditAnywhere, BlueprintReadWrite )
	UTexture2D* TipIcon;

	UPROPERTY( Category=InGameTip, EditAnywhere, BlueprintReadWrite )
	FLinearColor TipTint;

And here’s a corresponding csv file:

AttackTip,"ATTACKING",""It looks like you're trying to attack someone! Have you tried whacking them over the head?","Texture2D'/Game/UI/HUD/TipIcons/AttackIcon.AttackIcon'","(R=0.9,G=0.9,B=0.9,A=1.0)"

Once you have a csv file saved, it is simply imported into the editor like any other asset. It'll give you a preview of what the imported data will look like. Note the extra Name column -- this is implicit to all data table rows and that's how you identify and look up the row you want. For instance, looking up the above row would be done like this:

	const FName TipKey = "AttackTip";
	const FString ShowInGameTipContext = "ShowInGameTip";
	FInGameTip* InGameTipHandle = InGameTipData->FindRow<FInGameTip>( TipKey, ShowInGameTipContext );

One of the tricky things about data tables can be figuring out the format for some types, for instance the FLinearColor above. It's basically using the engine's text serialization format, it's been a while since I figured out the format above but I recall I did it by copying something from the editor and pasting it in notepad. I believe it can be found in code by getting a property through reflection (UProperty*) then using ExportTextItem.

It's a bit of work, but once you get it working, data tables are probably the most flexible non-editor-based type of asset.