Hello,
We have encountered rather unfortunate behavior regarding Composite data tables and Gameplay behavior tags. We set up a “main” composite data table for gameplay tags and split the data among multiple data tables. All of the tables are set with row type FGameplayTagTableRow.
When a new row is added to any of the parent tables (that hold the actual data) the newly added gameplay tag cannot be used unless the main (i.e. the composite) data table is saved.
I have looked into the code and found that gameplay tags are rebuilt in FGameplayTagsEditorModule::OnPackageSaved that verifies if the saved package contains some of the GameplayTagTables from UGameplayTagsManager. This naturally works only for the main composite data table and not for any of its parent tables (as they are not registered into UGameplayTagsManager directly).
This is not ideal since saving the composite table does checkout of the table and if someone then forgets to unlock the file, it partially negates one of the advantages of working with a composite data table - that it allows easy cooperation.
First of all, is there any other way to force the refresh of the gameplay tags? I haven’t found any button in the editor or console command.
We would like to implement the automatic refresh of the gameplay tags when one of the parent tables is saved. I think it can be achieved in FGameplayTagsEditorModule::OnPackageSaved by testing if the saved UObjects is not contained in one of the Manager.GameplayTagTables as a Parent table. It would require adding a test to the UCompositeDataTable that a specified UDataTable is one of its parent tables. At first glance it seems harmless, but there might be some catch. Is there something I am missing?
Thanks,
Matej
Hi Matej,
Sorry about the delay, I was just assigned this ticket now. I will look into it now and should get back to you soon.
Best regards,
Vitor
Hello,
thank you for the reply. In the meantime I’ve had a go at it myself. I’ve added this bit into FGameplayTagsEditorModule::OnPackageSaved
for (UObject* Entry : Objects)
{
if (UDataTable* DataTable = Cast<UDataTable>(Entry))
{
if (Manager.GameplayTagTables.Contains(DataTable))
{
bRefreshGameplayTagTree = true;
break;
}
// MODIFICATION BEGIN
for (UDataTable* GameplayTagTable : Manager.GameplayTagTables)
{
if (UCompositeDataTable* CompositeTable = Cast<UCompositeDataTable>(GameplayTagTable))
{
if (CompositeTable->IsParentTable(DataTable))
{
bRefreshGameplayTagTree = true;
break;
}
}
}
if (bRefreshGameplayTagTree)
{
// break the outer for loop iterating package's objects
break;
}
//~ MODIFICATION END
}
}
Naturally this requires adding new function to the UCompositeTable, which is quite straightforward
bool UCompositeDataTable::IsParentTable(const UDataTable* DataTable) const
{
return !!ParentTables.FindByPredicate([DataTable](UDataTable* ParentTable)
{
return ParentTable == DataTable;
});
}
That seems to be working fine. When I save any of the parent tables, the gameplay tags get refreshed and I can use the newly added tag straightaway.
Cheers,
Matej
Hi Vitor,
thanks for the reply and feedback. I’ve modified the code on our side accordingly to include TObjectPtr.
I think we are quite content now and we will eventually merge the code, if it gets solved in the engine.
Cheers,
Matej
Hi Matej,
Thank you for the report and repro steps. I was able to reproduce this issue here on all recent UE versions and latest source build. I also looked for an easy way to force a refresh of the gameplay tags, but unfortunately I couldn’t find any, except making some change to the related Project Settings.
One possible workaround (also non-ideal) would be to add all the parent tables to the Gameplay Tag Table List in the Project Settings, but I understand that this would mean keeping the same information in sync in two places. Another possibility would be to implement a BlueprintCallable function in C++ that calls UGameplayTagsManager::Get().EditorRefreshGameplayTagTree(), then using that to create an Editor Utility.
When building the engine from source, your solution seems appropriate and better than any of the workarounds above, as it follows the same idea currently being used by FGameplayTagsEditorModule::OnPackageSaved(). I would only suggest a minor change to UCompositeDataTable::IsParentTable():
bool UCompositeDataTable::IsParentTable(const TObjectPtr<UDataTable>& TableToCheck)
{
return ParentTables.Contains(TableToCheck);
}
I’ve filed a bug report about this issue so that the engine devs can take a look. Here’s the tracking number: UE-356915. The link should become available once the devs mark it as public.
Let me know if there is anything else I can do to assist you.
Best regards,
Vitor