Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ public static async void DeleteLastAvatar(BasisPlayer Player)
public static void SetupRemoteAvatar(BasisRemotePlayer Player)
{
Player.RemoteAvatarDriver.RemoteCalibration(Player);
Player.BasisAvatar.OnAvatarReady?.Invoke(false);
Player.BasisAvatar.NotifyAvatarReady(false);
}

/// <summary>
Expand All @@ -480,7 +480,7 @@ public static void SetupRemoteAvatar(BasisRemotePlayer Player)
public static void SetupLocalAvatar(BasisLocalPlayer Player)
{
Player.LocalAvatarDriver.InitialLocalCalibration(Player);
Player.BasisAvatar.OnAvatarReady?.Invoke(true);
Player.BasisAvatar.NotifyAvatarReady(true);
BasisLocalAvatarDriver.CalibrationComplete?.Invoke();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ public class BasisAvatar : BasisContentBase
/// <summary>
/// True if this avatar is owned by the local player.
/// </summary>
public bool IsOwnedLocally;
public bool IsOwnedLocally { get; set; }

/// <summary>
/// True once avatar setup has completed and readiness callbacks have fired for this instance.
/// </summary>
public bool IsReady { get; private set; }

/// <summary>
/// Gets or sets the linked player ID. Setting also marks <see cref="HasLinkedPlayer"/> true.
Expand Down Expand Up @@ -112,7 +117,56 @@ public bool TryGetLinkedPlayer(out ushort Id)
/// <summary>
/// Event triggered when the avatar is ready for further initialization or data queries.
/// </summary>
public OnReady OnAvatarReady;
public OnReady OnAvatarReady {get; set;}

/// <summary>
/// Marks this avatar as ready and notifies listeners with the owner locality.
/// </summary>
/// <param name="isOwner">True when this avatar belongs to the local player.</param>
public void NotifyAvatarReady(bool isOwner)
{
IsOwnedLocally = isOwner;
IsReady = true;
OnAvatarReady?.Invoke(isOwner);
}

public static GameObject GetGameObject(object o)
{
GameObject currentGameobject = null;
if (o is GameObject go)
{
currentGameobject = go;
}
else if (o is Component c)
{
currentGameobject = c.gameObject;
}

if (currentGameobject == null)
{
Debug.LogError($"Object {o} is not a GameObject or Component.");
return null;
}

while (currentGameobject != null)
{
if (currentGameobject.TryGetComponent<BasisAvatar>(out _))
{
return currentGameobject;
}

Transform parent = currentGameobject.transform.parent;
if (parent == null)
{
break;
}

currentGameobject = parent.gameObject;
}

Debug.LogError($"Object {o} is not part of an avatar hierarchy.");
return null;
}

/// <summary>
/// Processing options used when the avatar is processed. This is always null after the avatar is processed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,5 @@ MonoBehaviour:
- UnityEngine.AudioEchoFilter
- UnityEngine.AudioDistortionFilter
- Cilbox.CilboxAvatarBasis
- Basis.Shims.BasisAvatarShim
- Basis.Shims.BasisNetworkShim
209 changes: 209 additions & 0 deletions Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
using Basis.Scripts.BasisSdk;
using Cilbox;
using UnityEngine;
namespace Basis.Shims
{
[DisallowMultipleComponent]
public sealed class BasisAvatarShim : CilboxShim
{
private static readonly int[] DefaultFaceVisemeMovement = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
private static readonly int[] DefaultBlinkViseme = new int[] { -1 };

public delegate void OnReady(bool IsOwner);
public delegate void AvatarReadyEvent(bool isLocalPlayer);

public Vector2 AvatarEyePosition;
public Vector2 AvatarMouthPosition;
public Vector3 AnimatorHumanScale = Vector3.one;

private BasisAvatar avatar;
private bool isLocalPlayer;
private OnReady onAvatarReady;

public OnReady OnAvatarReady
{
get => onAvatarReady;
set
{
OnReady previousHandlers = onAvatarReady;
onAvatarReady = value;

// Always keep the newly assigned handlers. If the avatar is not ready yet,
// they remain registered and AvatarReady(...) will invoke them later.
bool shouldReplayImmediately = IsReady && onAvatarReady != null;
if (!shouldReplayImmediately)
{
return;
}

ReplayNewReadyHandlers(previousHandlers, onAvatarReady, isLocalPlayer);
}
}

public bool IsReady => avatar != null && avatar.IsReady;
public bool IsLocalPlayer => isLocalPlayer;
public bool IsOwner => isLocalPlayer;
public BasisAvatar Avatar => avatar;
public bool HasLinkedPlayer => avatar != null && avatar.HasLinkedPlayer;
public Animator Animator
{
get => avatar != null ? avatar.Animator : null;
}

public SkinnedMeshRenderer FaceVisemeMesh
{
get => avatar != null ? avatar.FaceVisemeMesh : null;
}

public SkinnedMeshRenderer FaceBlinkMesh
{
get => avatar != null ? avatar.FaceBlinkMesh : null;
}

public int[] FaceVisemeMovement
{
get => avatar != null ? avatar.FaceVisemeMovement : DefaultFaceVisemeMovement;
}

public int[] BlinkViseme
{
get => avatar != null ? avatar.BlinkViseme : DefaultBlinkViseme;
}

public int laughterBlendTarget
{
get => avatar != null ? avatar.laughterBlendTarget : -1;
}

public bool IsOwnedLocally
{
get => avatar != null ? avatar.IsOwnedLocally : isLocalPlayer;
}

public float HumanScale
{
get => avatar != null ? avatar.HumanScale : 1;
set
{
if (avatar != null)
{
avatar.HumanScale = value;
}
}
}

public ushort LinkedPlayerID
{
get => avatar != null ? avatar.LinkedPlayerID : (ushort)0;
}

private void Awake()
{
avatar = GetComponent<BasisAvatar>();
if (avatar == null)
{
avatar = GetComponentInParent<BasisAvatar>(true);
}

if (avatar == null)
{
BasisDebug.LogError("[BasisAvatarShim] Could not resolve a BasisAvatar for this shim.");
return;
}

SyncFieldsFromAvatar();
avatar.OnAvatarReady -= AvatarReady;
avatar.OnAvatarReady += AvatarReady;

if (avatar.IsReady)
{
AvatarReady(avatar.IsOwnedLocally);
}
}

private void OnDestroy()
{
if (avatar != null)
{
avatar.OnAvatarReady -= AvatarReady;
}
}

private void AvatarReady(bool ownerIsLocal)
{
isLocalPlayer = ownerIsLocal;
SyncFieldsFromAvatar();
OnAvatarReady?.Invoke(ownerIsLocal);
}

public bool TryGetLinkedPlayer(out ushort Id)
{
if (avatar == null)
{
Id = 0;
return false;
}

return avatar.TryGetLinkedPlayer(out Id);
}

private void NotifyAvatarReady(bool isOwner)
{
if (avatar == null)
{
return;
}

avatar.NotifyAvatarReady(isOwner);
SyncFieldsFromAvatar();
}

private static void ReplayNewReadyHandlers(OnReady previousHandlers, OnReady currentHandlers, bool ownerIsLocal)
{
System.Collections.Generic.Dictionary<System.Delegate, int> existingHandlers = new System.Collections.Generic.Dictionary<System.Delegate, int>();
if (previousHandlers != null)
{
foreach (System.Delegate handler in previousHandlers.GetInvocationList())
{
if (existingHandlers.TryGetValue(handler, out int count))
{
existingHandlers[handler] = count + 1;
}
else
{
existingHandlers[handler] = 1;
}
}
}

foreach (System.Delegate handler in currentHandlers.GetInvocationList())
{
if (existingHandlers.TryGetValue(handler, out int count) && count > 0)
{
existingHandlers[handler] = count - 1;
continue;
}

((OnReady)handler).Invoke(ownerIsLocal);
}
}
// Cilbox remaps BasisAvatar.GetGameObject(...) to this shim type, so forward to the real avatar helper.
public static GameObject GetGameObject(object o)
{
return BasisAvatar.GetGameObject(o);
}

private void SyncFieldsFromAvatar()
{
if (avatar == null)
{
return;
}

AvatarEyePosition = avatar.AvatarEyePosition;
AvatarMouthPosition = avatar.AvatarMouthPosition;
AnimatorHumanScale = avatar.AnimatorHumanScale;
isLocalPlayer = avatar.IsOwnedLocally;
}
}
}
11 changes: 11 additions & 0 deletions Basis/Packages/com.basis.shim/Shims/BasisAvatarShim.cs.meta

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

7 changes: 7 additions & 0 deletions Basis/Packages/com.basis.shim/Shims/BasisCilboxBuildHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ private static void Initialize()
//Debug.Log("BasisCilboxBuildHook initialized.");
BasisAssetBundlePipeline.OnBeforeBuildPrefab -= HandleBeforeBuildPrefab;
BasisAssetBundlePipeline.OnBeforeBuildPrefab += HandleBeforeBuildPrefab;
BasisAvatarSDKInspector.OnBeforeTestInEditor -= HandleBeforeTestInEditor;
BasisAvatarSDKInspector.OnBeforeTestInEditor += HandleBeforeTestInEditor;
}

private static void HandleBeforeTestInEditor(GameObject prefabRoot)
{
HandleBeforeBuildPrefab(prefabRoot, null);
}

private static void HandleBeforeBuildPrefab(GameObject prefabRoot, BasisAssetBundleObject settings)
Expand Down
1 change: 1 addition & 0 deletions Basis/Packages/com.basis.shim/Shims/BasisShims.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Basis.Shims;
using Basis.Scripts.BasisSdk;
using System;
using UnityEngine.Networking;
using UnityEngine;
Expand Down
Loading
Loading