SDK Question OrbiterAPI create vessel: setting custom parameters

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Hi Folks,

Ive been struggling along with creating a capsule/service module tandem without any success, & Ive decided to go the direct vessel creation route. In other words, at SM jettison, meshes are cleared, cg is shifted, & the vessel creates a new "SM vessel". The issue with this method is that the propellant reserves & custom resources of the service module are not created accurately. Is there any way to set them properly to the new vessel when I jettison the SM?
 
Last edited:

Ares

Donator
Donator
Joined
Sep 17, 2008
Messages
9
Reaction score
0
Points
0
Hi, I was struggling with something similar a while back. Do you want to set parameters for the base VESSEL class or custom parameters specific to your derived class?

If it's the former I guess you can send them in the VESSELSTATUS struct you use in your call to oapiCreateVessel.

If it's the latter you'll have to use the vessel handle from oapiCreateVessel with oapiGetVesselInterface to get a pointer to the new vessel.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Hi, I was struggling with something similar a while back. Do you want to set parameters for the base VESSEL class or custom parameters specific to your derived class?

If it's the former I guess you can send them in the VESSELSTATUS struct you use in your call to oapiCreateVessel.

If it's the latter you'll have to use the vessel handle from oapiCreateVessel with oapiGetVesselInterface to get a pointer to the new vessel.

Probably both, but the second method would be good to know. Could you post a sample of what the code in question should look like? Im not very familiar working with vessel handles.
 

Ares

Donator
Donator
Joined
Sep 17, 2008
Messages
9
Reaction score
0
Points
0
Is this any good? I think it will work if you include the header containing the SM class interface in the main vessel, and either "param" is a public member of the SM class or the SM class is a friend of the main vessel.

Code:
// Setup VESSELSTATUS struct for new vessel with required base class parameters.
VESSELSTATUS2 status;
status.version = 2;
status.rpos = LMpos;
// etc...

// Get vessel handle from oapiCreateVessel.
OBJHANDLE hVessel = oapiCreateVessel ("NewVesselName", "SMClass", &status);

// Get pointer to the instance of SMClass via oapiGetVesselInterface.
SMClass *sm = (SMClass*) oapiGetVesselInterface (hVessel);

// Set derived class custom parameters.
sm->param1 = 3;

Take a look at the Atlantis::SeparateBoosters function in the Atlantis.cpp sample.
 

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
Check out the tutorial linked in my sig, specifically part 10.

My wip Apollo CSM uses the same basic method to handle CM / SM separation.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Is this any good? I think it will work if you include the header containing the SM class interface in the main vessel, and either "param" is a public member of the SM class or the SM class is a friend of the main vessel.

Code:
// Setup VESSELSTATUS struct for new vessel with required base class parameters.
VESSELSTATUS2 status;
status.version = 2;
status.rpos = LMpos;
// etc...

// Get vessel handle from oapiCreateVessel.
OBJHANDLE hVessel = oapiCreateVessel ("NewVesselName", "SMClass", &status);

// Get pointer to the instance of SMClass via oapiGetVesselInterface.
SMClass *sm = (SMClass*) oapiGetVesselInterface (hVessel);

// Set derived class custom parameters.
sm->param1 = 3;

Take a look at the Atlantis::SeparateBoosters function in the Atlantis.cpp sample.

That looks very good. Is param1 a pointer to the actual variable name?

Unfortunately though, my code is not being cooperative at the moment. Ive created all of the necessary structure for it to work, but every time I try to jettison, my CG starts back about 6m on my vessel, slides back to center, doesnt update the meshes properly. The relevant code looks like this

SMJett int set to one at creation (1=SM attached, 0=SM jettisoned)

Code:
PhoenixASMN::PhoenixASMN (OBJHANDLE hObj, int fmodel)
	: VESSEL3 (hObj, fmodel)
{
	O2Tank = 70;
	Water = 230;
	SMJett = 1;
}

My pair of control functions that update the mesh visuals & physics parameters when needed. Both are called at SMJettison, and in setclasscaps

Code:
double PhoenixASMN::MeshControl ()
{

ClearMeshes();
	if (SMJett=1)
	{
SetMeshVisibilityMode (AddMesh (PhoenixCapsule = oapiLoadMeshGlobal ("PhoenixAoffset")), MESHVIS_ALWAYS);
SetMeshVisibilityMode (AddMesh (PhoenixCapsule = oapiLoadMeshGlobal ("PhoenixSMN MKII")), MESHVIS_ALWAYS);
return 1;
	}

	else
	{
SetMeshVisibilityMode (AddMesh (PhoenixCapsule = oapiLoadMeshGlobal ("PhoenixAoffset")), MESHVIS_ALWAYS);
return 1;
	}
return 1;
}

// PhoenixSMN MKII

// 6.214

double PhoenixASMN::ClassControl ()
{


	if (SMJett=1)
	{
	SetPMI (EXP_PMI_BEFORE_SMJETT);
	SetSize (EXP_SIZE_BEFORE_SMJETT);
	SetCrossSections (EXP_CS_BEFORE_SMJETT);
	return 1;
	}

	if (SMJett=0)
	{
	SetPMI (EXP_PMI_AFTER_SMJETT);
	SetSize (EXP_SIZE_AFTER_SMJETT);
	SetCrossSections (EXP_CS_AFTER_SMJETT);
	ShiftCG(CAPSULE_OFFSET);
	return 1;
	}
return 1;
}

Lastly my jettison function tied to the J key. It should set the SMJett int to 0 when called, but checking the scenario file seems to show it not working.

Code:
//---------------------------------------------------------------------------
	// Key "J" Jettison the service module
	if(key==OAPI_KEY_J&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))

	if (SMJett=1)
	{
	SMJettison();
	SMJett--;
	MeshControl ();
	ClassControl ();
	}

	else
	{
	MeshControl ();
	ClassControl ();
	}

Is there something that I'm missing here?
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,635
Reaction score
2,352
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Dirty trick for avoiding this error:

Code:
if(1 = SMJett)

Would result in a compiler error and

Code:
if(1 == SMJett)

would be still perfectly legal.

Much much better though, aside of this:

USE A BOOL TYPE FOR YES/NO FLAGS!
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,883
Reaction score
2,135
Points
203
Location
between the planets
USE A BOOL TYPE FOR YES/NO FLAGS!

And then just the value itself... like if (SMJett) or if (!SMJett)

Didn't really look at the code close enough to see wheather it was a boolean affair, I thought SMJett might have other values too.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Arrrrrgh!

Code:
if (SMJett == 1)

These can be real time wasters...

Bingo, that did it! I still have a fair number of things to fix on it yet though, even the RCS thrusters offset wrong with the new locations, but I can probably cover that up by having them NULL before SMJettison.

Out of curiosity, I wonder what would happen if I put the thruster definitions in clbkPoststep...
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,883
Reaction score
2,135
Points
203
Location
between the planets
Out of curiosity, I wonder what would happen if I put the thruster definitions in clbkPoststep...

A crash if a call to the thrusters happens in the first clbkPreStep, no problems if there are no calls prior to them being defined.

But really, thruster definitions should be put into clbkSetClassCaps or clbkPostCreation if they're static.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
A crash if a call to the thrusters happens in the first clbkPreStep, no problems if there are no calls prior to them being defined.

But really, thruster definitions should be put into clbkSetClassCaps or clbkPostCreation if they're static.

What if I define my thrusters with the SMJett variable setting their position, then call setclasscaps at SMJettison. Its an odd way to do it, but will it work?
 

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
No,

Calling clbksetclasscaps will reset the status of your entire vessel propellant tanks meshes and all not just thrusters. It may also cause instability because orbiter throws a fit when when default call-back functions are called out of order.

Instead either define all thrusters at the start and then use the shiftCG() or define your new thrusters and thruster groups in your stage seperation function. If you do not have a custom stage seperation function I strongly suggest that you write one.

ETA:
Again I strongly suggest you read my tutorial, it's not just self-pimpage, part 10 covers exactly this scenario and in detail.
 
Last edited:

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,883
Reaction score
2,135
Points
203
Location
between the planets
You don't call clbkSetClassCaps, Orbiter does at vessel creation. If you call it yourself from within your vessel, mayhem is guaranteed!

If the thrusters are static, just put their definition in the clbkSetClassCaps of the vessel. The function will be called as soon as the vessel is created.

If there's non-static properties at initialisation, like propellant and stuff as you mentioned, you can set those for the newly created vessel from inside the function that caused its creation, that's no problem at all. But if you do that and your new vessel has no thrusters defined yet, you might get hurt.

Ill try to put this in a short flow here, assuming I understood your intents correctly:

You have vesselA, which is the initial vessel, and then you have vesselB, which is the part that gets created on separation.

Register command for separation -> call separation function in vesselA.

separation function creates vesselB -> clbkSetClassCaps of vesselB gets called before the next line of code in vesselA gets executed.

Define any static properties of vesselB in clbkSetClassCaps of vesselB

after creation, separation function in vesselA will be continued, here you should do several things:
remove all properties that vesselA doesn't have anymore after the seperation.
set all dynamic properties of vesselB that are available through the vessel interface and that depend on information contained by vesselA.
If you have dynamic properties in vesselB that are not available through the vessel interface and are depending on data contained in vesselA, build a public function into the vesselB class to set those parameters. dynamic_cast the vessel interface returned by createVessel into a vesselB class, and call that function.

When the separation function ends, there should be no messing about with static properties or members anymore, nor should there be any more data exchange.
 
Last edited:

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
Ok detailed response time.

If you haven't already should create a boolean-type class variable named "SM_is_attached" or similar.

Initialize it as being true in your class constructor because I assume that your vessel starts with the SM attached and then jettisons it rather than vice versa :eek:.

In clbksetclasscaps declare your thrusters, propellant tanks, and meshes for both the CM and SM. Make sure that the CM's are declared before the SM's to avoid errors with indexing on scenario load (explained in my tutorial).

Now create a custom void function named "SeperateSM()" or similar. It's structure should look something like this...

Code:
void Pheonix::SeparateSM (void)
{
  if (SM_is_attached) // Sanity check, is there a SM to jettison?
  {
    declare a char (string-type) variable and copy your parent vessel's name to it.
    add "_SM" or something similar to the end of your string
    
    declare a VESSELSTATUS variable and copy your parent vessel's current state to it.

    declare a seperation offset for your SM, aka VECTOR3 showing it's location relative to the parent vessel
    declare a seperation vector, aka direction 
    declare a seperation velocity.

    apply the above vectors as transformations to your VESSELSTATUS variable

    Use oapiCreateVessel (name, class, status), with the above string and VESSELSTATUS variables to create the SM as a seperate vessel.

    Get the object handle of the newly created vessel using our string variable
    use that object handle in conjunction with oapiGetVesselInterface to get a independant VESSEL interface for our newly spawned SM vessel

    Using that interface set propellant level of the SM vessel's tanks to the propellant level in the parent vessel's SM tanks.

    Now that we've created the SM as a seperate vessel...
    Delete the parent vessel's SM tanks.
    Delete the parent vessel's SM thrusters.
    Delete the Parent vessel's SM mesh.
    Shift parent vessel's CoG.

    Declare new thrusters and thrust groups as required.
  } // end if statement 

SM_is_attached = false; // update status of SM 
} //Done

From there simply call the stage seperation function on the appropriate key press or when the assigned conditions are met.

This is all explained in detail, along with working code samples, in the following post
http://orbiter-forum.com/blog.php?b=1221

---------- Post added at 10:43 ---------- Previous post was at 10:30 ----------

PS:

Code:
	// Key "J" Jettison the service module
	if(key==OAPI_KEY_J&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))

	if (SMJett=1)
	{
	SMJettison();
	SMJett--;
	MeshControl ();
	ClassControl ();
	}

	else
	{
	MeshControl ();
	ClassControl ();
	}

Should look like

Code:
// Key "J" Jettison the service module
if(key==OAPI_KEY_J&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
{
  SeperateSM();
  return 1;
}


---------- Post added at 10:52 ---------- Previous post was at 10:43 ----------

PPS:

You'll also need something in clbkpostcreation to handle instances where the vessel is spawned without a SM, on scenario load for instance.

to do this copy/paste everything in your stage seperation function that is not spawing the descent stage into clbkpostcreation and place it within a "if (SM_is_attached == false)" statement.
 
Last edited:

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
to do this copy/paste everything in your stage seperation function that is not spawing the descent stage into clbkpostcreation and place it within a "if (SM_is_attached == false)" statement.
Why copy/paste it? Can't it be in a separate function called from both callbacks? One place fewer when you need to fix possible bugs in the code there, and smaller code (it can be also an inline function if you care more about 2 ticks faster execution in vessel initialization, than about the size).
 

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
Why copy/paste it? Can't it be in a separate function called from both callbacks? One place fewer when you need to fix possible bugs in the code there, and smaller code (it can be also an inline function if you care more about 2 ticks faster execution in vessel initialization, than about the size).

Yes it can, but then if you quit and then reload after jettisoning the SM there would be two SM vessels in the scenario. One where you left it and one where you currently are.

Though I suppose this functionality could be useful. the number of SMs floating around in a given scenario would indicate how often quick save or (load current state) was used ;)
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
Yes it can, but then if you quit and then reload after jettisoning the SM there would be two SM vessels in the scenario. One where you left it and one where you currently are.
And how would it different from copying and pasting the same code somewhere else? :shrug:
 

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
Because you're only copy/pasting the part that is not spawning the SM vessel.
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
Because you're only copy/pasting the part that is not spawning the SM vessel.
And that's the same part which you put to the separate (common) function. ;)
 
Top