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 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
- [ ] 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:
- [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
# 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
# even better, keep a list of dynamic objects per scene , updated only when needed ?
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
collection_name = object.instance_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
"""for object in original_collection.objects:
#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"""
is_dynamic = get_bevy_component_value_by_long_name(original_collection, 'blenvy::save_load::Dynamic') is not None
#print("IS OBJECT DYNAMIC", object, 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
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_list = getattr(propertyGroup, "with_list")
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
field_names = propertyGroup.field_names
layout.enabled = enabled
#print("")
#print("drawing", propertyGroup, nesting, "component_name", rootName)
if is_enum:
@ -31,7 +32,7 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
nested = getattr(nestedPropertyGroup, "nested", False)
#print("nestedPropertyGroup", nestedPropertyGroup, fname, 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
break
elif is_list:
@ -39,12 +40,13 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
list_index = getattr(propertyGroup, "list_index")
box = layout.box()
split = box.split(factor=0.9)
box.enabled = enabled
list_column, buttons_column = (split.column(),split.column())
list_column = list_column.box()
for index, item in enumerate(item_list):
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'
op = row.operator('blenvy.component_list_actions', icon=icon, text="")
op.action = 'SELECT'
@ -100,10 +102,10 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
row = box.row()
row.label(text="Add entry:")
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")
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.action = 'ADD'
@ -119,10 +121,10 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
for index, item in enumerate(keys_list):
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]
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.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.separator()
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:
subrow = layout.row()
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
#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
if component_name == "components_meta":
continue
@ -244,7 +249,9 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
component_invalid = getattr(component_meta, "invalid")
invalid_details = getattr(component_meta, "invalid_details")
component_visible = getattr(component_meta, "visible")
component_internal = component_name in internal_components # internal components are not editable ?
single_field = False
label = f"{component_name}{' (internal)' if component_internal else ''}"
# our whole row
box = layout.box()
@ -252,7 +259,8 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
# "header"
row.alert = component_invalid
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
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 !"
prop_group_location.label(text=error_message)
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 :
row.label(text="details hidden, click on toggle to display")
else:
@ -293,17 +301,18 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
op.component_name = component_name
row.separator()
op = row.operator("blenvy.component_remove", text="", icon="X")
op.component_name = component_name
op.item_name = object_or_collection.name
op.item_type = get_selection_type(object_or_collection)
row.separator()
if not component_internal:
op = row.operator("blenvy.component_remove", text="", icon="X")
op.component_name = component_name
op.item_name = object_or_collection.name
op.item_type = get_selection_type(object_or_collection)
row.separator()
op = row.operator("blenvy.component_copy", text="", icon="COPYDOWN")
op.source_component_name = component_name
op.source_item_name = object_or_collection.name
op.source_item_type = get_selection_type(object_or_collection)
row.separator()
op = row.operator("blenvy.component_copy", text="", icon="COPYDOWN")
op.source_component_name = component_name
op.source_item_name = object_or_collection.name
op.source_item_type = get_selection_type(object_or_collection)
row.separator()
#if not single_field:
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)
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 = []
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
component_settings = blenvy.components
#print("watching schema file for changes")
reloading_registry = False
try:
stamp = os.stat(component_settings.schema_path_full).st_mtime
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
bpy.app.timers.register(lambda: bpy.ops.blenvy.components_registry_reload(), first_interval=1)
component_settings.schemaTimeStamp = stamp
reloading_registry = True
if component_settings.schemaTimeStamp == "":
component_settings.schemaTimeStamp = stamp
except Exception as error:
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
class ComponentsSettings(PropertyGroup):

View File

@ -1,6 +1,7 @@
import os
import posixpath
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):
not_found_materials = []
@ -79,6 +80,7 @@ def get_all_materials(collection_names, library_scenes):
used_material_names = list(set(used_material_names))
return (used_material_names, materials_per_object)
import bpy
def add_material_info_to_objects(materials_per_object, settings):
materials_path = getattr(settings, "materials_path")
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)
# 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
#bpy.ops.blenvy.component_add(target_item_name=object.name, target_item_type="OBJECT", component_type="blenvy::blueprints::materials::MaterialInfos", component_value=component_value)
object['MaterialInfos'] = f"({material_infos})".replace("'","")
component_value = 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)