Thursday, May 17, 2007

SP1 is Live - New SDK Features

Talking about being really late on this.

Yes, you all probably know that the SP1 patch for FSX is out and can be found at FSInsider.com. The big news in relation to this blog is that there are tons and tons of features and fixes for SimConnect such as the following:

Facilities API
This was a top-level request from the community for programmatic access to our internal data set for things like airports, navigational aids and waypoints. Full support through both the native and managed interfaces, including new samples and documentation.

Modeless Dialog API
Ability to utilize an ATC-like XUI menu to allow modeless interaction with a SimConnect client. This was the last remaining feature of SimConnect required to meet the needs of FSUIPC interaction without binary offset manipulation. Supports both native and managed interfaces, and includes ability to manipulate a subset of the text format. Documentation and samples are also provided.


These two additions to the package integrate seamlessly with your code and add a wealth of information. Right off the bat, the modeless dialog lets you send feedback or collect user input via ATC/ATIS menus in the sim. I've done some work with the new APIs during beta testing, and I think they are fantastic.


Important to note that the SP1A patch on the site requires the original SDK (or a patched to SP1) version from the Deluxe edition of FSX.

Labels: ,

Monday, December 11, 2006

The Reason I Don't Make Promises

I got cranking on TrackerX this weekend, and I'm happy to say that shortly it will be ready for Beta.

To give you an idea of how soon, I'm just a bit too tired to finish up the last little section of the site, package up the installer, create an icon and put it up tonight, so I'll get that done tomorrow.

I really like how it all works. Nothing complicated, just location details being uploaded from the .NET program to a database and then displayed on an interactive googlemap on the website.

All in all, I think its kind of slick. In the future, I'll be adding in support for viewing the path the flight has taken and take-off and destination spots if you have a flight plan filed. It's one of those "side-project, add stuff when you have the chance" type of programs, but I think it looks nice.

I've got some bugs involving the PDMarkers and Google maps, but I think when I do a big clean up of the code down the line, some of those will be resolved. They are all on the webpage, not the program itself, so that's good.

Labels: ,

Thursday, December 7, 2006

A Ten-Thousand Foot View of SimConnect - Part 3

By this point, we have a basic operation that connects to SimConnect at the click of a button...and does nothing. So it's about time we start looking at the framework of how to actually interact with FSX.

You may have read, heard or gotten involved in the conversations about multithreading, hyperthreading, fibers, etc., but all you really need to know about the whole concept is the message queue. As we said before, your SimConnect program (like other Windows applications) is Event Driven. This means that the program acts on events sent to it from the system. Say for instance, you click on our "Connect" button. The operating system registers that mouse click, and sends a message to the program. The program gets the message, containing the click event, and fires off our function in response. A lot of this is transparent, because it is built into Windows and the .NET framework, but we have the ability to expose some of the functionality and expand upon it, which is exactly what we plan to do. In SimConnect, events and data are sent to our program via system messages.

For an in-depth look at the Windows System Message system, check out this page:
Messages and Message Queues

The core of our application's message system is the "Windows Procedures" or WinProc. It is a function that receives system messages and figures out what to do with them. We want to have our program handle the SimConnect messages when they come down the pipe, so we use an ability in programming to "override" the default function. This just means that we are taking an already defined function and creating our own version of it. In the case of the WinProc, it will look something like this:

protected override void DefWndProc(ref Message m)
{
  if (m.Msg == WM_USER_SIMCONNECT)
  {
    if (simconnect != null)
    {
      simconnect.ReceiveMessage();
    }
  }
  else
  {
    base.DefWndProc(ref m);
  }
}

As you can see, we are defining the function called DefWndProc, or Default Windows Procedures. "Protected" refers to the accessibility of the function in a way, meaning who can access or alter it. We have already talked about override, that tells us that we are making our own version of an existing function, and void is the return type. Functions can return a value, such as if you have a function that adds two integers together, the return value could be the sum. When you see void, it means that there is no return value.


Looking closer at the meat of the function, we discover our old friend WM_USER_SIMCONNECT. You will recall that we defined this constant variable back at the beginning and sent him along with our connection function. This variable identifies the system messages coming from FSX. When we connect to SimConnect, we pass along this identifier, and whenever FSX sends a message back to us, it has that same value attached to it. So by looking for that value, we know that it has come from SimConnect. Then, the function continues: "if the simconnect object is not null (meaning we have connected to FSX already), then run the method simconnect.ReceiveMessage( )". This is the function within the SimConnect framework that processes the messages sent to us and figures out what we want to do with them. If it's not a message from FSX, process it as normal. Basically, there's no reason why we would ever need to change this. We can just stick it in our Form1 class under the button click function and know that it will do what we want.


So now we are ready to handle messages from SimConnect. The first one we want to look for is the message telling us that our add-on has successfully connected to FSX. The messages contain data structures, which are just variables grouped together into a consolidated object. Think of them like classes, but without the functions. All we need to know about them is that they are little bundles of data wrapped into one object. The SIMCONNECT_RECV_OPEN data structure contains a whole slew of information about the connection, the version of SimConnect, all of that lovely nonsense. Right now, we don't need any of that, we just need to know what happens, and when.


Luckily, ACES likes us, and has put that functionality into the SimConnect wrapper. After we have our connection to SimConnect, and therefore, our simconnect object is defined, we can start adding stuff to it. The first thing is event handlers. This doesn't require a whole lot of explanation. It's just a statement of what function to run when a certain event is received.


NOTE: You may have noticed already that Visual C# Express has an "autocomplete" function. This is incredibly useful (although sometimes it gets in your way when you are coding quickly), in that it automates certain procedures based on what you are probably trying to do. In the case of these event handlers, they will allow you to press the tab key to enter the default values, and will even create the new function for you, like what happened with our button click function.


Speaking of our button click function, here it is as it stands right now:


        private void button_Connect_Click(object sender, EventArgs e)
        {
            try
            {
                simconnect = new SimConnect("SimConnect Tutorial", this.Handle, WM_USER_SIMCONNECT, null, 0);
                textBox_Connect.Text = "Connected to FSX";
            }
            catch (COMException ex)
            {
                textBox_Connect.Text = "Unable to Connect";
            }
        }

Right after our the line that sets the textbox text to "Connected to FSX" but before the } (curly bracket), we are going to enter this line:

simconnect.OnRecvOpen += new SimConnect.RecvOpenEventHandler(simconnect_OnRecvOpen);



As soon as you type "simconnect.", a drop down box will appear with all of the properties and methods of this object, as I mentioned above. You can type in "OnRecvOpen" or find it on the list. So far, we've only used the equal sign by itself (=), but here we use plus sign equal sign (+=). This adds a value to a definition, as opposed to just assigning a value. In this case, it is adding something new to the function that processes when the "Open" message is received (which happens when SimConnect is connected). Immediately after typing "+=", you should be presented with an option to press tab to enter the default value, and then to press tab again to create the new function automagically. That's the method I followed here. As you can see, we are adding a new event handler to the OnRecvOpen event, that fires off the function "simconnect_OnRecvOpen". In this function, we define what we want to do when FSX has told us that we are connected.


Everyone with me still? Just in case more clarification is needed, I mapped it out in another of the "Worst Flowcharts Ever" (click for full-size)



As you can see, SimConnect sends messages (events) into the message queue, which the OS sends to our program. The DefWndProc passes them along to the simconnect object, which sees that there is an event handler for this event. On top of that, we have added our own event handler to the mix, and in that we do whatever we need to do.


If you tabbed through the creation of our event handler line, you will notice that it added the function "simconnect_OnRecvOpen" to the code. There's an exception in there right now, telling us that we haven't done anything with it yet. We want to remove that. In it's place, just cut and paste the following line from our button click function:

textBox_Connect.Text = "Connected to FSX";


Because, really, we don't really want to tell the user that we are connected until we are sure that we are connected. This waits until we receive notification from SimConnect that the connection is made, then changes the status. Make sure you remove that line from it's original position as well. If you want to be fancy, you can leave it in, but change the text to "Connecting..." or something like that. In most cases, it won't be up very long anyways.


We're going to add another event handler right under our first one. This time, it's to catch the event that SimConnect sends out if the user quits out of FSX. The handler is OnRecvQuit, and the line looks like this:

simconnect.OnRecvQuit += new SimConnect.RecvQuitEventHandler(simconnect_OnRecvQuit);


If we use tab and autocomplete again, it will create another function called simconnect_OnRecvQuit. We're just going to add a line in there to tell the user that we have been disconnected.


        void simconnect_OnRecvQuit(SimConnect sender, SIMCONNECT_RECV data)
        {
            textBox_Connect.Text = "Disconnected";
        }


Now, run the program (once again, click the green arrow or use the menu option Debug -> Start Debugging. The shortcut key is F5) without FSX running. If we press the connect button, we should get a message telling us "Unable to Connect". Load FSX, start a flight, and press connect again. Now it should report that we are connected. Leave the program running, and exit out of FSX. Now we are informed that SimConnect has disconnected.


And then we get an exception.


Go back up to the debug menu and select "Stop Debugging". VC# will take you back to the basic code view. What went wrong? Well, we don't have SimConnect running anymore, but we still have the simconnect object waiting for messages. So we need to get rid of the simconnect object within our program. Luckily, again, they give us a simple way to do this, called the Dispose method. Add these two lines of code to dispose of the simconnect object and set it back to null where we started:


        void simconnect_OnRecvQuit(SimConnect sender, SIMCONNECT_RECV data)
        {
            textBox_Connect.Text = "Disconnected";
            simconnect.Dispose();
            simconnect = null;
        }


Try it again and everything should work as expected.


Now we have a good framework for the program, have the connection and some events running, but we also want to think about what the user might want to do. For our last step tonight, we are going to expand our button click function to turn the connect button into a disconnect button when we connect.


This is going to take a few lines of code throughout our program. First, in our simconnect_OnRecvOpen function, we want to change the text of the button to "Disconnect". When the program connects to FSX, this will just change what the button says. Right after the textbox line, add the following line of code:

button_Connect.Text = "Disconnect";


Same deal with the simconnect_OnRecvQuit function:

button_Connect.Text = "Connect";


So now, when the program connects or disconnects, the button changes. Now to implement the functionality, we use a if - then - else loop. This is called a "conditional". If this is true, do this, else do this. I'll paste the new button click code and then explain it.


        private void button_Connect_Click(object sender, EventArgs e)
        {
            if (simconnect == null)
            {
                try
                {
                    simconnect = new SimConnect("SimConnect Tutorial", this.Handle, WM_USER_SIMCONNECT, null, 0);
                    textBox_Connect.Text = "Connecting...";
 
                    simconnect.OnRecvOpen += new SimConnect.RecvOpenEventHandler(simconnect_OnRecvOpen);
                    simconnect.OnRecvQuit += new SimConnect.RecvQuitEventHandler(simconnect_OnRecvQuit);
                }
                catch (COMException ex)
                {
                    textBox_Connect.Text = "Unable to Connect";
                }
            }
            else
            {
                textBox_Connect.Text = "Disconnected";
                button_Connect.Text = "Connect";
                simconnect.Dispose();
                simconnect = null;
            }
        }


If our simconnect object equals (== compares two values, as opposed to = which just sets a value) null, meaning that we do not yet have a connected simconnect object, then run through our connection procedure. ELSE, if it does not equals null, meaning that we are connected, then do the same thing as if FSX just quit. Set our text to show that there is no connection and dispose of the SimConnect object.


Try it out. Run your program and FSX and you should find yourself able to connect and disconnect as many times as you want, both by using the button and by closing FSX.


By now, hopefully a lot of the theory behind this is understood. I've tried to put a lot of detail into a very small bit of actual operation so that those who aren't familiar with the procedures of programming or C# or even just SimConnect will be able to ride along smoothly down the line.


As of now, we have a program that is able to connect and disconnect from SimConnect, can detect and handle events sent from FSX, and has the beginnings of a useable interface. Not bad for a few lessons, I think. Now that we have a framework for events, we are going to use that ability to send and listen to events, so that we can control the toggling of landing gear from outside the program, and then to detect when the gear are up or down.


Could this happen tomorrow? Maybe. I'll certainly try my best to get it done by the end of the day (Friday).


And finally, here is the full code as I have it right now for Form1.cs:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.FlightSimulator.SimConnect;
using System.Runtime.InteropServices;
 
namespace SimConnect_Tutorial
{
    public partial class Form1 : Form
    {
        SimConnect simconnect;
        const int WM_USER_SIMCONNECT = 0x0402;
 
        public Form1()
        { 
            InitializeComponent();
        }
 
        private void button_Connect_Click(object sender, EventArgs e)
        {
            if (simconnect == null)
            {
                try
                {
                    simconnect = new SimConnect("SimConnect Tutorial", this.Handle, WM_USER_SIMCONNECT, null, 0);
                    textBox_Connect.Text = "Connecting...";
 
                    simconnect.OnRecvOpen += new SimConnect.RecvOpenEventHandler(simconnect_OnRecvOpen);
                    simconnect.OnRecvQuit += new SimConnect.RecvQuitEventHandler(simconnect_OnRecvQuit);
                }
                catch (COMException ex)
                {
                    textBox_Connect.Text = "Unable to Connect";
                }
            }
            else
            {
                textBox_Connect.Text = "Disconnected";
                button_Connect.Text = "Connect";
                simconnect.Dispose();
                simconnect = null;
            }
        }
 
        void simconnect_OnRecvQuit(SimConnect sender, SIMCONNECT_RECV data)
        {
            textBox_Connect.Text = "Disconnected";
            button_Connect.Text = "Connect";
            simconnect.Dispose();
            simconnect = null;
        }
 
        void simconnect_OnRecvOpen(SimConnect sender, SIMCONNECT_RECV_OPEN data)
        {
            textBox_Connect.Text = "Connected to FSX";
            button_Connect.Text = "Disconnect";
        }
 
        protected override void DefWndProc(ref Message m)
        {
            if (m.Msg == WM_USER_SIMCONNECT)
            {
                if (simconnect != null)
                {
                    simconnect.ReceiveMessage();
                }
            }
            else
            {
                base.DefWndProc(ref m);
            }
        }
    }
}

Labels: , ,

Wednesday, December 6, 2006

Updating from Work

A few quick hits:

  • I'm thinking about what would be better: longer, more in-depth tutorials that cover more ground and more detail, or short feature blogs that would take one step and then stop. Obviously, there are benefits to both methods. The short blogs could be posted more often, and would be easy to implement. The longer tutorials would have a greater sense of accomplishment and would have a greater lens on the fine details and inner workings of what you are doing. The purpose is, of course, not to just have you copy my code, but to understand why it works the way it works. The downside to the longer posts is that they probably would be less frequent than the daily updates I had planned on.
  • This project is completely open to suggestions. I have my own goals to accomplish with my programs, but this is separate from that. If you want to learn how to do something, let me know, and I'll incorporate it, assuming I can.
  • Icarus (my FSX add-on) is officially in-development. I even bought a big whiteboard to map everything out on. In case you don't know, Icarus is a program that replaces a good portion of the AI handling in FSX. Currently, I am hoping that I won't have to take over the actual flying of the planes (FSX actually does a rather good job of that), but mostly the way they are vectored via the ATC and how they act on the ground. This includes SIDS and STARS, multiple runways for takeoffs and landing (including crossing runways) better spacing (hopefully resulting in no go-arounds) and a number of other little features.
  • I will be looking for beta testers sometime early next year. The guys I really need are the people who have traffic packages (MyTrafficX, etc) installed. The goal is to accurately and smoothly integrate with those add-ons.
  • Although Icarus is going to be payware (it's a pretty complex undertaking), I am absolutely open to doing as many freeware tools as I can. First off, some of this stuff is not that difficult. Some is, but it's fun to make, so I'll do it anyways. Any ideas?
  • I definitely need beta testers soon for a project that I am almost finished with. It's called TrackerX, and it's basically a FlightAware.com style webpage for FSX. All you do is run a tiny little tray app while you fly, and it uploads your positional info to a database and displays it on a map with everyone else. So far, it's looking really cool, but once the webpage is close to finished, I want to be able to run with it.

That's all for now. Part Three of the tutorial will go up tonight, barring any craziness. I'll also be adding a link section on the sidebar for these tutorials, so you don't have to go digging around everywhere.

(P.S. - I like readers. Tell your friends )

Labels: , , ,

Friday, December 1, 2006

Engine Fires and Oil Leakage

Over at the Avsim SimConnect Forum, Endre brought up the question of getting engine fires and oil leaks to occur with SimConnect. He said that neither worked properly, so I set out to put together a program to show how it would indeed work as it should.

Problem is, it didn't.

I haven't tried this solution in C++, so it may just be an issue with the managed wrapper. But I think it's more likely that something doesn't work or we aren't implementing it right.

First off, the variables:

ENG ON FIRE:index On fire state
GENERAL ENG OIL LEAKED
PERCENT:index
Percent of max oil
capacity leaked


As you can see, ENG ON FIRE is a simple on/off switch for the failure (so it seems) and our oil var is just a percentage of how much oil has been lost. However, our second variable is read-only.

The ever-brilliant Pete Dowson ( http://www.schiratti.com/dowson.html ) has told us that most of the time in that case, we have to find an event that mirrors the effect. So far, I haven't found an event for either of these. Maybe someone has and can point me in the right direction. Because without an event and with the variable non-settable, we won't be able to do anything with it.

So the code is as follows (just for the engine part of things)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

// Include Simconnect and Interop References
// Remember to reference the SDK .DLL in the project
using Microsoft.FlightSimulator.SimConnect;
using System.Runtime.InteropServices;

namespace Engine_Fire
{
// Standard Windows Form, see the designer for placement
public partial class Form1 : Form
{
// SimConnect Object
SimConnect simconnect;

// User-defined win32 event
const int WM_USER_SIMCONNECT = 0x0402;

// Data definitions
enum DEFINITIONS
{
EngineData,
}

// Requests
enum DATA_REQUESTS
{
SET_ENGINE_FIRE,
}

// Our engine data struct.
// Standard marshalling message
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct EngineData
{
public bool engine1fire;
public bool engine2fire;
};

// Our initializer
// To-do: Initialize Simconnect object,
// Set up data definitions,
// Add struct to marshaller
public Form1()
{
InitializeComponent();

// Initialize SimConnect (this is straight from the SDK, just changed the app name)
simconnect = null;
try
{
simconnect = new SimConnect("Engine Fire Demo", this.Handle, WM_USER_SIMCONNECT, null, 0);
}
catch (COMException ex)
{
// A connection to the SimConnect server could not be established
// Normally you would handle the exception here
}

// Set up data definitions
simconnect.AddToDataDefinition(DEFINITIONS.EngineData, "Eng On Fire:0", "bool", SIMCONNECT_DATATYPE.FLOAT32, 0.0f, SimConnect.SIMCONNECT_UNUSED);
simconnect.AddToDataDefinition(DEFINITIONS.EngineData, "Eng On Fire:1", "bool", SIMCONNECT_DATATYPE.FLOAT32, 0.0f, SimConnect.SIMCONNECT_UNUSED);

// Add struct to marshaller
simconnect.RegisterDataDefineStruct(DEFINITIONS.EngineData);

}

// Default System Message Handler
protected override void DefWndProc(ref Message m)
{
if (m.Msg == WM_USER_SIMCONNECT)
{
if (simconnect != null)
{
simconnect.ReceiveMessage();
}
}
else
{
base.DefWndProc(ref m);
}
}

private void button1_Click(object sender, EventArgs e)
{
EngineData sendEngFire = new EngineData();

sendEngFire.engine1fire = true;
sendEngFire.engine2fire = true;
simconnect.SetDataOnSimObject(DEFINITIONS.EngineData, SimConnect.SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_DATA_SET_FLAG.DEFAULT, sendEngFire);
}
}
}


The key is the button1_Click function. I slapped a button my form and all it's doing is sending a message to FSX to set the ENG ON FIRE vars for engines 1 and 2 to "True". So I fire up FSX, run the code, press the button,

and nothing. No response. I check the console window, and the data certainly is being sent.

Just to make sure something wasn't backwards, I ran a test to pull the variables instead of setting them, and in normal flight, they are set to false, even after trying to set them to "true" with my program.

Here's a shot "in the thick of it" (click for larger version)



Even after sending the variables, they still come back as false.

My assumption right now is that I'm doing it wrong, and I'm certainly open to suggestions.

Labels: , , , , ,

SimConnect Debug Console

For those of you getting started with the SimConnect SDK, there is a message console that allows you to see pretty verbose output about what's happening with your program.

To get it running, copy the SimConnect.ini file from the SDK directory, located under Core Utilities Kit/SimConnect SDK/config and paste it into your My Documents/Flight Simulator X Files directory.

The file looks like this and turns on the console by default:

[SimConnect]
level=verbose
console=1
;RedirectStdOutToConsole=1
;OutputDebugString=1
;file=c:\simconnect%03u.log
;file_next_index=0
;file_max_index=9

For programs where you are doing a lot of data transfer or waiting on events, the log feature can be helpful as well. The SimConnect section of the SDK docs tells you in detail what each line does, but it should be pretty self explanatory.

Labels: ,

Wednesday, November 29, 2006

Little Signs of Life

Things are coming along nicely with the PFD so far.

Currently, I am pulling the bank and pitch angle.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct Struct1
{
public float bankangle;
public float pitchangle;
};

simconnect.AddToDataDefinition(DEFINITIONS.Struct1, "Plane Bank Degrees", "radians", SIMCONNECT_DATATYPE.FLOAT32, 0.0f, SimConnect.SIMCONNECT_UNUSED);
simconnect.AddToDataDefinition(DEFINITIONS.Struct1, "Plane Pitch Degrees", "radians", SIMCONNECT_DATATYPE.FLOAT32, 0.0f, SimConnect.SIMCONNECT_UNUSED);


After that, it's all pretty simple.

I've got three layers of texture, although, technically, it could be two. The first the large brown horizon, on top of that is a "glass ball" texture (using alpha to make it partially transparent) that includes the center marks, and the top black mask layer that frames it all.

Then it's just a matter of moving and rotating the horizon based on the angles that simconnect is sending me. The program runs at 60fps, and I've got FSX at 20fps, so I send really only get an update once every 3 frames on the client side, but it still looks smooth enough.

The core of the Update function is this:

RotationAngle = 0;

KeyboardState keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape))
{
Exit();
}
else
{
rotpasstrans = (float)hWindow.rotpass;
RotationAngle = rotpasstrans;

float switchPitch = (float)hWindow.pitchpass * -600.0f;
horizonPos.Y = (Window.ClientBounds.Width / 2.0f)+ switchPitch;
}


It's a bit messy, but it does the work.

Here's a screenshot of the PFD in action, chirping along (2048x800)



As you can see, it can use some polish and tuning, but for the most part, it's working perfectly. The next step is going to be sizing everything down a bit to make room for more stuff, and then adding the angle of attack registration lines, bank indicator at the top of the artificial horizon, and then the fun stuff: Heading indicator, and the speed and altitude tape.

I have an idea on how to do that, but it most certainly will not be as easy as I think it will.


I want to throw out a huge show of support for ZiggyWare for their wonderfully easy to use XNAFont tutorial. Although you don't see it there, I have been using it for debug purposes.

They have some great stuff going on over there, so I suggest checking out the tutorials if you want to get started from the ground floor on XNA programming.

More to come tomorrow, when I attempt to break everything.

Labels: , ,

SimConnect Datatypes

I overcame my last issue, with not being able to have an event handler, by nesting a call to open a hidden window in the initialization section, using the handle to that form for the SimConnect constructor. All of the event handlers and setup code for SimConnect stayed within that form's extended class. I kind of like it that way, like it was it's own little transport.

If I were to draw a diagram, the form would be represented by a Mini Cooper S.

With that solved, I moved on to the question of actually displaying my instruments. First up, just the artificial horizon. Two sprites, the blue background and the brown/orange "ground" section, that will move and rotate.

The data I'll be requesting from SimConnect is rather basic so far:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct Struct1
{
public float bankangle;
};
And then I set up my data definition:

simconnect.AddToDataDefinition(DEFINITIONS.Struct1, "Plane Bank Degrees", "radians", SIMCONNECT_DATATYPE.FLOAT64, 0.0f, SimConnect.SIMCONNECT_UNUSED);

Except, this is wrong.

By following this up with a call to pull in my data, I discovered all sorts of crazy numbers coming through as my bank angle. It didn't make any sense to me, until I looked back and found out the issue. The data type should be SIMCONNECT_DATATYPE.FLOAT32, not FLOAT64. As soon as that happened and my nice 32-bit doubles came flowing in, the horizon was banking beautifully, smooth as silk.

Later today, I'll be adding in the pitch on the horizon and pitch guide lines.

So, that's something to keep in mind if the data you are getting back doesn't make any sense.

Labels: ,

Tuesday, November 28, 2006

Swinging For The Fences

Leave it to me, of all people, to start hard.

I was trying to decide what to do first, a SimConnect project or a XNA project. Then I was struck with most absurd bit of inspiration and decided to combine the two. My first project on this blog is a Primary Flight Display for FSX, written in XNA and connecting with SimConnect. Right away, this presents a problem.

XNA is a cross-platform framework, meant to compile for both Windows XP and XBox360. This means that certain functionality, such as WinForms, is not natively present in the framework. SimConnect, on the other hand, is assuming that you are using standard .NET to create your programs and libraries. So they pass data to you via system messages. Here is the sample override for the defwndproc:

protected override void DefWndProc(ref Message m)
{
if (m.Msg == WM_USER_SIMCONNECT)
{
if (simconnect != null)
{
simconnect.ReceiveMessage();
}
}
else
{
base.DefWndProc(ref m);
}
}

This works great if you are using System.Windows.Forms, however the XNA Framework class 'Game' doesn't have a DefWndProc to override. Right now, the only option that presents itself would be to create a dummy windows form by including a reference to WinForms, and then calling the event handlers from there. This shouldn't be as tricky as it seems. I'll just put the call to run the game in the constructor for the Form class, and roll from there.

I'll see how that goes and update back here.


Labels: , ,

In The Beginning

I've done the livejournal thingy before, and MySpace and all that nonsense, but now I am moving into different avenues of my life and I finally have some stuff to blog about.

A little introduction, my name is Brian, 26, from Northern Virginia, and among other things, I'm the moderator of the SimConnect forum at avsim.com, the leading Flight Simulator enthusiast website. I'm also a developer who will be creating add-on programs for FSX (Flight Simulator X) and I wanted to chronicle that journey.

In addition to that, because my time isn't used up enough, I've been venturing into the world of game programming with the new Microsoft XNA framework. Although I'm not completely new to the world of game logic, this is a new level for me, so I'm going to struggle along and do a lot of things wrong.

The upside? You guys get to watch.

Labels: , , ,