Vearie

bz2wat.py - BZ2 Water Parser

Feb 29th, 2016 (edited)
235
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.95 KB | None | 0 0
  1. from struct import pack, unpack
  2. from math import sqrt
  3.  
  4. def from_file(file_path):
  5.     return WAT().from_file(file_path)
  6.  
  7. class WAT:
  8.     glow =       0x80 # 10000000 On/Off
  9.     direction =  0x03 # 00000011 First 2 bits to represnt 0, 1, 2, or 3
  10.     repeat =     0x7C # 01111100 5 bits to represnt 0 to 31 (Appears as 1 to 32 in editor)
  11.     rep_offset = 0x02 # How much to shift right by
  12.    
  13.     def __init__(self, tiles = None):
  14.         self.layers = []
  15.         self.index = []
  16.        
  17.         if tiles:
  18.             self.blank(tiles)
  19.    
  20.     def __str__(self):
  21.         return "WAT tiles=%d layers=%d" % (len(self.index), len(self.layers))
  22.    
  23.     def blank(self, tiles):
  24.         self.layers = []
  25.         for layer in range(15):
  26.             self.layers += [Layer()]
  27.         self.index = [0]*tiles
  28.    
  29.     def from_file(self, file_path):
  30.         with open(file_path, "rb") as fl:
  31.             # [Header:16 Bytes]
  32.             magic_number = fl.read(4)
  33.             version = unpack("i", fl.read(4))[0]
  34.             if magic_number != b"WATR" or version != 2:
  35.                 raise Exception("Invalid WAT file.")
  36.            
  37.             # Width(inverted), Height(inverted), Width, Height
  38.             size = unpack("HHHH", fl.read(8))
  39.             water_chunks = (size[2]//2)*(size[3]//2)
  40.            
  41.             # [Layers:92] *15 Total: 1380
  42.             self.layers = []
  43.             for layer in range(15):
  44.                 height, damage = 0.0, 0.0
  45.                 velocity, rgba, texture = [0, 0], [0, 0], [0, 0]
  46.                
  47.                 height = unpack("f", fl.read(4))[0]
  48.                 damage = unpack("f", fl.read(4))[0]
  49.                 for tex in range(2):
  50.                     velocity[tex] = unpack("f", fl.read(4))[0]
  51.                     rgba[tex] = unpack("BBBB", fl.read(4))
  52.                     texture[tex] = fl.read(32).decode("ascii", "ignore")
  53.                     texture[tex] = texture[tex][0:texture[tex].index("\x00")]
  54.                
  55.                 flags = unpack("BB", fl.read(2))
  56.                 fl.seek(2, 1)
  57.                
  58.                 glow = [bool(x & WAT.glow) for x in flags]
  59.                 direction = [(x & WAT.direction) for x in flags]
  60.                 repeat = [((x & WAT.repeat) >> WAT.rep_offset) for x in flags]
  61.                
  62.                 self.layers += [Layer(height, damage, texture, rgba, velocity, glow, direction, repeat)]
  63.            
  64.             # [Indices:1] Total: (water_chunks)
  65.             self.index = list(unpack("B"*water_chunks, fl.read(water_chunks)))
  66.         return self
  67.    
  68.     def to_file(self, file_path):
  69.         with open(file_path, "wb") as fl:
  70.             fl.write(b"WATR")
  71.             fl.write(pack("i", 2))
  72.             size = int(sqrt(len(self.index)))
  73.             fl.write(pack("HHHH", 0x10000-size*2, 0x10000-size*2, size*2, size*2))
  74.            
  75.             for layer in self.layers:
  76.                 fl.write(layer.pack())
  77.            
  78.             fl.write(pack("B"*len(self.index), *self.index))
  79.  
  80. class Layer:
  81.     def __init__(self,
  82.     height    = 0.0,
  83.     damage    = 0.0,
  84.     texture   = None,
  85.     rgba      = None,
  86.     velocity  = None,
  87.     glow      = None,
  88.     direction = None,
  89.     repeat    = None):
  90.         if texture is None:
  91.             texture = ["", ""]
  92.         if rgba is None:
  93.             rgba = [[0, 0, 0, 0], [0, 0, 0, 0]]
  94.         if velocity is None:
  95.             velocity = [0.0, 0.0]
  96.         if glow is None:
  97.             glow = [False, False]
  98.         if direction is None:
  99.             direction = [0, 0]
  100.         if repeat is None:
  101.             repeat = [31, 31]
  102.        
  103.         self.h = height
  104.         self.dmg = damage
  105.         self.t = [texture[0][0:31], texture[1][0:31]]
  106.         self.rgba = rgba
  107.         self.vel = velocity
  108.         self.g = glow
  109.         self.d = direction
  110.         self.rep = repeat
  111.    
  112.     def __str__(self):
  113.         return "h=%f dmg=%f %s" % (
  114.             self.h,
  115.             self.dmg,
  116.             str([("%r rgba%s glow=%d dir=%d veloc=%f rep=%d" % (
  117.                 self.t[i],
  118.                 str(self.rgba[i]),
  119.                 self.g[i],
  120.                 self.d[i],
  121.                 self.vel[i],
  122.                 self.rep[i])) for i in range(2)]))
  123.    
  124.     def pack(self):
  125.         """Pack data and return as bytes."""
  126.         data = bytearray(92)
  127.         data[0:8] = pack("ff", self.h, self.dmg)
  128.        
  129.         for tex in range(2):
  130.             i = tex*40+8
  131.             data[i+0:i+4] = pack("f", self.vel[tex])
  132.             data[i+4:i+8] = pack("BBBB", *self.rgba[tex])
  133.             data[i+8:i+40] = self.t[tex].ljust(32, "\x00").encode("ascii", "ignore")
  134.        
  135.         for tex in range(2):
  136.             data[88+tex] = self.d[tex] | self.g[tex]*WAT.glow | (self.rep[tex] << WAT.rep_offset)
  137.        
  138.         data[90:92] = b"\x00\x00" # Struct padding
  139.        
  140.         return data
  141.  
  142. if __name__ == "__main__":
  143.     file = "./Subject.WAT"
  144.     wat = WAT().from_file(file)
  145.     print(wat)
Add Comment
Please, Sign In to add comment