feat(auto_export): MORE experimenting, cleanup & analysis attempts

* moved temp scene prefix to new 'constants' file, updated code accordingly
 * fixed, updated & refactored handling of auto export & gltf parameters
 * added additional tests to changed_parameters
 * added display of changes since last save in new side tab
 * more investigation & fix attempts for change detection...
 * various related tweaks & cleanups
This commit is contained in:
kaosat.dev 2024-04-08 23:41:17 +02:00
parent 64fd308fd3
commit cf4673c1e3
12 changed files with 163 additions and 47 deletions

View File

@ -5,6 +5,7 @@ import traceback
from .export_main_scenes import export_main_scene from .export_main_scenes import export_main_scene
from .export_blueprints import check_if_blueprint_on_disk, check_if_blueprints_exist, export_blueprints_from_collections from .export_blueprints import check_if_blueprint_on_disk, check_if_blueprints_exist, export_blueprints_from_collections
from .get_standard_exporter_settings import get_standard_exporter_settings
from ..helpers.helpers_scenes import (get_scenes, ) from ..helpers.helpers_scenes import (get_scenes, )
from ..helpers.helpers_collections import (get_collections_in_library, get_exportable_collections, get_collections_per_scene, find_collection_ascendant_target_collection) from ..helpers.helpers_collections import (get_collections_in_library, get_exportable_collections, get_collections_per_scene, find_collection_ascendant_target_collection)
@ -34,9 +35,8 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs) [main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
# standard gltf export settings are stored differently # standard gltf export settings are stored differently
standard_gltf_exporter_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")
print("standard_gltf_exporter_settings", standard_gltf_exporter_settings.as_string()) standard_gltf_exporter_settings = get_standard_exporter_settings()
standard_gltf_exporter_settings = json.loads(standard_gltf_exporter_settings.as_string())
print("main scenes", main_scene_names, "library_scenes", library_scene_names) print("main scenes", main_scene_names, "library_scenes", library_scene_names)
print("export_output_folder", export_output_folder) print("export_output_folder", export_output_folder)

View File

@ -1,6 +1,7 @@
import os import os
import bpy import bpy
from ..constants import TEMPSCENE_PREFIX
from ..helpers.generate_and_export import generate_and_export from ..helpers.generate_and_export import generate_and_export
from .export_gltf import (generate_gltf_export_preferences) from .export_gltf import (generate_gltf_export_preferences)
from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into
@ -24,7 +25,7 @@ def export_collections(collections, folder_path, library_scene, addon_prefs, glt
collection = bpy.data.collections[collection_name] collection = bpy.data.collections[collection_name]
generate_and_export( generate_and_export(
addon_prefs, addon_prefs,
temp_scene_name="__temp_scene_"+collection.name, temp_scene_name=TEMPSCENE_PREFIX+collection.name,
export_settings=export_settings, export_settings=export_settings,
gltf_output_path=gltf_output_path, gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(collection, temp_collection, library_collections=library_collections, addon_prefs=addon_prefs), tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(collection, temp_collection, library_collections=library_collections, addon_prefs=addon_prefs),

View File

@ -2,6 +2,7 @@ import json
import os import os
import bpy import bpy
from .get_standard_exporter_settings import get_standard_exporter_settings
from .preferences import (AutoExportGltfPreferenceNames) from .preferences import (AutoExportGltfPreferenceNames)
def generate_gltf_export_preferences(addon_prefs): def generate_gltf_export_preferences(addon_prefs):
@ -48,9 +49,7 @@ def generate_gltf_export_preferences(addon_prefs):
gltf_export_preferences[key] = getattr(addon_prefs, key) gltf_export_preferences[key] = getattr(addon_prefs, key)
standard_gltf_exporter_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") standard_gltf_exporter_settings = get_standard_exporter_settings()
standard_gltf_exporter_settings = json.loads(standard_gltf_exporter_settings.as_string())
"""standard_gltf_exporter_settings = get_standard_exporter_settings()"""
#print("standard settings", standard_gltf_exporter_settings) #print("standard settings", standard_gltf_exporter_settings)
constant_keys = [ constant_keys = [

View File

@ -1,6 +1,7 @@
import os import os
import bpy import bpy
from ..constants import TEMPSCENE_PREFIX
from ..helpers.generate_and_export import generate_and_export from ..helpers.generate_and_export import generate_and_export
from .export_gltf import (generate_gltf_export_preferences, export_gltf) from .export_gltf import (generate_gltf_export_preferences, export_gltf)
from ..modules.bevy_dynamic import is_object_dynamic, is_object_static from ..modules.bevy_dynamic import is_object_dynamic, is_object_static
@ -38,7 +39,7 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
# first export static objects # first export static objects
generate_and_export( generate_and_export(
addon_prefs, addon_prefs,
temp_scene_name="__temp_scene", temp_scene_name=TEMPSCENE_PREFIX,
export_settings=export_settings, export_settings=export_settings,
gltf_output_path=gltf_output_path, gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, filter=is_object_static, addon_prefs=addon_prefs), tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, filter=is_object_static, addon_prefs=addon_prefs),
@ -49,7 +50,7 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
gltf_output_path = os.path.join(folder_path, export_output_folder, scene.name+ "_dynamic") gltf_output_path = os.path.join(folder_path, export_output_folder, scene.name+ "_dynamic")
generate_and_export( generate_and_export(
addon_prefs, addon_prefs,
temp_scene_name="__temp_scene", temp_scene_name=TEMPSCENE_PREFIX,
export_settings=export_settings, export_settings=export_settings,
gltf_output_path=gltf_output_path, gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, filter=is_object_dynamic, addon_prefs=addon_prefs), tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, filter=is_object_dynamic, addon_prefs=addon_prefs),
@ -60,7 +61,7 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
#print("NO SPLIT") #print("NO SPLIT")
generate_and_export( generate_and_export(
addon_prefs, addon_prefs,
temp_scene_name="__temp_scene", temp_scene_name=TEMPSCENE_PREFIX,
export_settings=export_settings, export_settings=export_settings,
gltf_output_path=gltf_output_path, gltf_output_path=gltf_output_path,
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, addon_prefs=addon_prefs), tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, addon_prefs=addon_prefs),

View File

@ -0,0 +1,14 @@
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
if standard_gltf_exporter_settings != None:
try:
standard_gltf_exporter_settings = json.loads(standard_gltf_exporter_settings.as_string())
except:
standard_gltf_exporter_settings = {}
else:
standard_gltf_exporter_settings = {}
return standard_gltf_exporter_settings

View File

@ -46,7 +46,6 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
bpy.types.WindowManager.main_scenes_list_index = IntProperty(name = "Index for main scenes list", default = 0) bpy.types.WindowManager.main_scenes_list_index = IntProperty(name = "Index for main scenes list", default = 0)
bpy.types.WindowManager.library_scenes_list_index = IntProperty(name = "Index for library scenes list", default = 0) bpy.types.WindowManager.library_scenes_list_index = IntProperty(name = "Index for library scenes list", default = 0)
bpy.types.WindowManager.previous_export_settings = StringProperty(default="")
cls.main_scenes_index = 0 cls.main_scenes_index = 0
cls.library_scenes_index = 0 cls.library_scenes_index = 0
@ -59,8 +58,6 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
del bpy.types.WindowManager.main_scenes_list_index del bpy.types.WindowManager.main_scenes_list_index
del bpy.types.WindowManager.library_scenes_list_index del bpy.types.WindowManager.library_scenes_list_index
del bpy.types.WindowManager.previous_export_settings
def is_scene_ok(self, scene): def is_scene_ok(self, scene):
try: try:
operator = bpy.context.space_data.active_operator operator = bpy.context.space_data.active_operator
@ -161,9 +158,20 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
# if there were no setting before, it is new, we need export # if there were no setting before, it is new, we need export
changed = False changed = False
if previous_auto_settings == None or previous_gltf_settings == None: print("previous_auto_settings", previous_auto_settings, "previous_gltf_settings", previous_gltf_settings)
if previous_auto_settings == None:
print("previous settings missing, exporting") print("previous settings missing, exporting")
changed = True 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.write(json.dumps({}))
if current_gltf_settings == None:
current_gltf_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"]
current_gltf_settings.write(json.dumps({}))
changed = True
else: 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 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 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
@ -192,7 +200,6 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
def execute(self, context): def execute(self, context):
print("execute") print("execute")
# disable change detection while the operator runs
bpy.context.window_manager.auto_export_tracker.disable_change_detection() bpy.context.window_manager.auto_export_tracker.disable_change_detection()
if self.direct_mode: if self.direct_mode:
self.load_settings(context) self.load_settings(context)
@ -203,11 +210,13 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
if self.auto_export: # only do the actual exporting if auto export is actually enabled if self.auto_export: # only do the actual exporting if auto export is actually enabled
#& do the export #& do the export
if self.direct_mode: #Do not auto export when applying settings in the menu, do it on save only if self.direct_mode: #Do not auto export when applying settings in the menu, do it on save only
# disable change detection while the operator runs
#determine changed parameters #determine changed parameters
params_changed = self.did_export_settings_change() params_changed = self.did_export_settings_change()
auto_export(changes_per_scene, params_changed, self) auto_export(changes_per_scene, params_changed, self)
# cleanup # cleanup
print("AUTO EXPORT DONE") print("AUTO EXPORT DONE")
if bpy.context.window_manager.auto_export_tracker.exports_count == 0: # we need this in case there was nothing to export, to make sure change detection is enabled again if bpy.context.window_manager.auto_export_tracker.exports_count == 0: # we need this in case there was nothing to export, to make sure change detection is enabled again
pass #print("YOLOOO") pass #print("YOLOOO")
#py.context.window_manager.auto_export_tracker.enable_change_detection() #py.context.window_manager.auto_export_tracker.enable_change_detection()
@ -217,14 +226,21 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
#bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1) #bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)
else: else:
print("auto export disabled, skipping") print("auto export disabled, skipping")
"""if not self.direct_mode:
print("enabling")
bpy.context.window_manager.auto_export_tracker.enable_change_detection()"""
bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)
return {'FINISHED'} return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
print("invoke")
bpy.context.window_manager.auto_export_tracker.disable_change_detection() bpy.context.window_manager.auto_export_tracker.disable_change_detection()
self.load_settings(context) self.load_settings(context)
addon_prefs = self addon_prefs = self
[main_scene_names, level_scenes, library_scene_names, library_scenes]=get_scenes(addon_prefs) """[main_scene_names, level_scenes, library_scene_names, library_scenes]=get_scenes(addon_prefs)
(collections, _) = get_exportable_collections(level_scenes, library_scenes, addon_prefs) (collections, _) = get_exportable_collections(level_scenes, library_scenes, addon_prefs)
try: try:
@ -235,15 +251,20 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
ui_info = bpy.context.window_manager.exportedCollections.add() ui_info = bpy.context.window_manager.exportedCollections.add()
ui_info.name = collection_name ui_info.name = collection_name
except Exception as error: except Exception as error:
self.report({"ERROR"}, "Failed to populate list of exported collections/blueprints") self.report({"ERROR"}, "Failed to populate list of exported collections/blueprints")"""
wm = context.window_manager wm = context.window_manager
wm.fileselect_add(self) wm.fileselect_add(self)
return {'RUNNING_MODAL'} return {'RUNNING_MODAL'}
def draw(self, context): def draw(self, context):
pass pass
def cancel(self, context): def cancel(self, context):
print("cancel")
#bpy.context.window_manager.auto_export_tracker.enable_change_detection()
bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1) bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)

View File

@ -1,8 +1,9 @@
import json import json
import bpy import bpy
from bpy.types import (PropertyGroup) from bpy.types import (PropertyGroup)
from bpy.props import (PointerProperty, IntProperty) from bpy.props import (PointerProperty, IntProperty, StringProperty)
from ..constants import TEMPSCENE_PREFIX
from .internals import CollectionsToExport from .internals import CollectionsToExport
class AutoExportTracker(PropertyGroup): class AutoExportTracker(PropertyGroup):
@ -21,6 +22,8 @@ class AutoExportTracker(PropertyGroup):
default=0 default=0
) # type: ignore ) # type: ignore
@classmethod @classmethod
def register(cls): def register(cls):
bpy.types.WindowManager.auto_export_tracker = PointerProperty(type=AutoExportTracker) bpy.types.WindowManager.auto_export_tracker = PointerProperty(type=AutoExportTracker)
@ -59,10 +62,15 @@ class AutoExportTracker(PropertyGroup):
@classmethod @classmethod
def deps_update_handler(cls, scene, depsgraph): def deps_update_handler(cls, scene, depsgraph):
print("change detection enabled", cls.change_detection_enabled, bpy.context.window_manager.auto_export_tracker.change_detection_enabled) print("change detection enabled", cls.change_detection_enabled)
ops = bpy.context.window_manager.operators
print("last operators", ops)
for op in ops:
print("operator", op)
active_operator = bpy.context.active_operator active_operator = bpy.context.active_operator
if active_operator: if active_operator:
# print("Operator", active_operator.bl_label, active_operator.bl_idname) print("Operator", active_operator.bl_label, active_operator.bl_idname)
if active_operator.bl_idname == "EXPORT_SCENE_OT_gltf" and active_operator.gltf_export_id == "gltf_auto_export": if active_operator.bl_idname == "EXPORT_SCENE_OT_gltf" and active_operator.gltf_export_id == "gltf_auto_export":
# we backup any existing gltf export settings, if there were any # we backup any existing gltf export settings, if there were any
scene = bpy.context.scene scene = bpy.context.scene
@ -80,19 +88,21 @@ class AutoExportTracker(PropertyGroup):
active_operator.will_save_settings = True active_operator.will_save_settings = True
active_operator.auto_export = True active_operator.auto_export = True
if not scene.name.startswith("__temp_scene"): # only deal with changes if we are NOT in the mids of saving/exporting
print("depsgraph_update_post", scene.name) if cls.change_detection_enabled:
changed_scene = scene.name or "" # ignore anything going on with temporary scenes
if not scene.name.startswith(TEMPSCENE_PREFIX):
print("depsgraph_update_post", scene.name)
changed_scene = scene.name or ""
# only deal with changes if we are no in the mids of saving/exporting
if cls.change_detection_enabled:
#print("-------------") #print("-------------")
if not changed_scene in cls.changed_objects_per_scene: if not changed_scene in cls.changed_objects_per_scene:
cls.changed_objects_per_scene[changed_scene] = {} cls.changed_objects_per_scene[changed_scene] = {}
print("cls.changed_objects_per_scene", cls.changed_objects_per_scene)
# depsgraph = bpy.context.evaluated_depsgraph_get() depsgraph = bpy.context.evaluated_depsgraph_get()
for obj in depsgraph.updates: for obj in depsgraph.updates:
# print("depsgraph update", obj) print("depsgraph update", obj)
if isinstance(obj.id, bpy.types.Object): if isinstance(obj.id, bpy.types.Object):
# get the actual object # get the actual object
object = bpy.data.objects[obj.id.name] object = bpy.data.objects[obj.id.name]
@ -100,7 +110,7 @@ class AutoExportTracker(PropertyGroup):
print("FOO","transforms", obj.is_updated_transform, "geometry", obj.is_updated_geometry) print("FOO","transforms", obj.is_updated_transform, "geometry", obj.is_updated_geometry)
cls.changed_objects_per_scene[scene.name][obj.id.name] = object cls.changed_objects_per_scene[scene.name][obj.id.name] = object
elif isinstance(obj.id, bpy.types.Material): # or isinstance(obj.id, bpy.types.ShaderNodeTree): elif isinstance(obj.id, bpy.types.Material): # or isinstance(obj.id, bpy.types.ShaderNodeTree):
# print("changed material", obj.id, "scene", scene.name,) print("changed material", obj.id, "scene", scene.name,)
material = bpy.data.materials[obj.id.name] material = bpy.data.materials[obj.id.name]
#now find which objects are using the material #now find which objects are using the material
for obj in bpy.data.objects: for obj in bpy.data.objects:
@ -113,10 +123,10 @@ class AutoExportTracker(PropertyGroup):
items += len(cls.changed_objects_per_scene[scene_name].keys()) items += len(cls.changed_objects_per_scene[scene_name].keys())
if items == 0: if items == 0:
cls.changed_objects_per_scene.clear() cls.changed_objects_per_scene.clear()
#print("changed_objects_per_scene", cls.changed_objects_per_scene) print("changed_objects_per_scene", cls.changed_objects_per_scene)
else: else:
cls.changed_objects_per_scene.clear() cls.changed_objects_per_scene.clear()
"""depsgraph = bpy.context.evaluated_depsgraph_get() """depsgraph = bpy.context.evaluated_depsgraph_get()
for update in depsgraph.updates: for update in depsgraph.updates:
print("update", update)""" print("update", update)"""
@ -125,13 +135,15 @@ class AutoExportTracker(PropertyGroup):
print("disable change detection") print("disable change detection")
self.change_detection_enabled = False self.change_detection_enabled = False
self.__class__.change_detection_enabled = False self.__class__.change_detection_enabled = False
return None return None
def enable_change_detection(self): def enable_change_detection(self):
print("enable change detection") print("enable change detection")
self.change_detection_enabled = True self.change_detection_enabled = True
self.__class__.change_detection_enabled = True self.__class__.change_detection_enabled = True
#FIXME: not sure about these
self.changed_objects_per_scene.clear()
self.__class__.changed_objects_per_scene.clear()
# bpy.context.window_manager.auto_export_tracker.change_detection_enabled = True # bpy.context.window_manager.auto_export_tracker.change_detection_enabled = True
print("bpy.context.window_manager.auto_export_tracker.change_detection_enabled", bpy.context.window_manager.auto_export_tracker.change_detection_enabled) print("bpy.context.window_manager.auto_export_tracker.change_detection_enabled", bpy.context.window_manager.auto_export_tracker.change_detection_enabled)
return None return None
@ -141,7 +153,7 @@ class AutoExportTracker(PropertyGroup):
bpy.context.window_manager.auto_export_tracker.exports_count -= 1 bpy.context.window_manager.auto_export_tracker.exports_count -= 1
if bpy.context.window_manager.auto_export_tracker.exports_count == 0: if bpy.context.window_manager.auto_export_tracker.exports_count == 0:
#print("preparing to reset change detection") #print("preparing to reset change detection")
#bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1) # bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)
self.enable_change_detection() self.enable_change_detection()
return None return None

View File

@ -0,0 +1 @@
TEMPSCENE_PREFIX = "__temp_scene"

View File

@ -195,11 +195,12 @@ def test_export_changed_parameters(setup_data):
# now same, but move the cube in the library # now same, but move the cube in the library
print("----------------") print("----------------")
print("library change") print("library change (blueprint) ")
print("----------------") print("----------------")
bpy.context.window_manager.auto_export_tracker.enable_change_detection() # FIXME: should not be needed, but .. bpy.context.window_manager.auto_export_tracker.enable_change_detection() # FIXME: should not be needed, but ..
bpy.data.objects["Blueprint1_mesh"].location = [1, 2, 1] bpy.data.objects["Blueprint1_mesh"].location = [1, 2, 1]
auto_export_operator( auto_export_operator(
auto_export=True, auto_export=True,
direct_mode=True, direct_mode=True,
@ -212,16 +213,54 @@ def test_export_changed_parameters(setup_data):
modification_times = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths + [world_file_path])) modification_times = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths + [world_file_path]))
assert modification_times != modification_times_first assert modification_times != modification_times_first
# only the "world" file should have changed # the "world" file should have changed (TODO: double check: this is since changing an instances collection changes the instance too ?)
world_file_index = mapped_files_to_timestamps_and_index["World"][1]
# and the blueprint1 file too, since that is the collection we changed
blueprint1_file_index = mapped_files_to_timestamps_and_index["Blueprint1"][1] blueprint1_file_index = mapped_files_to_timestamps_and_index["Blueprint1"][1]
other_files_modification_times = [value for index, value in enumerate(modification_times) if index not in [blueprint1_file_index]] other_files_modification_times = [value for index, value in enumerate(modification_times) if index not in [world_file_index, blueprint1_file_index]]
other_files_modification_times_first = [value for index, value in enumerate(modification_times_first) if index not in [blueprint1_file_index]] other_files_modification_times_first = [value for index, value in enumerate(modification_times_first) if index not in [world_file_index, blueprint1_file_index]]
assert modification_times[world_file_index] != modification_times_first[world_file_index]
assert modification_times[blueprint1_file_index] != modification_times_first[blueprint1_file_index] assert modification_times[blueprint1_file_index] != modification_times_first[blueprint1_file_index]
assert other_files_modification_times == other_files_modification_times_first assert other_files_modification_times == other_files_modification_times_first
# reset the comparing # reset the comparing
modification_times_first = modification_times modification_times_first = modification_times
# now change something in a nested blueprint
print("----------------")
print("library change (nested blueprint) ")
print("----------------")
bpy.context.window_manager.auto_export_tracker.enable_change_detection() # FIXME: should not be needed, but ..
bpy.data.objects["Blueprint3_mesh"]["test_component"] = 42
auto_export_operator(
auto_export=True,
direct_mode=True,
export_output_folder="./models",
export_scene_settings=True,
export_blueprints=True,
export_legacy_mode=False,
export_materials_library=False
)
modification_times = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths + [world_file_path]))
assert modification_times != modification_times_first
# the "world" file should have changed (TODO: double check: this is since changing an instances collection changes the instance too ?)
world_file_index = mapped_files_to_timestamps_and_index["World"][1]
# and the blueprint1 file too, since that is the collection we changed
blueprint1_file_index = mapped_files_to_timestamps_and_index["Blueprint1"][1]
other_files_modification_times = [value for index, value in enumerate(modification_times) if index not in [world_file_index, blueprint1_file_index]]
other_files_modification_times_first = [value for index, value in enumerate(modification_times_first) if index not in [world_file_index, blueprint1_file_index]]
assert modification_times[world_file_index] != modification_times_first[world_file_index]
assert modification_times[blueprint1_file_index] != modification_times_first[blueprint1_file_index]
assert other_files_modification_times == other_files_modification_times_first
# reset the comparing
modification_times_first = modification_times
# now same, but using an operator # now same, but using an operator

View File

@ -47,8 +47,28 @@ def setup_data(request):
- checks if timestamps have changed - checks if timestamps have changed
- if all worked => test is a-ok - if all worked => test is a-ok
- removes generated files - removes generated files
""" """
def test_export_no_parameters(setup_data):
root_path = "../../testing/bevy_example"
assets_root_path = os.path.join(root_path, "assets")
models_path = os.path.join(assets_root_path, "models")
auto_export_operator = bpy.ops.export_scenes.auto_gltf
# first test exporting withouth any parameters set, this should export with default parameters gracefully
auto_export_operator(
auto_export=True,
direct_mode=True,
export_output_folder="./models",
export_legacy_mode=False,
export_materials_library=True
)
def test_export_changed_parameters(setup_data): def test_export_changed_parameters(setup_data):
root_path = "../../testing/bevy_example" root_path = "../../testing/bevy_example"
assets_root_path = os.path.join(root_path, "assets") assets_root_path = os.path.join(root_path, "assets")
@ -77,11 +97,6 @@ def test_export_changed_parameters(setup_data):
stored_gltf_settings.clear() stored_gltf_settings.clear()
stored_gltf_settings.write(json.dumps(gltf_settings)) stored_gltf_settings.write(json.dumps(gltf_settings))
# move the main cube
bpy.data.objects["Cube"].location = [1, 0, 0]
# move the cube in the library
bpy.data.objects["Blueprint1_mesh"].location = [1, 2, 1]
auto_export_operator( auto_export_operator(
auto_export=True, auto_export=True,
direct_mode=True, direct_mode=True,

View File

@ -0,0 +1,4 @@
- investigate remove_blueprints_list_from_main_scene (could be a case of changes to bpy.data not being applied immediatly)
- investigate clearing of changed_objects_per_scene
- it seems bevy_components does not trigger updates
- undo redo is ignored: ie save, do something, undo it, you still get changes

View File

@ -48,6 +48,15 @@ class GLTF_PT_auto_export_SidePanel(bpy.types.Panel):
op = layout.operator("EXPORT_SCENES_OT_auto_gltf", text="Auto Export Settings") op = layout.operator("EXPORT_SCENES_OT_auto_gltf", text="Auto Export Settings")
op.auto_export = True op.auto_export = True
layout.label(text="changes since last save:")
changed_objects_per_scene = {}
for scene in context.window_manager.auto_export_tracker.changed_objects_per_scene:
if not scene in changed_objects_per_scene.keys():
changed_objects_per_scene[scene] = []
changed_objects_per_scene[scene]+= context.window_manager.auto_export_tracker.changed_objects_per_scene[scene].keys()
layout.label(text=str(changed_objects_per_scene))
#print("GLTF_PT_export_main", GLTF_PT_export_main.bl_parent_id) #print("GLTF_PT_export_main", GLTF_PT_export_main.bl_parent_id)
# main ui in the file => export # main ui in the file => export