How to avoid hardcode? (UPrimaryDataAsset)

I have a critical point in my code and I don’t like it.
It’s a horrible static hardcode full of literals in my Master Data Asset.

But without it is impossible (at least with my knowledge) to get an instance of the Master Asset.

UCLASS()
class UMasterDataAsset : public UPrimaryDataAsset
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere)
    TArray<TSoftObjectPtr<UPrimaryDataAsset>> Assets;  

    static inline const FName   PrimaryAssetTypeName = TEXT("Master");
    static inline const FName   FileName             = TEXT("PDA_Master");
    static inline const FString AssetPath            = TEXT("/Game/DataAssets/PDA_Master.PDA_Master");
    static inline const FPrimaryAssetId ID           = FPrimaryAssetId(FPrimaryAssetType(PrimaryAssetTypeName) , FileName);

	static const FSoftObjectPath& GetSoftObjectPath()
	{
		static const FSoftObjectPath Path(AssetPath);
		return Path;
	}

	static UClientMasterAsset* Load()
	{
		UObject* Obj = GetSoftObjectPath().TryLoad();
		return IsValid(Obj) ? Cast<UClientMasterAsset>(Obj) : nullptr;
	}


}

I also tried this but I always get an empty list.
The list is not empty only after the assets have been loaded into memory (not before).

TArray<FPrimaryAssetId>AssetIds;
UAssetManager::Get().GetPrimaryAssetIdList(FPrimaryAssetType(“Master”), AssetIds);

Any way to do this without hardcode?

Thank you so much!!

hardcoding is not a crime. it depends how you do it.

values will be “hardcoded” at a point anyway.

hardcoding values is often a problem when they are magic values (eg values scattered not bound to a variable with a nice name). but having value tables is pretty valid and still used nowadays. you can find plenty in the engine code.

in my project i use cpp mostly. so hardcoding is pretty natural. i keep the values in specific locations and structures.

if you don’t need to change the values often, hardcoding is ideal.

if you do need to change them, it depends how you want to handle that.

either have a developer settings object.

or you can have a blueprintfunctionlibrary marked as Config so that you can set them in your ini files (one of my favorites).

your code is pretty good, it looks acceptable for many settings. i guess it depends if it creates issues with your project. if it’s not broken then you don’t need to/can’t fix it.

all literal values get packaged in the binary anyway so it’s fine.

having them as static const is good. you can refer them by the class name, which gives you a namespace. which is pretty neat.

i have a special namespace ProjConsts where i store other namespaces with static const values that i reference from multiple places. it has served me really well.

i guess the question is why you don’t like it? there’s nothing inherently bad or horrible about what you’ve done.
are you putting a subjective aesthetic preference above functionality and practicality? (this is just a neutral comment i’m not judging, just trying to understand your goal and values).

what would you prefer and why?

The problem is that if I move the file from folder or rename it everything breaks… that’s why I want to avoid hardcoded paths.

Basically this is the biggest weakness of my entire project.
/Game/DataAssets/PDA_Master.PDA_Master"

If this breaks, literally everything breaks.

i see.

hmm. let me think some alternatives. these are some ideas:

in ue when you move something everything breaks, so it’s not that rare.

there are core redirectors which can help you. and can be modified on ini files and even after packaging.

also when you move an asset, doesn’t it leave an invisible redirector in that folder? is that not helping?

how often do you move that asset?

a developer settings seems like a good option. you can store the values there and when moving an asset they usually get updated (unless my memory fails me). i think you get a warning otherwise, which is not a huge feat since you can add a warning yourself too.

by your post count i imagine you know what i’m talking about, otherwise is this Developer Settings · Unreal🌱Garden

i think it will add a bit of code to get the values, you’ll have to execute a function instead of referencing a static value.

you can always get the default object of the settings, so it can be used in static contexes iirc.

would that help?

alternatively you can minimize the issue, by having a datatable with softlinks to the objects and constants that you need. then you define the values with an instance of the datatable in bps. and set it on a settings object. so you only have one point of failure which hopefully doesn’t need to move all the time. and ue will take care of updating the references because you’re in bp-land. i think.

so you have only one data table for project config, then on the row you get the data you need, for example the constants for this master data asset. but that seems like a lot of overhead to me. also i’m not sure if a masterDataAsset would have to be loaded in order for the datatable to be accessible.

they way i see it, the major issue is paths, not exactly hardcoding.

i think there are object ids (as in uuids) but i haven’t really used them much. these will be inmune to moving.

depending on how often you reference these assets you can also reference them by name and do a search in the asset registry. and it could reduce the chances of a broken reference.

1 Like

I’m moving those files very frequently now.
Because I’m just starting to use assets.
I’ve only been learning how to use assets for a week.
I’m looking for the best way to get a proper setup.
So I’m trying a few things and none of them seem to be optimal… assets are causing a ton of problems.
At this point I want to separate the assets that are loaded on the server and on the client separately.
So, actually there will be two Masters… and two critical paths that can be broken.

It seems that redirectors only work when something is referenced in bluprints.
I’ve used Developer Settings before. But redirectors don’t work there. If you move something there, it breaks too.
(At least that’s what I’ve seen in all versions prior to UE5.6)

I will investigate the Asset Registry and the uuids

Thank you very much for your help @nande

awesome. i also use the same approach. experiment to find the optimal.

keep in mind that once you settle the breakage will decrease.

i’ve been almost exclusively cpp for a few years, it has its rough edges but i love it more than using bps.

oh bummer. i’ll try with my project when i remember and see if that helps.

i just tested in my game. it does follows redirections, but once you fix it, it doesn’t use the new one… which i would report to ue as a bug.

awesome.

the asset registry is pretty cool, as you can iterate it async, and control loading/unloading of assets too.

my pleasure. thanks for the kindness :slight_smile: good luck and keep experimenting. :slight_smile:

you might also want to try using TSoftObjectPtr which has a load function.

and also TAssetPtr.

both of which could follow redirections potentially (just a hunch, untested, worth trying). Asynchronous Loading with TAssetPtr<T> · Unreal🌱Garden

here’s a demo of me testing the asset redirection with a developer settings reference https://www.youtube.com/watch?v=oi_CXqxlkvA

TSoftObjectPtr(FSoftObjectPath(“/Game/DataAssets/PDA_Master.PDA_Master”));

i use that all the time. it has the benefit that you can reference actors in the level. it’s ultra helpful.

for example, i can hardcode this and in runtime, when the actor gets loaded, the ptr becomes automagically populated. (i have dynamic loading of assets and actors)

TSoftObjectPtr<AActor>(FSoftObjectPath("/Game/LifeDev/Game/Sys/Game_L.Game_L:PersistentLevel.LNPC04_UAID_D8BBC116E501A1E401_1207918287"

1 Like

Hi @nande

Thank you for taking the time to explain the alternatives and prepare the video. I’ll take your ideas on Asset Registry, UUIDs, and redirects into consideration; I really appreciate the effort and thought you put into it, and I’m sure it will be useful. It’s clear you invested a lot of time and care, and that’s something I truly value.

Best regards :heart:

1 Like