Docking clearance requests to multiple stations at the same time? (and other docking related issues/questions)

For test results, bug reports, announcements of new builds etc.

Moderators: another_commander, winston, Getafix

Post Reply
User avatar
Milo
---- E L I T E ----
---- E L I T E ----
Posts: 466
Joined: Mon Sep 17, 2018 5:01 pm

Docking clearance requests to multiple stations at the same time? (and other docking related issues/questions)

Post by Milo »

When the player has a docking clearance request pending with station A, then targets station B and requests clearance without first cancelling the previous request with station A, what happens?

We can view the player's current docking clearance status from the player.dockingClearanceStatus property, which has codes indicating current status with respect to the player's current docking target, but we don't seem to have direct access to the player's current docking target.

There are five world-script event handlers triggered at various stages of the docking protocol:
1. playerDockingClearanceCancelled() // This method was added in Oolite test release 1.85. The playerDockingClearanceCancelled handler is called when the player withdraws their request to dock at a station.

2. playerDockingClearanceExpired() // This method was added in Oolite test release 1.83. The playerDockingClearanceExpired handler is called when the player exceeds the two minute window without requesting an extension

3. playerDockingClearanceGranted() // This method was added in Oolite test release 1.85. The playerDockingClearanceGranted handler is called when the player is given permission to dock at a station. If the player is given immediate clearance to dock, this event will be called immediately after the playerRequestedDockingClearance event. If, however, the station is unable to give immediate clearance, then there will be some delay between the request to dock and permission being granted. This event will be called when the station actually gives docking clearance.

4. playerDockingRefused() // The playerDockingRefused handler is called when a station refuses to provide autopilot docking instructions.
5. playerRequestedDockingClearance(string message) // this is invoked from two places in the game code:

a. When the player presses Shift-L (or equivalent remapped key) with a dockable as primary target
b. When the OOJS function player.ship.requestDockingClearance(station) is called from a script

Note that none of the above listed event handlers are informed which station triggered the event.

With both 5(a) and 5(b), the internal game function acceptDockingClearanceRequestFrom in StationEntity.m handles the request. Important for the multiple stations scenario, it checks if the player already has a docking target (an internal variable targetDockStation holds the dockable that the player most recently requested clearance from), and if it does, it then uses the internal game function setDockingClearanceStatus to update the player's status (accessible via player.dockingClearanceStatus) and sets that targetDockStation variable to the player ship's current target.

The 5(b) case, an OXP script triggering the docking request, is not used anywhere in the game Resources files, but at least one OXP uses it (BroadcastComms MFD). If the station provided in player.ship.requestDockingClearance(station) is not the player ship's primary target, it will log an error and set the targetDockStation to nil.

So, with either 5(a) or 5(b), it seems that we can use player.ship.target in the playerRequestedDockingClearance(string message) event handler to know which station generated the event.

But coming back to the multiple stations scenario, what happens with the clearance request to the previous station?

The internal game function update in StationEntity.m is the next point of interest. Every so often, each station independently runs this update function. It first looks at whether it is the player's current targetDockStation, and if it is, then it updates the player's docking clearance as appropriate (for example, changing it from granted to timing out, or from requested to granted, if the player has queued long enough). But if the player has some other station as targetDockStation then the update function does nothing.

So it seems that if you request docking with station A and then request docking with station B, the status with station A is overwritten and will not time out or progress in any way, and no further world script events are generated with respect to station A. If you then switch back to station A and request clearance again, it starts over from the beginning of the process.

This can leave OXPs that have been tracking these variables and events in a somewhat confused state unless they store the current player.ship.target each time the world script event handler playerRequestedDockingClearance(message) is called, and compare it any previously stored player.ship.target from that event to see if the target station was changed.

Another, unrelated, issue is that there is another OOJS function available to OXPs, player.ship.cancelDockingRequest(station), which seems to be the only way to trigger the playerDockingClearanceCancelled() world script event handler. Other methods of cancellation, such as pressing Shift-L again before the time out/renewal phase, do not seem to trigger that cancellation event handler.

I will leave the details of OOJS OXP-accessible Ship.dockingInstructions property and functions dockingInstructionsForShip, recallDockingInstructions and requestDockingInstructions as an exercise for the reader... (N.B., these are for NPCs and for the player ship under AI control when using docking computers; player.ship.dockingInstructions is null if the docking computers have not been activated, but remains with a value even after autopilot docking has been cancelled and clearance withdrawn, so it cannot be used to infer anything about the player ship's clearance status).

What am I proposing to change? Well, I don't know exactly, my analysis so far has only shown that it is complicated and confusing and has some inconsistencies. The game behavior around the docking clearance protocol seems okay, the pain point is mostly the ability for OXPs to figure out what is going on. I think that exposing the internal targetDockStation as an OOJS accessible property on the player ship would be helpful.

Perhaps we should also explicitly enforce that the station passed to player.ship.requestDockingClearance(station) must be the player.ship.target (this seems to be implicitly enforced once you get through several other functions but it could be checked earlier).

Also, player.ship.cancelDockingRequest(station) apparently returns without any effect if autopilot is engaged and the station is the same as targetDockStation. I imagine there is a story behind that.
Last edited by Milo on Wed Jun 24, 2020 3:28 pm, edited 1 time in total.
User avatar
Milo
---- E L I T E ----
---- E L I T E ----
Posts: 466
Joined: Mon Sep 17, 2018 5:01 pm

Re: Docking clearance requests to multiple stations at the same time? (and other docking related issues/questions)

Post by Milo »

ShipEntityAI.m function requestDockingCoordinates called from Resources/AI/dockingAI.plist for either player autopilot or NPC docking, has a fallback case if not given a target station, which is to find the nearest entity matching IsStationPredicate. That condition matches any station and doesn't check if it is dockable. I'm not sure if that code branch is reachable (since normally there would be a target station set when the AI starts), but if it ever does get used, it would be a good idea to make that predicate more robust. As is, I would expect the AI to abort when it realizes that it can't dock with the station selected, and presumably the AI would then find something else to do. But it might get into a loop situation if whatever caused it to get to that point without a valid station target happened again.
Last edited by Milo on Wed Jun 24, 2020 3:29 pm, edited 1 time in total.
User avatar
Milo
---- E L I T E ----
---- E L I T E ----
Posts: 466
Joined: Mon Sep 17, 2018 5:01 pm

Re: Docking clearance requests to multiple stations at the same time? (and other docking related issues/questions)

Post by Milo »

Further into the same requestDockingCoordinates function, if it has a valid station, it proceeds to call the function dockingInstructionsForShip from StationEntity.m.

In StationEntity.m, function dockingInstructionsForShip contains the following section:

Code: Select all

	// rolling is okay for some
	if	(fabs(flightRoll) > 0.01 && [chosenDock isOffCentre])
	{
		return [self holdPositionInstructionForShip:ship];
	}
flightRoll is a protected variable belonging to the station entity, containing the current roll rate.

The isOffCentre function is defined in DockEntity.m as follows:

Code: Select all

- (BOOL) isOffCentre
{
	if (fabs(position.x) + fabs(position.y) > 5.0)
	{
		return YES;
	}
	Vector dir = vector_forward_from_quaternion(orientation);
	if (fabs(dir.x) + fabs(dir.y) > 0.1)
	{
		return YES;
	}
	return NO;
}
Only if the dockingInstructionsForShip function makes it past the flightRoll / isOffCentre check, then the ship gets removed from the holding queue of the station and transferred to the chosenDock sub-entity's dockingInstructionsForShip function. Note that dockingInstructionsForShip is also defined (differently) in DockEntity.m, and has its own implementation of a "ships on approach" queue with instructions to back off or approach as needed.

If the flightRoll / isOffCentre check is true, then the ship is given coordinates to hold position. That then goes back into dockAI.plist, which is in AWAIT_COORDS state, and moves to HOLD_POSITION condition, which leads to STATIONKEEPING state. That state directs the ship to set speed to zero and pause for 10 seconds, after which it issues another requestDockingCoordinates and goes back into AWAIT_COORDS state. Repeat indefinitely?

If I understand all of this correctly, when an NPC or player ship wants to auto-dock, it must wait for the station to rotate until the dock is in proper alignment, before being able to proceed with further docking instructions. If it is unlucky with its timing, it might miss the optimal rotation multiple times, waiting 10 seconds each time. I am unclear why waiting for the station rotation is necessary simply to be handed off to the sub-entity for further instructions. I imagine that perhaps this is a factor in why sometimes NPC ships are slow to dock?

http://wiki.alioth.net/index.php/Docking_Instructions is relevant to this analysis and I notice that it only discusses the hold position state in the case of (1) "the station or carrier is moving too fast" and (2) "or is turning too fast with a non-rotating station".

(1) is handled earlier in the function dockingInstructionsForShip from StationEntity.m, with a moving station (not simply rolling, but actually moving) resulting in a hold position instruction. I didn't cover that above because it makes sense, and I understand that carriers' AI will cause them to stop when they receive a docking request (as the wiki article also covers), so it is only a transient condition.

(2) might refer to the flightRoll / isOffCentre check, but it's not checking if the rotating speed is a high value, it's checking if rotation is happening at all (> 0.01).
Post Reply