From 7cf8007b18c6ccc8cd10c5acb55255c633459ca7 Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Tue, 5 Mar 2024 15:55:42 +0100 Subject: [PATCH] feat(bevy_components): added working basics for diagnostics/ finding & replacing invalid & unregistered components * restructured the UI a bit * added basic ui for listing invalid & unregistered components * added boilerplate & basic functionality for component renaming/replacing --- tools/bevy_components/__init__.py | 14 +- tools/bevy_components/components/operators.py | 54 +++++++- tools/bevy_components/registry/operators.py | 38 ++++++ tools/bevy_components/registry/registry.py | 5 +- tools/bevy_components/registry/ui.py | 128 +++++++++++++++++- 5 files changed, 226 insertions(+), 13 deletions(-) diff --git a/tools/bevy_components/__init__.py b/tools/bevy_components/__init__.py index 8f41247..f776af3 100644 --- a/tools/bevy_components/__init__.py +++ b/tools/bevy_components/__init__.py @@ -1,7 +1,7 @@ bl_info = { "name": "bevy_components", "author": "kaosigh", - "version": (0, 4, 0), + "version": (0, 4, 1), "blender": (3, 4, 0), "location": "VIEW_3D", "description": "UI to help create Bevy blueprints and components", @@ -16,11 +16,11 @@ from bpy.props import (StringProperty) from .helpers import load_settings from .blueprints import CreateBlueprintOperator -from .components.operators import CopyComponentOperator, RemoveComponentOperator, GenerateComponent_From_custom_property_Operator, PasteComponentOperator, AddComponentOperator, Toggle_ComponentVisibility +from .components.operators import CopyComponentOperator, OT_rename_component, RemoveComponentOperator, GenerateComponent_From_custom_property_Operator, PasteComponentOperator, AddComponentOperator, RenameHelper, Toggle_ComponentVisibility from .registry.registry import ComponentsRegistry,MissingBevyType -from .registry.operators import (COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_CURRENT, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_CURRENT, ReloadRegistryOperator, OT_OpenFilebrowser) -from .registry.ui import (BEVY_COMPONENTS_PT_Configuration, BEVY_COMPONENTS_PT_MissingTypesPanel, MISSING_TYPES_UL_List) +from .registry.operators import (COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_CURRENT, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_CURRENT, OT_select_component_name_to_replace, OT_select_object, ReloadRegistryOperator, OT_OpenFilebrowser) +from .registry.ui import (BEVY_COMPONENTS_PT_Configuration, BEVY_COMPONENTS_PT_AdvancedToolsPanel, BEVY_COMPONENTS_PT_MissingTypesPanel, MISSING_TYPES_UL_List) from .components.metadata import (ComponentMetadata, ComponentsMeta, ensure_metadata_for_all_objects) from .propGroups.prop_groups import (generate_propertyGroups_for_components) @@ -87,6 +87,8 @@ classes = [ CopyComponentOperator, PasteComponentOperator, RemoveComponentOperator, + OT_rename_component, + RenameHelper, GenerateComponent_From_custom_property_Operator, Toggle_ComponentVisibility, @@ -105,10 +107,14 @@ classes = [ COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_CURRENT, + + OT_select_object, + OT_select_component_name_to_replace, BEVY_COMPONENTS_PT_MainPanel, BEVY_COMPONENTS_PT_ComponentsPanel, BEVY_COMPONENTS_PT_Configuration, + BEVY_COMPONENTS_PT_AdvancedToolsPanel, MISSING_TYPES_UL_List, BEVY_COMPONENTS_PT_MissingTypesPanel, diff --git a/tools/bevy_components/components/operators.py b/tools/bevy_components/components/operators.py index 13ddffc..3be44cd 100644 --- a/tools/bevy_components/components/operators.py +++ b/tools/bevy_components/components/operators.py @@ -90,8 +90,6 @@ class PasteComponentOperator(Operator): return {'FINISHED'} - - class RemoveComponentOperator(Operator): """Delete component from blueprint""" bl_idname = "object.remove_bevy_component" @@ -116,6 +114,58 @@ class RemoveComponentOperator(Operator): return {'FINISHED'} +class RenameHelper(bpy.types.PropertyGroup): + original_name: bpy.props.StringProperty(name="") # type: ignore + new_name: bpy.props.StringProperty(name="") # type: ignore + + #object: bpy.props.PointerProperty(type=bpy.types.Object) + @classmethod + def register(cls): + bpy.types.WindowManager.bevy_component_rename_helper = bpy.props.PointerProperty(type=RenameHelper) + + @classmethod + def unregister(cls): + # remove handlers & co + del bpy.types.WindowManager.bevy_component_rename_helper + +class OT_rename_component(Operator): + """Rename component""" + bl_idname = "object.rename_component" + bl_label = "rename component" + bl_options = {"UNDO"} + + new_name: StringProperty( + name="new_name", + description="new name of component", + ) # type: ignore + + target_objects: bpy.props.StringProperty() # type: ignore + + def execute(self, context): + registry = context.window_manager.components_registry + type_infos = registry.type_infos + settings = context.window_manager.bevy_component_rename_helper + original_name = settings.original_name + new_name = self.new_name + + print("renaming components: original name", settings.original_name, "new_name", self.new_name, "targets", self.target_objects) + target_objects = json.loads(self.target_objects) + if original_name != '' and new_name != '' and len(target_objects) > 0: + for object_name in target_objects: + object = bpy.data.objects[object_name] + if object and original_name in object: + object[new_name] = object[original_name] + remove_component_from_object(object, original_name) + # attempt conversion + long_name = registry.short_names_to_long_names[new_name] + component_definition = type_infos[long_name] + add_component_to_object(object, component_definition, object[new_name]) + # TODO: clear data after we are done + + + return {'FINISHED'} + + class GenerateComponent_From_custom_property_Operator(Operator): """generate components from custom property""" bl_idname = "object.generate_bevy_component_from_custom_property" diff --git a/tools/bevy_components/registry/operators.py b/tools/bevy_components/registry/operators.py index 8abee81..3c6d230 100644 --- a/tools/bevy_components/registry/operators.py +++ b/tools/bevy_components/registry/operators.py @@ -133,3 +133,41 @@ class OT_OpenFilebrowser(Operator, ImportHelper): return {'FINISHED'} + +class OT_select_object(Operator): + """Select object by name""" + bl_idname = "object.select" + bl_label = "Select object" + bl_options = {"UNDO"} + + object_name: StringProperty( + name="object_name", + description="object to select's name ", + ) # type: ignore + + def execute(self, context): + if self.object_name: + object = bpy.data.objects[self.object_name] + scenes_of_object = list(object.users_scene) + if len(scenes_of_object) > 0: + bpy.ops.object.select_all(action='DESELECT') + bpy.context.window.scene = scenes_of_object[0] + object.select_set(True) + bpy.context.view_layer.objects.active = object + return {'FINISHED'} + +class OT_select_component_name_to_replace(Operator): + """Select component name to replace""" + bl_idname = "object.select_component_name_to_replace" + bl_label = "Select object" + bl_options = {"UNDO"} + + component_name: StringProperty( + name="component_name", + description="component name to replace", + ) # type: ignore + + def execute(self, context): + context.window_manager.bevy_component_rename_helper.original_name = self.component_name + return {'FINISHED'} + \ No newline at end of file diff --git a/tools/bevy_components/registry/registry.py b/tools/bevy_components/registry/registry.py index 1299130..20eb14a 100644 --- a/tools/bevy_components/registry/registry.py +++ b/tools/bevy_components/registry/registry.py @@ -241,9 +241,6 @@ class ComponentsRegistry(PropertyGroup): del bpy.types.WindowManager.components_registry - - - def load_schema(self): print("load schema", self) # cleanup previous data if any @@ -352,9 +349,9 @@ class ComponentsRegistry(PropertyGroup): return propGroupName def get_propertyGroupName_from_shortName(self, shortName): - return self.short_names_to_propgroup_names.get(shortName, None) + ########### """ object[component_definition.name] = 0.5 diff --git a/tools/bevy_components/registry/ui.py b/tools/bevy_components/registry/ui.py index 18ff21a..0f9828a 100644 --- a/tools/bevy_components/registry/ui.py +++ b/tools/bevy_components/registry/ui.py @@ -1,9 +1,15 @@ +import json import bpy from bpy_types import (UIList) +from bpy.props import (StringProperty) + +from ..components.operators import OT_rename_component from .operators import( COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_CURRENT, - OT_OpenFilebrowser, ReloadRegistryOperator, + OT_OpenFilebrowser, + OT_select_component_name_to_replace, + OT_select_object, ReloadRegistryOperator, COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_CURRENT) @@ -21,8 +27,7 @@ class BEVY_COMPONENTS_PT_Configuration(bpy.types.Panel): def draw(self, context): layout = self.layout registry = context.window_manager.components_registry - registry_has_type_infos = registry.has_type_infos() - selected_object = context.selected_objects[0] if len(context.selected_objects) > 0 else None + row = layout.row() col = row.column() @@ -43,6 +48,123 @@ class BEVY_COMPONENTS_PT_Configuration(bpy.types.Panel): layout.separator() layout.separator() + +class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel): + """panel listing all the missing bevy types in the schema""" + bl_idname = "BEVY_COMPONENTS_PT_AdvancedToolsPanel" + bl_label = "Advanced tools & configuration" + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = "Bevy Components" + bl_context = "objectmode" + bl_parent_id = "BEVY_COMPONENTS_PT_MainPanel" + bl_options = {'DEFAULT_CLOSED'} + bl_description = "advanced tooling" + + def draw(self, context): + layout = self.layout + registry = bpy.context.window_manager.components_registry + registry_has_type_infos = registry.has_type_infos() + selected_object = context.selected_objects[0] if len(context.selected_objects) > 0 else None + available_components = bpy.context.window_manager.components_list + + row = layout.row() + box= row.box() + box.label(text="Invalid/ unregistered components") + + objects_with_invalid_components = [] + invalid_component_names = [] + + row = layout.row() + col = row.column() + col.label(text="Status") + col = row.column() + col.label(text="Component") + col = row.column() + col.label(text="Object") + col = row.column() + col.label(text="-----") + + for object in bpy.data.objects: # TODO: very inneficent + if "components_meta" in object: + components_metadata = object.components_meta.components + comp_names = [] + for index, component_meta in enumerate(components_metadata): + short_name = component_meta.name + if component_meta.invalid: + row = layout.row() + col = row.column() + col.label(text="Invalid") + col = row.column() + col.label(text=short_name) + col = row.column() + operator = col.operator(OT_select_object.bl_idname, text=object.name) + operator.object_name = object.name + + col = row.column() + operator = col.operator(OT_select_component_name_to_replace.bl_idname, text="select for rename") + operator.component_name = short_name + + if not object.name in objects_with_invalid_components: + objects_with_invalid_components.append(object.name) + + if not short_name in invalid_component_names: + invalid_component_names.append(short_name) + + + comp_names.append(short_name) + + for custom_property in object.keys(): + if custom_property != 'components_meta' and custom_property not in comp_names: + row = layout.row() + col = row.column() + col.label(text="Unregistered") + col = row.column() + col.label(text=custom_property) + col = row.column() + operator = col.operator(OT_select_object.bl_idname, text=object.name) + operator.object_name = object.name + + col = row.column() + operator = col.operator(OT_select_component_name_to_replace.bl_idname, text="select for rename") + operator.component_name = custom_property + + if not object.name in objects_with_invalid_components: + objects_with_invalid_components.append(object.name) + if not short_name in invalid_component_names: + invalid_component_names.append(custom_property) + layout.separator() + layout.separator() + + row = layout.row() + col = row.column() + col.label(text="Original") + col = row.column() + col.label(text="New") + col = row.column() + col.label(text="------") + + row = layout.row() + col = row.column() + box = col.box() + box.label(text=bpy.context.window_manager.bevy_component_rename_helper.original_name) + + col = row.column() + col.prop(available_components, "list", text="") + #row.prop(available_components, "filter",text="Filter") + + col = row.column() + operator = col.operator(OT_rename_component.bl_idname, text="rename") + operator.target_objects = json.dumps(objects_with_invalid_components) + new_name = registry.type_infos[available_components.list]['short_name'] if available_components.list in registry.type_infos else "" + operator.new_name = new_name + + layout.separator() + layout.separator() + row = layout.row() + box= row.box() + box.label(text="Conversions between custom properties and components & vice-versa") + row = layout.row() row.label(text="WARNING ! The following operations will overwrite your existing custom properties if they have matching types on the bevy side !") row.alert = True