Open-source versions of built-in MFDs?

There are also good cross platform game engines, which implement similar features as Orbiters graphics functions supply (in terms of user interfaces).

Maybe jarmonik means it will save trouble in porting existing MFD plugins, because in windows you already have a working GDI engine.

About the menu issue:
I was thinking into finding the function address in the Orbiter executable somehow, and then use that address as a hard-coded function pointer in the add-on. AFAIK windows doesn't use position independent code, so I think the address must always be the same, as long as you use the same version of the executable. If you don't use exactly the same version, this trick will most probably crash Orbiter. I think this can be avoided by checking the contents at that address first.

While my trick is a lot more dirty than yours, and probably more difficult too, it will create a more consistent user interface. Now I only need to find a good debugger that will tell me which instructions are touched and which are not. And it would be helpful if Martin gave me the exact function prototype of the function that triggers the menu.

Maybe the dialog option is a better way...


-----Posted Added-----


I have some progress on the menus!!!

It seems there are three functions that trigger the menu:

0x00431050
3 32-bit arguments
Select any celestial body
used by REF button in Align, Map, Orbit and Transfer MFD

0x00431190
4 32-bit arguments
Select a vessel or celestial body around a reference body
used by TGT button in Align, Orbit, Sync and Transfer MFD

0x4994d0
6 32-bit arguments
Select spaceports on, or vessels or moons around reference body
Select docking ports on vessels
Used by TGT button in Docking and Map MFD

This is easier than I thought! It really helps that Orbiter.exe isn't encrypted like those copy protection systems, but it would have been better if it had debugging info ;). Now I can set breakpoints to peek some typical argument values and guess their meaning. I already know one of them is the menu title, and I guess one of them is a function pointer.

I'm amazed by the things you can find out by reading an exe file:

  • the source code was located in C:\conspiracy\take_over_the_world\orbiter\source
  • each built in MFD has its own source file
  • all object files are linked in alphabetical order
  • You can edit the loading screen, as it's just a resource bitmap, but you're not allowed to, according to the built-in license information

I wonder what dr. Schweiger thinks when he reads this :lol:
 
It seems there are three functions that trigger the menu:

0x00431050
3 32-bit arguments
Select any celestial body
used by REF button in Align, Map, Orbit and Transfer MFD

0x00431190
4 32-bit arguments
Select a vessel or celestial body around a reference body
used by TGT button in Align, Orbit, Sync and Transfer MFD

0x4994d0
6 32-bit arguments
Select spaceports on, or vessels or moons around reference body
Select docking ports on vessels
Used by TGT button in Docking and Map MFD

...I already know one of them is the menu title, and I guess one of them is a function pointer.
One of them will be a function pointer to a callback, and similar to the callbacks for the oapi that pops up a user input text box.
One parameter is likely to be user information.

The extra parameter of 0x00431190 is most likely to be the handle of the celestial body that you are retrieving data from.

A good course of action would be to assume that some of the parameters will be handles of bodies/vessels etc. If you can into the function, try running the 32bit values through oapiGetObjectName and see what pops out. If the handle is invalid, it should return null or an empty string. It'll at least give you an idea of what some of the parameters are.

Or one of the parameters could be a pointer to the MFD that called it.

Either way, good work on the investigative skills. Low level hacking and assembly is one thing I've been wanting to do for a long time, but never had the time or reason to get into it.
 
Have you considered how much trouble it would save using a Windows platform instead of Linux ?

In porting existing MFDs, it would indeed save some trouble, I suppose.

In creating new ones, it would not save any trouble at all, and would indeed cause more trouble.

The decision to use Linux was based largely on the extremely limited capabilities of the laptops that will be hosting the MFDs. They certainly won't be able to run Orbiter (to use ExtMFD). Linux has *significantly* less overhead than Windows. Keep in mind that these computers will be doing nothing but displaying these MFDs. I have no need for all the additional features of Windows that will be taking up resources and slowing down the system--specifically, a windowed operating system.

With Linux, I can customize it to be exactly how I want it--I have the install under 100mb right now, and I can probably get it lower. All the stuff I need, and none of the stuff I don't.

The Allegro library that i'm using is (as far as I've seen) much more capable than GDI. Moreover, it can be used on the vast majority of operating systems out there, so if I want to have a Windows machine hosting MFDs at some point, the amount of porting necessary will be very low.

Plus, in my personal experience, Linux is overall easier to develop for than Windows, especially since my machines are all identical.

---------------------------------------
CJP: That's fantastic! I'm approaching completion on my version of the SurfaceMFD and was going to do Orbit next, but since you're working on that I'll do a different one, or perhaps work more on the networking bits.
 
I'm amazed by the things you can find out by reading an exe file:

  • the source code was located in C:conspiracytake_over_the_worldorbitersource
  • each built in MFD has its own source file
  • all object files are linked in alphabetical order
  • You can edit the loading screen, as it's just a resource bitmap, but you're not allowed to, according to the built-in license information

I wonder what dr. Schweiger thinks when he reads this :lol:

I just hope that it doesn't make him want to encrypt the binary :)

Great work guys !
 
I hacked into an MFD that normally uses the oapiOpenInputBox callback:

Code:
typedef void (*OAPI_TEST)( char *title, bool (*Clbk)(void*,char*,void*), void *usrdata ) ;
OAPI_TEST oapi_test = (OAPI_TEST)0x00431050 ;
 
bool cbSetValue( void *id, char *str, void *data )
{
   ((MYMFD*)data)->value = atof(str) ;
   return( true ) ;
}
 
// invoked by UI
void MYMFD::oapiSet( void )
{
   oapi_test( "Test", cbSetValue, (void *)this ) ;
}

but at runtime it explodes when called (see attachment). I'm not deep into MS error messages but it looks like some sort of stack corruption.
 

Attachments

  • grab_021.jpg
    grab_021.jpg
    113.6 KB · Views: 22
Looks like a stack corruption to me. The function may not return void. It may return a DWORD or similar (pointer). I don't have the rest of the API documentation to hand, so take a look in there and try and guess the return type, or devine it by some other means.
 
Good idea, I'll try different return types.

Where's Computerex? This problem would already be solved! :)

eta: Changing return type to bool or DWORD or void* has no effect - same error.

eta2nd: On a lark I called a "non-address" value (0x00420420) and got an immediate CTD. It does seem like we're hitting a valid function of some sort. (and there was much rejoicing--yay)
 
It's possible that the problem is not with the function you are calling, but with the callback function.

If the incorrect number of arguments are present in the callback function, the caller will offset ESP by the wrong amount, which could cause the error you're seeing.
 
Depends on the function call convention. the normal C call convention requires the caller to control the parameter stack (that's why printf and other variable argument functions can work at all). Pascal convention instead requires the function to clean the stack of them. But don't ask me, which one was used in that case. I don't do the reverse engineering.
 
It's possible that the problem is not with the function you are calling, but with the callback function.

If the incorrect number of arguments are present in the callback function, the caller will offset ESP by the wrong amount, which could cause the error you're seeing.
That could be so. In that case though wouldn't we expect the problem to occur when the dialog box closes? (That is, after the user input has been provided?) As it is the callback function is just a 32-bit pointer until it actually needs to be called (MFD->(immediate 3 pushes)->OAPI_TEST->(user input then unknown pushes)->Clbk). The debug error appears immediately upon the OAPI_TEST call. Am I assuming something wrong?

Oh and yeah leave it to somebody to raise the Pascal spectre. ;)
 
I'm just learning the thing by doing, but it seems I'm a fast learner...

I managed to trigger a menu, and get a useful response from it through the callback mechanism!!! Some more details:

  • 0x00431050 seems to use the __thiscall convention. In other words, it is a member function of a class, with the this pointer in ecx, and the arguments on the stack. It's just a small convenience function that calls 0x004994d0.
  • The this pointer seems to be of type "Instrument_User *". This class is not defined anywhere in the SDK header files, but one of the member variables of class MFD is of that type.
  • The three arguments on the stack are a char *title, a callback function pointer and a DWORD of flags
  • The callback prototype is "bool clbk(void *ptr, unsigned int index, char *name, void *user_ptr)".
    • User_ptr seems points to the this pointer given to 0x00431050.
    • menuIndex is the item index in the menu
    • name is the name of the menu item
    • I haven't figured ptr out yet. It doesn't seem to be an OBJHANDLE. It's probably an unique identifier to the menu, like in oapiOpenInputBox.
    • The return value has the same effect as in oapiInputBox
  • One of the bits in flags (that is 0x1) tells to hide the sun in the menu (like Map MFD REF does). flags = 0x0 gives a menu with all celestial bodies, like Orbit MFD REF.
I made a small assembly function to call 0x00431050 from an MFD, and it seems to work without crashing. I only have two issues: the first time I press my own MFD's REF button, nothing happens, and the menu appears only the second, third etc. time. The second issue is that sometimes there are way too many items in the menu: something like every celestial body twice. When going to a sub-menu and going back, the menu is normal again.

And: supplying arbitrary data as this pointer won't crash the thing. 0x00431050 simply gives it to 0x004994d0 as user data without dereferencing it.

Some code: (I know it's dirty but it will work on only one version anyway)
Code:
typedef bool (*menuClbk)(void *, unsigned int, char *, void *);

#define MENU_HIDE_SUN 0x00000001

void celBodyMenu(MFD *mfd, char *title, menuClbk clbk, DWORD flags)
{
    DWORD procAddr = 0x00431050
    Instrument_User **instrUserPtr = ((Instrument_User **)mfd) + 6;
    Instrument_User *instrUser = *instrUserPtr;
    
    __asm mov ecx, [instrUser]
    __asm push [flags]
    __asm push [clbk]
    __asm push [title]
    __asm call procAddr
}
 
Nice job!!

eta: FWIW I don't encounter any of the problems you mention, it works quite well. The menu width seems to auto-size to the supplied title.
 
Last edited:
Hielor: A VERY weird solution to your problem, make your own graphics client. You would need to use the latest Orbiter, but that is publicly available now(the beta anyway). It is very crazy, but may just be easier than having to rewrite MFDs (Plus it would be cool)
 
Another different solution might be - don't use a menu box. Treat it like a true MFD and use the edge buttons for everything, changing options/functions as you navigate menus. Perhaps add menu navigation buttons along the bottom.

Just a suggestion.
 
tl8: Possibly, but then I would have the exact same problem that Urwumpe's having with OGLA right now--GDI interfacing. All MFDs are currently written with GDI, so in order to host them I'd have to use that. That would not be easier, and would in fact be considerably harder.

yagni01: I'm not doing menu boxes, but if I were then they would be controlled with the edge buttons. I do like that idea of having an in-MFD menu, though. More realistic.

An update on where I am: I have the Surface MFD pretty much done. I'm a bit stalled right now due to school, but next up will be the Orb:Connect modifications and the network interface for my client.
 
If we can end up getting Orbiter running on a fire breathing monster of a computer, and a mission control style program running on an old computer running linux with both communicating - Awesome. I've tried Linux on my old 800MHz PC and something like that would be pretty good.
Also good would be getting orbiter to run under linux. I know its possible with wine, but opening up F4 style menus causes it to crash. Ah well, maybe in the future.
 
An update on where I am: I have the Surface MFD pretty much done. I'm a bit stalled right now due to school, but next up will be the Orb:Connect modifications and the network interface for my client.
No sneak peek? :)
 
Sneak Peek, actual size:
 

Attachments

  • mfd.jpg
    mfd.jpg
    79.9 KB · Views: 42
Back
Top