SDK Question Get Docking port Number from Dock Handle?

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
Hi Guys,

still messing around with multistage docking...

For sure it should be crucial to call the dock and undock commands for the proper docking ports.

Now, Dock and Undock commands are all relative to the port number. When you create a docking port you identify it with a dock handle.

There is a simple way to get the dockhandle from the port number, but I can't find the other way around.

If I have the dock_handle, how can I obtain the relevant port number?? isn't it something missing from the apis?

Thanks in advance :cheers:

Fred
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,398
Reaction score
578
Points
153
Location
Vienna
If I have the dock_handle, how can I obtain the relevant port number?? isn't it something missing from the apis?

It sure would be comfortable to have the reverse mapping API, but IMHO it is not so costly to simply iterate through the list to get the number. As long as docking port count stays lower than - let's say - 10, I wouldn't see it as huge performance problem.

What exactly is the use case?
 

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
What exactly is the use case?

the idea is to create an alternate version of the multistage module exploiting the fact that in orbiter2016 docking landed vessels are supported, therefore creating each stage, booster etc as separate vessel and dock one to the other to create the rocket.

The main vessel will always be the last stage which will control everything that happens underneath.

Now, let's say that it's not even too difficult to do it, I also have all the code of the current Multistage I can use many things from there. The first issue I'm encountering is that since I have to build and then to leave behind a variable number of things such as boosters, stages, fairings etc I wanted to easily manipulate docking ports. Dock and Undock commands where ideal to me, but they both refer to docking ports number instead of dockhandles.
For detaching I can use the DelDock command, but for creating the vehicles it would be useful to have the Dock command instead of

Dock(OBJHANDLE target, UINT n, UINT tgtn, UINT mode)

also

Dock(OBJHANDLE target, DOCKHANDLE my_dock_handle, DOCKHANDLE target_dock_handle, UINT mode)

with the attachment the AttachChild function works exactly like that and it works perfectly but we know that attachments do not support combined physics so it's not for our purpose here.
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,398
Reaction score
578
Points
153
Location
Vienna
the idea is to create an alternate version of the multistage module exploiting the fact that in orbiter2016 docking landed vessels are supported, therefore creating each stage, booster etc as separate vessel and dock one to the other to create the rocket.

The main vessel will always be the last stage which will control everything that happens underneath.

Now, let's say that it's not even too difficult to do it, I also have all the code of the current Multistage I can use many things from there. The first issue I'm encountering is that since I have to build and then to leave behind a variable number of things such as boosters, stages, fairings etc I wanted to easily manipulate docking ports. Dock and Undock commands where ideal to me, but they both refer to docking ports number instead of dockhandles.
For detaching I can use the DelDock command, but for creating the vehicles it would be useful to have the Dock command instead of

Dock(OBJHANDLE target, UINT n, UINT tgtn, UINT mode)

also

Dock(OBJHANDLE target, DOCKHANDLE my_dock_handle, DOCKHANDLE target_dock_handle, UINT mode)

with the attachment the AttachChild function works exactly like that and it works perfectly but we know that attachments do not support combined physics so it's not for our purpose here.

I think the docking approach to multistage concepts in general is a fallacy, but we discussed that already IIRC, so I'm not going into further detail.
However, the need here to manage all docking ports from a central component seems odd to me. Wouldn't it make more sense to let every component manage its docking ports itself and only distribute jettison events from the central component? This way every component can hold its own table of dock handles and manage events accordingly. It would be a kind of separation of concerns.
What I mean is this:

  • Let's say we have 3 stages A, B and C. C is the command module.
  • A is a booster stage that undocks automatically once propellant ran out.
  • B is an on-orbit stage that "undocks" some fairing automatically once in low pressure environment.
  • C can jettison A and B prematurely.
  • If C needs to implement and handle each dock, A and B code can't really encapsulate the automatic procedures, because it would possibly collide with C code (docking port deletion comes into mind).
  • If C just sends a "jettison" command to A or B, the appropriate module takes care of its docks, plus additional procedures (e.g. "undocking" fairing before undocking B from C).
With the later system, you could design your module interface in an abstract way instead of having to handle all the low-level plumbing explicitly in a potentially disruptive way.

But of course the API extension you mentioned would do no harm, so I'd certainly not oppose it. I think that the target object handle should not be necessary if the target dock handle is specified, though. You could also make VESSEL::Dock() an oapiDock() function, underlining the global nature of the operation, because the "this" pointer is not necessary to address the source docking port. It would be odd if a seemingly global handle had different meanings according to context.

Come to think, this might be the reason Martin did it the way it is now :hmm: . EDIT: No, can't be, because then the oapiGetDockStatus() would not work without an additional vessel handle.
 
Last edited:

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
I think the docking approach to multistage concepts in general is a fallacy, but we discussed that already IIRC, so I'm not going into further detail.

yep I remember this point. Atmospheric drag was the main issue IIRC. I'm also experiencing some not nice behaviour, but I was giving it a try to have something to test and to compare with the current multistage module.


However, the need here to manage all docking ports from a central component seems odd to me. Wouldn't it make more sense to let every component manage its docking ports itself and only distribute jettison events from the central component? This way every component can hold its own table of dock handles and manage events accordingly. It would be a kind of separation of concerns.
What I mean is this:

  • Let's say we have 3 stages A, B and C. C is the command module.
  • A is a booster stage that undocks automatically once propellant ran out.
  • B is an on-orbit stage that "undocks" some fairing automatically once in low pressure environment.
  • C can jettison A and B prematurely.
  • If C needs to implement and handle each dock, A and B code can't really encapsulate the automatic procedures, because it would possibly collide with C code (docking port deletion comes into mind).
  • If C just sends a "jettison" command to A or B, the appropriate module takes care of its docks, plus additional procedures (e.g. "undocking" fairing before undocking B from C).
With the later system, you could design your module interface in an abstract way instead of having to handle all the low-level plumbing explicitly in a potentially disruptive way.

This was exactly my initial plan, but then in a generic module there could be any number of stages or of boosters, that can fire at anytime the user wants, fairing may be attached to any stage etc. So suddenly I found myself in the need of the "main computer" to know everything is going on and to keep up with the sequence. I think that in the real world that's what happens.

I think that for the testing purpose I'll let the main stage create all the docks on all the stages, with relevant handles stored. Then to cut connections it will delete the docking ports using those handles. Let's see what happens in this way.

Edit: I think that it would be enough to have something like this:

DOCKHANDLE CreateDock(const VECTOR3& pos, const VECTOR3& dir, const VECTOR3& rot, UINT &idx)

so you call it with an empty UINT as last parameter and you get the index in the end, so you can reuse it. I can try to produce something like this, incorporating the CreateDock into some CreateDockIdx(...) to call everytime instead of createdock
 
Last edited:

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,398
Reaction score
578
Points
153
Location
Vienna
I think that for the testing purpose I'll let the main stage create all the docks on all the stages, with relevant handles stored. Then to cut connections it will delete the docking ports using those handles. Let's see what happens in this way.

I see. For testing purposes the linear search method should suffice: (compiles, but untested!)
Code:
int myoapiDock(DOCKHANDLE source, DOCKHANDLE target, UINT mode)
{
  OBJHANDLE sourceObject=NULL;
  OBJHANDLE targetObject=NULL;
  OBJHANDLE testObject=NULL;
  DOCKHANDLE testDock=NULL;
  int sourceIndex=-1;
  int targetIndex=-1;
  for(int i=0;(testObject=oapiGetVesselByIndex(i))!=NULL;i++)
    for(int j=0;(testDock=oapiGetDockHandle(testObject, j))!=NULL;j++)
    {
      if (testDock!=source && testDock!=target) continue;
      if (testDock==source)
      {
        sourceObject=testObject;
        sourceIndex=j;
      }
      else
      {
        targetObject=testObject;
        targetIndex=j;
      }
      if (sourceObject==targetObject) return 4; // Source is also target
      if (sourceObject!=NULL && targetObject!=NULL) break; // We have both, no need to search further.
    }
  if (sourceObject==NULL) return 5; // Source handle invalid
  if (targetObject==NULL) return 6; // Target handle invalid
  if (!oapiIsVessel(sourceObject)) return 7; // Source is no vessel
  return oapiGetVesselInterface(sourceObject)->Dock(targetObject, sourceIndex, targetIndex, mode);
}

bool myoapiUndock(DOCKHANDLE dock, const OBJHANDLE exclude = 0 )
{
  OBJHANDLE sourceObject=NULL;
  DOCKHANDLE testDock=NULL;
  int sourceIndex=-1;
  for(int i=0;(sourceObject=oapiGetVesselByIndex(i))!=NULL;i++)
    for(int j=0;(testDock=oapiGetDockHandle(sourceObject, j))!=NULL;j++)
    {
      if (testDock!=dock) continue;      
      sourceIndex=j;
      break;
    }
  if (sourceIndex<0) return false; // Handle invalid, thus no vessel undocked.
  if (!oapiIsVessel(sourceObject)) return false; // Source is no vessel, thus no vessel undocked.
  return oapiGetVesselInterface(sourceObject)->Undock(sourceIndex, exclude);
}


---------- Post added at 17:09 ---------- Previous post was at 17:07 ----------

Edit: I think that it would be enough to have something like this:

DOCKHANDLE CreateDock(const VECTOR3& pos, const VECTOR3& dir, const VECTOR3& rot, UINT &idx)

so you call it with an empty UINT as last parameter and you get the index in the end, so you can reuse it. I can try to produce something like this, incorporating the CreateDock into some CreateDockIdx(...) to call everytime instead of createdock

The problem I can see here is that you always need two keys to fully address the dock: object handle AND dock index. The single handle key is more comfortable to use in your use case, I'd say.
 
Last edited:
Top