using System.Collections.Generic; using UnityEngine; namespace VRC.SDK3.ClientSim { /// /// System responsible for highlighting objects. /// [AddComponentMenu("")] public class ClientSimHighlightManager : ClientSimBehaviour, IClientSimHighlightManager { [SerializeField] private Mesh cubeMesh; [SerializeField] private Mesh capsuleMesh; [SerializeField] private Mesh sphereMesh; [SerializeField] private GameObject proxyHighlightPrefab; // TODO wrap highlightFX to make it easier to test/replace. private HighlightsFX _highlightsFX; private readonly Dictionary _objectRenderProxies = new Dictionary(); private readonly Queue _proxyMeshQueue = new Queue(); public void Initialize(Camera playerCamera) { _highlightsFX = playerCamera.gameObject.AddComponent(); } public void EnableObjectHighlight(GameObject obj) { List renderers = GatherRenderers(obj, false); if (renderers.Count == 0) { Renderer rend = GetProxyHighlight(obj); if (rend != null) { renderers.Add(rend); } } foreach (var rend in renderers) { EnableObjectHighlight(rend, true); } } public void DisableObjectHighlight(GameObject obj) { if (_objectRenderProxies.TryGetValue(obj, out ClientSimHighlightProxy proxy)) { _objectRenderProxies.Remove(obj); EnableObjectHighlight(proxy.Renderer, false); _proxyMeshQueue.Enqueue(proxy); proxy.DisableProxy(); } List renderers = GatherRenderers(obj, true); foreach (var rend in renderers) { EnableObjectHighlight(rend, false); } } public void EnableObjectHighlight(Renderer rend, bool isEnabled) { _highlightsFX.EnableOutline(rend, isEnabled); } private List GatherRenderers(GameObject obj, bool findDisabled) { if(obj == null) { return new List(); } List results = new List(); foreach (var rend in obj.GetComponentsInChildren(findDisabled)) { if (!rend.enabled || rend.isPartOfStaticBatch) { continue; } MeshFilter filter = rend.GetComponent(); if (filter == null || filter.sharedMesh == null) { continue; } results.Add(rend); } return results; } private Renderer GetProxyHighlight(GameObject obj) { ClientSimHighlightProxy proxy = GetUnusedProxy(); Collider objCollider = obj.GetComponent(); _objectRenderProxies.Add(obj, proxy); proxy.EnableProxy(obj.transform, objCollider); return proxy.Renderer; } private ClientSimHighlightProxy GetUnusedProxy() { if (_proxyMeshQueue.Count == 0) { GameObject tooltipObj = Instantiate(proxyHighlightPrefab, transform); ClientSimHighlightProxy tooltip = tooltipObj.GetComponent(); tooltip.Initialize(cubeMesh, capsuleMesh, sphereMesh); return tooltip; } return _proxyMeshQueue.Dequeue(); } } }