sherlock wrote:
But the question is what do those extra 12 bytes after the "campid" field do? What function do they perform? After that question is answered (depending on what the answer is) we can move forward but I don't think it wise to just discard them without considering the question first.
I've really no idea what those fields do yet. Let's assume for a moment that they do something interesting. Nice, but who cares? F4AF can read older formats that don't have those bytes in there, and does it change your flying experience? No. Think of it like this -- if you saved a Microsoft Word 2007 document in an earlier Microsoft Word format, sure, you'd be throwing away some information, but most of that is going to be information you didn't really care about in the first place. However you'd have achieved compatibility with someone running an older version of Word. In our case by discarding certain information from the F4AF format, we achieve compatibility with TacEdit.
sherlock wrote:
Also, what is "CampBaseClass" and what purpose does it serve? (if you know).
Ok, first you'd have to understand the general concept of a class:
A "class" is basically a chunk of code that represents some sort of object (in the physical world, or in some abstract sense). For example, you could define a class called "Airplane", that provided some data (aka "properties", or "fields"), such as "Current airspeed", "Current altitude", "current heading", etc. that the programmer could read or write to in-memory. Classes can also provide behavior (aka "methods"). For example, one method on an Airplane class might be called "Turn", and another method might be called "Climb". Those methods would act upon and modify the data such as "Current altitude" and "current airspeed".
A class might also provide certain "utility" behavior, such as the ability to read or write that data to disk, in a certain format. That would be really nice because then the programmer who's using that class doesn't have to be concerned about the format of the data -- the class itself will handle that.
With that said, let's talk about serialization. Very easy concept here -- serialization, in plain English, is the process of "Writing to a file". Deserialization would be the reverse ("reading from a file").
Now let's talk about Falcon:
All the code classes in Falcon that represent campaign objectives and units, descend from one single "base" class, called "CampBaseClass". Common data elements (like "Location X/Y", object ID, etc.) belong to CampBaseClass. Therefore, every objective, and every unit, inherits those same properties, but each "child" class adds its own data and behavior in addition to the stuff that it inherits from "CampBaseClass".
Here's where it all comes together.
Anytime Falcon reads some piece of objective or unit data from a .CAM/.TRN/.TAC file, the data itself specifies the type of unit or objective that it represents. Falcon then knows which class to give the "raw" data to.
Each objective or unit class is then responsible for reassembling all its own raw data back into the proper structures in memory (i.e., deserializing it).
Now things get tricky.
Each class is only interested in its own data, not any data it inherited from a parent class. So, to work around this, during deserialization, each "child" class first hands the raw data off to its parent class, so that the parent class can deserialize *its* data. When the parent class is done reading its own data, the child class can then proceed with deserializing its own data. Of course, even a parent has parents. So, when a child class invokes its parent class to perform deserialization, the parent class invokes *its* parent, and so on. This process typically proceeds all the way back to the "Adam" class at the root of the inheritance tree. In Falcon, that class is "CampBaseClass". (Actually it goes a bit further, but it's not important for this discussion).
Now let's look at what happens if some parent class (or grandparent, etc.) reads TOO much data from the file. Assuming nothing breaks earlier on in the process, then, when control of the process utimately returns to the child class at the end, the file is positioned PAST the start of where that child class' data is supposed to begin. Sooner or later some child class is going to run past the end of the file, and bang, kablooey, an outright error will occur. Even if an error did not occur, the data in memory would still be corrupt...
The reverse situation is also possible, where a parent does not move the file far enough and so a child class ends up reading data that does not belong to itself. So, that's why the files contain version information.
The class can say "if it's version 21 or later, read 4 bytes for this field, or else don't try to read that field at all, it didn't exist till version 21".
What's happening in the case of the F4AF format is, you have an older tool, TacEdit, that doesn't know about any changes that were made to the format after about version (71-75, or so, maybe a tad later). So by stripping out any additional information from the files and then resetting the version number so it's consistent with the layout, TacEdit will work just fine on these. And F4AF won't puke on them either, coming back from TacEdit. F4AF will just silently re-upgrade them to the latest versions during the next save cycle. So you don't need a tool that goes in both directions, just a tool to migrate the newer formats backward.
Now the other alternative that I mentioned was to just add those extra bytes to TacEdit (assuming we have the source code for TacEdit somewhere...), even if we don't know their purpose. Or someone can write a whole new TacEdit...
Or someone here with some connections can inquire with some Lead Pursuit people and see if we can get the information on what was added to the .OBJ file (and the others) from, say, version 75 forward. We've got options
sherlock wrote:
Finally, can you post the file format information you have the deciphered files you have done so far (that you refer to above)?
I will. My plan was to conquer the whole set of embedded files and then post all the details including some example C# code that can read and interpret all those files. As well, I will then describe the physical layouts in a bunch of Wiki entries that will be linked to off the .CAM/.TRN/.TAC entry. Though the code will probably be more instructive than the descriptions. There's quite a bit of branching in order to handle different versions of the files...