using UnityEngine; using Fusion; using ReadyPlayerMe.Core; using System; public class GLBDownloader : NetworkBehaviour { private GameObject currentGlbModel; public GameObject GetCurrentGlbModel() => currentGlbModel; private AvatarObjectLoader avatarLoader; private AvatarLoaderSettings avatarLoaderSettings; [Networked, OnChangedRender(nameof(OnAvatarUrlChanged))] private NetworkString<_512> AvatarUrl { get; set; } private string _previousUrl = null; public override void Spawned() { Debug.Log($"[GLBDownloader] Spawned for {Object.InputAuthority}, local is {Runner.LocalPlayer}"); if (Object.HasInputAuthority) { string modelUrl = EN.instance.Me.characterUrl; if (!string.IsNullOrEmpty(modelUrl)) { Debug.Log($"[GLBDownloader] Setting AvatarUrl to {modelUrl} for local player"); AvatarUrl = modelUrl; } else { Debug.LogError("Character URL is empty."); } } else { // For late joiners: handle already set avatar URL if (!string.IsNullOrEmpty(AvatarUrl.ToString())) { Debug.Log($"[GLBDownloader] Late joiner loading avatar for player {Object.InputAuthority}: {AvatarUrl}"); _previousUrl = AvatarUrl.ToString(); LoadAvatar(_previousUrl); } } } private void OnAvatarUrlChanged() { Debug.Log($"[GLBDownloader] OnAvatarUrlChanged called on {Runner.LocalPlayer} for player {Object.InputAuthority}"); string newUrl = AvatarUrl.ToString(); if (!string.IsNullOrEmpty(newUrl) && newUrl != _previousUrl) { _previousUrl = newUrl; Debug.Log($"[GLBDownloader] Loading avatar for player {Object.InputAuthority}: {newUrl}"); LoadAvatar(newUrl); } } private void LoadAvatar(string url) { if (string.IsNullOrEmpty(url)) { Debug.LogWarning("[GLBDownloader] LoadAvatar called with empty URL."); return; } if (avatarLoaderSettings == null) { avatarLoaderSettings = AvatarLoaderSettings.LoadSettings(); } avatarLoader = new AvatarObjectLoader(); avatarLoader.OnFailed += OnFailed; avatarLoader.OnCompleted += OnCompleted; if (avatarLoaderSettings != null) { avatarLoader.AvatarConfig = avatarLoaderSettings.AvatarConfig; if (avatarLoaderSettings.GLTFDeferAgent != null) { avatarLoader.GLTFDeferAgent = avatarLoaderSettings.GLTFDeferAgent; } } avatarLoader.LoadAvatar(url); Debug.Log("[GLBDownloader] Avatar download started."); } private void OnFailed(object sender, FailureEventArgs args) { Debug.LogError($"[GLBDownloader] Avatar load failed: {args.Type} - {args.Message}"); } private void OnCompleted(object sender, CompletionEventArgs args) { if (args.Avatar == null) { Debug.LogError("[GLBDownloader] Avatar loading completed but avatar is null."); return; } currentGlbModel = args.Avatar; currentGlbModel.transform.position = transform.position; currentGlbModel.transform.rotation = transform.rotation; currentGlbModel.transform.localScale = Vector3.one; currentGlbModel.tag = "NetworkGLB"; GameObject avatar = this.gameObject; if (avatar != null) { AttachToAvatarRig(avatar); } Debug.Log($"[GLBDownloader] Avatar loaded and attached for player {Object.InputAuthority}"); } private void AttachToAvatarRig(GameObject avatar) { if (currentGlbModel == null) return; Transform avatarRig = avatar.transform.Find("1"); if (avatarRig == null) { Debug.LogWarning("[GLBDownloader] Could not find rig root (child named '1') to attach avatar."); return; } IKTargetFollowVRRig ikRig = avatarRig.GetComponent(); if (ikRig != null) { ikRig.head.ikTarget = currentGlbModel.transform; } currentGlbModel.transform.SetParent(avatarRig); currentGlbModel.transform.localPosition = new Vector3(0, 0.6f, 0); currentGlbModel.transform.localRotation = Quaternion.identity; currentGlbModel.transform.localScale = new Vector3(1.5f,1.5f,1.5f); } private void OnDestroy() { if (avatarLoader != null) { avatarLoader.OnFailed -= OnFailed; avatarLoader.OnCompleted -= OnCompleted; } } }