using UnityEngine; using UnityEngine.UIElements; using Fusion; namespace Hallucinate.UI { public class PerformanceOverlay : MonoBehaviour { private static PerformanceOverlay _instance; private Label _fpsLabel; private UIDocument _uiDocument; private VisualElement _root; private float _deltaTime = 0f; private bool _isVisible = false; public static void SetVisible(bool visible) { if (_instance == null && visible) { var go = new GameObject("PerformanceOverlay"); _instance = go.AddComponent(); DontDestroyOnLoad(go); } if (_instance != null) { _instance._isVisible = visible; if (_instance._root != null) { _instance._root.style.display = visible ? DisplayStyle.Flex : DisplayStyle.None; } } } private void Awake() { _uiDocument = gameObject.AddComponent(); // Đặt thứ tự hiển thị cực cao để luôn nằm trên cùng _uiDocument.sortingOrder = 999; // Thử lấy PanelSettings từ UIManager để đồng bộ tỉ lệ scale if (UIManager.Instance != null && UIManager.Instance.GetComponent() != null) { _uiDocument.panelSettings = UIManager.Instance.GetComponent().panelSettings; } _root = new VisualElement(); _root.style.position = Position.Absolute; _root.style.bottom = 15; _root.style.right = 15; _root.pickingMode = PickingMode.Ignore; _fpsLabel = new Label("0 FPS | 0.0ms | PING: 0ms"); _fpsLabel.pickingMode = PickingMode.Ignore; _fpsLabel.style.color = Color.white; _fpsLabel.style.fontSize = 12; _fpsLabel.style.unityFontStyleAndWeight = FontStyle.Bold; // Shadow effect _fpsLabel.style.textShadow = new TextShadow { offset = new Vector2(1, 1), blurRadius = 1, color = Color.black }; _root.Add(_fpsLabel); _uiDocument.rootVisualElement.Add(_root); _root.style.display = _isVisible ? DisplayStyle.Flex : DisplayStyle.None; } private void Update() { if (!_isVisible) return; _deltaTime += (Time.unscaledDeltaTime - _deltaTime) * 0.1f; float fps = 1.0f / _deltaTime; float ms = _deltaTime * 1000.0f; int ping = 0; if (BasicSpawner.Instance != null && BasicSpawner.Instance.Runner != null && BasicSpawner.Instance.Runner.IsRunning) { var runner = BasicSpawner.Instance.Runner; if (runner.LocalPlayer != PlayerRef.None) { ping = (int)(runner.GetPlayerRtt(runner.LocalPlayer) * 1000); } } var (_, deviceLatency) = MouseMetricsHelper.GetMetrics(); _fpsLabel.text = $"{Mathf.Ceil(fps)} FPS | {ms:F1}ms | LATENCY: {deviceLatency:F0}ms | PING: {ping}ms"; // Color coding based on performance if (fps < 30) _fpsLabel.style.color = Color.red; else if (fps < 55) _fpsLabel.style.color = Color.yellow; else _fpsLabel.style.color = Color.green; } } }