namespace TPSBR { using UnityEngine; using Fusion; /// /// This component serves as an AoI position proxy. It is useful for objects which don't need their own NetworkTransform component, but still need to be filtered by AoI. /// Example: Player + Weapon. Each Weapon is a separate dynamically spawned NetworkObject with NetworkAreaOfInterestProxy component. Upon spawn Weapon is parented under Player object (usually under a hand bone). /// There is no need to synchronize Weapon position because it is driven locally. But if a Player runs out of AoI, we want to stop updating both objects Player and Weapon. /// [DisallowMultipleComponent] [DefaultExecutionOrder(10000)] public sealed unsafe class NetworkAreaOfInterestProxy : NetworkTRSP { // PUBLIC MEMBERS public Transform PositionSource => _positionSource; // PRIVATE MEMBERS [SerializeField] private Transform _positionSource; private Transform _defaultPositionSource; private bool _hasExplicitPositionSource; private bool _isSpawned; // PUBLIC METHODS public void SetPosition(Vector3 position) { if (_isSpawned == true) { State.Position = position; } } public void SetPositionSource(Transform positionSource) { _positionSource = positionSource; _hasExplicitPositionSource = true; Synchronize(); } public void ResetPositionSource() { _positionSource = _defaultPositionSource; _hasExplicitPositionSource = false; Synchronize(); } public void FindPositionSourceInParent() { FindPositionSourceInParent(true); Synchronize(); } public void Synchronize() { if (_isSpawned == true && _positionSource != null) { State.Position = _positionSource.position; } } // NetworkBehaviour INTERFACE public override void Spawned() { _isSpawned = true; ReplicateToAll(false); if (_hasExplicitPositionSource == false && _positionSource == null) { State.Position = default; FindPositionSourceInParent(false); } Synchronize(); } public override void Despawned(NetworkRunner runner, bool hasState) { _isSpawned = false; ResetPositionSource(); } public override void FixedUpdateNetwork() { Synchronize(); } // MonoBehaviour INTERFACE private void Awake() { _defaultPositionSource = _positionSource; } // PRIVATE METHODS private void FindPositionSourceInParent(bool isExplicit) { Transform parentTransform = transform.parent; while (parentTransform != null) { NetworkObject networkObject = parentTransform.GetComponent(); if (networkObject != null) { _positionSource = parentTransform; _hasExplicitPositionSource = isExplicit; break; } parentTransform = parentTransform.parent; } } } }