diff --git a/ballance_blender_plugin/NAMES_rename_system.py b/ballance_blender_plugin/NAMES_rename_system.py index fdbe1ae..8dd2b06 100644 --- a/ballance_blender_plugin/NAMES_rename_system.py +++ b/ballance_blender_plugin/NAMES_rename_system.py @@ -11,15 +11,6 @@ class rename_system_props(bpy.types.Operator): ), ) - oper_source: bpy.props.EnumProperty( - name="Operation Target", - description="Rename target", - items=( - ("COLLECTION", "Selected Collections", ""), - ("OBJECTS", "Selected Objects", "") - ), - ) - def invoke(self, context, event): wm = context.window_manager return wm.invoke_props_dialog(self) @@ -28,10 +19,10 @@ class rename_system_props(bpy.types.Operator): layout = self.layout layout.prop(self, "name_standard") -class BALLANCE_OT_rename_via_group(rename_system_props): - """Rename object via Virtools groups""" - bl_idname = "ballance.rename_via_group" - bl_label = "Rename via Group" +class BALLANCE_OT_rename_by_group(rename_system_props): + """Rename object by Virtools groups""" + bl_idname = "ballance.rename_by_group" + bl_label = "Rename by Group" bl_options = {'UNDO'} def execute(self, context): @@ -55,25 +46,69 @@ class BALLANCE_OT_auto_grouping(rename_system_props): def execute(self, context): return {'FINISHED'} -class ObjectBasicType(): +class _ObjectBasicType(): COMPONENT = 0 -class NameInfoHelper(): + FLOOR = 1 + RAIL = 2 + WOOD = 3 + STOPPER = 4 + + DEPTH_CUBE = 5 + + DECORATION = 6 + + LEVEL_START = 7 + LEVEL_END = 8 + CHECKPOINT = 9 + RESETPOINT = 10 + +class _NameStandard(): + YYC = 0 + IMENGYU = 1 + + @staticmethod + def cvt_std_from_str_to_int(std_str): + if std_str == "YYC": + return _NameStandard.YYC + elif std_str == "IMENGYU": + return _NameStandard.IMENGYU + else: + raise Exception("Unknow name standard.") + +class _NameInfoHelper(): def __init__(_basic_type): self.basic_type = _basic_type # extra field notes: - # + # COMPONENT: + # component_type(string) + # sector(int) + # CHECKPOINT, RESETPOINT: + # sector(int)(following Ballance index, checkpoint starts with 1) def _get_selected_objects(oper_source): - if oper_source == 'COLLECTION': - for selected_item in bpy.context.selected_ids: - if selected_item.bl_rna.identifier == "Collection": - tuple(bpy.data.collections[item.name].objects) - elif oper_source == 'OBJECTS': - return bpy.context.selected_objects + return context.view_layer.active_layer_collection.collection.objects + +def _try_get_custom_property(obj, field): + try: + return obj[field] + except: + return None + +def _try_get_sector(group_set): + counter = 0 + last_matched_sector = '' + for i in group_set: + regex_result = UTILS_constants.rename_regexCKGroupSector.match(i) + if regex_result is not None: + last_matched_sector = regex_result.group(1) + counter += 1 + + if counter != 1: + return None else: - raise Exception("Unknow oper_source.") + return last_matched_sector def _get_name_info_from_yyc_name(obj_name): pass @@ -81,15 +116,143 @@ def _get_name_info_from_yyc_name(obj_name): def _get_name_info_from_imengyu_name(obj_name): pass -def _get_name_info_from_group(obj_name): +def _get_name_info_from_group(obj): + group_list = _try_get_custom_property(obj, 'virtools-group') + if group_list is None: + # name it as a decoration + return _NameInfoHelper(_ObjectBasicType.DECORATION) + + group_set = set(group_list) + + # try to filter unique elements first + set_result = UTILS_constants.rename_uniqueComponentsGroupName(group_set) + if len(set_result) == 1: + # get it + gotten_group_name = (list(set_result))[0] + if gotten_group_name == 'PS_Levelstart': + return _NameInfoHelper(_ObjectBasicType.LEVEL_START) + elif gotten_group_name == 'PE_Levelende': + return _NameInfoHelper(_ObjectBasicType.LEVEL_END) + elif gotten_group_name == 'PC_Checkpoints' or gotten_group_name == 'PR_Resetpoints': + # these type's data should be gotten from its name + # use _get_name_info_from_yyc_name to get it + # _get_name_info_from_yyc_name is Ballance-compatible name standard + data = _get_name_info_from_yyc_name(obj.name) + if data.basic_type != _ObjectBasicType.CHECKPOINT and data.basic_type != _ObjectBasicType.RESETPOINT: + # check whether it is checkpoint or resetpoint + # if not, it mean that we got error data from name + # return None instead + return None + # otherwise return data + return data + else: + return None + elif len(set_result) != 0: + # must be a weird grouping, report it + return None + + # distinguish normal elements + set_result = UTILS_constants.rename_normalComponentsGroupName.intersection(group_set) + if len(set_result) == 1: + # get it + # now try get its sector + gotten_elements = (tuple(set_result))[0] + gotten_sector = try_get_sector(group_set) + if gotten_sector is None: + # fail to get sector + return None + + data = _NameInfoHelper(_ObjectBasicType.COMPONENT) + data.component_type = gotten_elements + data.sector = int(gotten_sector) + return data + elif len(set_result) != 0: + # must be a weird grouping, report it + return None + + # distinguish road + if 'Phys_FloorRails' in group_set: + # rail + return _NameInfoHelper(_ObjectBasicType.RAIL) + elif 'Phys_Floors' in group_set: + # distinguish it between Floor and Wood + floor_result =UTILS_constants.rename_floorGroupTester.intersection(group_set) + rail_result = UTILS_constants.rename_woodGroupTester.intersection(group_set) + if len(floor_result) > 0 and len(rail_result) == 0: + return _NameInfoHelper(_ObjectBasicType.FLOOR) + elif len(floor_result) == 0 and len(rail_result) > 0: + return _NameInfoHelper(_ObjectBasicType.WOOD) + else: + return _NameInfoHelper(_ObjectBasicType.FLOOR) + elif 'Phys_FloorStopper' in group_set: + return _NameInfoHelper(_ObjectBasicType.STOPPER) + elif 'DepthTestCubes' in group_set: + return _NameInfoHelper(_ObjectBasicType.DEPTH_CUBE) + + # no matched + return None + +def _set_for_yyc_name(obj, name_info): + basic_type = name_info.basic_type + if basic_type == _ObjectBasicType.COMPONENT: + obj.name = "D_" + + elif basic_type == _ObjectBasicType.LEVEL_START: + obj.name = "PS_FourFlames_01" + elif basic_type == _ObjectBasicType.LEVEL_END: + obj.name = "PE_Balloon_01" + elif basic_type == _ObjectBasicType.RESETPOINT: + obj.name = "PR_Resetpoint_{:0>2d}".format(name_info.sector) + elif basic_type == _ObjectBasicType.CHECKPOINT: + obj.name = "PC_TwoFlames_{:0>2d}".format(name_info.sector) + + elif basic_type == _ObjectBasicType.DEPTH_CUBE: + obj.name = "DepthCubes_" + + elif basic_type == _ObjectBasicType.FLOOR: + obj.name = "A_Floor_" + elif basic_type == _ObjectBasicType.WOOD: + obj.name = "A_Wood_" + elif basic_type == _ObjectBasicType.RAIL: + obj.name = "A_Rail_" + elif basic_type == _ObjectBasicType.STOPPER: + obj.name = "A_Stopper_" + + elif basic_type == _ObjectBasicType.COMPONENT: + obj.name = "{}_{:0>2d}_".format(name_info.component_type, name_info.sector) + + +def _set_for_imengyu_name(obj, name_info): + basic_type = name_info.basic_type + if basic_type == _ObjectBasicType.COMPONENT: + obj.name = "O_" + + elif basic_type == _ObjectBasicType.LEVEL_START: + obj.name = "PS_LevelStart" + elif basic_type == _ObjectBasicType.LEVEL_END: + obj.name = "PE_LevelEnd" + elif basic_type == _ObjectBasicType.RESETPOINT: + obj.name = "PR_ResetPoint:{:d}".format(name_info.sector) + elif basic_type == _ObjectBasicType.CHECKPOINT: + obj.name = "PC_CheckPoint:{:d}".format(name_info.sector + 1) + + elif basic_type == _ObjectBasicType.DEPTH_CUBE: + obj.name = "DepthTestCubes" + + elif basic_type == _ObjectBasicType.FLOOR: + obj.name = "S_Floors" + elif basic_type == _ObjectBasicType.WOOD: + obj.name = "S_FloorWoods" + elif basic_type == _ObjectBasicType.RAIL: + obj.name = "S_FloorRails" + elif basic_type == _ObjectBasicType.STOPPER: + obj.name = "S_FloorStopper" + + elif basic_type == _ObjectBasicType.COMPONENT: + obj.name = "{}:{}:{:d}".format(name_info.component_type, obj.name.repalce(":", "_"), name_info.sector) + + +def _set_for_group(obj, name_info): pass -def _set_for_yyc_name(name_info): - pass - -def _set_for_imengyu_name(name_info): - pass - -def _set_for_group(name_info): - pass diff --git a/ballance_blender_plugin/UTILS_constants.py b/ballance_blender_plugin/UTILS_constants.py index 605e8fc..731f441 100644 --- a/ballance_blender_plugin/UTILS_constants.py +++ b/ballance_blender_plugin/UTILS_constants.py @@ -1,5 +1,6 @@ import json import os +import re bmfile_currentVersion = 14 bmfile_flagUnicode = 0x800 @@ -241,4 +242,53 @@ with open(os.path.join(os.path.dirname(__file__), "json", "DerivedBlock.json")) icons_floor = None icons_floorDict = {} # blenderIcon_elements = None -# blenderIcon_elements_dict = {} \ No newline at end of file +# blenderIcon_elements_dict = {} + +rename_normalComponentsGroupName = set([ + "P_Extra_Life", + "P_Extra_Point", + "P_Trafo_Paper", + "P_Trafo_Stone", + "P_Trafo_Wood", + "P_Ball_Paper", + "P_Ball_Stone", + "P_Ball_Wood", + "P_Box", + "P_Dome", + "P_Modul_01", + "P_Modul_03", + "P_Modul_08", + "P_Modul_17", + "P_Modul_18", + "P_Modul_19", + "P_Modul_25", + "P_Modul_26", + "P_Modul_29", + "P_Modul_30", + "P_Modul_34", + "P_Modul_37", + "P_Modul_41" +]) + +rename_uniqueComponentsGroupName = set([ + "PS_Levelstart", + "PE_Levelende", + "PC_Checkpoints", + "PR_Resetpoints" +]) + +rename_floorGroupTester = set([ + "Sound_HitID_01", + "Sound_RollID_01" +]) + +rename_woodGroupTester = set([ + "Sound_HitID_02", + "Sound_RollID_02" +]) + +# 61 mark: Sector_(0[1-8]|[1-9][0-9]{1,2}|9) may also work +rename_regexCKGroupSector = re.compile('Sector_([123456789]{1}[0123456789]{1}[0123456789]{1}|[123456789]{1}[0123456789]{1}|0[12345678]{1}|9)') +rename_regexYYCTwoFlames +rename_regexYYCResetpoint + diff --git a/ballance_blender_plugin/__init__.py b/ballance_blender_plugin/__init__.py index 86ed204..f5a8791 100644 --- a/ballance_blender_plugin/__init__.py +++ b/ballance_blender_plugin/__init__.py @@ -62,7 +62,7 @@ from . import NAMES_rename_system # menu system class BALLANCE_MT_ThreeDViewerMenu(bpy.types.Menu): - """Ballance related 3D operators""" + """Ballance 3D operators""" bl_idname = "BALLANCE_MT_ThreeDViewerMenu" bl_label = "Ballance" @@ -81,23 +81,9 @@ class BALLANCE_MT_OutlinerMenu(bpy.types.Menu): def draw(self, context): layout = self.layout - layout.label(text="For Collection") - oprt = layout.operator(NAMES_rename_system.BALLANCE_OT_rename_via_group.bl_idname) - oprt.oper_source = 'COLLECTION' + oprt = layout.operator(NAMES_rename_system.BALLANCE_OT_rename_by_group.bl_idname) oprt = layout.operator(NAMES_rename_system.BALLANCE_OT_convert_name.bl_idname) - oprt.oper_source = 'COLLECTION' oprt = layout.operator(NAMES_rename_system.BALLANCE_OT_auto_grouping.bl_idname) - oprt.oper_source = 'COLLECTION' - - layout.separator() - - layout.label(text="For Objects") - oprt = layout.operator(NAMES_rename_system.BALLANCE_OT_rename_via_group.bl_idname) - oprt.oper_source = 'OBJECTS' - oprt = layout.operator(NAMES_rename_system.BALLANCE_OT_convert_name.bl_idname) - oprt.oper_source = 'OBJECTS' - oprt = layout.operator(NAMES_rename_system.BALLANCE_OT_auto_grouping.bl_idname) - oprt.oper_source = 'OBJECTS' class BALLANCE_MT_AddFloorMenu(bpy.types.Menu): """Add Ballance floor""" @@ -143,7 +129,7 @@ classes = ( OBJS_add_floors.BALLANCE_OT_add_floors, BALLANCE_MT_AddFloorMenu, - NAMES_rename_system.BALLANCE_OT_rename_via_group, + NAMES_rename_system.BALLANCE_OT_rename_by_group, NAMES_rename_system.BALLANCE_OT_convert_name, NAMES_rename_system.BALLANCE_OT_auto_grouping, BALLANCE_MT_OutlinerMenu