feat(Blenvy:Blender):

* cleanups to dynamic/static object detection
 * filtered out MaterialInfos from "fixable" Components
 * will now attempt to inject actual component for materialInfos
 * if it fails, falls back to previous custom property logic
 * added ability to disable ui for certain components
 * added display of "internal" components
 * internal components such as MaterialInfos are now viewable but disabled (non editable) for more clarity
 * experimenting with auto_reload of registry if missing (wip)
 * minor tweaks
This commit is contained in:
kaosat.dev 2024-08-07 01:32:10 +02:00
parent 0b02a24313
commit bd830e5ad4
5 changed files with 68 additions and 35 deletions

17
TODO.md
View File

@ -259,6 +259,23 @@ Blender side:
- [x] make sure the "add scene" button is not available unless you have actually selected one - [x] make sure the "add scene" button is not available unless you have actually selected one
- [x] make auto export be on by default, however bail out early by detecting if there are any level/blueprint scenes - [x] make auto export be on by default, however bail out early by detecting if there are any level/blueprint scenes
- [x] remove custom components to filter out correctly from exported blueprints list - [x] remove custom components to filter out correctly from exported blueprints list
- [ ] for built in Component types that need to be injected to be used by blueprints,
namely:
- BlueprintInfos (not 100% sure for this one)
- MaterialInfos
- the various scene Components
- BlueprintAssets (although not really needed anymore with the meta files)
- [ ] Inject real components instead of just custom properties
- [ ] add boilerplate to generate real component values from type definitions instead of hacking pseudo ron strings
- [ ] fall back to bevy_components if that fails (missing registry) or just basic custom properties
- [ ] If that fails as well ?
- [ ] auto reload registry if absent/possible
- cannot be done from UI possibly polling with increasing timeout
- bpy.ops.blenvy.components_registry_reload()
- [x] filter out MaterialInfos from list of "fixable components"
Bevy Side: Bevy Side:
- [x] deprecate BlueprintName & BlueprintPath & use BlueprintInfo instead - [x] deprecate BlueprintName & BlueprintPath & use BlueprintInfo instead

View File

@ -3,7 +3,6 @@ import bpy
from ...bevy_components.components.metadata import get_bevy_component_value_by_long_name from ...bevy_components.components.metadata import get_bevy_component_value_by_long_name
# checks if an object is dynamic # checks if an object is dynamic
# TODO: for efficiency, it might make sense to write this flag semi automatically at the root level of the object so we can skip the inner loop
# TODO: we need to recompute these on blueprint changes too # TODO: we need to recompute these on blueprint changes too
# even better, keep a list of dynamic objects per scene , updated only when needed ? # even better, keep a list of dynamic objects per scene , updated only when needed ?
def is_object_dynamic(object): def is_object_dynamic(object):
@ -15,17 +14,9 @@ def is_object_dynamic(object):
# get the name of the collection this is an instance of # get the name of the collection this is an instance of
collection_name = object.instance_collection.name collection_name = object.instance_collection.name
original_collection = bpy.data.collections[collection_name] original_collection = bpy.data.collections[collection_name]
is_dynamic = get_bevy_component_value_by_long_name(original_collection, 'blenvy::save_load::Dynamic') is not None
# scan original collection, look for a 'Dynamic' flag # scan original collection, look for a 'Dynamic' flag
"""for object in original_collection.objects: is_dynamic = get_bevy_component_value_by_long_name(original_collection, 'blenvy::save_load::Dynamic') is not None
#print(" inner", object)
if object.type == 'EMPTY': #and object.name.endswith("components"):
for component_name in object.keys():
#print(" compo", component_name)
if component_name == 'Dynamic':
is_dynamic = True
break"""
#print("IS OBJECT DYNAMIC", object, is_dynamic) #print("IS OBJECT DYNAMIC", object, is_dynamic)
return is_dynamic return is_dynamic

View File

@ -5,7 +5,7 @@ from ..utils import get_selected_item, get_selection_type
from .metadata import do_item_custom_properties_have_missing_metadata, get_bevy_components from .metadata import do_item_custom_properties_have_missing_metadata, get_bevy_components
def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_type="OBJECT", item_name=""): def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_type="OBJECT", item_name="", enabled=True):
is_enum = getattr(propertyGroup, "with_enum") is_enum = getattr(propertyGroup, "with_enum")
is_list = getattr(propertyGroup, "with_list") is_list = getattr(propertyGroup, "with_list")
is_map = getattr(propertyGroup, "with_map") is_map = getattr(propertyGroup, "with_map")
@ -13,6 +13,7 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
# if it is an enum, the first field name is always the list of enum variants, the others are the variants # if it is an enum, the first field name is always the list of enum variants, the others are the variants
field_names = propertyGroup.field_names field_names = propertyGroup.field_names
layout.enabled = enabled
#print("") #print("")
#print("drawing", propertyGroup, nesting, "component_name", rootName) #print("drawing", propertyGroup, nesting, "component_name", rootName)
if is_enum: if is_enum:
@ -31,7 +32,7 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
nested = getattr(nestedPropertyGroup, "nested", False) nested = getattr(nestedPropertyGroup, "nested", False)
#print("nestedPropertyGroup", nestedPropertyGroup, fname, nested) #print("nestedPropertyGroup", nestedPropertyGroup, fname, nested)
if nested: if nested:
draw_propertyGroup(nestedPropertyGroup, subrow.column(), nesting + [fname], rootName, item_type, item_name ) draw_propertyGroup(nestedPropertyGroup, subrow.column(), nesting + [fname], rootName, item_type, item_name, enabled=enabled )
# if an enum variant is not a propertyGroup # if an enum variant is not a propertyGroup
break break
elif is_list: elif is_list:
@ -39,12 +40,13 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
list_index = getattr(propertyGroup, "list_index") list_index = getattr(propertyGroup, "list_index")
box = layout.box() box = layout.box()
split = box.split(factor=0.9) split = box.split(factor=0.9)
box.enabled = enabled
list_column, buttons_column = (split.column(),split.column()) list_column, buttons_column = (split.column(),split.column())
list_column = list_column.box() list_column = list_column.box()
for index, item in enumerate(item_list): for index, item in enumerate(item_list):
row = list_column.row() row = list_column.row()
draw_propertyGroup(item, row, nesting, rootName, item_type) draw_propertyGroup(item, row, nesting, rootName, item_type, enabled=enabled)
icon = 'CHECKBOX_HLT' if list_index == index else 'CHECKBOX_DEHLT' icon = 'CHECKBOX_HLT' if list_index == index else 'CHECKBOX_DEHLT'
op = row.operator('blenvy.component_list_actions', icon=icon, text="") op = row.operator('blenvy.component_list_actions', icon=icon, text="")
op.action = 'SELECT' op.action = 'SELECT'
@ -100,10 +102,10 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
row = box.row() row = box.row()
row.label(text="Add entry:") row.label(text="Add entry:")
keys_setter = getattr(propertyGroup, "keys_setter") keys_setter = getattr(propertyGroup, "keys_setter")
draw_propertyGroup(keys_setter, row, nesting, rootName, item_type, item_name) draw_propertyGroup(keys_setter, row, nesting, rootName, item_type, item_name, enabled=enabled)
values_setter = getattr(propertyGroup, "values_setter") values_setter = getattr(propertyGroup, "values_setter")
draw_propertyGroup(values_setter, row, nesting, rootName, item_type, item_name) draw_propertyGroup(values_setter, row, nesting, rootName, item_type, item_name, enabled=enabled)
op = row.operator('blenvy.component_map_actions', icon='ADD', text="") op = row.operator('blenvy.component_map_actions', icon='ADD', text="")
op.action = 'ADD' op.action = 'ADD'
@ -119,10 +121,10 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
for index, item in enumerate(keys_list): for index, item in enumerate(keys_list):
row = list_column.row() row = list_column.row()
draw_propertyGroup(item, row, nesting, rootName, item_type, item_name) draw_propertyGroup(item, row, nesting, rootName, item_type, item_name, enabled=enabled)
value = values_list[index] value = values_list[index]
draw_propertyGroup(value, row, nesting, rootName, item_type, item_name) draw_propertyGroup(value, row, nesting, rootName, item_type, item_name, enabled=enabled)
op = row.operator('blenvy.component_map_actions', icon='REMOVE', text="") op = row.operator('blenvy.component_map_actions', icon='REMOVE', text="")
op.action = 'REMOVE' op.action = 'REMOVE'
@ -151,7 +153,7 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
layout.label(text=display_name) # this is the name of the field/sub field layout.label(text=display_name) # this is the name of the field/sub field
layout.separator() layout.separator()
subrow = layout.row() subrow = layout.row()
draw_propertyGroup(nestedPropertyGroup, subrow, nesting + [fname], rootName, item_type, item_name ) draw_propertyGroup(nestedPropertyGroup, subrow, nesting + [fname], rootName, item_type, item_name, enabled )
else: else:
subrow = layout.row() subrow = layout.row()
subrow.prop(propertyGroup, fname, text=display_name) subrow.prop(propertyGroup, fname, text=display_name)
@ -233,6 +235,9 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
item_name = object_or_collection.name item_name = object_or_collection.name
#print("components_names", dict(components_bla).keys()) #print("components_names", dict(components_bla).keys())
#FIXME: move out, highly inneficient
internal_components = ['BlueprintInfos', 'blenvy::blueprints::materials::MaterialInfos']
for component_name in sorted(get_bevy_components(object_or_collection)) : # sorted by component name, practical for component_name in sorted(get_bevy_components(object_or_collection)) : # sorted by component name, practical
if component_name == "components_meta": if component_name == "components_meta":
continue continue
@ -244,7 +249,9 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
component_invalid = getattr(component_meta, "invalid") component_invalid = getattr(component_meta, "invalid")
invalid_details = getattr(component_meta, "invalid_details") invalid_details = getattr(component_meta, "invalid_details")
component_visible = getattr(component_meta, "visible") component_visible = getattr(component_meta, "visible")
component_internal = component_name in internal_components # internal components are not editable ?
single_field = False single_field = False
label = f"{component_name}{' (internal)' if component_internal else ''}"
# our whole row # our whole row
box = layout.box() box = layout.box()
@ -252,7 +259,8 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
# "header" # "header"
row.alert = component_invalid row.alert = component_invalid
row.prop(component_meta, "enabled", text="") row.prop(component_meta, "enabled", text="")
row.label(text=component_name) row.label(text=label)
#row.enabled = not component_internal
# we fetch the matching ui property group # we fetch the matching ui property group
root_propertyGroup_name = registry.get_propertyGroupName_from_longName(component_name) root_propertyGroup_name = registry.get_propertyGroupName_from_longName(component_name)
@ -272,7 +280,7 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
error_message = invalid_details if component_invalid else "Missing component UI data, please reload registry !" error_message = invalid_details if component_invalid else "Missing component UI data, please reload registry !"
prop_group_location.label(text=error_message) prop_group_location.label(text=error_message)
else: else:
draw_propertyGroup(propertyGroup, prop_group_location, [root_propertyGroup_name], component_name, item_type, item_name) draw_propertyGroup(propertyGroup, prop_group_location, [root_propertyGroup_name], component_name, item_type, item_name, enabled=not component_internal)
else : else :
row.label(text="details hidden, click on toggle to display") row.label(text="details hidden, click on toggle to display")
else: else:
@ -293,17 +301,18 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
op.component_name = component_name op.component_name = component_name
row.separator() row.separator()
op = row.operator("blenvy.component_remove", text="", icon="X") if not component_internal:
op.component_name = component_name op = row.operator("blenvy.component_remove", text="", icon="X")
op.item_name = object_or_collection.name op.component_name = component_name
op.item_type = get_selection_type(object_or_collection) op.item_name = object_or_collection.name
row.separator() op.item_type = get_selection_type(object_or_collection)
row.separator()
op = row.operator("blenvy.component_copy", text="", icon="COPYDOWN") op = row.operator("blenvy.component_copy", text="", icon="COPYDOWN")
op.source_component_name = component_name op.source_component_name = component_name
op.source_item_name = object_or_collection.name op.source_item_name = object_or_collection.name
op.source_item_type = get_selection_type(object_or_collection) op.source_item_type = get_selection_type(object_or_collection)
row.separator() row.separator()
#if not single_field: #if not single_field:
toggle_icon = "TRIA_DOWN" if component_visible else "TRIA_RIGHT" toggle_icon = "TRIA_DOWN" if component_visible else "TRIA_RIGHT"
@ -388,7 +397,7 @@ class BLENVY_PT_component_tools_panel(bpy.types.Panel):
self.draw_invalid_or_unregistered(layout, status, custom_property, item, item_type) self.draw_invalid_or_unregistered(layout, status, custom_property, item, item_type)
def gather_invalid_item_data(self, item, invalid_component_names, items_with_invalid_components, items_with_original_components, original_name, item_type): def gather_invalid_item_data(self, item, invalid_component_names, items_with_invalid_components, items_with_original_components, original_name, item_type):
blenvy_custom_properties = ['components_meta', 'bevy_components', 'user_assets', 'generated_assets', 'BlueprintAssets', 'export_path' ] # some of our own hard coded custom properties that should be ignored blenvy_custom_properties = ['components_meta', 'bevy_components', 'user_assets', 'generated_assets', 'BlueprintAssets', 'export_path', 'MaterialInfos' ] # some of our own hard coded custom properties that should be ignored
upgreadable_entries = [] upgreadable_entries = []
if "components_meta" in item or hasattr(item, "components_meta"): # FIXME; wrong way of determining if "components_meta" in item or hasattr(item, "components_meta"): # FIXME; wrong way of determining

View File

@ -32,6 +32,7 @@ def watch_schema():
blenvy = bpy.context.window_manager.blenvy blenvy = bpy.context.window_manager.blenvy
component_settings = blenvy.components component_settings = blenvy.components
#print("watching schema file for changes") #print("watching schema file for changes")
reloading_registry = False
try: try:
stamp = os.stat(component_settings.schema_path_full).st_mtime stamp = os.stat(component_settings.schema_path_full).st_mtime
stamp = str(stamp) stamp = str(stamp)
@ -47,11 +48,19 @@ def watch_schema():
# we need to add an additional delay as the file might not have loaded yet # we need to add an additional delay as the file might not have loaded yet
bpy.app.timers.register(lambda: bpy.ops.blenvy.components_registry_reload(), first_interval=1) bpy.app.timers.register(lambda: bpy.ops.blenvy.components_registry_reload(), first_interval=1)
component_settings.schemaTimeStamp = stamp component_settings.schemaTimeStamp = stamp
reloading_registry = True
if component_settings.schemaTimeStamp == "": if component_settings.schemaTimeStamp == "":
component_settings.schemaTimeStamp = stamp component_settings.schemaTimeStamp = stamp
except Exception as error: except Exception as error:
pass pass
# if there is no registry loaded yet, try to load it
"""registry = bpy.context.window_manager.components_registry
if not reloading_registry and len(list(registry.type_infos.keys())) == 0:
print("reload registry here")
bpy.app.timers.register(lambda: bpy.ops.blenvy.components_registry_reload(), first_interval=1)"""
return component_settings.watcher_poll_frequency if component_settings.watcher_enabled else None return component_settings.watcher_poll_frequency if component_settings.watcher_enabled else None
class ComponentsSettings(PropertyGroup): class ComponentsSettings(PropertyGroup):

View File

@ -1,6 +1,7 @@
import os import os
import posixpath import posixpath
from ..core.helpers_collections import (traverse_tree) from ..core.helpers_collections import (traverse_tree)
from ..add_ons.bevy_components.components.metadata import apply_propertyGroup_values_to_item_customProperties_for_component, upsert_bevy_component, get_bevy_component_value_by_long_name
def find_materials_not_on_disk(materials, materials_path_full, extension): def find_materials_not_on_disk(materials, materials_path_full, extension):
not_found_materials = [] not_found_materials = []
@ -79,6 +80,7 @@ def get_all_materials(collection_names, library_scenes):
used_material_names = list(set(used_material_names)) used_material_names = list(set(used_material_names))
return (used_material_names, materials_per_object) return (used_material_names, materials_per_object)
import bpy
def add_material_info_to_objects(materials_per_object, settings): def add_material_info_to_objects(materials_per_object, settings):
materials_path = getattr(settings, "materials_path") materials_path = getattr(settings, "materials_path")
export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb") export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb")
@ -90,8 +92,13 @@ def add_material_info_to_objects(materials_per_object, settings):
material_infos.append(material_info) material_infos.append(material_info)
# problem with using actual components: you NEED the type registry/component infos, so if there is none , or it is not loaded yet, it does not work # problem with using actual components: you NEED the type registry/component infos, so if there is none , or it is not loaded yet, it does not work
# for a few components we could hardcode this # for a few components we could hardcode this
#bpy.ops.blenvy.component_add(target_item_name=object.name, target_item_type="OBJECT", component_type="blenvy::blueprints::materials::MaterialInfos", component_value=component_value) component_value = f"({material_infos})".replace("'","")
object['MaterialInfos'] = f"({material_infos})".replace("'","") try:
bpy.ops.blenvy.component_add(target_item_name=object.name, target_item_type="OBJECT", component_type="blenvy::blueprints::materials::MaterialInfos", component_value=component_value )
except:
object['MaterialInfos'] = f"({material_infos})".replace("'","")
#upsert_bevy_component(object, "blenvy::blueprints::materials::MaterialInfos", f"({material_infos})".replace("'","") )
#apply_propertyGroup_values_to_item_customProperties_for_component(object, "MaterialInfos")
print("adding materialInfos to object", object, "material infos", material_infos) print("adding materialInfos to object", object, "material infos", material_infos)