/sc2-dood

StarCraft II terrain Objects file parser and exporter

Primary LanguageTypeScript

s2dood

StarCraft II terrain Objects file parser and exporter.

In its current stage it has one purpose: export doodads from a given map(s), then plug them back in a format that allows to query it from triggers. How it will be used and in what way is up to the user.

  • ✓ Can export data as GalaxyScript or UserData-like XML.
  • ✓ Can merge Objects from multiple SC2Maps

Installation

Windows

Download portable binary from releases.

Linux

npm install -g git+https://git@github.com/Talv/sc2-dood.git

Usage

It's command line tool.

Usage: s2dood [options]

Options:
  -V, --version               output the version number
  -s, --src-map <path>        source SC2Map(s) (default: [])
  -o, --out-map <path>        target SC2Map
  -O, --out-file <path>       output filename
  -F, --format-type <format>  output format: galaxy or xml (User Data)
  -h, --help                  output usage information

Example maps

Example 1 - basic

Download tdood-example1 and launch example map:

  • Press Z to clear all preplaced doodads.
  • Press X recreate actors respecting all properties from previously dumped data

Use wrapper batch file s2dood-run.bat to regenerate data.

Example 2 - multiple maps

Download tdood-example2 and launch example map:

  • Press 1 to loadup doodads from src1.SC2Map
  • Press 2 to loadup doodads from src2.SC2Map

Use wrapper batch file s2dood-multiple-g.bat to regenerate data.


Format: XML User Data

s2dood -s "src1.SC2Map" -s "src2.SC2Map" -o "tdood-example2.SC2Map" -F xml

Under default settings it will write to Base.SC2Data/Doodads.xml. Each source map will have its own CUser record. Example:

    <CUser id="d_src1">
        <Fields Id="actorLink" Type="GameLink" GameLinkType="Actor" EditorColumn="1"/>
        <Fields Id="flags" Type="Int"/>
        <Fields Id="variation" Type="Int" EditorColumn="2"/>
        <Fields Id="posX" Type="Fixed" EditorColumn="10"/>
        <Fields Id="posY" Type="Fixed" EditorColumn="11"/>
        <Fields Id="posZ" Type="Fixed" EditorColumn="12"/>
        <Fields Id="yaw" Type="Fixed"/>
        <Fields Id="pitch" Type="Fixed"/>
        <Fields Id="roll" Type="Fixed"/>
        <Fields Id="scaleX" Type="Fixed"/>
        <Fields Id="scaleY" Type="Fixed"/>
        <Fields Id="scaleZ" Type="Fixed"/>
        <Fields Id="tintColor" Type="Color"/>
        <Fields Id="tintMultiplier" Type="Fixed"/>
        <Fields Id="teamColorIndex" Type="Int"/>
        <Instances Id="[Default]"/>
        <Instances Id="0">
            <GameLink GameLink="ZerusTree">
                <Field Id="actorLink"/>
            </GameLink>
            <Fixed Fixed="23.7023">
                <Field Id="posX"/>
            </Fixed>
            <Fixed Fixed="94.0671">
                <Field Id="posY"/>
            </Fixed>
            <Fixed Fixed="-0.0002">
                <Field Id="posZ"/>
            </Fixed>
            <Int Int="11">
                <Field Id="variation"/>
            </Int>
            <Fixed Fixed="0.9001">
                <Field Id="scaleX"/>
            </Fixed>
            <Fixed Fixed="0.9001">
                <Field Id="scaleY"/>
            </Fixed>
            <Fixed Fixed="0.9001">
                <Field Id="scaleZ"/>
            </Fixed>
            <Fixed Fixed="95.568518">
                <Field Id="yaw"/>
            </Fixed>
            <Int Int="1792">
                <Field Id="flags"/>
            </Int>
        </Instances>
        <!-- ... -->
    </CUser>

Format: Galaxy script

s2dood -s "tdood-example1.SC2Map" -o "tdood-example1.SC2Map" -F galaxy

Data is exported as a .galaxy file. Which consists of one function that populates global array. Every element of an array is a struct that includes all relevant properties of a doodad.

Declarations required by generated script. Prefixes such as gv_ (etc.) makes it Trigger Editor compatible.

const int gv_doodadsLimit = 16384;

struct gs_PreplacedDoodadT {
    string lv_type;
    int lv_flags;
    int lv_variation;
    fixed lv_x;
    fixed lv_y;
    fixed lv_z;
    fixed lv_yaw;
    fixed lv_pitch;
    fixed lv_roll;
    fixed lv_scale_x;
    fixed lv_scale_y;
    fixed lv_scale_z;
    color lv_tint_col;
    fixed lv_tint_hdr;
    int lv_teamc;
    // --- extra vars filled on the runtime
    string lv_model;
};


// ====
// global variables that will be populdated by generated .galaxy file
// ====

// array of structures - each element of an structure describes one Terrain Doodad
gs_PreplacedDoodadT[gv_doodadsLimit + 1] gv__o;

// number of used entries from above array
int gv__oc = 0;

Example of .galaxy script generated by this tool. There's just one function - when called it will populate our global array.

void gf__opopulate() {
gv__o[0].lv_type = "ZerusLargeTree";
gv__o[0].lv_x = 80.5;
gv__o[0].lv_y = 38.5;
gv__o[0].lv_z = 7.9995;
gv__o[0].lv_scale_x = 1;
gv__o[0].lv_scale_y = 1;
gv__o[0].lv_scale_z = 1;
gv__o[0].lv_yaw = -87.129692;
gv__o[0].lv_pitch = -19.469106;
gv__o[0].lv_roll = -0.95110994;
gv__o[0].lv_flags = 0xd00;
// ---
// ... 16k more objects
// ---
gv__oc = 16000;
}

Why use this over UserData format?

Because UserData API is simply slow. Any performance sensitive use-case of this tool would likely require transfering all entries from UserData to galaxy variables. This vastly improves the performance, by taking advantage of static linking within Galaxy. We're avoiding overhead that would come from using UserData API to query data dynamically.