Format info: Difference between revisions

From ENIGMA
Jump to navigation Jump to search
 
(No difference)

Latest revision as of 02:56, 10 March 2012

This has been copied from a text document with only minor modifications to wikify it. It may still need some more wikification.

Hex

Most GM files are in a binary format, meaning that you cannot use a text editor to view/modify them by hand, and attempts to do so will most likely corrupt your file.

You are encouraged to instead use a hex editor to examine GM files and/or make modifications. For Windows, I would strongly recommend XVI32 and for Linux I would recommend Okteta, although GHex tends to be sufficient for most purposes.

Legality

I have thoroughly reviewed the License Agreement of Game Maker, and have a general knowledge of copyrights and such. These activities are legal, as long as I do not tamper with the compiler and as long as I maintain credit to Mark Overmars for the original Game Maker, which I will make sure to revere and worship greatly in this product. A note from Mark Overmars himself regarding this activity:

Sorry for not replying earlier. I was first was on holidays and then trying to catch up. I don;t think this is an important issue. Actually .gm6 files are not really protected. And even though I prefer people not to hack them, I cannot see a reason to be worried about this.



Mark

sic

Version

From time to time, you'll see some bytes documented as "GM Version needed for the following info". For resources, first GM version tells when the resource type was added, while the second GM version tells when the last update of the resource type was.

  • 800 for GM8.0 (notice, GM8's GMKs are zlib compressed. Please see Note About GM8 below)
  • 702 for GM7.0 (notice, GM7's GMKs are obfuscated. Please see the GMKrypt Documentation)
  • 701 for GM7.0 as well.
  • 620 for GM7.0 in some places. This may be because Mark was planning on calling it 6.2
  • 600 for GM6.1 and GM6.0 (cross-compatible)
  • 530 for GM5.3 and GM5.3a (bug-fix version. cross-compatible)
  • 520 for 510 for GM5.1
  • 500 for GM5.2 and GM5.0 (forward compatible)
  • 430 for GM4.3

and so on. Other numbers may pop up as well, as in-between versions. For example, 542 means that 530 cannot read it, but 600 can. Software usually does this for format changes during development. Also see Angle Brackets below.

Longint / Numbers

GM uses primarily 32-bit (4-byte) little-endian signed integers, which I choose to call "longints", for most of its data. Even basic things like True/False and Radio Buttons etc. each tend to be stored in their own 4-byte/32-bit set, rather than merging 8 of them to make a single byte or merging 32 of them to make that same 4-byte.

I will display any dates as Gregorian ISO standard (yyyy-mm-dd).

Dates are stored in 64-bit (8-byte) signed doubles representing the number of days that have passed since 1899-12-30. Fractional parts are used to represent fractions of days (hours, minutes, seconds, etc).

Colors are stored in a 32-bit integer, usually only using the first 3 bytes as R G B respectively, with the 4th byte as 0. Sometimes they'll make use of the 4th byte, so handle carefully. We're not yet fully certain what the 4th byte represents, but it may be Alpha.

Unless otherwise denoted by a preceding (<byte size> bytes) note, all data is stored in 32-bit integers or 32-bit preceded 8-bit character sequences (as denoted by insertions, explained below).

Insertion and Curly Brackets { }

Insertion will take 2 normal forms, and a third special form (see Angle Brackets). Both normal forms will almost always have a longint before the insertion to indicate how much information is contained in the insertion. If this number is 0, no additional data will be inserted. The data is then surrounded by curly brackets { }.

Data Insertion

The first kind of insertion is Data Insertion. This is when the data is a series of length-prefixed bytes. My documentation will show these by having all the information (the length longint, the curly brackets, and the data) on one line. The most common example of Data Insertion is String Insertion

Example of data insertion

Length of Name { Name }

which would turn out as something like 07 Sprites ...

or just 00 ...

Structured Insertion

The second kind of insertion is Structured Insertion (although you needn't remember the name). For this, the documentation format will start with a longint which will indicate how many times the structural contents actually appear, and then the first curly bracket { on a new line, followed by the data on its own lines separate from the curly brackets, and then concluded with an end curly bracket on a new line. See the examples below.

Two common forms will arise. One is the true/false Structured Insertion. This determines simply whether or not the insertion will appear.

Example of a true/false

Object exists
{
 Object ID
}

The other is the Repitition Structured Insertion. This means that the first longint will indicate *how many times* the data within will be inserted. The data itself is not actually repeated - only the structure format is.

Example of repetition

Number of Objects
{
 View ID
 Followed Object
}

In this case, supposing there's 8 views, each with increments of ID, and each following no object (-1).

The result would be: 08 00 -1 01 -1 02 -1 03 -1 04 -1 05 -1 06 -1 07 -1 (replacing each of those numbers with the longint equivelent)

Conditional Insertions and Angle Brackets < >

Conditional Insertions are when a certain condition (e.g. the value of a prior longint) must be met in order for the data to be inserted. This is set apart from normal insertions because that longint may not be adjacent, or because the longint value may not be an obvious indicator of the repetitions (e.g. 0 may indicate that data is indeed inserted, while 1 may indicate that it is not). Angle Brackets are placed around this conditional expression.

A very common example of Conditional Insertions is the Version Number, as this weighs heavily on what data appears in which version. Each section has its own version number - there's one for Game Information, one for each resource, and a separate one for the format of each resource. Thus you should keep an eye on which version number is being used for that section - and also keep an eye on the scope of that version number.

Example of Version Numbers

GM version needed for the following info (440/600/800)
<440 only> Kind (-1*=None, 0="Wave", 1="Midi", 2="Mp3", 10="Unknown")
<600+> Kind (0=Normal, 1=Background, 2=3D, 3=Multimedia)
<440-600> Preload (1)

Here we see something specific to 440, followed by something which only appears in 600 and up (and does not appear in 440), followed by something specific to versions 440 to 600 (and does not appear in 800)

When different versions get grouped together, I try to group the older versions first and the newer versions later.

Of course, Conditional Insertions aren't solely dependant on a version number. Here's an example of Special Case insertion (one which does not denote how often the data is repeated)

10 or -1
<if not -1> Size of Image data { Image Data }

This frequently occurs in Sounds and Images. At this time we do not understand why this odd conditional is there - why use 10 instead of 1, and -1 instead of 0?

Default Values in Parenthesis ()

I've also included default values and value ranges to my format documentations, for your convenience. When the default value is not obvious by the format, I will put an asterisk (*) next to it.

Here are a few examples of the formats used;

(<Default>) e.g. (0)
(<Lower>-<Upper>,<Default>) e.g. (0-100,10)
(<Lower> to <Upper>,<Default>)  e.g. (-1 to 100,-1)
([Range,]<Val1>=Name1,<Val2>=Name2[,<Val3>=Name3[,...]]) e.g. (0-2,0*=Yes,1=No,2=Cancel)