Orbiter-Forum  

Go Back   Orbiter-Forum > Projects > ORBITER: 2010-P1 > Bug
Register Blogs Orbinauts List Social Groups FAQ Projects Mark Forums Read

CTD when deleting dock after undocking Issue Tools
issueid=921 02-12-2012 02:29 PM
shoemaker without legs
CTD when deleting dock after undocking
when deleting a docking port after a vessel has been undocked from it, Orbiter crashes

That's pretty much it, really. Some may have seen my post in the SDK thread. By now I have narrowed causes down and built a minimal code example to reproduce the ctd with the shuttle PB. All I had to throw in was another docking port (crash seems to not happen for docking port 0) and a function to delete the docking port.

To reproduce, build code below, or take built dll from here (Debug build)
-Start any scenario
-Create shuttlePB
-Dock it to DG (or anything else for that matter) with docking port 2 (you can use scenario editor for this, has no effects on the result).
-Undock
-press "c" to delete docking port.
-ctd!

EDIT: The ctd is not 100% reliable, so it might show on some machines immediately, and on others not. In any case, kuddel was so kind to make a version that does the reproduction by itself and repeats the action indefinitely to increase the chances of the ctd occuring. Download and install the ShuttlePBLoopTest_rev1.zip below in the attachments (will not overwrite your old shuttlePB), and start the included scenario.


CTD does NOT occur if other vessel is still docked to docking port 2 when deleting docking port. Dock disconnects and deletes succesfully.

ShuttlePB.cpp:

Code:
// ==============================================================
//                 ORBITER MODULE: ShuttlePB
//                  Part of the ORBITER SDK
//          Copyright (C) 2002-2004 Martin Schweiger
//                   All rights reserved
//
// ShuttlePB.cpp
// Control module for ShuttlePB vessel class
//
// Notes:
// This is an example for a "minimal" vessel implementation which
// only overloads the clbkSetClassCaps method to define vessel
// capabilities and otherwise uses the default VESSEL class
// behaviour.
// ==============================================================

#define STRICT
#define ORBITER_MODULE

#include "orbitersdk.h"

// ==============================================================
// Some vessel parameters
// ==============================================================
const double  PB_SIZE       = 3.5;             // mean radius [m]
const VECTOR3 PB_CS         = {10.5,15.0,5.8}; // x,y,z cross sections [m^2]
const VECTOR3 PB_PMI        = {2.28,2.31,0.79};// principal moments of inertia (mass-normalised) [m^2]
const VECTOR3 PB_RD         = {0.025,0.025,0.02};//{0.05,0.1,0.05};  // rotation drag coefficients
const double  PB_EMPTYMASS  = 500.0;           // empty vessel mass [kg]
const double  PB_FUELMASS   = 750.0;           // max fuel mass [kg]
const double  PB_ISP        = 5e4;             // fuel-specific impulse [m/s]
const VECTOR3 PB_TDP[3]     = {{0,-1.5,2},{-1,-1.5,-1.5},{1,-1.5,-1.5}}; // touchdown points [m]
const VECTOR3 PB_COP        = {0,0,0};//{0,0,-0.1};      // centre of pressure for airfoils [m]
const double  PB_VLIFT_C    = 2.0;             // chord length [m]
const double  PB_VLIFT_S    = 2.0;             // wing area [m^2]
const double  PB_VLIFT_A    = 2.5;             // wing aspect ratio
const double  PB_HLIFT_C    = 2.0;             // chord length [m]
const double  PB_HLIFT_S    = 1.5;             // wing area [m^2]
const double  PB_HLIFT_A    = 2.0;             // wing aspect ratio

const double  PB_MAXMAINTH  = 3e4;             
const double  PB_MAXHOVERTH = 1.5e4;
const double  PB_MAXRCSTH   = 2e2;

const VECTOR3 PB_DOCK_POS   = {0,1.3,-1};      // docking port location [m]
const VECTOR3 PB_DOCK_DIR   = {0,1,0};         // docking port approach direction
const VECTOR3 PB_DOCK_ROT   = {0,0,-1};        // docking port alignment direction

// Calculate lift coefficient [Cl] as a function of aoa (angle of attack) over -Pi ... Pi
// Implemented here as a piecewise linear function
double LiftCoeff (double aoa)
{
    int i;
    const int nlift = 9;
    static const double AOA[nlift] = {-180*RAD,-60*RAD,-30*RAD,-1*RAD,15*RAD,20*RAD,25*RAD,60*RAD,180*RAD};
    static const double CL[nlift]  = {       0,      0,   -0.1,     0,   0.2,  0.25,   0.2,     0,      0};
    static const double SCL[nlift] = {(CL[1]-CL[0])/(AOA[1]-AOA[0]), (CL[2]-CL[1])/(AOA[2]-AOA[1]),
                                      (CL[3]-CL[2])/(AOA[3]-AOA[2]), (CL[4]-CL[3])/(AOA[4]-AOA[3]),
                                      (CL[5]-CL[4])/(AOA[5]-AOA[4]), (CL[6]-CL[5])/(AOA[6]-AOA[5]),
                                      (CL[7]-CL[6])/(AOA[7]-AOA[6]), (CL[8]-CL[7])/(AOA[8]-AOA[7])};
    for (i = 0; i < nlift-1 && AOA[i+1] < aoa; i++);
    return CL[i] + (aoa-AOA[i])*SCL[i];
}

// ==============================================================
// Shuttle-PB class interface
// ==============================================================

class ShuttlePB: public VESSEL3 {
public:
    ShuttlePB (OBJHANDLE hVessel, int flightmodel);
    ~ShuttlePB ();
    void clbkSetClassCaps (FILEHANDLE cfg);
    int clbkConsumeBufferedKey(DWORD key, bool down, char *kstate);

private:
    static void vlift (VESSEL *v, double aoa, double M, double Re,
        void *context, double *cl, double *cm, double *cd);
    static void hlift (VESSEL *v, double aoa, double M, double Re,
        void *context, double *cl, double *cm, double *cd);

    // transformations for control surface animations
    static MGROUP_ROTATE trans_Laileron, trans_Raileron;
    static MGROUP_ROTATE trans_Lelevator, trans_Relevator;
    void DeleteDock();
};

ShuttlePB::ShuttlePB (OBJHANDLE hVessel, int flightmodel)
: VESSEL3 (hVessel, flightmodel)
{
}

ShuttlePB::~ShuttlePB ()
{
}

// animation transformation definitions
static UINT GRP_LWING = 2;
static UINT GRP_RWING = 3;
static VECTOR3 LWING_REF  = {-1.3,-0.725,-1.5};
static VECTOR3 LWING_AXIS = {-0.9619,-0.2735,0};
static VECTOR3 RWING_REF  = {1.3,-0.725,-1.5};
static VECTOR3 RWING_AXIS = {0.9619,-0.2735,0};
static float AILERON_RANGE = (float)(20.0*RAD);
static float ELEVATOR_RANGE = (float)(30.0*RAD);
MGROUP_ROTATE ShuttlePB::trans_Laileron (0, &GRP_LWING, 1, LWING_REF, LWING_AXIS, AILERON_RANGE);
MGROUP_ROTATE ShuttlePB::trans_Raileron (0, &GRP_RWING, 1, RWING_REF, RWING_AXIS, AILERON_RANGE);
MGROUP_ROTATE ShuttlePB::trans_Lelevator (0, &GRP_LWING, 1, LWING_REF, LWING_AXIS, -ELEVATOR_RANGE);
MGROUP_ROTATE ShuttlePB::trans_Relevator (0, &GRP_RWING, 1, RWING_REF, RWING_AXIS, ELEVATOR_RANGE);


// ==============================================================
// Overloaded callback functions
// ==============================================================

// --------------------------------------------------------------
// Set the capabilities of the vessel class
// --------------------------------------------------------------
void ShuttlePB::clbkSetClassCaps (FILEHANDLE cfg)
{
    THRUSTER_HANDLE th_main, th_hover, th_rcs[14], th_group[4];

    // physical vessel parameters
    SetSize (PB_SIZE);
    SetEmptyMass (PB_EMPTYMASS);
    SetPMI (PB_PMI);
    SetCrossSections (PB_CS);
    SetRotDrag (PB_RD);
    SetTouchdownPoints (PB_TDP[0], PB_TDP[1], PB_TDP[2]);

    // docking port definitions
    SetDockParams (PB_DOCK_POS, PB_DOCK_DIR, PB_DOCK_ROT);

    // airfoil definitions
    CreateAirfoil3 (LIFT_VERTICAL,   PB_COP, vlift, NULL, PB_VLIFT_C, PB_VLIFT_S, PB_VLIFT_A);
    CreateAirfoil3 (LIFT_HORIZONTAL, PB_COP, hlift, NULL, PB_HLIFT_C, PB_HLIFT_S, PB_HLIFT_A);

    // control surface animations
    UINT anim_Laileron = CreateAnimation (0.5);
    UINT anim_Raileron = CreateAnimation (0.5);
    UINT anim_elevator = CreateAnimation (0.5);
    AddAnimationComponent (anim_Laileron, 0, 1, &trans_Laileron);
    AddAnimationComponent (anim_Raileron, 0, 1, &trans_Raileron);
    AddAnimationComponent (anim_elevator, 0, 1, &trans_Lelevator);
    AddAnimationComponent (anim_elevator, 0, 1, &trans_Relevator);

    // aerodynamic control surface defintions
    CreateControlSurface (AIRCTRL_ELEVATOR, 1.5, 0.7, _V( 0,0,-2.5), AIRCTRL_AXIS_XPOS, anim_elevator);
    CreateControlSurface (AIRCTRL_AILERON, 1.5, 0.25, _V( 1,0,-2.5), AIRCTRL_AXIS_XPOS, anim_Laileron);
    CreateControlSurface (AIRCTRL_AILERON, 1.5, 0.25, _V(-1,0,-2.5), AIRCTRL_AXIS_XNEG, anim_Raileron);

    // propellant resources
    PROPELLANT_HANDLE hpr = CreatePropellantResource (PB_FUELMASS);

    // main engine
    th_main = CreateThruster (_V(0,0,-4.35), _V(0,0,1), PB_MAXMAINTH, hpr, PB_ISP);
    CreateThrusterGroup (&th_main, 1, THGROUP_MAIN);
    AddExhaust (th_main, 8, 1, _V(0,0.3,-4.35), _V(0,0,-1));

    PARTICLESTREAMSPEC contrail_main = {
        0, 5.0, 16, 200, 0.15, 1.0, 5, 3.0, PARTICLESTREAMSPEC::DIFFUSE,
        PARTICLESTREAMSPEC::LVL_PSQRT, 0, 2,
        PARTICLESTREAMSPEC::ATM_PLOG, 1e-4, 1
    };
    PARTICLESTREAMSPEC exhaust_main = {
        0, 2.0, 20, 200, 0.05, 0.1, 8, 1.0, PARTICLESTREAMSPEC::EMISSIVE,
        PARTICLESTREAMSPEC::LVL_SQRT, 0, 1,
        PARTICLESTREAMSPEC::ATM_PLOG, 1e-5, 0.1
    };
    AddExhaustStream (th_main, _V(0,0.3,-10), &contrail_main);
    AddExhaustStream (th_main, _V(0,0.3,-5), &exhaust_main);

    // hover engine
    th_hover = CreateThruster (_V(0,-1.5,0), _V(0,1,0), PB_MAXHOVERTH, hpr, PB_ISP);
    CreateThrusterGroup (&th_hover, 1, THGROUP_HOVER);
    AddExhaust (th_hover, 8, 1, _V(0,-1.5,1), _V(0,-1,0));
    AddExhaust (th_hover, 8, 1, _V(0,-1.5,-1), _V(0,-1,0));

    PARTICLESTREAMSPEC contrail_hover = {
        0, 5.0, 8, 200, 0.15, 1.0, 5, 3.0, PARTICLESTREAMSPEC::DIFFUSE,
        PARTICLESTREAMSPEC::LVL_PSQRT, 0, 2,
        PARTICLESTREAMSPEC::ATM_PLOG, 1e-4, 1
    };
    PARTICLESTREAMSPEC exhaust_hover = {
        0, 2.0, 10, 200, 0.05, 0.05, 8, 1.0, PARTICLESTREAMSPEC::EMISSIVE,
        PARTICLESTREAMSPEC::LVL_SQRT, 0, 1,
        PARTICLESTREAMSPEC::ATM_PLOG, 1e-5, 0.1
    };

    AddExhaustStream (th_hover, _V(0,-3, 1), &contrail_hover);
    AddExhaustStream (th_hover, _V(0,-3,-1), &contrail_hover);
    AddExhaustStream (th_hover, _V(0,-2, 1), &exhaust_hover);
    AddExhaustStream (th_hover, _V(0,-2,-1), &exhaust_hover);

    // RCS engines
    th_rcs[ 0] = CreateThruster (_V( 1,0, 3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 1] = CreateThruster (_V( 1,0, 3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 2] = CreateThruster (_V(-1,0, 3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 3] = CreateThruster (_V(-1,0, 3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 4] = CreateThruster (_V( 1,0,-3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 5] = CreateThruster (_V( 1,0,-3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 6] = CreateThruster (_V(-1,0,-3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 7] = CreateThruster (_V(-1,0,-3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 8] = CreateThruster (_V( 1,0, 3), _V(-1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 9] = CreateThruster (_V(-1,0, 3), _V( 1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[10] = CreateThruster (_V( 1,0,-3), _V(-1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[11] = CreateThruster (_V(-1,0,-3), _V( 1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[12] = CreateThruster (_V( 0,0,-3), _V(0,0, 1), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[13] = CreateThruster (_V( 0,0, 3), _V(0,0,-1), PB_MAXRCSTH, hpr, PB_ISP);

    th_group[0] = th_rcs[0];
    th_group[1] = th_rcs[2];
    th_group[2] = th_rcs[5];
    th_group[3] = th_rcs[7];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHUP);

    th_group[0] = th_rcs[1];
    th_group[1] = th_rcs[3];
    th_group[2] = th_rcs[4];
    th_group[3] = th_rcs[6];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHDOWN);

    th_group[0] = th_rcs[0];
    th_group[1] = th_rcs[4];
    th_group[2] = th_rcs[3];
    th_group[3] = th_rcs[7];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_BANKLEFT);

    th_group[0] = th_rcs[1];
    th_group[1] = th_rcs[5];
    th_group[2] = th_rcs[2];
    th_group[3] = th_rcs[6];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_BANKRIGHT);

    th_group[0] = th_rcs[0];
    th_group[1] = th_rcs[4];
    th_group[2] = th_rcs[2];
    th_group[3] = th_rcs[6];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_UP);

    th_group[0] = th_rcs[1];
    th_group[1] = th_rcs[5];
    th_group[2] = th_rcs[3];
    th_group[3] = th_rcs[7];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_DOWN);

    th_group[0] = th_rcs[8];
    th_group[1] = th_rcs[11];
    CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWLEFT);

    th_group[0] = th_rcs[9];
    th_group[1] = th_rcs[10];
    CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWRIGHT);

    th_group[0] = th_rcs[8];
    th_group[1] = th_rcs[10];
    CreateThrusterGroup (th_group, 2, THGROUP_ATT_LEFT);

    th_group[0] = th_rcs[9];
    th_group[1] = th_rcs[11];
    CreateThrusterGroup (th_group, 2, THGROUP_ATT_RIGHT);

    CreateThrusterGroup (th_rcs+12, 1, THGROUP_ATT_FORWARD);
    CreateThrusterGroup (th_rcs+13, 1, THGROUP_ATT_BACK);

    // camera parameters
    SetCameraOffset (_V(0,0.8,0));

    // associate a mesh for the visual
    AddMesh ("ShuttlePB");

    CreateDock(_V(0,-5,0),_V(0,0,-1), _V(0,1,0));
}

// ==============================================================
// Airfoil lift/drag functions
// ==============================================================

void ShuttlePB::vlift (VESSEL *v, double aoa, double M, double Re,
    void *context, double *cl, double *cm, double *cd)
{
    static const double clp[] = {  // lift coefficient from -pi to pi in 10deg steps
        -0.1,-0.5,-0.4,-0.1,0,0,0,0,0,0,0,0,0,0,-0.2,-0.6,-0.6,-0.4,0.2,0.5,0.9,0.8,0.2,0,0,0,0,0,0,0,0,0,0.1,0.4,0.5,0.3,-0.1,-0.5
    };
    static const double aoa_step = 10.0*RAD;
    double a, fidx, saoa = sin(aoa);
    a = modf((aoa+PI)/aoa_step, &fidx);
    int idx = (int)(fidx+0.5);
    *cl = clp[idx]*(1.0-a) + clp[idx+1]*a;     // linear interpolation
    *cm = 0.0; //-0.03*sin(aoa-0.1);
    *cd = 0.03 + 0.4*saoa*saoa;                // profile drag
    *cd += oapiGetInducedDrag (*cl, 1.0, 0.5); // induced drag
    *cd += oapiGetWaveDrag (M, 0.75, 1.0, 1.1, 0.04);  // wave drag
}

void ShuttlePB::hlift (VESSEL *v, double aoa, double M, double Re,
    void *context, double *cl, double *cm, double *cd)
{
    static const double clp[] = {  // lift coefficient from -pi to pi in 45deg steps
        0,0.4,0,-0.4,0,0.4,0,-0.4,0,0.4
    };
    static const double aoa_step = 45.0*RAD;
    double a, fidx;
    a = modf((aoa+PI)/aoa_step, &fidx);
    int idx = (int)(fidx+0.5);
    *cl = clp[idx]*(1.0-a) + clp[idx+1]*a;     // linear interpolation
    *cm = 0.0;
    *cd = 0.03;
    *cd += oapiGetInducedDrag (*cl, 1.5, 0.6); // induced drag
    *cd += oapiGetWaveDrag (M, 0.75, 1.0, 1.1, 0.04);  // wave drag
}

void ShuttlePB::DeleteDock()
{
    DelDock(GetDockHandle(1));
}

int ShuttlePB::clbkConsumeBufferedKey(DWORD key, bool down, char *kstate) {
    if (KEYDOWN(kstate, OAPI_KEY_C)) {
        DeleteDock();
        return 1;
    }
}

// ==============================================================
// API callback interface
// ==============================================================

// --------------------------------------------------------------
// Vessel initialisation
// --------------------------------------------------------------
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
    return new ShuttlePB (hvessel, flightmodel);
}

// --------------------------------------------------------------
// Vessel cleanup
// --------------------------------------------------------------
DLLCLBK void ovcExit (VESSEL *vessel)
{
    if (vessel) delete (ShuttlePB*)vessel;
}
Issue Details
Project ORBITER: 2010-P1
Status Unconfirmed
Priority 3
Affected Version 100830 (2010-P1)
Fixed Version (none)
Users able to reproduce bug 4
Users unable to reproduce bug 1
Assigned Users (none)
Tags (none)

02-19-2012 08:20 AM
shoemaker without legs
 
Quote:
ive tried everything i can to reproduce this but i just cant
But docking port 2 did get deleted from the ShuttlePB? In that case, this just means that we have another negative, which is just as well. We have enough positives to conclude that there's something wrong somewhere, and the negatives are pointing at undefined behavior as the cause.
Reply
02-19-2012 11:14 AM
Cynder Fan
 
nope docking port 2 did not get deleted
Reply
02-19-2012 12:19 PM
Warranty man
 
It seems you're doing something wrong. The ShuttlePB.dll file from the archive must be copied into Orbiter/Modules folder, overwriting already existing ShuttlePB.dll Now any ShuttlePB vessel will have second docking port which is invisible and quite funny-oriented, the only way to find it out is to dock ShuttlePB with any other vessel with the help of Scenario Editor by chosing Dock no.2 in the upper left corner of the Docking window. If you've extracted the .dll file correctly you'll be able to select Docks from 1 to 2. After pressing the 'c' key you'll be able to choose only Dock 1.
Reply
02-19-2012 05:40 PM
Cynder Fan
 
i have dock 2 but when i press c i still have dock 2
Reply
02-19-2012 08:18 PM
Warranty man
 
Are you focused on the ShuttlePB when pressing the c key?
Reply
02-20-2012 10:44 AM
Cynder Fan
 
yep
Reply
02-20-2012 11:37 AM
Warranty man
 
I think it is classical case of poltergeist.
Reply
08-13-2012 01:07 PM
shoemaker without legs
 
A bit of an update on this one.

It seems there is an unholy alliance between DOCKHANDLE and dockindex. Maybe that's even the cause of the whole problem, but that's speculation. Here's the facts:

The problem, as described initially, is that if a dockport was undocked, and is then deleted while the vessel that was docked to it still exists, causes an access violation. Somethig somewhere writes out of memory, which might or might not lead to a CTD, based on where the access occurs, of course.

The new state of affairs now is that this doesn't only happen if there was a vessel docked to the DOCKHANDLE being deleted, but also if there is a vessel that was docked to the port's current index. I'll try to explain in more detail with a little example, but it's going to be a bit complicated.

Assume Docking port A at index 1 port B at index 2. They are docked to Vessel VA, and VB respectively.
Then there's port C at index 3, which doesn't have a vessel docked.

VA undocks. IF I delete port A now, I'll most probably get a crash. So I delete VA, then delete port A. No problem.

Now we have Port B at index 1, and C at 2. VB is still docked to port B, which was formerly index 2, now taken by port C.

If I now go on to delete port C, which doesn't and didn't have a vessel docked, but is at index 2, to which VB was docked while B was index 2, I get a ctd.

At least as long as VB exists in the scenario.
Reply
08-13-2012 10:48 PM
Donator
 
Hi jedida,

I just took a quick overlook at your code and there are some things, that might not be right:
  1. You are not storing the return value of CreateDock() anywhere. This is the DOCKHANDLE that you have to use at later DelDock() calls.
  2. You are deleting a docking port with DelDock() and are just giving the arbitrary interger '1'! This is just as good as guessing and should not work! You have to give that method/function the HANDLE that was returned by CreateDock()!
I am pretty sure when you add a member for each DOCKHANDLEin your class and use that (correct) DOCKHANDLE at DelDock() it will give you better results.


Something like:
PHP Code:
//...somewhere at class declaration
private:
  
// ...
  
DOCKHANDLE firstDockHandle;
  
// ...


//...somewhere at initialization method

firstDockHandle CreateDock(...);




//...somewhere at docking port removal method

if (firstDockHandle!= NULL) {
   
DelDock(firstDockHandle);

The only thing I am not sure out of my memory is whether the CreateDock() method returns INVALID_HANDLE or NULL in case of failure. But that is something you have to take care of only when using that firstDockHandle (check for beeing not NULL vs. check for beeing not INVALID_HANDLE).

Again, I've just taken a very quick look at your code and that was something think is wrong. If your code is just 'pseudo-code' and you are really doing it with a stored DOCKHANDLE, you can ignore my post

/Kuddel
Reply
08-14-2012 07:35 AM
Donator
 
Hi again,

here's my proposal for changes in your code (changes are colorized)
Code:
// ==============================================================
//                 ORBITER MODULE: ShuttlePB
//                  Part of the ORBITER SDK
//          Copyright (C) 2002-2004 Martin Schweiger
//                   All rights reserved
//
// ShuttlePB.cpp
// Control module for ShuttlePB vessel class
//
// Notes:
// This is an example for a "minimal" vessel implementation which
// only overloads the clbkSetClassCaps method to define vessel
// capabilities and otherwise uses the default VESSEL class
// behaviour.
// ==============================================================

#define STRICT
#define ORBITER_MODULE

#include "orbitersdk.h"

// ==============================================================
// Some vessel parameters
// ==============================================================
const double  PB_SIZE       = 3.5;             // mean radius [m]
const VECTOR3 PB_CS         = {10.5,15.0,5.8}; // x,y,z cross sections [m^2]
const VECTOR3 PB_PMI        = {2.28,2.31,0.79};// principal moments of inertia (mass-normalised) [m^2]
const VECTOR3 PB_RD         = {0.025,0.025,0.02};//{0.05,0.1,0.05};  // rotation drag coefficients
const double  PB_EMPTYMASS  = 500.0;           // empty vessel mass [kg]
const double  PB_FUELMASS   = 750.0;           // max fuel mass [kg]
const double  PB_ISP        = 5e4;             // fuel-specific impulse [m/s]
const VECTOR3 PB_TDP[3]     = {{0,-1.5,2},{-1,-1.5,-1.5},{1,-1.5,-1.5}}; // touchdown points [m]
const VECTOR3 PB_COP        = {0,0,0};//{0,0,-0.1};      // centre of pressure for airfoils [m]
const double  PB_VLIFT_C    = 2.0;             // chord length [m]
const double  PB_VLIFT_S    = 2.0;             // wing area [m^2]
const double  PB_VLIFT_A    = 2.5;             // wing aspect ratio
const double  PB_HLIFT_C    = 2.0;             // chord length [m]
const double  PB_HLIFT_S    = 1.5;             // wing area [m^2]
const double  PB_HLIFT_A    = 2.0;             // wing aspect ratio

const double  PB_MAXMAINTH  = 3e4;
const double  PB_MAXHOVERTH = 1.5e4;
const double  PB_MAXRCSTH   = 2e2;

const VECTOR3 PB_DOCK_POS   = {0,1.3,-1};      // docking port location [m]
const VECTOR3 PB_DOCK_DIR   = {0,1,0};         // docking port approach direction
const VECTOR3 PB_DOCK_ROT   = {0,0,-1};        // docking port alignment direction

// Calculate lift coefficient [Cl] as a function of aoa (angle of attack) over -Pi ... Pi
// Implemented here as a piecewise linear function
double LiftCoeff (double aoa)
{
    int i;
    const int nlift = 9;
    static const double AOA[nlift] = {-180*RAD,-60*RAD,-30*RAD,-1*RAD,15*RAD,20*RAD,25*RAD,60*RAD,180*RAD};
    static const double CL[nlift]  = {       0,      0,   -0.1,     0,   0.2,  0.25,   0.2,     0,      0};
    static const double SCL[nlift] = {(CL[1]-CL[0])/(AOA[1]-AOA[0]), (CL[2]-CL[1])/(AOA[2]-AOA[1]),
                                      (CL[3]-CL[2])/(AOA[3]-AOA[2]), (CL[4]-CL[3])/(AOA[4]-AOA[3]),
                                      (CL[5]-CL[4])/(AOA[5]-AOA[4]), (CL[6]-CL[5])/(AOA[6]-AOA[5]),
                                      (CL[7]-CL[6])/(AOA[7]-AOA[6]), (CL[8]-CL[7])/(AOA[8]-AOA[7])};
    for (i = 0; i < nlift-1 && AOA[i+1] < aoa; i++);
    return CL[i] + (aoa-AOA[i])*SCL[i];
}

// ==============================================================
// Shuttle-PB class interface
// ==============================================================

class ShuttlePB: public VESSEL3 {
public:
    ShuttlePB (OBJHANDLE hVessel, int flightmodel);
    ~ShuttlePB ();
    void clbkSetClassCaps (FILEHANDLE cfg);
    int clbkConsumeBufferedKey(DWORD key, bool down, char *kstate);

private:
    static void vlift (VESSEL *v, double aoa, double M, double Re,
        void *context, double *cl, double *cm, double *cd);
    static void hlift (VESSEL *v, double aoa, double M, double Re,
        void *context, double *cl, double *cm, double *cd);

    // transformations for control surface animations
    static MGROUP_ROTATE trans_Laileron, trans_Raileron;
    static MGROUP_ROTATE trans_Lelevator, trans_Relevator;
    DOCKHANDLE fistDockhandle;
    void DeleteDock();
};

ShuttlePB::ShuttlePB (OBJHANDLE hVessel, int flightmodel)
: VESSEL3 (hVessel, flightmodel)
{
    fistDockhandle = NULL;
}

ShuttlePB::~ShuttlePB ()
{
    DelecteDock();
}

// animation transformation definitions
static UINT GRP_LWING = 2;
static UINT GRP_RWING = 3;
static VECTOR3 LWING_REF  = {-1.3,-0.725,-1.5};
static VECTOR3 LWING_AXIS = {-0.9619,-0.2735,0};
static VECTOR3 RWING_REF  = {1.3,-0.725,-1.5};
static VECTOR3 RWING_AXIS = {0.9619,-0.2735,0};
static float AILERON_RANGE = (float)(20.0*RAD);
static float ELEVATOR_RANGE = (float)(30.0*RAD);
MGROUP_ROTATE ShuttlePB::trans_Laileron (0, &GRP_LWING, 1, LWING_REF, LWING_AXIS, AILERON_RANGE);
MGROUP_ROTATE ShuttlePB::trans_Raileron (0, &GRP_RWING, 1, RWING_REF, RWING_AXIS, AILERON_RANGE);
MGROUP_ROTATE ShuttlePB::trans_Lelevator (0, &GRP_LWING, 1, LWING_REF, LWING_AXIS, -ELEVATOR_RANGE);
MGROUP_ROTATE ShuttlePB::trans_Relevator (0, &GRP_RWING, 1, RWING_REF, RWING_AXIS, ELEVATOR_RANGE);


// ==============================================================
// Overloaded callback functions
// ==============================================================

// --------------------------------------------------------------
// Set the capabilities of the vessel class
// --------------------------------------------------------------
void ShuttlePB::clbkSetClassCaps (FILEHANDLE cfg)
{
    THRUSTER_HANDLE th_main, th_hover, th_rcs[14], th_group[4];

    // physical vessel parameters
    SetSize (PB_SIZE);
    SetEmptyMass (PB_EMPTYMASS);
    SetPMI (PB_PMI);
    SetCrossSections (PB_CS);
    SetRotDrag (PB_RD);
    SetTouchdownPoints (PB_TDP[0], PB_TDP[1], PB_TDP[2]);

    // docking port definitions
    SetDockParams (PB_DOCK_POS, PB_DOCK_DIR, PB_DOCK_ROT);

    // airfoil definitions
    CreateAirfoil3 (LIFT_VERTICAL,   PB_COP, vlift, NULL, PB_VLIFT_C, PB_VLIFT_S, PB_VLIFT_A);
    CreateAirfoil3 (LIFT_HORIZONTAL, PB_COP, hlift, NULL, PB_HLIFT_C, PB_HLIFT_S, PB_HLIFT_A);

    // control surface animations
    UINT anim_Laileron = CreateAnimation (0.5);
    UINT anim_Raileron = CreateAnimation (0.5);
    UINT anim_elevator = CreateAnimation (0.5);
    AddAnimationComponent (anim_Laileron, 0, 1, &trans_Laileron);
    AddAnimationComponent (anim_Raileron, 0, 1, &trans_Raileron);
    AddAnimationComponent (anim_elevator, 0, 1, &trans_Lelevator);
    AddAnimationComponent (anim_elevator, 0, 1, &trans_Relevator);

    // aerodynamic control surface defintions
    CreateControlSurface (AIRCTRL_ELEVATOR, 1.5, 0.7, _V( 0,0,-2.5), AIRCTRL_AXIS_XPOS, anim_elevator);
    CreateControlSurface (AIRCTRL_AILERON, 1.5, 0.25, _V( 1,0,-2.5), AIRCTRL_AXIS_XPOS, anim_Laileron);
    CreateControlSurface (AIRCTRL_AILERON, 1.5, 0.25, _V(-1,0,-2.5), AIRCTRL_AXIS_XNEG, anim_Raileron);

    // propellant resources
    PROPELLANT_HANDLE hpr = CreatePropellantResource (PB_FUELMASS);

    // main engine
    th_main = CreateThruster (_V(0,0,-4.35), _V(0,0,1), PB_MAXMAINTH, hpr, PB_ISP);
    CreateThrusterGroup (&th_main, 1, THGROUP_MAIN);
    AddExhaust (th_main, 8, 1, _V(0,0.3,-4.35), _V(0,0,-1));

    PARTICLESTREAMSPEC contrail_main = {
        0, 5.0, 16, 200, 0.15, 1.0, 5, 3.0, PARTICLESTREAMSPEC::DIFFUSE,
        PARTICLESTREAMSPEC::LVL_PSQRT, 0, 2,
        PARTICLESTREAMSPEC::ATM_PLOG, 1e-4, 1
    };
    PARTICLESTREAMSPEC exhaust_main = {
        0, 2.0, 20, 200, 0.05, 0.1, 8, 1.0, PARTICLESTREAMSPEC::EMISSIVE,
        PARTICLESTREAMSPEC::LVL_SQRT, 0, 1,
        PARTICLESTREAMSPEC::ATM_PLOG, 1e-5, 0.1
    };
    AddExhaustStream (th_main, _V(0,0.3,-10), &contrail_main);
    AddExhaustStream (th_main, _V(0,0.3,-5), &exhaust_main);

    // hover engine
    th_hover = CreateThruster (_V(0,-1.5,0), _V(0,1,0), PB_MAXHOVERTH, hpr, PB_ISP);
    CreateThrusterGroup (&th_hover, 1, THGROUP_HOVER);
    AddExhaust (th_hover, 8, 1, _V(0,-1.5,1), _V(0,-1,0));
    AddExhaust (th_hover, 8, 1, _V(0,-1.5,-1), _V(0,-1,0));

    PARTICLESTREAMSPEC contrail_hover = {
        0, 5.0, 8, 200, 0.15, 1.0, 5, 3.0, PARTICLESTREAMSPEC::DIFFUSE,
        PARTICLESTREAMSPEC::LVL_PSQRT, 0, 2,
        PARTICLESTREAMSPEC::ATM_PLOG, 1e-4, 1
    };
    PARTICLESTREAMSPEC exhaust_hover = {
        0, 2.0, 10, 200, 0.05, 0.05, 8, 1.0, PARTICLESTREAMSPEC::EMISSIVE,
        PARTICLESTREAMSPEC::LVL_SQRT, 0, 1,
        PARTICLESTREAMSPEC::ATM_PLOG, 1e-5, 0.1
    };

    AddExhaustStream (th_hover, _V(0,-3, 1), &contrail_hover);
    AddExhaustStream (th_hover, _V(0,-3,-1), &contrail_hover);
    AddExhaustStream (th_hover, _V(0,-2, 1), &exhaust_hover);
    AddExhaustStream (th_hover, _V(0,-2,-1), &exhaust_hover);

    // RCS engines
    th_rcs[ 0] = CreateThruster (_V( 1,0, 3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 1] = CreateThruster (_V( 1,0, 3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 2] = CreateThruster (_V(-1,0, 3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 3] = CreateThruster (_V(-1,0, 3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 4] = CreateThruster (_V( 1,0,-3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 5] = CreateThruster (_V( 1,0,-3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 6] = CreateThruster (_V(-1,0,-3), _V(0, 1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 7] = CreateThruster (_V(-1,0,-3), _V(0,-1,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 8] = CreateThruster (_V( 1,0, 3), _V(-1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[ 9] = CreateThruster (_V(-1,0, 3), _V( 1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[10] = CreateThruster (_V( 1,0,-3), _V(-1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[11] = CreateThruster (_V(-1,0,-3), _V( 1,0,0), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[12] = CreateThruster (_V( 0,0,-3), _V(0,0, 1), PB_MAXRCSTH, hpr, PB_ISP);
    th_rcs[13] = CreateThruster (_V( 0,0, 3), _V(0,0,-1), PB_MAXRCSTH, hpr, PB_ISP);

    th_group[0] = th_rcs[0];
    th_group[1] = th_rcs[2];
    th_group[2] = th_rcs[5];
    th_group[3] = th_rcs[7];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHUP);

    th_group[0] = th_rcs[1];
    th_group[1] = th_rcs[3];
    th_group[2] = th_rcs[4];
    th_group[3] = th_rcs[6];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHDOWN);

    th_group[0] = th_rcs[0];
    th_group[1] = th_rcs[4];
    th_group[2] = th_rcs[3];
    th_group[3] = th_rcs[7];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_BANKLEFT);

    th_group[0] = th_rcs[1];
    th_group[1] = th_rcs[5];
    th_group[2] = th_rcs[2];
    th_group[3] = th_rcs[6];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_BANKRIGHT);

    th_group[0] = th_rcs[0];
    th_group[1] = th_rcs[4];
    th_group[2] = th_rcs[2];
    th_group[3] = th_rcs[6];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_UP);

    th_group[0] = th_rcs[1];
    th_group[1] = th_rcs[5];
    th_group[2] = th_rcs[3];
    th_group[3] = th_rcs[7];
    CreateThrusterGroup (th_group, 4, THGROUP_ATT_DOWN);

    th_group[0] = th_rcs[8];
    th_group[1] = th_rcs[11];
    CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWLEFT);

    th_group[0] = th_rcs[9];
    th_group[1] = th_rcs[10];
    CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWRIGHT);

    th_group[0] = th_rcs[8];
    th_group[1] = th_rcs[10];
    CreateThrusterGroup (th_group, 2, THGROUP_ATT_LEFT);

    th_group[0] = th_rcs[9];
    th_group[1] = th_rcs[11];
    CreateThrusterGroup (th_group, 2, THGROUP_ATT_RIGHT);

    CreateThrusterGroup (th_rcs+12, 1, THGROUP_ATT_FORWARD);
    CreateThrusterGroup (th_rcs+13, 1, THGROUP_ATT_BACK);

    // camera parameters
    SetCameraOffset (_V(0,0.8,0));

    // associate a mesh for the visual
    AddMesh ("ShuttlePB");

    fistDockhandle = CreateDock(_V(0,-5,0),_V(0,0,-1), _V(0,1,0));
}

// ==============================================================
// Airfoil lift/drag functions
// ==============================================================

void ShuttlePB::vlift (VESSEL *v, double aoa, double M, double Re,
    void *context, double *cl, double *cm, double *cd)
{
    static const double clp[] = {  // lift coefficient from -pi to pi in 10deg steps
        -0.1,-0.5,-0.4,-0.1,0,0,0,0,0,0,0,0,0,0,-0.2,-0.6,-0.6,-0.4,0.2,0.5,0.9,0.8,0.2,0,0,0,0,0,0,0,0,0,0.1,0.4,0.5,0.3,-0.1,-0.5
    };
    static const double aoa_step = 10.0*RAD;
    double a, fidx, saoa = sin(aoa);
    a = modf((aoa+PI)/aoa_step, &fidx);
    int idx = (int)(fidx+0.5);
    *cl = clp[idx]*(1.0-a) + clp[idx+1]*a;     // linear interpolation
    *cm = 0.0; //-0.03*sin(aoa-0.1);
    *cd = 0.03 + 0.4*saoa*saoa;                // profile drag
    *cd += oapiGetInducedDrag (*cl, 1.0, 0.5); // induced drag
    *cd += oapiGetWaveDrag (M, 0.75, 1.0, 1.1, 0.04);  // wave drag
}

void ShuttlePB::hlift (VESSEL *v, double aoa, double M, double Re,
    void *context, double *cl, double *cm, double *cd)
{
    static const double clp[] = {  // lift coefficient from -pi to pi in 45deg steps
        0,0.4,0,-0.4,0,0.4,0,-0.4,0,0.4
    };
    static const double aoa_step = 45.0*RAD;
    double a, fidx;
    a = modf((aoa+PI)/aoa_step, &fidx);
    int idx = (int)(fidx+0.5);
    *cl = clp[idx]*(1.0-a) + clp[idx+1]*a;     // linear interpolation
    *cm = 0.0;
    *cd = 0.03;
    *cd += oapiGetInducedDrag (*cl, 1.5, 0.6); // induced drag
    *cd += oapiGetWaveDrag (M, 0.75, 1.0, 1.1, 0.04);  // wave drag
}

void ShuttlePB::DeleteDock()
{
    if (fistDockhandle != NULL) {
        DelDock(fistDockhandle);
        fistDockhandle = NULL;
    }
}

int ShuttlePB::clbkConsumeBufferedKey(DWORD key, bool down, char *kstate) {
    if (KEYDOWN(kstate, OAPI_KEY_C)) {
        DeleteDock();
        return 1;
    }
}

// ==============================================================
// API callback interface
// ==============================================================

// --------------------------------------------------------------
// Vessel initialisation
// --------------------------------------------------------------
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
    return new ShuttlePB (hvessel, flightmodel);
}

// --------------------------------------------------------------
// Vessel cleanup
// --------------------------------------------------------------
DLLCLBK void ovcExit (VESSEL *vessel)
{
    if (vessel) delete (ShuttlePB*)vessel;
}
Note, that I have not compiled that code, but I'm pretty sure that the CTD should not be present afterwards.

A side-node on your use of GetDockHandle() and DelDock(). I think this "pair" of methods is meant to be used in loops like this:
PHP Code:
for (UINT idx=0idx<DockCount(); ++idx) {
  if (
GetDockHandle(idx) != NULL) { // not neccessary I think, but let's play it save
    
DelDock(idx);
  }

I am not sure how those DOCJHANDLES are managed iside Orbiter-Core, but I would never assume that index 1 is valid per se.
Although you might have created 2 Docks (index 0 and 1), after you delete the first Dock (index 0) I would not assume that the other Dock would still stay at index 1! It could have been 'shifted' to the internal index 0 by the core (to save memory e.g.).
When I think about it, I am pretty sure that that must be the case, because the GetDockCount() should return 1 in that case and if the indices would not have been shifted/packed, the loop (see above) would not iterate through the second Dock!

/Kuddel
Reply
08-14-2012 09:03 AM
shoemaker without legs
 
Thanks for your input, but this was a quick and dirty repro. Yes, it would have been better to pass the DOCKHANDLE, but I didn't have much time and didn't think it over. The fact is that in these narrow circumstances it doesn't make any difference, since I know that the Dock I am deleting is indeed Index 1.

In the code where it actually matters, this is handled differently of course, but for the sake of a short repro, this works just as well.
Reply
08-14-2012 11:09 AM
Donator
 
Quote:
Originally Posted by jedidia
 The fact is that in these narrow circumstances it doesn't make any difference, since I know that the Dock I am deleting is indeed Index 1.
Are your sure? I don't see any reason why you should assume that!

Even if you place for example these two CreateDock() calls:
PHP Code:
  CreateDock(_V(0,-5,0),_V(0,0,-1), _V(0,1,0)); // first
  
CreateDock(_V(05,0),_V(0,01), _V(0,1,0)); // second 
You can not assume anything of the indexes of them!
You can not assure, that the first docking-port has index 0 and
you can not assure that the second docking port has index 1!
It is very propabble, but not sure!


Quote:
Originally Posted by jedidia
  In the code where it actually matters, this is handled differently of course, but for the sake of a short repro, this works just as well.
Yes it creates a CTD But the "shortened version" has that problem I've described.
You should always keep the Handle(s) returned by CreateDock() when you have to access 'em individually.

/Kuddel
Reply
08-14-2012 11:33 AM
Donator
 
I've just attached (see ShuttlePB.zip below) a working (not crashing) version of your
example.
When you debug the code you will see, that e.g. DockCount() returns 3 at destruction. So the indices are 0, 1 and 2. Nevertheless, what's important is, that I use the stored handles, to access one specific docking port!
Reply
08-14-2012 02:35 PM
shoemaker without legs
 
Negative, ctd unaffected. Docking ports are zero-indexed internally (only scenario editor writes them as one-indexed), and one docking port is already defined in ShuttlePB config, so by creating two docking ports, you have three of them, with the handle being deleted pointing to docking index 2, which in scenario editor would be 3. Ergo, you need to dock something to port 3 in scenario editor with your build, not to two as with mine. The important thing is that the dockhandle gets deleted that has previously been docked, and the CTD still happens with your example when I do it this way (On my machine, I have 100% repro, but since we're talking undefined behavior here, your mileage may vary).

Quote:
You can not assume anything of the indexes of them!
Sure you can. They're either handled in an Array or more probably a vector internally. Anything else but adding them to the end of it would be very tedious and have no practical advantage. For all it's worth, I've been working with creating and deleting docking ports for the last six months now, I haven't seen a single instance where the newest created docking port was not the highest index, and I am generally aware that I cannot identify a docking port by its index if I constantly delete and create them, because they'll be moving downwards in the vector over time.

I appreciate your help, but I've been over this problem a dozen times. I found workarounds for some instances where it causes a ctd in my code, but it's still not really stable. This example is about as clear a repro of an Orbiter bug as you can get, with any other potentially responsible processes well out of the way.
Reply
08-14-2012 03:09 PM
shoemaker without legs
 
I did a short little experiment with your build to illustrate the problem with indices I explained a few posts above:

If I change your code to delete firstHandle, and then dock something to Docking port 3 (secondHandle), then delete firstHandle without undocking secondHandle first, I also get a ctd.

Something that makes me suspicious is that almost everything docking related in Orbiter is done via DOCKHANDLES, except docking and undocking, where you have to pass indices. It seems completely counter-intuitive, but is it possible that a vessel stores its docking relations using the partners dockindex instead of the handle, and for some reason retains that index after undocking, until it is docked to another one? It would explain the trouble, but it would seem a somewhat unwieldy way to handle things. Also, attachment points which are handled very similarly, don't have this problem.
Reply
08-14-2012 08:47 PM
Donator
 
Quote:
Originally Posted by jedidia
 I did a short little experiment with your build to illustrate the problem with indices I explained a few posts above:

If I change your code to delete firstHandle, and then dock something to Docking port 3 (secondHandle), then delete firstHandle without undocking secondHandle first, I also get a ctd.
O.K. deleting a docking port before you've undocked anything from it might cause a CDT, but I am not sure


Quote:
Originally Posted by jedidia
 Something that makes me suspicious is that almost everything docking related in Orbiter is done via DOCKHANDLES, except docking and undocking, where you have to pass indices.
This is because you don't have a HANDLE to the target docking port.
But your're right, a method with a "source"-DOCKHANDLE and a "target"-Index might be nice.

--- edit ---
Have you noticed the note in the API description of Dock()?
Quote:
This function is useful for designing scenario editors and during
startup configuration, but its use should be avoided during a
running simulation, because it can lead to unphysical situations:
it allows to dock two vessels regardless of their current
separation, by teleporting one of them to the location of the other.

--- edit-end ---


Quote:
Originally Posted by jedidia
 It seems completely counter-intuitive, but is it possible that a vessel stores its docking relations using the partners dockindex instead of the handle, and for some reason retains that index after undocking, until it is docked to another one? It would explain the trouble, but it would seem a somewhat unwieldy way to handle things. Also, attachment points which are handled very similarly, don't have this problem.
The inices of the Docking Ports have to be 0-indexed and non-sparse (no empty indices)!
If that would not be the case you could not iterate over all docking ports via DockCount() and GetDockHandle(int)!

What might be the problem is, that one might delete a port via index and then try to delete that port again using a stored DOCKHANDLE.
Example:
PHP Code:
// assume there is no other docking port created before
// ...so DockCount() == 0 !
DOCKHANDLE a CreateDock(...);
DOCKHANDLE b CreateDock(...);
// DockCount() == 2 now
DelDock(GetDockHandle(0));
// DockCount() == 1 now!

DelDock(a); // this might fail, 'cause we've already deleted that one! 
by the way, my second attachment contains an example where each hit on the 'C' key deletes the docking port with index 0 (until there's no more dock left). The 'V' key lets you easily see that the DockCount() and the indexing is like I've described.
By the way I am using Orbiter v111105 maybe that makes a difference?!

/Kuddel
Reply
08-14-2012 09:19 PM
Donator
 
Quote:
Originally Posted by kuddel
 By the way I am using Orbiter v111105 maybe that makes a difference?!
Update! I've tried my ShuttlePB2 with Orbiter 100830 (2010-P1) and could not get any CTD.
By the way, you can also see the "re-"indexing when you have opened the "Object Info" window while tappin' the 'C' key. Although in that window the indices are 1-based, not 0-based. But that's just the output. C-Arrays are allways 0-based.

/Kuddel

P.S.: The project files in my ZIP (ShuttlePB2.zip) might create the module at c:\source\orbiter\... A relict of the Doc (a.k.a martins)
--- edit ---
The third attachment (ShuttlePB2-rev2.zip) should fix that.
--- edit-end ---
Reply
08-14-2012 09:59 PM
shoemaker without legs
 
Quote:
O.K. deleting a docking port before you've undocked anything from it might cause a CDT, but I am not sure
Nope, it works better than undocking first and then deleting, which does produce a ctd, as described.

Also, in that example I didn't delete the port the vessel was docked to. I deleted the port right in "front" of it, which was empty.

Quote:
This function is useful for designing scenario editors and during
startup configuration, but its use should be avoided during a
running simulation, because it can lead to unphysical situations:
it allows to dock two vessels regardless of their current
separation, by teleporting one of them to the location of the other.
This doesn't matter for my purposes, which are a bit... shall we say, unorthodox. It doesn't change the fact that a ctd when deleting a docking port after undocking a vessel from it is a bug.

Quote:
The inices of the Docking Ports have to be 0-indexed and non-sparse (no empty indices)!
I know. I was trying to explain why you might not have experienced a ctd when you tried it: You didn't delete the docking port the vessel just undocked from, if you docked it docking port 2 in scenario editor as described in the repro instructions and then pressed c, because that would have deleted port 3.

Quote:
What might be the problem is, that one might delete a port via index and then try to delete that port again using a stored DOCKHANDLE.
Nope. I always delete by handle, as my indices are in constant flux from creating and deleting docking ports, and therefore utterly useless for any sort of identification. As I said, I did the shuttlePB example as quick and dirty repro to demonstrate the problem. Which it does.

Quote:
The 'V' key lets you easily see that the DockCount() and the indexing is like I've described.
I never claimed anything different. I think we had a little misunderstanding here.

Quote:
Update! I've tried my ShuttlePB2 with Orbiter 100830 (2010-P1) and could not get any CTD.
As I said, it is undefined behavior. We had some machines on which the crash reproduced reliably, one on which it didn't at all, and some on which it did sometimes, sometimes not. This issue won't get cleared up until martin runs the thng through the debugger and sees if there's a memory exception happening somewhere.

Still, I'll try your newest example tomorrow. Time to go to bed now...
Reply
08-14-2012 10:24 PM
Donator
 
Hi jedida,

thank you for your information. I was not trying to teach you something that you already know, but I didn't know your level of experience. Sorry if my posts sounded like that.
(and sometimes the most obvious things are overlooked... at least I tend to do that )

O.K. back to topic:

When this is a problem that does not always appear (different machines, different times, etc...) it makes it more difficult to track, hmmm.
I've only tried this dock-undock-delete sequence a couple of times, apparently not often enough

Is it possible to create a scenario + module which
- creates a dock...
- docks to another (known) vehicle and port...
- undocks...
- delete that dock
in an endless loop?
This "Test-Scenario" might increase the probability a lot.
Maybe we can base this setup on my package.

Good night,
Kuddel
Reply
08-15-2012 04:30 AM
shoemaker without legs
 
Quote:
thank you for your information. I was not trying to teach you something that you already know, but I didn't know your level of experience. Sorry if my posts sounded like that.
No problem, I've just been a bit tired yesterday.

Quote:
Is it possible to create a scenario + module which
- creates a dock...
- docks to another (known) vehicle and port...
- undocks...
- delete that dock
in an endless loop?
This "Test-Scenario" might increase the probability a lot.
Nice idea, will do.
Reply
Reply

Issue Tools
Subscribe to this issue

All times are GMT. The time now is 09:11 PM.

Quick Links Need Help?


About Us | Rules & Guidelines | TOS Policy | Privacy Policy

Orbiter-Forum is hosted at Orbithangar.com
Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.
Copyright ©2007 - 2012, Orbiter-Forum.com. All rights reserved.