Problem Ummu - Disabling (and reenabling) ship control.

Ashaman42

New member
Joined
May 30, 2009
Messages
88
Reaction score
0
Points
0
Hi,

Wasn't sure whether to put this here or in the OrbiterSDK sub forum.

I've been updating the dll of a ship I made with Ummu capabilities, so far I've managed to disable control of the ship's attitude and main engine when it's empty like this:

Code:
if(Crew.GetCrewTotalNumber()==0)
    {
        sprintf(SendFocusScreenMessage(),"No Pilot Present. Control Impossible.");
        oapiSetAttitudeMode(GetHandle(),0);
        THGROUP_HANDLE hdl = NULL;
        hdl=GetThrusterGroupHandle(THGROUP_MAIN);
        DelThrusterGroup(hdl,THGROUP_MAIN,false);
    }
When I reenter the ship with an ummu I regain control of the attitude control but with the main thruster group being deleted I obviously can't control the main engines.

I've tried to reinstate main control the following two ways:

1)
Code:
if(Crew.GetCrewTotalNumber()>0)
    {
        PROPELLANT_HANDLE tank;
        tank = CreatePropellantResource (FUELMASS);
        THRUSTER_HANDLE th_main;
        th_main = CreateThruster (_V(0,0,-13.5), _V(0,0,1), MAXMAINTH, tank,ISP);
        CreateThrusterGroup (&th_main, 1, THGROUP_MAIN);
}
2)
Code:
if(Crew.GetCrewTotalNumber()>0)
    {
        THRUSTER_HANDLE hdltwo = NULL;
        hdltwo=GetThrusterHandleByIndex(3);
        CreateThrusterGroup (hdltwo, 1, THGROUP_MAIN);     
    }
The first approach compiles but with no effect on the main thrusters and the second attempt won't even compile.

Should I been disabling the main engines in the fashion I have or am I just missing something in the reenabling?

I don't know if it's relevant but the above code is inserted into the UmmuSample.cpp that come with the UmmuSDK rather than my ship.cpp
 
A more elegant approach is to add code to your ship's clbkPreStep method (not clbkPostStep) and force all thruster levels to zero (via SetThrusterLevel) when no pilot is on board; that way you don't need to delete or recreate any thrusters. Also, to disable control for all the other controls (i.e., panel buttons) you will need to add checks to each place that reads a control and ignore the input if no pilot is on board.
 
Setting the thruster levels to zero each time step wouldn't work, because the user would be able to still use them by holding down the + button. I think your original approach (deleting the thrusters) should work fine.

Some points:

1. Make sure you recreate/delete the thruster group only one time after either the last member evas or someone comes inside the empty ship.

2. Cache the handles for the thrusters you create within your vessel object. What you are doing right now is passing false for the delete thrusters parameter for DelThrusterGroup method, which prevents the thrusters you created from being deleted. Then you create a new set of thrusters when someone comes inside the ship.

So in your class:

Code:
class MyVessel : public VESSEL2
{
 // blah blah blah

  private:
     THRUSTER_HANDLE m_th;
};

Then in clbkSetClassCaps, create the thruster like you would normally. Then you would no longer need to create/delete thrusters. You would only use the CreateThrusterGroup/DelThrusterGroup calls.
 
Ok, I've put the thruster handle in my vessel class like you said, my code looks like this at the moment:

Code:
if(Crew.GetCrewTotalNumber()==0) //disable control
    {
        sprintf(SendFocusScreenMessage(),"No Pilot Present. Control Impossible.");
        oapiSetAttitudeMode(GetHandle(),0);
        THGROUP_HANDLE hdl = NULL;
        hdl=GetThrusterGroupHandle(THGROUP_MAIN);
        DelThrusterGroup(hdl,THGROUP_MAIN,false);
    }    
        
    if(Crew.GetCrewTotalNumber()==1) //enable control
    {
        CreateThrusterGroup (&th_main, 1, THGROUP_MAIN);
    }
Which is giving me a CTD whenever there is just one person in the ship. Am I right in thinking this is because it's trying to continually create a thruster group with only one person on board?

How would I go about making it only create the group once? Do I need to nest the recontrol code within the disable code or something?
 
Depends on where in the code this is. If it's in the section that gets executed every frame, then yes. It could also be fixed with a simple boolean in this case, e.g.

if(Crew.GetCrewTotalNumber()> 0 && !ControlEnabled) //enable control
{
CreateThrusterGroup (&th_main, 1, THGROUP_MAIN);
ControlEnabled = true;
}
 
Ok, so I've tried this:

Code:
if(Crew.GetCrewTotalNumber()>0)
    {
        ControlEnabled=true;
    }

    if(Crew.GetCrewTotalNumber()==0)
    {
        sprintf(SendFocusScreenMessage(),"No Pilot Present. Control Impossible."); //disable control
        oapiSetAttitudeMode(GetHandle(),0);
        THGROUP_HANDLE hdl = NULL;
        hdl=GetThrusterGroupHandle(THGROUP_MAIN);
        DelThrusterGroup(hdl,THGROUP_MAIN,false);
        ControlEnabled=false;
        if(Crew.GetCrewTotalNumber()>0&&!ControlEnabled) //enable control
            {
                CreateThrusterGroup(&th_main, 1, THGROUP_MAIN);
                ControlEnabled=true;
            } 
    }
but I'm still not getting any main engine control when I reenter the ship from EVA, however I do get the control back if I exit and reload the scenario.

This code is within the clbkLoadStateEx function of my code, should I move it elsewhere or it's location not the problem??

Sorry for all the questions, I'm trying to read up on C++ in general and the API docs with orbiter but not sure what to look at.
 
pretty messy bits there... ;)

Code:
        if(Crew.GetCrewTotalNumber()>0&&!ControlEnabled) //enable control
            {
                CreateThrusterGroup(&th_main, 1, THGROUP_MAIN);
                ControlEnabled=true;
            }

You are having this block of code INSIDE an if-block that only gets executed if crew == 0. Since it can't be 0 and >0 at the same time, this block will NEVER get executed. Hence, you are not recreating your thruster handles.

Just rearange your code like this:

Code:
   if(Crew.GetCrewTotalNumber()>0&&!ControlEnabled) //enable control
   {
        CreateThrusterGroup(&th_main, 1, THGROUP_MAIN);
        ControlEnabled=true;
   } 
 

   else if(Crew.GetCrewTotalNumber()==0 && ControlEnabled)
    {
        sprintf(SendFocusScreenMessage(),"No Pilot Present. Control Impossible."); //disable control
        oapiSetAttitudeMode(GetHandle(),0);
        THGROUP_HANDLE hdl = NULL;
        hdl=GetThrusterGroupHandle(THGROUP_MAIN);
        DelThrusterGroup(hdl,THGROUP_MAIN,false);
        ControlEnabled=false;
     }

Kick out the first if-block, you don't need it.

This way, your thrustergroup will be created whenever you have more than one crew on board and ControlEnabled == false, which is the case only once, since ControlEnabled gets set to true right in the block.
As soon as your crew reach zero, it will be deleted again, but only once, because ControlEnabled will be false afterwards.
 
Ok, will just try that now.

Initially I didn't have the reenable control section inside the if block for disabling control but it wasn't working, I had them as two separate ifs though rather than using an else if.

Will just go see if this works, thank you very much for your help :)
 
Well I'm getting a CTD unless I embed the reenable code like I was, bear with me, I'm just setting up a barebones orbiter folder in case it's a conflict with some other addon.

Should have done that before I started developing really but hindsight is 20/20 :s

**EDIT**
On a clean install with just the SDK and the Ummu addon installed:
1) Loading a scenario with my ship in orbit it's still under full control even though empty.
2) Starting a ShuttlePB scenario and then trying to add my ship via the scenario editor results in a CTD

I am now officially confused.
 
Setting the thruster levels to zero each time step wouldn't work, because the user would be able to still use them by holding down the + button.

With all due respect, it does work because the XR vessels do just that. :)

Code:
// if crew incapacitated, temporarily (for this timestep) disable systems so ship is unflyable
if (IsCrewIncapacitatedOrNoPilotOnBoard())
{
    // kill all the engine throttles
    for (int i = 0; i < 2; i++)
    {
        SetThrusterLevel(th_scram[i], 0);
        scram_intensity[i] = 0;

        SetThrusterLevel(th_hover[i], 0);
        SetThrusterLevel(th_main[i], 0);
        SetThrusterLevel(th_retro[i], 0);
    }

    // same for RCS jets
    for (int i=0; i < 14; i++)
        SetThrusterLevel(th_rcs[i], 0);

    // turn off the RCS and airfoil systems
    SetAttitudeMode(RCS_NONE);
    SetADCtrlMode(0);

    // APU check is handled manually elsewhere

    // ATC OFF is handled at the point of crew being incapacitated; however, we must also turn ATC off here in case the scenario was just reloaded.
    SoundOptionOnOff3(GetOrbiterSoundShipID(), PLAYRADIOATC, false);  
    // cabin airflow still active
}
By doing that in the PreStep handler you will override any control inputs from the user. Of course, you still need to add manual checks for any custom panel controls you have (like the XR's MDA screen, etc.)

Of course, an alternate approach of deleting and recreating thrusters can also work, albeit less elegantly IMHO. I found it was simpler and less error-prone to just "lock down" all the systems each timestep in the PreStep handler. Just trying to help here.
 
Well I don't mind which approach I end up using, I'm very new to this so learning what's best as I go.

I will do a copy of my files and have a look at your approach too :)

I'm sure you've heard this many times but the XRs series is all kinds of fantastic.
 
unless I embed the reenable code like I was,
Well, of course you don't get a CTD if the problematic code never gets executed... ;)

Anyways, we can now exclude that the crash happens because the thruster group is created repeatedly, so it's got to do something the process of recreating the thrustergroup. I'm not familiar enough with the API itself to see if there's something fishy with that line. maybe a bad handle or somesuch...

1) Loading a scenario with my ship in orbit it's still under full control even though empty.

That would most probably be because your bool is initialised as false by default. However, if the crew is 0 and ControlEnabled is false, that means the code doesn't get executed.

That said, listen to DBeachy. I don't know practically nothin' about the Orbiter API itself, and he probably knows it by heart.
 
Well, of course you don't get a CTD if the problematic code never gets executed... ;)

Yeah, I guess that's true :D


Ok, so I've got this code now:

Code:
///////////////////////////////////////////////////////////////////////////////////////////
// clbkPreStep function of Orbiter
// -------------------------------
///////////////////////////////////////////////////////////////////////////////////////////
void LunarFerry::clbkPreStep (double SimT, double SimDT, double mjd)
{
    if (Crew.GetCrewTotalNumber()==0) 
    {
        SetAttitudeMode(RCS_NONE);
        SetADCtrlMode(0);
        SetThrusterGroupLevel(THGROUP_MAIN, 0);
        
   
    }
}
Which works to an extent, the rcs is disabled when the ship's empty, I imagine the AD is disabled ok though my ship doesn't have any to disable yet.

Halfway there on the main engine, Ctrl+ doesn't work when the ship is empty but + on it's own still does.

I had a go setting each thruster individually rather than the group as a whole but ran into problems either with compiling or CTDs. Should I try again or should this approach be working?
 
Last edited:
Ah, my apologies! I forgot about the second part that the XRs do to suppress certain Orbiter default keys. Here's what the XRs do in their clbkConsumeDirectKey method:

Code:
#define RESET_KEY_IF_INCAP(keyCode)  if (KEYDOWN(kstate, keyCode) && IsCrewIncapacitatedOrNoPilotOnBoard()) RESETKEY(kstate, keyCode)

int DeltaGliderXR1::clbkConsumeDirectKey(char *kstate)
{
    // reset Orbiter core default keys if crew incapacitated
    RESET_KEY_IF_INCAP(OAPI_KEY_ADD);
    RESET_KEY_IF_INCAP(OAPI_KEY_SUBTRACT);
    RESET_KEY_IF_INCAP(OAPI_KEY_INSERT);   // elevator trim
    RESET_KEY_IF_INCAP(OAPI_KEY_DELETE);   // elevator trim

    //...snipped code that resets other keys as necessary ...

    return 0;
}
So what you need to do in addition to the first part is add a 'RESET_KEY_IF_INCAP' macro line for every key you want to suppress when ship control is disabled. Sorry I forgot about this part the first time. :)
 
Ah ace. That is working lovely :D

I think I'm starting to get my head round some of the coding concepts, though I'lll admit I'm still largely cutting and pasting/editing rather than creating code outright but we've all got to start somewhere.

Thank you to everyone for their help.
 
Back
Top