Experiment: NPC Non-AI ship

General discussion for players of Oolite.

Moderators: winston, another_commander

User avatar
hiran
Theorethicist
Posts: 2403
Joined: Fri Mar 26, 2021 1:39 pm
Location: a parallel world I created for myself. Some call it a singularity...

Experiment: NPC Non-AI ship

Post by hiran »

I'd like to run another experiment on Oolite.

Since I have control over the debug console, I am wondering whether I can spawn a ship at some position, then give it speed and turns to have it fly towards another position. Ideally I could see that ship flying by from my own ship.

So this ship would be a non player character (NPC), but at the same time not controlled by AI like so many other ships in Oolite.
Or would it make sense to have a minimal AI that could bring the ship to a given position/direction in given time so it would fly it's own bezier curve?

Any help here appreciated...
Sunshine - Moonlight - Good Times - Oolite
User avatar
hiran
Theorethicist
Posts: 2403
Joined: Fri Mar 26, 2021 1:39 pm
Location: a parallel world I created for myself. Some call it a singularity...

Re: Experiment: NPC Non-AI ship

Post by hiran »

It seems noone knows how this could be achieved.

That given, I will never be able to send events from a player controlling his local ship to some other Ooniverse to also move an avatar ship. Which means players will never see one another passing by.

So I will give up investigating in that direction.
Sunshine - Moonlight - Good Times - Oolite
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4830
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Experiment: NPC Non-AI ship

Post by phkb »

Giving a ship the null AI (oolite-nullAI.js) would make it unresponsive, allowing you to then do whatever you want with the ship programmatically. Although I haven't tested every function, so it might not work.
User avatar
hiran
Theorethicist
Posts: 2403
Joined: Fri Mar 26, 2021 1:39 pm
Location: a parallel world I created for myself. Some call it a singularity...

Re: Experiment: NPC Non-AI ship

Post by hiran »

phkb wrote: Fri Dec 17, 2021 11:39 am
Giving a ship the null AI (oolite-nullAI.js) would make it unresponsive, allowing you to then do whatever you want with the ship programmatically. Although I haven't tested every function, so it might not work.
That is half a solution, after all.
But how would one control the ship then? Especially via the debug console?

Or could it be feasible to have some AI that just beziers the ship to a given coordinate/heading/speed, and the cordinate/heading/speed triple would be injected via the debug console?
Sunshine - Moonlight - Good Times - Oolite
another_commander
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 6682
Joined: Wed Feb 28, 2007 7:54 am

Re: Experiment: NPC Non-AI ship

Post by another_commander »

Check ship.destination and ship.desiredSpeed JS properties, also PriorityAIController.prototype.behaviourApproachDestination in Resources/Scripts/oolite-priorityai.js.
User avatar
hiran
Theorethicist
Posts: 2403
Joined: Fri Mar 26, 2021 1:39 pm
Location: a parallel world I created for myself. Some call it a singularity...

Re: Experiment: NPC Non-AI ship

Post by hiran »

another_commander wrote: Fri Dec 17, 2021 2:24 pm
Check ship.destination and ship.desiredSpeed JS properties, also PriorityAIController.prototype.behaviourApproachDestination in Resources/Scripts/oolite-priorityai.js.
So how would this look as a complete example using the Debug Console?

How can a ship be spawned with the right controller?
How can the ship's position be set? How can direction, speed and destination coordinates be set?

Depending on the Oolite Debug Console communication performance we could estimate how many ships can be controlled this way in parallel.
Sunshine - Moonlight - Good Times - Oolite
User avatar
cim
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 4072
Joined: Fri Nov 11, 2011 6:19 pm

Re: Experiment: NPC Non-AI ship

Post by cim »

All ships have to have an AI - but it is possible for that AI to avoid using any of the in-built flight code whatsoever. You just have to combine a bunch of obscure features ... but then, you were going to have to do that anyway.

Start with https://wiki.alioth.net/index.php/Oolit ... ScriptedAI (and the neighbouring ScriptedAttack if you want it to be able to shoot too). A very basic JS AI can set that AI mode off (you probably don't even need the priority AI library) - or you can also call it from a simple plist AI if you prefer.

That lets you then control a ship's flight model and laser fire directly with a callback function as described at https://wiki.alioth.net/index.php/OXP_Scripted_AI - that callback can as well as returning the future flight parameters, also do all the usual things like setting position, firing ECM, etc. And of course the Debug Console can update suitable shipscript variables to tell the callback function what it should be doing.

Note: if you're using this for multiplayer, there'll be a discrepancy:
- the player will fire the laser when they think they're going to hit
- the ship under ScriptedAttack will fire when its AI thinks it's going to hit (based on its accuracy parameter)
So if you want to fire if and only if the player does, you may need to make use of a huge virtual invisible target in the right direction, so it always thinks it's going to hit, and then only use ScriptedAttack on the frames it should actually fire.

As far as a basic example (untested, but you can probably figure out the bugs) goes:
Ship script (just use a null AI script with this one):

Code: Select all

this.flightParameters = {};

this.shipSpawned = function()
{
  this.performScriptedAI();
}

this.scriptedAI = function(delta) 
{
   return this.flightParameters;  
}
Debug console:

Code: Select all

ship.script.flightParameters = { stickPitch: -0.2; desiredSpeed: this.ship.maxSpeed / 3; }
Ship starts off stationary, when you enter the debug console code it should start doing slow pitch loops.
User avatar
hiran
Theorethicist
Posts: 2403
Joined: Fri Mar 26, 2021 1:39 pm
Location: a parallel world I created for myself. Some call it a singularity...

Re: Experiment: NPC Non-AI ship

Post by hiran »

cim wrote: Mon Feb 28, 2022 9:17 pm
All ships have to have an AI - but it is possible for that AI to avoid using any of the in-built flight code whatsoever. You just have to combine a bunch of obscure features ... but then, you were going to have to do that anyway.

Start with https://wiki.alioth.net/index.php/Oolit ... ScriptedAI (and the neighbouring ScriptedAttack if you want it to be able to shoot too). A very basic JS AI can set that AI mode off (you probably don't even need the priority AI library) - or you can also call it from a simple plist AI if you prefer.

That lets you then control a ship's flight model and laser fire directly with a callback function as described at https://wiki.alioth.net/index.php/OXP_Scripted_AI - that callback can as well as returning the future flight parameters, also do all the usual things like setting position, firing ECM, etc. And of course the Debug Console can update suitable shipscript variables to tell the callback function what it should be doing.

Note: if you're using this for multiplayer, there'll be a discrepancy:
- the player will fire the laser when they think they're going to hit
- the ship under ScriptedAttack will fire when its AI thinks it's going to hit (based on its accuracy parameter)
So if you want to fire if and only if the player does, you may need to make use of a huge virtual invisible target in the right direction, so it always thinks it's going to hit, and then only use ScriptedAttack on the frames it should actually fire.

As far as a basic example (untested, but you can probably figure out the bugs) goes:
Ship script (just use a null AI script with this one):

Code: Select all

this.flightParameters = {};

this.shipSpawned = function()
{
  this.performScriptedAI();
}

this.scriptedAI = function(delta) 
{
   return this.flightParameters;  
}
Debug console:

Code: Select all

ship.script.flightParameters = { stickPitch: -0.2; desiredSpeed: this.ship.maxSpeed / 3; }
Ship starts off stationary, when you enter the debug console code it should start doing slow pitch loops.
Thank you for that response, but I may not yet be up to speed.

What I understand so far is I should create my own scripted AI. This is probably a file that goes into some OXP. I am wondering why your description sounds just so much different from https://wiki.alioth.net/index.php/OXP_howto_AI, which talks about state machines.

Next, how would I spawn a ship that makes use of this AI? I suspect this command would have to come via the Debug Console. I could try to make use of Ship::spawnOne, and then I'd need a handle on that ship for further instructions, such as setting the AI.

After that, I'd like to use the Debug Console to set position, rotation, speed etc. but these seem to be Ship variables
velocity, pitch, roll, yaw, position, orientation.

Could we create a working list of commands to be used on the Debug Console?
Sunshine - Moonlight - Good Times - Oolite
User avatar
cim
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 4072
Joined: Fri Nov 11, 2011 6:19 pm

Re: Experiment: NPC Non-AI ship

Post by cim »

I am wondering why your description sounds just so much different from https://wiki.alioth.net/index.php/OXP_howto_AI, which talks about state machines.
There are a few ways to write AIs. The original way involves the state machines described there.

You can also use a Javascript file as the ship's AI. There's a library called "Priority AI" shipped with the core game which provides one way to set up these AIs - https://wiki.alioth.net/index.php/Oolit ... I_Tutorial - but that's not the only option: any JS can be used in the AI script.
I suspect this command would have to come via the Debug Console.
Yes, if your intent is to then control the ship from the debug console, that makes sense.

System.addShips() would be the most straightforward way to add it, and returns a reference to the added ships which you can then access as a variable in the debug console.
https://wiki.alioth.net/index.php/Oolit ... m#addShips
Could we create a working list of commands to be used on the Debug Console?
Here you go - https://wiki.alioth.net/index.php/Oolit ... ject_model

Any JS method can be called from the debug console, and it has local variable storage to get the results back, and access to the standard Oolite worldscript globals like system. So you can do things like this to spawn a ship, get it into a local variable in the debug console, and then call Ship methods on that ship instance

Code: Select all

ships = system.addShips("trader", 1, [2000, 2000, 2000]); // near the witchpoint
ship = ships[0];
ship.commsMessage("Hello");
how would I spawn a ship that makes use of this AI
At least just for early testing, I'd set up a new shipdata.plist entry, based on an existing ship but then overriding a few properties

Code: Select all

"aitest_adder" = {
       like_ship = "adder";
       is_external_dependency = yes;
       roles = "aitest";
       script = "my-ship-script.js"; // or whatever you called the file from my previous post
       ai_type = "nullAI.plist";
};
Then you can swap aitest for trader in the system.addShips call above and you've got one ready to use.
User avatar
hiran
Theorethicist
Posts: 2403
Joined: Fri Mar 26, 2021 1:39 pm
Location: a parallel world I created for myself. Some call it a singularity...

Re: Experiment: NPC Non-AI ship

Post by hiran »

cim wrote: Wed Mar 02, 2022 12:40 pm
I suspect this command would have to come via the Debug Console.
Yes, if your intent is to then control the ship from the debug console, that makes sense.
My application, the Nexus is from Oolite perspective just a Debug Console. The fact that this debug console does not just allow to send low level commands into Oolite but adds to the gameplay is not known by Oolite. So it is ok to assume I am just controlling a ship from the Debug Console.
cim wrote: Wed Mar 02, 2022 12:40 pm
System.addShips() would be the most straightforward way to add it, and returns a reference to the added ships which you can then access as a variable in the debug console.
https://wiki.alioth.net/index.php/Oolit ... m#addShips
Could we create a working list of commands to be used on the Debug Console?
Here you go - https://wiki.alioth.net/index.php/Oolit ... ject_model

Any JS method can be called from the debug console, and it has local variable storage to get the results back, and access to the standard Oolite worldscript globals like system. So you can do things like this to spawn a ship, get it into a local variable in the debug console, and then call Ship methods on that ship instance

Code: Select all

ships = system.addShips("trader", 1, [2000, 2000, 2000]); // near the witchpoint
ship = ships[0];
ship.commsMessage("Hello");
Finally, one step ahead! I am able to spawn a ship, close to the witchpoint. And I can see the ship appearing out of a singularity, then wheezing off towards the planet. It will send whatever messages I inject with the commsMessage. :-)
After running the system.addShips command, Oolite responds back with e.g.

Code: Select all

[[Ship "Boa Class Cruiser Leader" position: (3456.26, 1553.22, 10340.5) scanClass: CLASS_NEUTRAL status: STATUS_IN_FLIGHT]]
But I am still not in control of the ship itself. Probably because when it was 'born' it also received a mind of it's own (=AI Pilot).
I never created an OXP so I am struggling with the next bits.
cim wrote: Wed Mar 02, 2022 12:40 pm
how would I spawn a ship that makes use of this AI
At least just for early testing, I'd set up a new shipdata.plist entry, based on an existing ship but then overriding a few properties

Code: Select all

"aitest_adder" = {
       like_ship = "adder";
       is_external_dependency = yes;
       roles = "aitest";
       script = "my-ship-script.js"; // or whatever you called the file from my previous post
       ai_type = "nullAI.plist";
};
Then you can swap aitest for trader in the system.addShips call above and you've got one ready to use.
So what I did is this:
- I created a folder underneath addons named ~/GNUstep/Applications/Oolite/Addons/Crossplay.oxp
- Inside that, I created the files
manifest.plist
AIs/RemoteControlled.js
Config/shipdata.plist

Here is the content of RemoteControlled.js:

Code: Select all

this.flightParameters = {};

this.shipSpawned = function()
{
  this.performScriptedAI();
}

this.scriptedAI = function(delta) 
{
   return this.flightParameters;  
}
Here is the content of shipdata.plist:

Code: Select all

"aitest_adder" = {
       like_ship = "adder";
       is_external_dependency = yes;
       roles = "aitest";
       script = "RemoteControlled.js"; // or whatever you called the file from my previous post
       ai_type = "nullAI.plist";
};
When starting up Oolite, I see this in Latest.log:

Code: Select all

...
    AddOns/Crossplay.oxp
    AddOns/Basic-debug.oxp
...
So it seems my expansion is correctly identified. After all I do not see any additional error message related to my expansion.
When I now issue the command

Code: Select all

ships = system.addShips("aitest", 1, [2000, 2000, 2000],1); 
Oolite responds back with

Code: Select all

null
and I do not see any ship. I guess something is still wrong in my expansion - the ship is not recognized for whatever reason. Help is welcome.
Sunshine - Moonlight - Good Times - Oolite
User avatar
cim
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 4072
Joined: Fri Nov 11, 2011 6:19 pm

Re: Experiment: NPC Non-AI ship

Post by cim »

Bearing in mind that it's been several years since I did any serious OXP coding, so others might be more able to help with this bit...

- your RemoteControlled.js file should go in Scripts/ not AIs/
- your shipdata.plist needs enclosing { and } to hold the aitest_adder entry

(More generally, your Debug Console emulating app is going to need an accompanying OXP, so it's probably worth taking some time out to just write a couple of simple ones - or at least have a good look through existing ones - to see what comes up.)
User avatar
hiran
Theorethicist
Posts: 2403
Joined: Fri Mar 26, 2021 1:39 pm
Location: a parallel world I created for myself. Some call it a singularity...

Re: Experiment: NPC Non-AI ship

Post by hiran »

cim wrote: Thu Mar 03, 2022 9:08 am
Bearing in mind that it's been several years since I did any serious OXP coding, so others might be more able to help with this bit...

- your RemoteControlled.js file should go in Scripts/ not AIs/
- your shipdata.plist needs enclosing { and } to hold the aitest_adder entry
Much better! I can flood the space now with adders that act like sitting ducks!
The next step is to make them fly.

I tried

Code: Select all

ship.script.flightParameters = { stickPitch: -0.2; desiredSpeed: this.ship.maxSpeed / 3; }
but the ship's still sitting.
Sunshine - Moonlight - Good Times - Oolite
User avatar
cim
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 4072
Joined: Fri Nov 11, 2011 6:19 pm

Re: Experiment: NPC Non-AI ship

Post by cim »

Try giving it a kick with ship.performScriptedAI() in the console.

If that doesn't work, to make sure it's getting the right AI attached, try replacing the function with this.

Code: Select all

this.scriptedAI = function(delta) 
{
   log(ship.name, delta);
   return { stickPitch: -0.2; desiredSpeed: this.ship.maxSpeed / 3; }
}
If the AI mode is being set properly, that should force the movement pattern, and also fill your logfile with time fractions. If the AI mode isn't being set properly nothing happens - but doing ship.performScriptedAI() in the console should then set it off.
User avatar
hiran
Theorethicist
Posts: 2403
Joined: Fri Mar 26, 2021 1:39 pm
Location: a parallel world I created for myself. Some call it a singularity...

Re: Experiment: NPC Non-AI ship

Post by hiran »

cim wrote: Thu Mar 03, 2022 10:50 pm
Try giving it a kick with ship.performScriptedAI() in the console.

If that doesn't work, to make sure it's getting the right AI attached, try replacing the function with this.

Code: Select all

this.scriptedAI = function(delta) 
{
   log(ship.name, delta);
   return { stickPitch: -0.2; desiredSpeed: this.ship.maxSpeed / 3; }
}
If the AI mode is being set properly, that should force the movement pattern, and also fill your logfile with time fractions. If the AI mode isn't being set properly nothing happens - but doing ship.performScriptedAI() in the console should then set it off.
Meanwhile I believe the problem is the nullAI. I switched to dumbAI and now at least the ships are rotating.
I am wondering which AI would be best to choose, as I just want to define position, orientation and speed.

Is there an AI that would just hold the course? Not worrying about what to do next (or, in state machines an AI with only one state)?
Sunshine - Moonlight - Good Times - Oolite
User avatar
cim
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 4072
Joined: Fri Nov 11, 2011 6:19 pm

Re: Experiment: NPC Non-AI ship

Post by cim »

You basically just need an AI that isn't going to do anything to interfere with ship behaviour once it's initialised - nullAI should be fine for that.

If the code isn't working it'll be because something in the script initialisation isn't working. Possibly shipSpawned() is too early to be calling ship.performScriptedAI() - as I said, it's been a while since I worked on any of this.

Try the following as an AI: call it "DebugControl.js" or something (yes, js not plist - but this one does go in the AI folder)
this.name = "Debug Control AI";

this.aiStarted = function()
{
this.ship.performScriptedAI()
}
That should be sufficient for now to permanently hand-off control to the ship script and debug console, and stop any other AI behaviour interfering.


(DumbAI will indeed cause the ship to rotate in place - but that's just because that's what it does)
Post Reply