Problems loading player Name and Id from Photon on Oculus Quest 2 (Unreal Engine 5 c++)

Hi! I'm working on a application for Oculus Quest 2 using Photon and Unreal Engine 5.

I've been able to test the application succesfull in the desktop, and the APK compiles perfectly. I've also been able to play in the Oculus fine. However, at some point when the application tries to get the Name and Id of the player (after successfully connecting Photon Server),

MutablePlayer LocalPlayer = PlayerClient->getLocalPlayer();
FString Name = FString(LocalPlayer.getName().UTF8Representation().cstr());
FString Id = FString(LocalPlayer.getUserID().UTF8Representation().cstr());

Oculus breaks and sends an error:

 ../Common-cpp/src/StringConverters/android/utf8/utf8/checked.h:105: utf8::uint32_t utf8::next(octet_iterator&, octet_iterator) [with octet_iterator = const unsigned char*; utf8::uint32_t = unsigned int]: assertion "err_code == internal::UTF8_OK" failed

(Please note again that everything works fine in the desktop. It only breaks in Oculus).

Just in case I also tried using ANSIConversion(), but I still get the same error.


Do you guys have any idea of why this could happen?

Thank you in advance!

Best Answers

  • ManuelOM
    ManuelOM
    Answer ✓

    I fixed the problem! It turns out that the problem was in the SetName instead of the GetName.

    replacing

    const char* Name = TCHAR_TO_UTF8(*PlayerName);
    PlayerClient->getLocalPlayer().setName(JString(Name));
    

    with

    PlayerClient->getLocalPlayer().setName(JString(TCHAR_TO_UTF8(*PlayerName)));
    

    fixed the error.

  • Kaiserludi
    Kaiserludi admin
    Answer ✓

    Hi @ManuelOM.


    Ah. That actually makes perfect sense.

    TCHAR_TO_UTF8(*PlayerName)
    

    returns a pointer to the member of a temporary class instance. The lifetime of that instance ends at the end of the expression, which in the presented code means at the ';'

    So in the very next line 'Name' already points to garbage.

    In your fixed version the JString-constructor is part of the same expression, as once again the expression ends at the ';', so the argument string is still valid during the construction of the JString and once setName() returns, so before the ';', the local player instance has it's own copy of the string, which won't get invalid at the end of the expression.

    https://docs.unrealengine.com/4.27/en-US/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/StringHandling/CharacterEncoding/ mentions the short lifetime and states that macros like TCHAR_TO_UTF8 are only supposed to be directly used as function parameters (like in your fixed version), and it explicitly says that assigning the return value of TCHAR_TO_UTF8 to a local variable (like in your original code) can cause a crash.

Answers

  • Hi @ManuelOM.

    The function cstr() returns a pointer to an array of char that is owned by the object that this function is called on.

    Your code calls it on a temporary object of class UTF8String that is returned by UTF8Representation().

    This temporary should be valid until the end of the full expression, so until the FString is constructed.

    However the error looks like somehow that temporary gets destructed before the FString is constructed, so that the pointer returned by cstr() is no longer pointing to valid memory inside the FString, which would be a bug in the compiler.

    If that is actually the case, then replacing the temporary with a local variable like this should solve the issue:

       MutablePlayer LocalPlayer = mClient.getLocalPlayer();
       UTF8String utf8Name = LocalPlayer.getName().UTF8Representation();
       UTF8String utf8Id = LocalPlayer.getName().UTF8Representation();
       FString Name = FString(utf8Name.cstr());
       FString Id = FString(utf8Id.cstr());
    


  • Thank you @Kaiserludi! I'm going to try it, and will let you know if it works :)

  • Hi @Kaiserludi ,

    I've tried your method but sadly I keep getting the same error. Do you have any other idea of why this could happen? 😅


    Thanks!

  • ManuelOM
    ManuelOM
    Answer ✓

    I fixed the problem! It turns out that the problem was in the SetName instead of the GetName.

    replacing

    const char* Name = TCHAR_TO_UTF8(*PlayerName);
    PlayerClient->getLocalPlayer().setName(JString(Name));
    

    with

    PlayerClient->getLocalPlayer().setName(JString(TCHAR_TO_UTF8(*PlayerName)));
    

    fixed the error.

  • Kaiserludi
    Kaiserludi admin
    Answer ✓

    Hi @ManuelOM.


    Ah. That actually makes perfect sense.

    TCHAR_TO_UTF8(*PlayerName)
    

    returns a pointer to the member of a temporary class instance. The lifetime of that instance ends at the end of the expression, which in the presented code means at the ';'

    So in the very next line 'Name' already points to garbage.

    In your fixed version the JString-constructor is part of the same expression, as once again the expression ends at the ';', so the argument string is still valid during the construction of the JString and once setName() returns, so before the ';', the local player instance has it's own copy of the string, which won't get invalid at the end of the expression.

    https://docs.unrealengine.com/4.27/en-US/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/StringHandling/CharacterEncoding/ mentions the short lifetime and states that macros like TCHAR_TO_UTF8 are only supposed to be directly used as function parameters (like in your fixed version), and it explicitly says that assigning the return value of TCHAR_TO_UTF8 to a local variable (like in your original code) can cause a crash.