Following on from the set up in Advent of Code in Unreal Engine – Boilerplate Part 1 I was unsatisfied with the result. The http headers cookie is definitely a hack, and fetching over the network, just because I need text, and then parsing it into lines every time it runs is relatively inefficient. It puts load on the advent of code servers, and asynchronous nodes can only be used in an event graph, creating some refactoring complications.
So I decided to look into creating a custom asset importer instead. First we need a class that describes the imported asset. I just want an array of strings, one per line on text, accessible from Blueprint, so I created UPlainTextAsset
:
/** * Asset that is a container for plain text, stored as string-per-line */ UCLASS(BlueprintType, HideCategories=(Object)) class AOC_2022_API UPlainTextAsset final : public UObject { GENERATED_BODY() public: UPROPERTY(EditAnywhere,BlueprintReadOnly) TArray<FString> Lines; };
Then a sub-class of UFactory
to hook into importer functionality:
UCLASS() class AOC_2022_API UPlainTextAssetFactory : public UFactory { GENERATED_BODY() UPlainTextAssetFactory(); virtual UObject* FactoryCreateFile(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, const FString& Filename, const TCHAR* Params, FFeedbackContext* Warn, bool& bOutOperationCanceled) override; };
UPlainTextAssetFactory::UPlainTextAssetFactory() { Formats.Add(FString(TEXT("txt;")) + NSLOCTEXT("UPlainTextAssetFactory", "FormatTxt", "Text File").ToString()); SupportedClass = UPlainTextAsset::StaticClass(); bCreateNew = false; bEditAfterNew = true; bEditorImport = true; }
Override FactoryCreateFile
to do all the work of loading a file and creating an asset:
UObject* UPlainTextAssetFactory::FactoryCreateFile(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, const FString& Filename, const TCHAR* Params, FFeedbackContext* Warn, bool& bOutOperationCanceled) { GEditor->GetEditorSubsystem<UImportSubsystem>()->BroadcastAssetPreImport( this, InClass, InParent, InName, *FPaths::GetExtension(Filename)); FString TextString; UPlainTextAsset* Result = NewObject<UPlainTextAsset>(InParent, InClass, InName, Flags); if (FFileHelper::LoadFileToString(TextString, *CurrentFilename)) { TextString.ParseIntoArrayLines(Result->Lines, false); } GEditor->GetEditorSubsystem<UImportSubsystem>()->BroadcastAssetPostImport(this, Result); bOutOperationCanceled = false; return Result; }
With that done, the Puzzle Input content can be saved locally as text files, and then imported into the project:
This creates an asset we can open up, inspect, and edit:
The lines of text can then be referenced directly from the blueprint:
This feels a lot closer to The Epic Way.
A complete tutorial on creating a custom asset and exporter can be found on Gerke Max Preussner’s website, here: https://gmpreussner.com/reference/adding-new-asset-types-to-ue4
PS: A word of warning, the Rider Link plugin “Engine Install” from Rider is not compatible with Unreal 5.1, and will break the build. The fix is simply to delete it from \Program Files\Epic Games\UE_5.1\Engine\Plugins\Developer
\
2 thoughts on “Advent of Code in Unreal Engine – Boilerplate Part 2”