From 382f37be7424ec46e64c0fc7977c7779930d2221 Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Mon, 20 May 2024 02:06:26 +0200 Subject: [PATCH] feat(blenvy): reorganising & upgrade of auto_export change detection * added new helpers to detect changes to project & settings * updated storage names * not using operator anymore * lots of related changes --- tools/blenvy/TODO.md | 4 +- tools/blenvy/assets/operators.py | 3 +- tools/blenvy/gltf_auto_export/__init__.py | 7 +- .../get_standard_exporter_settings.py | 2 +- .../gltf_auto_export/auto_export/operators.py | 10 +-- .../auto_export/prepare_and_export.py | 19 ++--- .../auto_export/project_diff.py | 28 +++++- .../auto_export/settings_diff.py | 85 +++++++++++++++++++ .../gltf_auto_export/auto_export/tracker.py | 6 +- .../helpers/serialize_scene.py | 2 +- .../helpers/to_remove_later.py | 2 +- tools/blenvy/gltf_auto_export/settings.py | 7 ++ tools/blenvy/tests/test_bevy_integration.py | 2 +- .../tests/test_bevy_integration_prepare.py | 2 +- tools/blenvy/tests/test_changed_parameters.py | 4 +- tools/blenvy/tests/test_helpers.py | 2 +- 16 files changed, 152 insertions(+), 33 deletions(-) create mode 100644 tools/blenvy/gltf_auto_export/auto_export/settings_diff.py diff --git a/tools/blenvy/TODO.md b/tools/blenvy/TODO.md index ef87791..7334435 100644 --- a/tools/blenvy/TODO.md +++ b/tools/blenvy/TODO.md @@ -9,6 +9,7 @@ Auto export - root path => relative to blend file path - asset path => relative to root path - blueprints/levels/blueprints path => relative to assets path + - [ ] add error handling for de/serialization of project, so that in case of error, the previous saved serialized project is thrown away - move out some parameters from auto export to a higher level (as they are now used in multiple places) @@ -81,4 +82,5 @@ General issues: - this can cause an issue for assets list "parent" - "parents" can only be blueprints - they normally need/have unique export paths (otherwise, user error, perhaps show it ?) - - perhaps a simple hashing of the parent's path would be enought \ No newline at end of file + - perhaps a simple hashing of the parent's path would be enought + - addon-prefs => settings \ No newline at end of file diff --git a/tools/blenvy/assets/operators.py b/tools/blenvy/assets/operators.py index c782ea6..4c1f850 100644 --- a/tools/blenvy/assets/operators.py +++ b/tools/blenvy/assets/operators.py @@ -200,12 +200,11 @@ class OT_test_bevy_assets(Operator): def execute(self, context): blenvy = context.window_manager.blenvy + settings = blenvy blueprints_registry = context.window_manager.blueprints_registry blueprints_registry.add_blueprints_data() blueprints_data = blueprints_registry.blueprints_data - settings = {"blueprints_path": "blueprints", "export_gltf_extension": ".glb"} - settings = SimpleNamespace(**settings) for scene in blenvy.main_scenes: assets_hierarchy = get_main_scene_assets_tree(scene, blueprints_data, settings) scene["assets"] = json.dumps(assets_hierarchy) diff --git a/tools/blenvy/gltf_auto_export/__init__.py b/tools/blenvy/gltf_auto_export/__init__.py index 515434e..f3459b7 100644 --- a/tools/blenvy/gltf_auto_export/__init__.py +++ b/tools/blenvy/gltf_auto_export/__init__.py @@ -13,9 +13,10 @@ def cleanup_file(): def gltf_post_export_callback(data): #print("post_export", data) + blenvy = bpy.context.window_manager.blenvy bpy.context.window_manager.auto_export_tracker.export_finished() - gltf_settings_backup = bpy.context.window_manager.gltf_settings_backup + gltf_settings_backup = blenvy.auto_export.gltf_settings_backup gltf_filepath = data["gltf_filepath"] gltf_export_id = data['gltf_export_id'] if gltf_export_id == "gltf_auto_export": @@ -30,7 +31,7 @@ def gltf_post_export_callback(data): scene = bpy.context.scene if "glTF2ExportSettings" in scene: settings = scene["glTF2ExportSettings"] - export_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings") + export_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings") # now write new settings export_settings.clear() @@ -42,7 +43,7 @@ def gltf_post_export_callback(data): else: if "glTF2ExportSettings" in scene: del scene["glTF2ExportSettings"] - bpy.context.window_manager.gltf_settings_backup = "" + blenvy.auto_export.gltf_settings_backup = "" # the absurd length one has to go through to RESET THE OPERATOR because it has global state !!!!! AAAAAHHH last_operator = bpy.context.window_manager.auto_export_tracker.last_operator diff --git a/tools/blenvy/gltf_auto_export/auto_export/get_standard_exporter_settings.py b/tools/blenvy/gltf_auto_export/auto_export/get_standard_exporter_settings.py index c3eaf04..21dffc0 100644 --- a/tools/blenvy/gltf_auto_export/auto_export/get_standard_exporter_settings.py +++ b/tools/blenvy/gltf_auto_export/auto_export/get_standard_exporter_settings.py @@ -2,7 +2,7 @@ import bpy import json def get_standard_exporter_settings(): - standard_gltf_exporter_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else None + standard_gltf_exporter_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else None if standard_gltf_exporter_settings != None: try: standard_gltf_exporter_settings = json.loads(standard_gltf_exporter_settings.as_string()) diff --git a/tools/blenvy/gltf_auto_export/auto_export/operators.py b/tools/blenvy/gltf_auto_export/auto_export/operators.py index 84781ec..4c7c079 100644 --- a/tools/blenvy/gltf_auto_export/auto_export/operators.py +++ b/tools/blenvy/gltf_auto_export/auto_export/operators.py @@ -135,10 +135,10 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences):#, ExportHelper): return True # compare both the auto export settings & the gltf settings previous_auto_settings = bpy.data.texts[".gltf_auto_export_settings_previous"] if ".gltf_auto_export_settings_previous" in bpy.data.texts else None - previous_gltf_settings = bpy.data.texts[".gltf_auto_export_gltf_settings_previous"] if ".gltf_auto_export_gltf_settings_previous" in bpy.data.texts else None + previous_gltf_settings = bpy.data.texts[".blenvy_gltf_settings_previous"] if ".blenvy_gltf_settings_previous" in bpy.data.texts else None current_auto_settings = bpy.data.texts[".gltf_auto_export_settings"] if ".gltf_auto_export_settings" in bpy.data.texts else None - current_gltf_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else None + current_gltf_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else None #check if params have changed @@ -149,10 +149,10 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences):#, ExportHelper): changed = True elif previous_gltf_settings == None: #print("previous gltf settings missing, exporting") - previous_gltf_settings = bpy.data.texts.new(".gltf_auto_export_gltf_settings_previous") + previous_gltf_settings = bpy.data.texts.new(".blenvy_gltf_settings_previous") previous_gltf_settings.write(json.dumps({})) if current_gltf_settings == None: - current_gltf_settings = bpy.data.texts.new(".gltf_auto_export_gltf_settings") + current_gltf_settings = bpy.data.texts.new(".blenvy_gltf_settings") current_gltf_settings.write(json.dumps({})) changed = True @@ -177,7 +177,7 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences):#, ExportHelper): previous_auto_settings.write(current_auto_settings.as_string()) # TODO : check if this is always valid if current_gltf_settings != None: - previous_gltf_settings = bpy.data.texts[".gltf_auto_export_gltf_settings_previous"] if ".gltf_auto_export_gltf_settings_previous" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings_previous") + previous_gltf_settings = bpy.data.texts[".blenvy_gltf_settings_previous"] if ".blenvy_gltf_settings_previous" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings_previous") previous_gltf_settings.clear() previous_gltf_settings.write(current_gltf_settings.as_string()) diff --git a/tools/blenvy/gltf_auto_export/auto_export/prepare_and_export.py b/tools/blenvy/gltf_auto_export/auto_export/prepare_and_export.py index dede857..37b8693 100644 --- a/tools/blenvy/gltf_auto_export/auto_export/prepare_and_export.py +++ b/tools/blenvy/gltf_auto_export/auto_export/prepare_and_export.py @@ -1,27 +1,26 @@ import bpy -from . import project_diff +from .project_diff import get_changes_per_scene, project_diff, serialize_current from ...settings import are_settings_identical -from . import auto_export +from .auto_export import auto_export +from .settings_diff import get_setting_changes # prepare export by gather the changes to the scenes & settings -def prepare_export(): +def prepare_and_export(): blenvy = bpy.context.window_manager.blenvy bpy.context.window_manager.auto_export_tracker.disable_change_detection() auto_export_settings = blenvy.auto_export if auto_export_settings.auto_export: # only do the actual exporting if auto export is actually enabled + # determine changed objects - previous_serialized_scene = None - current_serialized_scene = None - changes_per_scene = project_diff(previous_serialized_scene, current_serialized_scene) + per_scene_changes = get_changes_per_scene() # determine changed parameters - previous_settings = None - current_settings = None - params_changed = are_settings_identical(previous_settings, current_settings) + setting_changes = get_setting_changes() # do the actual export - auto_export(changes_per_scene, params_changed, blenvy) + auto_export(per_scene_changes, setting_changes, blenvy) # 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") diff --git a/tools/blenvy/gltf_auto_export/auto_export/project_diff.py b/tools/blenvy/gltf_auto_export/auto_export/project_diff.py index d8d5383..d8be240 100644 --- a/tools/blenvy/gltf_auto_export/auto_export/project_diff.py +++ b/tools/blenvy/gltf_auto_export/auto_export/project_diff.py @@ -22,7 +22,8 @@ def foo(): previous_stored.clear() previous_stored.write(json.dumps(current)) -def project_diff(previous, current): + +def serialize_current(): # sigh... you need to save & reset the frame otherwise it saves the values AT THE CURRENT FRAME WHICH CAN DIFFER ACROSS SCENES current_frames = [scene.frame_current for scene in bpy.data.scenes] for scene in bpy.data.scenes: @@ -39,11 +40,36 @@ def project_diff(previous, current): # reset previous frames for (index, scene) in enumerate(bpy.data.scenes): scene.frame_set(int(current_frames[index])) + + return current +def get_changes_per_scene(): + current = serialize_current() + + previous_stored = bpy.data.texts[".blenvy.project.serialized"] if ".blenvy.project.serialized" in bpy.data.texts else None + if previous_stored == None: + previous_stored = bpy.data.texts.new(".blenvy.project.serialized") + previous_stored.write(json.dumps(current)) + return {} + + previous = json.loads(previous_stored.as_string()) + + # determin changes + changes_per_scene = project_diff(previous, current) + + # save the current project as previous + previous_stored.clear() + previous_stored.write(json.dumps(current)) + return changes_per_scene + + +def project_diff(previous, current): + changes_per_scene = {} # TODO : how do we deal with changed scene names ??? for scene in current: + print("SCENE", scene) previous_object_names = list(previous[scene].keys()) current_object_names =list(current[scene].keys()) added = list(set(current_object_names) - set(previous_object_names)) diff --git a/tools/blenvy/gltf_auto_export/auto_export/settings_diff.py b/tools/blenvy/gltf_auto_export/auto_export/settings_diff.py new file mode 100644 index 0000000..18c0089 --- /dev/null +++ b/tools/blenvy/gltf_auto_export/auto_export/settings_diff.py @@ -0,0 +1,85 @@ +import bpy + +from ...settings import are_settings_identical, load_settings + +# which settings are specific to auto_export # TODO: can we infer this ? +auto_export_parameter_names = [ + 'project_root_path', + 'assets_path', + 'blueprints_path', + 'levels_path', + 'materials_path', + #'main_scene_names', + #'library_scene_names', + + 'export_scene_settings', + 'export_blueprints', + 'export_separate_dynamic_and_static_objects', + 'export_materials_library', + 'collection_instances_combine_mode', + 'export_marked_assets' +] + +def get_setting_changes(): + 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_export_settings = load_settings(".blenvy_export_settings_previous") + current_export_settings = load_settings(".blenvy_export_settings") + auto_export_settings_changed = not are_settings_identical(previous_export_settings, current_export_settings) + + + return {} + +def did_export_settings_change(self): + return True + # compare both the auto export settings & the gltf settings + previous_auto_settings = bpy.data.texts[".gltf_auto_export_settings_previous"] if ".gltf_auto_export_settings_previous" in bpy.data.texts else None + previous_gltf_settings = bpy.data.texts[".blenvy_gltf_settings_previous"] if ".blenvy_gltf_settings_previous" in bpy.data.texts else None + + current_auto_settings = bpy.data.texts[".gltf_auto_export_settings"] if ".gltf_auto_export_settings" in bpy.data.texts else None + current_gltf_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else None + + #check if params have changed + + # if there were no setting before, it is new, we need export + changed = False + if previous_auto_settings == None: + #print("previous settings missing, exporting") + changed = True + elif previous_gltf_settings == None: + #print("previous gltf settings missing, exporting") + previous_gltf_settings = bpy.data.texts.new(".blenvy_gltf_settings_previous") + previous_gltf_settings.write(json.dumps({})) + if current_gltf_settings == None: + current_gltf_settings = bpy.data.texts.new(".blenvy_gltf_settings") + current_gltf_settings.write(json.dumps({})) + + changed = True + + else: + auto_settings_changed = sorted(json.loads(previous_auto_settings.as_string()).items()) != sorted(json.loads(current_auto_settings.as_string()).items()) if current_auto_settings != None else False + gltf_settings_changed = sorted(json.loads(previous_gltf_settings.as_string()).items()) != sorted(json.loads(current_gltf_settings.as_string()).items()) if current_gltf_settings != None else False + + """print("auto settings previous", sorted(json.loads(previous_auto_settings.as_string()).items())) + print("auto settings current", sorted(json.loads(current_auto_settings.as_string()).items())) + print("auto_settings_changed", auto_settings_changed) + + print("gltf settings previous", sorted(json.loads(previous_gltf_settings.as_string()).items())) + print("gltf settings current", sorted(json.loads(current_gltf_settings.as_string()).items())) + print("gltf_settings_changed", gltf_settings_changed)""" + + changed = auto_settings_changed or gltf_settings_changed + # now write the current settings to the "previous settings" + if current_auto_settings != None: + previous_auto_settings = bpy.data.texts[".gltf_auto_export_settings_previous"] if ".gltf_auto_export_settings_previous" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_settings_previous") + previous_auto_settings.clear() + previous_auto_settings.write(current_auto_settings.as_string()) # TODO : check if this is always valid + + if current_gltf_settings != None: + previous_gltf_settings = bpy.data.texts[".blenvy_gltf_settings_previous"] if ".blenvy_gltf_settings_previous" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings_previous") + previous_gltf_settings.clear() + previous_gltf_settings.write(current_gltf_settings.as_string()) + + return changed \ No newline at end of file diff --git a/tools/blenvy/gltf_auto_export/auto_export/tracker.py b/tools/blenvy/gltf_auto_export/auto_export/tracker.py index e34bc5e..edc5e1a 100644 --- a/tools/blenvy/gltf_auto_export/auto_export/tracker.py +++ b/tools/blenvy/gltf_auto_export/auto_export/tracker.py @@ -4,6 +4,8 @@ import bpy from bpy.types import (PropertyGroup) from bpy.props import (PointerProperty, IntProperty, StringProperty) +from .prepare_and_export import prepare_and_export + from ..constants import TEMPSCENE_PREFIX class AutoExportTracker(PropertyGroup): @@ -51,9 +53,7 @@ class AutoExportTracker(PropertyGroup): def save_handler(cls, scene, depsgraph): print("-------------") print("saved", bpy.data.filepath) - # auto_export(changes_per_scene, export_parameters_changed) - bpy.ops.export_scenes.auto_gltf(direct_mode= True) - + prepare_and_export() # (re)set a few things after exporting # reset wether the gltf export paramters were changed since the last save cls.export_params_changed = False diff --git a/tools/blenvy/gltf_auto_export/helpers/serialize_scene.py b/tools/blenvy/gltf_auto_export/helpers/serialize_scene.py index a88314f..341836a 100644 --- a/tools/blenvy/gltf_auto_export/helpers/serialize_scene.py +++ b/tools/blenvy/gltf_auto_export/helpers/serialize_scene.py @@ -228,6 +228,6 @@ def serialize_scene(): print("") print("data json", json.dumps(data))""" - return json.dumps(data) + return data # json.dumps(data) diff --git a/tools/blenvy/gltf_auto_export/helpers/to_remove_later.py b/tools/blenvy/gltf_auto_export/helpers/to_remove_later.py index 2d69f86..8a5198b 100644 --- a/tools/blenvy/gltf_auto_export/helpers/to_remove_later.py +++ b/tools/blenvy/gltf_auto_export/helpers/to_remove_later.py @@ -296,7 +296,7 @@ def duplicate_object2(object, original_name): settings = scene["glTF2ExportSettings"] formatted_settings = dict(settings) - export_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings") + export_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings") #check if params have changed bpy.context.window_manager.gltf_settings_changed = sorted(json.loads(export_settings.as_string()).items()) != sorted(formatted_settings.items()) diff --git a/tools/blenvy/gltf_auto_export/settings.py b/tools/blenvy/gltf_auto_export/settings.py index 95bc062..31f0230 100644 --- a/tools/blenvy/gltf_auto_export/settings.py +++ b/tools/blenvy/gltf_auto_export/settings.py @@ -71,3 +71,10 @@ class AutoExportSettings(PropertyGroup): description='Collections that have been marked as assets will be systematically exported, even if not in use in another scene', default=True ) # type: ignore + + + # special property for gltf settings + gltf_settings_backup: StringProperty( + name="gltf settings backup", + description="backup for existing gltf settings so that we can restore them" + ) # type: ignore diff --git a/tools/blenvy/tests/test_bevy_integration.py b/tools/blenvy/tests/test_bevy_integration.py index 528d9e6..5bbe3e2 100644 --- a/tools/blenvy/tests/test_bevy_integration.py +++ b/tools/blenvy/tests/test_bevy_integration.py @@ -91,7 +91,7 @@ def test_export_complex(setup_data): stored_auto_settings.write(json.dumps(export_props)) # and store settings for the gltf part - stored_gltf_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings") + stored_gltf_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings") stored_gltf_settings.clear() stored_gltf_settings.write(json.dumps(gltf_settings)) diff --git a/tools/blenvy/tests/test_bevy_integration_prepare.py b/tools/blenvy/tests/test_bevy_integration_prepare.py index 2a3a36a..812e4c7 100644 --- a/tools/blenvy/tests/test_bevy_integration_prepare.py +++ b/tools/blenvy/tests/test_bevy_integration_prepare.py @@ -45,7 +45,7 @@ def test_export_external_blueprints(setup_data): stored_auto_settings.write(json.dumps(export_props)) # and store settings for the gltf part - stored_gltf_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings") + stored_gltf_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings") stored_gltf_settings.clear() stored_gltf_settings.write(json.dumps(gltf_settings)) diff --git a/tools/blenvy/tests/test_changed_parameters.py b/tools/blenvy/tests/test_changed_parameters.py index 53a314b..b83656a 100644 --- a/tools/blenvy/tests/test_changed_parameters.py +++ b/tools/blenvy/tests/test_changed_parameters.py @@ -133,7 +133,7 @@ def test_export_changed_parameters(setup_data): "export_optimize_animation_size": False } # and store settings for the gltf part - stored_gltf_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings") + stored_gltf_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings") stored_gltf_settings.clear() stored_gltf_settings.write(json.dumps(gltf_settings)) @@ -177,7 +177,7 @@ def test_export_changed_parameters(setup_data): "export_optimize_animation_size": True } - stored_gltf_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings") + stored_gltf_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings") stored_gltf_settings.clear() stored_gltf_settings.write(json.dumps(gltf_settings)) diff --git a/tools/blenvy/tests/test_helpers.py b/tools/blenvy/tests/test_helpers.py index c4ad5bf..c7c7738 100644 --- a/tools/blenvy/tests/test_helpers.py +++ b/tools/blenvy/tests/test_helpers.py @@ -20,7 +20,7 @@ def prepare_auto_export(auto_export_overrides={}, gltf_export_settings = {"expor gltf_settings = gltf_export_settings # and store settings for the gltf part - stored_gltf_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings") + stored_gltf_settings = bpy.data.texts[".blenvy_gltf_settings"] if ".blenvy_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".blenvy_gltf_settings") stored_gltf_settings.clear() stored_gltf_settings.write(json.dumps(gltf_settings))