• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Parsing old/new war3map.w3c files

Status
Not open for further replies.
Level 18
Joined
Jan 1, 2018
Messages
728
The war3map.w3c file contains cameras created in the world editor's camera palette. Since patch 1.31, cameras can have local rotations (pitch, yaw, roll). Additionally, since 1.30, a camera can also have a near clipping plane.
In both cases, blizzard decided in their unmatched wisdom to not change the file's format version. As a result, trying to open and old version of this file in patch 1.31 or later, the world editor will incorrectly parse the data. The near clipping plane shouldn't be an issue here, since even in old patches there was already some sort of placeholder value in the file format that was usually set to 100 (although the default value for the near clipping plane is 16). However, the local pitch, local yaw, and local roll require an additional 12 bytes.

So how does the world editor deal with parsing this file if it was created in an older patch? Well... it simply doesn't. It will just assume the file is in the new format. Here's how that looks:
invalid cameras.png

Again, this could all be prevented if blizzard simply changed the format version from 0 to... I don't know... 1? Maybe 2 if they updated the format for patch 1.30 as well.

So, how can we properly parse this file format, knowing that we cannot rely on a format version to know if we're reading an old or new format file? There are basically four ways:
  1. For every camera, try reading the local rotations, and if invalid, read the camera name string.
  2. For every camera, try reading the camera name string, and if invalid, read the local rotations.
  3. Read the entire file as if it's in the old format, and if any invalid data is found, read it in the new format.
  4. Read the entire file as if it's in the new format, and if any invalid data is found, read it in the old format.
The first approach is unreliable, because when parsing the local rotations, one can conclude their values are invalid when they're less than 0 or greater than 360. However, in the example file in the .zip (the same file as shown in the image), there are some cameras which start with the string "FanC". The first four bytes are [70, 97, 110, 67], which is equal to 238.379974 when parsed as float. This is between 0 and 360 degrees, so it's a valid value. The 20th camera in this example file also has a valid yaw and roll, and a name with at least one non-whitespace character.

The other three approaches appear to work correctly for all the files I've tried. Of course, there may be examples for which it's impossible to know if the file was created in the old or new file format.
The simplest example is a file with a single camera, which has a name of at least 13 characters, where the first 12 characters can be parsed as three floats, and the 13th character is not a whitespace character.

Another issue that applies to the first two approaches is that some cameras may be parsed in the old format, while others are parsed in the new format. With the last two approaches, you at least know for certain that all cameras will be parsed in the same format.

Of the third and fourth approaches, I'd probably prefer the fourth personally, since in that case you can also run into an end of stream exception, which is an indication that the file is in the old format (or that the file is corrupt). Something similar can be done for the third approach, by checking that there are exactly zero bytes left to be read in the stream after all cameras have been parsed. Although I haven't seen any examples of war3map.w3c files where this is the case, there are other war3map files where I have seen useless bytes are added to the end of the stream, so I find that approach less reliable than when you simply run into an exception.
 

Attachments

  • war3map.w3c.zip
    807 bytes · Views: 28

eejin

Tool Moderator
Level 12
Joined
Mar 6, 2017
Messages
221
What I did in HiveWE is check if the war3map.w3i game_version_major and game_version_minor indicate that the map is saved with 131 or higher.

Code:
if (map->info.game_version_major * 100 + map->info.game_version_minor >= 131) {
    i.local_pitch = reader.read<float>();
    i.local_yaw = reader.read<float>();
    i.local_roll = reader.read<float>();
}

Since afaik the editor always saves the cameras in the newer format.
 
Level 18
Joined
Jan 1, 2018
Messages
728
I usually parse files individually, so I hadn't even thought about using data from another file (in this case war3map.w3i) to parse.
In theory it makes sense to do it like that, but in my screenshot I simply put the war3map.w3c file in a new 1.31 map (because it came from a protected map), and you can see how that worked out.
So, I still prefer the fourth approach that I mentioned in my first post. Worst case: you read a 1KB file twice, no big deal.
 

eejin

Tool Moderator
Level 12
Joined
Mar 6, 2017
Messages
221
but in my screenshot I simply put the war3map.w3c file in a new 1.31 map (because it came from a protected map), and you can see how that worked out.
The thing is that unless you manually start swapping out the file you won't run into the issue since any map saved in 1.31 will have the new format. I'm pretty sure the game does the same check with the game version.
 
Status
Not open for further replies.
Top