feat(bevy_components): started migration of data storage to enable

support for components with identical short names
This commit is contained in:
kaosat.dev 2024-04-30 23:50:08 +02:00
parent dc053562bc
commit 185c25f7b2
6 changed files with 75 additions and 25 deletions

View File

@ -12,14 +12,26 @@ class ComponentDefinitionsList(bpy.types.PropertyGroup):
items = []
type_infos = context.window_manager.components_registry.type_infos
short_names = context.window_manager.components_registry.short_names_to_long_names
for short_name in sorted(short_names.keys()):
"""for short_name in sorted(short_names.keys()):
long_name = short_names[short_name]
definition = type_infos[long_name]
is_component = definition['isComponent'] if "isComponent" in definition else False
if self.filter in short_name and is_component:
if not 'Handle' in short_name and not "Cow" in short_name and not "AssetId" in short_name and short_name not in self.exclude: # FIXME: hard coded, seems wrong
items.append((long_name, short_name, long_name))"""
for long_name in type_infos.keys():
definition = type_infos[long_name]
short_name = definition["short_name"]
is_component = definition['isComponent'] if "isComponent" in definition else False
if self.filter in short_name and is_component:
if not 'Handle' in short_name and not "Cow" in short_name and not "AssetId" in short_name and short_name not in self.exclude: # FIXME: hard coded, seems wrong
items.append((long_name, short_name, long_name))
items.sort(key=lambda a: a[1])
return items
@classmethod

View File

@ -72,11 +72,13 @@ def get_component_metadata_by_short_name(object, short_name):
# remove no longer valid metadata from object
def cleanup_invalid_metadata(object):
bevy_components = json.loads(object['bevy_components']) if 'bevy_components' in object else {}
components_metadata = object.components_meta.components
to_remove = []
for index, component_meta in enumerate(components_metadata):
short_name = component_meta.name
if short_name not in object.keys():
long_name = component_meta.long_name
if long_name not in bevy_components.keys():
print("component:", short_name, "present in metadata, but not in object")
to_remove.append(index)
for index in to_remove:
@ -131,20 +133,34 @@ def add_metadata_to_components_without_metadata(object):
upsert_component_in_object(object, component_name, registry)
import json
def inject_component(object, long_name, value):
if not 'bevy_components' in object:
object['bevy_components'] = '{}'
previous = json.loads(object['bevy_components'])
previous[long_name] = value
object['bevy_components'] = json.dumps(previous)
#object['bevy_components'][long_name] = value # Sigh, this does not work, hits Blender's 63 char length limit
def bla_component(object, long_name):
if 'bevy_components' in object:
current = json.loads(object['bevy_components'])
del current[long_name]
object['bevy_components'] = json.dumps(current)
# adds a component to an object (including metadata) using the provided component definition & optional value
def add_component_to_object(object, component_definition, value=None):
cleanup_invalid_metadata(object)
if object is not None:
# print("add_component_to_object", component_definition)
long_name = component_definition["title"]
short_name = component_definition["short_name"]
registry = bpy.context.window_manager.components_registry
if not registry.has_type_infos():
raise Exception('registry type infos have not been loaded yet or are missing !')
definition = registry.type_infos[long_name]
print("HEAAAY", value)
# now we use our pre_generated property groups to set the initial value of our custom property
(_, propertyGroup) = upsert_component_in_object(object, component_name=short_name, registry=registry)
(_, propertyGroup) = upsert_component_in_object(object, long_name=long_name, registry=registry)
if value == None:
value = property_group_value_to_custom_property_value(propertyGroup, definition, registry, None)
else: # we have provided a value, that is a raw , custom property value, to set the value of the propertyGroup
@ -152,22 +168,25 @@ def add_component_to_object(object, component_definition, value=None):
property_group_value_from_custom_property_value(propertyGroup, definition, registry, value)
del object["__disable__update"]
object[short_name] = value
ping_depsgraph_update(object)
# object[short_name] = value
print("ADDING VAALUEEE", value)
inject_component(object, long_name, value)
#ping_depsgraph_update(object)
def upsert_component_in_object(object, component_name, registry):
def upsert_component_in_object(object, long_name, registry):
# print("upsert_component_in_object", object, "component name", component_name)
# TODO: upsert this part too ?
target_components_metadata = object.components_meta.components
component_definition = find_component_definition_from_short_name(component_name)
print("target_components_metadata", target_components_metadata)
component_definition = registry.type_infos.get(long_name, None)
if component_definition != None:
short_name = component_definition["short_name"]
long_name = component_definition["title"]
property_group_name = registry.get_propertyGroupName_from_shortName(short_name)
property_group_name = registry.get_propertyGroupName_from_longName(long_name)
propertyGroup = None
component_meta = next(filter(lambda component: component["name"] == short_name, target_components_metadata), None)
component_meta = next(filter(lambda component: component["long_name"] == long_name, target_components_metadata), None)
if not component_meta:
component_meta = target_components_metadata.add()
component_meta.name = short_name
@ -285,7 +304,7 @@ def apply_customProperty_values_to_object_propertyGroups(object):
# removes the given component from the object: removes both the custom property and the matching metadata from the object
def remove_component_from_object(object, component_name):
del object[component_name]
bla_component(object, component_name)
components_metadata = getattr(object, "components_meta", None)
if components_metadata == None:
@ -294,8 +313,8 @@ def remove_component_from_object(object, component_name):
components_metadata = components_metadata.components
to_remove = []
for index, component_meta in enumerate(components_metadata):
short_name = component_meta.name
if short_name == component_name:
long_name = component_meta.long_name
if long_name == component_name:
to_remove.append(index)
break
for index in to_remove:

View File

@ -114,7 +114,7 @@ class RemoveComponentOperator(Operator):
else:
object = bpy.data.objects[self.object_name]
print("removing component ", self.component_name, "from object '"+object.name+"'")
if object is not None and self.component_name in object:
if object is not None and 'bevy_components' in object and self.component_name in object['bevy_components']:
remove_component_from_object(object, self.component_name)
else:
self.report({"ERROR"}, "The object/ component to remove ("+ self.component_name +") does not exist")
@ -128,7 +128,7 @@ class RemoveComponentFromAllObjectsOperator(Operator):
bl_options = {"UNDO"}
component_name: StringProperty(
name="component name",
name="component name (long name)",
description="component to delete",
) # type: ignore

View File

@ -151,14 +151,18 @@ class BEVY_COMPONENTS_PT_ComponentsPanel(bpy.types.Panel):
components_in_object = object.components_meta.components
for component_name in sorted(dict(object)) : # sorted by component name, practical
components_bla = json.loads(object["bevy_components"]) if "bevy_components" in object else '{}'
#print("components_names", dict(components_bla).keys())
for component_name in sorted(dict(components_bla)) : # sorted by component name, practical
#print("component_name", component_name)
if component_name == "components_meta":
continue
# anything withouth metadata gets skipped, we only want to see real components, not all custom props
component_meta = next(filter(lambda component: component["name"] == component_name, components_in_object), None)
component_meta = next(filter(lambda component: component["long_name"] == component_name, components_in_object), None)
if component_meta == None:
continue
component_invalid = getattr(component_meta, "invalid")
invalid_details = getattr(component_meta, "invalid_details")
component_visible = getattr(component_meta, "visible")
@ -173,9 +177,13 @@ class BEVY_COMPONENTS_PT_ComponentsPanel(bpy.types.Panel):
row.label(text=component_name)
# we fetch the matching ui property group
root_propertyGroup_name = registry.get_propertyGroupName_from_shortName(component_name)
root_propertyGroup_name = registry.get_propertyGroupName_from_longName(component_name)
print("root_propertyGroup_name", root_propertyGroup_name)
print("component_meta", component_meta, component_invalid)
if root_propertyGroup_name:
propertyGroup = getattr(component_meta, root_propertyGroup_name, None)
print("propertyGroup", propertyGroup)
if propertyGroup:
# if the component has only 0 or 1 field names, display inline, otherwise change layout
single_field = len(propertyGroup.field_names) < 2

View File

@ -74,7 +74,7 @@ def process_component(registry, definition, update, extras=None, nesting = []):
-BasicTest => the registration & update callback of this one overwrites the first "basicTest"
have not found a cleaner workaround so far
"""
property_group_name = registry.generate_propGroup_name(nesting, short_name)
property_group_name = registry.generate_propGroup_name(nesting, short_name, component_name)
(property_group_pointer, property_group_class) = property_group_from_infos(property_group_name, property_group_params)
# add our component propertyGroup to the registry
registry.register_component_propertyGroup(property_group_name, property_group_pointer)

View File

@ -244,6 +244,7 @@ class ComponentsRegistry(PropertyGroup):
# cleanup previous data if any
self.propGroupIdCounter = 0
self.short_names_to_propgroup_names.clear()
self.long_names_to_propgroup_names.clear()
self.missing_types_list.clear()
self.type_infos.clear()
self.type_infos_missing.clear()
@ -330,10 +331,11 @@ class ComponentsRegistry(PropertyGroup):
default=0
) # type: ignore
short_names_to_propgroup_names = {}
short_names_to_propgroup_names = {} # TODO; double check if needed, remove otherwise
long_names_to_propgroup_names = {}
# generate propGroup name from nesting level & shortName: each shortName + nesting is unique
def generate_propGroup_name(self, nesting, shortName):
def generate_propGroup_name(self, nesting, shortName, longName):
#print("gen propGroup name for", shortName, nesting)
#if shortName in self.short_names_to_propgroup_names and len(nesting) == 0:
# return self.get_propertyGroupName_from_shortName(shortName)
@ -342,12 +344,21 @@ class ComponentsRegistry(PropertyGroup):
propGroupIndex = str(self.propGroupIdCounter)
propGroupName = propGroupIndex + "_ui"
key = str(nesting) + shortName if len(nesting) > 0 else shortName
self.short_names_to_propgroup_names[key] = propGroupName
#
"""key = str(nesting) + shortName if len(nesting) > 0 else shortName
self.short_names_to_propgroup_names[key] = propGroupName"""
# FIXME:
key = str(nesting) + longName if len(nesting) > 0 else longName
self.long_names_to_propgroup_names[longName] = propGroupName
return propGroupName
def get_propertyGroupName_from_shortName(self, shortName):
return self.short_names_to_propgroup_names.get(shortName, None)
def get_propertyGroupName_from_longName(self, longName):
return self.long_names_to_propgroup_names.get(longName, None)
###########