Files
2026-06-07 16:58:24 +01:00

127 lines
4.0 KiB
C#

using System.Collections.Generic;
using UnityEngine;
namespace VRC.SDK3.ClientSim
{
/// <summary>
/// System responsible for highlighting objects.
/// </summary>
[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<GameObject, ClientSimHighlightProxy> _objectRenderProxies =
new Dictionary<GameObject, ClientSimHighlightProxy>();
private readonly Queue<ClientSimHighlightProxy> _proxyMeshQueue = new Queue<ClientSimHighlightProxy>();
public void Initialize(Camera playerCamera)
{
_highlightsFX = playerCamera.gameObject.AddComponent<HighlightsFX>();
}
public void EnableObjectHighlight(GameObject obj)
{
List<Renderer> 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<Renderer> 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<Renderer> GatherRenderers(GameObject obj, bool findDisabled)
{
if(obj == null)
{
return new List<Renderer>();
}
List<Renderer> results = new List<Renderer>();
foreach (var rend in obj.GetComponentsInChildren<Renderer>(findDisabled))
{
if (!rend.enabled || rend.isPartOfStaticBatch)
{
continue;
}
MeshFilter filter = rend.GetComponent<MeshFilter>();
if (filter == null || filter.sharedMesh == null)
{
continue;
}
results.Add(rend);
}
return results;
}
private Renderer GetProxyHighlight(GameObject obj)
{
ClientSimHighlightProxy proxy = GetUnusedProxy();
Collider objCollider = obj.GetComponent<Collider>();
_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<ClientSimHighlightProxy>();
tooltip.Initialize(cubeMesh, capsuleMesh, sphereMesh);
return tooltip;
}
return _proxyMeshQueue.Dequeue();
}
}
}