C++ Question Extending OrbConnect to Other Vessels

markl316

XR2 Ravenstar Commander
Addon Developer
Tutorial Publisher
Joined
Mar 30, 2008
Messages
450
Reaction score
1
Points
18
Hi all,
It’s been a while, due to real life responsibilities, but I’m back, and am starting to get into coding my own vessels. I’m specifically interested in extending the ability of OrbConnect to my vessel in the same manner that it has been extended to XR vessels, so that I can command certain aspects of my vessel via OrbConnect and one day build a simpit.

As a very simple example to get my feet wet, I tried to add into OrbConnect a “ShuttleA API” similar to the XR Control API written by Doug, with two functions: one to extend the landing gear, and another to retract it. Like the “XCTL” prefix which is used for using OrbConnect with an XR vessel, I would extend and retract the landing gear in ship SH-01 by entering into the OrbConnect JAVA client, respectively:
SHA:SH-01:EXTENDLANDINGGEAR
SHA:SH-01:RETRACTLANDINGGEAR

Please forgive my copy paste approach, as I'm no expert C++ programmer. If there'a a better way to do this, I'm certainly open to that.

Starting with the source code available at [ame="http://orbithangar.com/searchid.php?ID=5824"]Orb:Connect v2.1 Project files[/ame], I downloaded, extracted, compiled source code, copied over to Orbiter, and verified functionality (so I know what I’m starting with is working). I did have to make one change: line 347, I changed the end from string.npos to string::npos (not sure why my compiler didn’t like the former).

I then made the following additions to the OrbConnect code base, basing off of the XR Control code, in an attempt to create a very basic “ShuttleA Control API” that only has two functions: one to raise the landing gear, and another to retract it.

Changes to OrbConnect.cpp:
1. Added to line 53:
Code:
ShuttleACtlCommandParser shaCtrlParser; // ShuttleA Addition
2. Added into the parseCommandID function, around line 90:
Code:
else if ("SHA" == area) // Begin ShuttleA Addition
	{
		SendText(lParam, IDstring, shaCtrlParser.parse(lParam, Command));
	} // End ShuttleA Addition
3. Added into parseCommand function, around line 150:
Code:
else if ("SHA" == area) // Begin ShuttleA Addition
	{
		SendText(lParam, Command, shaCtrlParser.parse(lParam, Command));
	} // End ShuttleA Addition



Changes to OrbConnect.h:
1. Added to the top, around line 13:
Code:
#include "ShuttleACtlCommandParser.h"
2. Added the initialization of shaCtrlParser around line 63:
Code:
extern ShuttleACtlCommandParser shaCtrlParser; // ShuttleA Addition



Then I created three new files (again based off of the XR Control API):
File ShuttleAVesselCtrl.h:
Code:
//ShuttleAVesselCtrl.h

#pragma once
#include "orbitersdk.h"

class ShuttleAVesselCtrl : public VESSEL3
{
public:

	// Constructor
	ShuttleAVesselCtrl(OBJHANDLE vessel, int fmodel) : VESSEL3(vessel, fmodel) { }

	// Pure virtual functions to retract the landing gear
	virtual void RevertLandingGear() = 0;
}; 



File ShuttleACtlCommandParser.h:
Code:
// File ShuttleACtlCommandParser.h

#ifndef _SHUTTLEACTL_COMMAND_PARSER_H
#define _SHUTTLEACTL_COMMAND_PARSER_H
#define VSEXPRESS 1

#include "VesselCommandParser.h"
#include "ShuttleAVesselCtrl.h"


using namespace std;

class ShuttleACtlCommandParser : public VesselCommandParser 
{
public:
	string parse(long lparam, string command);
};

string StowLandingGear(ShuttleAVesselCtrl * pVessel);



#endif



File: ShuttleACtlCommandParser.cpp
Here I'm assuming that a SHA:___ command will always be sent when the vessel of focus is a ShuttleA, so no need to check to make sure the vessel in focus is a ShuttleA (I don't think).
Code:
// File: ShuttleACtlCommandParser.cpp
#include "ShuttleACtlCommandParser.h"

string ShuttleACtlCommandParser::parse(long lParam, string command) {
	string message = "ERR02";
	bool found = false;
	VESSEL2* pVessel = 0;
	ShuttleAVesselCtrl* pShuttleAVessel;

	vector<string> tokens = stringSplit(command, ":");

	message = loadVessel(&pVessel, tokens);
	if (0 == pVessel) {
		return "ERR05";
	}


	pShuttleAVessel = (ShuttleAVesselCtrl*)pVessel;
	if (0 == pShuttleAVessel) {
		return "ERR07";
	}

	string cmd = uCase(tokens.at(2));


	if ("RETRACTLANDINGGEAR" == cmd)
	{
		message = StowLandingGear(pShuttleAVessel);
	}

	else
	{
		message = "ERR99";
	}

	return message;

}




string StowLandingGear(ShuttleAVesselCtrl *pVessel) {
	pVessel->RevertLandingGear(); // Function RevertLandingGear is defined in ShuttleA.cpp
	return "OK";
}
 


I then compiled OrbConnect successfully, and transferred the module over to Orbiter\Modules\Plugin, and activated it. The first problem is that I’m unable to send commands via the client; sending command “SHA:SH-15:RETRACTLANDINGGEAR” in the "ISS Approach" scenario caused Orbiter to crash.

The second issue is more bizarre: the very first time I transfer the newly compiled .dll into the Modules\Plugin folder, the client loads successfully with Orbiter running. All subsequent times I try to open the JAVA client while Orbiter is running, it immediately causes Orbiter to freeze, and the only way to get the client to load again with Orbiter running is to deactivate OrbConnect from the Modules tab in the Launchpad, delete the .dll file from the Modules\Plugin folder, re-copy a fresh copy over, then go into the Modules tab in the Launchpad and reactivate it.


If there's anybody who would be able to point me in the right direction here that would be great!
 
Last edited:

kamaz

Unicorn hunter
Addon Developer
Joined
Mar 31, 2012
Messages
2,298
Reaction score
4
Points
0
Hi,

1. First off get the newest version of Orb::Connect: [ame="http://www.orbithangar.com/searchid.php?ID=6435"]Orb::Connect::Web 3.19[/ame]. This build, in addition to adding HTTP server, also fixes some bugs the old version had. (You can still use the old socket interface, no problem).

2. Install orbiter in c:\orbiterDEV\orbiter100830

3. Install the add-on from the zip downloaded in step 1. (Take files out of the OrbConnect-3.19 directory into Orbiter root).

4. Run Orbiter and familiarize yourself with new features :)

5. Replace c:\orbiterDEV\orbiter100830\orbitersdk\samples\orbconnect\orbconnect\orbconnect.xcvproj.user with the following:

Code:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LocalDebuggerCommand>c:\orbiterDEV\orbiter100830\orbiter.exe</LocalDebuggerCommand>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LocalDebuggerCommandArguments />
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LocalDebuggerWorkingDirectory>c:\orbiterDEV\orbiter100830\</LocalDebuggerWorkingDirectory>
    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LocalDebuggerCommand>c:\orbiterDEV\orbiter100830\orbiter.exe</LocalDebuggerCommand>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LocalDebuggerWorkingDirectory>c:\orbiterDEV\orbiter100830</LocalDebuggerWorkingDirectory>
    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
  </PropertyGroup>
</Project>

(that replaces references to c:\orbiterDEV2 directory with c:\orbiterDEV. Because my development environment was messed up.)

6. Launch c:\orbiterDEV\orbiter100830\orbitersdk\samples\OrbConnect.sln.

7. Switch to "Debug" configuration, build the project.

8. Press the "Run" icon. It should start Orbiter under Visual Studio debugger so when it crashes the debugger will open showing you where it crashed.
 
Last edited:

markl316

XR2 Ravenstar Commander
Addon Developer
Tutorial Publisher
Joined
Mar 30, 2008
Messages
450
Reaction score
1
Points
18
Great instructions...Looks like it's making it all the way to when it tries to call RevertLandingGear() in the StowLandingGear function in ShuttleACtlCommandParser.cpp at the line:

Code:
pVessel->RevertLandingGear(); // Function RevertLandingGear is defined in ShuttleA.cpp

I got the following error message:
Unhandled exception at 0xbfeccccc in orbiter.exe: 0xC0000005: Access violation reading location 0xbfeccccc.

I'm assuming this has something to do with not being able to access the function RevertLandingGear in the ShuttleA class, though I'm not exactly sure where to go from here.... :(. Any help would be greatly appreciated.
 
Last edited:

kamaz

Unicorn hunter
Addon Developer
Joined
Mar 31, 2012
Messages
2,298
Reaction score
4
Points
0
Um.

In the Shuttle-A module, what does the vessel creation function actually return?

For your trick to work it must return ShuttleAVesselCtrl* , and not "pure" VESSEL3.

Otherwise you are trying to call a ShuttleAVesselCtrl method on VESSEL3 object which obviously will not work (because VESSEL3 does not have the methods you are trying to call).
 
Last edited:

markl316

XR2 Ravenstar Commander
Addon Developer
Tutorial Publisher
Joined
Mar 30, 2008
Messages
450
Reaction score
1
Points
18
Um.

In the Shuttle-A module, what does the vessel creation function actually return?

For your trick to work it must return ShuttleAVesselCtrl* , and not "pure" VESSEL3.

Otherwise you are trying to call a ShuttleAVesselCtrl method on VESSEL3 object which obviously will not work (because VESSEL3 does not have the methods you are trying to call).


Hmm...I'm not sure I follow. The constructor in ShuttleA.cpp doesn't return anything:
Code:
ShuttleA::ShuttleA (OBJHANDLE hObj, int fmodel)
: VESSEL3 (hObj, fmodel)
{
	int i;
	dock_proc = 0.0;
	dock_status = DOOR_CLOSED;
	lock_proc = 0.0;
	lock_status = DOOR_CLOSED;
	gear_proc = 0.0;
	gear_status = DOOR_CLOSED;
	DefineAnimations ();
	for (i = 0; i < nsurf; i++)
		srf[i] = 0;
	for (i = 0; i < 2; i++) {
		pod_angle[i] = pod_angle_request[i] = 0.0;
	};
	for (i = 0; i < 6; i++) {
		cargo_open[i]=0;	//not opened. not jettisoned
	cargo_arm_status = 0;	//not armed
	}
}


I did try something slightly different as well: I included my file (defined in my first post) "ShuttleAVesselCtrl.h" in ShuttleA.h, and changed the class definition of ShuttleA in ShuttleA.h such that class ShuttleA is now derived from base class "ShuttleAVesselCtrl" instead of base class "VESSEL3" so the tree goes:

Base class: VESSEL3
ShuttleAVesselCtrl: derived from class VESSEL3
ShuttleA: derived from class ShuttleAVesselCtrl

So in ShuttleA.h the class definition reads:
Code:
#ifndef __SHUTTLEA_H
#define __SHUTTLEA_H

#include "orbitersdk.h"
#include "ShuttleAVesselCtrl.h"

....
....

class ShuttleA: public ShuttleAVesselCtrl {
public:
	ShuttleA (OBJHANDLE hObj, int fmodel);
	~ShuttleA ();
......

And the constructor in ShuttleA.cpp reads:
Code:
ShuttleA::ShuttleA (OBJHANDLE hObj, int fmodel)
: ShuttleAVesselCtrl (hObj, fmodel)
{
	int i;
        ....
        ....

ShuttleA compiles and successfully runs in Orbiter, but unfortunately I still get the same error as before when trying to use OrbConnect.
 

Hielor

Defender of Truth
Donator
Beta Tester
Joined
May 30, 2008
Messages
5,580
Reaction score
2
Points
0
First off:
Here I'm assuming that a SHA:___ command will always be sent when the vessel of focus is a ShuttleA, so no need to check to make sure the vessel in focus is a ShuttleA (I don't think).
This is a bad assumption to make. You should definitely do something to ensure you don't crash when a SHA: is sent without a ShuttleA being in focus.

Further, rather than directly making a new API for your vessel and consuming that, wouldn't it be easier to just use the vessel communication function that's already defined on VESSEL3? (can't remember what it's called off the top of my head, it lets you pass messages around).

You could have your vessel respond to an incoming message of that type with the appropriate parameters by retracting the gear, and then you could program Orb:Connect to convert the SHA command into that message.
 

kamaz

Unicorn hunter
Addon Developer
Joined
Mar 31, 2012
Messages
2,298
Reaction score
4
Points
0
Hmm...I'm not sure I follow.

Because you don't understand how Orbiter works.

On vessel creation (oapiCreateVessel()) the core will call ovcInit() function in the vessel's module to create the object representing the vessel (derived from class VESSEL). This object is then being passed around in Orbiter.

Thus in ShuttleA.cpp you have:

Code:
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
	return new ShuttleA (hvessel, flightmodel);
}

Orb::Connect retrieves a pointer to the VESSEL object oapiGetVesselInterface() and that pointer is what you have in pVessel variable. So the solution is obviously to make ovcInit() return an instance of ShuttleACtrl.

Another issue is that I cannot figure out if your inheritance goes

VESSEL3 < ShuttleACtrl < ShuttleA

or

VESSEL3 < ShuttleA < ShuttleACtrl

---------- Post added at 10:27 PM ---------- Previous post was at 10:21 PM ----------

Also, two words of advice.

First, in Orb::Connect you should have Log module. Use it.

Second, use this pattern:

In ShuttleA.cpp:
Code:
[b]#define SHUTTLEA_MAGIC 0xdeadbeef[/b]

class ShuttleAVesselCtrl : public VESSEL3
{
public:
[b]       int magic = SHUTTLEA_MAGIC;[/b]

	// Constructor
	ShuttleAVesselCtrl(OBJHANDLE vessel, int fmodel) : VESSEL3(vessel, fmodel) { }

	// Pure virtual functions to retract the landing gear
	virtual void RevertLandingGear() = 0;
}; 

In Orb::Connect:
Code:
       pShuttleAVessel = (ShuttleAVesselCtrl*)pVessel;
	if (0 == pShuttleAVessel) {
		return "ERR07";
	}

[b]        if ( pShuttleAVessel->magic != SHUTTLEA_MAGIC ) {
                // Object is not a ShuttleACtrl object!
                return "ERRxx";
        }[/b]


---------- Post added at 10:36 PM ---------- Previous post was at 10:27 PM ----------



Also this check

Code:
	if (0 == pShuttleAVessel) {
		return "ERR07";
	}

is redundant because cast does not change pointer value. You could as well drop pVessel and do

Code:
      message = loadVessel((VESSEL2*)&pShuttleAVessel, tokens);

or maybe even

Code:
      message = loadVessel(&pShuttleAVessel, tokens);

(because I don't remember if you can drop a cast to superclass).
 
Last edited:

markl316

XR2 Ravenstar Commander
Addon Developer
Tutorial Publisher
Joined
Mar 30, 2008
Messages
450
Reaction score
1
Points
18
First off:

This is a bad assumption to make. You should definitely do something to ensure you don't crash when a SHA: is sent without a ShuttleA being in focus.

100% agreed...I took out the make-sure-it's-a-vessel, make-sure-it's-in-focus, etc. code checks just for this proof of concept, to keep the code as simple as possible. I would of course put all that in if it were a released version.

Further, rather than directly making a new API for your vessel and consuming that, wouldn't it be easier to just use the vessel communication function that's already defined on VESSEL3? (can't remember what it's called off the top of my head, it lets you pass messages around).

You could have your vessel respond to an incoming message of that type with the appropriate parameters by retracting the gear, and then you could program Orb:Connect to convert the SHA command into that message.

That's a good approach; I'll probably give it a try in the next couple of weeks as an alternate method of doing this.


Another issue is that I cannot figure out if your inheritance goes
VESSEL3 < ShuttleACtrl < ShuttleA
or
VESSEL3 < ShuttleA < ShuttleACtrl



The first one; ShuttleACtrl is defined from VESSEL3, and ShuttleA is derived from ShuttleACtrl.


Orb::Connect retrieves a pointer to the VESSEL object oapiGetVesselInterface() and that pointer is what you have in pVessel variable. So the solution is obviously to make ovcInit() return an instance of ShuttleACtrl.

I didn't end up having to make this change to get it functional, though I'm not sure if anything related to this is causing the spotty behavior (see below).


First, in Orb::Connect you should have Log module. Use it.
Are you referring to something other than the orbiter log?

------------

I got it (somewhat) working though! I kept my changes to the ShuttleA code in place (addition of my newly-defined ShuttleACtrl, with the above inheritance structure), and redid the ShuttleACommandParser.cpp portion of the OrbConnect code base. Note I bypassed the loadVessel function below, but copied over several commands from it. Again, to keep it super simple just for this proof of concept, there are no code checks verifying that the correct vessel class and ship name are in focus (but I'm making sure they are while testing it). Also to keep things simple, no matter what the command is, I'm just sending the command to stow the landing gear.

Code:
#include "ShuttleACtlCommandParser.h"

string ShuttleACtlCommandParser::parse(long lParam, string command) {
	
	string message = "ERR02";
	ShuttleAVesselCtrl* pShuttleAVessel;

	// Get the command from the inputted command through the socket
	vector<string> tokens = stringSplit(command, ":");
	string cmd = uCase(tokens.at(2));
	
	// Get the name of the vessel commanded
	char vesselName[256];
        strcpy_s(vesselName,tokens.at(1).c_str());

	// Get the pointer to the vessel returned by oapiGetVesselByName
	OBJHANDLE shipHandle = NULL;
	shipHandle = oapiGetVesselByName(vesselName);
	VESSEL *pCandidateVessel = oapiGetVesselInterface(shipHandle);

	// Cast to pointer to ShuttleAVesselCtrl
	ShuttleAVesselCtrl *pVessel = (ShuttleAVesselCtrl*)pCandidateVessel;

	// Run the StowLandingGear function, which calls the RevertLandingGear function in ShuttleA.cpp
	message = StowLandingGear(pVessel);

	return message;
	
}


string StowLandingGear(ShuttleAVesselCtrl *pVessel) {
	pVessel->RevertLandingGear(); // Function RevertLandingGear is defined in ShuttleA.cpp
	return "OK";
}


I'm not quite ready to declare victory yet, however...orbiter seems to lock up about half the time when using the JAVA client on a ShuttleA vessel. After some diagnosing, I noted the following behavior:

1. Everything is stable using the supplied JAVA client commanding an XR2 vessel.
2. When loading any ShuttleA scenario and using orbiter without OrbConnect for 15+ minutes (OrbConnect module still activated in the launchpad, just didn't open the JAVA client), everything is still rock solid.
3. The problem only arises when using the supplied JAVA client with a ShuttleA vessel in focus. That's when Orbiter crashes about half the time. Even more bizarre, sometimes the client will connect successfully, but Orbiter will crash when I'm in the middle of typing the command into the client's window. Sometimes this happens right when I start up Orbiter and the client and start typing in the window. Nothing weird in the orbiter log.
4. Running OrbConnect in Debug mode in VSExpress 2010, and using the client in the exact same manner as step 3, I sat there creating multiple ShuttleA vessels and raising and lowering the landing gear for 15 minutes and could not get it to crash.
5. OrbConnect.dll jumped from 242KB to 392 KB with my additions, despite the fact that I added very little text or additional files.
6. I'm out of town and am on a Windows 8 machine running VSExpress 2010, so I'm not sure if there's some sort of issue this could be causing.
7. I wasn't able to download the specific JAVA RTE linked to in the client readme, as the website no longer exists.



Was OrbConnect being much more stable in the debugger than when actually running Orbiter normally something you noticed when developing OrbConnect? I'm at a bit of a loss as to why it would work so well when debugging in VSExpress but then be spotty when running orbiter normally.
 
Last edited:

kamaz

Unicorn hunter
Addon Developer
Joined
Mar 31, 2012
Messages
2,298
Reaction score
4
Points
0
Ah yes, that's the textbook way of getting the VESSEL object :)

Add this:

if ( shipHandle == NULL ) return "ERRxx";

Now, your code crashes when you mistype vessel name.

Also add

if ( pCandidateVessel == NULL ) return "ERRxx";

in case someone sends planet name as a ship name.

---------- Post added at 10:16 AM ---------- Previous post was at 10:06 AM ----------

Are you referring to something other than the orbiter log?

Yes. See Log.h :)

Also:

- you can run Release build under VS debugger

- you can register VS ddebugger to be run on crash even if you are not running under VS currently
 

markl316

XR2 Ravenstar Commander
Addon Developer
Tutorial Publisher
Joined
Mar 30, 2008
Messages
450
Reaction score
1
Points
18
Ah yes, that's the textbook way of getting the VESSEL object :)

Yes. See Log.h :)

Still not seeing it...I looked in all the external dependencies and header files in OrbConnect when open in Visual Studio, and I searched my copy of Orbiter with OrbConnect installed for a "log.h" file, to no avail :(


Also:

- you can run Release build under VS debugger

- you can register VS ddebugger to be run on crash even if you are not running under VS currently

You learn something new every day, as they say. Building under released made the size 244 KB up from the original 242KB, so now that part makes sense.






-----------------------------------------------

Further, rather than directly making a new API for your vessel and consuming that, wouldn't it be easier to just use the vessel communication function that's already defined on VESSEL3? (can't remember what it's called off the top of my head, it lets you pass messages around).

You could have your vessel respond to an incoming message of that type with the appropriate parameters by retracting the gear, and then you could program Orb:Connect to convert the SHA command into that message.

I just coded this up, and it works brilliantly!! OrbConnect is rock solid with ShuttleA vessels, now matter how fast I send the commands or how fast I type in the client window :thumbup:

For those interested in seeing the solution, starting with a clean version of orbiter100830 and OrbConnect v3.19:

Added to the public members section of ShuttleA.h, around line 140
Code:
// Inherited virtual functions
	virtual int clbkGeneric(int msgid, int prm, void *nullPtr);

Added to ShuttleA.cpp:
Code:
// ==============================================================
// Generic callback interface
// ==============================================================
int ShuttleA::clbkGeneric(int msgid, int prm, void *nullPtr)
{
	if (msgid == 1 && prm == 1)
	{
		RevertLandingGear();
		return 1;
	};
}


Added to OrbConnect.h
Around line 13:
Code:
#include "ShuttleACtlCommandParser.h" // ShuttleA addition

Added to OrbConnect.cpp:

Around line 55:
Code:
ShuttleACtlCommandParser shaCtrlParser; // ShuttleA Addition

Around line 97:
Code:
else if ("SHA" == area)
    {
        SendText(lParam, IDstring, shaCtrlParser.parse(lParam, Command));
    }

Around line 150:
Code:
else if ("SHA" == area)
    {
        SendText(lParam, Command, shaCtrlParser.parse(lParam, Command));
    }


New File ShuttleACtlCommandParser.h:
Code:
#ifndef _SHUTTLEACTL_COMMAND_PARSER_H
#define _SHUTTLEACTL_COMMAND_PARSER_H
#define VSEXPRESS 1

#include "VesselCommandParser.h"
using namespace std;

// Class definition for ShuttleACtlCommandParser
class ShuttleACtlCommandParser : public VesselCommandParser 
{
public:
	string parse(long lparam, string command);
};

// Function definition for StowLandingGear
string StowLandingGear(VESSEL3 * pVessel);


#endif


And finally, the new file ShuttleACtlCommandParser.cpp
Code:
#include "ShuttleACtlCommandParser.h"

string ShuttleACtlCommandParser::parse(long lParam, string command) {
	
	string message = "ERR02";
	// VESSEL3* pShuttleAVessel;

	// Get the command from the inputted command through the socket
	vector<string> tokens = stringSplit(command, ":");
	string cmd = uCase(tokens.at(2));
	
	// Get the name of the vessel commanded
	char vesselName[256];
        strcpy_s(vesselName,tokens.at(1).c_str());

	// Get the pointer to the vessel returned by oapiGetVesselByName
	OBJHANDLE shipHandle = NULL;
	shipHandle = oapiGetVesselByName(vesselName);
	VESSEL *pCandidateVessel = oapiGetVesselInterface(shipHandle);

	// Cast to pointer to ShuttleAVesselCtrl
	VESSEL3 *pVessel = (VESSEL3*)pCandidateVessel;

	// Run the StowLandingGear function, which calls the RevertLandingGear function in ShuttleA.cpp
	message = StowLandingGear(pVessel);

	return message;
	
}


string StowLandingGear(VESSEL3 *pVessel) {
	void *emptyPointer = NULL;
	pVessel->clbkGeneric(1, 1, emptyPointer); // Function RevertLandingGear is defined in ShuttleA.cpp
	return "OK";
}

I think the stability issues I was having were probably due to restructuring the ShuttleA class, as that was the only vessel affected by the stability issues. But now, all is well.

Thank you all very much for your help on this!
 

kamaz

Unicorn hunter
Addon Developer
Joined
Mar 31, 2012
Messages
2,298
Reaction score
4
Points
0
Oh well. It seems I did not put my Log facility into Orb::Connect. Sorry for confusing you :)

Check for NULL returned by oapiGetVesselByName() otherwise it's going to crash if you mistype the ship name.
 

Hielor

Defender of Truth
Donator
Beta Tester
Joined
May 30, 2008
Messages
5,580
Reaction score
2
Points
0
Of course, at the point you've got the ShuttleA responding to clbkGeneric for the landing gear, you could just add the ability for OrbConnect to send arbitrary things to clbkGeneric (if it doesn't already have that), and then leave the logic for "landing gear down == clbkGeneric 1,1" on the client side :p
 

markl316

XR2 Ravenstar Commander
Addon Developer
Tutorial Publisher
Joined
Mar 30, 2008
Messages
450
Reaction score
1
Points
18
Actually, while this is all still fresh, one more thing...Using clbkGeneric works for sending a command to a vessel, but what about retrieving a variable from a vessel instance? I skimmed through the VESSEL/2/3 member functions in the Orbiter API reference but didn't find anything to be able to do this.

For example, say there was some struct defined by the ShuttleA class called <shaParam> that included info about the mass, number of attached cargo containers, pod thruster angle, etc., and I wanted to somehow have OrbConnect get a pointer to it. I can only operate with VESSEL3 member functions. I guess you'd ideally have clbkGeneric return a void* instead of an int, but is there a workaround that anybody knows about?
 
Last edited:

Bibi Uncle

50% Orbinaut, 50% Developer
Addon Developer
Joined
Aug 12, 2010
Messages
192
Reaction score
0
Points
0
Location
Québec, QC
You cannot change the return value of clbkGeneric. However, you can pass a pointer to an empty struct in the context parameter, and implement a message ID to fill in the struct.

Just some quick and dirty code:
Code:
int ShuttleA::clbkGeneric(int msgid, int prm, void* context)
{
    switch(msgid)
    {
    case 0:
        MyStruct* params = (MyStruct*)(context);
        params->mass = 15;
        // etc.
        return 1;
    }
}

And the calling function:
Code:
VESSEL3* vessel; // Your pointer to the ShuttleA.
MyStruct params; // An empty struct.

vessel->clbkGeneric(0, NULL, &params);

double mass = params.mass; // Accessing a value
// etc.
 
Last edited:

markl316

XR2 Ravenstar Commander
Addon Developer
Tutorial Publisher
Joined
Mar 30, 2008
Messages
450
Reaction score
1
Points
18
However, you can pass a pointer to an empty struct in the context parameter, and implement a message ID to fill in the struct.

Ah, I was wondering about the third argument of clbkGeneric. Great suggestion, I'm able to get ShuttleA passing info back to OrbConnect. Thanks!
 
Top