def start_debug(host='localhost', port=REMOTE_PORT): NifLog.debug(f"Setting up debugger") try: pydev_src = os.environ['PYDEVDEBUG'] NifLog.debug(f"Dev: Found: {pydev_src}") if sys.path.count(pydev_src) < 1: sys.path.append(pydev_src) NifLog.debug(f"Dev: Added to sys.path - {sys.path}") except KeyError: NifLog.info(f"Dev: Sys variable not set") return try: NifLog.debug(f"Attempting to load pydevd") from pydevd_pycharm import settrace NifLog.debug(f"Dev: Loaded pydevd") except ImportError: NifLog.debug(f"Dev: Import failed to find pydevd module.\nPython Remote Debugging Server not found") return try: NifLog.debug(f"Dev: Attempting to set a tracepoint in the stack") settrace(host=host, port=port, stdoutToServer=True, stderrToServer=True, suspend=True) NifLog.debug(f"Dev: Debugger was successfully detected") except Exception as e: NifLog.debug(f"Dev: Unable to connect to remote debugging server") NifLog.debug(e) return NifLog.debug("Debugger setup completed")
def apply_skin_deformation(n_data): """ Process all geometries in NIF tree to apply their skin """ # get all geometries with skin n_geoms = [ g for g in n_data.get_global_iterator() if isinstance(g, NifFormat.NiGeometry) and g.is_skin() ] # make sure that each skin is applied only once to avoid distortions when a model is referred to twice for n_geom in set(n_geoms): NifLog.info('Applying skin deformation on geometry {0}'.format( n_geom.name)) skininst = n_geom.skin_instance skindata = skininst.data if skindata.has_vertex_weights: vertices = n_geom.get_skin_deformation()[0] else: NifLog.info( "PyFFI does not support this type of skinning, so here's a workaround..." ) vertices = VertexGroup.get_skin_deformation_from_partition( n_geom) # finally we can actually set the data for vold, vnew in zip(n_geom.data.vertices, vertices): vold.x = vnew.x vold.y = vnew.y vold.z = vnew.z
def export_bsxflags_upb(self, root_block, root_objects): # TODO [object][property] Fixme NifLog.info("Checking collision") # activate oblivion/Fallout 3 collision and physics if bpy.context.scene.niftools_scene.game in ('OBLIVION', 'FALLOUT_3', 'SKYRIM'): b_obj = self.has_collision() if b_obj: # enable collision bsx = block_store.create_block("BSXFlags") bsx.name = 'BSX' root_block.add_extra_data(bsx) found_bsx = False for root_object in root_objects: if root_object.niftools.bsxflags: if found_bsx: raise NifError( "Multiple objects have BSXFlags. Only one onject may contain this data" ) else: found_bxs = True bsx.integer_data = root_object.niftools.bsxflags # many Oblivion nifs have a UPB, but export is disabled as # they do not seem to affect anything in the game if b_obj.niftools.upb: upb = block_store.create_block("NiStringExtraData") upb.name = 'UPB' if b_obj.niftools.upb == '': upb.string_data = UPB_DEFAULT else: upb.string_data = b_obj.niftools.upb.encode() root_block.add_extra_data(upb)
def export_root_node(self, root_objects, filebase): """ Exports a nif's root node; use blender root if there is only one, else create a meta root """ # TODO [collsion] detect root collision -> root collision node (can be mesh or empty) # self.nif_export.collisionhelper.export_collision(b_obj, n_parent) # return None # done; stop here self.n_root = None # there is only one root object so that will be our final root if len(root_objects) == 1: b_obj = root_objects[0] self.export_node(b_obj, None) # there is more than one root object so we create a meta root else: NifLog.info("Created meta root because blender scene had multiple root objects") self.n_root = types.create_ninode() self.n_root.name = "Scene Root" for b_obj in root_objects: self.export_node(b_obj, self.n_root) # TODO [object] How dow we know we are selecting the right node in the case of multi-root? # making root block a fade node root_type = b_obj.niftools.rootnode if bpy.context.scene.niftools_scene.game in ('FALLOUT_3', 'SKYRIM') and root_type == 'BSFadeNode': NifLog.info("Making root block a BSFadeNode") fade_root_block = NifFormat.BSFadeNode().deepcopy(self.n_root) fade_root_block.replace_global_node(self.n_root, fade_root_block) self.n_root = fade_root_block # various extra datas object_property = ObjectDataProperty() object_property.export_bsxflags_upb(self.n_root, root_objects) object_property.export_inventory_marker(self.n_root, root_objects) object_property.export_weapon_location(self.n_root, b_obj) types.export_furniture_marker(self.n_root, filebase) return self.n_root
def execute(self): """Main import function.""" try: dirname = os.path.dirname(NifOp.props.filepath) kf_files = [os.path.join(dirname, file.name) for file in NifOp.props.files if file.name.lower().endswith(".kf")] # if an armature is present, prepare the bones for all actions b_armature = math.get_armature() if b_armature: # the axes used for bone correction depend on the armature in our scene math.set_bone_orientation(b_armature.data.niftools.axis_forward, b_armature.data.niftools.axis_up) # get nif space bind pose of armature here for all anims self.transform_anim.get_bind_data(b_armature) for kf_file in kf_files: kfdata = KFFile.load_kf(kf_file) self.apply_scale(kfdata, NifOp.props.scale_correction) # calculate and set frames per second self.transform_anim.set_frames_per_second(kfdata.roots) for kf_root in kfdata.roots: self.transform_anim.import_kf_root(kf_root, b_armature) except NifError: return {'CANCELLED'} NifLog.info("Finished successfully") return {'FINISHED'}
def export_text_keys(self, b_action): """Process b_action's pose markers and return an extra string data block.""" if NifOp.props.animation == 'GEOM_NIF': # animation group extra data is not present in geometry only files return NifLog.info("Exporting animation groups") self.add_dummy_markers(b_action) # add a NiTextKeyExtraData block n_text_extra = block_store.create_block("NiTextKeyExtraData", b_action.pose_markers) # create a text key for each frame descriptor n_text_extra.num_text_keys = len(b_action.pose_markers) n_text_extra.text_keys.update_size() f0, f1 = b_action.frame_range for key, marker in zip(n_text_extra.text_keys, b_action.pose_markers): f = marker.frame if (f < f0) or (f > f1): NifLog.warn( f"Marker out of animated range ({f} not between [{f0}, {f1}])" ) key.time = f / self.fps key.value = marker.name.replace('/', '\r\n') return n_text_extra
def import_material_uv_controller(self, b_material, n_geom): """Import UV controller data.""" # search for the block n_ctrl = math.find_controller(n_geom, NifFormat.NiUVController) if not n_ctrl: return NifLog.info("Importing UV controller") b_mat_action = self.create_action(b_material, "MaterialAction") dtypes = ("offset", 0), ("offset", 1), ("scale", 0), ("scale", 1) for n_uvgroup, (data_path, array_ind) in zip(n_ctrl.data.uv_groups, dtypes): if n_uvgroup.keys: interp = self.get_b_interp_from_n_interp( n_uvgroup.interpolation) # in blender, UV offset is stored per n_texture slot # so we have to repeat the import for each used tex slot for i, texture_slot in enumerate(b_material.texture_slots): if texture_slot: fcurves = self.create_fcurves( b_mat_action, f"texture_slots[{i}]." + data_path, (array_ind, ), n_ctrl.flags) for key in n_uvgroup.keys: if "offset" in data_path: self.add_key(fcurves, key.time, (-key.value, ), interp) else: self.add_key(fcurves, key.time, (key.value, ), interp)
def start_debug(port=REMOTE_PORT): NifLog.debug("Setting up debugger") try: pydev_src = os.environ['PYDEVDEBUG'] NifLog.debug(f"Found: {pydev_src}") if sys.path.count(pydev_src) < 1: sys.path.append(pydev_src) except KeyError: NifLog.info("Dev: Sys variable not set") return try: from pydevd_pycharm import settrace except ImportError: NifLog.debug("Dev: Import failed to find pydevd module.\nPython Remote Debugging Server not found") return try: settrace('localhost', port=port, stdoutToServer=True, stderrToServer=True, suspend=True) except Exception as e: NifLog.debug("Unable to connect to remote debugging server") NifLog.debug(e) return NifLog.debug("Debugger setup completed")
def import_morph_controller(self, n_node, b_obj): """Import NiGeomMorpherController as shape keys for blender object.""" n_morphCtrl = math.find_controller(n_node, NifFormat.NiGeomMorpherController) if n_morphCtrl: NifLog.debug("NiGeomMorpherController processed") b_mesh = b_obj.data morphData = n_morphCtrl.data if morphData.num_morphs: # get name for base key keyname = morphData.morphs[0].frame_name.decode() if not keyname: keyname = 'Base' # insert base key at frame 1, using relative keys sk_basis = b_obj.shape_key_add(name=keyname) # get base vectors and import all morphs baseverts = morphData.morphs[0].vectors shape_action = self.create_action(b_obj.data.shape_keys, b_obj.name + "-Morphs") for idxMorph in range(1, morphData.num_morphs): # get name for key keyname = morphData.morphs[idxMorph].frame_name.decode() if not keyname: keyname = f'Key {idxMorph}' NifLog.info(f"Inserting key '{keyname}'") # get vectors morph_verts = morphData.morphs[idxMorph].vectors self.morph_mesh(b_mesh, baseverts, morph_verts) shape_key = b_obj.shape_key_add(name=keyname, from_mix=False) # first find the keys # older versions store keys in the morphData morph_data = morphData.morphs[idxMorph] # newer versions store keys in the controller if not morph_data.keys: try: if n_morphCtrl.interpolators: morph_data = n_morphCtrl.interpolators[idxMorph].data.data elif n_morphCtrl.interpolator_weights: morph_data = n_morphCtrl.interpolator_weights[idxMorph].interpolator.data.data except KeyError: NifLog.info(f"Unsupported interpolator \"{type(n_morphCtrl.interpolator_weights['idxMorph'].interpolator)}\"") continue # get the interpolation mode interp = self.get_b_interp_from_n_interp( morph_data.interpolation) fcu = self.create_fcurves(shape_action, "value", (0,), flags=n_morphCtrl.flags, keyname=shape_key.name) # set keyframes for key in morph_data.keys: self.add_key(fcu, key.time, (key.value,), interp)
def add_dummy_markers(self, b_action): # if we exported animations, but no animation groups are defined, # define a default animation group NifLog.info("Checking action pose markers.") if not b_action.pose_markers: NifLog.info("Defining default action pose markers.") for frame, text in zip(b_action.frame_range, ("Idle: Start/Idle: Loop Start", "Idle: Loop Stop/Idle: Stop")): marker = b_action.pose_markers.new(text) marker.frame = frame
def get_version_data(): """ Returns NifFormat.Data of the correct version and user versions """ b_scene = bpy.context.scene.niftools_scene game = b_scene.game version = b_scene.nif_version NifLog.info(f"Writing NIF version 0x{version:08X}") # get user version and user version 2 for export user_version = b_scene.user_version if b_scene.user_version else b_scene.USER_VERSION.get(game, 0) user_version_2 = b_scene.user_version_2 if b_scene.user_version_2 else b_scene.USER_VERSION_2.get(game, 0) return version, NifFormat.Data(version, user_version, user_version_2)
def locate_dependencies(): # Python dependencies are bundled inside the io_scene_nif/dependencies folder global current_dir current_dir = os.path.dirname(__file__) _dependencies_path = os.path.join(current_dir, "dependencies") if _dependencies_path not in sys.path: sys.path.append(_dependencies_path) del _dependencies_path with open(os.path.join(current_dir, "VERSION.txt")) as version: NifLog.info(f"Loading: Blender Niftools Addon: {version.read()}") import pyffi NifLog.info(f"Loading: PyFFi: {pyffi.__version__}")
def import_embedded_texture_source(self, source): fn, tex = self.generate_image_name() # save embedded texture as dds file with open(tex, "wb") as stream: try: NifLog.info(f"Saving embedded texture as {tex}") source.pixel_data.save_as_dds(stream) except ValueError: NifLog.warn(f"Pixel format not supported in embedded texture {tex}!") return self.load_image(tex)
def import_visibility(self, n_node, b_obj): """Import vis controller for blender object.""" n_vis_ctrl = math.find_controller(n_node, NifFormat.NiVisController) if not n_vis_ctrl: return NifLog.info("Importing vis controller") b_obj_action = self.create_action(b_obj, b_obj.name + "-Anim") fcurves = self.create_fcurves(b_obj_action, "hide", (0, ), n_vis_ctrl.flags) for key in n_vis_ctrl.data.keys: self.add_key(fcurves, key.time, (key.value, ), "CONSTANT")
def register_block(self, block, b_obj=None): """Helper function to register a newly created block in the list of exported blocks and to associate it with a Blender object. @param block: The nif block. @param b_obj: The Blender object. @return: C{block}""" if b_obj is None: NifLog.info(f"Exporting {block.__class__.__name__} block") else: NifLog.info( f"Exporting {b_obj} as {block.__class__.__name__} block") self._block_to_obj[block] = b_obj return block
def __init__(self, operator, context): """Common initialization functions for executing the import/export operators: """ NifOp.init(operator, context) debugging.start_debug() # print scripts info from . import bl_info niftools_ver = (".".join(str(i) for i in bl_info["version"])) NifLog.info( f"Executing - Niftools : Blender Niftools Addon v{niftools_ver}" f"(running on Blender {bpy.app.version_string}, " f"PyFFI {pyffi.__version__})")
def set_frames_per_second(roots): """Scan all blocks and set a reasonable number for FPS to this class and the scene.""" # find all key times key_times = [] for root in roots: for kfd in root.tree(block_type=NifFormat.NiKeyframeData): key_times.extend(key.time for key in kfd.translations.keys) key_times.extend(key.time for key in kfd.scales.keys) key_times.extend(key.time for key in kfd.quaternion_keys) key_times.extend(key.time for key in kfd.xyz_rotations[0].keys) key_times.extend(key.time for key in kfd.xyz_rotations[1].keys) key_times.extend(key.time for key in kfd.xyz_rotations[2].keys) for kfi in root.tree(block_type=NifFormat.NiBSplineInterpolator): if not kfi.basis_data: # skip bsplines without basis data (eg bowidle.kf in Oblivion) continue key_times.extend( point * (kfi.stop_time - kfi.start_time) / (kfi.basis_data.num_control_points - 2) for point in range(kfi.basis_data.num_control_points - 2)) for uv_data in root.tree(block_type=NifFormat.NiUVData): for uv_group in uv_data.uv_groups: key_times.extend(key.time for key in uv_group.keys) # not animated, return a reasonable default if not key_times: return # calculate FPS key_times = sorted(set(key_times)) fps = animation.FPS lowest_diff = sum( abs(int(time * fps + 0.5) - (time * fps)) for time in key_times) # for test_fps in range(1,120): #disabled, used for testing for test_fps in [20, 24, 25, 30, 35]: diff = sum( abs(int(time * test_fps + 0.5) - (time * test_fps)) for time in key_times) if diff < lowest_diff: lowest_diff = diff fps = test_fps NifLog.info(f"Animation estimated at {fps} frames per second.") animation.FPS = fps bpy.context.scene.render.fps = fps bpy.context.scene.frame_set(0)
def export_text_keys(self, b_action, n_text_extra): """Process b_action's pose markers and populate the extra string data block.""" NifLog.info("Exporting animation groups") self.add_dummy_markers(b_action) # create a text key for each frame descriptor n_text_extra.num_text_keys = len(b_action.pose_markers) n_text_extra.text_keys.update_size() f0, f1 = b_action.frame_range for key, marker in zip(n_text_extra.text_keys, b_action.pose_markers): f = marker.frame if (f < f0) or (f > f1): NifLog.warn( f"Marker out of animated range ({f} not between [{f0}, {f1}])" ) key.time = f / self.fps key.value = marker.name.replace('/', '\r\n')
def export_egm(self, key_blocks): EGMData.data = EgmFormat.Data(num_vertices=len(key_blocks[0].data)) for key_block in key_blocks: if key_block.name.startswith("EGM SYM"): morph = EGMData.data.add_sym_morph() elif key_block.name.startswith("EGM ASYM"): morph = EGMData.data.add_asym_morph() else: continue NifLog.info(f"Exporting morph {key_block.name} to egm") relative_vertices = [] # note: key_blocks[0] is base b_key for base_vert, key_vert in zip(key_blocks[0].data, key_block.data): relative_vertices.append(key_vert.co - base_vert.co) morph.set_relative_vertices(relative_vertices)
def add_dummy_controllers(self): NifLog.info("Adding controllers and interpolators for skeleton") # note: block_store.block_to_obj changes during iteration, so need list copy for n_block in list(block_store.block_to_obj.keys()): if isinstance( n_block, NifFormat.NiNode) and n_block.name.decode() == "Bip01": for n_bone in n_block.tree(block_type=NifFormat.NiNode): n_kfc, n_kfi = self.transform_anim.create_controller( n_bone, n_bone.name.decode()) # todo [anim] use self.nif_export.animationhelper.set_flags_and_timing n_kfc.flags = 12 n_kfc.frequency = 1.0 n_kfc.phase = 0.0 n_kfc.start_time = consts.FLOAT_MAX n_kfc.stop_time = consts.FLOAT_MIN
def import_material_alpha_controller(self, b_material, n_material): # find alpha controller n_alphactrl = math.find_controller(n_material, NifFormat.NiAlphaController) if not n_alphactrl: return NifLog.info("Importing alpha controller") b_mat_action = self.create_action(b_material, "MaterialAction") fcurves = self.create_fcurves(b_mat_action, "niftools.emissive_alpha", range(3), n_alphactrl.flags) interp = self.get_b_interp_from_n_interp( n_alphactrl.data.data.interpolation) for key in n_alphactrl.data.data.keys: self.add_key(fcurves, key.time, (key.value, key.value, key.value), interp)
def add_dummy_markers(self, b_action): # if we exported animations, but no animation groups are defined, # define a default animation group NifLog.info("Checking action pose markers.") if not b_action.pose_markers: # has_controllers = False # for block in block_store.block_to_obj: # # has it a controller field? # if isinstance(block, NifFormat.NiObjectNET): # if block.controller: # has_controllers = True # break # if has_controllers: NifLog.info("Defining default action pose markers.") for frame, text in zip(b_action.frame_range, ("Idle: Start/Idle: Loop Start", "Idle: Loop Stop/Idle: Stop")): marker = b_action.pose_markers.new(text) marker.frame = frame
def execute(self): """Main import function.""" try: egm_path = NifOp.props.filepath if egm_path: EGMData.init(EGMFile.load_egm(egm_path)) # scale the data EGMData.data.apply_scale(NifOp.props.scale_correction) # TODO [morph][egm] if there is an egm, the assumption is that there is only one mesh in the nif # grab the active object b_obj = bpy.context.view_layer.objects.active if b_obj and b_obj.type == "MESH": self.morph_anim.import_egm_morphs(b_obj) except NifError: return {'CANCELLED'} NifLog.info("Finished successfully") return {'FINISHED'}
def execute(self): """Main import function.""" try: dirname = os.path.dirname(NifOp.props.filepath) kf_files = [ os.path.join(dirname, file.name) for file in NifOp.props.files if file.name.lower().endswith(".kf") ] b_armature = math.get_armature() if not b_armature: raise NifError( "No armature was found in scene, can not import KF animation!" ) # the axes used for bone correction depend on the armature in our scene math.set_bone_orientation(b_armature.data.niftools.axis_forward, b_armature.data.niftools.axis_up) # get nif space bind pose of armature here for all anims bind_data = armature.get_bind_data(b_armature) for kf_file in kf_files: kfdata = KFFile.load_kf(kf_file) # use pyffi toaster to scale the tree toaster = pyffi.spells.nif.NifToaster() toaster.scale = NifOp.props.scale_correction pyffi.spells.nif.fix.SpellScale(data=kfdata, toaster=toaster).recurse() # calculate and set frames per second self.tranform_anim.set_frames_per_second(kfdata.roots) for kf_root in kfdata.roots: self.tranform_anim.import_kf_root(kf_root, b_armature, bind_data) except NifError: return {'CANCELLED'} NifLog.info("Finished successfully") return {'FINISHED'}
def import_mesh(self, n_block, b_obj): """Creates and returns a raw mesh, or appends geometry data to group_mesh. :param n_block: The nif block whose mesh data to import. :type n_block: C{NiTriBasedGeom} :param b_obj: The mesh to which to append the geometry data. If C{None}, a new mesh is created. :type b_obj: A Blender object that has mesh data. """ assert (isinstance(n_block, NifFormat.NiTriBasedGeom)) node_name = n_block.name.decode() NifLog.info(f"Importing mesh data for geometry '{node_name}'") b_mesh = b_obj.data # shortcut for mesh geometry data n_tri_data = n_block.data if not n_tri_data: raise io_scene_niftools.utils.logging.NifError(f"No shape data in {node_name}") # create raw mesh from vertices and triangles b_mesh.from_pydata(n_tri_data.vertices, [], n_tri_data.get_triangles()) b_mesh.update() # must set faces to smooth before setting custom normals, or the normals bug out! is_smooth = True if (n_tri_data.has_normals or n_block.skin_instance) else False self.set_face_smooth(b_mesh, is_smooth) # store additional data layers Vertex.map_uv_layer(b_mesh, n_tri_data) Vertex.map_vertex_colors(b_mesh, n_tri_data) Vertex.map_normals(b_mesh, n_tri_data) self.mesh_prop_processor.process_property_list(n_block, b_obj) # import skinning info, for meshes affected by bones VertexGroup.import_skin(n_block, b_obj) # import morph controller if NifOp.props.animation: self.morph_anim.import_morph_controller(n_block, b_obj)
def import_material_color_controller(self, b_material, n_material, b_channel, n_target_color): # find material color controller with matching target color for ctrl in n_material.get_controllers(): if isinstance(ctrl, NifFormat.NiMaterialColorController): if ctrl.get_target_color() == n_target_color: n_matcolor_ctrl = ctrl break else: return NifLog.info( f"Importing material color controller for target color {n_target_color} into blender channel {b_channel}" ) # import data as curves b_mat_action = self.create_action(b_material, "MaterialAction") fcurves = self.create_fcurves(b_mat_action, b_channel, range(3), n_matcolor_ctrl.flags) interp = self.get_b_interp_from_n_interp( n_matcolor_ctrl.data.data.interpolation) for key in n_matcolor_ctrl.data.data.keys: self.add_key(fcurves, key.time, key.value.as_list(), interp)
def export_bsxflags_upb(self, root_block): # TODO [object][property] Fixme NifLog.info("Checking collision") # activate oblivion/Fallout 3 collision and physics if bpy.context.scene.niftools_scene.game in ('OBLIVION', 'FALLOUT_3', 'SKYRIM'): b_obj = self.has_collision() if b_obj: # enable collision bsx = block_store.create_block("BSXFlags") bsx.name = 'BSX' bsx.integer_data = b_obj.niftools.bsxflags root_block.add_extra_data(bsx) # many Oblivion nifs have a UPB, but export is disabled as # they do not seem to affect anything in the game if b_obj.niftools.upb: upb = block_store.create_block("NiStringExtraData") upb.name = 'UPB' if b_obj.niftools.upb == '': upb.string_data = 'Mass = 0.000000\r\nEllasticity = 0.300000\r\nFriction = 0.300000\r\nUnyielding = 0\r\nSimulation_Geometry = 2\r\nProxy_Geometry = <None>\r\nUse_Display_Proxy = 0\r\nDisplay_Children = 1\r\nDisable_Collisions = 0\r\nInactive = 0\r\nDisplay_Proxy = <None>\r\n' else: upb.string_data = b_obj.niftools.upb.encode() root_block.add_extra_data(upb)
def execute(self): """Main export function.""" NifLog.info(f"Exporting {NifOp.props.filepath}") # extract directory, base name, extension directory = os.path.dirname(NifOp.props.filepath) filebase, fileext = os.path.splitext( os.path.basename(NifOp.props.filepath)) if bpy.context.scene.niftools_scene.game == 'NONE': raise NifError( "You have not selected a game. Please select a game in the scene tab." ) prefix = "x" if bpy.context.scene.niftools_scene.game in ( 'MORROWIND', ) else "" self.version, data = scene.get_version_data() # todo[anim] - change to KfData, but create_controller() [and maybe more] has to be updated first NifData.init(data) b_armature = math.get_armature() # some scenes may not have an armature, so nothing to do here if b_armature: math.set_bone_orientation(b_armature.data.niftools.axis_forward, b_armature.data.niftools.axis_up) NifLog.info("Creating keyframe tree") kf_root = self.transform_anim.export_kf_root(b_armature) # write kf (and xkf if asked) ext = ".kf" NifLog.info(f"Writing {prefix}{ext} file") data.roots = [kf_root] data.neosteam = (bpy.context.scene.niftools_scene.game == 'NEOSTEAM') # scale correction for the skeleton self.apply_scale(data, round(1 / NifOp.props.scale_correction)) kffile = os.path.join(directory, prefix + filebase + ext) with open(kffile, "wb") as stream: data.write(stream) NifLog.info("Finished successfully") return {'FINISHED'}
def load_kf(file_path): """Loads a Kf file from the given path""" NifLog.info(f"Loading {file_path}") kf_file = NifFormat.Data() # open keyframe file for binary reading with open(file_path, "rb") as kf_stream: # check if nif file is valid kf_file.inspect_version_only(kf_stream) if kf_file.version >= 0: # it is valid, so read the file NifLog.info(f"KF file version: {kf_file.version:x}") NifLog.info("Reading keyframe file") kf_file.read(kf_stream) elif kf_file.version == -1: raise NifError("Unsupported KF version.") else: raise NifError("Not a KF file.") return kf_file
def load_nif(file_path): """Loads a nif from the given file path""" NifLog.info(f"Importing {file_path}") data = NifFormat.Data() # open file for binary reading with open(file_path, "rb") as nif_stream: # check if nif file is valid data.inspect_version_only(nif_stream) if data.version >= 0: # it is valid, so read the file NifLog.info(f"NIF file version: {data.version:x}") NifLog.info("Reading file") data.read(nif_stream) elif data.version == -1: raise NifError("Unsupported NIF version.") else: raise NifError("Not a NIF file.") return data