Issues with loading avatars on Unity

Hi,

I’ve just integrated the AvatarCreator into our application, FirstStage, and could do with a few pointers.

(1) The creation process uses the AvatarManager class but if I load a saved avatar through that it does not respect the avatar config in the settings. So for the final load I’ve been trying to use AvatarObjectLoader but that fails in the MetadataDownloader with unexpected BodyType.

After a bit of digging, it seems that the two routes parse the json response differently. The AvatarAPIRequests pulls out the “data” element and then parses that into AvatarMetadata whereas the MetadataDownloader doesn’t and fails to parse the response as a result.

(2) It looks like the AvatarObjectLoader should be able to use the avatar cache but as far as I can tell, nothing saves avatars to the local cache - is that something I have to manage on our side of the code?

This integration has been going well so far, so hope you can help get over these snags…

Hey Dave,

What version of the SDK are you using?
What avatar URL are you using when the metadatadownloader fails?
How are you checking the local avatar cache? (which folder do you check and is the caching enabled in the settings?)

Hi Gonzalo,

Thanks for getting back to me. I’ve made a bit more progress since then: avatar caching is now working fine - I had misunderstood when it happened and I think confused between the avatar creator and the avatar wizard which seem to use different codepaths.

I have just upgraded to version 7.0.0 of the SDK and must report that there is still an issue with the MetadataDownloader failing to parse the json correctly.

I’m downloading the avatar with this call:

            var avatarLoader = new AvatarObjectLoader();

            var args = await avatarLoader.LoadAvatarAsync( $"{RPM_AVATAR_V2_BASE_URL}/{avatarId}.glb" );

With the latest SDK, I get the following error:

[Ready Player Me] MetadataDownloader: Failed to parse metadata. Unexpected body type.
UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
ReadyPlayerMe.Core.CustomLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[]) (at ./Library/PackageCache/com.readyplayerme.core@dc0efc3ec8/Runtime/Core/Scripts/Logger/CustomLogHandler.cs:15)
UnityEngine.Logger:Log (string,object)
ReadyPlayerMe.Core.SDKLogger:Log (string,object) (at ./Library/PackageCache/com.readyplayerme.core@dc0efc3ec8/Runtime/Core/Scripts/Logger/SDKLogger.cs:37)
ReadyPlayerMe.Core.MetadataDownloader/<Download>d__14:MoveNext () (at ./Library/PackageCache/com.readyplayerme.core@dc0efc3ec8/Runtime/Core/Scripts/Operations/MetadataDownloader.cs:105)

My fix is this (in MetadataDownloader)

        private AvatarMetadata ParseResponse(string response)
        {
            var json = JObject.Parse(response);
            var data = json[DATA]!.ToString();
            var metadata = JsonConvert.DeserializeObject<AvatarMetadata>(data, new JsonSerializerSettings
            {
                DateFormatString = METADATA_TIME_FORMAT
            });

            if (metadata.BodyType == BodyType.None)
            {
                throw new CustomException(FailureType.MetadataParseError, FAILED_TO_PARSE_METADATA_UNEXPECTED_BODY_TYPE);
            }

            SDKLogger.Log(TAG, $"{metadata.BodyType} metadata loading completed.");
            return metadata;
        }
        
        private const string DATA = "data";

However, it seems to me the original could never work, so I must be driving it wrong somehow?

I have two other issues (possibly as a result of moving to SDK 7.0.0):

(1) When the avatar is saved by the avatar creator, I keep getting errors from the server such as:

{"type":"NotFoundError","status":404,"message":"Avatar not found"}
PUT https://api.readyplayer.me/v2/avatars/668bfc051847c40762aa9582

(although sometimes it’s 403/Forbidden)

(2) The Gender metadata seems to be None with a load of avatars I’d previously saved. This leads to them using the wrong (Unity) Avatar - Feminine when it should be Masculine. This is how I’m trying to use it:

            var args = await avatarLoader.LoadAvatarAsync( $"{RPM_AVATAR_V2_BASE_URL}/{avatarId}.glb" );
            switch( args )
            {
                case CompletionEventArgs completion:
                {
                    AvatarAnimationHelper.SetupAnimator( completion.Metadata, completion.Avatar );

                    return completion.Avatar;
                }
                case FailureEventArgs failure:
                    throw new Exception( $"Failed to load RPM Character {avatarId} : {failure.Message}" );
                default:
                    throw new Exception( $"Failed to load RPM Character {avatarId} : {args}" );
            }

Any help would be much appreciated!