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.
This commit is contained in:
yyc12345 2023-12-25 15:04:22 +08:00
parent 03e8feac67
commit 50b7eb0bce
7 changed files with 166 additions and 19 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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:

View File

@ -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(

View File

@ -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:

View File

@ -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")