API Question Multi-MFD load from scenario

Mythos

Addon Developer
Addon Developer
Donator
Joined
Apr 28, 2012
Messages
103
Reaction score
7
Points
33
Location
Kiel
Hi,

I tried hard and long, but I don't get to a point. So here is a longer description of my problem, the interesting outtakes of code and some questions about API.

I want to implement saving and loading from scenario file for the status od my MFD. I put some work into splitting properties to vessel- and MFD-topics for the purpose of having two of my MFDs open at same time (left and right) and each displaying different pages.

This is my MFD class:
PHP:
class HoverMFD: public MFD2 {
public:
  HoverMFD (DWORD w, DWORD h, VESSEL *vessel, UINT mfd);
  ...
  void ReadStatus (FILEHANDLE scn);
  void WriteStatus (FILEHANDLE scn) const;

  //The data instance the MFD is linked to
  MfdData *mfdData;

For saving now I do:
PHP:
void HoverMFD::WriteStatus (FILEHANDLE scn) const {
  oapiWriteScenario_int (scn, "PAGE", mfdData->page);

This is quite easy and it works. Having two HoverMFD it will write to scenario:
Code:
BEGIN_MFD Left
  TYPE User
  MODE HoverMFD
  PAGE 1
END_MFD

BEGIN_MFD Right
  TYPE User
  MODE HoverMFD
  PAGE 2
END_MFD

The code to load a scenario file:
PHP:
void HoverMFD::ReadStatus (FILEHANDLE scn) {
  char *line;
  while (oapiReadScenario_nextline (scn, line)) {
    std::istringstream ss;
    ss.str(line);
    std::string id;
    if ( ss >> id ) {
      if ( id == "PAGE" )
        ss >> mfdData->page;

This works quite well if having only one HoverMFD. But when left and right are HoverMFD and should display different pages is does NOT work (one state is loaded, other ignored) :(

Since these scenario funtions are implemented I also noticed in my tests, that sometimes after scenario loading the pointers to my data instances point to somewhere. Since my MFD displays vessel class and name I then read "Brighton Beach" ore whatever and of course AP doesn't react to my settings since it is not a vessel at all... :rolleyes:

1. important question for me is: In what order do things happen? I thought it should be:
  1. all vessels are created from scenario
  2. vessel stuff is loaded from scenario
  3. all MFDs for active vessel are created
  4. MFD stuff is loaded from scenario

As MFD developer I had to learn that my MFD is created quite often (switching vessels, go out / inside cockpit etc.). But of course there has to be an instance of HoverMFD : public MFD2 before data is loaded!?

That MFD instance would have my data instance created:
PHP:
HoverMFD::HoverMFD (DWORD w, DWORD h, VESSEL *vessel, UINT mfd)
: MFD2 (w, h, vessel) {
  // Link to the correspondig data instance
  mfdData = g_HoverModule->mfdList->Get ( vessel, mfd, g_HoverModule->vesselList->Get(vessel) );

These Get() fuctions maintain two lists (vessels and MFDs), search for the given vessel pointer and that UINT mfd ID. If found that data will be used because it was created by earlier creations of the same MFD. If not found they create a proper data instance:
PHP:
MfdData *MfdList::Get(VESSEL *vessel, UINT mfdID, VesselData *vd) {
  // searching ...
  if (!result) {
    // nothing found
    result = new MfdData(vessel, mfdID, vd); }
  return result;

So I thought while within ReadStatus I can rely on an existing MFD and MfdData instance. And I think that's proven by my only one MFD attempts. But I'm irritated and put that into question, so:

2. important question: Is writing into data instances like "ss >> mfdData->page" allowed within ReadStatus?

3. important question: What's about that MFD ID? I thought it vessel dependent (some have more than left and right) and left MFD has always the same ID (maybe 0).

4. important question: Of course each scenario section (BEGIN_MFD Left / BEGIN_MFD Right) is loaded separately and for each an own instance of MFD is created (and then followed by my data instance creation)?

I hope someone is deep into MFD topics and can help me :)

Greetings
Mythos
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
1. important question for me is: In what order do things happen? I thought it should be:
  1. all vessels are created from scenario
  2. vessel stuff is loaded from scenario
  3. all MFDs for active vessel are created
  4. MFD stuff is loaded from scenario
Vessels are loaded first, then MFDs.

Vessels are loaded sequentially in the order they are in scenario file:
  1. ovcInit of the first vessel is being called, which calls constructor of the vessel, then clbkSetClassCaps, clbkLoadStateEx of the same vessel.
  2. ovcInit of the next vessel is being called, which calls constructor of the vessel, then clbkSetClassCaps, clbkLoadStateEx of the same vessel.
  3. ...
  4. clbkPostCreation of the first vessel in scenario is being called, and then for the next, and so on.

After vessels have been initialized, MFDs are created and loaded, in that order:
  1. Orbiter calls MsgProc of left MFD which calls constructor of it, then ReadStatus of it is being called.
  2. Orbiter calls MsgProc of right MFD which calls constructor of it (even if it's the same mode as on the left MFD), and then ReadStatus of it is being called.


As MFD developer I had to learn that my MFD is created quite often (switching vessels, go out / inside cockpit etc.). But of course there has to be an instance of HoverMFD : public MFD2 before data is loaded!?
MsgProc of the MFD is called with OAPI_MSG_MFD_OPENEDEX message, in which you create an instance of the MFD, and then the data is loaded if the MFD was loaded from scenario. The instance is deleted if you switch to other mode or turn off the MFD. ReadStatus isn't called when you switch modes, but insetead StoreStatus of the old mode and RecallStatus of the mode it's being switched to (after new instance of that new MFD mode has been created, of course).


2. important question: Is writing into data instances like "ss >> mfdData->page" allowed within ReadStatus?
Why wouldn't it be? mfdData isn't static and it was already initialized in the constructor. But this way the mfdData->page will be only set if you loaded the MFD from the scenario (if you haven't also restored it from saved state when you switched modes).


3. important question: What's about that MFD ID? I thought it vessel dependent (some have more than left and right) and left MFD has always the same ID (maybe 0).
You mean the UINT mfd of MsgProc which you pass to the constructor in your example?
MFD_LEFT = 0, MFD_RIGHT = 1, MFD_USER1 = 2, up to MFD_USER8 = 9.


4. important question: Of course each scenario section (BEGIN_MFD Left / BEGIN_MFD Right) is loaded separately and for each an own instance of MFD is created (and then followed by my data instance creation)?
This was answered at the beginning.




How is MfdList::Get searching for given MFD data?

What is debugger showing? Is MFD data found or not when you switch modes back and forth and are parameters the same as you saved there? Is the `page` set correctly in the ReadStatus when you start scenario?
 

Mythos

Addon Developer
Addon Developer
Donator
Joined
Apr 28, 2012
Messages
103
Reaction score
7
Points
33
Location
Kiel
Thank you orb. Most questions are answered and it is like I supposed it to be. So that could not be my problem.

My mfdData is created when it's MFD instance is first created and then stored in a list that is within my module class. And my instance of that module class is global and created within InitModule. So the lists and the MfdData instance stay in memory even if MFD is deleted (switching modes etc.)

When MFD is recreated (switching back) with same vessel pointer and UINT mfd, these values are searched in my list and that already existing MfdData bound to my MFD (that's what these Get() funtions do and I won't search the problem there, all that works for MFD switching, off/on etc.)

Within the MFD class there are no properties. So if I switch MFD mode and back, there has nothing to be stored or recalled, since all data is memory persistent (until the whole vessel is deleted).

So there was no use of StoreStatus or RecallStatus and I've never heard about them. Do I have to use them for scenario loading to work properly?

By debugging I found out that order:
- MFD 0 is created
- my VesselData for that is created
- my MfdData for MFD 0 is created
- ReadStatus is called
- the line with "PAGE 1" is read
- the line with "PAGE 2" is read (why?!)
- MFD 1 is created
- VesselData is reused because vessel pointer was in VesselList already
- my MfdData for MFD 1 is created
- ReadStatus is called
- only the line with "PAGE 2" is read

So the question now is: Why does the ReadStatus for left MFD 0 reads over the line "PAGE 2" within right MFD section?

Do I have to look for the "END" statement by myself? I didn't think so.
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
So the question now is: Why does the ReadStatus for left MFD 0 reads over the line "PAGE 2" within right MFD section?

Do I have to look for the "END" statement by myself? I didn't think so.
The oapiReadScenario_nextline checks only for END, and not for END_something to return false.

You can either make your own check for END_MFD or write into the MFD block "END" as the last saved line for your MFD. Then the oapiReadScenario_nextline condition will break the loop at that line when you reload it next time.
 
Top