From 50b7eb0bce4f95ac439a37f2bf6a4725363bdece Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Mon, 25 Dec 2023 15:04:22 +0800 Subject: [PATCH] fix issues - fix Sector group no-successive issue when saving as nmo - add nong ventilator adder. - use copy.copy to write some code to reduce the calling of get/set_raw_vt_mtl() - keep texture when apply virtools mtl preset. --- bbp_ng/OP_ADDS_component.py | 70 +++++++++++++++++++++++++++++ bbp_ng/OP_EXPORT_virtools.py | 77 ++++++++++++++++++++++++++++++-- bbp_ng/PROP_bme_material.py | 18 ++++---- bbp_ng/PROP_virtools_group.py | 2 +- bbp_ng/PROP_virtools_material.py | 15 +++++-- bbp_ng/UTIL_bme.py | 2 +- bbp_ng/__init__.py | 1 + 7 files changed, 166 insertions(+), 19 deletions(-) diff --git a/bbp_ng/OP_ADDS_component.py b/bbp_ng/OP_ADDS_component.py index 0b6fb47..728e00e 100644 --- a/bbp_ng/OP_ADDS_component.py +++ b/bbp_ng/OP_ADDS_component.py @@ -235,6 +235,74 @@ class BBP_OT_add_nong_extra_point(bpy.types.Operator, ComponentSectorParam, Comp ) ) +class BBP_OT_add_nong_ventilator(bpy.types.Operator, ComponentSectorParam, ComponentCountParam): + """Add Nong Ventilator""" + bl_idname = "bbp.add_nong_ventilator" + bl_label = "Nong Ventilator" + bl_options = {'REGISTER', 'UNDO'} + + ventilator_count_source: bpy.props.EnumProperty( + name = "Ventilator Count Source", + items = ( + ('DEFINED', "Predefined", "Pre-defined ventilator count."), + ('CUSTOM', "Custom", "User specified ventilator count."), + ), + ) + + preset_vetilator_count: bpy.props.EnumProperty( + name = "Preset Count", + description = "Pick preset ventilator count.", + items = ( + # (token, display name, descriptions, icon, index) + ('PAPER', 'Paper', 'The ventilator count (1) can push paper ball up.'), + ('WOOD', 'Wood', 'The ventilator count (6) can push wood ball up.'), + ('STONE', 'Stone', 'The ventilator count (32) can push stone ball up.'), + ), + ) + + def draw(self, context): + layout = self.layout + # draw sector settings + self.draw_component_sector_params(layout) + + # draw count settings by different source + layout.label(text = 'Count') + layout.prop(self, 'ventilator_count_source', expand = True) + if (self.ventilator_count_source == 'CUSTOM'): + self.draw_component_count_params(layout) + else: + layout.prop(self, 'preset_vetilator_count') + + def execute(self, context): + # get ventilator count + count: int = 0 + if (self.ventilator_count_source == 'CUSTOM'): + count = self.general_get_component_count() + else: + match(self.preset_vetilator_count): + case 'PAPER': count = 1 + case 'WOOD': count = 6 + case 'STONE': count = 32 + case _: raise UTIL_functions.BBPException('invalid enumprop data') + + # create elements without any move + _general_create_component( + PROP_ballance_element.BallanceElementType.P_Modul_18, + self.general_get_component_sector(), + count, + lambda _: mathutils.Matrix.Identity(4) + ) + return {'FINISHED'} + + @staticmethod + def draw_blc_menu(layout: bpy.types.UILayout): + layout.operator( + BBP_OT_add_nong_ventilator.bl_idname, + icon_value = UTIL_icons_manager.get_component_icon( + PROP_ballance_element.get_ballance_element_name(PROP_ballance_element.BallanceElementType.P_Modul_18) + ) + ) + #endregion #region Series Comp Adder @@ -412,6 +480,7 @@ class BBP_OT_add_sector_component_pair(bpy.types.Operator, ComponentSectorParam) def register(): bpy.utils.register_class(BBP_OT_add_component) bpy.utils.register_class(BBP_OT_add_nong_extra_point) + bpy.utils.register_class(BBP_OT_add_nong_ventilator) bpy.utils.register_class(BBP_OT_add_tilting_block_series) bpy.utils.register_class(BBP_OT_add_ventilator_series) bpy.utils.register_class(BBP_OT_add_sector_component_pair) @@ -420,5 +489,6 @@ def unregister(): bpy.utils.unregister_class(BBP_OT_add_sector_component_pair) bpy.utils.unregister_class(BBP_OT_add_ventilator_series) bpy.utils.unregister_class(BBP_OT_add_tilting_block_series) + bpy.utils.unregister_class(BBP_OT_add_nong_ventilator) bpy.utils.unregister_class(BBP_OT_add_nong_extra_point) bpy.utils.unregister_class(BBP_OT_add_component) diff --git a/bbp_ng/OP_EXPORT_virtools.py b/bbp_ng/OP_EXPORT_virtools.py index 0b40c1d..8e97a47 100644 --- a/bbp_ng/OP_EXPORT_virtools.py +++ b/bbp_ng/OP_EXPORT_virtools.py @@ -1,6 +1,6 @@ import bpy from bpy_extras.wm_utils.progress_report import ProgressReport -import tempfile, os, typing +import tempfile, os, typing, re from . import PROP_preferences, UTIL_ioport_shared from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture, UTIL_icons_manager from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh, PROP_virtools_texture @@ -164,15 +164,18 @@ def _export_virtools_groups( # start saving progress.enter_substeps(len(obj3d_crets), "Saving Groups") + # create group exporting helper + group_cret_guard: VirtoolsGroupCreationGuard = VirtoolsGroupCreationGuard(writer) + for obj3d, vtobj3d in obj3d_crets: # open group visitor with PROP_virtools_group.VirtoolsGroupsHelper(obj3d) as gp_visitor: for gp_name in gp_visitor.iterate_groups(): - # get group or create new group + # get group or create new group from guard vtgroup: bmap.BMGroup | None = group_cret_map.get(gp_name, None) if vtgroup is None: - vtgroup = writer.create_group() - vtgroup.set_name(gp_name) + # note: no need to set name, guard has set it. + vtgroup = group_cret_guard.create_group(gp_name) group_cret_map[gp_name] = vtgroup # group this object @@ -462,6 +465,72 @@ def _save_virtools_document( progress.step() progress.leave_substeps() +class VirtoolsGroupCreationGuard(): + """ + This class is designed for ensure that the created sector group is successive. + + Due to the design of Ballance, Ballance rely on checking the existance of Sector_XX to get how many sectors this map have. + Thus if there are no component in a sector, it still need to create a empty Sector_XX group, otherwise the game will crash + or be ended at a accident sector. + + This class hook the operation of Virtools group creation and check all Sector group creation. + Create essential group to make Sector_XX group successive. + Thus all group creation in this module should be passed by this class. + """ + cRegexGroupSector: typing.ClassVar[re.Pattern] = re.compile('^Sector_(0[1-8]|[1-9][0-9]{1,2}|9)$') + + @staticmethod + def __get_group_index(group_name: str) -> int | None: + """ + Return the sector index of group name if it is. Otherwise None. + """ + regex_result = VirtoolsGroupCreationGuard.cRegexGroupSector.match(group_name) + if regex_result is not None: + return int(regex_result.group(1)) + else: + return None + + @staticmethod + def __get_group_name(group_index: int) -> str: + """ + Output Sector group name by given sector index + """ + if group_index == 9: + return 'Sector_9' + else: + return f'Sector_{group_index:0>2d}' + + __mWriter: bmap.BMFileWriter + __mSectors: list[bmap.BMGroup] + + def __init__(self, assoc_writer: bmap.BMFileWriter): + self.__mWriter = assoc_writer + self.__mSectors = [] + + def create_group(self, group_name: str) -> bmap.BMGroup: + """ + The hooked group creation function. + + Please note the passed group name argument is just for name checking. + This function will set group name for you, not like BMFileWriter.create_group() operated. + """ + # check whether it is sector group + # note: the return sector index is 1 based, not 0 + sector_idx: int | None = VirtoolsGroupCreationGuard.__get_group_index(group_name) + # if it is regular group, return normal creation + if sector_idx is None: + gp: bmap.BMGroup = self.__mWriter.create_group() + gp.set_name(group_name) + return gp + + # get from sector cahce list + # enlarge sector cache list if it is not fulfilled given sector index + while sector_idx > len(self.__mSectors): + gp: bmap.BMGroup = self.__mWriter.create_group() + self.__mSectors.append(gp) + gp.set_name(self.__get_group_name(len(self.__mSectors))) + # return ordered sector from sector caches + return self.__mSectors[sector_idx - 1] def register() -> None: bpy.utils.register_class(BBP_OT_export_virtools) diff --git a/bbp_ng/PROP_bme_material.py b/bbp_ng/PROP_bme_material.py index 97c4f26..9ca7cb6 100644 --- a/bbp_ng/PROP_bme_material.py +++ b/bbp_ng/PROP_bme_material.py @@ -1,5 +1,5 @@ import bpy -import typing, enum +import typing, enum, copy from . import PROP_virtools_material, PROP_virtools_texture from . import UTIL_ballance_texture, UTIL_functions @@ -91,21 +91,19 @@ def _load_bme_material_preset(mtl: bpy.types.Material, preset_name: str) -> None # get preset first preset: _BMEMaterialPreset = _g_BMEMaterialPresets[preset_name] - # apply raw data first - PROP_virtools_material.set_raw_virtools_material(mtl, preset.mRawMtl) + # get raw mtl and do a shallow copy + # because we will change something later. but do not want to affect preset self. + raw_mtl: PROP_virtools_material.RawVirtoolsMaterial = copy.copy(preset.mRawMtl) # load ballance texture blctex: bpy.types.Image = UTIL_ballance_texture.load_ballance_texture(preset.mTexName) # apply texture props PROP_virtools_texture.set_raw_virtools_texture(blctex, PROP_virtools_texture.get_ballance_texture_preset(preset.mTexName)) + # set loaded texture to shallow copied raw mtl + raw_mtl.mTexture = blctex - # because preset's rawmtl is const, we can not change it directly - # so we need change its texture by triving it again as a new rawmtl - # after we got ballance texture - newrawmtl: PROP_virtools_material.RawVirtoolsMaterial = PROP_virtools_material.get_raw_virtools_material(mtl) - newrawmtl.mTexture = blctex - PROP_virtools_material.set_raw_virtools_material(mtl, newrawmtl) - + # set raw mtl + PROP_virtools_material.set_raw_virtools_material(mtl, raw_mtl) # apply vt mtl to blender mtl PROP_virtools_material.apply_to_blender_material(mtl) diff --git a/bbp_ng/PROP_virtools_group.py b/bbp_ng/PROP_virtools_group.py index f194b73..001d253 100644 --- a/bbp_ng/PROP_virtools_group.py +++ b/bbp_ng/PROP_virtools_group.py @@ -270,7 +270,7 @@ class SharedGroupNameInputProperties(): ) def draw_group_name_input(self, layout: bpy.types.UILayout) -> None: - layout.prop(self, 'group_name_source', expand=True) + layout.prop(self, 'group_name_source', expand = True) if (self.group_name_source == 'CUSTOM'): layout.prop(self, 'custom_group_name') else: diff --git a/bbp_ng/PROP_virtools_material.py b/bbp_ng/PROP_virtools_material.py index a4b5226..79a599f 100644 --- a/bbp_ng/PROP_virtools_material.py +++ b/bbp_ng/PROP_virtools_material.py @@ -1,5 +1,5 @@ import bpy -import typing, enum +import typing, enum, copy from . import UTIL_virtools_types, UTIL_functions, UTIL_ballance_texture, UTIL_file_browser from . import PROP_virtools_texture, PROP_preferences @@ -515,8 +515,17 @@ def get_virtools_material_preset(preset_type: MaterialPresetType) -> MaterialPre return _g_MaterialPresets[preset_type] def preset_virtools_material(mtl: bpy.types.Material, preset_type: MaterialPresetType) -> None: - preset_data: MaterialPresetData = _g_MaterialPresets[preset_type] - set_raw_virtools_material(mtl, preset_data.mData) + # get preset raw mtl member first + # but we need create a shallow copy for it first. + preset_data: RawVirtoolsMaterial = copy.copy(_g_MaterialPresets[preset_type].mData) + # the we get texture setting from now texture + now_data: RawVirtoolsMaterial = get_raw_virtools_material(mtl) + # change preset texture to current texture + # because we do not want to change texture by preset. + # also this is the reason why i need do a shallow copy for preset data + preset_data.mTexture = now_data.mTexture + # apply preset + set_raw_virtools_material(mtl, preset_data) # create preset enum blender helper _g_Helper_MtlPreset: UTIL_functions.EnumPropHelper = UTIL_functions.EnumPropHelper( diff --git a/bbp_ng/UTIL_bme.py b/bbp_ng/UTIL_bme.py index 9e39370..ae754f1 100644 --- a/bbp_ng/UTIL_bme.py +++ b/bbp_ng/UTIL_bme.py @@ -68,7 +68,7 @@ _g_BMEPrototypes: list[dict[str, typing.Any]] = [] _g_BMEPrototypeIndexMap: dict[str, int] = {} # the core loader -for walk_root, walk_dirs, walk_files in os.walk(os.path.join(os.path.dirname(__file__), 'json')): +for walk_root, walk_dirs, walk_files in os.walk(os.path.join(os.path.dirname(__file__), 'jsons')): for relfile in walk_files: if not relfile.endswith('.json'): continue with open(os.path.join(walk_root, relfile), 'r', encoding = 'utf-8') as fp: diff --git a/bbp_ng/__init__.py b/bbp_ng/__init__.py index b2595e9..c625da7 100644 --- a/bbp_ng/__init__.py +++ b/bbp_ng/__init__.py @@ -78,6 +78,7 @@ class BBP_MT_AddComponentsMenu(bpy.types.Menu): layout.separator() layout.label(text="Nong Components") OP_ADDS_component.BBP_OT_add_nong_extra_point.draw_blc_menu(layout) + OP_ADDS_component.BBP_OT_add_nong_ventilator.draw_blc_menu(layout) layout.separator() layout.label(text="Series Components")