see also https://wiki.flightgear.org/Nasal_Optimisation#Emesary_real_time_executive
Using a scheduler to manage the invocation of Nasal modules provides a more predictable and efficient way to replace update loops and also optimises property tree access to one access per property per frame by using a hash that contains the property values.
There is a default global object created (emexec.ExecScheduler) that should be used in most circumstances.
Each Nasal object simply has to have an update(notification) method. This will be called on a schedule and the notification will contain any requested property values.
The exec will also adapt the rate to the frame rate; with a maximum of 50hz, but this will drop to as low as 4hz based on the frame rate to optimise workload.
The modules will be called in the order in which they were added; so it is possible to have modules in the right sequence (i.e. an earlier module calculates values that are used by a later module)
A simple example is below. The VSD_device has the update method
------
# list of prooperties to include in the notification hash
var properties_to_monitor = {
OrientationHeadingDeg : "orientation/heading-deg",
OrientationPitchDeg : "orientation/pitch-deg",
OrientationRollDeg : "orientation/roll-deg",
GroundspeedKts : "velocities/groundspeed-kt",
radar2_range : "instrumentation/radar/radar2-range",
target_display : "sim/model/f15/instrumentation/radar-awg-9/hud/target-display",
vc_kts : "instrumentation/airspeed-indicator/true-speed-kt",
};
# create Canvas based device (that has an update method)
VSD = VSD_Device.new(designation, textureImage, notification.Ident, root_node);
# register with the exec;
# - ident
# - proprties to include in notification hash
# - object (with an .update(notification) method
# - rate (4 = 1/4)
emexec.ExecModule.register("F15-VSD", properties_to_monitor, VSD, 4);
Spray density realism improved by using a curve for the density and permitting the trigger to be changed (default 0.2)
Touchdown smoke trigerred by WoW changing using the velocity as a factor and then using a low pass filter on this to fade out the smoke. This results in smoke for a brief period that appears to be more realistic. F-14 example: https://i.imgur.com/FkwgoYV.gifv
Uses new property /sim/controls/brake-cancels-parking-brake.
Default is true; it is expected that some aircraft (e.g. p51d) will set this to
false so they can implement their own brake/parking-brake interaction.
Should address bug 2589.
- All non-ALS Effects have been removed (except generic ones from model-default and terrain-default).
- The rendering dialog has been reworked to accomodate the changes.
- All necessary properties have been added to graphics-properties.xml
- Five graphics presets have been added: Minimal, Low, Medium, High and Ultra.
- Some unused properties have been removed from defaults.xml
This view is like Helicopter View except that it does not change the view
heading to match the aircraft, which makes it work much better for vertical
flight, e.g. with the shuttle.
The new view is disabled by default.
Nasal/view.nas
contains the new view config.
defaults.xml:
Added view 8 to list of views for which we default to Helicopter view's
target offsets (so that they look at the centre of the aircraft).
Patch from Michael Danilov: when auto-hide of the menubar is enabled,
tigger the hide when we enter (via tab) mouse-flight-controls or
mouse-look mode, since the menubar is not accessible in these modes
anyway.
Fix the created binding for toggle buttons.
Add autopilotDisconnect helper to controls.nas, and expose the new
function in the joystick configurator dialog.
Fixes from Henning Stahlke
Previously props.condition threw an error if any of the
properties in the condition were not defines. This is
contrary to the behaviour of SGCondition, which it seeks
to emulate, which considers such undefined properties as
having the value 0.0.
Now this is the case.
This function only appears to be used by tutorials.nas,
where this behaviour was seen as discrepancy between
the checklist <condition> behaviour and the tutorial
<condition> behaviour.
See https://sourceforge.net/p/flightgear/codetickets/2394/?page=1
Use (!passive) instead of (passive == 0), so that passive == nil is treated as
0.
E.g. this allows keyboard control of autopilot target speed, heading and
altitude in harrier-gr3.
This change automatically changes the view direction to look
at a <marker> if any is defined for a checklist item or tutorial
step.
Both the tutorial and checklist features support a <marker> element
which can be used by an aircraft developer to display a magenta
circle around an item of interest (typically a control in the
cockpit).
Previously aircraft developers had to add a <view> element to move
the viewpoint to look at the marker, while users of checklists had
to look for the marker manually.
Now:
- For checklists, pressing the "?" button on a checklist will pan the viewpoint
to the marker.
- For tutorials, if there is not a <view> element defined for a
tutorial step, the view will automatically pan to the marker.
the partition processor can now either process a certain number of items per frame, or spend a certain amount of time processing items.
The two options work together - so typically you'd pick a sensible amount of items to process per frame and then maybe also set a maximum amount of time per frame to be sure.
Using the time limit option will take slightly more CPU - but can still be a net benefit
Previously valid SVG strings such as
m 547.56916,962.17731 c 10e-6,25.66886
M831,144.861c-0.236,0.087-0.423,0.255-0.629,
would fail to parse.
Fix by Henning STALHKE
- Transfer encoding rewritten to handle negative numbers properly and fix scaling.
- Change the "no receive method" to be just a warning as it is unwise rather than
being wrong.
Emesary MP bridge fixes from Nikolai
OutgoingBridge:
- When transmitting queue, make sure transmitted
messages cannot remain in the queue when not completely emptied, and
thus be sent again, and eventually fill up the queue.
- Also allow smaller messages to sent even though there was not room for
a larger message (the removal of the 'break' command).
- To prevent coding the same message again with the 'break' removed,
store an already coded string that was rejected due to too little room
inside the message so when there is room for it, it was coded only
once.
- Stop recalculating MessageExpiryTime when there is no
room for a notification. If it has asked to expire after expire time,
let it expire.
IncomingBridge:
- Make sure listeners on emesary[x] properties are
removed when a mp aircraft is invalid, otherwise a hidden bridge will
sit in background and process same notifications a new bridge is
already processing.
- Change order of setting IncomingMessageIndex to ease
debugging in reciever.
- Since a bridge class can handle multiple emesary
properties on same aircraft, use a vector per aircraft to store the
bridge instances in, to make sure Remove can be called on all
instances listening to same aircraft.
The partition processor is a simple class that allows lists of data to be processed in chunks per invocation. It is designed to minimise per frame processing whilst keeping the code simple and the performance acceptable.
test code (use with F-14):
var pptest = func{
var xx= frame_utils.PartitionProcessor.new("TEST", 6);
var obj = {}; # just for testing
for (ii=0;ii<5;ii+=1) {
xx.process(obj, awg_9.tgts_list,
func(pp, obj, data){
print("init");
obj.designated = -1;
obj.search = "Nimitz";
obj.completed = 0;
}
,
func(pp, obj, u){
printf("%-5d : %s",pp.data_index, u.Callsign.getValue());
if (u.Callsign.getValue() == obj.search)
obj.designated = pp.data_index;
return 1;
},
func(pp, obj, data)
{
obj.completed = 1;
printf("Completed: %s = %d\n", obj.search, obj.designated);
}
);
if (obj.completed)
break;
}
if (!obj.completed)
print("partial list processed");
}
pptest();