def __recalculate_connection_entry__(data_block, conn_key): """Recalculates connection entry data for given connection key. NOTE: if key doesn't exists error stack trace will be printed and script execution cancelled :param data_block: data block from where data should be read :type data_block: bpy_struct :param conn_key: connection key for connection which should be recalculated :type conn_key: str """ conn_entries = data_block[MAIN_DICT][REFS][CONNECTIONS][ENTRIES] locators_refs = data_block[MAIN_DICT][REFS][LOCATORS] conn_ref = conn_entries[conn_key] loc0_obj = bpy.data.objects[conn_ref[OUT]] loc1_obj = bpy.data.objects[conn_ref[IN]] conn_type = locators_refs[conn_ref[IN]][TYPE] conn_ref[VALID] = _object_utils.get_scs_root(loc0_obj) == _object_utils.get_scs_root(loc1_obj) # recalculate curves depending on type if conn_type == "Navigation Point": conn_ref[DATA] = _collector.collect_nav_curve_data(loc0_obj, loc1_obj) elif conn_type == "Map Point": conn_ref[DATA] = _collector.collect_map_line_data(loc0_obj, loc1_obj) elif conn_type == "Trigger Point": (loc0_avaliable, loc0_conns_count) = __tp_locator_avaliable__(data_block, loc0_obj.name) (loc1_avaliable, loc1_conns_count) = __tp_locator_avaliable__(data_block, loc1_obj.name) conn_ref[DATA] = _collector.collect_trigger_line_data(loc0_obj, loc0_conns_count, loc1_obj, loc1_conns_count)
def execute(self, context): scs_globals = _get_scs_globals() if self.type == "DefaultExportPath": obj = context.scene.scs_props prop = "default_export_filepath" elif self.type == "GameObjectExportPath": obj = context.active_object.scs_props prop = "scs_root_object_export_filepath" elif self.type == "GameObjectAnimExportPath": obj = _object_utils.get_scs_root(context.active_object).scs_props prop = "scs_root_object_anim_export_filepath" else: obj = context.active_object.scs_props prop = "scs_skeleton_custom_export_dirpath" if _path_utils.startswith(self.directory, scs_globals.scs_project_path): setattr(obj, prop, _path_utils.relative_path(scs_globals.scs_project_path, self.directory)) else: setattr(obj, prop, "//") self.report({'ERROR'}, "Selected path is not within SCS Project Base Path,\npath will be reset to SCS Project Base Path instead.") return {'CANCELLED'} return {'FINISHED'}
def execute(self, context): lprint("D " + self.bl_idname, report_errors=-1, report_warnings=-1) if not _path_utils.startswith(self.directory, _get_scs_globals().scs_project_path): message = "E Selected path is not inside SCS Project Base Path! Animation can't be exported to this directory." lprint(message) self.report({'ERROR'}, message[2:]) return {'CANCELLED'} armature = context.active_object scs_root_obj = _object_utils.get_scs_root(armature) anim_inventory = scs_root_obj.scs_object_animation_inventory skeleton_filepath = _path_utils.get_skeleton_relative_filepath( armature, self.directory, scs_root_obj.name) if 0 <= self.index < len(anim_inventory): anim = anim_inventory[self.index] _export.pia.export(scs_root_obj, armature, anim, self.directory, skeleton_filepath) lprint("", report_errors=1, report_warnings=1) return {'FINISHED'}
def locator_type_update(self, context): obj = context.object # PREVIEW MODELS LOADING if obj.scs_props.locator_type in ("Collision", "None"): _preview_models.unload(obj) elif not obj.scs_props.locator_preview_model_present: _preview_models.load(obj) # SCS_PART RESET if not _object_utils.has_part_property(obj): obj.scs_props.scs_part = "" else: scs_root_object = _object_utils.get_scs_root(obj) if scs_root_object: part_inventory = scs_root_object.scs_object_part_inventory # set part index to active or first # NOTE: direct access needed otherwise get function sets invalid index because # active object has still old part value part_index = scs_root_object.scs_props.active_scs_part_get_direct() if part_index >= len(part_inventory) or part_index < 0: part_index = 0 obj.scs_props.scs_part = part_inventory[part_index].name else: # if no root assign default obj.scs_props.scs_part = _PART_consts.default_name
def __objects_reparent__(parent, new_objs): """Hookup function for objects reparent operation. :param parent: parent object where all of the objects were parented :type parent: bpy.types.Object :param new_objs: list of object which were parented to object :type new_objs: list of bpy.types.Object """ # fixing parts on newly parented object scs_root_object = _object_utils.get_scs_root(parent) if scs_root_object: part_inventory = scs_root_object.scs_object_part_inventory assign_part_index = scs_root_object.scs_props.active_scs_part # if active is out of range assign first one if assign_part_index >= len(part_inventory) or assign_part_index < 0: assign_part_index = 0 new_mats = [] for new_obj in new_objs: if _object_utils.has_part_property(new_obj): new_obj.scs_props.scs_part = part_inventory[ assign_part_index].name for slot in new_obj.material_slots: if slot.material and slot.material not in new_mats: new_mats.append(slot.material) _looks.add_materials(scs_root_object, new_mats)
def __objects_reparent__(parent, new_objs): """Hookup function for objects reparent operation. :param parent: parent object where all of the objects were parented :type parent: bpy.types.Object :param new_objs: list of object which were parented to object :type new_objs: list of bpy.types.Object """ # fixing parts on newly parented object scs_root_object = _object_utils.get_scs_root(parent) if scs_root_object: part_inventory = scs_root_object.scs_object_part_inventory assign_part_index = scs_root_object.scs_props.active_scs_part # if active is out of range assign first one if assign_part_index >= len(part_inventory) or assign_part_index < 0: assign_part_index = 0 new_mats = [] for new_obj in new_objs: if _object_utils.has_part_property(new_obj): new_obj.scs_props.scs_part = part_inventory[assign_part_index].name for slot in new_obj.material_slots: if slot.material and slot.material not in new_mats: new_mats.append(slot.material) _looks.add_materials(scs_root_object, new_mats)
def execute(self, context): scs_globals = _get_scs_globals() if self.type == "DefaultExportPath": obj = context.scene.scs_props prop = "default_export_filepath" elif self.type == "GameObjectExportPath": obj = context.active_object.scs_props prop = "scs_root_object_export_filepath" elif self.type == "GameObjectAnimExportPath": obj = _object_utils.get_scs_root( context.active_object).scs_props prop = "scs_root_object_anim_export_filepath" else: obj = context.active_object.scs_props prop = "scs_skeleton_custom_export_dirpath" if _path_utils.startswith(self.directory, scs_globals.scs_project_path): setattr( obj, prop, _path_utils.relative_path(scs_globals.scs_project_path, self.directory)) else: setattr(obj, prop, "//") self.report({ 'ERROR' }, "Selected path is not within SCS Project Base Path,\npath will be reset to SCS Project Base Path instead." ) return {'CANCELLED'} return {'FINISHED'}
def name_update(self, context): lprint("D SCS Look inventory name update: %s", (self.name, )) # convert name to game engine like name tokenized_name = _name_utils.tokenize_name(self.name) if self.name != tokenized_name: self.name = tokenized_name # always get scs root to have access to look inventory scs_root_obj = _object_utils.get_scs_root(context.active_object) # if there is more of variants with same name, make postfixed name (this will cause another name update) if len( _inventory.get_indices(scs_root_obj.scs_object_look_inventory, self.name)) == 2: # duplicate i = 1 new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) while _inventory.get_index(scs_root_obj.scs_object_look_inventory, new_name) != -1: new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) i += 1 if new_name != self.name: self.name = new_name
def locator_type_update(self, context): obj = context.object # PREVIEW MODELS LOADING if obj.scs_props.locator_type in ("Collision", "None"): _preview_models.unload(obj) elif not obj.scs_props.locator_preview_model_present: _preview_models.load(obj) # SCS_PART RESET if not _object_utils.has_part_property(obj): obj.scs_props.scs_part = "" else: scs_root_object = _object_utils.get_scs_root(obj) if scs_root_object: part_inventory = scs_root_object.scs_object_part_inventory # set part index to active or first # NOTE: direct access needed otherwise get function sets invalid index because # active object has still old part value part_index = scs_root_object.scs_props.active_scs_part_get_direct( ) if part_index >= len(part_inventory) or part_index < 0: part_index = 0 obj.scs_props.scs_part = part_inventory[part_index].name else: # if no root assign default obj.scs_props.scs_part = _PART_consts.default_name
def execute(self, context): lprint('D Import Animation Action...') ''' print(' o directory: %r' % str(self.directory)) print(' o files:') for file in self.files: print(' o file: %r' % str(file.name)) ''' pia_files = [os.path.join(self.directory, file.name) for file in self.files] if context.active_object.type == 'ARMATURE': armature = context.active_object else: return {'CANCELLED'} skeleton = None bones = None ''' for file in pia_files: print(' o file: %r' % str(file)) ''' root_object = _object_utils.get_scs_root(armature) lprint('S armature: %s\nskeleton: %s\nbones: %s\n', (str(armature), str(skeleton), str(bones))) _import.pia.load(root_object, pia_files, armature) # , skeleton, bones) return {'FINISHED'}
def execute(self, context): lprint('D Decrease Animation Steps...') scene = context.scene scene.use_preview_range = True action = context.active_object.animation_data.action if action.scs_props.anim_export_step == 1: lprint('E Cannot set lower value for %r than %i!', ('Export Step', 1)) else: active_object = context.active_object scs_root_object = _object_utils.get_scs_root(active_object) # active_scs_animation = scs_root_object.scs_props.active_scs_animation inventory = scs_root_object.scs_object_animation_inventory # animation = inventory[active_scs_animation] # MOVE FRAMES # print_fcurve = 13 for fcurve_i, fcurve in enumerate(action.fcurves): # if fcurve_i == print_fcurve: print('fcurve: %r - %s' % (str(fcurve.data_path), str(fcurve.range()))) for keyframe_i, keyframe in enumerate(fcurve.keyframe_points): # if fcurve_i == print_fcurve: print(' %i keyframe: %s' % (keyframe_i, str(keyframe.co))) # OLD WAY OF INCREASING ACTION LENGTH FROM THE FIRST KEYFRAME # start_frame = fcurve.range()[0] # actual_frame = keyframe.co.x # keyframe.co.x = ((actual_frame - start_frame) / 2) + start_frame # NEW WAY - SIMPLE DOUBLING THE VALUES keyframe.co.x /= 2 fcurve.update() # ## PRINTOUTS # print(' group: %r' % str(fcurve.group.name)) # for channel_i, channel in enumerate(fcurve.group.channels): # print(' %i channel: %s - %s' % (channel_i, str(channel.data_path), str(channel.range()))) # for keyframe_i, keyframe in enumerate(channel.keyframe_points): # print(' %i keyframe: %s' % (keyframe_i, str(keyframe.co))) # INCREASE GLOBAL RANGE scene.frame_start /= 2 scene.frame_end /= 2 # INCREASE PREVIEW RANGE scene.frame_preview_start /= 2 scene.frame_preview_end /= 2 # INCREASE END FRAME NUMBER IN ALL ANIMATIONS THAT USES THE ACTUAL ACTION for anim in inventory: if anim.action == action.name: anim.anim_start /= 2 anim.anim_end /= 2 # INCREASE EXPORT STEP # print('anim_export_step: %s' % str(action.scs_props.anim_export_step)) action.scs_props.anim_export_step /= 2 # INCREASE FPS scene.render.fps /= 2 return {'FINISHED'}
def __objects_reparent__(parent, new_objs): """Hookup function for objects reparent operation. :param parent: parent object where all of the objects were parented :type parent: bpy.types.Object :param new_objs: list of object which were parented to object :type new_objs: list of bpy.types.Object """ # fixing parts on newly parented object scs_root_object = _object_utils.get_scs_root(parent) if scs_root_object: part_inventory = scs_root_object.scs_object_part_inventory assign_part_index = scs_root_object.scs_props.active_scs_part # if active is out of range assign first one if assign_part_index >= len(part_inventory) or assign_part_index < 0: assign_part_index = 0 new_mats = [] for new_obj in new_objs: # NOTE: second condition prevents overwriting part on object which already have # valid part from before (This might happen when re-parenting from one SCS Root to another) if _object_utils.has_part_property(new_obj) and new_obj.scs_props.scs_part not in part_inventory: new_obj.scs_props.scs_part = part_inventory[assign_part_index].name for slot in new_obj.material_slots: if slot.material and slot.material not in new_mats: new_mats.append(slot.material) _looks.add_materials(scs_root_object, new_mats)
def length_update(self, context): """If the total time for animation is tweaked, FPS value is recalculated to keep the playback speed as close as possible to the resulting playback speed in the game engine. :param context: Blender Context :type context: bpy.types.Context """ active_object = context.active_object if active_object: if active_object.animation_data: action = active_object.animation_data.action if action: scs_root_object = _object_utils.get_scs_root(active_object) if scs_root_object: active_scs_animation = scs_root_object.scs_props.active_scs_animation scs_object_animation_inventory = scs_root_object.scs_object_animation_inventory animation = scs_object_animation_inventory[ active_scs_animation] _animation_utils.set_fps_for_preview( context.scene, animation.length, action.scs_props.anim_export_step, animation.anim_start, animation.anim_end, )
def __locator_changed__(data_block, loc_obj): """Checks if locator object is different from current state in cache. In case that is, it returns True and already updates cached locator to current state :param loc_obj: Blender object which is locator :type loc_obj: bpy.types.Object :return: True if object was changed and False if there is no change :rtype: bool """ data = data_block[MAIN_DICT] loc_cached = data[CACHE][LOCATORS][loc_obj.name] changed = False # in case we will extend caching properties we have to make sure # that existing models saved in blend file won't fail because of # index out of bounds during access. while len(loc_cached) <= 7: loc_cached.append("") matrix_hash = hashlib.md5(str(loc_obj.matrix_world).encode("utf-8")).hexdigest() if matrix_hash != loc_cached[0]: loc_cached[0] = matrix_hash changed = True if loc_obj.scs_props.locator_prefab_np_blinker != loc_cached[1]: loc_cached[1] = loc_obj.scs_props.locator_prefab_np_blinker changed = True if loc_obj.scs_props.locator_prefab_np_allowed_veh != loc_cached[2]: loc_cached[2] = loc_obj.scs_props.locator_prefab_np_allowed_veh changed = True if loc_obj.scs_props.locator_prefab_np_priority_modifier != loc_cached[3]: loc_cached[3] = loc_obj.scs_props.locator_prefab_np_priority_modifier changed = True if loc_obj.scs_props.locator_prefab_mp_custom_color != loc_cached[4]: loc_cached[4] = loc_obj.scs_props.locator_prefab_mp_custom_color changed = True prefab_exit = str(loc_obj.scs_props.locator_prefab_mp_prefab_exit) if prefab_exit != loc_cached[5]: loc_cached[5] = prefab_exit changed = True road_size = str(loc_obj.scs_props.locator_prefab_mp_road_size) if road_size != loc_cached[6]: loc_cached[6] = road_size changed = True root_hash = hashlib.md5(str(_object_utils.get_scs_root(loc_obj)).encode("utf-8")).hexdigest() if root_hash != loc_cached[7]: loc_cached[7] = root_hash changed = True data[CACHE][LOCATORS][loc_obj.name] = loc_cached return changed
def __objects_reparent__(parent, new_objs): """Hookup function for objects reparent operation. :param parent: parent object where all of the objects were parented :type parent: bpy.types.Object :param new_objs: list of object which were parented to object :type new_objs: list of bpy.types.Object """ # fixing parts on newly parented object scs_root_object = _object_utils.get_scs_root(parent) if scs_root_object: part_inventory = scs_root_object.scs_object_part_inventory assign_part_index = scs_root_object.scs_props.active_scs_part # if active is out of range assign first one if assign_part_index >= len(part_inventory) or assign_part_index < 0: assign_part_index = 0 new_mats = [] for new_obj in new_objs: # NOTE: second condition prevents overwriting part on object which already have # valid part from before (This might happen when re-parenting from one SCS Root to another) if _object_utils.has_part_property( new_obj ) and new_obj.scs_props.scs_part not in part_inventory: new_obj.scs_props.scs_part = part_inventory[ assign_part_index].name for slot in new_obj.material_slots: if slot.material and slot.material not in new_mats: new_mats.append(slot.material) _looks.add_materials(scs_root_object, new_mats)
def poll(cls, context): if not _MaterialPanelBlDefs.poll(context): return False cls.object = context.active_object cls.scs_root = _object_utils.get_scs_root(cls.object) return cls.object and cls.scs_root
def execute(self, context): lprint('D Export From Menu...') from io_scs_tools import exp as _export from io_scs_tools.utils import object as _object_utils filepath = os.path.dirname(self.filepath) # convert it to None, so export will ignore given menu file path and try to export to other none menu set paths if self.filepath == "": filepath = None export_scope = _get_scs_globals().export_scope init_obj_list = {} if export_scope == "selection": for obj in bpy.context.selected_objects: root = _object_utils.get_scs_root(obj) if root: if root != obj: # add only selected children init_obj_list[obj.name] = obj init_obj_list[root.name] = root else: # add every children if all are unselected children = _object_utils.get_children(obj) local_reselected_objs = [] for child_obj in children: local_reselected_objs.append(child_obj) # if some child is selected this means we won't reselect nothing in this game object if child_obj.select: local_reselected_objs = [] break for reselected_obj in local_reselected_objs: init_obj_list[reselected_obj.name] = reselected_obj init_obj_list = tuple(init_obj_list.values()) elif export_scope == "scene": init_obj_list = tuple(bpy.context.scene.objects) elif export_scope == 'scenes': init_obj_list = tuple(bpy.data.objects) # check extension for EF format and properly assign it to name suffix ef_name_suffix = "" if _get_scs_globals().export_output_type == "EF": ef_name_suffix = ".ef" try: result = _export.batch_export(self, init_obj_list, name_suffix=ef_name_suffix, menu_filepath=filepath) except Exception as e: result = {"CANCELLED"} context.window.cursor_modal_restore() trace_str = traceback.format_exc().replace("\n", "\n\t ") lprint("E Unexpected %r accured during batch export:\n\t %s", (type(e).__name__, trace_str), report_errors=1, report_warnings=1) return result
def execute(self, context): lprint('D Decrease Animation Steps...') scene = context.scene scene.use_preview_range = True action = context.active_object.animation_data.action if action.scs_props.anim_export_step == 1: lprint('E Cannot set lower value for %r than %i!', ('Export Step', 1)) else: active_object = context.active_object scs_root_object = _object_utils.get_scs_root(active_object) # active_scs_animation = scs_root_object.scs_props.active_scs_animation inventory = scs_root_object.scs_object_animation_inventory # animation = inventory[active_scs_animation] # MOVE FRAMES # print_fcurve = 13 for fcurve_i, fcurve in enumerate(action.fcurves): # if fcurve_i == print_fcurve: print('fcurve: %r - %s' % (str(fcurve.data_path), str(fcurve.range()))) for keyframe_i, keyframe in enumerate( fcurve.keyframe_points): # if fcurve_i == print_fcurve: print(' %i keyframe: %s' % (keyframe_i, str(keyframe.co))) # OLD WAY OF INCREASING ACTION LENGTH FROM THE FIRST KEYFRAME # start_frame = fcurve.range()[0] # actual_frame = keyframe.co.x # keyframe.co.x = ((actual_frame - start_frame) / 2) + start_frame # NEW WAY - SIMPLE DOUBLING THE VALUES keyframe.co.x /= 2 fcurve.update() # ## PRINTOUTS # print(' group: %r' % str(fcurve.group.name)) # for channel_i, channel in enumerate(fcurve.group.channels): # print(' %i channel: %s - %s' % (channel_i, str(channel.data_path), str(channel.range()))) # for keyframe_i, keyframe in enumerate(channel.keyframe_points): # print(' %i keyframe: %s' % (keyframe_i, str(keyframe.co))) # INCREASE GLOBAL RANGE scene.frame_start /= 2 scene.frame_end /= 2 # INCREASE PREVIEW RANGE scene.frame_preview_start /= 2 scene.frame_preview_end /= 2 # INCREASE END FRAME NUMBER IN ALL ANIMATIONS THAT USES THE ACTUAL ACTION for anim in inventory: if anim.action == action.name: anim.anim_start /= 2 anim.anim_end /= 2 # INCREASE EXPORT STEP # print('anim_export_step: %s' % str(action.scs_props.anim_export_step)) action.scs_props.anim_export_step /= 2 return {'FINISHED'}
def execute(self, context): lprint('D Export From Menu...') from io_scs_tools import exp as _export from io_scs_tools.utils import object as _object_utils filepath = os.path.dirname(self.filepath) # convert it to None, so export will ignore given menu file path and try to export to other none menu set paths if self.filepath == "": filepath = None export_scope = _get_scs_globals().export_scope init_obj_list = {} if export_scope == "selection": for obj in bpy.context.selected_objects: root = _object_utils.get_scs_root(obj) if root: if root != obj: # add only selected children init_obj_list[obj.name] = obj init_obj_list[root.name] = root else: # add every children if all are unselected children = _object_utils.get_children(obj) local_reselected_objs = [] for child_obj in children: local_reselected_objs.append(child_obj) # if some child is selected this means we won't reselect nothing in this game object if child_obj.select: local_reselected_objs = [] break for reselected_obj in local_reselected_objs: init_obj_list[reselected_obj.name] = reselected_obj init_obj_list = tuple(init_obj_list.values()) elif export_scope == "scene": init_obj_list = tuple(bpy.context.scene.objects) elif export_scope == 'scenes': init_obj_list = tuple(bpy.data.objects) try: result = _export.batch_export(self, init_obj_list, menu_filepath=filepath) except Exception as e: result = {"CANCELLED"} context.window.cursor_modal_restore() import traceback traceback.print_exc() lprint("E Unexpected %r accured during batch export, see stack trace above.", (type(e).__name__,), report_errors=1, report_warnings=1) return result
def __update_look__(self, context): """Hookup function for triggering update look from material in internal module of looks. It should be used on any property which should be saved in exported into looks. :param context: Blender context :type context: bpy.types.Context """ if hasattr(context, "active_object") and hasattr(context.active_object, "active_material") and context.active_object.active_material: scs_root = _object_utils.get_scs_root(context.active_object) if scs_root: _looks.update_look_from_material(scs_root, context.active_object.active_material, "preset_change" in self)
def execute(self, context): lprint('D Export From Menu...') from io_scs_tools import exp as _export from io_scs_tools.utils import object as _object_utils filepath = os.path.dirname(self.filepath) export_type = _get_scs_globals().content_type init_obj_list = {} if export_type == "selection": for obj in bpy.context.selected_objects: root = _object_utils.get_scs_root(obj) if root: if root != obj: # add only selected children init_obj_list[obj.name] = obj init_obj_list[root.name] = root else: # add every children if all are unselected children = _object_utils.get_children(obj) local_reselected_objs = [] for child_obj in children: local_reselected_objs.append(child_obj) # if some child is selected this means we won't reselect nothing in this game object if child_obj.select: local_reselected_objs = [] break for reselected_obj in local_reselected_objs: init_obj_list[reselected_obj.name] = reselected_obj init_obj_list = tuple(init_obj_list.values()) elif export_type == "scene": init_obj_list = tuple(bpy.context.scene.objects) elif export_type == 'scenes': init_obj_list = tuple(bpy.data.objects) try: result = _export.batch_export(self, init_obj_list, export_type != "selection", filepath) except Exception as e: result = {"CANCELLED"} context.window.cursor_modal_restore() import traceback traceback.print_exc() lprint( "E Unexpected %r accured during batch export, see stack trace above.", (type(e).__name__, ), report_errors=1, report_warnings=1) return result
def name_update(self, context): lprint("D SCS Part inventory name update: %s", (self.name, )) # convert name to game engine like name tokenized_name = _name_utils.tokenize_name( self.name, default_name=_PART_consts.default_name) if self.name != tokenized_name: self.name = tokenized_name # always get scs root because we allow editing of parts in any child scs_root_obj = _object_utils.get_scs_root(context.active_object) # if there is more of parts with same name, make postfixed name (this will cause another name update) if len( _inventory.get_indices(scs_root_obj.scs_object_part_inventory, self.name)) == 2: # duplicate i = 1 new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) while _inventory.get_index(scs_root_obj.scs_object_part_inventory, new_name) != -1: new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) i += 1 if new_name != self.name: self.name = new_name if "scs_part_old_name" in self: if scs_root_obj: # fix part name in all children of current root children = _object_utils.get_children(scs_root_obj) for child in children: # fix part name in child with existing old name if child.scs_props.scs_part == self["scs_part_old_name"]: child.scs_props.scs_part = self.name # rename parts in all variants also variant_inventory = scs_root_obj.scs_object_variant_inventory for variant in variant_inventory: for part in variant.parts: if part.name == self["scs_part_old_name"]: part.name = self.name break # backup current name for checking children on next renaming self["scs_part_old_name"] = self.name
def set_active_scs_look(self, value): if value != self.get_active_scs_look(): self["active_scs_look"] = value if bpy.context.active_object: scs_root = _object_utils.get_scs_root(bpy.context.active_object) if scs_root: _looks.apply_active_look(scs_root)
def active_scs_animation_update(self, context): """Update function for Active SCS Animation record on Objects. :param context: Blender Context :type context: bpy.types.Context :rtype: None """ active_object = context.active_object scs_root_object = _object_utils.get_scs_root(active_object) scene = context.scene # GET ARMATURE OBJECT armature = None if active_object.type == 'ARMATURE': armature = active_object else: children = _object_utils.get_children(scs_root_object) for child in children: if child.type == 'ARMATURE': armature = child break scs_object_anim_inventory = scs_root_object.scs_object_animation_inventory active_scs_anim_i = self.active_scs_animation if len(scs_object_anim_inventory) > active_scs_anim_i: active_scs_anim = scs_object_anim_inventory[active_scs_anim_i] start_frame = active_scs_anim.anim_start end_frame = active_scs_anim.anim_end length = active_scs_anim.length # set frame range properly _animation_utils.set_frame_range(scene, start_frame, end_frame) # set action to armature end properly set preview fps action = None if active_scs_anim.action in bpy.data.actions: action = bpy.data.actions[active_scs_anim.action] _animation_utils.set_fps_for_preview(scene, length, start_frame, end_frame) # ensure animation data block to be able to set action if armature.animation_data is None: armature.animation_data_create() armature.animation_data.action = action # set/reset action of current animation else: print('Wrong Animation index %i/%i!' % (active_scs_anim_i, len(scs_object_anim_inventory))) return None
def __create_locator_entries__(data_block, loc_obj): """Creates new entries in LOCATORS and CACHE for given SCS locator object If type of given SCS locator object is not right entry is not created :param data_block: data block from where data should be read :type data_block: bpy_struct :param loc_obj: SCS locator object :type loc_obj: bpy.types.Object :return: True if creation was successfull otherwise False :rtype: bool """ data = data_block[MAIN_DICT] locators_refs = data[REFS][LOCATORS] locators_cache = data[CACHE][LOCATORS] loc_type = loc_obj.scs_props.locator_prefab_type if loc_type in ("Navigation Point", "Map Point", "Trigger Point"): # create LOCATORS and CACHE entry if necessary if loc_obj.name not in locators_refs: if loc_type == "Navigation Point": locators_refs[loc_obj.name] = { TYPE: loc_type, IN_CONNS: [], OUT_CONNS: [] } elif loc_type in ("Map Point", "Trigger Point"): locators_refs[loc_obj.name] = { TYPE: loc_type, CONNS: [] } locators_cache[loc_obj.name] = [ hashlib.md5(str(loc_obj.matrix_world).encode('utf-8')).hexdigest(), loc_obj.scs_props.locator_prefab_np_blinker, loc_obj.scs_props.locator_prefab_np_allowed_veh, loc_obj.scs_props.locator_prefab_np_priority_modifier, loc_obj.scs_props.locator_prefab_mp_custom_color, str(loc_obj.scs_props.locator_prefab_mp_prefab_exit), str(loc_obj.scs_props.locator_prefab_mp_road_size), hashlib.md5(str(_object_utils.get_scs_root(loc_obj)).encode('utf-8')).hexdigest() ] return True else: return False
def __create_locator_entries__(data_block, loc_obj): """Creates new entries in LOCATORS and CACHE for given SCS locator object If type of given SCS locator object is not right entry is not created :param data_block: data block from where data should be read :type data_block: bpy_struct :param loc_obj: SCS locator object :type loc_obj: bpy.types.Object :return: True if creation was successfull otherwise False :rtype: bool """ data = data_block[MAIN_DICT] locators_refs = data[REFS][LOCATORS] locators_cache = data[CACHE][LOCATORS] loc_type = loc_obj.scs_props.locator_prefab_type if loc_type in ("Navigation Point", "Map Point", "Trigger Point"): # create LOCATORS and CACHE entry if necessary if loc_obj.name not in locators_refs: if loc_type == "Navigation Point": locators_refs[loc_obj.name] = { TYPE: loc_type, IN_CONNS: [], OUT_CONNS: [] } elif loc_type in ("Map Point", "Trigger Point"): locators_refs[loc_obj.name] = {TYPE: loc_type, CONNS: []} locators_cache[loc_obj.name] = [ hashlib.md5(str(loc_obj.matrix_world).encode('utf-8')).hexdigest(), loc_obj.scs_props.locator_prefab_np_blinker, loc_obj.scs_props.locator_prefab_np_allowed_veh, loc_obj.scs_props.locator_prefab_np_priority_modifier, loc_obj.scs_props.locator_prefab_mp_custom_color, str(loc_obj.scs_props.locator_prefab_mp_prefab_exit), str(loc_obj.scs_props.locator_prefab_mp_road_size), hashlib.md5( str(_object_utils.get_scs_root(loc_obj)).encode( 'utf-8')).hexdigest() ] return True else: return False
def __recalculate_connection_entry__(data_block, conn_key): """Recalculates connection entry data for given connection key. NOTE: if key doesn't exists error stack trace will be printed and script execution cancelled :param data_block: data block from where data should be read :type data_block: bpy_struct :param conn_key: connection key for connection which should be recalculated :type conn_key: str """ conn_entries = data_block[MAIN_DICT][REFS][CONNECTIONS][ENTRIES] locators_refs = data_block[MAIN_DICT][REFS][LOCATORS] conn_ref = conn_entries[conn_key] loc0_obj = bpy.data.objects[conn_ref[OUT]] loc1_obj = bpy.data.objects[conn_ref[IN]] conn_type = locators_refs[conn_ref[IN]][TYPE] conn_ref[VALID] = _object_utils.get_scs_root( loc0_obj) == _object_utils.get_scs_root(loc1_obj) # recalculate curves depending on type if conn_type == "Navigation Point": conn_ref[DATA] = _collector.collect_nav_curve_data(loc0_obj, loc1_obj) elif conn_type == "Map Point": conn_ref[DATA] = _collector.collect_map_line_data(loc0_obj, loc1_obj) elif conn_type == "Trigger Point": (loc0_avaliable, loc0_conns_count) = __tp_locator_avaliable__(data_block, loc0_obj.name) (loc1_avaliable, loc1_conns_count) = __tp_locator_avaliable__(data_block, loc1_obj.name) conn_ref[DATA] = _collector.collect_trigger_line_data( loc0_obj, loc0_conns_count, loc1_obj, loc1_conns_count)
def draw(self, context): """UI draw function.""" layout = self.layout scene = bpy.context.scene mat = context.material scs_globals = _get_scs_globals() if mat: # PROVISIONAL SHADER PRESET PANEL _draw_preset_shader_panel(layout.box(), mat, scene.scs_props, scs_globals) active_object = context.active_object scs_root_object = _object_utils.get_scs_root(active_object) if active_object and scs_root_object: _shared.draw_scs_looks_panel(layout, scene, active_object, scs_root_object)
def execute(self, context): lprint('D Import Animation Action...') pia_files = [os.path.join(self.directory, file.name) for file in self.files] armature = context.active_object root_object = _object_utils.get_scs_root(armature) imported_count = _import.pia.load(root_object, pia_files, armature) # report warnings and errors if actually imported count differs from number of pia files if imported_count != len(pia_files): lprint("", report_warnings=1, report_errors=1) return {'FINISHED'}
def name_update(self, context): lprint("D SCS Part inventory name update: %s", (self.name,)) # convert name to game engine like name tokenized_name = _name_utils.tokenize_name(self.name, default_name=_PART_consts.default_name) if self.name != tokenized_name: self.name = tokenized_name # always get scs root because we allow editing of parts in any child scs_root_obj = _object_utils.get_scs_root(context.active_object) # if there is more of parts with same name, make postfixed name (this will cause another name update) if len(_inventory.get_indices(scs_root_obj.scs_object_part_inventory, self.name)) == 2: # duplicate i = 1 new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) while _inventory.get_index(scs_root_obj.scs_object_part_inventory, new_name) != -1: new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) i += 1 if new_name != self.name: self.name = new_name if "scs_part_old_name" in self: if scs_root_obj: # fix part name in all children of current root children = _object_utils.get_children(scs_root_obj) for child in children: # fix part name in child with existing old name if child.scs_props.scs_part == self["scs_part_old_name"]: child.scs_props.scs_part = self.name # rename parts in all variants also variant_inventory = scs_root_obj.scs_object_variant_inventory for variant in variant_inventory: for part in variant.parts: if part.name == self["scs_part_old_name"]: part.name = self.name break # backup current name for checking children on next renaming self["scs_part_old_name"] = self.name
def _fix_ex_parent(obj): """Fixes ex parent settings which were caused by re/unparenting. NOTE: ex parent is readed from parent identity property :param obj: SCS Blender object from which ex parent object should be taken :type obj: bpy.types.Object """ # fix children count for ex parent if obj.scs_props.parent_identity in bpy.data.objects: ex_parent_obj = bpy.data.objects[obj.scs_props.parent_identity] ex_parent_obj.scs_cached_num_children = len(ex_parent_obj.children) ex_parent_scs_root = _object_utils.get_scs_root(ex_parent_obj) if ex_parent_scs_root: _looks.clean_unused(ex_parent_scs_root)
def __locator_changed__(data_block, loc_obj): """Checks if locator object is different from current state in cache. In case that is, it returns True and already updates cached locator to current state :param loc_obj: Blender object which is locator :type loc_obj: bpy.types.Object :return: True if object was changed and False if there is no change :rtype: bool """ data = data_block[MAIN_DICT] loc_cached = data[CACHE][LOCATORS][loc_obj.name] changed = False matrix_hash = hashlib.md5(str( loc_obj.matrix_world).encode("utf-8")).hexdigest() if matrix_hash != loc_cached[0]: loc_cached[0] = matrix_hash changed = True if loc_obj.scs_props.locator_prefab_np_blinker != loc_cached[1]: loc_cached[1] = loc_obj.scs_props.locator_prefab_np_blinker changed = True if loc_obj.scs_props.locator_prefab_np_allowed_veh != loc_cached[2]: loc_cached[2] = loc_obj.scs_props.locator_prefab_np_allowed_veh changed = True if loc_obj.scs_props.locator_prefab_mp_custom_color != loc_cached[3]: loc_cached[3] = loc_obj.scs_props.locator_prefab_mp_custom_color changed = True prefab_exit = str(loc_obj.scs_props.locator_prefab_mp_prefab_exit) if prefab_exit != loc_cached[4]: loc_cached[4] = prefab_exit changed = True root_hash = hashlib.md5( str(_object_utils.get_scs_root(loc_obj)).encode("utf-8")).hexdigest() if root_hash != loc_cached[5]: loc_cached[5] = root_hash changed = True data[CACHE][LOCATORS][loc_obj.name] = loc_cached return changed
def execute(self, context): material = context.active_object.active_material if material and hasattr(material.scs_props, self.property_str): scs_root = _object_utils.get_scs_root(context.active_object) if scs_root: altered_looks = _looks.write_through(scs_root, material, self.property_str) if altered_looks > 0: message = "Write through successfully altered %s looks!" % altered_looks else: message = "Nothing to write through." self.report({'INFO'}, message) return {'FINISHED'}
def get_objects(context): if context.scene.scs_props.visibility_tools_scope == "Global": objects = context.scene.objects else: scs_root_object = _object_utils.get_scs_root(context.scene.objects.active) if scs_root_object: objects = _object_utils.get_children(scs_root_object) scs_root_object.hide = False scs_root_object.select = True bpy.context.scene.objects.active = scs_root_object else: # fallback don't do anything objects = [] return objects
def __locator_changed__(data_block, loc_obj): """Checks if locator object is different from current state in cache. In case that is, it returns True and already updates cached locator to current state :param loc_obj: Blender object which is locator :type loc_obj: bpy.types.Object :return: True if object was changed and False if there is no change :rtype: bool """ data = data_block[MAIN_DICT] loc_cached = data[CACHE][LOCATORS][loc_obj.name] changed = False matrix_hash = hashlib.md5(str(loc_obj.matrix_world).encode("utf-8")).hexdigest() if matrix_hash != loc_cached[0]: loc_cached[0] = matrix_hash changed = True if loc_obj.scs_props.locator_prefab_np_blinker != loc_cached[1]: loc_cached[1] = loc_obj.scs_props.locator_prefab_np_blinker changed = True if loc_obj.scs_props.locator_prefab_np_allowed_veh != loc_cached[2]: loc_cached[2] = loc_obj.scs_props.locator_prefab_np_allowed_veh changed = True if loc_obj.scs_props.locator_prefab_mp_custom_color != loc_cached[3]: loc_cached[3] = loc_obj.scs_props.locator_prefab_mp_custom_color changed = True prefab_exit = str(loc_obj.scs_props.locator_prefab_mp_prefab_exit) if prefab_exit != loc_cached[4]: loc_cached[4] = prefab_exit changed = True root_hash = hashlib.md5(str(_object_utils.get_scs_root(loc_obj)).encode("utf-8")).hexdigest() if root_hash != loc_cached[5]: loc_cached[5] = root_hash changed = True data[CACHE][LOCATORS][loc_obj.name] = loc_cached return changed
def get_objects(context): if context.workspace.scs_props.visibility_tools_scope == "Global": objects = context.scene.objects else: scs_root_object = _object_utils.get_scs_root( context.view_layer.objects.active) if scs_root_object: objects = _object_utils.get_children(scs_root_object) _object_utils.hide_set(scs_root_object, False) _object_utils.select_set(scs_root_object, True) bpy.context.view_layer.objects.active = scs_root_object else: # fallback don't do anything objects = [] return objects
def execute(self, context): material = context.active_object.active_material if material and hasattr(material.scs_props, self.property_str): scs_root = _object_utils.get_scs_root(context.active_object) if scs_root: altered_looks = _looks.write_through( scs_root, material, self.property_str) if altered_looks > 0: message = "Write through successfully altered %s looks!" % altered_looks else: message = "Nothing to write through." self.report({'INFO'}, message) return {'FINISHED'}
def get_objects(context): if context.scene.scs_props.visibility_tools_scope == "Global": objects = context.scene.objects else: scs_root_object = _object_utils.get_scs_root( context.scene.objects.active) if scs_root_object: objects = _object_utils.get_children(scs_root_object) scs_root_object.hide = False scs_root_object.select = True bpy.context.scene.objects.active = scs_root_object else: # fallback don't do anything objects = [] return objects
def locator_type_update(self, context): obj = context.object # safety check to ensure we are dealing with proper object # NOTE: if this gets triggered during import, it's very likely that another object # was already set as active. In that case error might occur while accessing scs properties. if not hasattr(obj, "scs_props"): return # PREVIEW MODELS LOADING if obj.scs_props.locator_type in ("Collision", "None"): _preview_models.unload(obj) elif not obj.scs_props.locator_preview_model_present: _preview_models.load(obj) # SCS_PART RESET if not _object_utils.has_part_property(obj): obj.scs_props.scs_part = "" else: scs_root_object = _object_utils.get_scs_root(obj) if scs_root_object: part_inventory = scs_root_object.scs_object_part_inventory # set part index to active or first # NOTE: direct access needed otherwise get function sets invalid index because # active object has still old part value part_index = scs_root_object.scs_props.active_scs_part_get_direct( ) if part_index >= len(part_inventory) or part_index < 0: part_index = 0 obj.scs_props.scs_part = part_inventory[part_index].name else: # if no root assign default obj.scs_props.scs_part = _PART_consts.default_name
def __init__(self): """Shows all layer to be able to alter selection on the whole scene and alter Blender selection the way that: 1. if only child within root is selected -> selects root too 2. if only root is selected -> select all children 3. if root and some children are selected -> don't change selection """ self.layers_visibilities = _view3d_utils.switch_layers_visibility( [], True) self.last_active_obj = bpy.context.active_object self.altered_objs = [] self.altered_objs_visibilities = [] self.not_root_objs = [] for obj in bpy.context.selected_objects: root = _object_utils.get_scs_root(obj) if root: if root != obj: if not root.select: root.select = True self.altered_objs.append(root.name) else: children = _object_utils.get_children(obj) local_reselected_objs = [] for child_obj in children: local_reselected_objs.append(child_obj.name) # if some child is selected this means we won't reselect nothing in this game objecdt if child_obj.select: local_reselected_objs = [] break self.altered_objs.extend(local_reselected_objs) else: obj.select = False self.not_root_objs.append(obj.name) for obj_name in self.altered_objs: self.altered_objs_visibilities.append( bpy.data.objects[obj_name].hide) bpy.data.objects[obj_name].hide = False bpy.data.objects[obj_name].select = True
def execute(self, context): lprint("D " + self.bl_idname, report_errors=-1, report_warnings=-1) if not _path_utils.startswith(self.directory, _get_scs_globals().scs_project_path): message = "E Selected path is not inside SCS Project Base Path! Animation can't be exported to this directory." lprint(message) self.report({'ERROR'}, message[2:]) return {'CANCELLED'} armature = context.active_object scs_root_obj = _object_utils.get_scs_root(armature) anim_inventory = scs_root_obj.scs_object_animation_inventory skeleton_filepath = _path_utils.get_skeleton_relative_filepath(armature, self.directory, scs_root_obj.name) if 0 <= self.index < len(anim_inventory): anim = anim_inventory[self.index] _export.pia.export(scs_root_obj, armature, anim, self.directory, skeleton_filepath) lprint("", report_errors=1, report_warnings=1) return {'FINISHED'}
def __init__(self): """Shows all layer to be able to alter selection on the whole scene and alter Blender selection the way that: 1. if only child within root is selected -> selects root too 2. if only root is selected -> select all children 3. if root and some children are selected -> don't change selection """ self.layers_visibilities = _view3d_utils.switch_layers_visibility([], True) self.last_active_obj = bpy.context.active_object self.altered_objs = [] self.altered_objs_visibilities = [] self.not_root_objs = [] for obj in bpy.context.selected_objects: root = _object_utils.get_scs_root(obj) if root: if root != obj: if not root.select: root.select = True self.altered_objs.append(root.name) else: children = _object_utils.get_children(obj) local_reselected_objs = [] for child_obj in children: local_reselected_objs.append(child_obj.name) # if some child is selected this means we won't reselect nothing in this game objecdt if child_obj.select: local_reselected_objs = [] break self.altered_objs.extend(local_reselected_objs) else: obj.select = False self.not_root_objs.append(obj.name) for obj_name in self.altered_objs: self.altered_objs_visibilities.append(bpy.data.objects[obj_name].hide) bpy.data.objects[obj_name].hide = False bpy.data.objects[obj_name].select = True
def active_scs_part_get(self): """Getting active index in SCS Parts list. On active object change active index of the list is altered with the index of part belonging to new active object. """ if not "active_scs_part_old_active" in self: self["active_scs_part_old_active"] = "" if not "active_scs_part_value" in self: self["active_scs_part_value"] = 0 scs_root_object = _object_utils.get_scs_root(bpy.context.active_object) if scs_root_object and bpy.context.active_object != scs_root_object: # if old active object is different than current # set the value for active part index from it if self["active_scs_part_old_active"] != bpy.context.active_object.name: self["active_scs_part_value"] = _inventory.get_index(scs_root_object.scs_object_part_inventory, bpy.context.active_object.scs_props.scs_part) self["active_scs_part_old_active"] = bpy.context.active_object.name return self["active_scs_part_value"]
def __material_assignement__(obj, new_mat_ids, removed_mat_ids): """Hookup function for material reassignement on object. :param obj: object on which material assignement happend :type obj: bpy.types.Object :param new_mat_ids: ID of newly added materials :type new_mat_ids: iter :param removed_mat_ids: ID of removed materials :type removed_mat_ids: iter """ # create actual new materials list new_mats = [] for mat in bpy.data.materials: curr_mat_id = str(mat.scs_props.id) if curr_mat_id in new_mat_ids: new_mats.append(mat) scs_root = _object_utils.get_scs_root(obj) if scs_root: _looks.add_materials(scs_root, new_mats) if len(removed_mat_ids) > 0: _looks.clean_unused(scs_root)
def name_update(self, context): lprint("D SCS Look inventory name update: %s", (self.name,)) # convert name to game engine like name tokenized_name = _name_utils.tokenize_name(self.name) if self.name != tokenized_name: self.name = tokenized_name # always get scs root to have access to look inventory scs_root_obj = _object_utils.get_scs_root(context.active_object) # if there is more of variants with same name, make postfixed name (this will cause another name update) if len(_inventory.get_indices(scs_root_obj.scs_object_look_inventory, self.name)) == 2: # duplicate i = 1 new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) while _inventory.get_index(scs_root_obj.scs_object_look_inventory, new_name) != -1: new_name = _name_utils.tokenize_name(self.name + "_" + str(i).zfill(2)) i += 1 if new_name != self.name: self.name = new_name
def length_update(self, context): """If the total time for animation is tweaked, FPS value is recalculated to keep the playback speed as close as possible to the resulting playback speed in the game engine. :param context: Blender Context :type context: bpy.types.Context """ active_object = context.active_object if active_object: if active_object.animation_data: action = active_object.animation_data.action if action: scs_root_object = _object_utils.get_scs_root(active_object) if scs_root_object: active_scs_animation = scs_root_object.scs_props.active_scs_animation scs_object_animation_inventory = scs_root_object.scs_object_animation_inventory animation = scs_object_animation_inventory[active_scs_animation] _animation_utils.set_fps_for_preview( context.scene, animation.length, action.scs_props.anim_export_step, animation.anim_start, animation.anim_end, )
def draw(self, context): """UI draw function.""" layout = self.layout scene = context.scene if scene: scs_root_is_reachable = _object_utils.get_scs_root(context.active_object) is not None box = layout.box() row = box.row() row.prop(scene.scs_props, "visibility_tools_scope", expand=True) col = box.column(align=True) col.enabled = scs_root_is_reachable or scene.scs_props.visibility_tools_scope == "Global" row1 = col.row(align=True) row1.alignment = 'CENTER' props = row1.operator('object.switch_model_objects_visibility', text='', icon_value=get_icon(_ICON_TYPES.mesh)) props.view_type = _OP_consts.ViewType.viewonly props = row1.operator('object.switch_shadow_casters_visibility', text='', icon_value=get_icon(_ICON_TYPES.mesh_shadow_caster)) props.view_type = _OP_consts.ViewType.viewonly props = row1.operator('object.switch_glass_objects_visibility', text='', icon_value=get_icon(_ICON_TYPES.mesh_glass)) props.view_type = _OP_consts.ViewType.viewonly props = row1.operator('object.switch_substance_objects_visibility', text='', icon_value=get_icon(_ICON_TYPES.mesh_with_physics)) props.view_type = _OP_consts.ViewType.viewonly row2 = col.row(align=True) row2.alignment = 'CENTER' props = row2.operator('object.switch_all_locators_visibility', text='', icon_value=get_icon(_ICON_TYPES.loc)) props.view_type = _OP_consts.ViewType.viewonly props = row2.operator('object.switch_model_locators_visibility', text='', icon_value=get_icon(_ICON_TYPES.loc_model)) props.view_type = _OP_consts.ViewType.viewonly props = row2.operator('object.switch_prefab_locators_visibility', text='', icon_value=get_icon(_ICON_TYPES.loc_prefab)) props.view_type = _OP_consts.ViewType.viewonly props = row2.operator('object.switch_collision_locators_visibility', text='', icon_value=get_icon(_ICON_TYPES.loc_collider)) props.view_type = _OP_consts.ViewType.viewonly col = box.column(align=True) col.enabled = scs_root_is_reachable or scene.scs_props.visibility_tools_scope == "Global" row2 = col.row(align=True) row2.alignment = 'CENTER' props = row2.operator('object.switch_prefab_nodes_visibility', text='', icon_value=get_icon(_ICON_TYPES.loc_prefab_node)) props.view_type = _OP_consts.ViewType.viewonly props = row2.operator('object.switch_prefab_signs_visibility', text='', icon_value=get_icon(_ICON_TYPES.loc_prefab_sign)) props.view_type = _OP_consts.ViewType.viewonly props = row2.operator('object.switch_prefab_spawns_visibility', text='', icon_value=get_icon(_ICON_TYPES.loc_prefab_spawn)) props.view_type = _OP_consts.ViewType.viewonly props = row2.operator('object.switch_prefab_traffics_visibility', text='', icon_value=get_icon(_ICON_TYPES.loc_prefab_semaphore)) props.view_type = _OP_consts.ViewType.viewonly row2 = col.row(align=True) row2.alignment = 'CENTER' props = row2.operator('object.switch_prefab_navigations_visibility', text='', icon_value=get_icon(_ICONS_consts.Types.loc_prefab_navigation)) props.view_type = _OP_consts.ViewType.viewonly props = row2.operator('object.switch_prefab_maps_visibility', text='', icon_value=get_icon(_ICON_TYPES.loc_prefab_map)) props.view_type = _OP_consts.ViewType.viewonly props = row2.operator('object.switch_prefab_triggers_visibility', text='', icon_value=get_icon(_ICON_TYPES.loc_prefab_trigger)) props.view_type = _OP_consts.ViewType.viewonly row2.operator('object.blank_operator', text='', icon='BLANK1') col = layout.column(align=True) col.enabled = scs_root_is_reachable or scene.scs_props.visibility_tools_scope == "Global" col.label("Current SCS Root:", icon_value=get_icon(_ICONS_consts.Types.scs_root)) col.operator('object.invert_visibility_within_root', text='Invert Visibility') col.operator('object.view_all_objects_within_root', text='View All') col.operator('object.isolate_objects_within_root', text='Isolate')
def execute(self, context): material = context.active_object.active_material if not material or not hasattr(material.scs_props, self.property_str): return {'CANCELLED'} scs_roots = [] active_scs_root = _object_utils.get_scs_root(context.active_object) if active_scs_root: scs_roots.append(active_scs_root) if self.is_ctrl: scs_roots = _object_utils.gather_scs_roots(bpy.data.objects) if self.is_shift or not self.is_ctrl: # WT either on active only or all SCS roots; (Shift + Ctrl) or none altered_looks = 0 for scs_root in scs_roots: altered_looks += _looks.write_through(scs_root, material, self.property_str) if altered_looks > 0: message = "Write through successfully altered %s looks on %s SCS Root Objects!" % (altered_looks, len(scs_roots)) else: message = "Nothing to write through." self.report({'INFO'}, message) elif self.is_ctrl: # special WT only into the same look of other SCS Roots # get current look id look_i = active_scs_root.scs_props.active_scs_look look_name = active_scs_root.scs_object_look_inventory[look_i].name if look_i >= 0 else None if look_name is None: self.report({'WARNING'}, "Aborting as current object is not in any SCS Game Object, parent it to SCS Root first!") return {'CANCELLED'} altered_looks = 0 for scs_root in scs_roots: # ignore active root if scs_root == active_scs_root: continue look_id = -1 # search for same look by name on other scs root for look in scs_root.scs_object_look_inventory: if look.name == look_name: look_id = look.id break if _looks.write_prop_to_look(scs_root, look_id, material, self.property_str): altered_looks += 1 if len(scs_roots) - 1 != altered_looks: self.report({'WARNING'}, "WT partially done, same look was found on %s/%s other SCS Root Objects!" % (altered_looks, len(scs_roots) - 1)) else: self.report({'INFO'}, "Write through altered property on %s other SCS Root Objects!" % altered_looks) return {'FINISHED'}
def object_data_check(scene): # during rendering in Blender active_object doesn't exists so ignore this case if not hasattr(bpy.context, "active_object"): return active_obj = bpy.context.active_object selected_objs = bpy.context.selected_objects # skip persistent check if import is in the process if _get_scs_globals().import_in_progress: return # CHECK FOR DATA CHANGE UPON SELECTION if active_obj: if active_obj.is_updated_data: _Timer.data_updated += 1 if active_obj.is_updated: _Timer.updated += 1 elif len(selected_objs) > 0: # search for any updated object for sel_obj in selected_objs[:2]: if sel_obj.is_updated: _Timer.updated += 1 break if _Timer.updated > 0: _connections_group_wrapper.switch_to_update() # BREAK EXECUTION IF TIMER SAYS SO if not _Timer.can_execute(): return # GET UPDATE STATES updated = _Timer.updated > 0 data_updated = _Timer.data_updated > 0 _Timer.updated = _Timer.data_updated = 0 if not updated: _connections_group_wrapper.switch_to_stall() # NEW/COPY if len(scene.objects) > scene.scs_cached_num_objects: scene.scs_cached_num_objects = len(scene.objects) if len(selected_objs) > 0: # create real selected list # (in case that one of selected objects is parent then children are not in this list) real_sel_objs = selected_objs.copy() for sel_obj in selected_objs: for child in sel_obj.children: if child.select: real_sel_objs.append(child) if real_sel_objs[0].scs_props.object_identity != "": old_objects = [] for obj in real_sel_objs: old_objects.append(bpy.data.objects[obj.scs_props.object_identity]) obj.scs_props.object_identity = obj.name __objects_copy__(old_objects, real_sel_objs) lprint("D ---> COPY of the objects: %s", (len(real_sel_objs),)) return else: for obj in real_sel_objs: obj.scs_props.object_identity = obj.name lprint("D ---> NEW objects: %s", (len(real_sel_objs),)) return # DELETE if len(scene.objects) < scene.scs_cached_num_objects: scene.scs_cached_num_objects = len(scene.objects) unparented_objects = [] for obj in scene.objects: if obj.scs_props.parent_identity != "" and not obj.scs_props.parent_identity in bpy.data.objects: obj.scs_props.parent_identity = "" unparented_objects.append(obj) obj.scs_cached_num_children = len(obj.children) __objects_delete__(unparented_objects) lprint("D ---> DELETE of the objects!") return # if there is no active object then all of rest actions can not be executed at all if active_obj: # RENAME active_obj_identity = active_obj.scs_props.object_identity if active_obj.name != active_obj_identity and active_obj_identity != "": old_name = active_obj_identity new_name = active_obj.name active_obj.scs_props.object_identity = active_obj.name _fix_children(active_obj) __object_rename__(old_name, new_name) if old_name in bpy.data.objects: lprint("D ---> NAME SWITCHING") bpy.data.objects[old_name].scs_props.object_identity = old_name _fix_children(bpy.data.objects[old_name]) # switching names causes invalid connections data so recalculate curves for these objects _connections_group_wrapper.force_recalculate([bpy.data.objects[old_name], bpy.data.objects[new_name]]) lprint("D ---> RENAME of the active object!") return # RE/PARENT active_obj_children_count = len(active_obj.children) if active_obj_children_count > active_obj.scs_cached_num_children: active_obj.scs_cached_num_children = active_obj_children_count for obj in selected_objs: if obj != active_obj: _fix_ex_parent(obj) obj.scs_props.parent_identity = active_obj.name obj.scs_cached_num_children = len(obj.children) __objects_reparent__(active_obj, selected_objs) lprint("D ---> RE/PARENT selected objects to active object %s", (len(selected_objs),)) return if active_obj.parent and active_obj.parent.name != active_obj.scs_props.parent_identity: _fix_ex_parent(active_obj) active_obj.scs_props.parent_identity = active_obj.parent.name __objects_reparent__(active_obj.parent, [active_obj]) lprint("D ---> RE/PARENT active object to some other parent") return # UNPARENT if not active_obj.select and not active_obj.parent and active_obj.scs_props.parent_identity != "": _fix_ex_parent(active_obj) active_obj.scs_props.parent_identity = "" lprint("D ---> UNPARENT active object in panel") return if ((not active_obj.parent and active_obj.scs_props.parent_identity != "") or (len(selected_objs) > 0 and not selected_objs[0].parent and selected_objs[0].scs_props.parent_identity != "")): for obj in selected_objs: _fix_ex_parent(obj) obj.scs_props.parent_identity = "" lprint("D ---> UNPARENT selected objects in 3D view: %s", (len(selected_objs),)) return # ACTIVE SCS ROOT CHANGED active_scs_root = _object_utils.get_scs_root(active_obj) if active_scs_root and scene.scs_cached_active_scs_root != active_scs_root.name: __active_scs_root_change__(active_scs_root) scene.scs_cached_active_scs_root = active_scs_root.name lprint("D ---> ACTIVE SCS ROOT CHANGE: %r", (active_scs_root.name,)) return # MATERIAL ASSIGNEMENT ACTION if data_updated or updated: mats_ids = {} new_mats = {} removed_mats = dict(active_obj.scs_cached_materials_ids) for slot in active_obj.material_slots: if slot.material: curr_id = str(slot.material.scs_props.id) mats_ids[curr_id] = 1 if curr_id not in active_obj.scs_cached_materials_ids: # if not in cached -> it's newly assigned new_mats[curr_id] = 1 elif curr_id in removed_mats: # if in cached remove it from dictionary which stores removed materials del removed_mats[curr_id] if len(new_mats) > 0 or len(removed_mats) > 0: active_obj.scs_cached_materials_ids = mats_ids __material_assignement__(active_obj, new_mats.keys(), removed_mats.keys()) lprint("D ---> MATERIAL ASSIGNEMENT CHANGED") return
def object_data_check(scene): # during rendering in Blender active_object doesn't exists so ignore this case if not hasattr(bpy.context, "active_object"): return active_obj = bpy.context.active_object selected_objs = bpy.context.selected_objects # skip persistent check if import is in the process if _get_scs_globals().import_in_progress: return # CHECK FOR DATA CHANGE UPON SELECTION if active_obj: if active_obj.is_updated_data: _Timer.data_updated += 1 if active_obj.is_updated: _Timer.updated += 1 elif len(selected_objs) > 0: # search for any updated object for sel_obj in selected_objs[:2]: if sel_obj.is_updated: _Timer.updated += 1 break if _Timer.updated > 0: _connections_group_wrapper.switch_to_update() # BREAK EXECUTION IF TIMER SAYS SO if not _Timer.can_execute(): return # GET UPDATE STATES updated = _Timer.updated > 0 data_updated = _Timer.data_updated > 0 _Timer.updated = _Timer.data_updated = 0 if not updated: _connections_group_wrapper.switch_to_stall() # NEW/COPY if len(scene.objects) > scene.scs_cached_num_objects: scene.scs_cached_num_objects = len(scene.objects) if len(selected_objs) > 0: # create real selected list # (in case that one of selected objects is parent then children are not in this list) real_sel_objs = selected_objs.copy() for sel_obj in selected_objs: for child in sel_obj.children: if child.select: real_sel_objs.append(child) if real_sel_objs[0].scs_props.object_identity != "": old_objects = [] for obj in real_sel_objs: old_objects.append( bpy.data.objects[obj.scs_props.object_identity]) obj.scs_props.object_identity = obj.name __objects_copy__(old_objects, real_sel_objs) lprint("D ---> COPY of the objects: %s", (len(real_sel_objs), )) return else: for obj in real_sel_objs: obj.scs_props.object_identity = obj.name lprint("D ---> NEW objects: %s", (len(real_sel_objs), )) return # DELETE if len(scene.objects) < scene.scs_cached_num_objects: scene.scs_cached_num_objects = len(scene.objects) unparented_objects = [] for obj in scene.objects: if obj.scs_props.parent_identity != "" and not obj.scs_props.parent_identity in bpy.data.objects: obj.scs_props.parent_identity = "" unparented_objects.append(obj) obj.scs_cached_num_children = len(obj.children) __objects_delete__(unparented_objects) lprint("D ---> DELETE of the objects!") return # if there is no active object then all of rest actions can not be executed at all if active_obj: # RENAME active_obj_identity = active_obj.scs_props.object_identity if active_obj.name != active_obj_identity and active_obj_identity != "": old_name = active_obj_identity new_name = active_obj.name active_obj.scs_props.object_identity = active_obj.name _fix_children(active_obj) __object_rename__(old_name, new_name) if old_name in bpy.data.objects: lprint("D ---> NAME SWITCHING") bpy.data.objects[old_name].scs_props.object_identity = old_name _fix_children(bpy.data.objects[old_name]) # switching names causes invalid connections data so recalculate curves for these objects _connections_group_wrapper.force_recalculate( [bpy.data.objects[old_name], bpy.data.objects[new_name]]) lprint("D ---> RENAME of the active object!") return # RE/PARENT active_obj_children_count = len(active_obj.children) if active_obj_children_count > active_obj.scs_cached_num_children: active_obj.scs_cached_num_children = active_obj_children_count for obj in selected_objs: if obj != active_obj: _fix_ex_parent(obj) obj.scs_props.parent_identity = active_obj.name obj.scs_cached_num_children = len(obj.children) __objects_reparent__(active_obj, selected_objs) lprint("D ---> RE/PARENT selected objects to active object %s", (len(selected_objs), )) return if active_obj.parent and active_obj.parent.name != active_obj.scs_props.parent_identity: _fix_ex_parent(active_obj) active_obj.scs_props.parent_identity = active_obj.parent.name __objects_reparent__(active_obj.parent, [active_obj]) lprint("D ---> RE/PARENT active object to some other parent") return # UNPARENT if not active_obj.select and not active_obj.parent and active_obj.scs_props.parent_identity != "": _fix_ex_parent(active_obj) active_obj.scs_props.parent_identity = "" lprint("D ---> UNPARENT active object in panel") return if ((not active_obj.parent and active_obj.scs_props.parent_identity != "") or (len(selected_objs) > 0 and not selected_objs[0].parent and selected_objs[0].scs_props.parent_identity != "")): for obj in selected_objs: _fix_ex_parent(obj) obj.scs_props.parent_identity = "" lprint("D ---> UNPARENT selected objects in 3D view: %s", (len(selected_objs), )) return # ACTIVE SCS ROOT CHANGED active_scs_root = _object_utils.get_scs_root(active_obj) if active_scs_root and scene.scs_cached_active_scs_root != active_scs_root.name: __active_scs_root_change__(active_scs_root) scene.scs_cached_active_scs_root = active_scs_root.name lprint("D ---> ACTIVE SCS ROOT CHANGE: %r", (active_scs_root.name, )) return # MATERIAL ASSIGNEMENT ACTION if data_updated or updated: mats_ids = {} new_mats = {} removed_mats = dict(active_obj.scs_cached_materials_ids) for slot in active_obj.material_slots: if slot.material: curr_id = str(slot.material.scs_props.id) mats_ids[curr_id] = 1 if curr_id not in active_obj.scs_cached_materials_ids: # if not in cached -> it's newly assigned new_mats[curr_id] = 1 elif curr_id in removed_mats: # if in cached remove it from dictionary which stores removed materials del removed_mats[curr_id] if len(new_mats) > 0 or len(removed_mats) > 0: active_obj.scs_cached_materials_ids = mats_ids __material_assignement__(active_obj, new_mats.keys(), removed_mats.keys()) lprint("D ---> MATERIAL ASSIGNEMENT CHANGED") return
def execute(self, context): material = context.active_object.active_material if not material or not hasattr(material.scs_props, self.property_str): return {'CANCELLED'} scs_roots = [] active_scs_root = _object_utils.get_scs_root(context.active_object) if active_scs_root: scs_roots.append(active_scs_root) if self.is_ctrl: scs_roots = _object_utils.gather_scs_roots(bpy.data.objects) if self.is_shift or not self.is_ctrl: # WT either on active only or all SCS roots; (Shift + Ctrl) or none altered_looks = 0 for scs_root in scs_roots: altered_looks += _looks.write_through( scs_root, material, self.property_str) if altered_looks > 0: message = "Write through successfully altered %s looks on %s SCS Root Objects!" % ( altered_looks, len(scs_roots)) else: message = "Nothing to write through." self.report({'INFO'}, message) elif self.is_ctrl: # special WT only into the same look of other SCS Roots # get current look id look_i = active_scs_root.scs_props.active_scs_look look_name = active_scs_root.scs_object_look_inventory[ look_i].name if look_i >= 0 else None if look_name is None: self.report({ 'WARNING' }, "Aborting as current object is not in any SCS Game Object, parent it to SCS Root first!" ) return {'CANCELLED'} altered_looks = 0 for scs_root in scs_roots: # ignore active root if scs_root == active_scs_root: continue look_id = -1 # search for same look by name on other scs root for look in scs_root.scs_object_look_inventory: if look.name == look_name: look_id = look.id break if _looks.write_prop_to_look(scs_root, look_id, material, self.property_str): altered_looks += 1 if len(scs_roots) - 1 != altered_looks: self.report({ 'WARNING' }, "WT partially done, same look was found on %s/%s other SCS Root Objects!" % (altered_looks, len(scs_roots) - 1)) else: self.report({ 'INFO' }, "Write through altered property on %s other SCS Root Objects!" % altered_looks) return {'FINISHED'}
def poll(cls, context): active_obj = context.active_object return active_obj and active_obj.type == "ARMATURE" and _object_utils.get_scs_root(active_obj)