Skip to content

Commit b670aa7

Browse files
committed
From Unity-Discover (3b477fb34318d7b990900bcd4c39bf239e9536c4)
1 parent 409b42f commit b670aa7

142 files changed

Lines changed: 12415 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

com.meta.utilities.avatars/Avatar.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
// Copyright (c) Meta Platforms, Inc. and affiliates.
2+
3+
using System;
4+
using System.Collections;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Threading.Tasks;
8+
using Meta.Utilities;
9+
using Oculus.Avatar2;
10+
using Oculus.Platform;
11+
using UnityEngine;
12+
using UnityEngine.Events;
13+
using static Oculus.Avatar2.CAPI;
14+
15+
namespace Meta.Utilities.Avatars
16+
{
17+
public interface IAvatarNetworking
18+
{
19+
public void Initialize();
20+
public void OnUserIdSet(ulong id);
21+
public bool IsNetworked { get; }
22+
public bool IsOwner { get; }
23+
}
24+
25+
/// <summary>
26+
/// The AvatarEntity handles the setup of the Avatar, adds functionalities to the base class OvrAvatarEntity.
27+
/// On Joint loaded callbacks
28+
/// Set up lipsync and body tracking.
29+
/// Paired with the AvatarNetworking it initializes it to support networking in a multiplayer project.
30+
/// In a not networked setup, it will track the camera rig to keep the position in sync.
31+
/// </summary>
32+
[DefaultExecutionOrder(50)] // after GpuSkinningConfiguration initializes
33+
public class AvatarEntity : OvrAvatarEntity
34+
{
35+
[Serializable]
36+
public struct OnJointLoadedPair
37+
{
38+
public ovrAvatar2JointType Joint;
39+
public Transform TargetToSetAsChild;
40+
public UnityEvent<Transform> OnLoaded;
41+
}
42+
43+
[SerializeField, AutoSet(typeof(IAvatarNetworking))]
44+
private MonoBehaviour m_networking;
45+
46+
public IAvatarNetworking Networking => m_networking != null ? m_networking as IAvatarNetworking : null;
47+
48+
[SerializeField, AutoSetFromChildren(IncludeInactive = true)]
49+
private OvrAvatarLipSyncBehavior m_lipSync;
50+
51+
[SerializeField] private bool m_isLocalIfNotNetworked;
52+
53+
public List<OnJointLoadedPair> OnJointLoadedEvents = new();
54+
55+
public Transform GetJointTransform(ovrAvatar2JointType jointType) => GetSkeletonTransformByType(jointType);
56+
public bool HasUserAvatar { get; private set; } = false;
57+
public bool HasDoneAvatarCheck { get; private set; }
58+
59+
public ovrAvatar2EntityId EntityId => entityId;
60+
61+
[Header("Face Pose Input")]
62+
[SerializeField, AutoSet]
63+
private OvrAvatarFacePoseBehavior m_facePoseProvider;
64+
[SerializeField, AutoSet]
65+
private OvrAvatarEyePoseBehavior m_eyePoseProvider;
66+
67+
private Task m_initializationTask;
68+
private Task m_setUpAccessTokenTask;
69+
70+
private OvrAvatarInputManagerBehavior m_bodyTracking;
71+
public OvrAvatarInputManagerBehavior BodyTracking
72+
{
73+
get => m_bodyTracking;
74+
protected set
75+
{
76+
m_bodyTracking = value;
77+
SetInputManager(value);
78+
}
79+
}
80+
81+
protected override void Awake()
82+
{
83+
m_setUpAccessTokenTask = SetUpAccessTokenAsync();
84+
85+
base.Awake();
86+
87+
_ = OVRPlugin.StartFaceTracking();
88+
_ = OVRPlugin.StartEyeTracking();
89+
}
90+
91+
92+
private void Start()
93+
{
94+
if (Networking?.IsNetworked != true && m_isLocalIfNotNetworked)
95+
{
96+
Initialize();
97+
}
98+
}
99+
100+
private async Task SetUpAccessTokenAsync()
101+
{
102+
while (!Core.IsInitialized())
103+
{
104+
await Task.Yield();
105+
}
106+
107+
var accessToken = await Users.GetAccessToken().Gen();
108+
if (string.IsNullOrEmpty(accessToken.Data))
109+
{
110+
var error = accessToken.GetError();
111+
Debug.LogError($@"[AvatarEntity] OVR GetAccessToken failed. {new {accessToken.IsError, error?.Code, error?.HttpCode, error?.Message}}", this);
112+
return;
113+
}
114+
115+
OvrAvatarEntitlement.SetAccessToken(accessToken.Data);
116+
}
117+
118+
public void Initialize()
119+
{
120+
var prevInit = m_initializationTask;
121+
m_initializationTask = Impl();
122+
123+
async Task Impl()
124+
{
125+
try
126+
{
127+
if (prevInit != null)
128+
await prevInit;
129+
await InitializeImpl();
130+
}
131+
catch (Exception exception)
132+
{
133+
Debug.LogException(exception);
134+
}
135+
}
136+
}
137+
138+
private async Task InitializeImpl()
139+
{
140+
Teardown();
141+
142+
var isOwner = Networking?.IsNetworked != true ? m_isLocalIfNotNetworked : Networking.IsOwner;
143+
144+
SetIsLocal(isOwner);
145+
if (isOwner)
146+
{
147+
_creationInfo.features |= ovrAvatar2EntityFeatures.Animation;
148+
149+
// TODO: remove FindObject
150+
var body = FindObjectsByType<OvrAvatarInputManagerBehavior >(FindObjectsSortMode.None).
151+
FirstOrDefault(b => b.isActiveAndEnabled);
152+
Debug.Log($"[AvatarEntity] Setting local body tracking to {body?.GetType()}", this);
153+
BodyTracking = body;
154+
155+
m_lipSync.gameObject.SetActive(true);
156+
SetLipSync(m_lipSync);
157+
158+
SetFacePoseProvider(m_facePoseProvider);
159+
SetEyePoseProvider(m_eyePoseProvider);
160+
161+
AvatarLODManager.Instance.firstPersonAvatarLod = AvatarLOD;
162+
}
163+
else
164+
{
165+
_creationInfo.features &= ~ovrAvatar2EntityFeatures.Animation;
166+
_creationInfo.features |= ovrAvatar2EntityFeatures.Preset_Remote;
167+
168+
SetInputManager(null);
169+
SetFacePoseProvider(null);
170+
SetEyePoseProvider(null);
171+
SetLipSync(null);
172+
}
173+
174+
var activeView = isOwner ? ovrAvatar2EntityViewFlags.FirstPerson : ovrAvatar2EntityViewFlags.ThirdPerson;
175+
176+
Debug.Log($"[AvatarEntity] Creating entity", this);
177+
178+
CreateEntity();
179+
180+
SetActiveView(activeView);
181+
182+
Debug.Log($"[AvatarEntity] Awaiting access token", this);
183+
await m_setUpAccessTokenTask;
184+
185+
if (this == null)
186+
return;
187+
188+
Networking?.Initialize();
189+
190+
if (IsLocal)
191+
{
192+
var user = await Users.GetLoggedInUser().Gen();
193+
_userId = user.Data.ID;
194+
195+
if (_userId != 0)
196+
{
197+
await CheckForUserAvatar();
198+
199+
if (this == null)
200+
return;
201+
}
202+
203+
Networking?.OnUserIdSet(_userId);
204+
205+
ForceLoadUser();
206+
}
207+
else if (_userId != 0)
208+
{
209+
ForceLoadUser();
210+
}
211+
}
212+
213+
protected override ovrAvatar2EntityCreateInfo? ConfigureCreationInfo()
214+
{
215+
var info = base.ConfigureCreationInfo() ?? _creationInfo;
216+
217+
//This checks if the user has a custom avatar. If so, this will disable the default avatar features from this entity. This is done to fix a bug in PlayerWristband.
218+
//Avatar Bone name mappings are failing when default avatar features are enabled.
219+
if (HasDoneAvatarCheck)
220+
{
221+
var defaultModelFeatures = ovrAvatar2EntityFeatures.UseDefaultAnimHierarchy | ovrAvatar2EntityFeatures.UseDefaultModel;
222+
if (HasUserAvatar)
223+
info.features &= ~defaultModelFeatures;
224+
else
225+
info.features |= defaultModelFeatures;
226+
}
227+
228+
if (IsLocal)
229+
info.features |= ovrAvatar2EntityFeatures.Animation;
230+
else
231+
{
232+
info.features &= ~ovrAvatar2EntityFeatures.Animation;
233+
info.features |= ovrAvatar2EntityFeatures.Preset_Remote;
234+
}
235+
236+
237+
return info;
238+
}
239+
240+
public async void ForceLoadUser()
241+
{
242+
await m_setUpAccessTokenTask;
243+
LoadUser();
244+
}
245+
246+
public void LoadUser(ulong userId)
247+
{
248+
if (_userId != userId)
249+
{
250+
_userId = userId;
251+
ForceLoadUser();
252+
}
253+
}
254+
255+
private async Task CheckForUserAvatar()
256+
{
257+
var hasAvatarCheck = await OvrAvatarManager.Instance.UserHasAvatarAsync(_userId);
258+
if (hasAvatarCheck == OvrAvatarManager.HasAvatarRequestResultCode.HasAvatar)
259+
{
260+
HasUserAvatar = true;
261+
}
262+
else if (hasAvatarCheck == OvrAvatarManager.HasAvatarRequestResultCode.HasNoAvatar)
263+
{
264+
Debug.Log("Failed to load user avatar: user has no avatar!");
265+
HasUserAvatar = false;
266+
}
267+
else
268+
{
269+
Debug.Log("Avatar check failed, retrying...");
270+
await Task.Delay(4000);
271+
await CheckForUserAvatar();
272+
}
273+
274+
HasDoneAvatarCheck = true;
275+
}
276+
277+
public void Show()
278+
{
279+
SetActiveView(Networking?.IsOwner == false
280+
? ovrAvatar2EntityViewFlags.ThirdPerson
281+
: ovrAvatar2EntityViewFlags.FirstPerson);
282+
}
283+
284+
public void Hide()
285+
{
286+
SetActiveView(ovrAvatar2EntityViewFlags.None);
287+
}
288+
289+
protected override void OnSkeletonLoaded()
290+
{
291+
base.OnSkeletonLoaded();
292+
293+
foreach (var evt in OnJointLoadedEvents)
294+
{
295+
var jointTransform = GetJointTransform(evt.Joint);
296+
if (evt.TargetToSetAsChild != null)
297+
{
298+
evt.TargetToSetAsChild.SetParent(jointTransform, false);
299+
}
300+
301+
evt.OnLoaded?.Invoke(jointTransform);
302+
}
303+
}
304+
}
305+
}

com.meta.utilities.avatars/Avatar/AvatarEntity.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.

com.meta.utilities.avatars/Avatar/AvatarMeshUtils.meta

Lines changed: 8 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)