Tracking player progression?

Hey guys, I’m working on a tracking system to know what “Objectives” my player is doing / has done in order to complete a “Quest” but I’m stuck.

The way I’m building it so far is like this :

S_DataObjective : Structure

  • var ObjectiveID : FName
  • var ObjectiveDescription : Text
  • var ObjectiveIsCompleted : Bool

S_QuestTableFormat : Structure

  • var QuestDescription : Text
  • var QuestIsCompleted : Bool
  • var QuestObjectives : Array of Structure of type S_DataObjective

DT_Quests : Data Table based of S_QuestTableFormat containing all the information about all the quests, one quest per row.

Finally, once I spawn a new quest at runtime, I look into this Data Table to assign the values to this specific quest on its beginplay, using the Row Name of the Data Table as an ID for the quest.

This is all working fine so far, but I fear it might be hard to scale this up or if I have to add new objectives or rename an objective of a quest.


I now have different objects that can interact with a Quest to update its state. For instance, I have a collision box that can address the quest by sending a S_DataObjective (manually typed) through an interface and set it as completed inside the quest.

Since I’m using FName as the Objectives identifiers, I have to write the exact same name as the Data Table each time I want to address a specific quest, and I feel there must be another way to do this that would be more secure. Currently, if for some reason the FName is changed in the Data Table, none of my objects will follow this updated ID which I find scary.

I was thinking of using an enum containing all the IDs of the objectives, and using this enum in the S_DataObjective structure instead of the FName. This way, I would only type the ID once in the enum, and select it (in drop-down menu) everywhere else when I need to address this objective. The thing though is that this enum would end up having maybe more than 200+ enumerators.

Am i setting myself for a catastrophe? What would you recommend I look into?

Thank you!

Hello @insertech ,

I think using FName as a identifier is fine but pretty risky. It will definitely became a problem in the future if there is a change in there. For example, if you save that FName, and there is an update on that specific one, that will be a problem.

I think its better if you add one more variable separated from that FName if you show the FName on Screen, so in the future if you want to update that FName value, that won’t cause any problem.

Using Enum is a great way for this, however, one thing that you must note about enum, as far as I know, Enum can only accept uint8 (0-255) and that mean you can only have around 250 QuestObjective. If you know that you only need that size, that’s fine. However, if you plan to update the game much larger in the future, or the quests are more than that value, consider using normal integer for that.

If you aren’t sure about how much, it’s better to use uint32/int32 so you can freely increase the objective without limiting yourself to that 250.

You don’t want to think like “for now I will use enum and in the future if I need it, I will change it to integer” because there will be a lot to work on at that moment, and you have to make sure that every objective work again after that changes.

Edit
I already do a little experiment about creating enum in C++, you can create an uint32 enum, however, if you need to access the enum via blueprint / use in blueprint, you can only have uint8 enum. So in your case, the size limit is just around 250 (uint8).

Thank you so much for your answer and your test!

Is there another thing I could use other than an enum to do this, even if it’s changing how I handle things? I can’t say for sure as of right now, but I’m pretty confident I’m going to have more than 250+ enumerators in my enum of IDs.

I’ve read comments about using gameplay tags instead of an enum, which would also offer the possibility to select the ID in a form of drop-down menu. Do you know if I would hit a similar limit or if it isn’t the right use of gameplay tags?

Hello @insertech , sorry for late respond,

If you’re pretty sure that you will have more than 250, definitely don’t use enum. Just use another type.

About gameplay tags, I never use it, however, I look through the C++ and I see that it is saved in an TArray type which is usually don’t have any limit. I think it’s fine if you want to use Gameplay tags, however I can’t provide any weakness or how to implement it since I never touch it before.

If you want to consider using gameplay tags for that, maybe you have to do a little experiment about it first for that usage. I can’t help much for gameplay tags, sorry.

Edit
I might be wrong at this but there is a possibility that if you rename the tag, it will also be a problem. Example case:
My player take a quest and the gameplay tag is “BuyAHouse” and then save the game. After then you rename the gameplay tags to “RentAHouse” since it make more sense to rent first before buying it. Then you load the old save game which “BuyAHouse” is still the tag for the quest, it won’t be loaded since “BuyAHouse” is not valid anymore and the code don’t know if you rename it.

This might be wrong, since I don’t know how do we save the tags. However if you save it just the String value, like in a FString/FName/FText variable, this definitely will be a problem.

You won’t get this kind of problem with Enum since enum store it in integer. Even tough you rename your enumerator from Quest_BuyHouse to Quest_RentHouse, the integer value is still the same so it won’t be a problem. I hope this make sense to you.

Also please @ / tag me if you reply for visibility ;D