Hello,
While working on some feature in our project we have faced an issue with some string tables. After an investigation, we have found that there is a bug in the asynchronous path of the string table loading logic. Please find details below.
[Simplified] description of the issue:
1. If there is a string table StringTableA with the package path /Game/<SomePakagePath>/StringTableA, and
2. StringTableA was moved to a new location with a redirection asset creation, so that:
a. /Game/<SomeNewPakagePath>/StringTableA is a new package path for the moved string table, and
b. /Game/<SomePakagePath>/StringTableA now points to the created redirector asset, and
3. FTextHistory_StringTableEntry is created using the old string table path (table id) /Game/<SomePakagePath>/StringTableA, and
4. StringTableA is loaded asyncronously, then
5. After the StringTableA is loaded, the FTextHistory_StringTableEntry::StringTableReferenceData->TableId will not be properly updated to hold the real new table id (which is now /Game/<SomeNewPakagePath>/StringTableA), but will be set instead to the old table id value (/Game/<SomePakagePath>/StringTableA).
6. The incorrect value of FTextHistory_StringTableEntry::StringTableReferenceData->TableId (which is not the real new table id, but instead the old table id (before the string table was moved)) will cause the issue when the affected TextHistory_StringTableEntry is saved as a part of some asset (please do the provided repro steps to see the problem in action).
Some additional notes on the problem:
1. The hidden implicit redirectors application to soft paths during the serialization is a part of the problem.
2. The FTextHistory_StringTableEntry::Serialize(…) has flawed implementation. In particular, the serialized value of TableId can be changed between the different executions during the package saving (harvesting / saving steps):
`void FTextHistory_StringTableEntry::Serialize(FStructuredArchive::FRecord Record)
{
…
if (BaseArchive.IsLoading())
{
…
}
else if (BaseArchive.IsSaving())
{
FName TableId;
FTextKey Key;
if (StringTableReferenceData)
{
StringTableReferenceData->GetTableIdAndKey(TableId, Key);
}
Record << SA_VALUE(TEXT("TableId"), TableId); // <== HERE: different executions during the package saving
Key.SerializeAsString(Record.EnterField(TEXT("Key"))); // will see different values for the TableId
}
// Collect string table asset references
if (StringTableReferenceData)
{
StringTableReferenceData->CollectStringTableAssetReferences(Record); // <== TableId will be changed here (after the
} // first serialization above)
}`These things contribute to the problem, but for the real cause please see the next post (post characters limit) …