def create_locator_empty(name, loc, rot=(0, 0, 0), scale=(1, 1, 1), size=1.0, data_type='Prefab', hookup=None, blend_coords=False): """ Creates an empty object for a Locator. :param name: :param loc: :param rot: :param scale: :param size: :param data_type: :param hookup: :param blend_coords: :return: """ rot_quaternion = None if len(rot) == 4: rot_quaternion = rot rot = (0, 0, 0) if blend_coords: location = loc else: location = _convert.change_to_scs_xyz_coordinates(loc, _get_scs_globals().import_scale) unique_name = _name.get_unique(name, bpy.data.objects, sep=".") locator = bpy.data.objects.new(unique_name, None) locator.empty_display_type = 'PLAIN_AXES' locator.scs_props.object_identity = locator.name # link to active layer and scene and make it active and selected bpy.context.view_layer.active_layer_collection.collection.objects.link(locator) bpy.context.view_layer.objects.active = locator locator.select_set(True) # fix scene objects count to avoid callback of new object bpy.context.scene.scs_cached_num_objects = len(bpy.context.scene.objects) locator.location = location if rot_quaternion: locator.rotation_mode = 'QUATERNION' if blend_coords: locator.rotation_quaternion = rot_quaternion else: locator.rotation_quaternion = _convert.change_to_blender_quaternion_coordinates(rot_quaternion) else: locator.rotation_mode = 'XYZ' locator.rotation_euler = rot locator.scale = scale locator.scs_props.empty_object_type = 'Locator' locator.scs_props.locator_type = data_type if data_type == "Prefab": locator.scs_props.scs_part = "" if hookup: locator.scs_props.locator_model_hookup = hookup return locator
def add_animation_to_root(scs_root_object, animation_name): animation_inventory = scs_root_object.scs_object_animation_inventory # ENSURE, THAT THE NAME IS UNIQUE animation_name = _name.get_unique(animation_name, animation_inventory) # ADD THE ANIMATION animation = animation_inventory.add() animation.name = animation_name return animation
def create_locator_empty(name, loc, rot=(0, 0, 0), scale=(1, 1, 1), size=1.0, data_type='Prefab', hookup=None): """ Creates an empty object for a Locator. :param name: :param loc: :param rot: :param scale: :param size: :param data_type: :param hookup: :return: """ rot_quaternion = None if len(rot) == 4: rot_quaternion = rot rot = (0, 0, 0) bpy.ops.object.empty_add( type='PLAIN_AXES', view_align=False, location=_convert.change_to_scs_xyz_coordinates( loc, _get_scs_globals().import_scale), rotation=rot, ) bpy.context.active_object.name = _name.get_unique(name, bpy.data.objects, sep=".") locator = bpy.context.active_object locator.scs_props.object_identity = locator.name if rot_quaternion: locator.rotation_mode = 'QUATERNION' locator.rotation_quaternion = _convert.change_to_blender_quaternion_coordinates( rot_quaternion) locator.scale = scale locator.scs_props.empty_object_type = 'Locator' locator.scs_props.locator_type = data_type if data_type == "Prefab": locator.scs_props.scs_part = "" if hookup: locator.scs_props.locator_model_hookup = hookup return locator
def add_animation_to_root(scs_root_object, animation_name="Default"): animation_inventory = scs_root_object.scs_object_animation_inventory # ENSURE, THAT THE NAME IS UNIQUE while animation_name in animation_inventory: animation_name = _name.get_unique(animation_name) # ADD THE ANIMATION lprint('I Adding a Animation name: "%s"', animation_name) animation = animation_inventory.add() animation.name = animation_name animation.active = True return animation
def create_locator_empty(name, loc, rot=(0, 0, 0), scale=(1, 1, 1), size=1.0, data_type="Prefab", hookup=None): """ Creates an empty object for a Locator. :param name: :param loc: :param rot: :param scale: :param size: :param data_type: :param hookup: :return: """ rot_quaternion = None if len(rot) == 4: rot_quaternion = rot rot = (0, 0, 0) bpy.ops.object.empty_add( type="PLAIN_AXES", view_align=False, location=_convert.change_to_scs_xyz_coordinates(loc, _get_scs_globals().import_scale), rotation=rot, ) bpy.context.active_object.name = _name.get_unique(name, bpy.data.objects, sep=".") locator = bpy.context.active_object locator.scs_props.object_identity = locator.name if rot_quaternion: locator.rotation_mode = "QUATERNION" locator.rotation_quaternion = _convert.change_to_blender_quaternion_coordinates(rot_quaternion) locator.scale = scale locator.scs_props.empty_object_type = "Locator" locator.scs_props.locator_type = data_type if data_type == "Prefab": locator.scs_props.scs_part = "" if hookup: locator.scs_props.locator_model_hookup = hookup return locator
def make_scs_root_object(context, dialog=False): # FAIRLY SMART SELECTION OF SCS GAME OBJECT CONTENT scs_game_object_content = [] for obj in context.selected_objects: if not obj.parent: scs_game_object_content.append(obj) else: if not obj.parent.select: scs_game_object_content.append(obj) # ADD SCS ROOT OBJECT (EMPTY OBJECT) bpy.ops.object.empty_add( view_align=False, location=context.scene.cursor_location, ) # SET PROPERTIES name = _name.get_unique("game_object", bpy.data.objects) bpy.context.active_object.name = name new_scs_root = bpy.data.objects.get(name) new_scs_root.scs_props.scs_root_object_export_enabled = True new_scs_root.scs_props.empty_object_type = 'SCS_Root' # SET A NEW NAME DIALOG if dialog: bpy.ops.object.add_scs_root_object_dialog_operator('INVOKE_DEFAULT') # PARENT OBJECTS TO SCS ROOT OBJECT part_inventory = new_scs_root.scs_object_part_inventory if len(scs_game_object_content) > 0: bpy.ops.object.select_all(action='DESELECT') new_scs_root_mats = [] # select content object for parenting later for obj in scs_game_object_content: obj.select = True # fix old parent with new children number and cleaned looks if obj.parent: ex_parent_obj = obj.parent obj.parent = None ex_parent_obj.scs_cached_num_children = len( ex_parent_obj.children) ex_parent_scs_root = get_scs_root(ex_parent_obj) if ex_parent_scs_root: _looks.clean_unused(ex_parent_scs_root) obj.scs_props.parent_identity = new_scs_root.name obj.scs_cached_num_children = len(obj.children) for slot in obj.material_slots: if slot.material and slot.material not in new_scs_root_mats: new_scs_root_mats.append(slot.material) _looks.add_materials(new_scs_root, new_scs_root_mats) bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) bpy.ops.object.select_all(action='DESELECT') new_scs_root.select = True # fix children count to prevent persistent to hook up new_scs_root.scs_cached_num_children = len(new_scs_root.children) for part_name in collect_parts_on_root(new_scs_root): _inventory.add_item(part_inventory, part_name) # MAKE DEFAULT PART IF THERE IS NO PARTS if len(part_inventory) == 0: _inventory.add_item(part_inventory, _PART_consts.default_name) return new_scs_root
def _create_scs_root_object(name, loaded_variants, loaded_looks, mats_info, objects, locators, armature): """Creates an 'SCS Root Object' (Empty Object) for currently imported 'SCS Game Object' and parent all import content to it. :param name: :type name: str :param loaded_variants: X :type loaded_variants: list :param loaded_looks: X :type loaded_looks: list :param mats_info: list of material info, one material info consists of list: [ blend_mat_name, mat_effect, original_mat_alias ] :type mats_info: list of list :param objects: X :type objects: list :param locators: X :type locators: list :param armature: Armature Object :type armature: bpy.types.Object :return: SCS Root Object :rtype: bpy.types.Object """ context = bpy.context # MAKE THE 'SCS ROOT OBJECT' NAME UNIQUE name = _name_utils.get_unique(name, bpy.data.objects) # CREATE EMPTY OBJECT & MAKE A PROPER SETTINGS TO THE 'SCS Game Object' OBJECT scs_root_object = bpy.data.objects.new(name, None) bpy.context.view_layer.active_layer_collection.collection.objects.link( scs_root_object) bpy.context.view_layer.objects.active = scs_root_object scs_root_object.scs_props.scs_root_object_export_enabled = True scs_root_object.scs_props.empty_object_type = 'SCS_Root' # print('LOD.pos: %s' % str(scs_root_object.location)) # print('CUR.pos: %s' % str(context.space_data.cursor_location)) # PARENTING bpy.ops.object.select_all(action='DESELECT') if armature: # if armature is present we can specify our game object as animated scs_root_object.scs_props.scs_root_animated = "anim" # print('ARM.pos: %s' % str(armature.location)) armature.select_set(True) armature.scs_props.parent_identity = scs_root_object.name for obj in objects: # print('OBJ.pos: %s' % str(object.location)) obj.select_set(True) obj.scs_props.parent_identity = scs_root_object.name for obj in locators: obj.select_set(True) obj.scs_props.parent_identity = scs_root_object.name bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) bpy.ops.object.parent_clear(type='CLEAR_INVERSE') # LOCATION scs_root_object.location = context.scene.cursor.location # MAKE ONLY 'SCS GAME OBJECT' SELECTED bpy.ops.object.select_all(action='DESELECT') scs_root_object.select_set(True) context.view_layer.objects.active = scs_root_object # MAKE PART RECORD part_inventory = scs_root_object.scs_object_part_inventory parts_dict = _object_utils.collect_parts_on_root(scs_root_object) for part_name in parts_dict: _inventory.add_item(part_inventory, part_name) # MAKE VARIANT RECORD variant_inventory = scs_root_object.scs_object_variant_inventory for variant_i, variant_record in enumerate(loaded_variants): variant_name = variant_record[0] variantparts = variant_record[1] variant = _inventory.add_item(variant_inventory, variant_name) # for every variant create all of the part entries and mark them included properly for part in part_inventory: part = _inventory.add_item(variant.parts, part.name) if part.name in variantparts: part.include = True # cleanup generated terrain points vertex layers by variant for obj in parts_dict[part.name]: if obj.type != "MESH": continue vg_to_delete = [] accepted_vg_nodes = {} for vertex_group in obj.vertex_groups: # ignore any vertex group which isn't from terrain points # (others might come from skinning) if _OP_consts.TerrainPoints.vg_name_prefix not in vertex_group.name: continue # ignore already fixed vertex group if vertex_group.name.startswith( _OP_consts.TerrainPoints.vg_name_prefix): continue # get variant index from first 6 chars -> check PIM importer for more info vg_var_index = int(vertex_group.name[:6]) # ignore other variant vertex groups and add them to delete list if vg_var_index >= 0 and vg_var_index != variant_i: vg_to_delete.append(vertex_group) continue # finally remove variant prefixing name if variant is not defined (-1) # or index matches current one vertex_group.name = vertex_group.name[6:] # log accepted node index for identifying which vertex groups # really have to be deleted accepted_vg_nodes[vertex_group.name[-1]] = 1 # cleanup possible duplicates for the same node # because one object anyway can not have terrain points vertex groups for multiple variants while len(vg_to_delete) > 0 and len(accepted_vg_nodes) > 0: curr_vg = vg_to_delete.pop() # extra caution step where group can be deleted # only if one of vertex groups for this node was accepted if curr_vg.name[-1] in accepted_vg_nodes: obj.vertex_groups.remove(curr_vg) else: part.include = False # MAKE LOOK RECORDS for look_i, look in enumerate(loaded_looks): look_name = look[0] look_mat_settings = look[1] # setup all the materials. NOTE: They should be already created by PIM import. for mat_info in mats_info: mat = bpy.data.materials[mat_info[0]] if mat_info[2] in look_mat_settings: # extract imported shader data material_effect, material_attributes, material_textures, material_section = _get_shader_data( look_mat_settings[mat_info[2]]) # try to find suitable preset (preset_name, preset_section) = _material_utils.find_preset( material_effect, material_textures) # we don't support effect mismatch between looks, even if game works with it, somehow. # most probably imported model is result of third party software, thus let user know and skip look for this material if look_i != 0 and material_effect != mat.scs_props.mat_effect_name: lprint( "E Look %r skipped on material %r, mismatched material effect: %r but should be %r.", (look_name, mat.name, material_effect, mat.scs_props.mat_effect_name)) continue # preset name is found & shader data are compatible with found preset if preset_name and _are_shader_data_compatible( preset_section, material_attributes, material_textures, mat_info[0]): mat.scs_props.active_shader_preset_name = preset_name if preset_section: preset_effect = preset_section.get_prop_value("Effect") mat.scs_props.mat_effect_name = preset_effect if look_i == 0: # apply default shader settings _material_utils.set_shader_data_to_material( mat, preset_section, is_import=True) # reapply settings from material _material_utils.set_shader_data_to_material( mat, material_section, is_import=True, override_back_data=False) lprint("D Using shader preset on material %r.", (mat.name, )) else: print('''NO "preset_section"! (Shouldn't happen!)''') else: # import shader directly from material and mark it as imported mat.scs_props.active_shader_preset_name = "<imported>" _material_utils.set_shader_data_to_material( mat, material_section, is_import=True) lprint( "W Using imported shader on material %r, effect: %r.", (mat.name, mat.scs_props.mat_effect_name)) if look_i == len(loaded_looks) - 1: # delete not needed data on material if "scs_tex_aliases" in mat: del mat["scs_tex_aliases"] # create new look entry on root bpy.ops.object.scs_tools_add_look(look_name=look_name, instant_apply=False) # apply first look after everything is done scs_root_object.scs_props.active_scs_look = 0 # fix scs root children objects count so it won't trigger persistent cycle scs_root_object.scs_cached_num_children = len(scs_root_object.children) return scs_root_object
def make_scs_root_object(context, dialog=False): # FAIRLY SMART SELECTION OF SCS GAME OBJECT CONTENT scs_game_object_content = [] for obj in context.selected_objects: if not obj.parent: scs_game_object_content.append(obj) else: if not obj.parent.select: scs_game_object_content.append(obj) # ADD SCS ROOT OBJECT (EMPTY OBJECT) bpy.ops.object.empty_add(view_align=False, location=context.scene.cursor_location) # SET PROPERTIES name = _name.get_unique("game_object", bpy.data.objects) bpy.context.active_object.name = name new_scs_root = bpy.data.objects.get(name) new_scs_root.scs_props.scs_root_object_export_enabled = True new_scs_root.scs_props.empty_object_type = "SCS_Root" # SET A NEW NAME DIALOG if dialog: bpy.ops.object.add_scs_root_object_dialog_operator("INVOKE_DEFAULT") # PARENT OBJECTS TO SCS ROOT OBJECT part_inventory = new_scs_root.scs_object_part_inventory if len(scs_game_object_content) > 0: bpy.ops.object.select_all(action="DESELECT") new_scs_root_mats = [] # select content object for parenting later for obj in scs_game_object_content: obj.select = True # fix old parent with new children number and cleaned looks if obj.parent: ex_parent_obj = obj.parent obj.parent = None ex_parent_obj.scs_cached_num_children = len(ex_parent_obj.children) ex_parent_scs_root = get_scs_root(ex_parent_obj) if ex_parent_scs_root: _looks.clean_unused(ex_parent_scs_root) obj.scs_props.parent_identity = new_scs_root.name obj.scs_cached_num_children = len(obj.children) for slot in obj.material_slots: if slot.material and slot.material not in new_scs_root_mats: new_scs_root_mats.append(slot.material) _looks.add_materials(new_scs_root, new_scs_root_mats) bpy.ops.object.parent_set(type="OBJECT", keep_transform=False) bpy.ops.object.select_all(action="DESELECT") new_scs_root.select = True # fix children count to prevent persistent to hook up new_scs_root.scs_cached_num_children = len(new_scs_root.children) for part_name in collect_parts_on_root(new_scs_root): _inventory.add_item(part_inventory, part_name) # MAKE DEFAULT PART IF THERE IS NO PARTS if len(part_inventory) == 0: _inventory.add_item(part_inventory, _PART_consts.default_name) return new_scs_root
def _create_scs_root_object(name, loaded_variants, loaded_looks, mats_info, objects, locators, armature): """Creates an 'SCS Root Object' (Empty Object) for currently imported 'SCS Game Object' and parent all import content to it. :param name: :type name: str :param loaded_variants: X :type loaded_variants: list :param loaded_looks: X :type loaded_looks: list :param mats_info: list of material info, one material info consists of list: [ blend_mat_name, mat_effect, original_mat_alias ] :type mats_info: list of list :param objects: X :type objects: list :param locators: X :type locators: list :param armature: Armature Object :type armature: bpy.types.Object :return: SCS Root Object :rtype: bpy.types.Object """ context = bpy.context # MAKE THE 'SCS ROOT OBJECT' NAME UNIQUE name = _name_utils.get_unique(name, bpy.data.objects) # CREATE EMPTY OBJECT bpy.ops.object.empty_add( view_align=False, location=(0.0, 0.0, 0.0), # rotation=rot, ) # , layers=(False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, # False, False)) # MAKE A PROPER SETTINGS TO THE 'SCS Game Object' OBJECT scs_root_object = context.active_object scs_root_object.name = name scs_root_object.scs_props.scs_root_object_export_enabled = True scs_root_object.scs_props.empty_object_type = 'SCS_Root' # print('LOD.pos: %s' % str(scs_root_object.location)) # print('CUR.pos: %s' % str(context.space_data.cursor_location)) # PARENTING if armature: # if armature is present we can specify our game object as animated scs_root_object.scs_props.scs_root_animated = "anim" # print('ARM.pos: %s' % str(armature.location)) bpy.ops.object.select_all(action='DESELECT') armature.select = True bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) armature.scs_props.parent_identity = scs_root_object.name for obj in objects: # print('OBJ.pos: %s' % str(object.location)) bpy.ops.object.select_all(action='DESELECT') obj.select = True bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) obj.scs_props.parent_identity = scs_root_object.name for obj in locators: bpy.ops.object.select_all(action='DESELECT') obj.select = True bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) obj.scs_props.parent_identity = scs_root_object.name # LOCATION scs_root_object.location = context.scene.cursor_location # MAKE ONLY 'SCS GAME OBJECT' SELECTED bpy.ops.object.select_all(action='DESELECT') for obj in bpy.data.objects: obj.select = False scs_root_object.select = True context.scene.objects.active = scs_root_object # MAKE PART RECORD part_inventory = scs_root_object.scs_object_part_inventory parts_dict = _object_utils.collect_parts_on_root(scs_root_object) for part_name in parts_dict: _inventory.add_item(part_inventory, part_name) # MAKE VARIANT RECORD variant_inventory = scs_root_object.scs_object_variant_inventory for variant_i, variant_record in enumerate(loaded_variants): variant_name = variant_record[0] variantparts = variant_record[1] variant = _inventory.add_item(variant_inventory, variant_name) # for every variant create all of the part entries and mark them included properly for part in part_inventory: part = _inventory.add_item(variant.parts, part.name) if part.name in variantparts: part.include = True # cleanup generated terrain points vertex layers by variant for obj in parts_dict[part.name]: if obj.type != "MESH": continue vg_to_delete = [] accepted_vg_nodes = {} for vertex_group in obj.vertex_groups: # ignore any vertex group which isn't from terrain points # (others might come from skinning) if _OP_consts.TerrainPoints.vg_name_prefix not in vertex_group.name: continue # ignore already fixed vertex group if vertex_group.name.startswith(_OP_consts.TerrainPoints.vg_name_prefix): continue # get variant index from first 6 chars -> check PIM importer for more info vg_var_index = int(vertex_group.name[:6]) # ignore other variant vertex groups and add them to delete list if vg_var_index >= 0 and vg_var_index != variant_i: vg_to_delete.append(vertex_group) continue # finally remove variant prefixing name if variant is not defined (-1) # or index matches current one vertex_group.name = vertex_group.name[6:] # log accepted node index for identifying which vertex groups # really have to be deleted accepted_vg_nodes[vertex_group.name[-1]] = 1 # cleanup possible duplicates for the same node # because one object anyway can not have terrain points vertex groups for multiple variants while len(vg_to_delete) > 0 and len(accepted_vg_nodes) > 0: curr_vg = vg_to_delete.pop() # extra caution step where group can be deleted # only if one of vertex groups for this node was accepted if curr_vg.name[-1] in accepted_vg_nodes: obj.vertex_groups.remove(curr_vg) else: part.include = False # MAKE LOOK RECORDS for look_i, look in enumerate(loaded_looks): look_name = look[0] look_mat_settings = look[1] # SETUP ALL THE MATERIALS, NOTE: They should be already created by PIM import. for mat_info in mats_info: mat = bpy.data.materials[mat_info[0]] if mat_info[2] in look_mat_settings: # ASSIGN IMPORTED SHADER DATA material_effect, material_attributes, material_textures, material_section = _get_shader_data(look_mat_settings[mat_info[2]]) # TRY TO FIND SUITABLE PRESET (preset_name, preset_section) = _material_utils.find_preset(material_effect, material_textures) if preset_name: # preset name is found within presets shaders mat.scs_props.active_shader_preset_name = preset_name if preset_section: preset_effect = preset_section.get_prop_value("Effect") mat.scs_props.mat_effect_name = preset_effect if look_i == 0: # apply default shader settings _material_utils.set_shader_data_to_material(mat, preset_section, is_import=True) # reapply settings from material _material_utils.set_shader_data_to_material(mat, material_section, is_import=True, override_back_data=False) lprint("D Using shader preset on material %r.", (mat.name,)) else: print('''NO "preset_section"! (Shouldn't happen!)''') else: # import shader directly from material and mark it as imported mat.scs_props.active_shader_preset_name = "<imported>" _material_utils.set_shader_data_to_material(mat, material_section, is_import=True) lprint("W Using imported shader on material %r, effect: %r.", (mat.name, mat.scs_props.mat_effect_name)) if look_i == len(loaded_looks) - 1: # delete not needed data on material if "scs_tex_aliases" in mat: del mat["scs_tex_aliases"] # CREATE NEW LOOK ENTRY ON ROOT bpy.ops.object.add_scs_look(look_name=look_name, instant_apply=False) # apply first look after everything is done scs_root_object.scs_props.active_scs_look = 0 # fix scs root children objects count so it won't trigger persistent cycle scs_root_object.scs_cached_num_children = len(scs_root_object.children) return scs_root_object
def load(filepath, terrain_points_trans): """Loads given PIP file. :param filepath: complete filepath to PIP file :type filepath: str :param terrain_points_trans: terrain points transitional structure where terrain points shall be saved :type terrain_points_trans: io_scs_tools.imp.transition_structs.terrain_points.TerrainPntsTrans :return: set of operator result and list of created locators :rtype: tuple[set, list[bpy.types.Objects]] """ scs_globals = _get_scs_globals() print("\n************************************") print("** SCS PIP Importer **") print("** (c)2014 SCS Software **") print("************************************\n") # from bpy_extras.image_utils import load_image # UNUSED # scene = context.scene ind = ' ' pip_container = _pix_container.get_data_from_file(filepath, ind) # LOAD HEADER ''' NOTE: skipped for now as no data needs to be readed (format_version, source, f_type, f_name, source_filename, author) = _get_header(pip_container) ''' # LOAD GLOBALS ''' NOTE: skipped for now as no data needs to be readed (node_count, terrain_point_count, nav_curve_count, sign_count, spawn_point_count, traffic_light_count, map_point_count, trigger_point_count, intersection_count) = _get_global(pip_container) ''' # DATA BUILDING nodes_data = {} # terrain_points_data = {} signs_data = {} spawn_points_data = {} traffic_lights_data = {} nav_curves_data = {} map_points_data = [] trigger_points_data = [] locators = [] # node_index = 0 sign_index = 0 spawn_index = 0 tsem_index = 0 map_index = 0 trp_index = 0 for section in pip_container: if section.type == 'Node': ( node_name, node_index, node_position, node_direction, node_input_lanes, node_output_lanes, tp_positions, tp_normals, tp_variants, ) = _get_node_properties(section) if node_name is None: node_name = str('Node_Locator_' + str(node_index)) else: node_name = _name_utils.get_unique(node_name, nodes_data.keys()) node_direction = _curve_utils.set_direction(node_direction) nodes_data[node_name] = (node_index, node_position, node_direction, node_input_lanes, node_output_lanes, tp_positions, tp_normals, tp_variants) elif section.type == 'Sign': (sign_name, sign_position, sign_rotation, sign_model, sign_part) = _get_sign_properties(section) if sign_name is None: sign_name = str('Sign_Locator_' + str(sign_index)) else: sign_name = _name_utils.get_unique(sign_name, signs_data.keys()) signs_data[sign_name] = ( sign_index, sign_position, sign_rotation, sign_model, sign_part, ) sign_index += 1 elif section.type == 'SpawnPoint': (spawn_name, spawn_position, spawn_rotation, spawn_type) = _get_spawn_properties(section) if spawn_name is None: spawn_name = str('Sign_Locator_' + str(spawn_index)) else: spawn_name = _name_utils.get_unique(spawn_name, spawn_points_data.keys()) spawn_points_data[spawn_name] = ( spawn_index, spawn_position, spawn_rotation, spawn_type, ) spawn_index += 1 elif section.type == 'Semaphore': # former "TrafficLight" (tsem_name, tsem_position, tsem_rotation, tsem_type, tsem_id, tsem_intervals, tsem_cycle, tsem_profile) = _get_t_light_properties(section) if tsem_name is None: tsem_name = str('Semaphore_Locator_' + str(tsem_index)) else: tsem_name = _name_utils.get_unique(tsem_name, traffic_lights_data.keys()) if tsem_id is None: tsem_id = -1 traffic_lights_data[tsem_name] = ( tsem_position, tsem_rotation, tsem_type, tsem_id, tsem_intervals, tsem_cycle, tsem_profile, ) tsem_index += 1 elif section.type == 'Curve': (cur_name, cur_index, cur_flags, cur_leads_to_nodes, cur_traffic_rule, cur_sempahore_id, cur_next_curves, cur_prev_curves, cur_length, bezier_start_pos, bezier_start_dir, bezier_start_qua, bezier_end_pos, bezier_end_dir, bezier_end_qua) = _get_curve_properties(section) nav_curves_data[cur_index] = ( cur_name, cur_flags, cur_leads_to_nodes, # not used cur_traffic_rule, cur_sempahore_id, cur_next_curves, cur_prev_curves, cur_length, # not used bezier_start_pos, bezier_start_dir, bezier_start_qua, bezier_end_pos, bezier_end_dir, bezier_end_qua, ) elif section.type == 'MapPoint': (map_indexx, map_name, map_visual_flags, map_nav_flags, map_position, map_neighbours) = _get_map_point_properties(section) if map_indexx is None: map_indexx = map_index if map_name is None: map_name = str("Map_Point_Locator_" + str(map_indexx)) map_points_data.append(( map_name, map_indexx, map_visual_flags, map_nav_flags, map_position, map_neighbours, )) map_index += 1 elif section.type == 'TriggerPoint': (trp_indexx, trp_name, trp_trigger_id, trp_action, trp_range, trp_reset_delay, trp_flags, trp_position, trp_neighbours) = _get_trigger_point_properties(section) if trp_indexx is None: trp_indexx = trp_index if trp_name is None: trp_name = str('Trigger_Locator_' + str(trp_indexx)) trp_range = float(trp_range) trigger_points_data.append(( trp_name, trp_indexx, trp_action, trp_range, trp_reset_delay, trp_flags, trp_position, trp_neighbours, )) trp_index += 1 # print('') # CREATE NODES for name in nodes_data: loc = _create_node_locator( name, nodes_data[name][0], # node_index nodes_data[name][1], # node_position nodes_data[name][2], # node_direction ) tp_pos_l = nodes_data[name][5] tp_nor_l = nodes_data[name][6] tp_var_l = nodes_data[name][7] # save terrain points into transitional structure if len(tp_var_l) > 0: # save per variant block for var_i, var in enumerate(tp_var_l): for i in range(var[0], var[0] + var[1]): terrain_points_trans.add(var_i, nodes_data[name][0], tp_pos_l[i], tp_nor_l[i]) else: for i in range(len(tp_pos_l)): terrain_points_trans.add(-1, nodes_data[name][0], tp_pos_l[i], tp_nor_l[i]) if loc: _print_locator_result(loc, "Node", name) locators.append(loc) # CREATE SIGNS for name in signs_data: # print('signs_data[name]: %s' % str(signs_data[name])) loc = _create_sign_locator(name, signs_data[name][1], signs_data[name][2], signs_data[name][3], signs_data[name][4], scs_globals.scs_sign_model_inventory) if loc: _print_locator_result(loc, "Sign", name) locators.append(loc) # CREATE SPAWN POINTS for name in spawn_points_data: # print('spawn_points_data[name]: %s' % str(spawn_points_data[name])) loc = _create_spawn_locator( name, spawn_points_data[name][1], spawn_points_data[name][2], spawn_points_data[name][3], ) if loc: _print_locator_result(loc, "Spawn Point", name) locators.append(loc) # CREATE TRAFFIC LIGHTS for name in traffic_lights_data: # print('traffic_lights_data[name]: %s' % str(traffic_lights_data[name])) loc = _create_traffic_light_locator( name, traffic_lights_data[name][0], # tsem_position traffic_lights_data[name][1], # tsem_rotation traffic_lights_data[name][2], # tsem_type traffic_lights_data[name][3], # tsem_id traffic_lights_data[name][4], # tsem_intervals traffic_lights_data[name][5], # tsem_cycle traffic_lights_data[name][6], # tsem_profile scs_globals.scs_tsem_profile_inventory) if loc: _print_locator_result(loc, "Traffic Semaphore", name) locators.append(loc) # PREPROCESS CURVE DATA AND CREATE LOCATORS AND DICTIONARY OF CONNECTIONS conns_dict = {} nav_locs_count = 0 for index in nav_curves_data: # assemble variables # cur_name = nav_curves_data[index][0] cur_flags = nav_curves_data[index][1] cur_traffic_rule = nav_curves_data[index][3] cur_sempahore_id = nav_curves_data[index][4] cur_next_curves = nav_curves_data[index][5] cur_prev_curves = nav_curves_data[index][6] bezier_start_pos = nav_curves_data[index][8] bezier_start_dir = bezier_start_qua = bezier_end_dir = bezier_end_qua = None if nav_curves_data[index][9]: bezier_start_dir = _curve_utils.set_direction( nav_curves_data[index][9]) else: bezier_start_qua = nav_curves_data[index][10] bezier_end_pos = nav_curves_data[index][11] if nav_curves_data[index][12]: bezier_end_dir = _curve_utils.set_direction( nav_curves_data[index][12]) else: bezier_end_qua = nav_curves_data[index][13] # check if there is need to create new one or alter the existing curve_locators_to_create = {"start": True, "end": True} for prev_curve_ind in cur_prev_curves: if prev_curve_ind != -1 and prev_curve_ind in conns_dict: if "end" in conns_dict[prev_curve_ind]: curve_locators_to_create["start"] = False # properly create entry for current curve if index in conns_dict: conns_dict[index]["start"] = conns_dict[ prev_curve_ind]["end"] else: conns_dict[index] = { "start": conns_dict[prev_curve_ind]["end"] } break for next_curve_ind in cur_next_curves: if next_curve_ind != -1 and next_curve_ind in conns_dict: if "start" in conns_dict[next_curve_ind]: curve_locators_to_create["end"] = False if index in conns_dict: conns_dict[index]["end"] = conns_dict[next_curve_ind][ "start"] else: conns_dict[index] = { "end": conns_dict[next_curve_ind]["start"] } break # CREATE 2 LOCATORS FOR EACH CURVE IF NEEDED for loc_key in curve_locators_to_create: nav_locator_data = {} nav_locs_count += 1 if loc_key == "start": nav_locator_data['np_name'] = "Nav_Point_" + str( nav_locs_count) nav_locator_data['np_pos'] = bezier_start_pos nav_locator_data['np_dir'] = bezier_start_dir nav_locator_data['np_qua'] = bezier_start_qua elif loc_key == "end": nav_locator_data['np_name'] = "Nav_Point_" + str( nav_locs_count) nav_locator_data['np_pos'] = bezier_end_pos nav_locator_data['np_dir'] = bezier_end_dir nav_locator_data['np_qua'] = bezier_end_qua nav_locator_data['np_low_probab'] = ( cur_flags & _PL_consts.PNCF.LOW_PROBABILITY) != 0 nav_locator_data['np_add_priority'] = ( cur_flags & _PL_consts.PNCF.ADDITIVE_PRIORITY) != 0 nav_locator_data['np_limit_displace'] = ( cur_flags & _PL_consts.PNCF.LIMIT_DISPLACEMENT) != 0 nav_locator_data[ 'np_allowed_veh'] = cur_flags & _PL_consts.PNCF.ALLOWED_VEHICLES_MASK if cur_flags & _PL_consts.PNCF.LEFT_BLINKER != 0: nav_locator_data['np_blinker'] = _PL_consts.PNCF.LEFT_BLINKER elif cur_flags & _PL_consts.PNCF.FORCE_NO_BLINKER != 0: nav_locator_data[ 'np_blinker'] = _PL_consts.PNCF.FORCE_NO_BLINKER elif cur_flags & _PL_consts.PNCF.RIGHT_BLINKER != 0: nav_locator_data['np_blinker'] = _PL_consts.PNCF.RIGHT_BLINKER else: nav_locator_data['np_blinker'] = 0 nav_locator_data['np_prior_modif'] = ( cur_flags & _PL_consts.PNCF.PRIORITY_MASK ) >> _PL_consts.PNCF.PRIORITY_SHIFT nav_locator_data['np_semaphore_id'] = cur_sempahore_id nav_locator_data['np_traffic_rule'] = cur_traffic_rule for node_data in nodes_data.values(): if loc_key == "start": for lane_index, curve_index in enumerate(node_data[3]): if curve_index == index: nav_locator_data['np_boundary'] = 1 + lane_index nav_locator_data['np_boundary_node'] = node_data[0] break else: for lane_index, curve_index in enumerate(node_data[4]): if curve_index == index: nav_locator_data[ 'np_boundary'] = 1 + lane_index + _PL_consts.PREFAB_LANE_COUNT_MAX nav_locator_data['np_boundary_node'] = node_data[0] break # locator already exists just set properties if curve_locators_to_create[loc_key] is False: loc_obj = conns_dict[index][loc_key] _set_nav_locator_props(loc_obj, nav_locator_data, loc_key == "start") continue loc = _create_nav_locator(nav_locator_data) _set_nav_locator_props(loc, nav_locator_data, loc_key == "start") locators.append(loc) if loc: # decide which side to update if loc_key == "start": related_curves = cur_prev_curves related_end = "end" else: related_curves = cur_next_curves related_end = "start" # create or update references for current connection if index not in conns_dict: conns_dict[index] = {loc_key: loc} else: conns_dict[index][loc_key] = loc # update references for prev or next connections for prev_curve_ind in related_curves: if prev_curve_ind != -1: if prev_curve_ind in conns_dict: if related_end not in conns_dict[prev_curve_ind]: conns_dict[prev_curve_ind][related_end] = loc else: conns_dict[prev_curve_ind] = {related_end: loc} # CREATE CONNECTIONS BETWEEN NAVIGATION POINTS for connection in conns_dict.values(): _group_connections_wrapper.create_connection(connection["start"], connection["end"]) # COLLECT MAP POINT CONNECTIONS connections = [] for map_point in map_points_data: # ignore auto generated map points if map_point[3] & _PL_consts.MPNF.NAV_BASE != 0: continue loc_index = map_point[1] for loc_neighbour_index in map_point[5]: if loc_neighbour_index == -1: continue if loc_index == loc_neighbour_index: continue for con in connections: if loc_neighbour_index == con[0] and loc_index == con[1]: continue if loc_neighbour_index == con[1] and loc_index == con[0]: continue connections.append((loc_index, loc_neighbour_index)) # CREATE MAP POINTS mp_locs = {} for map_point in map_points_data: name = map_point[0] # ignore auto generated map points if map_point[3] & _PL_consts.MPNF.NAV_BASE != 0: continue loc = _create_map_locator( map_point[0], map_point[2], map_point[3], map_point[4], ) _print_locator_result(loc, "Map Point", name) if loc: locators.append(loc) mp_locs[map_point[1]] = loc # APPLY MAP POINT CONNECTIONS for connection in connections: # safety check if connection indexes really exists if connection[0] in mp_locs and connection[1] in mp_locs: start_node = mp_locs[connection[0]] end_node = mp_locs[connection[1]] else: lprint('E Map connection out of range: %s', (str(connection), )) continue _group_connections_wrapper.create_connection(start_node, end_node) # COLLECT TRIGGER POINT CONNECTIONS connections = [] for tr_point in trigger_points_data: loc_index = tr_point[1] # print(' name: %s' % tr_point[0]) if len(tr_point[7]) != 2: lprint( 'W Unexpected number of connections (%i) for Trigger Point "%s"!', (len(tr_point[7]), tr_point[0])) for loc_neighbour_index in tr_point[7]: connections.append((loc_index, loc_neighbour_index)) # CREATE TRIGGER POINTS tp_locs = {} for tr_point in trigger_points_data: name = tr_point[0] # print('trigger_points_data[%r]: %s' % (name, str(tr_point))) loc = _create_trigger_locator( tr_point[0], tr_point[2], tr_point[3], tr_point[4], tr_point[5], tr_point[6], scs_globals.scs_trigger_actions_inventory) _print_locator_result(loc, "Trigger Point", name) if loc: locators.append(loc) tp_locs[tr_point[1]] = loc for connection in connections: # safety check if connection indexes really exists if connection[0] in tp_locs and connection[1] in tp_locs: start_node = tp_locs[connection[0]] end_node = tp_locs[connection[1]] else: print('E Trigger connection: %s', (str(connection), )) continue _group_connections_wrapper.create_connection(start_node, end_node) print("************************************") return {'FINISHED'}, locators
def _create_scs_root_object(name, loaded_variants, loaded_looks, mats_info, objects, skinned_objects, locators, armature): """Creates an 'SCS Root Object' (Empty Object) for currently imported 'SCS Game Object' and parent all import content to it. :param name: :type name: str :param loaded_variants: X :type loaded_variants: list :param loaded_looks: X :type loaded_looks: list :param mats_info: list of material info, one material info consists of list: [ blend_mat_name, mat_effect, original_mat_alias ] :type mats_info: list of list :param objects: X :type objects: list :param skinned_objects: X :type skinned_objects: list :param locators: X :type locators: list :param armature: Armature Object :type armature: bpy.types.Object :return: SCS Root Object :rtype: bpy.types.Object """ context = bpy.context # MAKE THE 'SCS ROOT OBJECT' NAME UNIQUE name = _name_utils.get_unique(name, bpy.data.objects) # CREATE EMPTY OBJECT bpy.ops.object.empty_add( view_align=False, location=(0.0, 0.0, 0.0), # rotation=rot, ) # , layers=(False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, # False, False)) # MAKE A PROPER SETTINGS TO THE 'SCS Game Object' OBJECT scs_root_object = context.active_object scs_root_object.name = name scs_root_object.scs_props.scs_root_object_export_enabled = True scs_root_object.scs_props.empty_object_type = 'SCS_Root' # print('LOD.pos: %s' % str(scs_root_object.location)) # print('CUR.pos: %s' % str(context.space_data.cursor_location)) # PARENTING if armature: # if armature is present we can specify our game object as animated scs_root_object.scs_props.scs_root_animated = "anim" # print('ARM.pos: %s' % str(armature.location)) bpy.ops.object.select_all(action='DESELECT') armature.select = True bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) armature.scs_props.parent_identity = scs_root_object.name for obj in objects: if obj not in skinned_objects: # print('OBJ.pos: %s' % str(object.location)) bpy.ops.object.select_all(action='DESELECT') obj.select = True bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) obj.scs_props.parent_identity = scs_root_object.name for obj in locators: bpy.ops.object.select_all(action='DESELECT') obj.select = True bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) obj.scs_props.parent_identity = scs_root_object.name # LOCATION scs_root_object.location = context.scene.cursor_location # MAKE ONLY 'SCS GAME OBJECT' SELECTED bpy.ops.object.select_all(action='DESELECT') for obj in bpy.data.objects: obj.select = False scs_root_object.select = True context.scene.objects.active = scs_root_object # MAKE PART RECORD part_inventory = scs_root_object.scs_object_part_inventory for part_name in _object_utils.collect_parts_on_root(scs_root_object): _inventory.add_item(part_inventory, part_name) # MAKE VARIANT RECORD variant_inventory = scs_root_object.scs_object_variant_inventory for variant_record in loaded_variants: variant_name = variant_record[0] variantparts = variant_record[1] variant = _inventory.add_item(variant_inventory, variant_name) # fore every variant create all of the part entries and mark them included properly for part in part_inventory: part = _inventory.add_item(variant.parts, part.name) if part.name in variantparts: part.include = True else: part.include = False # MAKE LOOK RECORDS # get preset container only once to speed up import process presets_container = _material_utils.get_shader_presets_container(_get_scs_globals().shader_presets_filepath) for look_i, look in enumerate(loaded_looks): look_name = look[0] look_mat_settings = look[1] # SETUP ALL THE MATERIALS, NOTE: They should be already created by PIM import. for mat_info in mats_info: mat = bpy.data.materials[mat_info[0]] if mat_info[2] in look_mat_settings: # ASSIGN IMPORTED SHADER DATA material_effect, material_attributes, material_textures, material_section = _get_shader_data(look_mat_settings[mat_info[2]]) # TRY TO FIND SUITABLE PRESET (preset_index, preset_name, preset_section) = _find_preset(presets_container, material_effect, material_textures) if preset_index: # preset name is found within presets shaders mat.scs_props.active_shader_preset_name = preset_name if preset_section: preset_effect = preset_section.get_prop_value("Effect") mat.scs_props.mat_effect_name = preset_effect if look_i == 0: # apply default shader settings _material_utils.set_shader_data_to_material(mat, preset_section, preset_effect, is_import=True) # reapply settings from material _material_utils.set_shader_data_to_material(mat, material_section, material_effect, is_import=True, override_back_data=False) lprint("I Using shader preset on material %r.", (mat.name,)) else: print('''NO "preset_section"! (Shouldn't happen!)''') else: # import shader directly from material and mark it as imported mat.scs_props.active_shader_preset_name = "<imported>" _material_utils.set_shader_data_to_material(mat, material_section, material_effect, is_import=True) lprint("I Using imported shader on material %r.", (mat.name,)) if look_i == len(loaded_looks) - 1: # delete not needed data on material if "scs_tex_aliases" in mat: del mat["scs_tex_aliases"] # CREATE NEW LOOK ENTRY ON ROOT bpy.ops.object.add_scs_look(look_name=look_name, instant_apply=False) # apply first look after everything is done scs_root_object.scs_props.active_scs_look = 0 # fix scs root children objects count so it won't trigger persistent cycle scs_root_object.scs_cached_num_children = len(scs_root_object.children) return scs_root_object
def _create_scs_root_object(name, loaded_variants, loaded_looks, mats_info, objects, skinned_objects, locators, armature): """Creates an 'SCS Root Object' (Empty Object) for currently imported 'SCS Game Object' and parent all import content to it. :param name: :type name: str :param loaded_variants: X :type loaded_variants: list :param loaded_looks: X :type loaded_looks: list :param mats_info: list of material info, one material info consists of list: [ blend_mat_name, mat_effect, original_mat_alias ] :type mats_info: list of list :param objects: X :type objects: list :param skinned_objects: X :type skinned_objects: list :param locators: X :type locators: list :param armature: Armature Object :type armature: bpy.types.Object :return: SCS Root Object :rtype: bpy.types.Object """ context = bpy.context # MAKE THE 'SCS ROOT OBJECT' NAME UNIQUE name = _name_utils.get_unique(name, bpy.data.objects) # CREATE EMPTY OBJECT bpy.ops.object.empty_add( view_align=False, location=(0.0, 0.0, 0.0), # rotation=rot, ) # , layers=(False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, # False, False)) # MAKE A PROPER SETTINGS TO THE 'SCS Game Object' OBJECT scs_root_object = context.active_object scs_root_object.name = name scs_root_object.scs_props.scs_root_object_export_enabled = True scs_root_object.scs_props.empty_object_type = 'SCS_Root' # print('LOD.pos: %s' % str(scs_root_object.location)) # print('CUR.pos: %s' % str(context.space_data.cursor_location)) # PARENTING if armature: # if armature is present we can specify our game object as animated scs_root_object.scs_props.scs_root_animated = "anim" # print('ARM.pos: %s' % str(armature.location)) bpy.ops.object.select_all(action='DESELECT') armature.select = True bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) armature.scs_props.parent_identity = scs_root_object.name for obj in objects: if obj not in skinned_objects: # print('OBJ.pos: %s' % str(object.location)) bpy.ops.object.select_all(action='DESELECT') obj.select = True bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) obj.scs_props.parent_identity = scs_root_object.name for obj in locators: bpy.ops.object.select_all(action='DESELECT') obj.select = True bpy.ops.object.parent_set(type='OBJECT', keep_transform=False) obj.scs_props.parent_identity = scs_root_object.name # LOCATION scs_root_object.location = context.scene.cursor_location # MAKE ONLY 'SCS GAME OBJECT' SELECTED bpy.ops.object.select_all(action='DESELECT') for obj in bpy.data.objects: obj.select = False scs_root_object.select = True context.scene.objects.active = scs_root_object # MAKE PART RECORD part_inventory = scs_root_object.scs_object_part_inventory for part_name in _object_utils.collect_parts_on_root(scs_root_object): _inventory.add_item(part_inventory, part_name) # MAKE VARIANT RECORD variant_inventory = scs_root_object.scs_object_variant_inventory for variant_record in loaded_variants: variant_name = variant_record[0] variantparts = variant_record[1] variant = _inventory.add_item(variant_inventory, variant_name) # fore every variant create all of the part entries and mark them included properly for part in part_inventory: part = _inventory.add_item(variant.parts, part.name) if part.name in variantparts: part.include = True else: part.include = False # MAKE LOOK RECORDS # get preset container only once to speed up import process presets_container = _material_utils.get_shader_presets_container( _get_scs_globals().shader_presets_filepath) for look_i, look in enumerate(loaded_looks): look_name = look[0] look_mat_settings = look[1] # SETUP ALL THE MATERIALS, NOTE: They should be already created by PIM import. for mat_info in mats_info: mat = bpy.data.materials[mat_info[0]] if mat_info[2] in look_mat_settings: # ASSIGN IMPORTED SHADER DATA material_effect, material_attributes, material_textures, material_section = _get_shader_data( look_mat_settings[mat_info[2]]) # TRY TO FIND SUITABLE PRESET (preset_index, preset_name, preset_section) = _find_preset(presets_container, material_effect, material_textures) if preset_index: # preset name is found within presets shaders mat.scs_props.active_shader_preset_name = preset_name if preset_section: preset_effect = preset_section.get_prop_value("Effect") mat.scs_props.mat_effect_name = preset_effect if look_i == 0: # apply default shader settings _material_utils.set_shader_data_to_material( mat, preset_section, preset_effect, is_import=True) # reapply settings from material _material_utils.set_shader_data_to_material( mat, material_section, material_effect, is_import=True, override_back_data=False) lprint("I Using shader preset on material %r.", (mat.name, )) else: print('''NO "preset_section"! (Shouldn't happen!)''') else: # import shader directly from material and mark it as imported mat.scs_props.active_shader_preset_name = "<imported>" _material_utils.set_shader_data_to_material( mat, material_section, material_effect, is_import=True) lprint("I Using imported shader on material %r.", (mat.name, )) if look_i == len(loaded_looks) - 1: # delete not needed data on material if "scs_tex_aliases" in mat: del mat["scs_tex_aliases"] # CREATE NEW LOOK ENTRY ON ROOT bpy.ops.object.add_scs_look(look_name=look_name, instant_apply=False) # apply first look after everything is done scs_root_object.scs_props.active_scs_look = 0 # fix scs root children objects count so it won't trigger persistent cycle scs_root_object.scs_cached_num_children = len(scs_root_object.children) return scs_root_object