Page 1 of 1

[Javascript] cloning objects

Posted: Fri Dec 07, 2012 9:28 pm
by bungi
Problem : automatically add extra Mamushi whenever one is spawned. Effectively ensuring that they never appear alone.

However... I'm struggling creating new ship objects in a sensible way.

(all working is shown for completeness)

I can't find any kind of clone ship method.
There does not seem to be a constructor for Ship. So I can't create an empty one and populate it from the existing object...
I looked to see if I could spawn one of anything, and copy the existing one over it, but not all fields are writable...
I could use legacy_spawnShip, but that creates a ship, and does not return a reference to it, so the created ship is a mamushi somewhere in the system, not in this group...
So I added a new role to the mamushi allowing me to call this.ship.spawnOne with that role, then move it to the appropriate position, role and group.
Fine? Except that spawnOne creates a shipSpawned event, which leads to the wonderful phenomenon of infinite regression.
To try to control the regression I've tried to override the method, setting a default function which just logs, but it appears that this is neither an error, nor working. (i.e. I can set the function reference, but it seems to use the default as setup originally).
I've also tried to use a global variable which gets changed the very first time the shipSpawned method is called, and therefore I can put a guard condition in so it is limited to how often it is called, but that obviously would need resetting on some event or else you would only be able to do this once.
I have stopped infinite regression by counting the number of Mamushi in the system, but that means that I always get none, or that number split roughly evenly across the groups. I have subsequently limited each group to a maximum number of Mamushi, but this all seems rather clunky.


In addition to that, the 'cloned' ships don't seem quite all there, or sticking in their groups. Dumping data shows some odditites.
I'm manually copying the role, group and AIState, and calling setAI, but I'm seeing data like this:
21:16:12.126 [universe.objectDump]: Ent: 35 ShipEntity "Mamushi Light Fighter" position: (1.#QNAN, -9728.54, 143254) scanClass: CLASS_NEUTRAL status: STATUS_IN_FLIGHT range: 1.#QNAN (visible: no) mass 12745.8 AI: nullAI.plist:GLOBAL
worrying bits in bold.

I looked at AIs but they didn't seem to be very clear, so I left them alone for now.

Anyone else hit this and got an elegant and working solution? Is it in fact possible?

By the way is there any info on the event calling under the hood. I'm guessing events are added to a queue or a set and fired one at a time? I'm not sure if the collection of events is ordered or not.

thanks in advance

Re: [Javascript] cloning objects

Posted: Fri Dec 07, 2012 10:04 pm
by cim
bungi wrote:
There does not seem to be a constructor for Ship. So I can't create an empty one and populate it from the existing object...
system.addShips is what you (almost always) want for adding new ships.
bungi wrote:
I looked to see if I could spawn one of anything, and copy the existing one over it, but not all fields are writable...
The key thing to remember is that the ships are not Javascript objects. The ships are core Oolite engine objects (ShipEntity class). A Javascript Ship object is an interface object which has an internal pointer to a particular core ShipEntity, to allow it to be manipulated a bit like a native JS object.

As a result, things such as copy, object methods, etc. however do not work as you might expect for a native JS object.
bungi wrote:
To try to control the regression I've tried to override the method, setting a default function which just logs, but it appears that this is neither an error, nor working. (i.e. I can set the function reference, but it seems to use the default as setup originally).
The ship scripts are not shared. So you might change the shipSpawned script for your first ship - but by then it's already fired (and won't be again, in this case). When you create a second ship, it gets a fresh copy of the script, which includes the original shipSpawned event, not the modified version the other ship has.

If you use a method such as system.addShips which returns references to the ships, you can do ship.script.shipSpawned = function() {} on them and have it do what you want, provided you do it immediately (i.e. before you return from the function which called addShips) so that it gets changed before shipSpawned fires. Or ... you could use like_ship to have two similar ships with slightly different ship scripts, one with the shipSpawned event and one without.
bungi wrote:
In addition to that, the 'cloned' ships don't seem quite all there, or sticking in their groups. Dumping data shows some odditites.
I'm manually copying the role, group and AIState, and calling setAI, but I'm seeing data like this:
That's probably the wrong approach. Copying the group won't work (ship.group is an interface object, not a native JS one) - so you'll have to use firstship.group.addShip(secondship). Make sure you call setAI before you set AIState. It also looks like something is going wrong in your position setting, so that the ship's positions are outside the universe (NaN). Using system.addShips might avoid that.
bungi wrote:
Anyone else hit this and got an elegant and working solution? Is it in fact possible?
If you weren't making these into escort ships in the first place, the easy way to do it would be to have two copies of the ship in shipdata.plist (using like_ship to avoid a lot of copy/paste) and make one an escort of the other. But you can't have nested escort relationships (the core game doesn't allow it, and the AI wouldn't work even if it did), so that won't work here.

Further, what you're wanting for escorts is the mothership to get extra escorts as a result. That's difficult: the mothership will want ... let's say it's a Boa ... 4 escorts. When it's spawned, it gets 4 escorts spawned with it. If you then add other ships near the Boa, and try to get them to act as escorts, the Boa won't accept them - it already has enough - and you'll get into a real mess.

Now, if they're escorts of a custom ship, that's not a problem - you just make that ship only have Mamushi escorts, and increase its escort numbers until it has the right amount.

So ... if you want an average Boa trader to have 8 Mamushi escorts sometimes, you need to make a copy of the Boa using like_ship: set its roles to the same as the original Boa but at a much lower weight, so it doesn't show up as often; set its escort role to the Mamushi's custom role; and increase its escort count. Let like_ship handle the rest so that it otherwise looks and acts like a standard Boa. Then do the same for the other escorted ships in the core game. (If you want to go further, use is_external_dependency and like_ship to do the same for your favourite OXP ships)

...the catch is, you can't have a ship with mixed Mamushi and normal escorts this way, at least not easily. Still, that's perhaps more complexity than you need right now.
bungi wrote:
By the way is there any info on the event calling under the hood. I'm guessing events are added to a queue or a set and fired one at a time? I'm not sure if the collection of events is ordered or not.
Much simpler, as it happens. Any time the core game engine does something which would cause an event, the Javascript engine is immediately activated to process that event. Once all processing is done, control is returned to the core game. You can in certain circumstances get a situation in which one event causes another event, in which case the events are dealt with as a stack, and you can have the processing for one event inside the processing of another event. (But provided your event handlers are written sensibly, you rarely need to worry about that possibility)

Does this clarify things a bit?

Re: [Javascript] cloning objects

Posted: Sat Dec 08, 2012 10:47 am
by bungi
mmmm. explains loads of things. Thanks!
That's probably the wrong approach. Copying the group won't work (ship.group is an interface object, not a native JS one) - so you'll have to use firstship.group.addShip(secondship). Make sure you call setAI before you set AIState. It also looks like something is going wrong in your position setting, so that the ship's positions are outside the universe (NaN). Using system.addShips might avoid that.
I'm calling firstship.group.addShip(secondship). The groups do seem to be getting set according to my voluminous debug logging, but the observed behaviour issues are probably down to AI and position.
I'll check but I'm pretty sure setAI is called first, it seemed sensible to me to set the AI before setting the state.
The position code was informed by ripping off carefully looking at other examples. I'll double check, but it just adds up to +/- 400 units in each axis to the first ship's position, then sets the position, overriding the spawned one.

I'll look at addShips, I didn't think it did what I wanted but after another look it does take a role and a position which makes life very easy. The like ships approach neatly fixes the regression issue, so I'll use that. I presume I just need to override the script key to point to a different script file?

As for escorts, hmmmm. No chance of getting an addEscort(s) operation added to the Ship interface for version 1.77... I presume that's past code freeze now. In the short term the Mamushi is too light to be any good as a single escort, so it looks like a new role, and a bunch of like_ships.

Interestingly they do work well as police ships. During testing I watched 3 of them take down a Python Class Cruiser. Not fast, but they didn't take any losses. Might need to add a specific police version with flashy lights :-). Add it to the backlog.

Re: [Javascript] cloning objects

Posted: Sat Dec 08, 2012 11:16 am
by cim
bungi wrote:
As for escorts, hmmmm. No chance of getting an addEscort(s) operation added to the Ship interface for version 1.77...
Can be done in 1.76 - mother.escortGroup.addShip(newescort) - and set the new escort to escortAI.plist, of course. (The new escort must have primaryRole = escort or wingman, compatible legal status, etc.)

The catch is that it only works if the mother ship has a spare escort slot, and you can't increase that number from script.
bungi wrote:
I presume that's past code freeze now
It's past the stage where I feel personally comfortable introducing any more major new features, but making a ship's max escort number writable (and indeed readable...) is pretty straightforward. We're not in any code freeze at the moment.

Re: [Javascript] cloning objects

Posted: Sat Dec 08, 2012 4:17 pm
by bungi
making a ship's max escort number writable (and indeed readable...) is pretty straightforward
As long as it doesn't have a nasty side effect back in the oolite source. I don't know the code and I'm not an Objective C programmer, but based on other similar languages I'd be worried that the max escorts parameter is set at startup for a ShipEntity class and the escort slots created and memory allocated for a specific instance as part of the constructor using that value. Changing the max escorts after construction may not be trivial. Or it could be if coded using some collection type interface that allows flexibility. Don't know and loathe to guess.
It also has game side impact in that an OXP could reduce the number creating an issue with the existing escorts and what to do with them. Though that could be kind of fun if someone did an OXP where you could bribe escorts to go away, or even aid the player.

I'll leave it up to you. If the impact is more than a few minutes work, leave it and I'll pull the source and have a look at it myself, with a view to maybe submitting a patch when I've worked through the implications. I can do a good chunk of what I wanted with existing code, and i've yet to even start on sorting out where I left things last night.

Re: [Javascript] cloning objects

Posted: Sat Dec 08, 2012 4:27 pm
by Thargoid
The latter point can already be done - whilst adding escorts over the maximum count is not possible, the array of existing ones is fully visible to script and those escort entities can be manipulated or removed. They can also be broken away from their mother, for whatever purpose the OXP may wish to give them.

Re: [Javascript] cloning objects

Posted: Sat Dec 08, 2012 4:36 pm
by cim
bungi wrote:
It also has game side impact in that an OXP could reduce the number creating an issue with the existing escorts and what to do with them. Though that could be kind of fun if someone did an OXP where you could bribe escorts to go away, or even aid the player.
There would need to be limitations for simplicity - no raising above the internal MAX_ESCORTS constant (currently 16), no lowering below the current group size - but apart from that it's just a few lines of code.

Re: [Javascript] cloning objects

Posted: Sat Dec 08, 2012 5:14 pm
by Rese249er
A possible point of interest: Aquatics Guardian System, part of the Aquatics OXP by Thargoid. I've been able to have the Guardian system eject two of Shipbuilder's Colonial Viper mk1's instead of the usual drone model. A modified version could be used to have one or more Mamushi for each escort slot.

Re: [Javascript] cloning objects

Posted: Sat Dec 08, 2012 5:18 pm
by Eric Walch
bungi wrote:
Changing the max escorts after construction may not be trivial.
I think it is rather straightforward. For ships added with class Police or role 'hunter' the max escorts is already flexible, up to 16, even when not explicitly defined.

Re: [Javascript] cloning objects

Posted: Sat Dec 08, 2012 7:53 pm
by bungi
alright then, if it's that easy, and the limit is 16, then yes please.

I'll do a Mamushi version 0.2 which will be tested against 1.76, and comment the code for when I start testing vs 1.77.

As for multiply launching Guardians... sounds interesting. I'll pull Aquatics and have a look sometime. I've not used that OXP so far.

Re: [Javascript] cloning objects

Posted: Sat Dec 08, 2012 8:13 pm
by Thargoid
The Raptor ships in TCAT may also be useful reference for you in doing ships that can be singles or small squadrons. Those can come in single entities or trios, and sound along similar lines to your ones.

Also that OXP uses grouping for the Thargoid invasion fleet, which may also be useful reference for you. Feel free to use anything from either of there or Aquatics if it's helpful.