77 lines
3.0 KiB
C#
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
|
|
}
|
|
}
|