Removing NetworkBehaviour in runtime

Hello. I have PlayerMovement.cs script

using Unity.Netcode;
using UnityEngine;

[RequireComponent(typeof(CharacterController))]
public class PlayerMovement : NetworkBehaviour
{
    [SerializeField]
    private GameObject cameraObject;

    [SerializeField]
    private float speed = 4f;
    [SerializeField]
    private float accelerationMultiplier = 1.7f;

    [SerializeField]
    private float rotationSensitivity = 4f;

    private const float GravityAcceleration = -9.81f;
    private const float UpAngleCameraLimit = -0.7f;
    private const float DownAngleCameraLimit = 0.7f;

    private const float DeltaAngle = 0.0001f;

    private CharacterController characterController;

    public override void OnNetworkSpawn()
    {
        if (IsOwner)
        {
            characterController = GetComponent<CharacterController>();

            cameraObject.SetActive(true);

            if (Camera.main)
            {
                Destroy(Camera.main.gameObject);
            }
        } else
        {
            enabled = false;
        }
    }

    private void Update()
    {
        Move();
        LookCamera();
    }

    private void Move()
    {
        var horizontal = Input.GetAxis("Horizontal");
        var vertical = Input.GetAxis("Vertical");

        var acceleration = Input.GetAxis("Acceleration") > 0.01f ? accelerationMultiplier : 1;

        var gravityMovement = characterController.isGrounded ? 0 : GravityAcceleration;

        // ToDo: (Potential optimization) Don't create new Vector3 each time. Create private variable in class and use it as cache.
        _ = characterController.Move(acceleration * speed * Time.deltaTime * transform.TransformDirection(new Vector3(horizontal, 0, vertical)));
        _ = characterController.Move(Time.deltaTime * new Vector3(0, gravityMovement));
    }

    private void LookCamera()
    {
        var horizontal = Input.GetAxis("Mouse X");
        var vertical = Input.GetAxis("Mouse Y");

        if (UpAngleCameraLimit < cameraObject.transform.localRotation.x && cameraObject.transform.localRotation.x < DownAngleCameraLimit)
        {
            cameraObject.transform.Rotate(-vertical * rotationSensitivity, 0, 0);
        }
        else
        {
            var limitedQuaternion = cameraObject.transform.localRotation;

            if (cameraObject.transform.localRotation.x < UpAngleCameraLimit)
            {
                limitedQuaternion.x = UpAngleCameraLimit + DeltaAngle;
            }

            if (cameraObject.transform.localRotation.x > DownAngleCameraLimit)
            {
                limitedQuaternion.x = DownAngleCameraLimit - DeltaAngle;
            }

            cameraObject.transform.localRotation = limitedQuaternion;
        }

        transform.Rotate(horizontal * rotationSensitivity * Vector3.up);
    }
}

When I try remove this script (Destroy(this)) on not ownable player prefabs, NetworkManager no longer synchronises Transform (last position before removing the script), but when Disabling the script everything works fine.

Is that expected behaviour? If yes please send link to documentation with this issue described.

You shouldn’t destroy NetworkBehaviour (or NetworkObject). Disabling is fine. And for entire objects you’d use Spawn/Despawn.

I setup my player to have Local and Remote child objects underneath it, which get enabled/disabled depending on whether the player is controlled locally or a remote player. That way I can also show name tags above remote players, without the local player seeing his own name when looking up.

1 Like