Skip to content

Commit 231ee27

Browse files
Merge branch 'fix/9665' into fix/9588-9591-9592-9598-9618-9630-9641-9643-9665
2 parents bfdb2ba + 69e62d9 commit 231ee27

3 files changed

Lines changed: 84 additions & 4 deletions

File tree

Explorer/Assets/DCL/AvatarRendering/Emotes/Systems/Play/EmotePlayer.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88
using System.Runtime.CompilerServices;
99
using UnityEngine;
1010
using UnityEngine.Pool;
11-
using UnityEngine.Rendering;
1211
using Utility.Animations;
13-
using AvatarMask = UnityEngine.AvatarMask;
1412
using Object = UnityEngine.Object;
1513

1614
namespace DCL.AvatarRendering.Emotes.Play
@@ -58,6 +56,8 @@ public bool Play(GameObject mainAsset, AudioClip? audioAsset, bool isLooping, bo
5856
EmoteReferences? emoteReferences = AcquireEmoteReferences(mainAsset, audioAsset, isLooping, isSpatial, in view, emoteInUse);
5957
if (emoteReferences == null) return false;
6058

59+
emotesInUse.Add(emoteReferences, pools[mainAsset]);
60+
6161
if (emoteReferences.legacy)
6262
{
6363
if (!legacyAnimationsEnabled)
@@ -71,7 +71,6 @@ public bool Play(GameObject mainAsset, AudioClip? audioAsset, bool isLooping, bo
7171
else
7272
PlayMecanimEmote(view, ref emoteComponent, emoteReferences, isLooping);
7373

74-
emotesInUse.Add(emoteReferences, pools[mainAsset]);
7574
emoteComponent.CurrentEmoteReference = emoteReferences;
7675
return true;
7776
}
@@ -87,6 +86,8 @@ public bool PlayMasked(GameObject mainAsset, AudioClip? audioAsset, bool isLoopi
8786
EmoteReferences? emoteReferences = AcquireEmoteReferences(mainAsset, audioAsset, isLooping, isSpatial, in view, emoteInUse);
8887
if (emoteReferences == null) return false;
8988

89+
emotesInUse.Add(emoteReferences, pools[mainAsset]);
90+
9091
if (emoteReferences.legacy)
9192
{
9293
if (!PlayMaskedLegacyEmote(view, ref maskedEmote, emoteReferences, isLooping))
@@ -98,7 +99,6 @@ public bool PlayMasked(GameObject mainAsset, AudioClip? audioAsset, bool isLoopi
9899
else
99100
PlayMaskedMecanimEmote(view, ref maskedEmote, emoteReferences, isLooping);
100101

101-
emotesInUse.Add(emoteReferences, pools[mainAsset]);
102102
maskedEmote.CurrentEmoteReference = emoteReferences;
103103
return true;
104104
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using DCL.AvatarRendering.AvatarShape.UnityInterface;
2+
using DCL.AvatarRendering.Emotes.Play;
3+
using NSubstitute;
4+
using NUnit.Framework;
5+
using UnityEngine;
6+
using Object = UnityEngine.Object;
7+
8+
namespace DCL.AvatarRendering.Emotes.Tests
9+
{
10+
public class EmotePlayerShould
11+
{
12+
private GameObject poolRoot = null!;
13+
private GameObject audioSourcePrefab = null!;
14+
private GameObject legacyEmoteAsset = null!;
15+
private GameObject avatarGameObject = null!;
16+
private EmotePlayer emotePlayer = null!;
17+
private IAvatarView avatarView = null!;
18+
19+
[SetUp]
20+
public void Setup()
21+
{
22+
poolRoot = new GameObject("ROOT_POOL_CONTAINER");
23+
audioSourcePrefab = new GameObject("EmoteAudioSource");
24+
audioSourcePrefab.AddComponent<AudioSource>();
25+
26+
emotePlayer = new EmotePlayer(audioSourcePrefab.GetComponent<AudioSource>(),
27+
ScriptableObject.CreateInstance<EmoteMaskCatalog>(), legacyAnimationsEnabled: false);
28+
29+
// Legacy emote asset: an Animator with no controller (so CreateNewEmoteReference takes the
30+
// legacy branch) plus an Animation carrying a legacy clip.
31+
legacyEmoteAsset = new GameObject("LegacyEmoteAsset");
32+
legacyEmoteAsset.AddComponent<Animator>();
33+
var animation = legacyEmoteAsset.AddComponent<Animation>();
34+
var clip = new AnimationClip { legacy = true, name = "wave" };
35+
animation.AddClip(clip, clip.name);
36+
37+
avatarGameObject = new GameObject("Avatar");
38+
39+
avatarView = Substitute.For<IAvatarView>();
40+
avatarView.GetTransform().Returns(avatarGameObject.transform);
41+
}
42+
43+
[TearDown]
44+
public void TearDown()
45+
{
46+
Object.DestroyImmediate(avatarGameObject);
47+
Object.DestroyImmediate(legacyEmoteAsset);
48+
Object.DestroyImmediate(audioSourcePrefab);
49+
Object.DestroyImmediate(poolRoot);
50+
}
51+
52+
// Regression for https://github.com/decentraland/unity-explorer/issues/9665: a legacy emote
53+
// rejected because legacyAnimationsEnabled is false must return its pooled instance to the pool.
54+
// Before the fix the reference was registered in emotesInUse only after the early-out, so Stop()
55+
// released nothing and the instance stayed parented under the avatar, leaking on every play.
56+
[Test]
57+
public void NotLeakPooledInstanceWhenLegacyEmoteRejected()
58+
{
59+
var emoteComponent = new CharacterEmoteComponent();
60+
61+
bool played = emotePlayer.Play(legacyEmoteAsset, null, false, false, in avatarView, ref emoteComponent);
62+
63+
Assert.IsFalse(played);
64+
Assert.IsNull(emoteComponent.CurrentEmoteReference);
65+
Assert.IsNull(avatarGameObject.GetComponentInChildren<EmoteReferences>(true),
66+
"Rejected legacy emote leaked a pooled instance under the avatar.");
67+
}
68+
}
69+
}

Explorer/Assets/DCL/AvatarRendering/Emotes/Tests/EmotePlayerShould.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)