1
0
Fork 0

Emesary changes to better support GeoEventNotifications.

A GeoEventNotification can be used to notify all other MP craft (that are connected to the bridge) of AI objects or ballistic items that are present on the local player's machine. For example tankers, dropped payloads, missiles, carriers.

Changes

- Fix transfer string encoding for bridge. If the string contained untransmittable characters the length was wrong. Change to use the valid characters from BinaryTransfer.

- Fix bug transferring negative numbers.

- Add method to notification to provide the type key to be used to decide if a non distinct message should be added to the queue; rather than relying on the simple type.ident. This allows multiple notifications of the same type to be non distinct but also be transmitted

- Allow the maximum size of the mp string to be defined per bridge; rather than a system wide value. This allows the bridges to have their size tuned to match expected requirements; for example a bridge that is transmitting GeoEventNotification may need a lot more space than a bridge that is transmitting property sync notifications.

- Improve error message when out of space (due to the maximum string length)

- add trace option to bridges to aid debugging of transmitted values. This will produce verbose output.

- Add UniqueIndex to GeoEventNotification; to allow for multiple non-distinct notifications to be transmitted concurrently. This overrides the GetBridgeMessageNotificationTypeKey to include the UniqueIndex
This commit is contained in:
Richard Harrison 2017-11-18 01:51:08 +01:00
parent 1e69f3eb75
commit 28fbda2e2a
3 changed files with 99 additions and 51 deletions

View file

@ -173,6 +173,10 @@ var Notification =
new_class.IsDistinct = 1;
new_class.FromIncomingBridge = 0;
new_class.Callsign = nil;
new_class.GetBridgeMessageNotificationTypeKey = func {
return me.NotificationType~"."~me.Ident;
};
if (_typeid == 0)
{
_typeid = NotificationAutoTypeId;
@ -246,8 +250,13 @@ var BinaryAsciiTransfer =
{
if (num == 0)
return substr(BinaryAsciiTransfer.empty_encoding,0,length);
var arr="";
var negate=0;
if (num < 0) {
negate = 1;
num = -num;
}
while (num > 0 and length > 0) {
var num0 = num;
num = (int)(num / BinaryAsciiTransfer._base);
@ -257,14 +266,23 @@ var BinaryAsciiTransfer =
}
if (length>0)
arr = substr(BinaryAsciiTransfer.spaces,0,length)~arr;
if(negate)
arr = "-"~arr;
return arr;
},
retval : {value:0, pos:0},
decodeInt : func(str, length, pos)
{
var power = length-1;
var negate = 0;
BinaryAsciiTransfer.retval.value = 0;
BinaryAsciiTransfer.retval.pos = pos;
if (substr(str,BinaryAsciiTransfer.retval.pos,1)=="-") {
negate=1;
BinaryAsciiTransfer.retval.pos = BinaryAsciiTransfer.retval.pos+1;
}
while (length > 0 and power > 0) {
var c = substr(str,BinaryAsciiTransfer.retval.pos,1);
if (c != " ") break;
@ -288,18 +306,21 @@ var BinaryAsciiTransfer =
length = length-1;
BinaryAsciiTransfer.retval.pos = BinaryAsciiTransfer.retval.pos + 1;
}
if (negate)
BinaryAsciiTransfer.retval.value = -BinaryAsciiTransfer.retval.value;
return BinaryAsciiTransfer.retval;
}
};
var TransferString =
{
MaxLength:16,
#
# 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)
if (find(v,BinaryAsciiTransfer.alphabet) > 0)#"-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz") > 0)
return v;
return nil;
},
@ -308,22 +329,27 @@ var TransferString =
if (v==nil)
return "0";
var l = size(v);
if (l > 16)
l = 16;
var rv = BinaryAsciiTransfer.encodeInt(l,1);
if (l > TransferString.MaxLength)
l = TransferString.MaxLength;
var rv = "";
var actual_len = 0;
for(var ii = 0; ii < l; ii = ii + 1)
{
ev = TransferString.getalphanumericchar(substr(v,ii,1));
if (ev != nil)
if (ev != nil) {
rv = rv ~ ev;
actual_len = actual_len + 1;
}
}
rv = BinaryAsciiTransfer.encodeInt(l,1) ~ rv;
return rv;
},
decode : func(v,pos)
{
var dv = BinaryAsciiTransfer.decodeInt(v,1,pos);
var length = dv.value;
if (length == 0)
return dv;
var rv = substr(v,dv.pos,length);
dv.pos = dv.pos + length;
dv.value = rv;

View file

@ -97,6 +97,7 @@ var OutgoingMPBridge =
new_class.MpVariable = _root~"sim/multiplay/generic/string["~new_class.MPidx~"]";
new_class.TransmitterActive = 0;
new_class.TransmitFrequencySeconds = 1;
new_class.trace = 0;
new_class.TransmitTimer =
maketimer(6, func
@ -139,7 +140,6 @@ var OutgoingMPBridge =
#
# The message key is a composite of the type and ident to allow for multiple senders
# of the same message type.
notification.BridgeMessageNotificationTypeKey = notification.NotificationType~"."~notification.Ident;
#print("Received ",notification.BridgeMessageNotificationTypeKey," expire=",notification.MessageExpiryTime);
me.AddToOutgoing(notification);
return emesary.Transmitter.ReceiptStatus_Pending;
@ -153,16 +153,24 @@ var OutgoingMPBridge =
{
for (var idx = 0; idx < size(me.OutgoingList); idx += 1)
{
if(me.OutgoingList[idx].BridgeMessageNotificationTypeKey == notification.BridgeMessageNotificationTypeKey)
if (me.trace)
print("Compare [",idx,"] qId=",me.OutgoingList[idx].GetBridgeMessageNotificationTypeKey() ," noti --> ",notification.GetBridgeMessageNotificationTypeKey());
if(me.OutgoingList[idx].GetBridgeMessageNotificationTypeKey() == notification.GetBridgeMessageNotificationTypeKey())
{
#print("Update ",me.OutgoingList[idx].BridgeMessageNotificationTypeKey);
if (me.trace)
print(" --> Update ",me.OutgoingList[idx].GetBridgeMessageNotificationTypeKey() ," noti --> ",notification.GetBridgeMessageNotificationTypeKey());
me.OutgoingList[idx]= notification;
me.TransmitterActive = size(me.OutgoingList);
return;
}
}
}
#print("Added ",notification.BridgeMessageNotificationTypeKey);
else
if (me.trace)
print("Not distinct, adding always");
if (me.trace)
print(" --> Added ",notification.GetBridgeMessageNotificationTypeKey());
append(me.OutgoingList, notification);
me.TransmitterActive = size(me.OutgoingList);
};
@ -192,16 +200,15 @@ var OutgoingMPBridge =
OutgoingMPBridge.SeperatorChar, emesary.BinaryAsciiTransfer.encodeInt(notification.BridgeMessageNotificationTypeId,1),
OutgoingMPBridge.SeperatorChar, encval, OutgoingMPBridge.MessageEndChar);
if (size(outgoing) + size(sect) < OutgoingMPBridge.MPStringMaxLen)
if (size(outgoing) + size(sect) < me.MPStringMaxLen)
{
outgoing = outgoing~sect;
}
else
{
if(idx == 0)
print("Emesary: ERROR Notification is too large for outgoing queue: ",notification.NotificationType);
# print("outgoing buffer full: Qsize ",size(me.OutgoingList),": message lifetime extended ",notification.Ident, " xmit ",idx, " outtext=",size(outgoing), " sect=",size(sect));
print("Emesary: ERROR out of space for ",notification.NotificationType, " transmitted count=",idx, " queue size ",size(me.OutgoingList));
notification.MessageExpiryTime = systime()+me.MessageLifeTime;
break;
}
}
else
@ -211,7 +218,7 @@ var OutgoingMPBridge =
}
me.TransmitterActive = size(me.OutgoingList);
setprop(me.MpVariable,outgoing);
# print("Set ",me.MpVariable," to ",outgoing);
# print("Set ",me.MpVariable," size(",size(outgoing));
#loopback test:
# incomingBridge.ProcessIncoming(outgoing);
@ -261,7 +268,7 @@ var IncomingMPBridge =
if (_transmitter == nil)
_transmitter = emesary.GlobalTransmitter;
print("IncominggMPBridge created for "~_ident," mp=",_mpidx, " using Transmitter ",_transmitter.Ident);
print("IncomingMPBridge created for "~_ident," mp=",_mpidx, " using Transmitter ",_transmitter.Ident);
var new_class = emesary.Transmitter.new("IncominggMPBridge "~_ident);
@ -284,6 +291,7 @@ var IncomingMPBridge =
new_class.OutgoingList = [];
new_class.Transmitter = _transmitter;
new_class.MpVariable = "";
new_class.trace = 0;
new_class.Connect = func(_root)
{
@ -317,54 +325,53 @@ var IncomingMPBridge =
{
if (encoded_val == "")
return;
# print("ProcessIncoming ", encoded_val);
# print("ProcessIncoming ", encoded_val);
var encoded_notifications = split(OutgoingMPBridge.MessageEndChar, encoded_val);
for (var idx = 0; idx < size(encoded_notifications); idx += 1)
{
for (var idx = 0; idx < size(encoded_notifications); idx += 1) {
if (encoded_notifications[idx] == "")
continue;
# get the message parts
continue ;
# get the message parts
var encoded_notification = split(OutgoingMPBridge.SeperatorChar, encoded_notifications[idx]);
if (size(encoded_notification) < 4)
print("Error: emesary.IncomingBridge.ProcessIncoming bad msg ",encoded_notifications[idx]);
else
{
else {
var msg_idx = emesary.BinaryAsciiTransfer.decodeInt(encoded_notification[1],4,0).value;
var msg_type_id = emesary.BinaryAsciiTransfer.decodeInt(encoded_notification[2],1,0).value;
var bridged_notification = new_class.NotificationsToBridge_Lookup[msg_type_id];
if (bridged_notification == nil)
{
if (bridged_notification == nil) {
print("Error: emesary.IncomingBridge.ProcessIncoming invalid type_id ",msg_type_id);
}
else
{
if (msg_idx > bridged_notification.IncomingMessageIndex)
{
} else {
if (msg_idx > bridged_notification.IncomingMessageIndex) {
var msg_body = encoded_notification[3];
#print("received idx=",msg_idx," ",msg_type_id,":",bridged_notification.NotificationType);
if (me.trace)
print("received idx=",msg_idx," ",msg_type_id,":",bridged_notification.NotificationType);
# populate fields
var bridgedProperties = bridged_notification.bridgeProperties();
var msglen = size(msg_body);
#print("Process ",msg_body," len=",msglen, " BPsize = ",size(bridgedProperties));
var bridgePropertyIndex = 0;
if (me.trace)
print("Process ",msg_body," len=",msglen, " BPsize = ",size(bridgedProperties));
var pos = 0;
for (var bpi = 0; bpi < size(bridgedProperties); bpi += 1)
{
if (pos < msglen)
{
for (var bpi = 0; bpi < size(bridgedProperties); bpi += 1) {
if (pos < msglen) {
if (me.trace)
print("dec: pos ",pos);
var bp = bridgedProperties[bpi];
dv = bp.setValue(msg_body, me, pos);
if (me.trace)
print(" --> next pos ",pos);
if (dv.pos == pos or dv.pos > msglen)
break;
#debug.dump(dv);
pos = dv.pos;
}
else
{
print("Error: emesary.IncomingBridge.ProcessIncoming: supplementary encoded value at",bridgePropertyIndex);
} else {
print("Error: emesary.IncomingBridge.ProcessIncoming: [",bridged_notification.NotificationType,"] supplementary encoded value at position ",bpi);
break;
}
}
# maybe extend the bridge to allow certain notifications to only be routed to a specific player;
# i.e.
# (notification.Callsign == nil or notification.Callsign == getprop("/sim/multiplay/callsign"))
if (bridged_notification.Ident == "none")
bridged_notification.Ident = "mp-bridge";
bridged_notification.FromIncomingBridge = 1;
@ -376,12 +383,12 @@ var IncomingMPBridge =
}
}
}
foreach(var n; new_class.NotificationsToBridge)
{
foreach (var n; new_class.NotificationsToBridge) {
print("IncomingBridge: ",n.NotificationType);
}
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)

View file

@ -102,6 +102,17 @@ var PropertySyncNotificationBase =
setValue:func(v,bridge,pos){var dv=emesary.TransferNorm.decode(v,length,pos);me[variable] = dv.value;setprop(bridge.PropertyRoot~property, me[variable]);return dv;},
});
}
new_class.addStringProperty = func(variable, property)
{
me[variable] = nil;
append(me._bridgeProperties,
{
getValue:func{return emesary.TransferString.encode(getprop(property) or 0);},
setValue:func(v,bridge,pos){var dv=emesary.TransferString.decode(v,pos);me[variable] = dv.value;setprop(bridge.PropertyRoot~property, me[variable]);return dv;},
});
}
new_class.bridgeProperties = func()
{
return me._bridgeProperties;
@ -161,6 +172,7 @@ var GeoEventNotification =
new_class.Name = _name;
new_class.SecondaryKind = _secondary_kind;
new_class.Position = geo.aircraft_position();
new_class.UniqueIndex = 0;
new_class.Heading = getprop("/orientation/heading");
new_class.u_fps = getprop("/velocities/uBody-fps");
@ -171,6 +183,9 @@ var GeoEventNotification =
new_class.RemoteCallsign = ""; # associated remote callsign.
new_class.Flags = 0; # 8 bits for whatever.
new_class.GetBridgeMessageNotificationTypeKey = func {
return new_class.NotificationType~"."~new_class.Ident~"."~new_class.UniqueIndex;
};
new_class.bridgeProperties = func
{
return