Skip to content

Commit

Permalink
Merge branch 'release/v7.3.0' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
HarrisonHough committed Oct 23, 2024
2 parents 6310fde + 03d2f31 commit f6ea3c4
Show file tree
Hide file tree
Showing 18 changed files with 329 additions and 42 deletions.
4 changes: 1 addition & 3 deletions .github/latest.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@
## Changelog

## Updated
- Updated handling of response data to reduce garbage allocation [#314](https://github.com/readyplayerme/rpm-unity-sdk-core/pull/314)
## Fixed
- Preserve AssetId property in IAssetData [#313](https://github.com/readyplayerme/rpm-unity-sdk-core/pull/313)
- auth-related requests now use auth-service endpoints [#317](https://github.com/readyplayerme/rpm-unity-sdk-core/pull/317)
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [7.3.0] - 2024.10.22

## Updated
- auth-related requests now use auth-service endpoints [#317](https://github.com/readyplayerme/rpm-unity-sdk-core/pull/317)
- updated shader variants to fix issues various material issues

## Fixed
- Fixed an issue causing Out of Bounds exception in WebGL voice handler [#322](https://github.com/readyplayerme/rpm-unity-sdk-core/pull/322)

## Added
- DestroyMesh class can be used to destroy manually destroy mesh, materials and textures to prevent memory leaks

## [7.2.0] - 2024.09.06

Expand Down
5 changes: 2 additions & 3 deletions Runtime/AvatarCreator/Scripts/Data/Constants/AuthConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
public static class AuthConstants
{
public const string EMAIL = "email";
public const string AUTH_TYPE = "authType";
public const string AUTH_TYPE_CODE = "code";
public const string AUTH_TYPE_PASSWORD = "password";
public const string CODE = "code";
public const string TOKEN = "token";
public const string REFRESH_TOKEN = "refreshToken";
public const string USER_ID = "id";
public const string APP_NAME = "appName";
}
}
13 changes: 13 additions & 0 deletions Runtime/AvatarCreator/Scripts/Data/CreatedUser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace ReadyPlayerMe.AvatarCreator
{
public struct CreatedUser
{
public string Id;
public string Name;
public string Email;
public string Token;
public string RefreshToken;
public string LastModifiedAvatarId;
}
}

11 changes: 11 additions & 0 deletions Runtime/AvatarCreator/Scripts/Data/CreatedUser.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions Runtime/AvatarCreator/Scripts/Data/UserSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,16 @@ public struct UserSession
public string Token;
public string RefreshToken;
public string LastModifiedAvatarId;

public UserSession(CreatedUser createdUser)
{
Id = createdUser.Id;
Name = createdUser.Name;
Email = createdUser.Email;
Token = createdUser.Token;
RefreshToken = createdUser.RefreshToken;
LastModifiedAvatarId = createdUser.LastModifiedAvatarId;
}
}
}

17 changes: 17 additions & 0 deletions Runtime/AvatarCreator/Scripts/JsonConverters/AuthDataConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,30 @@ public static class AuthDataConverter
private const string DATA = "data";

public static string CreatePayload(Dictionary<string, string> data)
{
return JObject.FromObject(data).ToString();
}

public static string CreateDataPayload(Dictionary<string, string> data)
{
return new JObject(
new JProperty(DATA, JObject.FromObject(data))
).ToString();
}

public static JToken ParseResponse(string response)
{
var json = JObject.Parse(response);

if (json == null)
{
throw new Exception("No data received");
}

return json;
}

public static JToken ParseDataResponse(string response)
{
var json = JObject.Parse(response);
var data = json.GetValue(DATA);
Expand Down
36 changes: 22 additions & 14 deletions Runtime/AvatarCreator/Scripts/WebRequests/AuthAPIRequests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class AuthAPIRequests
private readonly string domain;
private readonly IDictionary<string, string> headers = CommonHeaders.GetHeadersWithAppId();
private readonly string rpmAuthBaseUrl;
private readonly string appName;

private readonly WebRequestDispatcher webRequestDispatcher;

Expand All @@ -33,24 +34,33 @@ public AuthAPIRequests(string domain)
this.domain = domain;
webRequestDispatcher = new WebRequestDispatcher();

rpmAuthBaseUrl = string.Format(Env.RPM_SUBDOMAIN_BASE_URL, domain);
rpmAuthBaseUrl = Env.RPM_API_V1_BASE_URL;
appName = CoreSettingsHandler.CoreSettings.Subdomain;
}

public async Task<UserSession> LoginAsAnonymous(CancellationToken cancellationToken = default)
{
var response = await webRequestDispatcher.SendRequest<ResponseText>($"{rpmAuthBaseUrl}/users", HttpMethod.POST, headers, ctx:cancellationToken);
var payload = JsonConvert.SerializeObject(new {
data = new {
appName = appName,
requestToken = true
}
});

var response = await webRequestDispatcher.SendRequest<ResponseText>($"{rpmAuthBaseUrl}users", HttpMethod.POST, headers, payload, ctx:cancellationToken);
response.ThrowIfError();

var data = AuthDataConverter.ParseResponse(response.Text);
return JsonConvert.DeserializeObject<UserSession>(data!.ToString());
var data = AuthDataConverter.ParseDataResponse(response.Text);
var createdUser = JsonConvert.DeserializeObject<CreatedUser>(data!.ToString());

return new UserSession(createdUser);
}

public async Task SendCodeToEmail(string email, string userId = "",CancellationToken cancellationToken = default)
{
var data = new Dictionary<string, string>
{
{ AuthConstants.EMAIL, email },
{ AuthConstants.AUTH_TYPE, AuthConstants.AUTH_TYPE_CODE }
};

if (!string.IsNullOrEmpty(userId))
Expand All @@ -60,23 +70,24 @@ public async Task SendCodeToEmail(string email, string userId = "",CancellationT

var payload = AuthDataConverter.CreatePayload(data);

var response = await webRequestDispatcher.SendRequest<ResponseText>($"{rpmAuthBaseUrl}/auth/start", HttpMethod.POST, headers, payload, ctx:cancellationToken);
var response = await webRequestDispatcher.SendRequest<ResponseText>($"{rpmAuthBaseUrl}auth/request-login-code", HttpMethod.POST, headers, payload, ctx:cancellationToken);
response.ThrowIfError();
}

public async Task<UserSession> LoginWithCode(string code, string userIdToMerge = null, CancellationToken cancellationToken = default)
{
var body = new Dictionary<string, string>
{
{ AuthConstants.AUTH_TYPE_CODE, code }
{ AuthConstants.CODE, code },
{ AuthConstants.APP_NAME, appName }
};
if (userIdToMerge != null)
{
body.Add(AuthConstants.USER_ID, userIdToMerge);
}
var payload = AuthDataConverter.CreatePayload(body);

var response = await webRequestDispatcher.SendRequest<ResponseText>($"{rpmAuthBaseUrl}/auth/login", HttpMethod.POST, headers, payload, ctx:cancellationToken);
var response = await webRequestDispatcher.SendRequest<ResponseText>($"{rpmAuthBaseUrl}auth/login", HttpMethod.POST, headers, payload, ctx:cancellationToken);
response.ThrowIfError();

var data = AuthDataConverter.ParseResponse(response.Text);
Expand All @@ -88,12 +99,11 @@ public async Task Signup(string email, string userId, CancellationToken cancella
var data = new Dictionary<string, string>
{
{ AuthConstants.EMAIL, email },
{ AuthConstants.AUTH_TYPE, AuthConstants.AUTH_TYPE_PASSWORD },
{ AuthConstants.USER_ID, userId }
};

var payload = AuthDataConverter.CreatePayload(data);
var response = await webRequestDispatcher.SendRequest<ResponseText>($"{rpmAuthBaseUrl}/auth/start", HttpMethod.POST, headers, payload, ctx:cancellationToken);
var response = await webRequestDispatcher.SendRequest<ResponseText>($"{rpmAuthBaseUrl}auth/signup/passwordless", HttpMethod.POST, headers, payload, ctx:cancellationToken);
response.ThrowIfError();
}

Expand All @@ -114,18 +124,16 @@ public async Task<RefreshTokenResponse> GetRefreshToken(string token, string ref

private async Task<JToken> RefreshRequest(string token, string refreshToken, CancellationToken cancellationToken)
{
var url = $"{rpmAuthBaseUrl}/auth/refresh";

var payload = AuthDataConverter.CreatePayload(new Dictionary<string, string>
{
{ AuthConstants.TOKEN, token },
{ AuthConstants.REFRESH_TOKEN, refreshToken }
});

var response = await webRequestDispatcher.SendRequest<ResponseText>(url, HttpMethod.POST, headers, payload, ctx:cancellationToken);
var response = await webRequestDispatcher.SendRequest<ResponseText>($"{rpmAuthBaseUrl}auth/refresh", HttpMethod.POST, headers, payload, ctx:cancellationToken);
response.ThrowIfError();

return AuthDataConverter.ParseResponse(response.Text);
return AuthDataConverter.ParseDataResponse(response.Text);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public async Task<AvatarProperties> CreateFromTemplateAvatar(string templateId,
{ BODY_TYPE, CoreSettingsHandler.CoreSettings.BodyType.GetDescription() }
};

var payload = AuthDataConverter.CreatePayload(payloadData);
var payload = AuthDataConverter.CreateDataPayload(payloadData);

var response = await authorizedRequest.SendRequest<ResponseText>(
new RequestData
Expand Down
15 changes: 11 additions & 4 deletions Runtime/Core/Scripts/Animation/VoiceHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class VoiceHandler : MonoBehaviour
private bool CanGetAmplitude => AudioSource != null && AudioSource.clip != null && AudioSource.isPlaying;

private CancellationTokenSource ctxSource;

private void Start()
{
CreateBlendshapeMeshMap();
Expand Down Expand Up @@ -165,10 +165,17 @@ public void PlayAudioClip(AudioClip audioClip)

private float GetAmplitude()
{
if (CanGetAmplitude)
if (CanGetAmplitude && AudioSource.clip.loadState == AudioDataLoadState.Loaded)
{
var amplitude = 0f;
var currentPosition = AudioSource.timeSamples;
var remaining = AudioSource.clip.samples - currentPosition;
if (remaining > 0 && remaining < AUDIO_SAMPLE_LENGTH)
{
return 0f;
}

AudioSource.clip.GetData(audioSample, AudioSource.timeSamples);
var amplitude = 0f;

foreach (var sample in audioSample)
{
Expand All @@ -178,7 +185,7 @@ private float GetAmplitude()
return Mathf.Clamp01(amplitude / audioSample.Length * AMPLITUDE_MULTIPLIER);
}

return 0;
return 0f;
}

#region Blend Shape Movement
Expand Down
2 changes: 1 addition & 1 deletion Runtime/Core/Scripts/Data/ApplicationData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ReadyPlayerMe.Core
{
public static class ApplicationData
{
public const string SDK_VERSION = "v7.2.0";
public const string SDK_VERSION = "v7.3.0";
private const string TAG = "ApplicationData";
private const string DEFAULT_RENDER_PIPELINE = "Built-In Render Pipeline";
private static readonly AppData Data;
Expand Down
52 changes: 52 additions & 0 deletions Runtime/Core/Scripts/Utils/DestroyMesh.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using UnityEngine;

namespace ReadyPlayerMe
{
/// <summary>
/// This class is responsible for destroying all SkinnedMeshRenderer components and their associated resources (meshes, materials, and textures)
/// when the GameObject is destroyed to prevent memory leaks.
/// </summary>
public class DestroyMesh : MonoBehaviour
{
private SkinnedMeshRenderer[] meshes;

/// <summary>
/// Called when the script instance is being loaded.
/// Initializes the meshes array by finding all SkinnedMeshRenderer components in the child objects of the current GameObject.
/// </summary>
private void Awake()
{
meshes = GetComponentsInChildren<SkinnedMeshRenderer>();
}

/// <summary>
/// Called when the GameObject is destroyed.
/// Destroys all associated SkinnedMeshRenderer meshes, materials, and textures to ensure proper memory management.
/// </summary>
private void OnDestroy()
{
foreach (var mesh in meshes)
{
var materials = mesh.sharedMaterials;

foreach (var material in materials)
{
if (material == null) continue;

foreach (var property in material.GetTexturePropertyNames())
{
var texture = material.GetTexture(property);

if (texture == null) continue;

Destroy(texture);
}

Destroy(material);
}

Destroy(mesh.sharedMesh);
}
}
}
}
11 changes: 11 additions & 0 deletions Runtime/Core/Scripts/Utils/DestroyMesh.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f6ea3c4

Please sign in to comment.