mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-12-22 23:54:10 +00:00
feat(Blenvy): fixed & overhauled components processing & hashing
* now correctly using nested long names + attribute name for structs * so no more hashing collisions for all test cases ! * restructured internals of property group generation & registration * dynamically generated property group classes are now unregistered correctly * lots of minor related tweaks & improvements
This commit is contained in:
parent
e86920168a
commit
2abdb7f64e
@ -95,7 +95,7 @@ Components:
|
||||
-> VERY likely due to the int-offset computation for hashes of components
|
||||
- now switched to tiger_hash
|
||||
- [x] add warning about hash colision (not much we can/ could do if it is the case ?)
|
||||
- [ ] double check weird collisions AND/OR reuse existing if applicable
|
||||
- [x] double check weird collisions AND/OR reuse existing if applicable
|
||||
|
||||
- [x] annoying default path for registry, should be relative to the assets path
|
||||
|
||||
@ -163,8 +163,9 @@ General issues:
|
||||
- [ ] remove/replace bevy editor pls with some native ui to display hierarchies
|
||||
- [ ] switch to bevy rc2
|
||||
|
||||
|
||||
|
||||
- [ ] simplify examples:
|
||||
- [ ] a full fledged demo (including physics & co)
|
||||
- [ ] other examples without interactions or physics
|
||||
|
||||
|
||||
- [x] overall cleanup
|
||||
|
@ -220,7 +220,7 @@ def upsert_component_in_item(item, long_name, registry):
|
||||
if property_group_name in registry.component_propertyGroups:
|
||||
# we have found a matching property_group, so try to inject it
|
||||
# now inject property group
|
||||
setattr(ComponentMetadata, property_group_name, registry.component_propertyGroups[property_group_name]) # FIXME: not ideal as all ComponentMetadata get the propGroup, but have not found a way to assign it per instance
|
||||
setattr(ComponentMetadata, property_group_name, registry.component_propertyGroups[property_group_name]) # FIXME: not ideal as ALL instances of ComponentMetadata get the propGroup, but have not found a way to assign it per instance
|
||||
propertyGroup = getattr(component_meta, property_group_name, None)
|
||||
|
||||
# now deal with property groups details
|
||||
|
@ -30,13 +30,14 @@ def process_component(registry, definition, update, extras=None, nesting_long_na
|
||||
with_list = False
|
||||
with_map = False
|
||||
|
||||
padding = " " * (len(nesting_long_names) + 1)
|
||||
#padding = " " * (len(nesting_long_names) + 1)
|
||||
#print(f"{padding}process component", long_name, "nesting_long_names",nesting_long_names, "foo", has_properties, has_prefixItems, is_enum, is_list, is_map)
|
||||
|
||||
if has_properties:
|
||||
__annotations__ = __annotations__ | process_structs.process_structs(registry, definition, properties, update, nesting_long_names)
|
||||
with_properties = True
|
||||
tupple_or_struct = "struct"
|
||||
#print(f"{padding}struct")
|
||||
|
||||
if has_prefixItems:
|
||||
__annotations__ = __annotations__ | process_tupples.process_tupples(registry, definition, prefixItems, update, nesting_long_names)
|
||||
@ -61,7 +62,6 @@ def process_component(registry, definition, update, extras=None, nesting_long_na
|
||||
for a in __annotations__:
|
||||
field_names.append(a)
|
||||
|
||||
|
||||
extras = extras if extras is not None else {
|
||||
"long_name": long_name
|
||||
}
|
||||
@ -78,25 +78,16 @@ def process_component(registry, definition, update, extras=None, nesting_long_na
|
||||
**dict(with_properties = with_properties, with_items= with_items, with_enum= with_enum, with_list= with_list, with_map = with_map, short_name= short_name, long_name=long_name),
|
||||
'root_component': root_component
|
||||
}
|
||||
#FIXME: YIKES, but have not found another way:
|
||||
""" Withouth this ; the following does not work
|
||||
|
||||
# we need to pass the full hierarchy to disambiguate between components
|
||||
# Withouth this ; the following does not work
|
||||
"""
|
||||
-BasicTest
|
||||
- NestingTestLevel2
|
||||
-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_long_names)
|
||||
(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)
|
||||
(property_group_pointer, property_group_class) = registry.register_component_propertyGroup(nesting_long_names, property_group_params)
|
||||
|
||||
return (property_group_pointer, property_group_class)
|
||||
|
||||
def property_group_from_infos(property_group_name, property_group_parameters):
|
||||
# print("creating property group", property_group_name)
|
||||
property_group_class = type(property_group_name, (PropertyGroup,), property_group_parameters)
|
||||
|
||||
bpy.utils.register_class(property_group_class)
|
||||
property_group_pointer = PointerProperty(type=property_group_class)
|
||||
|
||||
return (property_group_pointer, property_group_class)
|
@ -33,7 +33,7 @@ def process_structs(registry, definition, properties, update, nesting_long_names
|
||||
__annotations__[property_name] = blender_property
|
||||
else:
|
||||
original_long_name = original["long_name"]
|
||||
(sub_component_group, _) = process_component.process_component(registry, original, update, {"nested": True, "long_name": original_long_name}, nesting_long_names)
|
||||
(sub_component_group, _) = process_component.process_component(registry, original, update, {"nested": True, "long_name": original_long_name}, nesting_long_names+[property_name])
|
||||
__annotations__[property_name] = sub_component_group
|
||||
# if there are sub fields, add an attribute "sub_fields" possibly a pointer property ? or add a standard field to the type , that is stored under "attributes" and not __annotations (better)
|
||||
else:
|
||||
|
@ -34,12 +34,10 @@ def generate_propertyGroups_for_components():
|
||||
|
||||
type_infos = registry.type_infos
|
||||
|
||||
for component_name in type_infos:
|
||||
definition = type_infos[component_name]
|
||||
is_component = definition['isComponent'] if "isComponent" in definition else False
|
||||
root_property_name = component_name# if is_component else None
|
||||
print("root property", component_name,f"({is_component})")
|
||||
process_component(registry, definition, update_calback_helper(definition, update_component, root_property_name), extras=None, nesting_long_names=[])
|
||||
for root_type_name in type_infos:
|
||||
definition = type_infos[root_type_name]
|
||||
#print("root property", component_name,f"({is_component})")
|
||||
process_component(registry, definition, update_calback_helper(definition, update_component, root_type_name), extras=None, nesting_long_names=[])
|
||||
|
||||
# if we had to add any wrapper types on the fly, process them now
|
||||
registry.process_custom_types()
|
@ -7,6 +7,8 @@ from bpy_types import (PropertyGroup)
|
||||
from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty)
|
||||
from ..components.metadata import ComponentMetadata
|
||||
from .hashing.tiger import hash as tiger_hash
|
||||
|
||||
|
||||
# helper class to store missing bevy types information
|
||||
class MissingBevyType(bpy.types.PropertyGroup):
|
||||
long_name: bpy.props.StringProperty(
|
||||
@ -14,6 +16,15 @@ class MissingBevyType(bpy.types.PropertyGroup):
|
||||
) # type: ignore
|
||||
|
||||
|
||||
def property_group_from_infos(property_group_name, property_group_parameters):
|
||||
# print("creating property group", property_group_name)
|
||||
property_group_class = type(property_group_name, (PropertyGroup,), property_group_parameters)
|
||||
|
||||
bpy.utils.register_class(property_group_class)
|
||||
property_group_pointer = PointerProperty(type=property_group_class)
|
||||
|
||||
return (property_group_pointer, property_group_class)
|
||||
|
||||
# this is where we store the information for all available components
|
||||
class ComponentsRegistry(PropertyGroup):
|
||||
registry: bpy.props. StringProperty(
|
||||
@ -140,6 +151,8 @@ class ComponentsRegistry(PropertyGroup):
|
||||
type_infos = {}
|
||||
type_infos_missing = []
|
||||
component_propertyGroups = {}
|
||||
component_property_group_classes = []
|
||||
|
||||
custom_types_to_add = {}
|
||||
invalid_components = []
|
||||
|
||||
@ -152,8 +165,18 @@ class ComponentsRegistry(PropertyGroup):
|
||||
for propgroup_name in cls.component_propertyGroups.keys():
|
||||
try:
|
||||
delattr(ComponentMetadata, propgroup_name)
|
||||
#print("sucess REMOVAL from Metadata")
|
||||
except Exception as error:
|
||||
pass
|
||||
#print("failed to unregister")
|
||||
|
||||
for propgroup_class in cls.component_property_group_classes:
|
||||
try:
|
||||
bpy.utils.unregister_class(propgroup_class)
|
||||
#print("sucess UNREGISTER")
|
||||
except Exception as error:
|
||||
pass
|
||||
#print("NEW failed to unregister")
|
||||
|
||||
del bpy.types.WindowManager.components_registry
|
||||
|
||||
@ -167,7 +190,10 @@ class ComponentsRegistry(PropertyGroup):
|
||||
self.missing_types_list.clear()
|
||||
self.type_infos.clear()
|
||||
self.type_infos_missing.clear()
|
||||
|
||||
self.component_propertyGroups.clear()
|
||||
self.component_property_group_classes.clear()
|
||||
|
||||
self.custom_types_to_add.clear()
|
||||
self.invalid_components.clear()
|
||||
# now prepare paths to load data
|
||||
@ -188,10 +214,6 @@ class ComponentsRegistry(PropertyGroup):
|
||||
def has_type_infos(self):
|
||||
return len(self.type_infos.keys()) != 0
|
||||
|
||||
# we keep a list of component propertyGroup around
|
||||
def register_component_propertyGroup(self, name, propertyGroup):
|
||||
self.component_propertyGroups[name] = propertyGroup
|
||||
|
||||
# to be able to give the user more feedback on any missin/unregistered types in their schema file
|
||||
def add_missing_typeInfo(self, long_name):
|
||||
if not long_name in self.type_infos_missing:
|
||||
@ -217,18 +239,25 @@ class ComponentsRegistry(PropertyGroup):
|
||||
|
||||
long_names_to_propgroup_names = {}
|
||||
|
||||
# we keep a list of component propertyGroup around
|
||||
def register_component_propertyGroup(self, nesting, property_group_params):
|
||||
property_group_name = self.generate_propGroup_name(nesting)
|
||||
(property_group_pointer, property_group_class) = property_group_from_infos(property_group_name, property_group_params)
|
||||
self.component_propertyGroups[property_group_name] = property_group_pointer
|
||||
self.component_property_group_classes.append(property_group_class)
|
||||
|
||||
return (property_group_pointer, property_group_class)
|
||||
|
||||
# generate propGroup name from nesting level: each longName + nesting is unique
|
||||
def generate_propGroup_name(self, nesting):
|
||||
#print("gen propGroup name for", shortName, nesting)
|
||||
key = str(nesting)
|
||||
|
||||
propGroupHash = tiger_hash(key)
|
||||
propGroupName = propGroupHash + "_ui"
|
||||
|
||||
# check for collision
|
||||
padding = " " * (len(nesting) + 1)
|
||||
|
||||
print(f"{padding}--computing hash for", nesting)
|
||||
#padding = " " * (len(nesting) + 1)
|
||||
#print(f"{padding}--computing hash for", nesting)
|
||||
if propGroupName in self.long_names_to_propgroup_names.values():
|
||||
print(" WARNING !! you have a collision between the hash of multiple component names: collision for", nesting)
|
||||
|
||||
@ -238,7 +267,6 @@ class ComponentsRegistry(PropertyGroup):
|
||||
|
||||
def get_propertyGroupName_from_longName(self, longName):
|
||||
return self.long_names_to_propgroup_names.get(str([longName]), None)
|
||||
|
||||
|
||||
###########
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user