Blender addon to import and export models in .m3
format, which is used in Blizzard's games: StarCraft II and Heroes of the Storm.
Originally made by: Florian Köberle (aka "println").
Edit -> Preferences
. Then Add-ons
tab.Install
button and point it to downloaded zipfile.m3addon
directory which should be placed in following location:%APPDATA%\Blender Foundation\Blender\2.80\scripts\addons
~/.config/blender/2.80/scripts/addons
Refresh
button or restart the application.)[✓]
for m3addon
entry in Add-ons tab.#artisttavern
). That's the place to go for some general guidance and support.The Python scripts can be used as a Blender addon.
Currently, the following content can be exported and imported:
The script m3ToXml.py
can also be used to convert an m3 file into an XML file. It
takes an m3 file as an argument and prints the XML on the command line.
The script xmlToM3.py
can convert the XML files exported by m3ToXml.py
back into an m3 file.
The file structures.xml gets used by the m3.py
library to parse the m3 files.
Modifying this XML file will have an impact on the above scripts and the Blender addon.
The Blender addon adds panels to the scene tab of the properties editor.
To create a particle system and preview it in the Starcraft 2 editor you can perform the following steps:
+
in the M3 Animation Sequences
panel+
in the M3 Materials
panelDiffuse
in the M3 Materials Layer
panelAssets/Textures/Glow_Blue2.dds
in the M3 Materials Layer
panel+
in the M3 Particle Systems
panelM3 Quick Export
panelExport As M3
in the M3 Quick Export
panelsWindow/Previewer
m3.py
file is a python library for reading and writing m3 files. It uses the structures.xml file to do so.m3.py
file gets called to create a python data structure of the m3 file content.m3.py
data structures that represent an m3 file.m3.py
file gets used to convert the latter data structure into an m3 file.structures.xml
fileThe m3 file format is a list of sections. Each section contains an array of a certain structure in a certain version.
The first section of an m3 file contains always a single structure of type MD34
in version 11. It is defined at the bottom of the structures.xml
file:
<structure name="MD34" version="11" size="24">
<description>Header of a M3 file: Can be found at the start of the file.</description>
<versions>
<version number="11" size="24" />
</versions>
<fields>
<field name="tag" type="tag" />
<field name="indexOffset" type="uint32"/>
<field name="indexSize" type="uint32" />
<field name="model" type="Reference" refTo="MODL" />
</fields>
</structure>
Structures may reference other sections via a data structure called Reference (or SmallReference in some exceptions).
The MD34
structure for example has a field called model, that is referencing a MODL
structure within another section. To which structure type a reference is pointing is indicated by the refTo field.
References typically do not however reference a single structure, but the whole section and thus an array of structures. Thus theoretically a MD34
structure could reference multiple MODL
structures but that has never been observed in a valid m3 file.
The m3.py
file requires all structures to be first defined in the structures.xml
file before they get used/referenced by another structure. For this reason, the structure MD34
is defined at the bottom.
An m3 file contains also an index/overview about those sections it contains, which can be found at the location specified by indexOffset and indexSize. If you want to get a list of the sections in an m3 file programmatic wise you can use the m3.py
method loadSections(filename)
.
However, it is usually easier to just work with a tree-like representation of the MODL
structure in which all references to structure arrays have been replaced by a list of the section that got referenced. This is possible via the m3.py
python function loadModel(filename)
.
structures.xml
fileA structure definition defines a structure for all versions that exist of it:
For the creep material for example (structure name CREP
) 2 versions exist that have different sizes. In the structures.xml
file there is however just a single structure definition:
<structure name="CREP">
<description>Creep Material</description>
<versions>
<version number="0" size="24" />
<version number="1" size="28" />
</versions>
<fields>
<field name="name" type="Reference" refTo="CHAR" />
<field name="creepLayer" type="Reference" refTo="LAYR" />
<field name="unknownda1b4eb3" size="4" expected-value="0x00000000" since-version="1" />
</fields>
</structure>
The <versions>
block contains a <verson>
element for all known versions of that structure. For each structure, the
size needs to be known and defined in the <version>
element. When an m3 file contains a version of a structure that is not yet known, an exception will be thrown and information about the structure will be logged that contains also a guess on the size of the structure.
A newer version of a structure might have additional fields. The attribute since-version
can be used to indicate that a field exists since a certain version. The attribute till-version
can be used to indicate that a field exists only till a certain version of the structure.
The m3.py
file checks that the defined fields have indeed the sizes specified in the <version>
elements. So when you add a new version you probably also need to find out what new fields got added and which fields stayed the same.
A field needs either to have a size or type attribute. The type attribute can be one of the following primitive types:
In addition to that, all structures that got defined above the structure in the structures.xml
file can be also be used as type. However, a Version suffix with V + version number needs to be added to the structure name. e.g. VEC3V0 to get version 0 of the structure VEC3.
Exception: XYZ_V4.unknown0 has value 42 instead of the expected value int(0)
In the structures.xml
file, it's configured what structures exist, what fields those structures have, and what their default or expected value is. The exceptions mean that the field "unknown0" of the structure XYZ_
has been configured in the structures.xml
file to be 0, but it was actually 42.
For each structure exists an XML element in the structures.xml
file. Just search for the structure name (XYZ_
in the example) to find it. In the structure xml element there are field elements.
To fix the given error message we would search in the structure element for the field with the name attribute unknown0
and would replace the attribute expected-value="0"
with default-value="0"
.
Exception: There were 1 unknown sections
The error message means that the m3 file contained a structure that it is unknown to the script since it has not been defined in the structures.xml
file.
You can fix the error message by defining the unknown section. To do that have a look at the log, it will contain a message like this:
ERROR: Unknown section at offset 436124 with tag=XYZ_ version=1 repetitions=2 sectionLengthInBytes=32 guessedUnusedSectionBytes=4 guessedBytesPerEntry=14.0
The error message means that it found a section in the m3 file that contains two (repetitions=2) entries of type XYZ_. The script guesses that 4 bytes are unused and knowns that the section is 32 bytes long. So it calculates 2*X-4=32
where X is the number of guessed bytes per entry.
The result of this calculation is printed at the end "guessedBytesPerEntry=14.0". So the script guesses that version 1 of the structure XYZ_
is 14 bytes long.
To fix this error you would have to define the structure XYZ_
in version 1 in the structures.xml
file. See the section about the structures.xml
file to learn about how to do that.
Field ABCDV7.xyz can be marked as a reference pointing to XYZ_V1
:
To fix this example error message, we would search in the structures.xml
file for a structure called "ABCD" with the attribute version="7".
It will contain a xml element field with the attribute name="xyz". To this field we would add an attribute refTo="XYZ_V1".
Exception: Unable to load all data: There were 1 unreferenced sections. View log for details
When this error occurs, you will find in the log a message like this:
WARNING: XYZ_V1 (2 repetitions) got 0 times referenced
Every section in an m3 file gets usually referenced exactly 1 time(except for the header). The error message means that there is a section that contains 2 structures of type XYZ_ in version 1, but which got not referenced from anywhere. Most likely there is actually a reference to this section, but it hasn't been configured as such in the structures.xml
file.
If you are lucky, then there will be exactly 1 line below the former warning which looks like this:
-> Found a reference at offset 56 in a section of type ABCDV7
To fix the error message we need to change the structure definition of ABCD in version 7 to contain a field definition like this:
<field name="xyzData" type="Reference" refTo="XYZ_V1" />