/// <summary> /// Invokes all matching methods contained in nodes on the given network. /// </summary> /// <param name="publishedData">The data passed to the methods to be invoked.</param> /// <param name="publisher">Typically, the object that is invoking publish.</param> /// <param name="network">The network to publish to.</param> protected static void PublishToNetwork(object publishedData, object publisher, Tags tags, string network) { CommunicationNode current = null; if (!root.TryGetValue(network, out current)) { return; } List <CommunicationNode> orphanList = null; //iterate over all nodes on the network do { //keep track of orphaned nodes (unity objects that have been deleted will register as null) if (current.NodeOwner == null) { if (orphanList == null) { orphanList = new List <CommunicationNode>(); } orphanList.Add(current); continue; } //prevent sources from publishing to themselves if (current.allowPublishToSelf || current.NodeOwner != publisher) { if (debugPrintAllActivity) { DebugLogger.Log("Publish is Invoking handler for : " + publishedData.GetType().Name + " on " + GetObjectName(current.NodeOwner) + " sent by " + GetObjectName(publisher)); } bool result = current.InvokeMatchingCallback(publishedData, publisher, tags); if (result) { debugPublishWasHandled = true; } } current = current.next[network]; } while(current != root[network]); if (orphanList != null) { //remove/clean up orphaned nodes for (int i = 0; i < orphanList.Count; ++i) { RemoveNode(orphanList[i]); } } }
/// <summary> /// Add the given node to all networks. /// This method assumes that the networks exist and that the node is not already part of these networks. /// </summary> protected static void AddNodeToNetworks(CommunicationNode node, List <string> networkCollection) { foreach (string n in networkCollection) { CommunicationNode prev = root[n]; CommunicationNode next = root[n].next[n]; node.next[n] = next; node.prev[n] = prev; next.prev[n] = node; prev.next[n] = node; } }
/// <summary> /// Create any networks that don't already exist /// </summary> protected static void CreateNetworks(CommunicationNode node, List <string> networkCollection) { foreach (string n in networkCollection) { if (root.ContainsKey(n)) { continue; } root.Add(n, node); root[n].next[n] = root[n]; root[n].prev[n] = root[n]; } }
/// <summary> /// Does this node have any non-null connections on any networks? /// </summary> protected static bool NodeHasAnyConnections(CommunicationNode node) { foreach (var n in node.next) { if (n.Value.next != null) { return(true); } } foreach (var p in node.prev) { if (p.Value.prev != null) { return(true); } } return(false); }
/// <summary> /// Internal method that removes a node from the network in an intrusive linked-list style. /// </summary> protected static void RemoveNode(CommunicationNode node) { if (node.next == null) { return; } if (debugPrintAllActivity) { string removingNetworks = ""; node.Networks.ToList().Select(x => { removingNetworks += x + ", "; return(x); }); removingNetworks = removingNetworks.TrimEnd(',', ' '); DebugLogger.Log("Removing node with owner " + GetObjectName(node.NodeOwner) + " from network(s): " + removingNetworks); } foreach (string n in networks) { if (!node.next.ContainsKey(n)) { continue; } if (node.next[n] != null) { node.next[n].prev[n] = node.prev[n]; } if (node.prev[n] != null) { node.prev[n].next[n] = node.next[n]; } node.next[n] = null; node.prev[n] = null; //remove the network if it exists and it's empty if (root != null && root.ContainsKey(n) && root[n].next[n] == null && root[n].prev[n] == null) { root.Remove(n); } } }
/// <summary> /// Internal method that adds a node to the given networks in an intrusive linked-list style. /// </summary> protected static void AddNode(CommunicationNode node, List <string> networks) { if (debugPrintAllActivity) { string addingToNetworks = ""; networks.Select(x => { addingToNetworks += x + ", "; return(x); }); addingToNetworks = addingToNetworks.TrimEnd(',', ' '); DebugLogger.Log("Adding node with owner " + GetObjectName(node.NodeOwner) + " to network(s): " + addingToNetworks); } //if the node has non-null connections, clear them by removing it before we process the insertion if (NodeHasAnyConnections(node)) { RemoveNode(node); } CreateNetworks(node, networks); //add new nodes to the root AddNodeToNetworks(node, networks); }
/// <summary> /// Removes the node from all networks. For a unity object this should typically go in OnDisable or OnDestroy, depending on the desired behavior. /// </summary> public virtual void DisableNode() { CommunicationNode.RemoveNode(this); NodeOwner = null; }
/// <summary> /// Enables this node on the network. /// Any methods in the nodeOwner object that have the [CommunicationCallback] attribute will be registered as handlers on the network. /// Typically this should be put in Start/Awake/OnEnable or some other similar method. /// </summary> /// <param name="nodeOwner">An object with zero or more methods decorated with the [CommunicationCallback] attribute.</param> /// <param name="networksToJoin">(Optional) Zero or more strings, arrays of string, or lists of strings specifying the networks to publish to. If empty, will publish to all networks.</param> public virtual void EnableNode(object nodeOwner, params object[] networksToJoin) { //error: nodes themselves cannot be owners if (nodeOwner.GetType() == this.GetType()) { DisableNode(); throw new InvalidOperationException("A CommunicationNode may not be the owner of itself. A CommunicationNode needs a reference to a class with zero or more methods that have the [CommunicationCallback] attribute."); } //There must be an owner, so treat this as a removal. if (nodeOwner == null) { DisableNode(); return; } this.NodeOwner = nodeOwner; List <string> totalNetworks = new List <string>(); //Attempt to cast the params to strings, arrays of strings, or lists of strings and concat them into totalNetworks foreach (var n in networksToJoin) { if (n == null) { continue; } if (n as string[] != null) { totalNetworks.AddRange(n as string[]); } else if (n as List <string> != null) { totalNetworks.AddRange(n as List <string>); } else if (n as string != null) { totalNetworks.Add(n as string); } else { #if UNITY_5_3_OR_NEWER DebugLogger.LogError("Non-string parameter type or container found in networksToJoin params. All network params must be string, arrays of string, or lists of string."); #else DebugLogger.Write("Non-string parameter type or container found in networksToJoin params. All network params must be string, arrays of string, or lists of string."); #endif } } totalNetworks.AddRange(networksToJoinOnEnable); //By default, use the type name to add the object to its own network if (totalNetworks.Count <= 0) { totalNetworks.Add(nodeOwner.GetType().Name); } CommunicationNode.AddNode(this, totalNetworks); RefreshCallbackBindings(); }