Board index FlightGear Development Nasal

Working with AI/Multiplayer properties

Nasal is the scripting language of FlightGear.

Working with AI/Multiplayer properties

Postby Algernon » Mon Nov 29, 2010 4:36 pm

I am about to exceed the limits of my Nasal with my current project, and could do with a bit of guidance.

I want to write scripts which can be bound to keys or joystick buttons to cycle through AI/Multiplayer models and assign them as targets to either the weapons system (in the future) or the target-tracking autopilot (a modification of the script that comes with FG). So I think I need four functions, one to cycle forward through the model list, one to cycle backwards, one to assign the preselected model to the autopilot and one to assign it to the weapons system. This would then fit nicely onto a hat switch.

Could somebody suggest the best way to get Nasal to do this efficiently, so I can look into the processes and figure them out, thus advancing my experience with scripting - I would be most grateful :)
Algernon
FGUK - A FlightGear community in the United Kingdom and Republic of Ireland
User avatar
Algernon
 
Posts: 498
Joined: Sun Jun 27, 2010 3:55 pm
Callsign: G-ALGY
Version: 3.0
OS: W7U

Re: Working with AI/Multiplayer properties

Postby Hooray » Mon Nov 29, 2010 4:52 pm

Enable AI and/or MP.

Then, just open the property browser, go to /ai/models - that's where all models are listed.
The total count of instantiated models is in /ai/models/count - beginning at 0.

Keep in mind that even non-aircraft models may be listed there, such as e.g. the carrier. So if you are only interested in certain types of AI models, you need to do some further checking.

To access a certain model, you add the index number to the path - for example /ai/models/aircraft[1] or /ai/models/aircraft[2]

All models have their own sub branches, such as "orientation", "position" or "velocities" - which contain the corresponding values.

When you use the property browser to navigate the property tree, you can see the full path to the corresponding property at the top of the browser.

Iterating through the list of AI/MP vehicles is then just a matter of changing the index number and getting out the corresponding position for the vehicle.
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 !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11340
Joined: Tue Mar 25, 2008 8:40 am

Re: Working with AI/Multiplayer properties

Postby Algernon » Mon Nov 29, 2010 5:10 pm

Hooray wrote:Iterating through the list of AI/MP vehicles is then just a matter of changing the index number and getting out the corresponding position for the vehicle.

Yep, that's the bit I need to know about in Nasal - I assume there is an efficient way of doing this, for instance, the function which cycles forward through the list needs to know the current index number, so it can check the next indexed property to see if the model is there, and if not, jump back to the beginning of the list.

I think I can write the Nasal if I can find out how to extract the index number from a property as a variable to be used in the script.

Thanks for getting back to me. :)
Algernon
FGUK - A FlightGear community in the United Kingdom and Republic of Ireland
User avatar
Algernon
 
Posts: 498
Joined: Sun Jun 27, 2010 3:55 pm
Callsign: G-ALGY
Version: 3.0
OS: W7U

Re: Working with AI/Multiplayer properties

Postby ot-666 » Mon Nov 29, 2010 6:30 pm

If you come up with a solution fort his, I could use this for a project to make an automated jet way.

Oliver
Callsign: ot-666
Working on LOWI and other stuff - Custom Scenery Overlay Repo: http://gitorious.org/fgfs-custom-scenery/custom-scenery-overlay/
VMX22 - Osprey... sometimes in 2014
ot-666
 
Posts: 746
Joined: Sun Nov 08, 2009 5:14 pm
Location: Germany, Konstanz
Callsign: ot-666
IRC name: ot666
Version: GIT
OS: win7 64bit

Re: Working with AI/Multiplayer properties

Postby Hooray » Mon Nov 29, 2010 8:29 pm

Actually, the code to do this is already readily available in FlightGear.
$FG_ROOT/tanker.nas is a good demonstration for code that iterates over the AI properties.
Another good example is the multiplayer pilot list, which also iterates over the property tree.
You only need to combine snippets from these two files to come up with what you need.

Iteration is just a matter of using a loop to examine the property tree.

For example, to get a list of all aircraft entries in /ai/models and dump it to the console, use something like this:
Code: Select all
foreach(var a; props.globals.getNode("/ai/models").getChildren("aircraft"))
  props.dump ( a );


Obviously, you can repeat this using settimer() - and instead of dumping all nodes to the console, you could just as well process them in a different way.

Just post the code that you got so far, and we can tell you what you need to do differently.
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 !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11340
Joined: Tue Mar 25, 2008 8:40 am

Re: Working with AI/Multiplayer properties

Postby Algernon » Tue Nov 30, 2010 12:20 am

Hooray wrote:Just post the code that you got so far, and we can tell you what you need to do differently.

That'd be perfect. I'll hopefully have a first attempt - or at least part of one - written tomorrow evening. Cheers :)
Algernon
FGUK - A FlightGear community in the United Kingdom and Republic of Ireland
User avatar
Algernon
 
Posts: 498
Joined: Sun Jun 27, 2010 3:55 pm
Callsign: G-ALGY
Version: 3.0
OS: W7U

Re: Working with AI/Multiplayer properties

Postby Hooray » Tue Nov 30, 2010 8:28 pm

getting started should not pose a real problem at all, even if you don't understand everything in the $FG_ROOT/Nasal directory, or the tanker.nas example - what I posted previously is all you need to know to get started, to get a list of all "aircraft" entries under /ai/models, just use a call like this:

Code: Select all
var list= props.globals.getNode("/ai/models").getChildren("aircraft");


You can get the size of the list by using the size() function:
Code: Select all
size(list);


Each element then contains a complete props node object for the corresponding aircraft.
You can access each element by using the array notation:

Code: Select all
var callsign=list[0].getNode("callsign").getValue();
print (callsign);


Where 0 is the index of the list.
So if you want to do this in a loop, you can use foreach or use a conventional for loop and a size() call.

Thus, all properties can be easily accessed by using the helpers provided in $FG_ROOT/Nasal/props.nas http://gitorious.org/fg/fgdata/blobs/ma ... /props.nas

To see what properties are commonly available, just browse the property tree as previously suggested already.

Each valid aircraft node then gets its own sub trees for position, orientation, velocities respectively.

I would suggest to start with a very simple function for just dumping the callsign of each AI aircraft model to the console, accessing other properties should then be fairly simple actually.

Here is something to get you started:
Code: Select all
##
# ai_dumper.nas (save in $FG_ROOT/Nasal)
#

var dumper = func {
  foreach (var ai_aircraft; props.globals.getNode("/ai/models").getChildren("aircraft"))
  {
     print( ai_aircraft.getNode("callsign") );
  }
 settimer(dumper,1); # call this function again with a 1 second delay
}

_setlistener("/sim/signals/nasal-dir-initialized", dumper); # register the dumper function to be invoked




Let us know if you have specific questions
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 !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11340
Joined: Tue Mar 25, 2008 8:40 am

Re: Working with AI/Multiplayer properties

Postby Hooray » Tue Nov 30, 2010 11:58 pm

Code: Select all
##
# ai_dumper.nas - save in $FG_ROOT/Nasal
#
# purpose: iterates over /ai/models/aircraft and calls a handler routine for each valid entry, using a configurable update interval
#

var update_interval_secs = 2;

# some helpers:

# register: register a callback to be invoked once the Nasal directory is initialized
var register= func(handler) _setlistener("/sim/signals/nasal-dir-initialized", handler);

# repeat: register a timer to call a function again after a given timeout
var get_caller = func caller(2)[1];
var repeat = func(delay_secs=1) settimer(get_caller(), delay_secs);

# this function will be called for each instance
var process_ai_instance = func(aircraft) {
 var callsign = aircraft.getNode("callsign").getValue();
 print("Processing aircraft with callsign:", callsign);
}


var processAI = func {
 foreach(var aircraft; props.globals.getNode("/ai/models").getChildren("aircraft"))
 {
  process_ai_instance( aircraft ) ;
 }

 repeat(update_interval_secs); # repeat this function (one second delay by default)
}

register(processAI);
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 !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11340
Joined: Tue Mar 25, 2008 8:40 am

Re: Working with AI/Multiplayer properties

Postby Algernon » Wed Dec 01, 2010 11:55 am

Thank you very much, Hooray, I have a clearer understanding now (although the second block of code is proving slightly harder to follow). I was pretty tired when I read it last night, though, so am about to give it another thorough read.

One specific question I could ask at this point - having printed the property to the console, I would like to set a property, or in fact selected properties from the 'aircraft' child into a new property branch "/systems/AIS/targets/target[0]" and so on for each index. I could then use setlisteners on /ai/models/model-added and /ai/models/model-removed to call the function whenever the MP environment changes. I'm guessing the good old setprop won't be powerful enough - do I use something like props.globals.setValues?
Algernon
FGUK - A FlightGear community in the United Kingdom and Republic of Ireland
User avatar
Algernon
 
Posts: 498
Joined: Sun Jun 27, 2010 3:55 pm
Callsign: G-ALGY
Version: 3.0
OS: W7U

Re: Working with AI/Multiplayer properties

Postby Hooray » Wed Dec 01, 2010 1:04 pm

Algernon wrote:Thank you very much, Hooray, I have a clearer understanding now (although the second block of code is proving slightly harder to follow). I was pretty tired when I read it last night, though, so am about to give it another thorough read.

The code is only slightly more complex, I would suggest to disregard the "helper" functions at the beginning of the code, they are just meant to be convenience wrappers to make the rest of the code more readable - and understanding those isn't really needed to understand the rest of the code.

One specific question I could ask at this point - having printed the property to the console, I would like to set a property, or in fact selected properties from the 'aircraft' child into a new property branch "/systems/AIS/targets/target[0]" and so on for each index. I could then use setlisteners on /ai/models/model-added and /ai/models/model-removed to call the function whenever the MP environment changes.


There are several ways for doing this.
You could add an "index" (count) property to your /systems/AIS/ node - so that the foreach loop can pick up the index and update the AIS.
Then, you could simply write the properties to /systems/AIS/target[n]


I'm guessing the good old setprop won't be powerful enough - do I use something like props.globals.setValues?


The property tree doesn't care if it is being accessed using setprop/getprop or a props object.

Obviously you can also use a props node "object", but both methods will work.
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 !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11340
Joined: Tue Mar 25, 2008 8:40 am

Re: Working with AI/Multiplayer properties

Postby Algernon » Wed Dec 01, 2010 1:23 pm

Hooray wrote:
You could add an "index" (count) property to your /systems/AIS/ node - so that the foreach loop can pick up the index and update the AIS.
Then, you could simply write the properties to /systems/AIS/target[n]


That's ideal, as I have already decided to identify multiplayer/AI aircraft/carriers by their property index instead of the ID property, which is often unusual. Something like:

Code: Select all
var register = func {
   foreach (var ai_aircraft; props.globals.getNode("/ai/models").getChildren("aircraft")) {
      var callsign = getprop( ai_aircraft.getNode("callsign") );
     var n = getprop( ai_aircraft.getIndex );
     setprop("/systems/AIS/targets/target[n]/callsign", callsign);
          setprop("/systems/AIS/targets/target[n]/index", n);
   }
}

# Update AIS with current situation
setlistener("/ai/models/model-added", register;)
setlistener("/ai/models/model-removed", register);


I'm certain that the syntax will be wrong, but is that the general idea?
Algernon
FGUK - A FlightGear community in the United Kingdom and Republic of Ireland
User avatar
Algernon
 
Posts: 498
Joined: Sun Jun 27, 2010 3:55 pm
Callsign: G-ALGY
Version: 3.0
OS: W7U

Re: Working with AI/Multiplayer properties

Postby Hooray » Wed Dec 01, 2010 2:39 pm

just some quick notes while looking at your pseudo code:
  • ai_aircraft would already be a "props" node object, see $FG_ROOT/Nasal/props.nas, thus there is no need to wrap it in another getprop call, instead you directly call the "getIndex" method
  • a method call is basically just another function call (specific to the object), so you need to add an argument list to the function call, even if it is empty (if you don't do that, you are not invoking the function but rather assigning the getIndex method itself to the variable):
    Code: Select all
    var n = ai_aircraft.getIndex();
  • regarding your usage of setprop: obviously you need to replace 'n' with the actual index number in these calls, the following piece of code will assemble the property string from all variables passed in, minus the last argument (which is the value to be set):
    Code: Select all
    setprop("/systems/AIS/targets/target[",n,"]/callsign", callsign);
  • you can also use Nasal's string concatenation syntax for this, where you use the tilde character (~) to assemble strings:
    Code: Select all
    var foo = "hello" ~ " world" ~ " :-)";
    print (foo);
    This can also be directly used in function calls:
    Code: Select all
    print ("hello" ~ "world");
    setprop("/foo/bar/" ~ "value", 1);

Regarding your listeners, you will probably not just want to update your AIS property whenever models are added or removed, but also at a configurable update rate (e.g. at 1-5 hz) - this is so that you can recompute positions, bearings and trajectories (thinking in terms of a weapons systems here), timers can be used for this, like I previously illustrated.
When you need to read many properties, polling may be a better option than listeners - so that you could update properties at framerate.

Obviously, if you want this to work for non-aircraft, too (like carriers), you don't just need to process the /ai/models/aircraft[n] nodes, but also the ones for /ai/models/carrier[n].
My suggestion is however to first get this working for one thing, enhancing things later on is easier once everything is working already.
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 !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11340
Joined: Tue Mar 25, 2008 8:40 am

Re: Working with AI/Multiplayer properties

Postby Algernon » Wed Dec 01, 2010 5:02 pm

That all makes sense to me now - I'll be spending some time in the hangar after work tonight, hopefully I'll get it working now. Thanks for all your time on this.

Regarding your listeners, you will probably not just want to update your AIS property whenever models are added or removed, but also at a configurable update rate (e.g. at 1-5 hz) - this is so that you can recompute positions, bearings and trajectories (thinking in terms of a weapons systems here), timers can be used for this, like I previously illustrated.


My thinking here is that the AIS may eventually do more complicated calculations, but at this stage, it just takes care of the user input involved in pre-selecting a target and then allocating it either to the weapons system, later on, or the autopilot, my current concern. The AIS/targets/target[n] properties are just for identification purposes at this stage, holding basic information including the ai/models/ root of each target and allowing those properties to be copied into a branch such as /AIS/targets/preselect when the cycle-forward and cycle-back functions are called. Two further functions will then allocate the preselection to either weapons or tracking autopilot, both of which will pull more detailed information from the models branch and will need to update much faster, so timers will be the natural choice for them.
Algernon
FGUK - A FlightGear community in the United Kingdom and Republic of Ireland
User avatar
Algernon
 
Posts: 498
Joined: Sun Jun 27, 2010 3:55 pm
Callsign: G-ALGY
Version: 3.0
OS: W7U

Re: Working with AI/Multiplayer properties

Postby Hooray » Wed Dec 01, 2010 6:05 pm

That all makes sense to me now - I'll be spending some time in the hangar after work tonight, hopefully I'll get it working now. Thanks for all your time on this.

Let me know if you have any further questions.

To be honest, I think this thread has already become pretty informative - so it would be great if we could turn your project into a "howto" tutorial for the wiki, specifically about working with AI/MP properties in Nasal.

We could probably copy/paste a lot of stuff from this thread "as is". So if you have any other questions or ideas, my suggestion would be that we move this over to the wiki eventually.
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 !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11340
Joined: Tue Mar 25, 2008 8:40 am

Re: Working with AI/Multiplayer properties

Postby Algernon » Thu Dec 02, 2010 1:00 am

I'd be more than happy to transmute this discussion into a Howto, as I think Nasal is one of those big stumbling blocks for would-be aircraft developers without a good head for code (myself included). Hopefully the Typhoon AIS system will require some more basic, condition based code (if, else, that sort of thing) which could provide a "first step on the ladder". I'm definitely keen :)
Algernon
FGUK - A FlightGear community in the United Kingdom and Republic of Ireland
User avatar
Algernon
 
Posts: 498
Joined: Sun Jun 27, 2010 3:55 pm
Callsign: G-ALGY
Version: 3.0
OS: W7U

Next

Return to Nasal

Who is online

Users browsing this forum: No registered users and 0 guests