Modules.nas: Difference between revisions

no edit summary
No edit summary
Line 1: Line 1:
= Nasal runtime re-loadable modules =
= Nasal runtime re-loadable modules =
== Introduction and motivation ==
== Introduction and motivation ==
Nasal (Flightgears integrated scripting language) comes with a limited number of [[Nasal library|core functions]].  
Nasal (Flightgears integrated scripting language) comes with a limited number of [[Nasal library|core functions]].  
Line 10: Line 9:
For more information on how and when these files are loaded see [[Nasal Initialization]].
For more information on how and when these files are loaded see [[Nasal Initialization]].


== modules.nas ==
== Differences between add-ons and modules ==
In ''modules.nas'' the class ''Module'' is defined.
A module object holds information about the path and filename of the Nasal script and supports unloading and reloading the code at runtime
(e.g. without restarting Flightgear as a whole) by tracking some critical resources like [[Listeners|listeners]] and [[Timers|timers]].
 
Parts of this functionality were added to the [[Addons|addons]] manager earlier and have now been extracted to avoid code duplication.
 
{{caution|
Within a module {{code|setlistener()}} is overloaded and the default value for the 4th argument (runtime) is changed to 0, so the listener will run only if the property value has changed.
}}
=== Differences between add-ons and modules ===
While there are many similarities between add-ons and modules, some words on the differences:  
While there are many similarities between add-ons and modules, some words on the differences:  


Line 29: Line 18:
Add-ons are selected by the user before launching FlightGear, thus they may or may not be available at runtime.
Add-ons are selected by the user before launching FlightGear, thus they may or may not be available at runtime.


== Nasal modules ==
Reloadable modules are stored in subdirectories of FGDATA/Nasal/modules/ as these subdirectories will not be loaded automatically by Flightgear on start.
However, modules.nas will scan this directory to create a list of available modules (= list of subdirectories).
Each module correspondes to one subdirectory and the direcory name is also the module name.


A module must contain at least the file '''main.nas''' (default, other filename is possible)  
= HowTo / Examples =
First some examples, the API documentation follows below.
 
== Nasal modules in an aircraft (e.g. for development) ==
Nasal code for an aircraft is usually loaded by a XML declaration in the <aircraft>-set.xml file like this:
<syntaxhighlight lang="xml">
<PropertyList>
    <nasal>
        <foo> <!-- Nasal namespace foo -->
            <file>Nasal/foo.nas</file>
        </foo>
        <bar> <!-- Nasal namespace bar -->
            <file>Aircraft/Generic/foo.nas</file>
        </bar>
        <myAircraft>
            <file>Nasal/efis_module.nas</file>
        </myAircraft>
    </nasal>
</PropertyList>
</syntaxhighlight>
 
This is fine unless you are developing a Nasal subsystem for the aircraft and have to restart FlightGear every time you edit a few lines.
For this case you could consider to use the Module class (defined in FGDATA/Nasal/modules.nas) and make your code re-loadable at runtime,
which means you do not have to restart whole FlightGear just for a few lines of edited Nasal code.
 
'''Example Nasal/efis_module.nas:'''
<syntaxhighlight lang="nasal">
#-- load EFIS as reloadable module
var my_efis = modules.Module.new("myAircraft_EFIS"); # Module name
my_efis.setDebug(1); # 0=(mostly) silent; 1=print setlistener and maketimer calls to console; 2=print also each listener hit, be very careful with this!
my_efis.setFilePath(getprop("/sim/aircraft-dir")~"/Nasal/EFIS");
my_efis.setMainFile("myAircraft-efis.nas");
my_efis.load();
</syntaxhighlight>
 
Now add a menu item for easy reloading like this:
{{note|
The module name in the property path must match the name passed to modules.Module.new()
|margin=10px |width=50%}}
<syntaxhighlight lang="xml">
<menubar>
    <default>
        <menu n=100>
            <!-- normal aircraft menu -->
        </menu>
        <menu n=101>
            <label>Aircraft Development</label>
            <item>
                <label>Reload EFIS</label>
                <binding>
                    <command>property-assign</command>
                    <property>/nasal/modules/myAircraft_EFIS/reload</property>
                    <value>1</value>
                </binding>
            </item>
        </menu>
    </default>
</menubar>
</syntaxhighlight>
 
{{tip|
You can also call {{code| myAircraft.my_efis.reload();}} to trigger the reload. myAircraft is the namespace given in the <aircraft>-set.xml file, my_efis is the module object (see above).
|margin=10px |width=50%}}
 
= Structure of Nasal reloadable modules =
A module must contain at least the file '''main.nas''' (default, other filename is possible) and should contain the functions {{code|main()}} and {{code|unload()}}.


=== main() function ===
=== main() function ===
Line 50: Line 100:
# The name must contain at least one letter so it cannot be confused with a number
# The name must contain at least one letter so it cannot be confused with a number
# The name shall not match any existing .nas file or directory in FGDATA/Nasal to avoid namespace clashes
# The name shall not match any existing .nas file or directory in FGDATA/Nasal to avoid namespace clashes
{{note|
Reloadable modules shipped with FlightGear are stored in subdirectories of FGDATA/Nasal/modules/ as these subdirectories will not be loaded automatically by Flightgear on start.
However, modules.nas will scan this directory to create a list of available modules (= list of subdirectories).
Each module correspondes to one subdirectory and the direcory name is also the module name.
}}
= modules.nas =
In ''modules.nas'' the class ''Module'' is defined.
A module object holds information about the path and filename of the Nasal script and supports unloading and reloading the code at runtime
(e.g. without restarting Flightgear as a whole) by tracking some critical resources like [[Listeners|listeners]] and [[Timers|timers]].
{{note|Parts of this functionality were added to the [[Addons|addons]] manager earlier and have now been extracted to avoid code duplication.}}
{{caution| Within a module {{code|setlistener()}} is overloaded and the default value for the 4th argument (runtime) is changed to 0, so the listener will run only if the property value has changed.
}}


== library functions ==
== library functions ==
Line 153: Line 219:
var bar = foo.get("bar"); # get variable "bar" defined in FGDATA/Nasal/modules/foo/main.nas (or a file included by this file)
var bar = foo.get("bar"); # get variable "bar" defined in FGDATA/Nasal/modules/foo/main.nas (or a file included by this file)
}}
}}
= HowTo / Examples =
== Nasal modules in an aircraft (e.g. for development) ==
Nasal code for an aircraft is usually loaded by a XML declaration in the <aircraft>-set.xml file like this:
<syntaxhighlight lang="xml">
<PropertyList>
    <nasal>
        <foo> <!-- Nasal namespace foo -->
            <file>Nasal/foo.nas</file>
        </foo>
        <bar> <!-- Nasal namespace bar -->
            <file>Aircraft/Generic/foo.nas</file>
        </bar>
        <myAircraft>
            <file>Nasal/efis_module.nas</file>
        </myAircraft>
    </nasal>
</PropertyList>
</syntaxhighlight>
This is fine unless you are developing a Nasal subsystem for the aircraft and have to restart FlightGear every time you edit a few lines.
For this case you could consider to use the Module class (defined in FGDATA/Nasal/modules.nas) and make your code re-loadable at runtime,
which means you do not have to restart whole FlightGear just for a few lines of edited Nasal code.
'''Example Nasal/efis_module.nas:'''
<syntaxhighlight lang="nasal">
#-- load EFIS as reloadable module
var my_efis = modules.Module.new("myAircraft_EFIS"); # Module name
my_efis.setDebug(1); # 0=(mostly) silent; 1=print setlistener and maketimer calls to console; 2=print also each listener hit, be very careful with this!
my_efis.setFilePath(getprop("/sim/aircraft-dir")~"/Nasal/EFIS");
my_efis.setMainFile("myAircraft-efis.nas");
my_efis.load();
</syntaxhighlight>
Now add a menu item for easy reloading like this:
{{note|
The module name in the property path must match the name passed to modules.Module.new()
|margin=10px |width=50%}}
<syntaxhighlight lang="xml">
<menubar>
    <default>
        <menu n=100>
            <!-- normal aircraft menu -->
        </menu>
        <menu n=101>
            <label>Aircraft Development</label>
            <item>
                <label>Reload EFIS</label>
                <binding>
                    <command>property-assign</command>
                    <property>/nasal/modules/myAircraft_EFIS/reload</property>
                    <value>1</value>
                </binding>
            </item>
        </menu>
    </default>
</menubar>
</syntaxhighlight>
{{tip|
You can also call {{code| myAircraft.my_efis.reload();}} to trigger the reload. myAircraft is the namespace given in the <aircraft>-set.xml file, my_efis is the module object (see above).
|margin=10px |width=50%}}


= Existing modules =
= Existing modules =
246

edits