1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Zwiebelchen is hosting a special UI texturing contest. Whomever wins will get a $150 reward through paypal! Come along and draw your texturing tools for the Fantastic Adventurer UI contest.
    Dismiss Notice
  3. Decide who's the leader among the leaders! The poll for the Paired Modeling/Texturing Contest #3 is up!
    Dismiss Notice
  4. We are looking for your vote! Choose the best icon set of the Icon Contest #15!
    Dismiss Notice
  5. Join Music Contest #7 - Location! Craft a song that depicts any place.
    Dismiss Notice

Warcraft 3 Trigger Format Specification (WTG!)

Discussion in 'Programming' started by Ralle, Jun 11, 2017.

  1. Ralle

    Ralle

    Owner

    Joined:
    Oct 6, 2004
    Messages:
    10,740
    Warcraft 3 Trigger Format Specification (WTG!)

    The past few weeks I have been working on a tool to display the triggers of any map on the site. As some of you know, we had a similar system on the old site. The most difficult task in the creation of this tool is the parsing of the file "war3map.wtg" inside any (unprotected) Warcraft 3 map. It's problematic because it is a binary file format undocumented by Blizzard. There exist unofficial specifications but most of them are incomplete and incorrect.
    Many years ago when I built the parsing used on the site it was not perfect either but better than the existing documentation. Today I am happy to say that I have written a parser that successfully parses a little over 16,000 maps uploaded to the site. The only cases where it fails to parse are cases where World Editor fails similarly.

    Today I am sharing my improvements to the existing specifications in the hopes of furthering the third party tools for WC3. There are still some values which are not explained but everything needed to parse the whole structure succesfully every time is there.

    The incomplete documentation used to get started is this frequently reposted W3M/W3X specification:

    TriggerData.txt

    To begin parsing this format you will need the latest version of TriggerData.txt (UI\TriggerData.txt) which can be extracted from the MPQs. We need this file because we must setup a mapping between functions and their number of arguments. It is assumed that we have this mapping prior to parsing WTG files.

    This is a standard INI file (I expect that you can parse those, if not, Google it), we are interested in the following groups:
    Code (Text):
    [TriggerActions]
    ...
    [TriggerEvents]
    ...
    [TriggerConditions]
    ...
    [TriggerCalls]
    ...
    Iterate over each key-value item (where the key does not start with '_') in these groups and count the number of arguments but filter out empty strings, numbers and the string 'nothing'.

    For the group called 'TriggerCalls' one of the types is a return value, so the resulting count must be deducted by one.

    Here is sample code for the setup of my mapping:
    Code (PHP):
    $areas = [
        'TriggerActions',
        'TriggerEvents',
        'TriggerConditions',
        'TriggerCalls',
    ];
    $lookup = [];
    foreach ($areas as $area)
    {
        foreach ($iniParser->data->groups[$area] as $key => $argsString)
        {
            if ($key[0] == '_')
            {
                continue;
            }
            $args = explode(',', $argsString);
            $args = array_filter($args, function($arg) {
                return $arg != '0' && $arg != '1' && $arg != 'nothing' && trim($arg) != '';
            });
            $r = count($args);
            if ($area == 'TriggerCalls')
            {
                $r--;
            }
            $lookup[$key] = $r;
        }
    }


    war3map.wtg

    In the coming structures, the type 'string' is referenced. A string is a sequence of bytes terminated by a null (0x00).

    The file is defined by the 'Root' structure as seen below. Everything else is nested within that. Some values display as 'Unknown'. If you can figure out what they are for, I'd love to update this specification to reach perfection some day.

    Structure: Root
    Code (Text):
    char[4]: File id (WTG!)
    int32: File format version: 4 for Reign of Chaos, 7 for Frozen Throne (very important later on)
    int32: Number "x" of trigger categories
    struct TriggerCategory[x]: Repeat the TriggerCategory structure x times
    int32: Unknown (always 0)
    int32: Number "y" of variables
    struct Variable[y]: Repeat the Variable structure y times
    int32: Number "z" of triggers
    struct Trigger[z]: Repeat the Trigger structure z times

    Structure: TriggerCategory
    Code (Text):
    int32: Id of the category
    string: Name
    int32: Is comment (1 = yes, 0 = no) (Version 7 only)

    Structure: Variable
    Code (Text):
    string: Name
    string: Type
    int32: Unknown (always 1)
    int32: Is array (1 = yes, 0 = no)
    int32: Array size (Version 7 only)
    int32: Is initialized (1 = yes, 0 = no)
    string: Initial value

    Structure: Trigger
    Code (Text):
    string: Name
    string: Description
    int32: Is comment (Version 7 only, 0 = no, any other = yes)
    int32: Is enabled (1 = yes, 0 = no)
    int32: Is custom (1 = yes, 0 = no)
    int32: Is initially off (1 = yes, 0 = no)
    int32: Run on initialization (1 = yes, 0 = no)
    int32: Trigger category id
    int32: Total number "x" of events/conditions/actions
    struct ECA[x]: Repeat the ECA structure x times

    Structure: ECA
    Code (Text):
    int32: Type (0 = event, 1 = condition, 2 = action)
    int32: Group for if-then-else (0 = condition, 1 = then action, 2 = else action) (Only exists if it is a child-ECA)
    string: Name "x"
    int32: Is enabled (1 = yes, 0 = no)
    struct Parameter[y]: Repeat the Parameter structure y times (where y is found in our lookup table for the key x)
    int32: Number "z" of child events/conditions/actions (Version 7 only)
    struct ECA[z]: Repeat the ECA structure z times (these are child ECAs) (Version 7 only)

    The parameter structure will be divided into separate versions for 4 and 7 because of slight nuances in whether various values exist or not.

    Structure: Parameter (Version 4)
    Code (Text):
    int32: Type "x" (0 = PRESET, 1 = VARIABLE, 2 = FUNCTION, 3 = STRING, -1 = INVALID)
    string: Value
    int32: Has sub parameters "y" (1 = yes, 0 = no)
    struct SubParameters: (Only exists if y = yes)
    int32: Unknown (Always 0, Only exists if "x" = FUNCTION)
    int32: Is array "z" (1 = yes, 0 = no) (Only exists if "x" != 2)
    struct Parameter: Array index (Only exists if z = yes)

    Structure: Parameter (Version 7)
    Code (Text):
    int32: Type "x" (0 = PRESET, 1 = VARIABLE, 2 = FUNCTION, 3 = STRING, -1 = INVALID)
    string: Value
    int32: Has sub parameters "y" (1 = yes, 0 = no)
    struct SubParameters: (Only exists if y = yes)
    int32: Unknown (Always 0, Only exists if "y" = yes)
    int32: Is array "z" (1 = yes, 0 = no)
    struct Parameter: Array index (Only exists if z = yes)

    Structure: SubParameters
    Code (Text):
    int32: Type
    string: Name "x"
    int32: Begin parameters "y" (0 = no, any other = yes)
    struct Parameter[z]: Repeat the Parameter structure z times (where z is found in our lookup table for the key x)
     
    Last edited: Jul 7, 2017
  2. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    396
    Interesting. :ogre_haosis:
     
  3. MindWorX

    MindWorX

    Tool Moderator

    Joined:
    Aug 3, 2004
    Messages:
    608
    Man, that's some good work Ralle. I'm proud of you ... son.
     
  4. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,203
    Awesome, love seeing more detailed specs come out. Approved.
     
  5. Ralle

    Ralle

    Owner

    Joined:
    Oct 6, 2004
    Messages:
    10,740
    Thanks guys :).
     
  6. WaterKnight

    WaterKnight

    Joined:
    Aug 18, 2009
    Messages:
    3,868
    You know you could have asked for a bit here and there since others like myself were also digging into file formats and parsers as the various uploaded tools hint at. Still, thanks for the specs :)
     
  7. Ralle

    Ralle

    Owner

    Joined:
    Oct 6, 2004
    Messages:
    10,740
    I guess I have been a bit of a hermit then. Anyway, if you have any feedback on values that actually mean something else, feel free to comment :).
     
  8. WaterKnight

    WaterKnight

    Joined:
    Aug 18, 2009
    Messages:
    3,868
    What's the difference between 'integer' and 'integervar' as variable type?
     
  9. GhostWolf

    GhostWolf

    Joined:
    Jul 29, 2007
    Messages:
    4,410
    You are free to write your own specs or contribute to existing ones. I encourage you to do both. It's nice to have a repository of specs that are more-or-less updated compared to all of the specs posted elsewhere.
    So far every time I tried implementing anything, it required cross-referencing multiple specs, and usually fixing errors. Even in the most finalized and accepted specs (specifically for me MDX and BLP).
     
  10. Ralle

    Ralle

    Owner

    Joined:
    Oct 6, 2004
    Messages:
    10,740
    Where do you see that? Integervar?
     
  11. WaterKnight

    WaterKnight

    Joined:
    Aug 18, 2009
    Messages:
    3,868
    Zangarmarsh [v1.2]

    My tool says the same, just curious how Blizzard made a difference there.

    @GhostWolf: Not active anymore, but yeah, would be nice to collect/maintain the specs somewhere on Hive, so we are all on the same page.
     
  12. GhostWolf

    GhostWolf

    Joined:
    Jul 29, 2007
    Messages:
    4,410
    That variable has no type selected in WE. No idea how that's possible.
     
  13. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    413
    There are some cope paste bugs (Autogenerating, over two maps) which removes/hides types this two i know:
    Strings picking Models; new in 1.28.5 I never seen that in other versions.
    Integers beeing loop variables and never be set.; but kb is set here?


    Unbenannt.png
     
    Last edited: Jul 18, 2017 at 1:32 PM