using System; using System.Collections; using System.Collections.Generic; using BlockSpace.Worlds; using Photon.Pun; using Photon.Realtime; using UnityEngine; [DisallowMultipleComponent] public sealed class NodeGraphPhotonSync : MonoBehaviourPunCallbacks { [Serializable] private sealed class NodeRecordEnvelope { public WorldGroupsCodec.WorldNodeRecord record; } [SerializeField] private NodeGraphManager nodeGraphManager; [SerializeField] private float lateJoinReplayDelay = 0.5f; private PhotonView cachedPhotonView; private void Reset() { nodeGraphManager = GetComponent(); } private void Awake() { cachedPhotonView = GetComponent(); if (nodeGraphManager == null) { nodeGraphManager = GetComponent(); if (nodeGraphManager == null) { nodeGraphManager = UnityEngine.Object.FindAnyObjectByType(); } } nodeGraphManager?.RegisterNetworkSync(this); } public override void OnEnable() { base.OnEnable(); nodeGraphManager?.RegisterNetworkSync(this); } public override void OnJoinedRoom() { base.OnJoinedRoom(); if (!(nodeGraphManager == null) && !PhotonNetwork.IsMasterClient) { nodeGraphManager.ClearAllNodesForNetworkSync(); } } public override void OnPlayerEnteredRoom(Player newPlayer) { base.OnPlayerEnteredRoom(newPlayer); if (newPlayer != null) { nodeGraphManager?.NotifyPlayerJoined(newPlayer.ActorNumber); } if (PhotonNetwork.IsMasterClient && newPlayer != null && !(nodeGraphManager == null)) { StartCoroutine(SendExistingGraphToPlayerAfterDelay(newPlayer)); } } public override void OnPlayerLeftRoom(Player otherPlayer) { base.OnPlayerLeftRoom(otherPlayer); if (otherPlayer != null) { nodeGraphManager?.NotifyPlayerLeft(otherPlayer.ActorNumber); } } public override void OnLeftRoom() { int num = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : 0); if (num > 0) { nodeGraphManager?.NotifyPlayerLeft(num); } base.OnLeftRoom(); } public void BroadcastUpsertNode(Node node, Player targetPlayer = null) { if (!(node == null) && CanSendRpc()) { WorldGroupsCodec.WorldNodeRecord record = nodeGraphManager.BuildNetworkNodeRecord(node); BroadcastUpsertRecord(record, targetPlayer); } } public void BroadcastDeleteNode(int nodeId) { if (CanSendRpc() && nodeId > 0) { cachedPhotonView.RPC("RPC_DeleteNode", RpcTarget.Others, nodeId); } } public void BroadcastConnectWire(WorldGroupsCodec.WorldWireRecord record, Player targetPlayer = null) { int groupId; bool flag = WorldGroupsCodec.TryGetGroupRuntimeWireSourceId(record, out groupId) || WorldGroupsCodec.TryGetGroupSavedWireIndex(record, out groupId); if (CanSendRpc() && record.inputNodeId > 0 && !string.IsNullOrEmpty(record.inputPortName) && (flag || record.outputNodeId > 0)) { if (targetPlayer != null) { cachedPhotonView.RPC("RPC_ConnectWire", targetPlayer, record.outputNodeId, record.outputPortName, record.inputNodeId, record.inputPortName); } else { cachedPhotonView.RPC("RPC_ConnectWire", RpcTarget.Others, record.outputNodeId, record.outputPortName, record.inputNodeId, record.inputPortName); } } } public void BroadcastDisconnectInput(int inputNodeId, string inputPortName) { if (CanSendRpc() && inputNodeId > 0 && !string.IsNullOrEmpty(inputPortName)) { cachedPhotonView.RPC("RPC_DisconnectInput", RpcTarget.Others, inputNodeId, inputPortName); } } public void BroadcastDisconnectOutput(int outputNodeId, string outputPortName) { if (CanSendRpc() && outputNodeId > 0 && !string.IsNullOrEmpty(outputPortName)) { cachedPhotonView.RPC("RPC_DisconnectOutput", RpcTarget.Others, outputNodeId, outputPortName); } } public void BroadcastTriggerRun(int outputNodeId, string outputPortName) { if (CanSendRpc() && outputNodeId > 0 && !string.IsNullOrEmpty(outputPortName)) { cachedPhotonView.RPC("RPC_TriggerRun", RpcTarget.Others, outputNodeId, outputPortName); } } public void BroadcastEventRun(int nodeId, string outputPortName) { if (CanSendRpc() && nodeId > 0 && !string.IsNullOrEmpty(outputPortName)) { cachedPhotonView.RPC("RPC_EventRun", RpcTarget.Others, nodeId, outputPortName); } } [PunRPC] private void RPC_UpsertNode(string recordJson) { if (!(nodeGraphManager == null) && !string.IsNullOrEmpty(recordJson)) { NodeRecordEnvelope nodeRecordEnvelope = JsonUtility.FromJson(recordJson); if (nodeRecordEnvelope != null) { nodeGraphManager.ApplyNetworkNodeRecord(nodeRecordEnvelope.record); } } } [PunRPC] private void RPC_DeleteNode(int nodeId) { nodeGraphManager?.ApplyNetworkDelete(nodeId); } [PunRPC] private void RPC_ConnectWire(int outputNodeId, string outputPortName, int inputNodeId, string inputPortName) { if (!(nodeGraphManager == null)) { nodeGraphManager.ApplyNetworkWireRecord(new WorldGroupsCodec.WorldWireRecord { outputNodeId = outputNodeId, outputPortName = outputPortName, inputNodeId = inputNodeId, inputPortName = inputPortName }); } } [PunRPC] private void RPC_DisconnectInput(int inputNodeId, string inputPortName) { nodeGraphManager?.ApplyNetworkDisconnectInput(inputNodeId, inputPortName); } [PunRPC] private void RPC_DisconnectOutput(int outputNodeId, string outputPortName) { nodeGraphManager?.ApplyNetworkDisconnectOutput(outputNodeId, outputPortName); } [PunRPC] private void RPC_TriggerRun(int outputNodeId, string outputPortName) { nodeGraphManager?.ApplyNetworkTriggerRun(outputNodeId, outputPortName); } [PunRPC] private void RPC_EventRun(int nodeId, string outputPortName) { nodeGraphManager?.ApplyNetworkTriggerRun(nodeId, outputPortName); } private IEnumerator SendExistingGraphToPlayerAfterDelay(Player newPlayer) { float num = Mathf.Max(0f, lateJoinReplayDelay); if (num > 0f) { yield return new WaitForSecondsRealtime(num); } else { yield return null; } if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && newPlayer != null && !(nodeGraphManager == null)) { List allNodesSnapshot = nodeGraphManager.GetAllNodesSnapshot(); for (int i = 0; i < allNodesSnapshot.Count; i++) { BroadcastUpsertNode(allNodesSnapshot[i], newPlayer); } yield return null; List list = nodeGraphManager.BuildWorldWireRecords(); for (int j = 0; j < list.Count; j++) { BroadcastConnectWire(list[j], newPlayer); } } } private void BroadcastUpsertRecord(WorldGroupsCodec.WorldNodeRecord record, Player targetPlayer) { if (CanSendRpc()) { string text = JsonUtility.ToJson(new NodeRecordEnvelope { record = record }); if (targetPlayer != null) { cachedPhotonView.RPC("RPC_UpsertNode", targetPlayer, text); } else { cachedPhotonView.RPC("RPC_UpsertNode", RpcTarget.Others, text); } } } private bool CanSendRpc() { if (!PhotonNetwork.InRoom || cachedPhotonView == null) { return false; } if (cachedPhotonView.ViewID == 0) { Debug.LogWarning("NodeGraphPhotonSync requires a valid PhotonView ViewID to send RPCs.", this); return false; } return true; } }