Board index FlightGear Development New features

New Feature: Addon - "API"

Discussion and requests for new features. Please note that FlightGear developers are volunteers and may or may not be able to consider these requests.

New Feature: Addon - "API"

Postby Torsten » Tue Jul 18, 2017 11:03 am

Hi,

we now have a simple API to add addons to FlightGear without the need to mess around with FGData/Nasal or FGHome/Nasal directories.
FlightGear now accepts the command line switch --addon=/path/to/some/addon (note: command line switch is just that: a command line switch - not an option to be entered into the launcher).

fgfs (through options.cxx) takes care of
- creating a property under /addons/addon[n]/path=/path/to/some/addon
- adding /path/to/some/addon/config.xml as a config file (same as --config=/path/to/some/addon/config.xml)
- adding /path/to/some/addon to the list of allowed directories (same as --fg-aircraft=/path/to/some/addon)

The addon may be installed anywhere on your hard disk and it needs at least two files:
* config.xml - a standard PropertyList to be used to populate or modify the property tree. (Same as to be used in --config=foo.xml)
* main.nas - the Nasal hook for the logic. This file needs a function called main() which will be called from the global addon initializer (FGData/addons.nas)

It is pretty simple but does it's job nicely with our two addons we currently have in FGAddon (ATCChatter and SpokenATC).

There is a very simple Skeleton addon available to be used as a boilerplate here: https://sourceforge.net/p/flightgear/fg ... /Skeleton/

As always: feedback is much appreciated.

Torsten
flightgear.org - where development happens.
User avatar
Torsten
 
Posts: 598
Joined: Fri Feb 01, 2008 9:22 pm
Location: near Hamburg, Germany
Callsign: offline
Version: next
OS: Linux

Re: New Feature: Addon - "API"

Postby Hooray » Tue Jul 18, 2017 7:34 pm

I haven't looked at any of your code, but this is something that a number of folks have contemplated to do over the years - and one of the key things to support would be some kind of versioning scheme - possibly in conjunction with using the package manager to easily install/remove/manage such "addons".

I think that FGCamera would make for an excellent "testbed" to see how complete the current framework really is.

EDIT: regarding the loader script, you may also want wrap io.load_nasal() in a call so that you can do error handling (e.g. showing errors in the console or a message box), that should be really helpful for people prototyping/testing their addons
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
Nasal | Projects | Core development |
Programming resources
Hooray
 
Posts: 10508
Joined: Tue Mar 25, 2008 8:40 am

Re: New Feature: Addon - "API"

Postby Torsten » Tue Jul 18, 2017 8:47 pm

Hooray wrote in Tue Jul 18, 2017 7:34 pm:I think that FGCamera would make for an excellent "testbed" to see how complete the current framework really is.

Challenge accepted. What's the current license state of FGCamera? I found a statement here in the forum that it is "license free". I need it to be GPL (compatible).

Hooray wrote in Tue Jul 18, 2017 7:34 pm:EDIT: regarding the loader script, you may also want wrap io.load_nasal() in a call so that you can do error handling (e.g. showing errors in the console or a message box), that should be really helpful for people prototyping/testing their addons

If you could post a patch or a code snippet, that would be helpful.
flightgear.org - where development happens.
User avatar
Torsten
 
Posts: 598
Joined: Fri Feb 01, 2008 9:22 pm
Location: near Hamburg, Germany
Callsign: offline
Version: next
OS: Linux

Re: New Feature: Addon - "API"

Postby Hooray » Tue Jul 18, 2017 9:01 pm

Don't know about the license, but Marius_A stated on several ocassions that he was hoping for it to be included in fgdata some day (IIRC), which would seem to suggest that it is indeed GPL.

http://wiki.flightgear.org/Canvas_MessageBox
Image


untested pseudo code:
Code: Select all
var path ="/foo/bar/baz";
call(io.load_nasal, [path], nil, nil, var err=[]);

# the error vector is non-empty, so build an error string
if (size(err)) {
var error_string = "";

foreach(var e; err) {
error_string ~=e;
}  # foreach

# show message box (could also print to the console or use a property to be shown in Phi/Qt etc .)
canvas.MessageBox.warning(
    "Error loading addon",
    error_string,
    func(sel){
        if(sel != canvas.MessageBox.Ok) return;
}, # event handler for messageBox
    canvas.MessageBox.Ok |canvas.MessageBox.Cancel
); # MessageBox
} # if



Like I said, this is untested - but that's basically how it could work.

People wanting to write/port or update addons would surely appreciate a way to see proper parse errors, without having to exit/restart fgfs.
And we can accomplish that fairly easily.
Also, looking at some of the other addons floating around here, one of the most common things that people tend to add is some form of "changelog" - that could be a tag with a version number.
And for the sake of completeness, it may be nice to also support some kind of <authors> tag that could be shown by some kind of UI.
As a matter of fact, it would not be that difficult to load/unload (start/suspend and resume) such addons at runtime, using a little UI.

Overall, I really like the idea - we've seen countless of "addon", "plugins" and "modding" discussions around here, and I would suggest to view this as a great opportunity to leverage tons of community contributions that may otherwise not show up in fgdata at all.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
Nasal | Projects | Core development |
Programming resources
Hooray
 
Posts: 10508
Joined: Tue Mar 25, 2008 8:40 am

Re: New Feature: Addon - "API"

Postby CaptB » Wed Jul 19, 2017 7:08 am

This is very good, thanks.
CaptB
 
Posts: 377
Joined: Thu May 23, 2013 6:36 pm
Callsign: EKCH_AP
IRC name: CAPTB
Version: 2016.1
OS: Kubuntu, Win7 64

Re: New Feature: Addon - "API"

Postby daweed » Wed Jul 19, 2017 10:45 am

Hello Torsten,

i am not sure this can fit to my project, but will ask.
For the FG Interface, in some case (some plane) it need to load some extra "nasal" function and create some new properties (/fgint branch in propertries tree), but actually, i use the aircraft directory where i add a fgint.nas and a fgint.xml files.
Does this feature allow me to "externalize" theese files outside of the aircraft directory to make them more "general" .?
Nasal and xml files are actually loaded from the -set.xml file

Regards
----------------------------------------
Linux Mint 18.2
AMD FX 4300 Quad-Core Black Edition
8 Go RAM
GeForce GTX 750 Ti
----------------------------------------
FG Interface
Lyon Saint Exupery Scenery
daweed
 
Posts: 230
Joined: Thu Dec 11, 2014 10:45 am
Location: LFKP LFLL
Callsign: daweed
Version: FG 2016.3
OS: Linux Mint 17.2

Re: New Feature: Addon - "API"

Postby Torsten » Wed Jul 19, 2017 11:28 am

As this API does nothing more than loading a overlay XML into the property tree and starts a well known Nasal function, the answer to your question is probably "yes".

I am not so sure if aircraft specific addons really is good design, though.
flightgear.org - where development happens.
User avatar
Torsten
 
Posts: 598
Joined: Fri Feb 01, 2008 9:22 pm
Location: near Hamburg, Germany
Callsign: offline
Version: next
OS: Linux

Re: New Feature: Addon - "API"

Postby daweed » Wed Jul 19, 2017 11:40 am

Ok, i will give a try, thanks.
I don't know how to handle some case as like in airbus series. FCU for example use lot's of nasal code executed when acting on a 3d sufrace (Nasal function are directly binded in the xml file on the 3d object).
=> In this case i didn't find any other way that to create somes properties that exactly doing the same thing (trigger nasal code execution) when receiving data from interface. Updating direcly for example the heading property will not execute the nasal code in the original file, as the code is binded on the 3d object.

I you smarter solution, or if way of think is wrong, my hears are open :)
----------------------------------------
Linux Mint 18.2
AMD FX 4300 Quad-Core Black Edition
8 Go RAM
GeForce GTX 750 Ti
----------------------------------------
FG Interface
Lyon Saint Exupery Scenery
daweed
 
Posts: 230
Joined: Thu Dec 11, 2014 10:45 am
Location: LFKP LFLL
Callsign: daweed
Version: FG 2016.3
OS: Linux Mint 17.2

Re: New Feature: Addon - "API"

Postby Thorsten » Wed Jul 19, 2017 11:51 am

Add it to the aircraft itself.

Or, if it's a general instrument usable for more aircraft, make a merge request for FGData to get it into Aircraft/Generic.

I can't really see the use case of an addon to an aircraft (unless it's a non-GPL addon, in which case we won't host it anyway).
Thorsten
 
Posts: 8566
Joined: Mon Nov 02, 2009 8:33 am

Re: New Feature: Addon - "API"

Postby daweed » Wed Jul 19, 2017 7:53 pm

For example, on airbus A330 series, when turning the Heading coder on fcu, 2 things are made :

--> A heading property is update

--> A nasal function is executed (bind style <command>Nasal</command>)

Code: Select all
<animation>
      <type>knob</type>
      <object-name>hdg-sel</object-name>
      <drag-direction>vertical</drag-direction>
      <action>
         <binding>
            <command>property-adjust</command>
            <property>/flight-management/fcu-values/hdg</property>
            <factor>-1</factor>
            <min>0</min>
            <max>359</max>
            <wrap>true</wrap>
            <condition>
               <not>
                  <property>aircraft-config/saved/fcu/shift-to-rotate</property>
               </not>
            </condition>
         </binding>
         <binding>
            <command>nasal</command>
            <script>
               var hdg = getprop('/flight-management/fcu-values/hdg');
               setprop('autopilot/settings/heading-bug-deg', hdg);
               flightdeck.fcu.knob_rotated('hdg');
            </script>
            <condition>
               <not>
                  <property>aircraft-config/saved/fcu/shift-to-rotate</property>
               </not>
            </condition>
         </binding>
      </action>
      <shift-action>
         <binding>
            <command>property-adjust</command>
            <property>/flight-management/fcu-values/hdg</property>
            <factor>-1</factor>
            <min>0</min>
            <max>359</max>
            <wrap>true</wrap>
            <condition>
               <property>aircraft-config/saved/fcu/shift-to-rotate</property>
            </condition>
         </binding>
         <binding>
            <command>nasal</command>
            <script>
               var hdg = getprop('/flight-management/fcu-values/hdg');
               setprop('autopilot/settings/heading-bug-deg', hdg);
               flightdeck.fcu.knob_rotated('hdg');
            </script>
            <condition>
               <property>aircraft-config/saved/fcu/shift-to-rotate</property>
            </condition>
         </binding>
      </shift-action>
      <shift-increase>
         <binding>
            <command>nasal</command>
            <script>
               flightdeck.fcu.knob_pushed('hdg');
            </script>
            <condition>
               <not>
                  <property>aircraft-config/saved/fcu/shift-to-rotate</property>
               </not>
            </condition>
         </binding>
      </shift-increase>
      <shift-decrease>
         <binding>
            <command>nasal</command>
            <script>
               flightdeck.fcu.knob_pulled('hdg');
            </script>
            <condition>
               <not>
                  <property>aircraft-config/saved/fcu/shift-to-rotate</property>
               </not>
            </condition>
         </binding>
      </shift-decrease>
      <increase>
         <binding>
            <command>nasal</command>
            <script>
               flightdeck.fcu.knob_pushed('hdg');
            </script>
            <condition>
               <property>aircraft-config/saved/fcu/shift-to-rotate</property>
            </condition>
         </binding>
      </increase>
      <decrease>
         <binding>
            <command>nasal</command>
            <script>
               flightdeck.fcu.knob_pulled('hdg');
            </script>
            <condition>
               <property>aircraft-config/saved/fcu/shift-to-rotate</property>
            </condition>
         </binding>
      </decrease>
      <hovered>
         <binding>
            <command>set-tooltip</command>
            <label>Drag: rotate, Shift+Drag: push/pull, Shift-Click: push, Shift-Alt-Click: pull</label>
            <tooltip-id>hdg-knob-tooltip</tooltip-id>
            <condition>
               <and>
                  <not>
                     <property>aircraft-config/saved/fcu/shift-to-rotate</property>
                  </not>
                  <not>
                     <property>aircraft-config/saved/fcu/disable-tooltips</property>
                  </not>
               </and>
            </condition>
         </binding>
         <binding>
            <command>set-tooltip</command>
            <label>Shift-Drag: rotate, Click: push, Alt-Click: pull</label>
            <tooltip-id>hdg-knob-tooltip</tooltip-id>
            <condition>
               <and>
                  <property>aircraft-config/saved/fcu/shift-to-rotate</property>
                  <not>
                     <property>aircraft-config/saved/fcu/disable-tooltips</property>
                  </not>
               </and>
            </condition>
         </binding>
      </hovered>
   </animation>


So i am using generic protocol to communicate with FG.
=> if i send data to update the property "/flight-management/fcu-values/hdg" as like it done by the first binding, ok that work, prop is update... but the nasal code (and so on the function flightdeck.fcu.knob_rotated('hdg') ) is not executed, as it's binded too to the 3d model (the knob)

So to make that fully working, i have added a prop hdg in a /fgint branch in the props tree, that the property that is update by the data received from interface ... and a listener on this prop to update the /flight-management/fcu-values/hdg prop and execute nasal each time data is received from interface.

=> you could tel me to update directly the /flight-management/fcu-values/hdg prop and use listener on this one, but this does not work, as AP update this property too ... and function for example should be executed ONLY if acting on the knob.

That's why i finally decide to implement a fgint branch for theese type of bind and props that just update a prop (with no nasal binded) are update directly.

I am open to other solution if exist, as i am not knowing all internal arcane of fg, there is maybe better solution.

Regards

PS I didn't made the FCU code of the airbus. I use the aircraft and participate to it dev only on the 3d aspect.
----------------------------------------
Linux Mint 18.2
AMD FX 4300 Quad-Core Black Edition
8 Go RAM
GeForce GTX 750 Ti
----------------------------------------
FG Interface
Lyon Saint Exupery Scenery
daweed
 
Posts: 230
Joined: Thu Dec 11, 2014 10:45 am
Location: LFKP LFLL
Callsign: daweed
Version: FG 2016.3
OS: Linux Mint 17.2

Re: New Feature: Addon - "API"

Postby Hooray » Fri Jul 21, 2017 4:24 pm

As always: feedback is much appreciated.

Looking at the fgcamera effort, and other "addon candidates" mentioned elsewhere, the addon API would probably benefit from having helpers to deal with some of the more common customization options, such as loading custom keyboard bindings, and especially adding items to the menubar, as well as registering addon specific UI dialogs.

Also, we may want to look at ThorstenB's submodule approach to provide a sane mechanism to load/unload addons at runtime (dynamically), and maybe add an API to suspend/resume an addon. For starters, this could be a skeleton of functions that need to be filled in (analogous to SGSubsystem), but registered as callbacks for listeners monitoring /sim/signals

Right now, we only have the main() function, so we could also look for equivalent pause/unpause and load/unload, suspend/resume helpers

The other thing we should take into consideration is that addons probably shouldn't by default use some of the more critical Nasal APIs from the globals namespace, but instead be provided with re-implementations of getprop()/setprop() and maketimer()/makelistener - so that these can be wrapped in a closure and automatically cleaned up when necessary (think suspending, reloading/restarting an addon).

Right now this is an incredibly messy situation for most Nasal scripts (think reset/re-init), but it would be fairly easy to address by requiring well-defined entry points to be specified serving as handlers to deal with such events (signals).

And if this thing takes off, we also need to add a new dialog showing the status of different addons (loaded/unloaded or disabled), akin to the help/about dialog.
And we could also provide a Nasal/Canvas dialog to dynamically reload addons from disk.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
Nasal | Projects | Core development |
Programming resources
Hooray
 
Posts: 10508
Joined: Tue Mar 25, 2008 8:40 am

Re: New Feature: Addon - "API"

Postby ThomasS » Wed Sep 13, 2017 5:11 am

In addition to adding Addon specific menu items to FGs menu bar, for my use case (making http://wiki.flightgear.org/Ground_Services an Addon) it would be nice to also load model files from the Addon location. Currently I need to copy these files into FG_ROOT/model during installation, which is no good solution for the same reasons why using addons is a good solution.

Are there any plans for extending the Addon mechanism in that direction?
ThomasS
 
Posts: 42
Joined: Sun Sep 11, 2016 1:21 pm
Location: West of EDDK
Version: 2016.3.1
OS: Linux,MacOS,Windows

Re: New Feature: Addon - "API"

Postby Thorsten » Wed Sep 13, 2017 5:27 am

Why would a Nasal command to load a model from any desired location not work?
Thorsten
 
Posts: 8566
Joined: Mon Nov 02, 2009 8:33 am

Re: New Feature: Addon - "API"

Postby ThomasS » Wed Sep 13, 2017 7:02 pm

Well, I have to admit I never tried this way because I just didn't expect it to be possible. In this case the Addon needs information about its own location, which I think is available from the property tree /addons/addon branch. So I'll check and give it a try.
ThomasS
 
Posts: 42
Joined: Sun Sep 11, 2016 1:21 pm
Location: West of EDDK
Version: 2016.3.1
OS: Linux,MacOS,Windows

Re: New Feature: Addon - "API"

Postby Hooray » Wed Sep 13, 2017 7:33 pm

there is a resource/lookup API to do this sort of thing, it should just work like Thorsten said - if in doubt, check the early "addon" related commits, where Thorsten is adding to the list of paths to be traversed when doing file lookups
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
Nasal | Projects | Core development |
Programming resources
Hooray
 
Posts: 10508
Joined: Tue Mar 25, 2008 8:40 am


Return to New features

Who is online

Users browsing this forum: No registered users and 4 guests