Vearie

BZ2 MSH File Reader

May 9th, 2021
926
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import json
  2. from ctypes import sizeof, Structure, Array
  3. from ctypes import c_ubyte, c_int32, c_uint16, c_uint32, c_uint16, c_float
  4.  
  5. MSH_MATERIAL = 0x9709513E
  6. MSH_TEXTURE = 0x7951FC0B
  7. MSH_CHILD = 0xF74C51EE
  8. MSH_SIBLING = 0xB8990880
  9. MSH_END = 0xA93EB864
  10. MSH_EOF = 0xE3BB47F1
  11.  
  12. class ZeroLengthName(Exception): pass
  13. class UnknownBlock(Exception): pass
  14. class InvalidFormat(Exception): pass
  15.  
  16. def read_optional_blocks(f):
  17.     block_type_check = c_uint32()
  18.    
  19.     material = None
  20.     f.readinto(block_type_check)
  21.     if block_type_check.value == MSH_MATERIAL:
  22.         material = Material(f)
  23.     else:
  24.         f.seek(f.tell() - sizeof(c_uint32))
  25.    
  26.     texture = None
  27.     f.readinto(block_type_check)
  28.     if block_type_check.value == MSH_TEXTURE:
  29.         texture = Texture(f)
  30.     else:
  31.         f.seek(f.tell() - sizeof(c_uint32))
  32.    
  33.     return material, texture
  34.  
  35. class StructureJSON(Structure):
  36.     def json(self):
  37.         json_handled_types = (int, str, float, list, tuple, bool)
  38.         j = {}
  39.        
  40.         for field_name, field_type in self._fields_:
  41.             field_value = getattr(self, field_name)
  42.            
  43.             if issubclass(field_type, __class__):
  44.                 # Inherits from this class
  45.                 field_value = field_value.json()
  46.            
  47.             elif type(field_value) in json_handled_types:
  48.                 pass # Handled by python's JSON serializer
  49.            
  50.             elif type(field_value) in (bytes, bytearray):
  51.                 field_value = field_value.decode("ascii", "ignore")
  52.            
  53.             else:
  54.                 try:
  55.                     # Iterable (e.g. float array)
  56.                     field_value = [value for value in field_value]
  57.                 except TypeError:
  58.                     field_value = str(field_value)
  59.            
  60.             j[field_name] = field_value
  61.        
  62.         return j
  63.  
  64. class UVPair(StructureJSON):
  65.     _fields_ = [
  66.         ("u", c_float),
  67.         ("v", c_float)
  68.     ]
  69.    
  70.     def __iter__(self):
  71.         yield self.u
  72.         yield self.y
  73.  
  74. class Vector(StructureJSON):
  75.     _fields_ = [
  76.         ("x", c_float),
  77.         ("y", c_float),
  78.         ("z", c_float)
  79.     ]
  80.    
  81.     def __iter__(self):
  82.         yield self.x
  83.         yield self.y
  84.         yield self.z
  85.  
  86. class Vertex(StructureJSON):
  87.     _fields_ = [
  88.         ("pos", Vector),
  89.         ("norm", Vector),
  90.         ("uv", UVPair)
  91.     ]
  92.  
  93. class ColorValue(StructureJSON):
  94.     _fields_ = [
  95.         ("r", c_float),
  96.         ("g", c_float),
  97.         ("b", c_float),
  98.         ("a", c_float)
  99.     ]
  100.    
  101.     def __iter__(self):
  102.         yield self.r
  103.         yield self.g
  104.         yield self.b
  105.         yield self.a
  106.  
  107. class Color(StructureJSON):
  108.     _fields_ = [
  109.         ("b", c_ubyte),
  110.         ("g", c_ubyte),
  111.         ("r", c_ubyte),
  112.         ("a", c_ubyte)
  113.     ]
  114.    
  115.     def __iter__(self):
  116.         yield self.b
  117.         yield self.g
  118.         yield self.r
  119.         yield self.a
  120.  
  121. class Matrix(StructureJSON):
  122.     _fields_ = [
  123.         ("right", c_float * 4),
  124.         ("up", c_float * 4),
  125.         ("front", c_float * 4),
  126.         ("posit", c_float * 4)
  127.     ]
  128.  
  129. class Quaternion(StructureJSON):
  130.     _fields_ = [
  131.         ("s", c_float),
  132.         ("x", c_float),
  133.         ("y", c_float),
  134.         ("z", c_float)
  135.     ]
  136.    
  137.     def __iter__(self):
  138.         yield s
  139.         yield x
  140.         yield y
  141.         yield z
  142.  
  143. class AnimKey(StructureJSON):
  144.     _fields_ = [
  145.         ("frame", c_float),
  146.         ("type", c_uint32),
  147.         ("quat", Quaternion),
  148.         ("vect", Vector)
  149.     ]
  150.  
  151. class BlockHeader(StructureJSON):
  152.     _fields_ = [
  153.         ("fileType", c_ubyte * 4),
  154.         ("verID", c_uint32),
  155.         ("blockCount", c_uint32),
  156.         ("notUsed", c_ubyte * 32)
  157.     ]
  158.  
  159. class BlockInfo(StructureJSON):
  160.     _fields_ = [
  161.         ("key", c_uint32),
  162.         ("size", c_uint32)
  163.     ]
  164.  
  165. class Sphere(StructureJSON):
  166.     _fields_ = [
  167.         ("radius", c_float),
  168.         ("matrix", Matrix),
  169.         ("Width", c_float),
  170.         ("Height", c_float),
  171.         ("Breadth", c_float)
  172.     ]
  173.  
  174. class MSH_Header(StructureJSON):
  175.     _fields_ = [
  176.         ("dummy", c_float),
  177.         ("scale", c_float),
  178.         ("indexed", c_uint32),
  179.         ("moveAnim", c_uint32),
  180.         ("oldPipe", c_uint32),
  181.         ("isSingleGeometry", c_uint32),
  182.         ("skinned", c_uint32)
  183.     ]
  184.  
  185. class FaceObj(StructureJSON):
  186.     _fields_ = [
  187.         ("buckyIndex", c_uint16),
  188.         ("verts", c_uint16 * 3),
  189.         ("norms", c_uint16 * 3),
  190.         ("uvs", c_uint16 * 3)
  191.     ]
  192.  
  193. class VertIndex(StructureJSON):
  194.     _fields_ = [
  195.         ("weight", c_float),
  196.         ("index", c_uint16),
  197.     ]
  198.  
  199. class VertIndexContainer:
  200.     def __init__(self, count, array):
  201.         self.count = count
  202.         self.array = array
  203.    
  204.     def json(self):
  205.         return {
  206.             "count": self.count,
  207.             "array": [item.json() for item in self.array],
  208.         }
  209.  
  210. class Plane(StructureJSON):
  211.     _fields_ = [
  212.         ("d", c_float),
  213.         ("x", c_float),
  214.         ("y", c_float),
  215.         ("z", c_float)
  216.     ]
  217.    
  218.     def __iter__(self):
  219.         yield d
  220.         yield x
  221.         yield y
  222.         yield z
  223.  
  224. class BuckyDesc:
  225.     def __init__(self, f=None):
  226.         self.flags = c_uint32()
  227.         self.vert_count = c_uint32()
  228.         self.index_count = c_uint32()
  229.        
  230.         self.material = None
  231.         self.texture = None
  232.        
  233.         if f:
  234.             self.read(f)
  235.    
  236.     def read(self, f):
  237.         f.readinto(self.flags)
  238.         f.readinto(self.index_count)
  239.         f.readinto(self.vert_count)
  240.         self.material, self.texture = read_optional_blocks(f)
  241.    
  242.     def json(self):
  243.         j = {
  244.             "flags": self.flags.value,
  245.             "indexCount": self.vert_count.value,
  246.             "vertCount": self.index_count.value
  247.         }
  248.        
  249.         if self.material:
  250.             j["matBlock"] = self.material.json()
  251.        
  252.         if self.texture:
  253.             j["matTexture"] = self.texture.json()
  254.        
  255.         return j
  256.  
  257. class VertGroup:
  258.     def __init__(self, f=None):
  259.         self.vert_count = c_uint32()
  260.         self.state_index = c_uint32()
  261.         self.index_count = c_uint32()
  262.         self.plane_index = c_uint32()
  263.        
  264.         self.material = None
  265.         self.texture = None
  266.        
  267.         if f:
  268.             self.read(f)
  269.    
  270.     def read(self, f):
  271.         f.readinto(self.state_index)
  272.         f.readinto(self.vert_count)
  273.         f.readinto(self.index_count)
  274.         f.readinto(self.plane_index)
  275.         self.material, self.texture = read_optional_blocks(f)
  276.    
  277.     def json(self):
  278.         j = {
  279.             "stateIndex": self.state_index.value,
  280.             "vertCount": self.vert_count.value,
  281.             "indexCount": self.index_count.value,
  282.             "planeIndex": self.plane_index.value
  283.         }
  284.        
  285.         if self.material:
  286.             j["matBlock"] = self.material.json()
  287.        
  288.         if self.texture:
  289.             j["matTexture"] = self.texture.json()
  290.        
  291.         return j
  292.  
  293. class Material:
  294.     def __init__(self, f=None):
  295.         self.name = ""
  296.         self.diffuse = ColorValue()
  297.         self.specular = ColorValue()
  298.         self.specular_power = c_float()
  299.         self.emissive = ColorValue()
  300.         self.ambient = ColorValue()
  301.        
  302.         if f:
  303.             self.read(f)
  304.    
  305.     def read(self, f):
  306.         name_length = c_uint16()
  307.         f.readinto(name_length)
  308.         self.name = f.read(name_length.value)[0:-1].decode("ascii", "ignore")
  309.         f.readinto(self.diffuse)
  310.         f.readinto(self.specular)
  311.         f.readinto(self.specular_power)
  312.         f.readinto(self.emissive)
  313.         f.readinto(self.ambient)
  314.    
  315.     def json(self):
  316.         return {
  317.             "name": {
  318.                 "string": self.name,
  319.                 "length": len(self.name)+1,
  320.             },
  321.        
  322.             "diffuse": self.diffuse.json(),
  323.             "specular": self.specular.json(),
  324.             "specularPower": self.specular_power.value,
  325.             "emissive": self.emissive.json(),
  326.             "ambient": self.ambient.json()
  327.         }
  328.  
  329. class Texture:
  330.     def __init__(self, f=None):
  331.         self.name = ""
  332.         self.texture_type = c_uint32()
  333.         self.mipmaps = c_uint32()
  334.        
  335.         if f:
  336.             self.read(f)
  337.    
  338.     def read(self, f):
  339.         name_length = c_uint16()
  340.         f.readinto(name_length)
  341.         self.name = f.read(name_length.value)[0:-1].decode("ascii", "ignore")
  342.         f.readinto(self.texture_type)
  343.         f.readinto(self.mipmaps)
  344.    
  345.     def json(self):
  346.         return {
  347.             "name": {
  348.                 "string": self.name,
  349.                 "length": len(self.name)+1,
  350.             },
  351.            
  352.             "mipMapCount": self.mipmaps.value,
  353.             "type": self.texture_type.value
  354.         }
  355.  
  356. class Anim:
  357.     def __init__(self, f=None):
  358.         self.index = c_uint32()
  359.         self.max_frame = c_float()
  360.         self.states = None
  361.        
  362.         if f:
  363.             self.read(f)
  364.    
  365.     def read(self, f):
  366.         f.readinto(self.index)
  367.         f.readinto(self.max_frame)
  368.        
  369.         count = c_uint32()
  370.         f.readinto(count)
  371.         self.keys = (AnimKey * count.value)()
  372.         f.readinto(self.keys)
  373.    
  374.     def json(self):
  375.         return {
  376.             "index": self.index.value,
  377.             "maxFrame": self.max_frame.value,
  378.             "keys": [state.json() for state in self.keys]
  379.         }
  380.  
  381. class AnimList:
  382.     def __init__(self, f=None):
  383.         self.name = ""
  384.         self.anim_type = c_uint32()
  385.         self.max_frame = c_float()
  386.         self.end_frame = c_float()
  387.        
  388.         self.states = None
  389.         self.animations = None
  390.        
  391.         if f:
  392.             self.read(f)
  393.    
  394.     def read(self, f):
  395.         count = c_uint32()
  396.         name_length = c_uint16()
  397.         f.readinto(name_length)
  398.         self.name = f.read(name_length.value)[0:-1].decode("ascii", "ignore")
  399.        
  400.         f.readinto(self.anim_type)
  401.         f.readinto(self.max_frame)
  402.         f.readinto(self.end_frame)
  403.        
  404.         f.readinto(count)
  405.         self.states = (AnimKey * count.value)()
  406.         f.readinto(self.states)
  407.        
  408.         f.readinto(count)
  409.         self.animations = []
  410.         for animation_index in range(count.value):
  411.             self.animations += [Anim(f)]
  412.    
  413.     def json(self):
  414.         return {
  415.             "name": {
  416.                 "string": self.name,
  417.                 "length": len(self.name)+1,
  418.             },
  419.            
  420.             "type": self.anim_type.value,
  421.             "maxFrame": self.max_frame.value,
  422.             "endFrame": self.end_frame.value,
  423.            
  424.             "animations": [animation.json() for animation in self.animations],
  425.             "states": [animkey.json() for animkey in self.states]
  426.         }
  427.  
  428. class Mesh:
  429.     def __init__(self, f, msh, level=0):
  430.         self.msh = msh
  431.        
  432.         self.name = ""
  433.         self.state_index = c_uint32()
  434.         self.is_single_geom = c_int32()
  435.         self.renderflags = c_uint32()
  436.         self.matrix = Matrix()
  437.        
  438.         self.color = []
  439.         self.plane = []
  440.         self.vertex = []
  441.         self.vert_group = []
  442.         self.indices = []
  443.        
  444.         self.child = None
  445.         self.sibling = None
  446.        
  447.         # Hierarchize like an XSI
  448.         self.meshes = []
  449.         self.level = level
  450.        
  451.         if f:
  452.             self.read(f)
  453.    
  454.     def read(self, f):
  455.         count = c_uint32()
  456.         name_length = c_uint16()
  457.        
  458.         f.readinto(name_length)
  459.         self.name = f.read(name_length.value)[0:-1].decode("ascii", "ignore")
  460.        
  461.         if len(self.name) <= 0:
  462.             raise ZeroLengthName()
  463.        
  464.         f.readinto(self.state_index)
  465.         f.readinto(self.is_single_geom)
  466.         f.readinto(self.renderflags)
  467.         f.readinto(self.matrix)
  468.        
  469.         f.readinto(count)
  470.         self.color = (Color * count.value)()
  471.         f.readinto(self.color)
  472.        
  473.         f.readinto(count)
  474.         self.plane = (Plane * count.value)()
  475.         f.readinto(self.plane)
  476.        
  477.         f.readinto(count)
  478.         self.vertex = (Vertex * count.value)()
  479.         f.readinto(self.vertex)
  480.        
  481.         f.readinto(count)
  482.         self.vert_groups = []
  483.         for i in range(count.value):
  484.             self.vert_groups += [VertGroup(f)]
  485.        
  486.         f.readinto(count)
  487.         self.indices = (c_uint16 * count.value)()
  488.         f.readinto(self.indices)
  489.    
  490.     def walk(self, indentation_level=1):
  491.         for mesh in self.meshes:
  492.             yield mesh, indentation_level
  493.             yield from mesh.walk(indentation_level+1)
  494.    
  495.     def json(self):
  496.         j = {
  497.             "name": {
  498.                 "string": self.name,
  499.                 "length": len(self.name)+1
  500.             },
  501.            
  502.             "isSingleGeometry": self.is_single_geom.value,
  503.             "renderFlags": self.renderflags.value,
  504.             "stateIndex": self.state_index.value,
  505.             "objectMatrix": self.matrix.json(),
  506.            
  507.             "localColors": [color.json() for color in self.color],
  508.             "localGroups": [group.json() for group in self.vert_groups],
  509.             "localIndices": [index for index in self.indices],
  510.             "localPlanes": [plane.json() for plane in self.plane],
  511.             "localVertex": [vertex.json() for vertex in self.vertex]
  512.         }
  513.        
  514.         if self.child:
  515.             j["child"] = self.child.json()
  516.        
  517.         if self.sibling:
  518.             j["siblings"] = [self.sibling.json()]
  519.        
  520.         return j
  521.  
  522. class Block:
  523.     def __init__(self, f):
  524.         self.block_info = BlockInfo()
  525.         self.sphere = Sphere()
  526.         self.msh_header = MSH_Header()
  527.         self.name = ""
  528.        
  529.         self.vertices = None
  530.         self.vertex_normals = None
  531.         self.uvs = None
  532.         self.vertex_colors = None
  533.         self.faces = None
  534.        
  535.         self.buckydescriptions = []
  536.        
  537.         self.vert_to_state = []
  538.        
  539.         self.vert_groups = None
  540.         self.group_materials = []
  541.         self.group_textures = []
  542.        
  543.         self.indices = None
  544.        
  545.         self.planes = None
  546.         self.state_matrices = None
  547.         self.states = None
  548.        
  549.         self.anim_list = []
  550.        
  551.         self.root = None
  552.        
  553.         if f:
  554.             self.read(f)
  555.    
  556.     def read(self, f):
  557.         f.readinto(self.block_info)
  558.        
  559.         count = c_uint32()
  560.         block_type = c_uint32()
  561.         name_length = c_uint16()
  562.         f.readinto(name_length)
  563.         self.name = f.read(name_length.value)[0:-1].decode("ascii", "ignore")
  564.        
  565.         f.readinto(self.sphere)
  566.         f.readinto(self.msh_header)
  567.        
  568.         f.readinto(count)
  569.         self.vertices = (Vector * count.value)()
  570.         f.readinto(self.vertices)
  571.        
  572.         f.readinto(count)
  573.         self.vertex_normals = (Vector * count.value)()
  574.         f.readinto(self.vertex_normals)
  575.        
  576.         f.readinto(count)
  577.         self.uvs = (UVPair * count.value)()
  578.         f.readinto(self.uvs)
  579.        
  580.         f.readinto(count)
  581.         self.vertex_colors = (Color * count.value)()
  582.         f.readinto(self.vertex_colors)
  583.        
  584.         f.readinto(count)
  585.         self.faces = (FaceObj * count.value)()
  586.         f.readinto(self.faces)
  587.        
  588.         f.readinto(count)
  589.         for index in range(count.value):
  590.             self.buckydescriptions += [BuckyDesc(f)]
  591.        
  592.         f.readinto(count)
  593.         self.vert_to_state = []
  594.         array_count = c_uint32()
  595.         for index in range(count.value):
  596.             f.readinto(array_count)
  597.             array = []
  598.             for count_index in range(array_count.value):
  599.                 # f.readinto() for VertIndex causes 8 byte read.
  600.                 weight = c_float()
  601.                 vertex_index = c_uint16()
  602.                 f.readinto(weight)
  603.                 f.readinto(vertex_index)
  604.                 array += [VertIndex(weight, vertex_index)]
  605.            
  606.             self.vert_to_state += [VertIndexContainer(array_count.value, array)]
  607.        
  608.         f.readinto(count)
  609.         self.vert_groups = []
  610.         for i in range(count.value):
  611.             self.vert_groups += [VertGroup(f)]
  612.        
  613.         f.readinto(count)
  614.         self.indices = (c_uint16 * count.value)()
  615.         f.readinto(self.indices)
  616.        
  617.         f.readinto(count)
  618.         self.planes = (Plane * count.value)()
  619.         f.readinto(self.planes)
  620.        
  621.         f.readinto(count)
  622.         self.state_matrices = (Matrix * count.value)()
  623.         f.readinto(self.state_matrices)
  624.        
  625.         f.readinto(count)
  626.         self.states = (AnimKey * count.value)()
  627.         f.readinto(self.states)
  628.        
  629.         f.readinto(count)
  630.         self.animation_list = []
  631.         for animlist_index in range(count.value):
  632.             self.animation_list += [AnimList(f)]
  633.        
  634.         self.root = Mesh(f, self, 0)
  635.         self.meshes = [self.root]
  636.        
  637.         in_mesh = 1
  638.         indentation_level = 0 # 0 is root level
  639.         mesh_at = [self.root]
  640.        
  641.         return
  642.        
  643.         while in_mesh > 0:
  644.             f.readinto(block_type)
  645.             if block_type.value == MSH_CHILD:
  646.                 this_mesh = Mesh(f, self, indentation_level + 1)
  647.                 mesh_at[indentation_level].child = this_mesh
  648.                 mesh_at[indentation_level].meshes += [this_mesh]
  649.                
  650.                 indentation_level += 1
  651.                 in_mesh += 1
  652.                
  653.                 if len(mesh_at) < indentation_level+1:
  654.                     mesh_at += [this_mesh]
  655.                 else:
  656.                     mesh_at[indentation_level] = this_mesh
  657.            
  658.             elif block_type.value == MSH_SIBLING:
  659.                 this_mesh = Mesh(f, self, indentation_level)
  660.                 mesh_at[indentation_level].sibling = this_mesh
  661.                 mesh_at[indentation_level-1].meshes += [this_mesh]
  662.                 mesh_at[indentation_level] = this_mesh
  663.                
  664.                 in_mesh += 1
  665.            
  666.             elif block_type.value == MSH_END:
  667.                 in_mesh -= 1
  668.                
  669.                 while in_mesh < indentation_level:
  670.                     indentation_level -= 1
  671.            
  672.             else:
  673.                 raise UnknownBlock("Unhandled Mesh Block %s" % hex(block_type.value))
  674.        
  675.         f.readinto(block_type)
  676.        
  677.         if block_type.value != MSH_EOF:
  678.             raise InvalidFormat("Unexpected EOF")
  679.    
  680.     def walk(self):
  681.         yield self.root, 0 # 0 indentation level
  682.         yield from self.root.walk()
  683.    
  684.     def json(self):
  685.         j = {
  686.             "name": {
  687.                 "string": self.name,
  688.                 "length": len(self.name)+1
  689.             },
  690.            
  691.             "bigSphere": self.sphere.json(),
  692.             "blockInfo": self.block_info.json(),
  693.            
  694.             "vertices": [vertex.json() for vertex in self.vertices],
  695.             "normals": [nomral.json() for nomral in self.vertex_normals],
  696.             "uvs": [uv.json() for uv in self.uvs],
  697.             "colors": [color.json() for color in self.vertex_colors],
  698.             "faces": [face.json() for face in self.faces],
  699.             "buckys": [bucky.json() for bucky in self.buckydescriptions],
  700.             "vertToState": [vts.json() for vts in self.vert_to_state],
  701.             "groups": [vg.json() for vg in self.vert_groups],
  702.             "indices": [index for index in self.indices],
  703.             "planes": [plane.json() for plane in self.planes],
  704.             "stateMats": [state_mat.json() for state_mat in self.state_matrices],
  705.             "States": [state.json() for state in self.states],
  706.             "animList": [al.json() for al in self.animation_list],
  707.            
  708.             "mesh": self.root.json()
  709.         }
  710.        
  711.         j.update(self.msh_header.json())
  712.        
  713.         return j
  714.  
  715. class MSH:
  716.     def __init__(self, file_path):
  717.         self.block_header = BlockHeader()
  718.         self.blocks = []
  719.        
  720.         with open(file_path, "rb") as f:
  721.             self.read(f)
  722.    
  723.     def read(self, f):
  724.         f.readinto(self.block_header)
  725.        
  726.         for block_index in range(self.block_header.blockCount):
  727.             self.blocks += [Block(f)]
  728.    
  729.     def walk(self):
  730.         for block in self.blocks:
  731.             yield from block.walk()
  732.    
  733.     def to_json(self, file_path, indent=None):
  734.         with open(file_path, "w") as f:
  735.             j = {
  736.                 "verID": self.block_header.verID,
  737.                 "blockCount": self.block_header.blockCount,
  738.                 "fileType": bytearray(self.block_header.fileType).decode("ascii", "ignore"),
  739.                 "notUsed": " ".join(["%02X" % x for x in self.block_header.notUsed])
  740.             }
  741.            
  742.             j["meshRoot"] = [block.json() for block in self.blocks]
  743.            
  744.             f.write(json.dumps(j, sort_keys=bool(indent), indent=indent))
  745.  
  746. if __name__ == "__main__":
  747.     #~ msh = MSH("./sfvltank_MORPH.msh")
  748.     msh = MSH(r"D:\BZ2 Static\Data Paks\data.pak\binData\fvsent_skel.msh")
  749.     #~ msh = MSH(r"D:\BZ2 Static\Data Paks\data.pak\binData\ivrecy00.msh")
  750.     #~ msh = MSH(r"D:\BZ2 Static\Data Paks\fedata.pak\binData\Cvconst02_skel.msh")
  751.     #~ msh = MSH(r"D:\BZ2 Static\Data Paks\data.pak\binData\ivtank00.msh")
  752.     #~ msh = MSH(r"D:\BZ2 Static\Data Paks\data.pak\binData\apwrck00.msh")
  753.     #~ msh = MSH(r"D:\BZ2 Static\Data Paks\data.pak\binData\ibcrat00.msh")
  754.    
  755.     for x, y in msh.walk():
  756.         print("|" + "-"*y + ">"*bool(y) + " " + x.name[0:16])
  757.    
  758.     msh.to_json("test.json", "    ")
  759.  
RAW Paste Data