Inconsistent Behaviour with FPaths::FileExists() and GetPlatformFile().FileExists()

Hi all.

I am working on a project which requires various assets to be downloaded at run time.

In order to prevent unnecessary downloads, I am trying to check to see if the asset (in this case 120 PNG’s) already exists. If they don’t, trigger the download for the asset, otherwise, move on to the next asset check.

I am working with a struct map that contains information such as the asset name, URL for the asset, and some other misc information.

First implementation

Loop through the values of the map, access the URL, and check to see if the asset exists. If it doesn’t, add it to a new array that will be used in the download procedure.

Result: 40% of assets don’t think they exist when they do.

I believe this may have been caused due to trying to check 120 assets at once, so I went for a timed solution

Second implementation
Loop through the values of the map, access the URL, and check to see if the asset exists. If doesn’t exist start the async download procedure before checking the next asset. Otherwise initiate a timer for 0.1 seconds before attempting to check the next asset.

Result: Mostly works, sometimes it may think that one or two assets don’t exist when they do. However, I can accept this margin of error.

The problem comes with packaged builds. In the packaged build, the opposite happens. The FileExists check returns that files exist when they actually don’t and they don’t when they actually do.

Project Information

The checks are handled within a function library

All logic is C++ based.

Logic is executed from a “main menu” in an empty world. No other actor is running any logic (except for base implementation logic).

The logic is executed from an actor which is spawned into the world.

All file names and file paths are correct.

No other functionality or async operation is being called at the time of the file checks. I am 99.9% there is no logic or stack conflict.

**The code **

The code itself is relatively simple.

Function Library header

	/** Returns TRUE if a file exists (Not project specific) */
	UFUNCTION(BlueprintCallable, Category = "Support Library|File Handling")
	static bool DoesFileExist(FString path);


	UFUNCTION(BlueprintPure, Category = "Support Library|Support Functions")
	static bool DoesAssetRequireDownload(FString contentPathName, FAsset asset);

Function Library cpp

bool UContentFunctionLib::DoesFileExist(FString dir)
{
	// Return TRUE if the Platform File Manager can find the target file
	return FPaths::FileExists(dir);
	//return FPlatformFileManager::Get().GetPlatformFile().FileExists(*dir);
}

bool UContentFunctionLib::DoesAssetRequireDownload(FString contentPathName, FAsset asset)
{
	FString path = GetContentDataDir(contentPathName) + asset.assetDir;
	FString name = FString::FromInt(asset.assetID) + "_" + asset.assetGUID + ".png";
	
	FString fullPath = FPaths::ConvertRelativePathToFull(path);

	bool result = !DoesFileExist(path + name);

	if (result)
	{
		UE_LOG(LogTemp, Warning, TEXT("%s%s REQUIRES DOWNLOAD"), *fullPath, *name);
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("%s%s FOUND"), *fullPath, *name);
	}
	

	return result;
}

The execution cpp

void ADownloadManager::DownloadNextImageAsset()
{
	if (!assetDownloadList.IsValidIndex(assetDownloadQueueIndex)){ return;}

	UE_LOG(LogDownloadManager, Log, TEXT("Downloading image %d out of %d. Current download asset: %s"), assetDownloadQueueIndex + 1, assetDownloadList.Num(), *assetDownloadList[assetDownloadQueueIndex].displayName);

	OnSendDownloadMessage.Broadcast(FString::Printf(TEXT("Validating asset %d of %d"), assetDownloadQueueIndex + 1, assetDownloadList.Num()), GetPercentageDownloaded());

	FAsset* asset = &assetDownloadList[assetDownloadQueueIndex];

	if (UContentFunctionLib::DoesAssetRequireDownload(contentPathName, *asset))
	{
		OnSendDownloadMessage.Broadcast(FString::Printf(TEXT("Validating asset %d of %d\nDownloading %s"), assetDownloadQueueIndex + 1, assetDownloadList.Num(), *assetDownloadList[assetDownloadQueueIndex].displayName), GetPercentageDownloaded());
		UAsyncTaskDownloadImage* imageDownloadHandle = UAsyncTaskDownloadImage::DownloadImage(asset->fileURL);
		imageDownloadHandle->OnSuccess.AddDynamic(this, &ADownloadManager::OnImageDownloadComplete);
		imageDownloadHandle->OnFail.AddDynamic(this, &ADownloadManager::OnImageDownloadFailed);
	}
	else
	{
		GetWorld()->GetTimerManager().SetTimer(OnFileExistCheckTimerHandle, OnFileExistCheckTimerDel, 0.1f, false);
	}
}

I am at a loss as to why the results are failing and more importantly, why they are so inconsistently failing. If anyone has any alternatives to check to see if a file exists or any further suggestions for debugging this issue, I would be truly grateful.

Thank you for your time.

Alex

log your path in DoesFileExist

Hi UPO33

Thanks for the suggestion. Logging inside the DoesFileExist is something I already tried, everything matches correctly.

The fact it works “sometimes” is what is throwing me, even when I make the calls asynchronously.

Any other suggestions would be appreciated.

Thanks

Alex