From 31f6a0f12247d5e2ca3988ece326661452b9e784 Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Tue, 25 Jun 2024 18:27:52 +0200 Subject: [PATCH] feat(blenvy:blender): a ton of cleanups, fixes & improvements * fixed bad hashing causing hashed project across two different blender sessions to appear different aka, no more systematic re-export of everything when reloading a project in blender ! * fixed issues with modifier & material hashing that was also causing overly eager change detection * previous_xxx_settings are now only saved AFTER a sucessfull export, for coherence * added more fine grained setting change detection (aka some setting changes do not require a re-export of all levels & blueprints !) * fixed handling of level & library scene names as part of the settings * fixed numerous issues with core, auto_export & component settings * cleaned up a ton of very verbose debug message * BlenvyAssets => BlueprintAssets * a lot of minor cleanups --- tools/blenvy/TODO.md | 45 ++++++++---- tools/blenvy/add_ons/auto_export/__init__.py | 2 +- .../blueprints/export_blueprints.py | 7 +- .../add_ons/auto_export/common/auto_export.py | 1 - .../auto_export/common/duplicate_object.py | 2 +- .../generate_temporary_scene_and_export.py | 1 - .../auto_export/common/prepare_and_export.py | 20 ++++-- .../auto_export/common/project_diff.py | 12 +--- .../auto_export/common/serialize_scene.py | 70 +++++++++++++------ .../auto_export/common/serialize_scene_bak.py | 56 --------------- .../auto_export/common/settings_diff.py | 50 ++++++------- .../auto_export/levels/export_main_scenes.py | 10 +-- tools/blenvy/add_ons/auto_export/settings.py | 6 +- .../add_ons/bevy_components/settings.py | 12 ++-- tools/blenvy/assets/assets_scan.py | 5 +- tools/blenvy/assets/ui.py | 2 - tools/blenvy/blueprints/blueprint_helpers.py | 11 ++- tools/blenvy/core/blenvy_manager.py | 59 ++++++++-------- tools/blenvy/core/ui/scenes_list.py | 6 +- tools/blenvy/settings.py | 33 ++++++++- tools/blenvy/tests/test_bevy_integration.py | 6 +- 21 files changed, 212 insertions(+), 204 deletions(-) delete mode 100644 tools/blenvy/add_ons/auto_export/common/serialize_scene_bak.py diff --git a/tools/blenvy/TODO.md b/tools/blenvy/TODO.md index b7b273e..b65572f 100644 --- a/tools/blenvy/TODO.md +++ b/tools/blenvy/TODO.md @@ -139,29 +139,53 @@ General issues: - [x] overall cleanup - [x] object.add_bevy_component => blenvy.component_add - +Blender side: +- [x] force overwrite of settings files instead of partial updates ? +- [x] prevent loop when loading/setting/saving settings +- [x] fix asset changes not being detected as a scene change +- [x] fix scene setting changes not being detected as a scene change +- [x] add back lighting_components +- [x] check if scene components are being deleted through our scene re-orgs in the spawn post process +- [x] fix unreliable project hashing between sessions: (note, it is due to the use of hash() : https://stackoverflow.com/questions/27522626/hash-function-in-python-3-3-returns-different-results-between-sessions) +- [x] figure out why there are still changes per session (it is due to object pointer being present in the generated "hash") + - materials & modifiers, both using the same underlying logic + - [x] filter out components_meta + - [x] filter out xxx_ui propgroups +- [x] fix missing main/lib scene names in blenvy_common_settings +- [x] fix incorect updating of main/lib scenes list in settings +- [ ] and what about scene renames ?? perhaps tigger a forced "save settings" before doing the export ? +- [x] should we write the previous _xxx data only AFTER a sucessfull export only ? +- [x] finer grained control of setting changes to trigger a re-export: + - [x] common: any of them should trigger + - [x] components: none + - [x] auto_export: + - auto_export: yes + - gltf settings: yes + - change detection: no ? + - export blueprints: YES + - export split dynamic/static: YES + - export merge mode : YES + - materials: YES - [ ] inject_export_path_into_internal_blueprints should be called on every asset/blueprint scan !! Not just on export - [ ] undo after a save removes any saved "serialized scene" data ? DIG into this - [ ] handle scene renames between saves (breaks diffing) => very hard to achieve -- [ ] force overwrite of settings files instead of partial updates ? - [ ] add tests for disabled components -- [ ] should we write the previous _xxx data only AFTER a sucessfull export only ? +- [ ] find a solution for the new color handling +- [ ] hidden objects/collections not respected at export !!! - [ ] add option to 'split out' meshes from blueprints ? - [ ] ie considering meshletts etc , it would make sense to keep blueprints seperate from purely mesh gltfs - [ ] persist exported materials path in blueprints so that it can be read from library file users - [ ] just like "export_path" write it into each blueprint's collection - [ ] scan for used materials per blueprint ! - [ ] for scenes, scan for used materials of all non instance objects (TODO: what about overrides ?) -- [ ] find a solution for the new color handling -- [x] add back lighting_components -- [x] check if scene components are being deleted through our scene re-orgs in the spawn post process -- [ ] should "blueprint spawned" only be triggered after all its sub blueprints have spawned ? +Bevy Side: +- [x] deprecate BlueprintName & BlueprintPath & use BlueprintInfo instead +- [ ] should "blueprint spawned" only be triggered after all its sub blueprints have spawned ? - [ ] simplify testing example: - [x] remove use of rapier physics (or even the whole common boilerplate ?) - [ ] remove/replace bevy editor pls with some native ui to display hierarchies -- [ ] try out hot reloading - +- [x] try out hot reloading - [ ] simplify examples: - [ ] a full fledged demo (including physics & co) - [ ] other examples without interactions or physics @@ -170,12 +194,9 @@ General issues: - [ ] replace all references to the old 2 add-ons with those to Blenvy - [ ] rename repo to "Blenvy" - [ ] do a deprecation release of all bevy_gltf_xxx crates to point at the new Blenvy crate -- [ ] hidden objects/collections not respected at export !!! - [ ] add a way of overriding assets for collection instances - [ ] add a way of visualizing per blueprint instances - [ ] cleanup all the spurious debug messages -- [ ] deprecate BlueprintName & BlueprintPath & use BlueprintInfo instead - [ ] fix animation handling - clear && pytest -svv --blender-template ../../testing/bevy_example/art/testing_library.blend --blender-executable /home/ckaos/tools/blender/blender-4.1.0-linux-x64/blender tests/test_bevy_integration_prepare.py && pytest -svv --blender-executable /home/ckaos/tools/blender/blender-4.1.0-linux-x64/blender tests/test_bevy_integration.py \ No newline at end of file diff --git a/tools/blenvy/add_ons/auto_export/__init__.py b/tools/blenvy/add_ons/auto_export/__init__.py index ecdf6f2..b82dc75 100644 --- a/tools/blenvy/add_ons/auto_export/__init__.py +++ b/tools/blenvy/add_ons/auto_export/__init__.py @@ -11,7 +11,7 @@ def cleanup_file(): os.remove(gltf_filepath) return None else: - return 1 + return 1.0 def gltf_post_export_callback(data): #print("post_export", data) diff --git a/tools/blenvy/add_ons/auto_export/blueprints/export_blueprints.py b/tools/blenvy/add_ons/auto_export/blueprints/export_blueprints.py index 10e2a4c..d732567 100644 --- a/tools/blenvy/add_ons/auto_export/blueprints/export_blueprints.py +++ b/tools/blenvy/add_ons/auto_export/blueprints/export_blueprints.py @@ -36,14 +36,9 @@ def export_blueprints(blueprints, settings, blueprints_data): collection = bpy.data.collections[blueprint.name] - print("BLUEPRINT", blueprint.name) - - for asset in collection.user_assets: - print(" user asset", asset.name, asset.path) - all_assets = [] auto_assets = [] - collection["BlenvyAssets"] = assets_to_fake_ron([]) #assets_to_fake_ron([{"name": asset.name, "path": asset.path} for asset in collection.user_assets] + auto_assets) #all_assets + [{"name": asset.name, "path": asset.path} for asset in collection.user_assets] + auto_assets) + collection["BlueprintAssets"] = assets_to_fake_ron([]) #assets_to_fake_ron([{"name": asset.name, "path": asset.path} for asset in collection.user_assets] + auto_assets) #all_assets + [{"name": asset.name, "path": asset.path} for asset in collection.user_assets] + auto_assets) # do the actual export diff --git a/tools/blenvy/add_ons/auto_export/common/auto_export.py b/tools/blenvy/add_ons/auto_export/common/auto_export.py index 9509fac..cf64c73 100644 --- a/tools/blenvy/add_ons/auto_export/common/auto_export.py +++ b/tools/blenvy/add_ons/auto_export/common/auto_export.py @@ -51,7 +51,6 @@ def auto_export(changes_per_scene, changed_export_parameters, settings): for blueprint in blueprints_data.blueprints: bpy.context.window_manager.blueprints_registry.add_blueprint(blueprint) #bpy.context.window_manager.blueprints_registry.refresh_blueprints() - print("YO YO") if export_scene_settings: # inject/ update scene components diff --git a/tools/blenvy/add_ons/auto_export/common/duplicate_object.py b/tools/blenvy/add_ons/auto_export/common/duplicate_object.py index 5bfefc9..22af988 100644 --- a/tools/blenvy/add_ons/auto_export/common/duplicate_object.py +++ b/tools/blenvy/add_ons/auto_export/common/duplicate_object.py @@ -90,7 +90,7 @@ def duplicate_object(object, parent, combine_mode, destination_collection, bluep original_name = object.name blueprint_name = original_collection.name # FIXME: blueprint path is WRONG ! - print("BLUEPRINT PATH", original_collection.get('export_path', None)) + # print("BLUEPRINT PATH", original_collection.get('export_path', None)) blueprint_path = original_collection['export_path'] if 'export_path' in original_collection else f'./{blueprint_name}' # TODO: the default requires the currently used extension !! diff --git a/tools/blenvy/add_ons/auto_export/common/generate_temporary_scene_and_export.py b/tools/blenvy/add_ons/auto_export/common/generate_temporary_scene_and_export.py index ba81539..05bbe75 100644 --- a/tools/blenvy/add_ons/auto_export/common/generate_temporary_scene_and_export.py +++ b/tools/blenvy/add_ons/auto_export/common/generate_temporary_scene_and_export.py @@ -19,7 +19,6 @@ def generate_temporary_scene_and_export(settings, gltf_export_settings, gltf_out temp_scene = bpy.data.scenes.new(name=temp_scene_name) temp_root_collection = temp_scene.collection - print("additional_dataAAAAAAAAAAAAAAAH", additional_data) properties_black_list = ['glTF2ExportSettings', 'assets', 'user_assets', 'components_meta', 'Components_meta', 'Generated_assets', 'generated_assets'] if additional_data is not None: # FIXME not a fan of having this here for entry in dict(additional_data): diff --git a/tools/blenvy/add_ons/auto_export/common/prepare_and_export.py b/tools/blenvy/add_ons/auto_export/common/prepare_and_export.py index 20dc0ae..fcfdf4c 100644 --- a/tools/blenvy/add_ons/auto_export/common/prepare_and_export.py +++ b/tools/blenvy/add_ons/auto_export/common/prepare_and_export.py @@ -3,6 +3,7 @@ import bpy from .project_diff import get_changes_per_scene from .auto_export import auto_export from .settings_diff import get_setting_changes +from blenvy.settings import load_settings, upsert_settings # prepare export by gather the changes to the scenes & settings def prepare_and_export(): @@ -13,17 +14,28 @@ def prepare_and_export(): if auto_export_settings.auto_export: # only do the actual exporting if auto export is actually enabled # determine changed objects - per_scene_changes = get_changes_per_scene(settings=blenvy) + per_scene_changes, project_hash = get_changes_per_scene(settings=blenvy) # determine changed parameters - setting_changes = get_setting_changes() - print("setting_changes", setting_changes) + setting_changes, current_common_settings, current_export_settings, current_gltf_settings = get_setting_changes() + print("changes: settings:", setting_changes) + print("changes: scenes:", per_scene_changes) + + print("project_hash", project_hash) # do the actual export # blenvy.auto_export.dry_run = 'NO_EXPORT'#'DISABLED'# auto_export(per_scene_changes, setting_changes, blenvy) + # ------------------------------------- + # now that this point is reached, the export should have run correctly, so we can save all the current state to the "previous one" + # save the current project hash as previous + upsert_settings(".blenvy.project_serialized_previous", project_hash, overwrite=True) + # write the new settings to the old settings + upsert_settings(".blenvy_common_settings_previous", current_common_settings, overwrite=True) + upsert_settings(".blenvy_export_settings_previous", current_export_settings, overwrite=True) + upsert_settings(".blenvy_gltf_settings_previous", current_gltf_settings, overwrite=True) + # cleanup # TODO: these are likely obsolete # reset the list of changes in the tracker #bpy.context.window_manager.auto_export_tracker.clear_changes() print("AUTO EXPORT DONE") - #bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=0.1) diff --git a/tools/blenvy/add_ons/auto_export/common/project_diff.py b/tools/blenvy/add_ons/auto_export/common/project_diff.py index f253a8b..1f96a00 100644 --- a/tools/blenvy/add_ons/auto_export/common/project_diff.py +++ b/tools/blenvy/add_ons/auto_export/common/project_diff.py @@ -22,6 +22,7 @@ def serialize_current(settings): current_scene = bpy.context.window.scene bpy.context.window.scene = bpy.data.scenes[0] #serialize scene at frame 0 + # TODO: add back """with bpy.context.temp_override(scene=bpy.data.scenes[1]): bpy.context.scene.frame_set(0)""" @@ -38,7 +39,6 @@ def get_changes_per_scene(settings): previous = load_settings(".blenvy.project_serialized_previous") current = serialize_current(settings) - # determine changes changes_per_scene = {} try: @@ -46,11 +46,7 @@ def get_changes_per_scene(settings): except Exception as error: print("failed to compare current serialized scenes to previous ones", error) - # save the current project as previous - upsert_settings(".blenvy.project_serialized_previous", current, overwrite=True) - - print("changes per scene", changes_per_scene) - return changes_per_scene + return changes_per_scene, current def project_diff(previous, current, settings): @@ -58,17 +54,13 @@ def project_diff(previous, current, settings): print("current", current)""" if previous is None or current is None: return {} - print("Settings", settings,"current", current, "previous", previous) changes_per_scene = {} # TODO : how do we deal with changed scene names ??? # possible ? on each save, inject an id into each scene, that cannot be copied over - print('TEST SCENE', bpy.data.scenes.get("ULTRA LEVEL2"), None) - for scene in current: - print("SCENE", scene) current_object_names =list(current[scene].keys()) if scene in previous: # we can only compare scenes that are in both previous and current data diff --git a/tools/blenvy/add_ons/auto_export/common/serialize_scene.py b/tools/blenvy/add_ons/auto_export/common/serialize_scene.py index 5361480..93e8dc8 100644 --- a/tools/blenvy/add_ons/auto_export/common/serialize_scene.py +++ b/tools/blenvy/add_ons/auto_export/common/serialize_scene.py @@ -7,13 +7,23 @@ import numpy as np import bpy from ..constants import TEMPSCENE_PREFIX +import hashlib + +# horrible and uneficient +def h1_hash(w): + try: + w = w.encode('utf-8') + except: pass + return hashlib.md5(w).hexdigest() fields_to_ignore_generic = [ "tag", "type", "update_tag", "use_extra_user", "use_fake_user", "user_clear", "user_of_id", "user_remap", "users", 'animation_data_clear', 'animation_data_create', 'asset_clear', 'asset_data', 'asset_generate_preview', 'asset_mark', 'bl_rna', 'evaluated_get', 'library', 'library_weak_reference', 'make_local','name', 'name_full', 'original', 'override_create', 'override_hierarchy_create', 'override_library', 'preview', 'preview_ensure', 'rna_type', - 'session_uid', 'copy', 'id_type', 'is_embedded_data', 'is_evaluated', 'is_library_indirect', 'is_missing', 'is_runtime_data' + 'session_uid', 'copy', 'id_type', 'is_embedded_data', 'is_evaluated', 'is_library_indirect', 'is_missing', 'is_runtime_data', + + 'components_meta', 'cycles' ] @@ -40,9 +50,7 @@ def _lookup_array2(data): return peel_value(data) def _lookup_prop_group(data): - bla = generic_fields_hasher_evolved(data, fields_to_ignore=fields_to_ignore_generic) - print("PROPGROUP", bla) - return bla + return generic_fields_hasher_evolved(data, fields_to_ignore=fields_to_ignore_generic) def _lookup_collection(data): return [generic_fields_hasher_evolved(item, fields_to_ignore=fields_to_ignore_generic) for item in data] @@ -50,9 +58,16 @@ def _lookup_collection(data): def _lookup_materialLineArt(data): return generic_fields_hasher_evolved(data, fields_to_ignore=fields_to_ignore_generic) +def _lookup_object(data): + return data.name + return generic_fields_hasher_evolved(data, fields_to_ignore=fields_to_ignore_generic) + +def _lookup_generic(data): + return generic_fields_hasher_evolved(data, fields_to_ignore=fields_to_ignore_generic) + # used for various node trees: shaders, modifiers etc def node_tree(node_tree): - print("SCANNING NODE TREE", node_tree) + #print("SCANNING NODE TREE", node_tree) # storage for hashing links_hashes = [] @@ -99,18 +114,19 @@ def node_tree(node_tree): links_hashes.append(link_hash) #print("node hashes",nodes_hashes, "links_hashes", links_hashes) - print("root_inputs", root_inputs) return f"{str(root_inputs)}_{str(nodes_hashes)}_{str(links_hashes)}" type_lookups = { Color: _lookup_color,#lambda input: print("dsf")', + bpy.types.Object: _lookup_object, bpy.types.FloatVectorAttribute: _lookup_array2, bpy.types.bpy_prop_array: _lookup_array, bpy.types.PropertyGroup: _lookup_prop_group, bpy.types.bpy_prop_collection: _lookup_collection, bpy.types.MaterialLineArt: _lookup_materialLineArt, bpy.types.NodeTree: node_tree, + bpy.types.CurveProfile: _lookup_generic } def convert_field(raw_value, field_name="", scan_node_tree=True): @@ -122,6 +138,7 @@ def convert_field(raw_value, field_name="", scan_node_tree=True): conversion_lookup = None # type_lookups.get(type(raw_value), None) all_types = inspect.getmro(type(raw_value)) for s_type in all_types: + #print(" stype", s_type) if type_lookups.get(s_type, None) is not None: conversion_lookup = type_lookups[s_type] break @@ -132,6 +149,9 @@ def convert_field(raw_value, field_name="", scan_node_tree=True): #print("field_name",field_name,"conv value", field_value) else: #print("field_name",field_name,"raw value", raw_value) + """try: + field_value=_lookup_generic(raw_value) + except:pass""" field_value = raw_value return field_value @@ -146,6 +166,7 @@ def obj_to_dict(object): # TODO: replace the first one with this once if its done def generic_fields_hasher_evolved(data, fields_to_ignore, scan_node_tree=True): dict_data = obj_to_dict(data) # in some cases, some data is in the key/value pairs of the object + dict_data = {key: dict_data[key] for key in dict_data.keys() if key not in fields_to_ignore}# we need to filter out fields here too all_field_names = dir(data) field_values = [] for field_name in all_field_names: @@ -153,6 +174,8 @@ def generic_fields_hasher_evolved(data, fields_to_ignore, scan_node_tree=True): raw_value = getattr(data, field_name, None) #print("raw value", raw_value, "type", type(raw_value), isinstance(raw_value, Color), isinstance(raw_value, bpy.types.bpy_prop_array)) field_value = convert_field(raw_value, field_name, scan_node_tree) + #print("field name", field_name, "raw", raw_value, "converted", field_value) + field_values.append(str(field_value)) return str(dict_data) + str(field_values) @@ -163,7 +186,7 @@ def mesh_hash(obj): vertex_count = len(obj.data.vertices) vertices_np = np.empty(vertex_count * 3, dtype=np.float32) obj.data.vertices.foreach_get("co", vertices_np) - h = str(hash(vertices_np.tobytes())) + h = str(h1_hash(vertices_np.tobytes())) return h # TODO: redo this one, this is essentially modifiec copy & pasted data, not fitting @@ -202,7 +225,7 @@ def animation_hash(obj): markers_per_animation[animation_name][marker.frame] = [] markers_per_animation[animation_name][marker.frame].append(marker.name) - compact_result = hash(str((blender_actions, blender_tracks, markers_per_animation, animations_infos))) + compact_result = h1_hash(str((blender_actions, blender_tracks, markers_per_animation, animations_infos))) return compact_result @@ -213,7 +236,7 @@ def custom_properties_hash(obj): for property_name in obj.keys(): if property_name not in '_RNA_UI' and property_name != 'components_meta': custom_properties[property_name] = obj[property_name] - return str(hash(str(custom_properties))) + return str(h1_hash(str(custom_properties))) def camera_hash(obj): camera_data = obj.data @@ -233,7 +256,7 @@ def bones_hash(bones): fields = [getattr(bone, prop, None) for prop in all_field_names if not prop.startswith("__") and not prop in fields_to_ignore and not prop.startswith("show_")] bones_result.append(fields) #print("fields of bone", bones_result) - return str(hash(str(bones_result))) + return str(h1_hash(str(bones_result))) # fixme: not good enough ? def armature_hash(obj): @@ -250,8 +273,10 @@ def armature_hash(obj): def material_hash(material, settings): scan_node_tree = settings.auto_export.materials_in_depth_scan - hashed_material_except_node_tree = generic_fields_hasher_evolved(material, fields_to_ignore_generic, scan_node_tree=scan_node_tree) - return str(hashed_material_except_node_tree) + #print("HASHING MATERIAL", material.name) + hashed_material = generic_fields_hasher_evolved(material, fields_to_ignore_generic, scan_node_tree=scan_node_tree) + #print("HASHED MATERIAL", hashed_material) + return str(hashed_material) # TODO: this is partially taken from export_materials utilities, perhaps we could avoid having to fetch things multiple times ? def materials_hash(obj, cache, settings): @@ -271,21 +296,23 @@ def materials_hash(obj, cache, settings): cache['materials'][material.name] = mat materials.append(mat) - return str(hash(str(materials))) + return str(h1_hash(str(materials))) def modifier_hash(modifier_data, settings): scan_node_tree = settings.auto_export.modifiers_in_depth_scan + #print("HASHING MODIFIER", modifier_data.name) hashed_modifier = generic_fields_hasher_evolved(modifier_data, fields_to_ignore_generic, scan_node_tree=scan_node_tree) + #print("modifier", modifier_data.name, "hashed", hashed_modifier) return str(hashed_modifier) def modifiers_hash(object, settings): modifiers = [] for modifier in object.modifiers: - print("modifier", modifier )# modifier.node_group) + #print("modifier", modifier )# modifier.node_group) modifiers.append(modifier_hash(modifier, settings)) - print(" ") - return str(hash(str(modifiers))) + #print(" ") + return str(h1_hash(str(modifiers))) def serialize_scene(settings): cache = {"materials":{}} @@ -309,16 +336,15 @@ def serialize_scene(settings): "custom_properties": custom_properties, "eevee": eevee_settings } - print("SCENE WORLD", scene.world, dir(scene.eevee)) #generic_fields_hasher_evolved(scene.eevee, fields_to_ignore=fields_to_ignore_generic) - data[scene.name]["____scene_settings"] = str(hash(str(scene_field_hashes))) + # FIXME: how to deal with this cleanly + print("SCENE CUSTOM PROPS", custom_properties) + data[scene.name]["____scene_settings"] = str(h1_hash(str(scene_field_hashes))) for object in scene.objects: object = bpy.data.objects[object.name] - #loc, rot, scale = bpy.context.object.matrix_world.decompose() - transform = str((object.location, object.rotation_euler, object.scale)) #str((object.matrix_world.to_translation(), object.matrix_world.to_euler('XYZ'), object.matrix_world.to_quaternion()))# visibility = object.visible_get() custom_properties = custom_properties_hash(object) if len(object.keys()) > 0 else None @@ -332,7 +358,6 @@ def serialize_scene(settings): materials = materials_hash(object, cache, settings) if len(object.material_slots) > 0 else None modifiers = modifiers_hash(object, settings) if len(object.modifiers) > 0 else None - object_field_hashes = { "name": object.name, "transforms": transform, @@ -348,8 +373,9 @@ def serialize_scene(settings): "materials": materials, "modifiers":modifiers } + object_field_hashes_filtered = {key: object_field_hashes[key] for key in object_field_hashes.keys() if object_field_hashes[key] is not None} - objectHash = str(hash(str(object_field_hashes_filtered))) + objectHash = str(h1_hash(str(object_field_hashes_filtered))) data[scene.name][object.name] = objectHash """print("data", data) diff --git a/tools/blenvy/add_ons/auto_export/common/serialize_scene_bak.py b/tools/blenvy/add_ons/auto_export/common/serialize_scene_bak.py deleted file mode 100644 index d669055..0000000 --- a/tools/blenvy/add_ons/auto_export/common/serialize_scene_bak.py +++ /dev/null @@ -1,56 +0,0 @@ - #print("THIS IS A GEOMETRY NODE") - - # storage for hashing - links_hashes = [] - nodes_hashes = [] - modifier_inputs = dict(modifier_data) - - for node in node_group.nodes: - #print("node", node, node.type, node.name, node.label) - #print("node info", dir(node)) - - input_hashes = [] - for input in node.inputs: - #print(" input", input, "label", input.label, "name", input.name) - input_hash = f"{getattr(input, 'default_value', None)}" - input_hashes.append(input_hash) - """if hasattr(input, "default_value"): - print("YOHO", dict(input), input.default_value)""" - - output_hashes = [] - # IF the node itself is a group input, its outputs are the inputs of the geometry node (yes, not easy) - node_in_use = True - for (index, output) in enumerate(node.outputs): - # print(" output", output, "label", output.label, "name", output.name, "generated name", f"Socket_{index+1}") - output_hash = f"{getattr(output, 'default_value', None)}" - output_hashes.append(output_hash) - """if hasattr(output, "default_value"): - print("YOHO", output.default_value)""" - node_in_use = node_in_use and hasattr(output, "default_value") - #print("NODE IN USE", node_in_use) - - node_fields_to_ignore = fields_to_ignore_generic + ['internal_links', 'inputs', 'outputs'] - - node_hash = f"{generic_fields_hasher(node, node_fields_to_ignore)}_{str(input_hashes)}_{str(output_hashes)}" - #print("node hash", node_hash) - nodes_hashes.append(node_hash) - #print(" ") - - for link in node_group.links: - """print("LINK", link) #dir(link) - print("FROM", link.from_node, link.from_socket) - print("TO", link.to_node, link.to_socket)""" - - from_socket_default = link.from_socket.default_value if hasattr(link.from_socket, "default_value") else None - to_socket_default = link.to_socket.default_value if hasattr(link.to_socket, "default_value") else None - link_hash = f"{link.from_node.name}_{link.from_socket.name}_{from_socket_default}+{link.to_node.name}_{link.to_socket.name}_{to_socket_default}" - - """if hasattr(link.from_socket, "default_value"): - print("[FROM SOCKET]", link.from_socket.default_value) - if hasattr(link.to_socket, "default_value"): - print("[TO SOCKET]", link.to_socket.default_value)""" - - links_hashes.append(link_hash) - #print("link_hash", link_hash) - - return f"{str(modifier_inputs)}_{str(nodes_hashes)}_{str(links_hashes)}" \ No newline at end of file diff --git a/tools/blenvy/add_ons/auto_export/common/settings_diff.py b/tools/blenvy/add_ons/auto_export/common/settings_diff.py index 40e26db..8c014b5 100644 --- a/tools/blenvy/add_ons/auto_export/common/settings_diff.py +++ b/tools/blenvy/add_ons/auto_export/common/settings_diff.py @@ -1,8 +1,8 @@ import bpy -from blenvy.settings import are_settings_identical, load_settings, upsert_settings +from blenvy.settings import are_settings_identical, load_settings, changed_settings -# which settings are specific to auto_export # TODO: can we infer this ? +# which common settings changes should trigger a re-export parameter_names_whitelist_common = [ # blenvy core 'project_root_path', @@ -14,6 +14,7 @@ parameter_names_whitelist_common = [ 'library_scene_names', ] +# which auto export settings changes should trigger a re-export parameter_names_whitelist_auto_export = [ # auto export 'export_scene_settings', @@ -24,34 +25,29 @@ parameter_names_whitelist_auto_export = [ ] def get_setting_changes(): - print("get setting changes") + previous_common_settings = load_settings(".blenvy_common_settings_previous") + current_common_settings = load_settings(".blenvy_common_settings") + changed_common_settings_fields = changed_settings(previous_common_settings, current_common_settings, white_list=parameter_names_whitelist_common) + common_settings_changed = len(changed_common_settings_fields) > 0 - previous_common_settings = load_settings(".blenvy_common_settings_previous") - current_common_settings = load_settings(".blenvy_common_settings") - common_settings_changed = not are_settings_identical(previous_common_settings, current_common_settings, white_list=parameter_names_whitelist_common) + previous_export_settings = load_settings(".blenvy_export_settings_previous") + current_export_settings = load_settings(".blenvy_export_settings") + changed_export_settings_fields = changed_settings(previous_export_settings, current_export_settings, white_list=parameter_names_whitelist_auto_export) + export_settings_changed = len(changed_export_settings_fields) > 0 - previous_export_settings = load_settings(".blenvy_export_settings_previous") - current_export_settings = load_settings(".blenvy_export_settings") - export_settings_changed = not are_settings_identical(previous_export_settings, current_export_settings, white_list=parameter_names_whitelist_auto_export) + previous_gltf_settings = load_settings(".blenvy_gltf_settings_previous") + current_gltf_settings = load_settings(".blenvy_gltf_settings") + gltf_settings_changed = not are_settings_identical(previous_gltf_settings, current_gltf_settings) - previous_gltf_settings = load_settings(".blenvy_gltf_settings_previous") - current_gltf_settings = load_settings(".blenvy_gltf_settings") - print("previous_gltf_settings", previous_gltf_settings, "current_gltf_settings", current_gltf_settings) - gltf_settings_changed = not are_settings_identical(previous_gltf_settings, current_gltf_settings) + settings_changed = common_settings_changed or gltf_settings_changed or export_settings_changed - # write the new settings to the old settings - upsert_settings(".blenvy_common_settings_previous", current_common_settings, overwrite=True) - upsert_settings(".blenvy_export_settings_previous", current_export_settings, overwrite=True) - upsert_settings(".blenvy_gltf_settings_previous", current_gltf_settings, overwrite=True) + # if there were no setting before, it is new, we need export # TODO: do we even need this ? I guess in the case where both the previous & the new one are both none ? very unlikely, but still + if previous_common_settings is None: + settings_changed = True + if previous_export_settings is None: + settings_changed = True + if previous_gltf_settings is None: + settings_changed = True - print("common_settings_changed", common_settings_changed,"export_settings_changed", export_settings_changed, "gltf_settings_changed", gltf_settings_changed, ) - # if there were no setting before, it is new, we need export # TODO: do we even need this ? I guess in the case where both the previous & the new one are both none ? very unlikely, but still - if previous_common_settings is None: - return True - if previous_export_settings is None: - return True - if previous_gltf_settings is None: - return True - - return common_settings_changed or gltf_settings_changed or export_settings_changed + return settings_changed, current_common_settings, current_export_settings, current_gltf_settings diff --git a/tools/blenvy/add_ons/auto_export/levels/export_main_scenes.py b/tools/blenvy/add_ons/auto_export/levels/export_main_scenes.py index 22eab4f..747835f 100644 --- a/tools/blenvy/add_ons/auto_export/levels/export_main_scenes.py +++ b/tools/blenvy/add_ons/auto_export/levels/export_main_scenes.py @@ -41,11 +41,11 @@ def export_main_scene(scene, settings, blueprints_data): gltf_output_path = os.path.join(levels_path_full, scene.name) inject_blueprints_list_into_main_scene(scene, blueprints_data, settings) - print("main scene", scene) + """print("main scene", scene) for asset in scene.user_assets: print(" user asset", asset.name, asset.path) for asset in scene.generated_assets: - print(" generated asset", asset) + print(" generated asset", asset)""" """for blueprint in blueprints_data.blueprints_per_scenes[scene.name]: print("BLUEPRINT", blueprint)""" blueprint_instances_in_scene = blueprints_data.blueprint_instances_per_main_scene.get(scene.name, {}).keys() @@ -69,7 +69,7 @@ def export_main_scene(scene, settings, blueprints_data): # now also add the assets of the blueprints # TODO: wait no , these should not be a part of the (scene) local assets for asset in blueprint.collection.user_assets: - print("adding assets of blueprint", asset.name) + #print("adding assets of blueprint", asset.name) all_assets.append({"name": asset.name, "path": asset.path}) """for asset in auto_assets: @@ -81,8 +81,8 @@ def export_main_scene(scene, settings, blueprints_data): materials_exported_path = os.path.join(materials_path, f"{materials_library_name}{export_gltf_extension}") material_assets = [{"name": materials_library_name, "path": materials_exported_path}] # we also add the material library as an asset - scene["BlenvyAssets"] = assets_to_fake_ron(all_assets + [{"name": asset.name, "path": asset.path} for asset in scene.user_assets] + auto_assets + material_assets) - #scene["BlenvyAssets"] = assets_to_fake_ron([{'name':'foo', 'path':'bar'}]) + scene["BlueprintAssets"] = assets_to_fake_ron(all_assets + [{"name": asset.name, "path": asset.path} for asset in scene.user_assets] + auto_assets + material_assets) + #scene["BlueprintAssets"] = assets_to_fake_ron([{'name':'foo', 'path':'bar'}]) if export_separate_dynamic_and_static_objects: #print("SPLIT STATIC AND DYNAMIC") diff --git a/tools/blenvy/add_ons/auto_export/settings.py b/tools/blenvy/add_ons/auto_export/settings.py index dd6cfdb..8f3c45e 100644 --- a/tools/blenvy/add_ons/auto_export/settings.py +++ b/tools/blenvy/add_ons/auto_export/settings.py @@ -6,16 +6,15 @@ from blenvy.settings import load_settings, upsert_settings, generate_complete_se # list of settings we do NOT want to save settings_black_list = ['settings_save_enabled', 'dry_run'] -def save_settings(settings, context): +def save_settings(settings, context): if settings.settings_save_enabled: settings_dict = generate_complete_settings_dict(settings, AutoExportSettings, []) - print("save settings", settings, context, settings_dict) upsert_settings(settings.settings_save_path, {key: settings_dict[key] for key in settings_dict.keys() if key not in settings_black_list}, overwrite=True) class AutoExportSettings(PropertyGroup): settings_save_path = ".blenvy_export_settings" # where to store data in bpy.texts - settings_save_enabled = BoolProperty(name="settings save enabled", default=True) + settings_save_enabled: BoolProperty(name="settings save enabled", default=True) # type: ignore auto_export: BoolProperty( name='Auto export', @@ -119,7 +118,6 @@ class AutoExportSettings(PropertyGroup): self.settings_save_enabled = False # we disable auto_saving of our settings try: for setting in settings: - print("setting", setting, settings[setting]) setattr(self, setting, settings[setting]) except: pass # TODO: remove setting if there was a failure diff --git a/tools/blenvy/add_ons/bevy_components/settings.py b/tools/blenvy/add_ons/bevy_components/settings.py index 7ba4660..7e4edf9 100644 --- a/tools/blenvy/add_ons/bevy_components/settings.py +++ b/tools/blenvy/add_ons/bevy_components/settings.py @@ -1,7 +1,7 @@ import os import bpy from bpy_types import (PropertyGroup) -from bpy.props import (EnumProperty, PointerProperty, StringProperty, BoolProperty, CollectionProperty, IntProperty) +from bpy.props import (EnumProperty, PointerProperty, StringProperty, BoolProperty, CollectionProperty, FloatProperty) from blenvy.settings import load_settings, upsert_settings, generate_complete_settings_dict from .propGroups.prop_groups import generate_propertyGroups_for_components from .components.metadata import ensure_metadata_for_all_items @@ -18,7 +18,6 @@ def save_settings(settings, context): # helper function to deal with timer def toggle_watcher(self, context): - #print("toggling watcher", self.watcher_enabled, watch_schema, self, bpy.app.timers) if not self.watcher_enabled: try: bpy.app.timers.unregister(watch_schema) @@ -76,12 +75,12 @@ class ComponentsSettings(PropertyGroup): watcher_enabled: BoolProperty(name="Watcher_enabled", default=True, update=toggle_watcher)# type: ignore watcher_active: BoolProperty(name = "Flag for watcher status", default = False)# type: ignore - watcher_poll_frequency: IntProperty( + watcher_poll_frequency: FloatProperty( name="watcher poll frequency", description="frequency (s) at wich to poll for changes to the registry file", - min=1, - max=10, - default=1, + min=1.0, + max=10.0, + default=1.0, update=save_settings )# type: ignore @@ -134,7 +133,6 @@ class ComponentsSettings(PropertyGroup): self.settings_save_enabled = False # we disable auto_saving of our settings try: for setting in settings: - print("setting", setting, settings[setting]) setattr(self, setting, settings[setting]) except:pass try: diff --git a/tools/blenvy/assets/assets_scan.py b/tools/blenvy/assets/assets_scan.py index 9f41885..a628a05 100644 --- a/tools/blenvy/assets/assets_scan.py +++ b/tools/blenvy/assets/assets_scan.py @@ -19,14 +19,13 @@ def scan_assets(scene, blueprints_data, settings): for blueprint_name in blueprint_instance_names_for_scene: blueprint = blueprints_data.blueprints_per_name.get(blueprint_name, None) if blueprint is not None: - print("BLUEPRINT", blueprint) + #print("BLUEPRINT", blueprint) blueprint_exported_path = None if blueprint.local: blueprint_exported_path = os.path.join(relative_blueprints_path, f"{blueprint.name}{export_gltf_extension}") else: # get the injected path of the external blueprints blueprint_exported_path = blueprint.collection['Export_path'] if 'Export_path' in blueprint.collection else None - print("foo", dict(blueprint.collection)) if blueprint_exported_path is not None: blueprint_assets_list.append({"name": blueprint.name, "path": blueprint_exported_path}) @@ -45,7 +44,7 @@ def scan_assets(scene, blueprints_data, settings): assets_list_name = f"assets_{scene.name}" assets_list_data = {"blueprints": json.dumps(blueprint_assets_list), "sounds":[], "images":[]} - print("blueprint assets", blueprint_assets_list) + #print("blueprint assets", blueprint_assets_list) def get_userTextures(): diff --git a/tools/blenvy/assets/ui.py b/tools/blenvy/assets/ui.py index d8c7e09..b4984aa 100644 --- a/tools/blenvy/assets/ui.py +++ b/tools/blenvy/assets/ui.py @@ -42,9 +42,7 @@ def draw_assets(layout, name, title, asset_registry, target_type, target_name, e if editable: row = panel.row() #panel.separator() - print("here", user_assets) for asset in user_assets: - print("asset", asset) row = panel.row() split = row.split(factor=nesting_indent) col = split.column() diff --git a/tools/blenvy/blueprints/blueprint_helpers.py b/tools/blenvy/blueprints/blueprint_helpers.py index b1f5f76..633eeca 100644 --- a/tools/blenvy/blueprints/blueprint_helpers.py +++ b/tools/blenvy/blueprints/blueprint_helpers.py @@ -17,13 +17,12 @@ def find_blueprints_not_on_disk(blueprints, folder_path, extension): def check_if_blueprint_on_disk(scene_name, folder_path, extension): gltf_output_path = os.path.join(folder_path, scene_name + extension) found = os.path.exists(gltf_output_path) and os.path.isfile(gltf_output_path) - print("level", scene_name, "found", found, "path", gltf_output_path) return found def inject_export_path_into_internal_blueprints(internal_blueprints, blueprints_path, gltf_extension): for blueprint in internal_blueprints: blueprint_exported_path = os.path.join(blueprints_path, f"{blueprint.name}{gltf_extension}") - print("injecting blueprint path", blueprint_exported_path, "for", blueprint.name) + # print("injecting blueprint path", blueprint_exported_path, "for", blueprint.name) blueprint.collection["export_path"] = blueprint_exported_path @@ -44,14 +43,14 @@ def inject_blueprints_list_into_main_scene(scene, blueprints_data, settings): for blueprint_name in blueprint_instance_names_for_scene: blueprint = blueprints_data.blueprints_per_name.get(blueprint_name, None) if blueprint is not None: - print("BLUEPRINT", blueprint) + #print("BLUEPRINT", blueprint) blueprint_exported_path = None if blueprint.local: blueprint_exported_path = os.path.join(blueprints_path, f"{blueprint.name}{export_gltf_extension}") else: # get the injected path of the external blueprints blueprint_exported_path = blueprint.collection['Export_path'] if 'Export_path' in blueprint.collection else None - print("foo", dict(blueprint.collection)) + #print("foo", dict(blueprint.collection)) if blueprint_exported_path is not None: blueprint_assets_list.append({"name": blueprint.name, "path": blueprint_exported_path, "type": "MODEL", "internal": True}) @@ -61,9 +60,7 @@ def inject_blueprints_list_into_main_scene(scene, blueprints_data, settings): assets_list_name = f"assets_{scene.name}" scene["assets"] = json.dumps(blueprint_assets_list) - print("blueprint assets", blueprint_assets_list) - """add_scene_property(scene, assets_list_name, assets_list_data) - """ + #print("blueprint assets", blueprint_assets_list) def remove_blueprints_list_from_main_scene(scene): assets_list = None diff --git a/tools/blenvy/core/blenvy_manager.py b/tools/blenvy/core/blenvy_manager.py index 511bf68..001b250 100644 --- a/tools/blenvy/core/blenvy_manager.py +++ b/tools/blenvy/core/blenvy_manager.py @@ -7,31 +7,25 @@ import blenvy.add_ons.auto_export.settings as auto_export_settings import blenvy.add_ons.bevy_components.settings as component_settings - # list of settings we do NOT want to save -settings_black_list = ['settings_save_enabled', 'main_scene_selector', 'main_scenes', 'main_scenes_index', 'library_scene_selector', 'library_scenes', 'library_scenes_index', - #'project_root_path_full', 'assets_path_full', '' - ] +settings_black_list = ['settings_save_enabled', 'main_scene_selector', 'library_scene_selector'] def save_settings(settings, context): if settings.settings_save_enabled: settings_dict = generate_complete_settings_dict(settings, BlenvyManager, []) - print("save settings", settings, context, settings_dict) - # upsert_settings(settings.settings_save_path, {key: settings_dict[key] for key in settings_dict.keys() if key not in settings_black_list}) + raw_settings = {key: settings_dict[key] for key in settings_dict.keys() if key not in settings_black_list} + # we need to inject the main & library scene names as they are computed properties, not blender ones + raw_settings['main_scenes_names'] = settings.main_scenes_names + raw_settings['library_scenes_names'] = settings.library_scenes_names + upsert_settings(settings.settings_save_path, raw_settings, overwrite=True) -def update_scene_lists(blenvy, context): - blenvy.main_scene_names = [scene.name for scene in blenvy.main_scenes] # FIXME: unsure - blenvy.library_scene_names = [scene.name for scene in blenvy.library_scenes] # FIXME: unsure - upsert_settings(blenvy.settings_save_path, {"main_scene_names": [scene.name for scene in blenvy.main_scenes]}) - upsert_settings(blenvy.settings_save_path, {"library_scene_names": [scene.name for scene in blenvy.library_scenes]}) - -def update_asset_folders(blenvy, context): +def update_asset_folders(settings, context): asset_path_names = ['project_root_path', 'assets_path', 'blueprints_path', 'levels_path', 'materials_path'] for asset_path_name in asset_path_names: - upsert_settings(blenvy.settings_save_path, {asset_path_name: getattr(blenvy, asset_path_name)}) + upsert_settings(settings.settings_save_path, {asset_path_name: getattr(settings, asset_path_name)}) + settings_dict = generate_complete_settings_dict(settings, BlenvyManager, []) + upsert_settings(settings.settings_save_path, {key: settings_dict[key] for key in settings_dict.keys() if key not in settings_black_list}, overwrite=True) -def update_mode(blenvy, context): - upsert_settings(blenvy.settings_save_path, {"mode": blenvy.mode }) def is_scene_already_in_use(self, scene): try: @@ -45,7 +39,7 @@ def is_scene_already_in_use(self, scene): class BlenvyManager(PropertyGroup): settings_save_path = ".blenvy_common_settings" # where to store data in bpy.texts - settings_save_enabled = BoolProperty(name="settings save enabled", default=True) + settings_save_enabled: BoolProperty(name="settings save enabled", default=True) # type: ignore mode: EnumProperty( items=( @@ -56,14 +50,15 @@ class BlenvyManager(PropertyGroup): ('SETTINGS', "Settings", ""), ('TOOLS', "Tools", ""), ), - update=update_mode + default="SETTINGS", + update=save_settings ) # type: ignore project_root_path: StringProperty( name = "Project Root Path", description="The root folder of your (Bevy) project (not assets!)", default='../', - update= update_asset_folders + update= save_settings ) # type: ignore # computed property for the absolute path of assets @@ -76,7 +71,7 @@ class BlenvyManager(PropertyGroup): description='The root folder for all exports(relative to the root folder/path) Defaults to "assets" ', default='./assets', options={'HIDDEN'}, - update= update_asset_folders + update= save_settings ) # type: ignore # computed property for the absolute path of assets @@ -88,7 +83,7 @@ class BlenvyManager(PropertyGroup): name='Blueprints path', description='path to export the blueprints to (relative to the assets folder)', default='blueprints', - update= update_asset_folders + update= save_settings ) # type: ignore # computed property for the absolute path of blueprints @@ -100,7 +95,7 @@ class BlenvyManager(PropertyGroup): name='Levels path', description='path to export the levels (main scenes) to (relative to the assets folder)', default='levels', - update= update_asset_folders + update= save_settings ) # type: ignore # computed property for the absolute path of blueprints @@ -112,7 +107,7 @@ class BlenvyManager(PropertyGroup): name='Materials path', description='path to export the materials libraries to (relative to the assets folder)', default='materials', - update= update_asset_folders + update= save_settings ) # type: ignore # computed property for the absolute path of blueprints @@ -124,8 +119,8 @@ class BlenvyManager(PropertyGroup): auto_export: PointerProperty(type=auto_export_settings.AutoExportSettings) # type: ignore components: PointerProperty(type=component_settings.ComponentsSettings) # type: ignore - main_scene_selector: PointerProperty(type=bpy.types.Scene, name="main scene", description="main_scene_picker", poll=is_scene_already_in_use)# type: ignore - library_scene_selector: PointerProperty(type=bpy.types.Scene, name="library scene", description="library_scene_picker", poll=is_scene_already_in_use)# type: ignore + main_scene_selector: PointerProperty(type=bpy.types.Scene, name="main scene", description="main_scene_picker", poll=is_scene_already_in_use, update=save_settings)# type: ignore + library_scene_selector: PointerProperty(type=bpy.types.Scene, name="library scene", description="library_scene_picker", poll=is_scene_already_in_use, update=save_settings)# type: ignore @property def main_scenes(self): @@ -171,14 +166,22 @@ class BlenvyManager(PropertyGroup): print("LOAD SETTINGS") settings = load_settings(self.settings_save_path) if settings is not None: - if "mode" in settings: + self.settings_save_enabled = False # we disable auto_saving of our settings + try: + for setting in settings: + print("setting", setting, settings[setting]) + setattr(self, setting, settings[setting]) + except:pass + """if "mode" in settings: self.mode = settings["mode"] asset_path_names = ['project_root_path', 'assets_path', 'blueprints_path', 'levels_path', 'materials_path'] for asset_path_name in asset_path_names: if asset_path_name in settings: - setattr(self, asset_path_name, settings[asset_path_name]) - + setattr(self, asset_path_name, settings[asset_path_name])""" + + self.settings_save_enabled = True + # now load auto_export settings self.auto_export.load_settings() diff --git a/tools/blenvy/core/ui/scenes_list.py b/tools/blenvy/core/ui/scenes_list.py index 855c04e..65501a9 100644 --- a/tools/blenvy/core/ui/scenes_list.py +++ b/tools/blenvy/core/ui/scenes_list.py @@ -28,6 +28,8 @@ class BLENVY_OT_scenes_list_actions(Operator): def invoke(self, context, event): if self.action == 'REMOVE': bpy.data.scenes[self.scene_name].blenvy_scene_type = 'None' + context.window_manager.blenvy.main_scene_selector = None # we use these to force update/save the list of main/library scenes + context.window_manager.blenvy.library_scene_selector = None # we use these to force update/save the list of main/library scenes """info = 'Item "%s" removed from list' % (target[idx].name) target.remove(idx) @@ -49,9 +51,9 @@ class BLENVY_OT_scenes_list_actions(Operator): print("adding scene", scene_to_add) if self.scene_type == "LEVEL": - context.window_manager.blenvy.main_scene_selector = None + context.window_manager.blenvy.main_scene_selector = None # we use these to force update/save the list of main/library scenes else: - context.window_manager.blenvy.library_scene_selector = None + context.window_manager.blenvy.library_scene_selector = None # we use these to force update/save the list of main/library scenes #setattr(source, target_index, len(target) - 1) diff --git a/tools/blenvy/settings.py b/tools/blenvy/settings.py index 2def404..87ac93e 100644 --- a/tools/blenvy/settings.py +++ b/tools/blenvy/settings.py @@ -70,7 +70,6 @@ def are_settings_identical(old, new, white_list=None): if old is not None and new is None: return False - #print("TUTU", old_items, new_items) old_items = sorted(old.items()) new_items = sorted(new.items()) @@ -85,4 +84,34 @@ def are_settings_identical(old, new, white_list=None): old_items = sorted(old_items_override.items()) new_items = sorted(new_items_override.items()) - return old_items == new_items \ No newline at end of file + return old_items == new_items + + +# if one of the changed settings is not in the white list, it gets discarded +def changed_settings(old, new, white_list=[]): + if old is None and new is None: + return [] + if old is None and new is not None: + return new.keys() + if old is not None and new is None: + return [] + + old_items = sorted(old.items()) + new_items = sorted(new.items()) + + result = [] + old_keys = list(old.keys()) + new_keys =list(new.keys()) + added = list(set(new_keys) - set(old_keys)) + removed = list(set(old_keys) - set(new_keys)) + + result += added + result += removed + for key in new.keys(): + if key in old: + if new[key] != old[key]: + result.append(key) + + + + return [key for key in list(set(result)) if key in white_list] diff --git a/tools/blenvy/tests/test_bevy_integration.py b/tools/blenvy/tests/test_bevy_integration.py index 532c613..498eb0b 100644 --- a/tools/blenvy/tests/test_bevy_integration.py +++ b/tools/blenvy/tests/test_bevy_integration.py @@ -121,9 +121,9 @@ def test_export_complex(setup_data): user_asset.path = "audio/fake.mp3" # we have to cheat, since we cannot rely on the data injected when saving the library file - bpy.data.collections["External_blueprint"]["export_path"] = "blueprints/External_blueprint.glb" - bpy.data.collections["External_blueprint2"]["export_path"] = "blueprints/External_blueprint2.glb" - bpy.data.collections["External_blueprint3"]["export_path"] = "blueprints/External_blueprint3.glb" + #bpy.data.collections["External_blueprint"]["export_path"] = "blueprints/External_blueprint.glb" + #bpy.data.collections["External_blueprint2"]["export_path"] = "blueprints/External_blueprint2.glb" + #bpy.data.collections["External_blueprint3"]["export_path"] = "blueprints/External_blueprint3.glb" prepare_and_export()