Emesary mp support
Add support for transfer string Change Type to NotificationType as Type can be confusing
This commit is contained in:
parent
7fa52ea4ee
commit
4ed25ac361
3 changed files with 135 additions and 52 deletions
|
@ -275,7 +275,7 @@ var ANSPN46_System =
|
||||||
|
|
||||||
new_class.Receive = func(notification)
|
new_class.Receive = func(notification)
|
||||||
{
|
{
|
||||||
if (notification.Type == "ANSPN46ActiveResponseNotification")
|
if (notification.NotificationType == "ANSPN46ActiveResponseNotification")
|
||||||
{
|
{
|
||||||
if (notification.Tuned)
|
if (notification.Tuned)
|
||||||
{
|
{
|
||||||
|
|
|
@ -153,7 +153,7 @@ var Transmitter =
|
||||||
# SubClasses can add extra properties or methods.
|
# SubClasses can add extra properties or methods.
|
||||||
# Properties:
|
# Properties:
|
||||||
# Ident : Generic message identity. Can be an ident, or for simple messages a value that needs transmitting.
|
# Ident : Generic message identity. Can be an ident, or for simple messages a value that needs transmitting.
|
||||||
# Type : Message Type
|
# NotificationType : Notification Type
|
||||||
# IsDistinct : non zero if this message supercedes previous messages of this type.
|
# IsDistinct : non zero if this message supercedes previous messages of this type.
|
||||||
# Distinct messages are usually sent often and self contained
|
# Distinct messages are usually sent often and self contained
|
||||||
# (i.e. no relative state changes such as toggle value)
|
# (i.e. no relative state changes such as toggle value)
|
||||||
|
@ -168,7 +168,7 @@ var Notification =
|
||||||
{
|
{
|
||||||
var new_class = { parents: [Notification]};
|
var new_class = { parents: [Notification]};
|
||||||
new_class.Ident = _ident;
|
new_class.Ident = _ident;
|
||||||
new_class.Type = _type;
|
new_class.NotificationType = _type;
|
||||||
new_class.IsDistinct = 1;
|
new_class.IsDistinct = 1;
|
||||||
new_class.FromIncomingBridge = 0;
|
new_class.FromIncomingBridge = 0;
|
||||||
new_class.Callsign = nil;
|
new_class.Callsign = nil;
|
||||||
|
@ -221,6 +221,43 @@ var TransferCoord =
|
||||||
return mp_broadcast.Binary.decodeCoord(v);
|
return mp_broadcast.Binary.decodeCoord(v);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var TransferString =
|
||||||
|
{
|
||||||
|
#
|
||||||
|
# just to pack a valid range and keep the lower and very upper control codes for seperators
|
||||||
|
# that way we don't need to do anything special to encode the string.
|
||||||
|
getalphanumericchar : func(v)
|
||||||
|
{
|
||||||
|
if (find(v,"-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz") > 0)
|
||||||
|
return v;
|
||||||
|
return nil;
|
||||||
|
},
|
||||||
|
encode : func(v)
|
||||||
|
{
|
||||||
|
var l = size(v);
|
||||||
|
if (l > 16)
|
||||||
|
l = 16;
|
||||||
|
var rv = mp_broadcast.Binary.encodeByte(l);
|
||||||
|
|
||||||
|
print ("Encode string ",v," l=",l);
|
||||||
|
for(var ii = 0; ii < l; ii = ii + 1)
|
||||||
|
{
|
||||||
|
printf("%d,%d (%s)\n",ii+1,1,rv);
|
||||||
|
ev = TransferString.getalphanumericchar(substr(v,ii,1));
|
||||||
|
if (ev != nil)
|
||||||
|
rv = rv ~ ev;
|
||||||
|
}
|
||||||
|
print("String encode l=",l," val=",rv);
|
||||||
|
return rv;
|
||||||
|
},
|
||||||
|
decode : func(v)
|
||||||
|
{
|
||||||
|
var l = mp_broadcast.Binary.decodeByte(v);
|
||||||
|
var rv = substr(v,1,l-1);
|
||||||
|
print("String decode l=",l," val=",rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var TransferByte =
|
var TransferByte =
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,28 +1,69 @@
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Title : EMESARY multiplayer bridge
|
||||||
|
#
|
||||||
|
# File Type : Implementation File
|
||||||
|
#
|
||||||
|
# Description : Bridges selected emesary notifications over MP
|
||||||
|
# : To send a message use a Transmitter with an object. That's all there is to it.
|
||||||
|
#
|
||||||
|
# References : http://chateau-logic.com/content/emesary-nasal-implementation-flightgear
|
||||||
|
#
|
||||||
|
# Author : Richard Harrison (richard@zaretto.com)
|
||||||
|
#
|
||||||
|
# Creation Date : 04 April 2016
|
||||||
|
#
|
||||||
|
# Version : 4.8
|
||||||
|
#
|
||||||
|
# Copyright © 2016 Richard Harrison Released under GPL V2
|
||||||
|
#
|
||||||
|
#---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
# Example of connecting an incoming and outgoing bridge (should reside inside an aircraft nasal file)
|
||||||
|
#
|
||||||
|
# var routedNotifications = [notifications.TacticalNotification.new(nil)];
|
||||||
|
# var incomingBridge = emesary_mp_bridge.IncomingMPBridge.startMPBridge(routedNotifications);
|
||||||
|
# var outgoingBridge = emesary_mp_bridge.OutgoingMPBridge.new("F-15mp",routedNotifications);
|
||||||
|
#------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# bridge message rules;
|
# NOTES: Aircraft do not need to have both an incoming and outgoing bridge, but it is usual.
|
||||||
# - if distinct must be absolute and self contained as a later message will supercede any earlier ones in the outgoing queue.
|
# Only the notifications specified will be routed via the bridge.
|
||||||
# - use the message type and ident to identify distinct messages
|
# Once routed a message will by default not be re-rerouted again by the outgoing bridge.
|
||||||
# The outgoing 'port' is a multiplay/generic/string index.
|
# Transmit frequency and message lifetime may need to be tuned.
|
||||||
# - ! is used as a seperator between the elements that are used to send the notification (typeid, sequence, notification)
|
# IsDistinct messages must be absolute and self contained as a later message will
|
||||||
|
# supercede any earlier ones in the outgoing queue (possibly prior to receipt)
|
||||||
|
# Use the message type and ident to identify distinct messages
|
||||||
|
# The outgoing 'port' is a multiplay/generic/string index.
|
||||||
|
# - ! is used as a seperator between the elements that are used to send the
|
||||||
|
# notification (typeid, sequence, notification)
|
||||||
|
# - There is an extra ! at the start of the message that is used to indicate protocol version.
|
||||||
# - ; is used to seperate serialzied elemnts of the notification
|
# - ; is used to seperate serialzied elemnts of the notification
|
||||||
#
|
|
||||||
# Outgoing messages are sent in a scheduled manner, usually once per second, and each message has a lifetime (to allow for propogation to
|
# General Notes
|
||||||
# all clients over UDP). Clients will ignore messages that they have already received (based on the sequence id).
|
#----------------------------------------------------------------------
|
||||||
#
|
# Outgoing messages are sent in a scheduled manner, usually once per
|
||||||
# The incoming bridge will usually be created part of the aircraft model file; it is important to understand that each AI/MP model will have an incoming bridge
|
# second, and each message has a lifetime (to allow for propogation to
|
||||||
# as each element in /ai/models needs its own bridge to keep up with the incoming sequence id. This scheme may not work properly as it relies on the model being
|
# all clients over UDP). Clients will ignore messages that they have
|
||||||
# loaded which may only happen when visible so it may be necessary to track AI models in a seperate instantiatable incoming bridge manager.
|
# already received (based on the sequence id).
|
||||||
|
|
||||||
|
# The incoming bridge will usually be created part of the aircraft
|
||||||
|
# model file; it is important to understand that each AI/MP model will
|
||||||
|
# have an incoming bridge as each element in /ai/models needs its own
|
||||||
|
# bridge to keep up with the incoming sequence id. This scheme may not
|
||||||
|
# work properly as it relies on the model being loaded which may only
|
||||||
|
# happen when visible so it may be necessary to track AI models in a
|
||||||
|
# seperate instantiatable incoming bridge manager.
|
||||||
#
|
#
|
||||||
# The outgoing bridge would usually be created within the aircraft loading Nasal.
|
# The outgoing bridge would usually be created within the aircraft loading Nasal.
|
||||||
|
|
||||||
var OutgoingMPBridge =
|
var OutgoingMPBridge =
|
||||||
{
|
{
|
||||||
new: func(_ident, _notifications_to_bridge=nil, _mpidx=19, _root="", _transmitter=nil)
|
new: func(_ident, _notifications_to_bridge=nil, _mpidx=18, _root="", _transmitter=nil)
|
||||||
{
|
{
|
||||||
if (_transmitter == nil)
|
if (_transmitter == nil)
|
||||||
_transmitter = emesary.GlobalTransmitter;
|
_transmitter = emesary.GlobalTransmitter;
|
||||||
|
|
||||||
print("OutgoingMPBridge created for "~_ident);
|
print("OutgoingMPBridge created for "~_ident);
|
||||||
|
|
||||||
var new_class = emesary.Recipient.new("OutgoingMPBridge "~_ident);
|
var new_class = emesary.Recipient.new("OutgoingMPBridge "~_ident);
|
||||||
|
|
||||||
new_class.MessageIndex = 100;
|
new_class.MessageIndex = 100;
|
||||||
|
@ -33,6 +74,9 @@ var OutgoingMPBridge =
|
||||||
else
|
else
|
||||||
new_class.NotificationsToBridge = _notifications_to_bridge;
|
new_class.NotificationsToBridge = _notifications_to_bridge;
|
||||||
|
|
||||||
|
foreach(var n ; new_class.NotificationsToBridge)
|
||||||
|
print(" bridge --> ",n.NotificationType);
|
||||||
|
|
||||||
new_class.MPout = "";
|
new_class.MPout = "";
|
||||||
new_class.MPidx = _mpidx;
|
new_class.MPidx = _mpidx;
|
||||||
new_class.MessageLifeTime = 10; # seconds
|
new_class.MessageLifeTime = 10; # seconds
|
||||||
|
@ -42,6 +86,7 @@ var OutgoingMPBridge =
|
||||||
new_class.Transmitter.Register(new_class);
|
new_class.Transmitter.Register(new_class);
|
||||||
new_class.MpVariable = _root~"sim/multiplay/generic/string["~new_class.MPidx~"]";
|
new_class.MpVariable = _root~"sim/multiplay/generic/string["~new_class.MPidx~"]";
|
||||||
new_class.TransmitterActive = 0;
|
new_class.TransmitterActive = 0;
|
||||||
|
new_class.TransmitFrequencySeconds = 1;
|
||||||
|
|
||||||
new_class.TransmitTimer =
|
new_class.TransmitTimer =
|
||||||
maketimer(6, func
|
maketimer(6, func
|
||||||
|
@ -49,9 +94,8 @@ var OutgoingMPBridge =
|
||||||
if(new_class.TransmitterActive)
|
if(new_class.TransmitterActive)
|
||||||
new_class.Transmit();
|
new_class.Transmit();
|
||||||
|
|
||||||
new_class.TransmitTimer.restart(1);
|
new_class.TransmitTimer.restart(new_class.TransmitFrequencySeconds);
|
||||||
});
|
});
|
||||||
new_class.TransmitTimer.restart(1);
|
|
||||||
|
|
||||||
new_class.Delete = func
|
new_class.Delete = func
|
||||||
{
|
{
|
||||||
|
@ -72,20 +116,20 @@ var OutgoingMPBridge =
|
||||||
if (notification.FromIncomingBridge)
|
if (notification.FromIncomingBridge)
|
||||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||||
|
|
||||||
#print("Receive ",notification.Type," (",notification.Ident);
|
print("Receive ",notification.NotificationType," ",notification.Ident);
|
||||||
for (var idx = 0; idx < size(me.NotificationsToBridge); idx += 1)
|
for (var idx = 0; idx < size(me.NotificationsToBridge); idx += 1)
|
||||||
{
|
{
|
||||||
if(me.NotificationsToBridge[idx].Type == notification.Type)
|
if(me.NotificationsToBridge[idx].NotificationType == notification.NotificationType)
|
||||||
{
|
{
|
||||||
me.MessageIndex += 1;
|
me.MessageIndex += 1;
|
||||||
notification.MessageExpiryTime = systime()+me.MessageLifeTime;
|
notification.MessageExpiryTime = systime()+me.MessageLifeTime;
|
||||||
notification.BridgeMessageId = me.MessageIndex;
|
notification.BridgeMessageId = me.MessageIndex;
|
||||||
notification.BridgeMessageTypeId = idx;
|
notification.BridgeMessageNotificationTypeId = idx;
|
||||||
#
|
#
|
||||||
# The message key is a composite of the type and ident to allow for multiple senders
|
# The message key is a composite of the type and ident to allow for multiple senders
|
||||||
# of the same message type.
|
# of the same message type.
|
||||||
notification.BridgeMessageTypeKey = notification.Type~"."~notification.Ident;
|
notification.BridgeMessageNotificationTypeKey = notification.NotificationType~"."~notification.Ident;
|
||||||
#print("Received ",notification.BridgeMessageTypeKey," expire=",notification.MessageExpiryTime);
|
#print("Received ",notification.BridgeMessageNotificationTypeKey," expire=",notification.MessageExpiryTime);
|
||||||
me.AddToOutgoing(notification);
|
me.AddToOutgoing(notification);
|
||||||
return emesary.Transmitter.ReceiptStatus_Pending;
|
return emesary.Transmitter.ReceiptStatus_Pending;
|
||||||
}
|
}
|
||||||
|
@ -98,16 +142,16 @@ var OutgoingMPBridge =
|
||||||
{
|
{
|
||||||
for (var idx = 0; idx < size(me.OutgoingList); idx += 1)
|
for (var idx = 0; idx < size(me.OutgoingList); idx += 1)
|
||||||
{
|
{
|
||||||
if(me.OutgoingList[idx].BridgeMessageTypeKey == notification.BridgeMessageTypeKey)
|
if(me.OutgoingList[idx].BridgeMessageNotificationTypeKey == notification.BridgeMessageNotificationTypeKey)
|
||||||
{
|
{
|
||||||
#print("Update ",me.OutgoingList[idx].BridgeMessageTypeKey);
|
#print("Update ",me.OutgoingList[idx].BridgeMessageNotificationTypeKey);
|
||||||
me.OutgoingList[idx]= notification;
|
me.OutgoingList[idx]= notification;
|
||||||
me.TransmitterActive = size(me.OutgoingList);
|
me.TransmitterActive = size(me.OutgoingList);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#print("Added ",notification.BridgeMessageTypeKey);
|
#print("Added ",notification.BridgeMessageNotificationTypeKey);
|
||||||
append(me.OutgoingList, notification);
|
append(me.OutgoingList, notification);
|
||||||
me.TransmitterActive = size(me.OutgoingList);
|
me.TransmitterActive = size(me.OutgoingList);
|
||||||
};
|
};
|
||||||
|
@ -133,7 +177,7 @@ var OutgoingMPBridge =
|
||||||
#print("Encode ",eidx,"=",encval);
|
#print("Encode ",eidx,"=",encval);
|
||||||
eidx += 1;
|
eidx += 1;
|
||||||
}
|
}
|
||||||
sect = sprintf("%d!%d!%s",notification.BridgeMessageId, notification.BridgeMessageTypeId, encval);
|
sect = sprintf("!%d!%d!%s",notification.BridgeMessageId, notification.BridgeMessageNotificationTypeId, encval);
|
||||||
outgoing = outgoing~sect;
|
outgoing = outgoing~sect;
|
||||||
me.OutgoingList[out_idx] = me.OutgoingList[idx];
|
me.OutgoingList[out_idx] = me.OutgoingList[idx];
|
||||||
# print("xmit ",idx," out=",out_idx);
|
# print("xmit ",idx," out=",out_idx);
|
||||||
|
@ -150,6 +194,7 @@ var OutgoingMPBridge =
|
||||||
for(var del_i=0; del_i < del_count; del_i += 1)
|
for(var del_i=0; del_i < del_count; del_i += 1)
|
||||||
pop(me.OutgoingList);
|
pop(me.OutgoingList);
|
||||||
};
|
};
|
||||||
|
new_class.TransmitTimer.restart(new_class.TransmitFrequencySeconds);
|
||||||
return new_class;
|
return new_class;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -160,7 +205,7 @@ var OutgoingMPBridge =
|
||||||
# route messages to
|
# route messages to
|
||||||
var IncomingMPBridge =
|
var IncomingMPBridge =
|
||||||
{
|
{
|
||||||
new: func(_ident, _notifications_to_bridge=nil, _mpidx=19, _transmitter=nil)
|
new: func(_ident, _notifications_to_bridge=nil, _mpidx=18, _transmitter=nil)
|
||||||
{
|
{
|
||||||
if (_transmitter == nil)
|
if (_transmitter == nil)
|
||||||
_transmitter = emesary.GlobalTransmitter;
|
_transmitter = emesary.GlobalTransmitter;
|
||||||
|
@ -216,12 +261,12 @@ var IncomingMPBridge =
|
||||||
{
|
{
|
||||||
# get the message parts
|
# get the message parts
|
||||||
var encoded_notification = split("!", encoded_val);
|
var encoded_notification = split("!", encoded_val);
|
||||||
if (size(encoded_notification) < 3)
|
if (size(encoded_notification) < 4)
|
||||||
print("Error: emesary.IncomingBridge.ProcessIncoming bad msg ",encoded_val);
|
print("Error: emesary.IncomingBridge.ProcessIncoming bad msg ",encoded_val);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var msg_idx = encoded_notification[0];
|
var msg_idx = encoded_notification[1];
|
||||||
var msg_type_id = encoded_notification[1];
|
var msg_type_id = encoded_notification[2];
|
||||||
if (msg_type_id >= size(me.NotificationsToBridge))
|
if (msg_type_id >= size(me.NotificationsToBridge))
|
||||||
{
|
{
|
||||||
print("Error: emesary.IncomingBridge.ProcessIncoming invalid type_id ",msg_type_id);
|
print("Error: emesary.IncomingBridge.ProcessIncoming invalid type_id ",msg_type_id);
|
||||||
|
@ -229,14 +274,14 @@ var IncomingMPBridge =
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var msg = me.NotificationsToBridge[msg_type_id];
|
var msg = me.NotificationsToBridge[msg_type_id];
|
||||||
var msg_notify = encoded_notification[2];
|
var msg_notify = encoded_notification[3];
|
||||||
print("received idx=",msg_idx," ",msg_type_id,":",msg.Type);
|
print("received idx=",msg_idx," ",msg_type_id,":",msg.NotificationType);
|
||||||
if(msg_idx <= me.IncomingMessageIndex)
|
if(msg_idx <= me.IncomingMessageIndex)
|
||||||
print(" **Already processed");
|
print(" **Already processed");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
# raise notification
|
# raise notification
|
||||||
var bridged_notification = msg; #emesary.Notification.new(msg.Type,"BridgedMessage");
|
var bridged_notification = msg; #emesary.Notification.new(msg.NotificationType,"BridgedMessage");
|
||||||
# populate fields
|
# populate fields
|
||||||
var bridgedProperties = msg.bridgeProperties();
|
var bridgedProperties = msg.bridgeProperties();
|
||||||
var encvals=split(";", msg_notify);
|
var encvals=split(";", msg_notify);
|
||||||
|
@ -267,30 +312,45 @@ var IncomingMPBridge =
|
||||||
}
|
}
|
||||||
foreach(var n; new_class.NotificationsToBridge)
|
foreach(var n; new_class.NotificationsToBridge)
|
||||||
{
|
{
|
||||||
print("IncomingBridge: ",n.Type);
|
print("IncomingBridge: ",n.NotificationType);
|
||||||
}
|
}
|
||||||
return new_class;
|
return new_class;
|
||||||
},
|
},
|
||||||
|
#
|
||||||
|
# Each multiplayer object will have its own incoming bridge. This is necessary to allow message ID
|
||||||
|
# tracking (as the bridge knows which messages have been already processed)
|
||||||
|
# Whenever a client connects over MP a new bridge is instantiated
|
||||||
startMPBridge : func(notification_list)
|
startMPBridge : func(notification_list)
|
||||||
{
|
{
|
||||||
var incomingBridgeList = {};
|
var incomingBridgeList = {};
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create bridge whenever a client connects
|
||||||
|
#
|
||||||
setlistener("/ai/models/model-added", func(v)
|
setlistener("/ai/models/model-added", func(v)
|
||||||
{
|
{
|
||||||
#Model added /ai[0]/models[0]/multiplayer[0]
|
# Model added will be eg: /ai[0]/models[0]/multiplayer[0]
|
||||||
var path = v.getValue();
|
var path = v.getValue();
|
||||||
|
|
||||||
print("Model added ",path);
|
print("Model added ",path);
|
||||||
|
# Ensure we only handle multiplayer elements
|
||||||
if (find("/multiplayer",path) > 0)
|
if (find("/multiplayer",path) > 0)
|
||||||
{
|
{
|
||||||
var callsign = getprop(path~"/callsign");
|
var callsign = getprop(path~"/callsign");
|
||||||
print("Creating Emesary MPBridge for ",callsign);
|
print("Creating Emesary MPBridge for ",callsign);
|
||||||
if (callsign == "" or callsign == nil)
|
if (callsign == "" or callsign == nil)
|
||||||
callsign = path;
|
callsign = path;
|
||||||
var incomingBridge = emesary_mp_bridge.IncomingMPBridge.new(callsign~"mp", notification_list, 19);
|
|
||||||
|
var incomingBridge = emesary_mp_bridge.IncomingMPBridge.new(callsign~"mp", notification_list, 18);
|
||||||
|
|
||||||
incomingBridge.Connect(path~"/");
|
incomingBridge.Connect(path~"/");
|
||||||
incomingBridgeList[path] = incomingBridge;
|
incomingBridgeList[path] = incomingBridge;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#
|
||||||
|
# when a client disconnects remove the associated bridge.
|
||||||
|
#
|
||||||
setlistener("/ai/models/model-removed", func(v){
|
setlistener("/ai/models/model-removed", func(v){
|
||||||
print("Model removed ",v.getValue());
|
print("Model removed ",v.getValue());
|
||||||
var path = v.getValue();
|
var path = v.getValue();
|
||||||
|
@ -303,17 +363,3 @@ var IncomingMPBridge =
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
#to setup bridges;
|
|
||||||
#io.load_nasal(getprop("/sim/fg-root") ~ "/Nasal/emesary_mp_bridge.nas");
|
|
||||||
#var outgoingBridge = emesary_mp_bridge.OutgoingMPBridge.new("F-15mp");
|
|
||||||
#outgoingBridge.AddMessage(an_spn_46.ANSPN46ActiveNotification.new("template"));
|
|
||||||
#incomingBridge = emesary_mp_bridge.IncomingMPBridge.new("F-15mp");
|
|
||||||
#incomingBridge.AddMessage(an_spn_46.ANSPN46ActiveNotification.new("template"));
|
|
||||||
#var outgoingBridge = emesary_mp_bridge.OutgoingMPBridge.new("F-15mp");
|
|
||||||
#outgoingBridge.AddMessage(an_spn_46.ANSPN46ActiveNotification.new("template"));
|
|
||||||
# var m = emesary.notifications.TacticalNotification("rr",2);
|
|
||||||
# emesary.GlobalTransmitter.NotifyAll(m);
|
|
||||||
#var outgoingBridge = emesary_mp_bridge.OutgoingMPBridge.new("F-15mp");
|
|
||||||
#outgoingBridge.AddMessage(notifications.TacticalNotification.new(nil));
|
|
||||||
# var m = emesary.notifications.TacticalNotification("rr",2);
|
|
||||||
# emesary.GlobalTransmitter.NotifyAll(m);
|
|
||||||
|
|
Loading…
Reference in a new issue