Files
Emberwild/Assets/GAME/Script/Network/PlayerBodyVisibility.cs
T
2026-07-04 09:33:53 +02:00

77 lines
3.0 KiB
C#

using FishNet.Object;
using UnityEngine;
namespace Ashwild.Network
{
/// <summary>
/// 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.
/// </summary>
[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
/// <summary>
/// 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.
/// </summary>
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
/// <summary>
/// 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.
/// </summary>
private static void SetLayerRecursively(GameObject root, int layer)
{
root.layer = layer;
foreach (Transform child in root.transform)
SetLayerRecursively(child.gameObject, layer);
}
#endregion
}
}