<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.fightorder.net/wiki/index.php?action=history&amp;feed=atom&amp;title=Smf_decompiler</id>
	<title>Smf decompiler - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://www.fightorder.net/wiki/index.php?action=history&amp;feed=atom&amp;title=Smf_decompiler"/>
	<link rel="alternate" type="text/html" href="https://www.fightorder.net/wiki/index.php?title=Smf_decompiler&amp;action=history"/>
	<updated>2026-04-21T02:44:50Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.2</generator>
	<entry>
		<id>https://www.fightorder.net/wiki/index.php?title=Smf_decompiler&amp;diff=2237&amp;oldid=prev</id>
		<title>Qrow: Created page with &quot;This simple python2.x script will decompile fully decompile a map, outputs features, raw heightmap, texture, typemap, metal map, grass map, elevations, texturemap, minimap.  &lt;code&gt;&lt;pre&gt; #!/usr/bin/python # PD license by Beherith import sys import struct import Image  print &#039;Welcome to the SMF decompiler by Beherith (mysterme@gmail.com). Place this script next to the .smf file and pass the .smf as a command line argument to this script to get it decompiled&#039;  if len(sys.ar...&quot;</title>
		<link rel="alternate" type="text/html" href="https://www.fightorder.net/wiki/index.php?title=Smf_decompiler&amp;diff=2237&amp;oldid=prev"/>
		<updated>2026-02-25T00:19:05Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;This simple python2.x script will decompile fully decompile a map, outputs features, raw heightmap, texture, typemap, metal map, grass map, elevations, texturemap, minimap.  &amp;lt;code&amp;gt;&amp;lt;pre&amp;gt; #!/usr/bin/python # PD license by Beherith import sys import struct import Image  print &amp;#039;Welcome to the SMF decompiler by Beherith (mysterme@gmail.com). Place this script next to the .smf file and pass the .smf as a command line argument to this script to get it decompiled&amp;#039;  if len(sys.ar...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;This simple python2.x script will decompile fully decompile a map, outputs features, raw heightmap, texture, typemap, metal map, grass map, elevations, texturemap, minimap.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# PD license by Beherith&lt;br /&gt;
import sys&lt;br /&gt;
import struct&lt;br /&gt;
import Image&lt;br /&gt;
&lt;br /&gt;
print &amp;#039;Welcome to the SMF decompiler by Beherith (mysterme@gmail.com). Place this script next to the .smf file and pass the .smf as a command line argument to this script to get it decompiled&amp;#039;&lt;br /&gt;
&lt;br /&gt;
if len(sys.argv)&amp;gt;1:&lt;br /&gt;
	print &amp;#039;Working on:&amp;#039;,sys.argv[1]&lt;br /&gt;
else:&lt;br /&gt;
	exit(1)&lt;br /&gt;
SMFHeader_struct= struct.Struct(&amp;#039;&amp;lt; 16s i i i i i i i f f i i i i i i i&amp;#039;)&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;	char magic[16];      ///&amp;lt; &amp;quot;spring map file\0&amp;quot;&lt;br /&gt;
	int version;         ///&amp;lt; Must be 1 for now&lt;br /&gt;
	int mapid;           ///&amp;lt; Sort of a GUID of the file, just set to a random value when writing a map&lt;br /&gt;
&lt;br /&gt;
	int mapx;            ///&amp;lt; Must be divisible by 128&lt;br /&gt;
	int mapy;            ///&amp;lt; Must be divisible by 128&lt;br /&gt;
	int squareSize;      ///&amp;lt; Distance between vertices. Must be 8&lt;br /&gt;
	int texelPerSquare;  ///&amp;lt; Number of texels per square, must be 8 for now&lt;br /&gt;
	int tilesize;        ///&amp;lt; Number of texels in a tile, must be 32 for now&lt;br /&gt;
	float minHeight;     ///&amp;lt; Height value that 0 in the heightmap corresponds to	&lt;br /&gt;
	float maxHeight;     ///&amp;lt; Height value that 0xffff in the heightmap corresponds to&lt;br /&gt;
&lt;br /&gt;
	int heightmapPtr;    ///&amp;lt; File offset to elevation data (short int[(mapy+1)*(mapx+1)])&lt;br /&gt;
	int typeMapPtr;      ///&amp;lt; File offset to typedata (unsigned char[mapy/2 * mapx/2])&lt;br /&gt;
	int tilesPtr;        ///&amp;lt; File offset to tile data (see MapTileHeader)&lt;br /&gt;
	int minimapPtr;      ///&amp;lt; File offset to minimap (always 1024*1024 dxt1 compresed data plus 8 mipmap sublevels)&lt;br /&gt;
	int metalmapPtr;     ///&amp;lt; File offset to metalmap (unsigned char[mapx/2 * mapy/2])&lt;br /&gt;
	int featurePtr;      ///&amp;lt; File offset to feature data (see MapFeatureHeader)&lt;br /&gt;
&lt;br /&gt;
	int numExtraHeaders; ///&amp;lt; Numbers of extra headers following main header&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
ExtraHeader_struct= struct.Struct(&amp;#039;&amp;lt; i i i&amp;#039;)&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;	int size; ///&amp;lt; Size of extra header&lt;br /&gt;
	int type; ///&amp;lt; Type of extra header&lt;br /&gt;
	int extraoffset ; //MISSING FROM DOCS, only exists if type=1 (vegmap)&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
MapTileHeader_struct=struct.Struct(&amp;#039;&amp;lt; i i&amp;#039;)&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;	int numTileFiles; ///&amp;lt; Number of tile files to read in (usually 1)&lt;br /&gt;
	int numTiles;     ///&amp;lt; Total number of tiles&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
MapFeatureHeader_struct=struct.Struct(&amp;#039;&amp;lt; i i&amp;#039;)&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;	int numFeatureType;&lt;br /&gt;
	int numFeatures;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
	&lt;br /&gt;
MapFeatureStruct_struct=struct.Struct(&amp;#039;&amp;lt; i f f f f f&amp;#039;)&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;int featureType;    ///&amp;lt; Index to one of the strings above&lt;br /&gt;
	float xpos;         ///&amp;lt; X coordinate of the feature&lt;br /&gt;
	float ypos;         ///&amp;lt; Y coordinate of the feature (height)&lt;br /&gt;
	float zpos;         ///&amp;lt; Z coordinate of the feature&lt;br /&gt;
&lt;br /&gt;
	float rotation;     ///&amp;lt; Orientation of this feature (-32768..32767 for full circle)&lt;br /&gt;
	float relativeSize; ///&amp;lt; Not used at the moment keep 1&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
TileFileHeader_struct =struct.Struct(&amp;#039;&amp;lt; 16s i i i i&amp;#039;)&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;	char magic[16];      ///&amp;lt; &amp;quot;spring tilefile\0&amp;quot;&lt;br /&gt;
	int version;         ///&amp;lt; Must be 1 for now&lt;br /&gt;
&lt;br /&gt;
	int numTiles;        ///&amp;lt; Total number of tiles in this file&lt;br /&gt;
	int tileSize;        ///&amp;lt; Must be 32 for now&lt;br /&gt;
	int compressionType; ///&amp;lt; Must be 1 (= dxt1) for now&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
_S3OHeader_struct = struct.Struct(&amp;quot;&amp;lt; 12s i 5f 4i&amp;quot;)&lt;br /&gt;
_S3OPiece_struct = struct.Struct(&amp;quot;&amp;lt; 10i 3f&amp;quot;)&lt;br /&gt;
_S3OVertex_struct = struct.Struct(&amp;quot;&amp;lt; 3f 3f 2f&amp;quot;)&lt;br /&gt;
_S3OChildOffset_struct = struct.Struct(&amp;quot;&amp;lt; i&amp;quot;)&lt;br /&gt;
_S3OIndex_struct = struct.Struct(&amp;quot;&amp;lt; i&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
SMALL_TILE_SIZE=680&lt;br /&gt;
MINIMAP_SIZE=699048&lt;br /&gt;
def pythonDecodeDXT1(data):# Python-only DXT1 decoder; this is slow!&lt;br /&gt;
	# input: one &amp;quot;row&amp;quot; of data (i.e. will produce 4*width pixels)&lt;br /&gt;
	blocks = len(data) / 8  # number of blocks in row&lt;br /&gt;
	out = [&amp;#039;&amp;#039;, &amp;#039;&amp;#039;, &amp;#039;&amp;#039;, &amp;#039;&amp;#039;]  # row accumulators&lt;br /&gt;
&lt;br /&gt;
	for xb in xrange(blocks):&lt;br /&gt;
		# Decode next 8-byte block.        &lt;br /&gt;
		c0, c1, bits = struct.unpack(&amp;#039;&amp;lt;HHI&amp;#039;, data[xb*8:xb*8+8])&lt;br /&gt;
		# print c0,c1,bits&lt;br /&gt;
		# color 0, packed 5-6-5&lt;br /&gt;
		b0 = (c0 &amp;amp; 0x1f) &amp;lt;&amp;lt; 3&lt;br /&gt;
		g0 = ((c0 &amp;gt;&amp;gt; 5) &amp;amp; 0x3f) &amp;lt;&amp;lt; 2&lt;br /&gt;
		r0 = ((c0 &amp;gt;&amp;gt; 11) &amp;amp; 0x1f) &amp;lt;&amp;lt; 3&lt;br /&gt;
		&lt;br /&gt;
		# color 1, packed 5-6-5&lt;br /&gt;
		b1 = (c1 &amp;amp; 0x1f) &amp;lt;&amp;lt; 3&lt;br /&gt;
		g1 = ((c1 &amp;gt;&amp;gt; 5) &amp;amp; 0x3f) &amp;lt;&amp;lt; 2&lt;br /&gt;
		r1 = ((c1 &amp;gt;&amp;gt; 11) &amp;amp; 0x1f) &amp;lt;&amp;lt; 3&lt;br /&gt;
&lt;br /&gt;
		# Decode this block into 4x4 pixels&lt;br /&gt;
		# Accumulate the results onto our 4 row accumulators&lt;br /&gt;
		for yo in xrange(4):&lt;br /&gt;
			for xo in xrange(4):&lt;br /&gt;
				# get next control op and generate a pixel&lt;br /&gt;
				&lt;br /&gt;
				control = bits &amp;amp; 3&lt;br /&gt;
				bits = bits &amp;gt;&amp;gt; 2&lt;br /&gt;
				if control == 0:&lt;br /&gt;
					out[yo] += chr(r0) + chr(g0) + chr(b0)&lt;br /&gt;
				elif control == 1:&lt;br /&gt;
					out[yo] += chr(r1) + chr(g1) + chr(b1)&lt;br /&gt;
				elif control == 2:                                &lt;br /&gt;
					if c0 &amp;gt; c1:&lt;br /&gt;
						out[yo] += chr((2 * r0 + r1 + 1) / 3) + chr((2 * g0 + g1 + 1) / 3) + chr((2 * b0 + b1 + 1) / 3)&lt;br /&gt;
					else:&lt;br /&gt;
						out[yo] += chr((r0 + r1) / 2) + chr((g0 + g1) / 2) + chr((b0 + b1) / 2)&lt;br /&gt;
				elif control == 3:&lt;br /&gt;
					if c0 &amp;gt; c1:&lt;br /&gt;
						out[yo] += chr((2 * r1 + r0 + 1) / 3) + chr((2 * g1 + g0 + 1) / 3) + chr((2 * b1 + b0 + 1) / 3)&lt;br /&gt;
					else:&lt;br /&gt;
						out[yo] += &amp;#039;\0\0\0&amp;#039;&lt;br /&gt;
&lt;br /&gt;
	# All done.&lt;br /&gt;
	return out&lt;br /&gt;
	&lt;br /&gt;
def unpack_null_terminated_string(data, offset):&lt;br /&gt;
	result=&amp;#039;&amp;#039;&lt;br /&gt;
	nextchar = &amp;#039;X&amp;#039;&lt;br /&gt;
	while True:&lt;br /&gt;
		nextchar=struct.unpack_from(&amp;#039;c&amp;#039;,data,offset+len(result))[0]&lt;br /&gt;
		if nextchar==&amp;#039;\0&amp;#039;:&lt;br /&gt;
			return result&lt;br /&gt;
		else:&lt;br /&gt;
			result+=nextchar&lt;br /&gt;
		if len(result)&amp;gt;10000:&lt;br /&gt;
			return result&lt;br /&gt;
&lt;br /&gt;
class SMFMap:&lt;br /&gt;
	def __init__(self,filename):&lt;br /&gt;
		self.filename=filename&lt;br /&gt;
		self.basename=filename.rpartition(&amp;#039;.&amp;#039;)[0]&lt;br /&gt;
		self.smffile=open(filename,&amp;#039;rb&amp;#039;).read()&lt;br /&gt;
		self.SMFHeader= SMFHeader_struct.unpack_from(self.smffile, 0)&lt;br /&gt;
		&lt;br /&gt;
		self.magic=self.SMFHeader[0]#;      ///&amp;lt; &amp;quot;spring map file\0&amp;quot;&lt;br /&gt;
		self.version=self.SMFHeader[1]#;         ///&amp;lt; Must be 1 for now&lt;br /&gt;
		self.mapid=self.SMFHeader[2]#;           ///&amp;lt; Sort of a GUID of the file, just set to a random value when writing a map&lt;br /&gt;
&lt;br /&gt;
		self.mapx=self.SMFHeader[3]#;            ///&amp;lt; Must be divisible by 128&lt;br /&gt;
		self.mapy=self.SMFHeader[4]#;            ///&amp;lt; Must be divisible by 128&lt;br /&gt;
		self.squareSize=self.SMFHeader[5]#;      ///&amp;lt; Distance between vertices. Must be 8&lt;br /&gt;
		self.texelPerSquare=self.SMFHeader[6]#;  ///&amp;lt; Number of texels per square, must be 8 for now&lt;br /&gt;
		self.tilesize=self.SMFHeader[7]#;        ///&amp;lt; Number of texels in a tile, must be 32 for now&lt;br /&gt;
		self.minHeight=self.SMFHeader[8]#;     ///&amp;lt; Height value that 0 in the heightmap corresponds to	&lt;br /&gt;
		self.maxHeight=self.SMFHeader[9]#;     ///&amp;lt; Height value that 0xffff in the heightmap corresponds to&lt;br /&gt;
&lt;br /&gt;
		self.heightmapPtr=self.SMFHeader[10]#;    ///&amp;lt; File offset to elevation data (short int[(mapy+1)*(mapx+1)])&lt;br /&gt;
		self.typeMapPtr=self.SMFHeader[11]#;      ///&amp;lt; File offset to typedata (unsigned char[mapy/2 * mapx/2])&lt;br /&gt;
		self.tilesPtr=self.SMFHeader[12]#;        ///&amp;lt; File offset to tile data (see MapTileHeader)&lt;br /&gt;
		self.minimapPtr=self.SMFHeader[13]#;      ///&amp;lt; File offset to minimap (always 1024*1024 dxt1 compresed data plus 8 mipmap sublevels)&lt;br /&gt;
		self.metalmapPtr=self.SMFHeader[14]#;     ///&amp;lt; File offset to metalmap (unsigned char[mapx/2 * mapy/2])&lt;br /&gt;
		self.featurePtr=self.SMFHeader[15]#;      ///&amp;lt; File offset to feature data (see MapFeatureHeader)&lt;br /&gt;
&lt;br /&gt;
		self.numExtraHeaders=self.SMFHeader[16]#; ///&amp;lt; Numbers of extra headers following main header&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
		&lt;br /&gt;
		print &amp;#039;Writing heightmap RAW (Remember, this is a %i by %i 16bit 1 channel IBM byte order raw!)&amp;#039;%((1+self.mapx),(1+self.mapy))&lt;br /&gt;
		self.heightmap=struct.unpack_from(&amp;#039;&amp;lt; %iH&amp;#039;%((1+self.mapx)*(1+self.mapy)),self.smffile,self.heightmapPtr)&lt;br /&gt;
		heightmap_file=open(self.basename+&amp;#039;_height.raw&amp;#039;,&amp;#039;wb&amp;#039;)&lt;br /&gt;
		for pixel in self.heightmap:&lt;br /&gt;
			heightmap_file.write(struct.pack(&amp;#039;&amp;lt; H&amp;#039;,pixel))&lt;br /&gt;
		heightmap_file.close()&lt;br /&gt;
		heightmap_img=Image.new(&amp;#039;RGB&amp;#039;,(1+self.mapx,1+self.mapy),&amp;#039;black&amp;#039;)&lt;br /&gt;
		heightmap_img_pixels=heightmap_img.load()&lt;br /&gt;
		for x in range(heightmap_img.size[0]):&lt;br /&gt;
			for y in range(heightmap_img.size[1]):&lt;br /&gt;
				height=self.heightmap[(heightmap_img.size[0])*y+x]/256&lt;br /&gt;
				heightmap_img_pixels[x,y]=(height,height,height)&lt;br /&gt;
		heightmap_img.save(self.basename+&amp;#039;_height.bmp&amp;#039;)&lt;br /&gt;
				&lt;br /&gt;
		print &amp;#039;Writing MetalMap&amp;#039;&lt;br /&gt;
		self.metalmap= struct.unpack_from(&amp;#039;&amp;lt; %iB&amp;#039;%((self.mapx/2)*(self.mapy/2)),self.smffile,self.metalmapPtr)&lt;br /&gt;
		metalmap_img=Image.new(&amp;#039;RGB&amp;#039;,(self.mapx/2,self.mapy/2),&amp;#039;black&amp;#039;)&lt;br /&gt;
		metalmap_img_pixels=metalmap_img.load()&lt;br /&gt;
		for x in range(metalmap_img.size[0]):&lt;br /&gt;
			for y in range(metalmap_img.size[1]):&lt;br /&gt;
				metal=self.metalmap[(metalmap_img.size[0])*y+x]&lt;br /&gt;
				metalmap_img_pixels[x,y]=(metal,0,0)&lt;br /&gt;
		metalmap_img.save(self.basename+&amp;#039;_metal.bmp&amp;#039;)&lt;br /&gt;
		&lt;br /&gt;
		print &amp;#039;Writing typemap&amp;#039;&lt;br /&gt;
		self.typemap=  struct.unpack_from(&amp;#039;&amp;lt; %iB&amp;#039;%((self.mapx/2)*(self.mapy/2)),self.smffile,self.typeMapPtr)&lt;br /&gt;
		typemap_img=Image.new(&amp;#039;RGB&amp;#039;,(self.mapx/2,self.mapy/2),&amp;#039;black&amp;#039;)&lt;br /&gt;
		typemap_img_pixels=typemap_img.load()&lt;br /&gt;
		for x in range(typemap_img.size[0]):&lt;br /&gt;
			for y in range(typemap_img.size[1]):&lt;br /&gt;
				type=self.typemap[(typemap_img.size[0])*y+x]&lt;br /&gt;
				typemap_img_pixels[x,y]=(type,0,0)&lt;br /&gt;
		typemap_img.save(self.basename+&amp;#039;_type.bmp&amp;#039;)&lt;br /&gt;
	&lt;br /&gt;
		print &amp;#039;Writing minimap&amp;#039;&lt;br /&gt;
		miniddsheaderstr=([68, 68, 83, 32, 124, 0, 0, 0, 7, 16, 10, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, &lt;br /&gt;
		11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &lt;br /&gt;
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 4, 0, 0, 0, 68, 88, 84, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,&lt;br /&gt;
		0, 0, 0, 0, 0, 0, 0, 8, 16, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])&lt;br /&gt;
		self.minimap=self.smffile[self.minimapPtr:self.minimapPtr+MINIMAP_SIZE]&lt;br /&gt;
		minimap_file=open(self.basename+&amp;#039;_mini.dds&amp;#039;,&amp;#039;wb&amp;#039;)&lt;br /&gt;
		for c in miniddsheaderstr:&lt;br /&gt;
			minimap_file.write(struct.pack(&amp;#039;&amp;lt; B&amp;#039;,c))&lt;br /&gt;
		minimap_file.write(self.minimap)&lt;br /&gt;
		minimap_file.close()&lt;br /&gt;
		&lt;br /&gt;
		print &amp;#039;Writing grassmap&amp;#039;&lt;br /&gt;
		vegmapoffset = SMFHeader_struct.size+ExtraHeader_struct.size+4&lt;br /&gt;
		for extraheader_index in range(self.numExtraHeaders):&lt;br /&gt;
			extraheader = ExtraHeader_struct.unpack_from(self.smffile,extraheader_index*ExtraHeader_struct.size+SMFHeader_struct.size)&lt;br /&gt;
			extraheader_size,extraheader_type,extraoffset =extraheader&lt;br /&gt;
			# print &amp;#039;ExtraHeader&amp;#039;,extraheader&lt;br /&gt;
			if extraheader_type==1: #grass&lt;br /&gt;
				# self.grassmap=struct.unpack_from(&amp;#039;&amp;lt; %iB&amp;#039;%((self.mapx/4)*(self.mapy/4)),self.smffile,ExtraHeader_struct.size+SMFHeader_struct.size+extraheader_size)&lt;br /&gt;
				self.grassmap=struct.unpack_from(&amp;#039;&amp;lt; %iB&amp;#039;%((self.mapx/4)*(self.mapy/4)),self.smffile,extraoffset)&lt;br /&gt;
				grassmap_img=Image.new(&amp;#039;RGB&amp;#039;,(self.mapx/4,self.mapy/4),&amp;#039;black&amp;#039;)&lt;br /&gt;
				grassmap_img_pixels=grassmap_img.load()&lt;br /&gt;
				for x in range(grassmap_img.size[0]):&lt;br /&gt;
					for y in range(grassmap_img.size[1]):&lt;br /&gt;
						grass=self.grassmap[(grassmap_img.size[0])*y+x]&lt;br /&gt;
						if grass==1:&lt;br /&gt;
							grass = 255&lt;br /&gt;
						else:&lt;br /&gt;
							grass = 0&lt;br /&gt;
						grassmap_img_pixels[x,y]=(grass,grass,grass)&lt;br /&gt;
				grassmap_img.save(self.basename+&amp;#039;_grass.bmp&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
		&lt;br /&gt;
		#MapFeatureHeader is followed by numFeatureType zero terminated strings indicating the names&lt;br /&gt;
		#of the features in the map. Then follow numFeatures MapFeatureStructs.&lt;br /&gt;
		self.mapfeaturesheader = MapFeatureHeader_struct.unpack_from(self.smffile,self.featurePtr)&lt;br /&gt;
		self.numFeatureType,self.numFeatures=self.mapfeaturesheader&lt;br /&gt;
		self.featurenames=[]&lt;br /&gt;
		featureoffset = self.featurePtr + MapFeatureHeader_struct.size&lt;br /&gt;
		while len(self.featurenames)&amp;lt;self.numFeatureType:&lt;br /&gt;
			featurename = unpack_null_terminated_string(self.smffile,featureoffset)&lt;br /&gt;
			self.featurenames.append(featurename)&lt;br /&gt;
			featureoffset+=len(featurename)+1 #cause of null terminator&lt;br /&gt;
			# print featurename&lt;br /&gt;
			&amp;#039;&amp;#039;&amp;#039;nextchar= &amp;#039;N&amp;#039;&lt;br /&gt;
			while nextchar != &amp;#039;\0&amp;#039;:&lt;br /&gt;
				nextchar=struct.unpack_from(&amp;#039;c&amp;#039;,self.smffile,len(featurename)+self.featurePtr+MapFeatureHeader_struct.size&lt;br /&gt;
					+sum([len(fname)+1 for fname in self.featurenames]))[0]&lt;br /&gt;
				if nextchar ==&amp;#039;\0&amp;#039;:&lt;br /&gt;
					self.featurenames.append(featurename)&lt;br /&gt;
					featurename=&amp;#039;&amp;#039;&lt;br /&gt;
				else:&lt;br /&gt;
					featurename+=nextchar&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
					&lt;br /&gt;
		print &amp;#039;Features found in map definition&amp;#039;,self.featurenames&lt;br /&gt;
		feature_offset=self.featurePtr+MapFeatureHeader_struct.size+sum([len(fname)+1 for fname in self.featurenames])&lt;br /&gt;
		self.features=[]&lt;br /&gt;
		for feature_index in range(self.numFeatures):&lt;br /&gt;
			feat= MapFeatureStruct_struct.unpack_from(self.smffile,feature_offset+MapFeatureStruct_struct.size*feature_index)&lt;br /&gt;
			# print feat&lt;br /&gt;
			self.features.append({&amp;#039;name&amp;#039;:self.featurenames[feat[0]],&amp;#039;x&amp;#039;:feat[1],&amp;#039;y&amp;#039;:feat[2],&amp;#039;z&amp;#039;:feat[3],&amp;#039;rotation&amp;#039;:feat[4],&amp;#039;relativeSize&amp;#039;:feat[5],})&lt;br /&gt;
			# print self.features[-1]&lt;br /&gt;
		print &amp;#039;Writing feature placement file&amp;#039;&lt;br /&gt;
		feature_file=open(self.basename+&amp;#039;_featureplacement.lua&amp;#039;,&amp;#039;w&amp;#039;)&lt;br /&gt;
		for feature in self.features:&lt;br /&gt;
			feature_file.write(&amp;#039;{ name = \&amp;#039;%s\&amp;#039;, x = %i, z = %i, rot = &amp;quot;%i&amp;quot; ,scale = %f },\n&amp;#039;%(feature[&amp;#039;name&amp;#039;],feature[&amp;#039;x&amp;#039;],feature[&amp;#039;z&amp;#039;],feature[&amp;#039;rotation&amp;#039;],feature[&amp;#039;relativeSize&amp;#039;]))&lt;br /&gt;
		feature_file.close()&lt;br /&gt;
		&lt;br /&gt;
		print &amp;#039;loading tile files&amp;#039;&lt;br /&gt;
		self.maptileheader=MapTileHeader_struct.unpack_from(self.smffile,self.tilesPtr)&lt;br /&gt;
		self.numtilefiles,self.numtiles=self.maptileheader&lt;br /&gt;
		self.tilefiles=[]&lt;br /&gt;
		tileoffset=self.tilesPtr+MapTileHeader_struct.size&lt;br /&gt;
		for i in range(self.numtilefiles):&lt;br /&gt;
			numtilesinfile=struct.unpack_from(&amp;#039;&amp;lt; i&amp;#039;,self.smffile,tileoffset)[0]&lt;br /&gt;
			tileoffset+=4 #sizeof(int)&lt;br /&gt;
			tilefilename=unpack_null_terminated_string(self.smffile,tileoffset)&lt;br /&gt;
			tileoffset+=len(tilefilename)+1 #cause of null terminator&lt;br /&gt;
			self.tilefiles.append([tilefilename,numtilesinfile,open(tilefilename,&amp;#039;rb&amp;#039;).read()])&lt;br /&gt;
			print tilefilename, &amp;#039;has&amp;#039;,numtilesinfile,&amp;#039;tiles&amp;#039;&lt;br /&gt;
		self.tileindices=struct.unpack_from(&amp;#039;&amp;lt; %ii&amp;#039;%((self.mapx/4)*(self.mapy/4)),self.smffile,tileoffset)&lt;br /&gt;
			&lt;br /&gt;
		&lt;br /&gt;
		self.tiles=[]&lt;br /&gt;
		for tilefile in self.tilefiles:&lt;br /&gt;
			tileFileHeader = TileFileHeader_struct.unpack_from(tilefile[2],0)&lt;br /&gt;
			magic,version,numTiles,tileSize,compressionType=tileFileHeader&lt;br /&gt;
			#print tilefile[0],&amp;#039;: magic,version,numTiles,tileSize,compressionType&amp;#039;,magic,version,numTiles,tileSize,compressionType&lt;br /&gt;
			for i in range(numTiles):&lt;br /&gt;
				self.tiles.append(struct.unpack_from(&amp;#039;&amp;lt; %is&amp;#039;%(SMALL_TILE_SIZE),tilefile[2], TileFileHeader_struct.size+i*SMALL_TILE_SIZE)[0])&lt;br /&gt;
			&lt;br /&gt;
			&lt;br /&gt;
		&lt;br /&gt;
		print &amp;#039;Generating texture, this is very very slow (few minutes)&amp;#039;&lt;br /&gt;
		textureimage=Image.new(&amp;#039;RGB&amp;#039;,(self.mapx*8,self.mapy*8),&amp;#039;black&amp;#039;)&lt;br /&gt;
		textureimagepixels=textureimage.load()&lt;br /&gt;
		for ty in range(self.mapy/4):&lt;br /&gt;
			# print &amp;#039;row&amp;#039;,ty&lt;br /&gt;
			for tx in range(self.mapx/4):&lt;br /&gt;
				currtile=self.tiles[self.tileindices[(self.mapx/4)*ty+tx]]&lt;br /&gt;
				# print &amp;#039;Tile&amp;#039;,(self.mapx/4)*ty+tx&lt;br /&gt;
				#one tile is 32x32, and pythonDecodeDXT1 will need one &amp;#039;row&amp;#039; of data, assume this is 8*8 bytes&lt;br /&gt;
				for rows in xrange(8):&lt;br /&gt;
					# print &amp;quot;currtile&amp;quot;,currtile&lt;br /&gt;
					dxdata=currtile[rows*64:(rows+1)*64]&lt;br /&gt;
					# print len(dxdata),dxdata&lt;br /&gt;
					dxtrows=pythonDecodeDXT1(dxdata) #decode in 8 block chunks&lt;br /&gt;
					for x in xrange(tx*32,(tx+1)*32):&lt;br /&gt;
						for y in xrange(ty*32+4*rows,ty*32+4+4*rows):&lt;br /&gt;
							# print rows, tx,ty,x,y&lt;br /&gt;
							# print dxtrows&lt;br /&gt;
							oy=(ty*32+4*rows)&lt;br /&gt;
							textureimagepixels[x,y]=(ord(dxtrows[y-oy][3*(x-tx*32) +0]),ord(dxtrows[y-oy][3*(x-tx*32) +1]),ord(dxtrows[y-oy][3*(x-tx*32) +2]))&lt;br /&gt;
		textureimage.save(self.basename+&amp;#039;_texture.bmp&amp;#039;)&lt;br /&gt;
		print &amp;#039;Done, one final bit of important info: the maps maxheight is %i, while the minheight is %i&amp;#039;%(self.maxHeight,self.minHeight)&lt;br /&gt;
mymap = SMFMap(sys.argv[1])&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Map Tools]]&lt;/div&gt;</summary>
		<author><name>Qrow</name></author>
	</entry>
</feed>