using FishNet.Connection; using FishNet.Object; using FishNet.Object.Synchronizing; using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; namespace _PROJECT.Multiplayer.NewBow { public class TwoHandedBowNetworkManager : NetworkBehaviour { [SerializeField] private GameObject arrowPrefab; private XRInteractionManager _interactionManager; private TwoHandedBowNotch _notch; [SyncVar] private NetworkObject _arrowNetworkObject; public Vector3 lastKnownLaunchDirection { get; [ServerRpc(RunLocally = true)] set; } public float lastKnownPullAmount { get; [ServerRpc(RunLocally = true)] set; } public override void OnStartServer() { base.OnStartServer(); _interactionManager = GameObject.Find("XR Interaction Manager").GetComponent(); _notch = GetComponentInChildren(); if (_interactionManager == null) Debug.LogError("Interaction manager not found"); if (_notch == null) Debug.LogError("Notch not found"); CreateArrowServer(); } public override void OnStartClient() { base.OnStartClient(); _interactionManager = GameObject.Find("XR Interaction Manager").GetComponent(); _notch = GetComponentInChildren(); if (_interactionManager == null) Debug.LogError("Interaction manager not found"); if (_notch == null) Debug.LogError("Notch not found"); } public void LaunchArrow(float pullAmount) { if (!IsOwner) return; lastKnownPullAmount = pullAmount; Debug.Log("Sending launch Arrow RPC"); LaunchArrowRPC(); } [ServerRpc(RequireOwnership = false)] private void LaunchArrowRPC() { if (!IsServer) return; Debug.Log("Got launch arrow RPC"); if (_notch.hasSelection) { NetworkObject arrow = _notch.firstInteractableSelected.transform.GetComponent(); OwnerDeselectRpc(Owner, arrow); _interactionManager.SelectExit(_notch, _notch.firstInteractableSelected); PlayReleaseSoundRPC(); } _arrowNetworkObject = null; Invoke(nameof(CreateArrowServer), _notch.recycleDelayTime + 0.1f); } private void CreateArrowServer() { if (!IsServer) return; Debug.Log("Spawning arrow at " + transform.position); GameObject arrowObject = Instantiate(arrowPrefab, transform.position, transform.rotation); Spawn(arrowObject, Owner); Arrow arrow = arrowObject.GetComponent(); _arrowNetworkObject = arrow.GetComponent(); _interactionManager.SelectEnter(_notch as IXRSelectInteractor, arrow); OwnerSelectRpc(Owner, arrowObject.GetComponent()); PlayNockSoundRPC(); } public override void OnOwnershipClient(NetworkConnection prevOwner) { base.OnOwnershipClient(prevOwner); if (IsOwner && _arrowNetworkObject != null) TakeArrowOwnershipRPC(); } [ServerRpc(RequireOwnership = false)] private void TakeArrowOwnershipRPC(NetworkConnection conn = null) { if (!IsServer) return; Debug.Assert(_arrowNetworkObject != null, "Network arrow was null, but bow should always have arrow"); _arrowNetworkObject.GiveOwnership(conn); OwnerSelectRpc(conn, _arrowNetworkObject); } [TargetRpc] private void OwnerSelectRpc(NetworkConnection conn, NetworkObject arrow) { if (!IsClient) return; _interactionManager.SelectEnter(_notch as IXRSelectInteractor, arrow.gameObject.GetComponent()); } [TargetRpc] private void OwnerDeselectRpc(NetworkConnection conn, NetworkObject arrow) { if (!IsClient) return; _interactionManager.SelectExit(_notch as IXRSelectInteractor, arrow.gameObject.GetComponent()); } [ObserversRpc] private void PlayReleaseSoundRPC() { if (!IsClient) return; _notch.PlayReleaseSound(); } [ObserversRpc] private void PlayNockSoundRPC() { if (!IsClient) return; _notch.PlayNockSound(); } public void SetLaunchDirection(Vector3 direction) { if (!IsOwner) return; lastKnownLaunchDirection = direction; } } }