Steps to Reproduce
If you pass in a negative number in an FName it fails to resolve correctly with a soft object ptr. See example code that can be added to an actor:
It seems to boil down to the fact that the “ParseNumberFromName” function assumes that FNames don’t have negative numbers when they are stored as a string:
/**
* Parse the number from the end of a string like Prefix_1.
*
* Number must be non-negative, less than MAX_int32, and not have a leading 0 unless the number is 0.
* Returns the internal representation of the external number in the string. Example: Prefix_0 returns 1.
*
* @param Name Name to parse the trailing number from.
* [Content removed] updated to exclude the _<N> suffix if a number is parsed.
* [Content removed] or NAME_NO_NUMBER_INTERNAL if no number was parsed.
*/
template <typename CharType>
static constexpr uint32 ParseNumberFromName(const CharType* Name, int32& InOutLen)
{
int32 Digits = 0;
for (const CharType* It = Name + InOutLen - 1; It >= Name && *It >= '0' && *It <= '9'; --It)
{
++Digits;
}
const CharType* FirstDigit = Name + InOutLen - Digits;
constexpr int32 MaxDigitsInt32 = 10;
if (Digits && Digits < InOutLen && FirstDigit[-1] == '_' && Digits <= MaxDigitsInt32 && (Digits == 1 || *FirstDigit != '0'))
{
int64 Number = 0;
for (int32 Index = 0; Index < Digits; ++Index)
{
Number = 10 * Number + (FirstDigit[Index] - '0');
}
if (Number < MAX_int32)
{
InOutLen -= 1 + Digits;
return static_cast<uint32>(NAME_EXTERNAL_TO_INTERNAL(Number));
}
}
return NAME_NO_NUMBER_INTERNAL;
}
I’m working around this by only using positive numbers in my FNames so this is not an urgent issue for me but it feels like something that could cause issues so I thought I would raise it here.
ParseNumberFromName is right in that a negative number shouldn’t be possible when constructing an FName. I think all of your problems with TSoftObjectPtr are downstream from this.
I think the issue here is an oversight in the FName(const CharType* Name, int32 Number) constructors, which should really assert if given a negative number. Or did you manage to create your negative FName by other means?
Just to keep you up to date on this issue - there are a few systems which are using NAME_NO_NUMBER instead of NAME_NO_NUMBER_INTERNAL to construct an FName, causing a negative number to be created. I’ve already updated the name API to make it clear(er) that incoming numbers are in internal format, and I’ve requested that those aforementioned systems clean up their uses. After that, I’ve got a change ready to go which will cause FName to assert if constructed with a negative number. So we shouldn’t get into this state.
I have not tried creating them in other ways. If the intention is to not allow negative numbers then the constructor should not allow it. Not sure if there are other mechanisms that stop users from creating fnames with negative numbers if they are typed in the editor for example.