using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using VRC.SDKBase; using VRC.Udon; using VRC.Udon.Common.Interfaces; namespace VRC.SDK3.ClientSim { /// /// System to hold all the current initialized Udon in the scene /// /// /// Listens to Events: /// - ClientSimOnPlayerJoinedEvent /// - ClientSimOnPlayerLeftEvent /// - ClientSimOnPlayerRespawnEvent /// public class ClientSimUdonManager : IClientSimUdonManager, IDisposable { private IClientSimEventDispatcher _eventDispatcher; private IClientSimSyncedObjectManager _syncedObjectManager; private IClientSimUdonEventSender _udonEventSender; private readonly ClientSimObjectCollection _udonBehaviours = new ClientSimObjectCollection(); private bool _isReady = false; public ClientSimUdonManager( IClientSimEventDispatcher eventDispatcher, IClientSimSyncedObjectManager syncedObjectManager, IClientSimUdonEventSender udonEventSender) { _eventDispatcher = eventDispatcher; _syncedObjectManager = syncedObjectManager; _udonEventSender = udonEventSender; Subscribe(); } ~ClientSimUdonManager() { Dispose(); } private void Subscribe() { _eventDispatcher.Subscribe(OnPlayerJoined); _eventDispatcher.Subscribe(OnPlayerLeft); _eventDispatcher.Subscribe(OnPlayerRespawn); _eventDispatcher.Subscribe(OnScreenUpdate); _eventDispatcher.Subscribe(OnVRCPlusMassGift); } public void Dispose() { _eventDispatcher.Unsubscribe(OnPlayerJoined); _eventDispatcher.Unsubscribe(OnPlayerLeft); _eventDispatcher.Unsubscribe(OnPlayerRespawn); _eventDispatcher.Unsubscribe(OnScreenUpdate); _eventDispatcher.Unsubscribe(OnVRCPlusMassGift); } public void InitUdon(UdonBehaviour behaviour, IUdonProgram program) { ClientSimUdonHelper[] helpers = behaviour.gameObject.GetComponents(); foreach (ClientSimUdonHelper helper in helpers) { if(helper.GetUdonBehaviour() == behaviour) { return; } } ClientSimUdonHelper helperAdded = behaviour.gameObject.AddComponent(); helperAdded.Initialize(behaviour, this, _syncedObjectManager, _isReady); } public IEnumerator OnClientSimReady() { _isReady = true; _udonBehaviours.ProcessAddedAndRemovedObjects(); HashSet objs = new HashSet(); foreach (var udonBehavior in _udonBehaviours.GetObjects()) { if (udonBehavior == null || objs.Contains(udonBehavior.gameObject)) { continue; } objs.Add(udonBehavior.gameObject); foreach (var helper in udonBehavior.GetComponents()) { try { helper.OnReady(); } catch (Exception e) { this.LogError($"{e.Message}\n{e.StackTrace}"); this.LogWarning($"Failed to set ready for object: {Tools.GetGameObjectPath(helper.gameObject)}"); } } } // Wait one frame for all active UdonBehaviours to properly run start. yield return null; } #region ClientSimEvent handling private void OnPlayerJoined(ClientSimOnPlayerJoinedEvent joinEvent) { _udonEventSender.RunEvent(UdonManager.UDON_EVENT_ONINPUTMETHODCHANGED, ("inputMethod", VRCInputMethod.Keyboard)); _udonEventSender.RunEvent(UdonManager.UDON_EVENT_ONLANGUAGECHANGED, ("language", ClientSimSettings.Instance.currentLanguage)); _udonEventSender.RunEvent("_onPlayerJoined", ("player", joinEvent.player)); } private void OnPlayerLeft(ClientSimOnPlayerLeftEvent leftEvent) { _udonEventSender.RunEvent("_onPlayerLeft", ("player", leftEvent.player)); } private void OnPlayerRespawn(ClientSimOnPlayerRespawnEvent respawnEvent) { _udonEventSender.RunEvent("_onPlayerRespawn", ("player", respawnEvent.player)); } private void OnScreenUpdate(ClientSimScreenUpdateEvent screenUpdateEvent) { _udonEventSender.RunEvent(UdonManager.UDON_EVENT_ONSCREENUPDATE, ("data", screenUpdateEvent.data)); } private void OnVRCPlusMassGift(ClientSimOnVRCPlusMassGift giftEvent) { _udonEventSender.RunEvent(UdonManager.UDON_EVENT_ONVRCPLUSMASSGIFT, ("gifter", giftEvent.gifter), ("numGifts", giftEvent.numGifts)); } #endregion #region IClientSimUdonManager public void AddUdonBehaviour(UdonBehaviour udonBehaviour) { _udonBehaviours.AddObject(udonBehaviour); } public void RemoveUdonBehaviour(UdonBehaviour udonBehaviour) { _udonBehaviours.RemoveObject(udonBehaviour); } #endregion } }