Editing Storing MFD Instances

Jump to navigation Jump to search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.

Latest revision Your text
Line 1: Line 1:
In Orbiter, if you switch focus to another vessel, or switch camera modes, the [[MFD]]s that are open get deleted. This is because [[MFD]]s are strictly designed for displaying data. But what if you were writing an [[MFD]] that needed to cache data? For example, a user defined value. Every time the user switches focus, or camera modes, the [[MFD]] will get destroyed. This article shows how you can bypass this problem. Moreover this approach allows every vessel to store its own data. Based on the approach presented first, a library has been created, that hides all the implementation details, and provides a more secure and cleaner way of achieving the same goal. Additionally it allows to execute code independently of the created MFDs, like for guidance algorithms. The library is called MultipleVesselsMFD.
+
In Orbiter, if you switch focus to another vessel, or switch camera modes, the [[MFD]]s that are open get deleted. This is because [[MFD]]s are strictly designed for displaying data. But what if you were writing an [[MFD]] that needed to cache data? For example, a user defined value. Every time the user switches focus, or camera modes, the [[MFD]] will get destroyed. This article shows how you can bypass this problem. Moreover this approach allows every vessel to store its own data.
  
 
== Basic Plan ==  
 
== Basic Plan ==  
Line 103: Line 103:
 
     {
 
     {
 
         it = g_data.begin() + i;
 
         it = g_data.begin() + i;
         if (!oapiIsVessel(g_data.at(i)->hook)) // if vessel does not exist, delete from the vector
+
         if (!oapiIsVessel(g_data.at(i)->hook)) // if vessel does not exist, delete the vector
 
         {
 
         {
 
             delete g_data.at(i);
 
             delete g_data.at(i);
Line 112: Line 112:
 
</pre>
 
</pre>
  
== MultipleVesselsMFD library ==
 
The library is available at [http://sourceforge.net/projects/enjomitchsorbit/ SourceForge]-->Code, and licensed as LGPL. This means that if you want link it with your code, you can link it dynamically, without any responsibilities, but if you link it statically, you have to LGPL or GPL your code. The library provides a very clean and random-CTD-at-vessel-deletion secure way of achieving the same goal as the above code, but requires to do a few things described here. The package contains Doxygen documentation. You should open it and keep it as a reference, to view specific classes that will be described. The necessary steps are the following:
 
  
* Derive a class from MFDData to add any additional members and functionalities that you want your MFD to contain. In this example, it will be called MyMFDData.
+
[[Category:Addon tutorials]][[Category:Tutorials]]
* Derive from PluginMultipleVessels, where the method ConstructNewMFDData should return a new MFDData derived object pointer (MyMFDData *). It will be stored and managed internally. In this example, the Plugin derived class will be called PluginMyMFD. For instance:
 
<pre>
 
MFDData * PluginMyMFD::ConstructNewMFDData( VESSEL * vessel )
 
{
 
    return new MyMFDData( vessel );
 
}
 
</pre>
 
* Declare a global pointer to the derived Plugin class, initialize it and register it in Orbiter's InitModule() along with the usual MFD inits.
 
<pre>
 
PluginMyMFD * pPluginMyMFD;
 
 
// Called on module init
 
DLLCLBK void InitModule (HINSTANCE hDLL)
 
{
 
    // init spec and register MFD mode
 
    pPluginMyMFD = new PluginMyMFD(hDLL);
 
    oapiRegisterModule (pPluginMyMFD);
 
}
 
</pre>
 
* Declare a specific constructor that accepts the derived PluginMultipleVessels class and Declare the derived MFDData in the main MFD class, for instance:
 
<pre>
 
class MyMFD : public MFD2
 
{
 
  public:
 
    /// Default constructor
 
  MyMFD( DWORD w, DWORD h, VESSEL * vessel, PluginMyMFD * pluginMyMFD );
 
    /// Returns MFDData
 
    MyMFDData * GetData() const;
 
   
 
  private:
 
    MyMFDData * m_data;
 
}
 
</pre>
 
* Pass the Plugin to MFD's constructor, initialize the MyMFDData and perform a simple check
 
<pre>
 
// Constructor
 
MyMFD::MyMFD(DWORD w, DWORD h, VESSEL *vessel, PluginMyMFD * pluginMyMFD )
 
// Initialisation list
 
: MFD2 (w, h, vessel)
 
/* init m_data with PluginMultipleVessels's return value, depending on the vessel pointer. If dynamic cast fails, the m_data member becomes NULL. */
 
, m_data(dynamic_cast<MyMFDData *>(pluginMyMFD->AssociateMFDData(vessel)))
 
{
 
    if ( m_data == NULL ) // Programming error
 
        sprintf_s(oapiDebugString(), 512, "m_data pointer type is not compatible with the pointer that was being assigned to it in Ctor");
 
}
 
</pre>
 
* Place all vessel state updates in MyMFDData::Update() and call it in MFD2::Update()
 
<pre>
 
// Repaint the MFD
 
bool MyMFD::Update ( oapi::Sketchpad * skp )
 
{
 
    if ( m_data == NULL )
 
        return false;
 
 
 
    // Update all ship's variables
 
    m_data->Update();
 
 
    // Draws the MFD title
 
    Title (skp, "My Multiple Vessels MFD");
 
    PrintResults(skp); // Print data from m_data
 
 
    return true;
 
}
 
</pre>
 
* If it's necessary, you can update each of the vessels' MFDData in your derived plugin's UpdatePreStep() (or UpdatePostStep() if needed) that runs even if the MFD itself is disabled and for all vessels simultaneously. Example usage would be autopilots.
 
<pre>
 
void PluginMyMFD::UpdatePreStep( MFDData * data )
 
{
 
  // Normally you'd use dynamic_cast and check if the returned value is NULL,
 
    // but this method is supposed to work fast enough.
 
    MyMFDData * myMFDData = static_cast<MyMFDData *> (data);
 
    AutopilotBase * apBase = m_apMan.GetAP(myMFDData->GetAutopilotType());
 
    if (apBase != NULL)
 
    {
 
      // Only now it's reasonable to call data->Update() not to waste resources in case it's actually not needed.
 
        myMFDData->Update();
 
        apBase->Guide(myMFDData);
 
    }
 
}
 
 
 
void PluginMyMFD::UpdatePostStep( MFDData * data )
 
{
 
  // Must be implemented
 
}
 
</pre>
 
 
 
These were the minimal steps to use the library, but there is a working example in the library package.
 
 
 
[[Category: Articles]]
 
[[Category:Tutorials]]
 
[[Category:Add-on tutorials]]
 
[[Category:Libraries]]
 

Please note that all contributions to OrbiterWiki are considered to be released under the GNU Free Documentation License 1.2 (see OrbiterWiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To protect the wiki against automated edit spam, we kindly ask you to solve the following hCaptcha:

Cancel Editing help (opens in new window)