using FishNet.Object;
using UnityEngine;
namespace Ashwild.Network
{
///
/// Splits the player's visible body by viewpoint. The local owner's third-person body is
/// moved onto a dedicated "local body" layer that his own first-person camera excludes from
/// its culling mask, so he never sees his own torso/head clip through the view — while every
/// remote client still renders that same body normally. The layer change is purely local and
/// never travels over the network, so hiding your body from yourself does not hide it from
/// anyone else. The Animator/NetworkAnimator are left untouched, so the third-person animation
/// keeps replicating to other players even while the mesh is culled from the owner's own view.
///
[DisallowMultipleComponent]
public class PlayerBodyVisibility : NetworkBehaviour
{
#region Serialized Fields
[Header("Body")]
[Tooltip("Root of the third-person body mesh hierarchy (skinned mesh + bones).")]
[SerializeField] private GameObject bodyRoot;
[Header("Local hiding")]
[Tooltip("Layer the owner's own body is moved to. The first-person camera must exclude this layer from its culling mask.")]
[SerializeField] private string localBodyLayer = "LocalBody";
#endregion
#region Network Lifecycle
///
/// Once ownership is resolved, relayers the third-person body so the owning player's own
/// camera stops rendering it. Remote copies return early and keep the body on its authored
/// (visible) layer, which is why other players still see it.
///
public override void OnStartClient()
{
base.OnStartClient();
if (!base.IsOwner) return;
if (bodyRoot == null)
{
Debug.LogError($"[PlayerBodyVisibility] '{name}' has no bodyRoot assigned — cannot hide the local body.", this);
return;
}
int layer = LayerMask.NameToLayer(localBodyLayer);
if (layer < 0)
{
Debug.LogError($"[PlayerBodyVisibility] '{name}' — layer '{localBodyLayer}' does not exist. Add it in Project Settings ▸ Tags and Layers, then exclude it from the first-person camera's culling mask.", this);
return;
}
SetLayerRecursively(bodyRoot, layer);
}
#endregion
#region Internal Helpers
///
/// Applies a layer to a GameObject and every descendant, since a skinned body spans many
/// child renderers and bones that must all move together for the camera cull to hide it fully.
///
private static void SetLayerRecursively(GameObject root, int layer)
{
root.layer = layer;
foreach (Transform child in root.transform)
SetLayerRecursively(child.gameObject, layer);
}
#endregion
}
}