• Which the release of FS2020 we see an explosition of activity on the forun and of course we are very happy to see this. But having all questions about FS2020 in one forum becomes a bit messy. So therefore we would like to ask you all to use the following guidelines when posting your questions:

    • Tag FS2020 specific questions with the MSFS2020 tag.
    • Questions about making 3D assets can be posted in the 3D asset design forum. Either post them in the subforum of the modelling tool you use or in the general forum if they are general.
    • Questions about aircraft design can be posted in the Aircraft design forum
    • Questions about airport design can be posted in the FS2020 airport design forum. Once airport development tools have been updated for FS2020 you can post tool speciifc questions in the subforums of those tools as well of course.
    • Questions about terrain design can be posted in the FS2020 terrain design forum.
    • Questions about SimConnect can be posted in the SimConnect forum.

    Any other question that is not specific to an aspect of development or tool can be posted in the General chat forum.

    By following these guidelines we make sure that the forums remain easy to read for everybody and also that the right people can find your post to answer it.

MSFS20 Trying to set an LVAR, but unsure of the timing.

Messages
75
Country
us-newyork
I am working with WASM standalone sample from SDK. I am declaring and setting some LVARS, all of which work fine, except, one of them I would like to set to TRUE when my WASM app is active... sort of, declare "hey, I am running!". The purpose of this is to let other WASM apps know this one is running, so that certain tasks are (or aren't) performed.
The problem I have is that, if I set this LVAR in module_init block, just after I declare it:
Code:
extern "C" MSFS_CALLBACK void module_init(void)
...
    hr = SimConnect_AddToDataDefinition(hSimConnect, DEF_MYAPP_LVARS, "L:LVAR_MYAPP_IS_ACTIVE", "number", SIMCONNECT_DATATYPE_FLOAT64);
    m_Def_MYAPP_LVARS.LVAR_MYAPP_IS_ACTIVE= 1.0f
    hr = SimConnect_SetDataOnSimObject(hSimConnect, DEF_MYAPP_LVARS, SIMCONNECT_SIMOBJECT_TYPE_USER, 0, 0, sizeof(Def_MYAPP_LVARS), &m_Def_MYAPP_LVARS);
...
hr = SimConnect_CallDispatch(hSimConnect, MyDispatchProc, NULL);
...
}
This LVAR is NOT set to 1 (Later in the code, I check the value by requesting the LVAR and checking its contents, which comes back as 0)

In order to have it set to 1, I have to do the SimConnect_SetDataOnSimObject bit in the actual MyDispatchProc.

So my question is, what are the nuances of timing in there? Why are LVARS "settable" only when set inside the MyDispatchProc? Or, am I doing something wrong?
 
Hi Hornet,

My first question is why are you using SimConnect from a WASM module to manipulate vars? There are more efficient dedicated functions for that (Gauge API). To create an L var you could use
https://docs.flightsimulator.com/html/Programming_Tools/WASM/Gauge_API/register_named_variable.htm followed by https://docs.flightsimulator.com/html/Programming_Tools/WASM/Gauge_API/set_named_variable_value.htm

Back to your SimConnect code, what is m_Def_MYAPP_LVARS? In the first SimConnect call you're declaring that DEF_MYAPP_LVARS contains (starts with?) a double size value, but it seems to be a struct and the LVAR_MYAPP_IS_ACTIVE
member is a float type (not a double), and it is unclear where in the struct it is actually positioned. I'm confused about what this is supposed to do. So it's possible SimConnect is also confused. Though you say the same call to SetDataOnSimObject() works later? Do you add other definitions for DEF_MAPP_LVARS in the interim... or something?

Personally I've never tried var definitions, or setting them, with SimConnect in a WASM module, especially from the module_init() call, but seems odd if that doesn't work... all the SimConnect calls I've used from inside module_init() do work, such as setting up client data areas, custom events, and SubscribeToSystemEvent(). I suppose potentially there's some undiscovered bug there since I'm guessing most people would just use the Gauge API functions.

I assume there's a call to SimConnect_Open() in there somewhere, before using the other SimConnect functions? In external apps I never assume a valid connection until SIMCONNECT_RECV_ID_OPEN message is actually received, but in a WASM module this shouldn't be necessary... that I know of.

Just curious, are you actually checking the hr value after each of those calls? It's a good idea. Or don't bother assigning them in the first place if you're not using the result (all the SimConnect examples which do that are dumb).

What about checking for SimConnect SIMCONNECT_RECV_ID_EXCEPTION messages (in your message dispatch function)? Also a good idea, since it may be trying to tell you what's wrong. There is also the main dev mode console output log, plus the dev mode SimConnect inspector thing.

That's all I got for now... :-)

Cheers,
-Max
 
Thanks for taking time replying, Max!

So yeah, as I was mentioning, this is a standalone WASM module, nothing to do with gauges, and I am quite comfortable with it, I did quite a few projects under contracts, and some personal ones. Standalone WASM modules don't even include any gauge headers. To me, the LVAR code for SimConnect/WASM is quite simple and elegant, and my area of expertise is C++. And while I have a question about this particular problem, the rest of the code works quite well.

To answer your questions: m_Def_MYAPP_LVARS is a struct:
Code:
struct Def_MYAPP_LVARS
{
    double  LVAR_MYAPP_IS_ACTIVE                = 0.0f;
    double  LVAR_MYAPP_LVAR1                      = 0.0f;
    double  LVAR_MYAPP_LVAR2                      = 0.0f;
    double  LVAR_MYAPP_LVAR3                      = 0.0f;
    double  LVAR_MYAPP_LVAR4                      = 0.0f;
};
Def_MYAPP_LVARS m_Def_MYAPP_LVARS;
and, I assemble them with:
Code:
hr = SimConnect_AddToDataDefinition(hSimConnect, DEF_MYAPP_LVARS, "L:LVAR_MYAPP_IS_ACTIVE",                "number", SIMCONNECT_DATATYPE_FLOAT64);
hr = SimConnect_AddToDataDefinition(hSimConnect, DEF_MYAPP_LVARS, "L:LVAR_MYAPP_LVAR1",                "number", SIMCONNECT_DATATYPE_FLOAT64);
...

Then, I use them within the MyDispatchProc() callback loop as needed, for example:
Code:
case EVENT_Z_KEY:
{
     m_Def_MYAPP_LVARS.LVAR_MYAPP_LVAR3 = 13.5f;
     m_Def_MYAPP_LVARS.LVAR_MYAPP_IS_ACTIVE = 1.0f;
     hr = SimConnect_SetDataOnSimObject(hSimConnect, DEF_MYAPP_LVARS, SIMCONNECT_SIMOBJECT_TYPE_USER, 0, 0, sizeof(Def_MYAPP_LVARS), &m_Def_MYAPP_LVARS);
}
break;

And that works perfectly. However... if I want to set an LVAR OUTSIDE MyDispatchProc() callback loop, for example, like this:
Code:
extern "C" MSFS_CALLBACK void module_init(void)
{
    hSimConnect = 0;
    HRESULT hr = SimConnect_Open(&hSimConnect, "My Module", NULL, 0, 0, 0);
    if (hr != S_OK)
    {
        fprintf(stderr, "[Could not open SimConnect connection.]\n");
        return;
    }
    else
    {
        fprintf(stderr, "connected to SimConnect.\n");
    }

     hr = SimConnect_AddToDataDefinition(hSimConnect, DEF_MYAPP_LVARS, "L:LVAR_MYAPP_IS_ACTIVE",                "number", SIMCONNECT_DATATYPE_FLOAT64);
     hr = SimConnect_AddToDataDefinition(hSimConnect, DEF_MYAPP_LVARS, "L:LVAR_MYAPP_LVAR1",                "number", SIMCONNECT_DATATYPE_FLOAT64);

     m_Def_MYAPP_LVARS.LVAR_MYAPP_IS_ACTIVE = 1.0
     hr = SimConnect_SetDataOnSimObject(hSimConnect, DEF_MYAPP_LVARS, SIMCONNECT_SIMOBJECT_TYPE_USER, 0, 0, sizeof(Def_MYAPP_LVARS), &m_Def_MYAPP_LVARS);

    hr = SimConnect_CallDispatch(hSimConnect, MyDispatchProc, NULL);
    if (hr != S_OK)
    {
        fprintf(stderr, "[Could not set dispatch proc.]\n");
        return;
    }
}

.. the m_Def_MYAPP_LVARS.LVAR_MYAPP_IS_ACTIVE is NOT set to 1.

So - why is that?

oh, and the SimConnect_SetDataOnSimObject call outside the callback loop (as in above) is NOT failing. hr comes back as S_OK.

thanks again,
Hornet
 
Last edited:
oh, and the SimConnect_SetDataOnSimObject call outside the callback loop (as in above) is NOT failing. hr comes back as S_OK.
Not necessarily true. All S_OK means is that no error has been thrown. You might also want to take a look at how I've set up the despatch_proc in the simconnect samples in sd2gau; I don't do any work in there at all.
 
Hi Hornet,

Thanks for the details, clearer now! And based on that.... I don't know why it's not getting set properly in module_init(). 🤷‍♂️ I've never seen this come up (in various forums), so it might be a new quirk you discovered. Fun!

So all the AddToDataDefinition() calls work in module_init() (presumably, since you can use the DEF_MYAPP_LVARS later), but not SetDataOnSimObject(), right? I wonder if the "user object" doesn't exist yet when standalone modules are initialized. So you may be right about timing. Somewhat academic, but I'd be curious to know when the LVAR_MYAPP_IS_ACTIVE is actually created in the sim... eg. if you only call SetDataOnSimObject(hSimConnect, DEF_MYAPP_LVARS, ...) in module_init(), (and not later) do the vars even exist once the sim boots?

Did you check dev mode output console or SimConnect log/status/SIMCONNECT_RECV_ID_EXCEPTION? Maybe there's a clue in there somewhere. If nothing is logged and it's just failing silently then it probably deserves a bug report (FWIW). Even if this is "expected" behavior due to timing or whatever, there should at least be some indication, I think.

Regarding "Gauge" API, it can be used from standalone modules with no problems. It's a "C-style" interface but so is SimConnect, and either can be used from C++ of course. Quite simple to use, simpler than SimConnect IMHO.

I'm curious if creating & setting the L var from module_init() using the Gauge API functions would work or if that would run into the same issue. I think we would have heard by now if it doesn't, but who knows!

Cheers,
-Max

PS. One workaround, if you haven't tried it yet, is to set your LVAR_MYAPP_IS_ACTIVE in your dispatch function's SIMCONNECT_RECV_ID_OPEN message handler, since that will only run once anyway. (And technically maybe it is even more accurate to say your module is fully loaded once SimConnect is actually connected.) Again would interesting to see if that works properly.
 
Last edited:
Interesting problem. Your set up is quite correct, I don't see anything wrong but, my first thought (as Max mentioned) was that, since LVARS are being set through SimObjects using SimConnect_SetDataOnSimObject, and in this case, user object, perhaps that user object does not exist yet. So - I set out to test this in one of my projects.

Now, within SDK environment, we have an option to invoke the WASM module from almost any point while interacting with sim (Either in the UI, rotating globe, or actually, while in-sim). And, lo and behold - when "build" is performed in SDK from within pre-flight interface (globe UI), this call indeed fails, as you specified. BUT - if you perform a build while in-flight, it actually works! My best guess is obvious - the user object (user aircraft) exists in-flight, while it is obviously not yet created/spawned while in the pre-flight UI. So, that, for the lack of a better explanation, would be my best guess. The sim obviously knows WHAT aircraft will be the user aircraft (there is always one selected) but I guess it knows it only by its string title, to be used for spawning when the flight is initiated. So, if you want all the other WASMs to know your WASM is "alive", that will be possible only once you are in-flight. You will have to come up with some other scheme if you need this before the user starts flying.

And, why the call doesn't return an error, as in, "Method failed: No SimObject found" is beyond me.
 
Hey, thanks everyone @MaxPaperno , @DragonflightDesign , @Misho for your invaluable insight! Correct, Misho, I checked starting up the module in UI and during the flight, and indeed, the LVAR is being set as you described... so it MUST be the lack of SimObject that is not setting it while in UI. That means I should be probably setting it just after the user aircraft is loaded... does that seem correct?

But yeah, that does seem to make sense, when there is no user aircraft, it cannot be used to set LVARS through it.
 
Assuming there's no major differences to that part of the sim compared to Prepar3D, all processing is suspended when a dialog (i.e. dropdown menu) is active. I'm in agreement with Misho that the user aircraft is not completely loaded in the pre-flight UI. I'm not sure if the following will work in MSFS202X, but take a look at the 'Letting the Sim Tell You When it's Ready' topic in sd2gau; you may be able to translate it to MSFS202X.
 
@DragonflightDesign , there is a very handy way of seeing at what stage the sim is, and I am using it with good results: Reading the "CAMERA STATE" simVar. You can set up a simple SimConnect app that reports the state as it changes. It has a list of around 20 different states that indicate in what state the sim is, covering pretty much everything. Some states are undocumented, like 18, which is a developer mode drone camera.
 
Back
Top