/// <summary> /// Register all MmResponders that can receive messages. /// </summary> /// <param name="responder"></param> public void RegisterMmNetworkResponder(MmNetworkResponder responder) { MmRelayNode nodeToAdd; bool presentInDictionary = MmRelayNodes.TryGetValue(responder.netId.Value, out nodeToAdd); if (!presentInDictionary) { MmRelayNodes.Add(responder.netId.Value, responder.MmRelayNode); } }
/// <summary> /// Removes a particular relay node from the dictionary of supported nodes. /// </summary> public void RemoveMmNetworkResponder(MmNetworkResponder responder) { MmRelayNode nodeToRemove; bool presentInDictionary = MmRelayNodes.TryGetValue(responder.netId.Value, out nodeToRemove); if (!presentInDictionary) { MmRelayNodes.Remove(responder.netId.Value); } }
/// <summary> /// Invoke an MmMethod. /// </summary> /// <param name="msgType">Type of message. This specifies /// the type of the payload. This is important in /// networked scenarios, when proper deseriaization into /// the correct type requires knowing what was /// used to serialize the object originally. /// </param> /// <param name="message">The message to send. /// This class builds on UNET's MessageBase so it is /// Auto [de]serialized by UNET.</param> public override void MmInvoke(MmMessageType msgType, MmMessage message) { //If the MmRelayNode has not been initialized, initialize it here, // and refresh the parents - to ensure proper routing can occur. InitializeNode(); //TODO: Switch to using mutex for threaded applications doNotModifyRoutingTable = true; MmNetworkFilter networkFilter = message.MetadataBlock.NetworkFilter; //Experimental: Allow forced serial execution (ordered) of messages. //if (serialExecution) //{ // if (!_executing) // { // _executing = true; // } // else // { // MmLogger.LogFramework("<<<<<>>>>>Queueing<<<<<>>>>>"); // KeyValuePair<MmMessageType, MmMessage> newMessage = // new KeyValuePair<MmMessageType, MmMessage>(msgType, message); // SerialExecutionQueue.Enqueue(newMessage); // return; // } //} //MmLogger.LogFramework (gameObject.name + ": MmRelayNode received MmMethod call: " + param.MmMethod.ToString ()); // If an MmNetworkResponder is attached to this object, and the MmMessage has not already been deserialized // then call the MmNetworkResponder's network message invocation function. if (MmNetworkResponder != null && message.MetadataBlock.NetworkFilter != MmNetworkFilter.Local && !message.IsDeserialized) { //if (!dirty) //{ // dirty = true; // message.TimeStamp = DateTime.UtcNow.ToShortTimeString(); // _prevMessageTime = message.TimeStamp; //} //This will ensure that beyond the point at which a message is determined to be sendable, // it will not be treated as networ networkFilter = NetworkFilterAdjust(ref message); MmNetworkResponder.MmInvoke(msgType, message); } //Todo: it's possible to get this to happen only once per graph. Switch Invoke code to support. var upwardMessage = message.Copy(); upwardMessage.MetadataBlock.LevelFilter = MmLevelFilterHelper.SelfAndParents; var downwardMessage = message.Copy(); downwardMessage.MetadataBlock.LevelFilter = MmLevelFilterHelper.SelfAndChildren; MmLevelFilter levelFilter = message.MetadataBlock.LevelFilter; MmActiveFilter activeFilter = ActiveFilterAdjust(ref message); MmSelectedFilter selectedFilter = SelectedFilterAdjust(ref message); //If this message was a network-only message and // this node does not allow for propagation of network messages, // then return. if (!AllowNetworkPropagationLocally && !message.IsDeserialized && message.MetadataBlock.NetworkFilter == MmNetworkFilter.Network) { return; } foreach (var routingTableItem in RoutingTable) { var responder = routingTableItem.Responder; //bool isLocalResponder = responder.MmGameObject == this.gameObject; MmLevelFilter responderLevel = routingTableItem.Level; //Check individual responder level and then call the right param. MmMessage responderSpecificMessage; if ((responderLevel & MmLevelFilter.Parent) > 0) { responderSpecificMessage = upwardMessage; } else if ((responderLevel & MmLevelFilter.Child) > 0) { responderSpecificMessage = downwardMessage; } else { responderSpecificMessage = message; } //MmLogger.LogFramework (gameObject.name + "observing " + responder.MmGameObject.name); if (ResponderCheck(levelFilter, activeFilter, selectedFilter, networkFilter, routingTableItem, responderSpecificMessage)) { responder.MmInvoke(msgType, responderSpecificMessage); } } //if (dirty && _prevMessageTime == message.TimeStamp) //{ // dirty = false; //} doNotModifyRoutingTable = false; while (MmRespondersToAdd.Any()) { var routingTableItem = MmRespondersToAdd.Dequeue(); MmAddToRoutingTable(routingTableItem.Responder, routingTableItem.Level); if (ResponderCheck(levelFilter, activeFilter, selectedFilter, networkFilter, routingTableItem, message)) { routingTableItem.Responder.MmInvoke(msgType, message); } } //if (serialExecution) //{ // if (SerialExecutionQueue.Count != 0) // { // MmLogger.LogFramework("%%%%%%%%%%%Dequeueing%%%%%%%%%"); // KeyValuePair<MmMessageType, MmMessage> DequeuedMessage = SerialExecutionQueue.Dequeue(); // MmInvoke(DequeuedMessage.Key, DequeuedMessage.Value); // } // _executing = false; //} }