using UnityEngine; using Unity.Netcode; using System.Collections; public class PlayerFacade : NetworkBehaviour { private const string OwnerHiddenBodyLayerName = "OwnerHiddenBody"; [SerializeField] private PlayerMovement playerMovement; [SerializeField] private PlayerHealth playerHealth; [SerializeField] private PlayerShoot playerShoot; [SerializeField] private PlayerShield playerShield; [SerializeField] private PlayerUIController playerUIController; [Header("First / third person setup")] [SerializeField] private Transform thirdPersonVisualRoot; [SerializeField] private Camera playerCamera; [SerializeField] private Camera playerHandCamera; [SerializeField] private GameObject fpvHands; [SerializeField] private GameObject tpvHands; public PlayerHealth PlayerHealth => playerHealth; private void Awake() { if (thirdPersonVisualRoot == null) thirdPersonVisualRoot = transform.Find("Root"); Transform _cameraRoot = transform.Find("Camera"); if (playerCamera == null && _cameraRoot != null) playerCamera = _cameraRoot.GetComponent(); if (playerHandCamera == null && _cameraRoot != null) playerHandCamera = _cameraRoot.Find("Camera-Hands")?.GetComponent(); if (fpvHands == null && _cameraRoot != null) fpvHands = _cameraRoot.Find("FPV-Hands")?.gameObject; if (tpvHands == null) tpvHands = transform.Find("TPV-Hands")?.gameObject; } public override void OnNetworkSpawn() { // Клон (GhostPlayer) — серверный объект. На хосте он считается IsOwner, // из-за чего перехватывал HUD игрока. Игроковую логику на клоне не запускаем. if (GetComponent() != null) return; SetupCamerasAndHands(); if (IsOwner) HideOwnThirdPersonVisual(); if (IsOwner) { StartCoroutine(InitPlayerUIController()); if (playerMovement != null) playerMovement.Init(); if (playerShoot != null) playerShoot.Init(); if (playerShield != null) playerShield.InitInput(); } if (playerHealth != null) playerHealth.Init(IsServer); } private void SetupCamerasAndHands() { if (playerCamera != null) { playerCamera.enabled = IsOwner; AudioListener _listener = playerCamera.GetComponent(); if (_listener != null) _listener.enabled = IsOwner; } if (playerHandCamera != null) playerHandCamera.enabled = IsOwner; if (fpvHands != null) fpvHands.SetActive(IsOwner); if (tpvHands != null) tpvHands.SetActive(!IsOwner); if (!IsOwner) return; Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; int _hiddenLayer = LayerMask.NameToLayer(OwnerHiddenBodyLayerName); if (playerCamera != null && _hiddenLayer >= 0) playerCamera.cullingMask &= ~(1 << _hiddenLayer); } // Свой Root у владельца переводим на слой, который его FPV-камера не рисует. // На других клиентах Root остаётся как в префабе — чужие тела видны. // Слой меняется только локально у владельца, в сеть не уходит. private void HideOwnThirdPersonVisual() { if (thirdPersonVisualRoot == null) return; int _hiddenLayer = LayerMask.NameToLayer(OwnerHiddenBodyLayerName); if (_hiddenLayer < 0) { Debug.LogWarning($"Layer '{OwnerHiddenBodyLayerName}' is missing. Create it in Tags & Layers."); return; } GameObject _shieldVisual = playerShield != null ? playerShield.ShieldVisual : null; foreach (Transform _child in thirdPersonVisualRoot.GetComponentsInChildren(true)) { if (_shieldVisual != null && (_child.gameObject == _shieldVisual || _child.IsChildOf(_shieldVisual.transform))) continue; _child.gameObject.layer = _hiddenLayer; } } private IEnumerator InitPlayerUIController() { yield return new WaitUntil(() => { playerUIController = FindFirstObjectByType(); return playerUIController != null; }); if (playerUIController != null) playerUIController.Init(this); } }