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
}
}