feat(auto_export): more work done to get various merging/split modes to work coherently

* updated both get_collections & get_levels to use information about combine modes
 * basic implementation, seems to work, needs more tests & logic check
 * related changes
This commit is contained in:
kaosat.dev 2024-04-22 23:24:15 +02:00
parent 9af2cba1cf
commit 791861c06f
6 changed files with 50 additions and 35 deletions

View File

@ -27,17 +27,27 @@ def get_collections_to_export(changes_per_scene, changed_export_parameters, blue
for scene in library_scenes: for scene in library_scenes:
if scene.name in changes_per_scene: if scene.name in changes_per_scene:
print("scanning", scene.name)
changed_objects = list(changes_per_scene[scene.name].keys()) changed_objects = list(changes_per_scene[scene.name].keys())
changed_blueprints = [blueprints_data.blueprints_from_objects[changed] for changed in changed_objects if changed in blueprints_data.blueprints_from_objects] changed_blueprints = [blueprints_data.blueprints_from_objects[changed] for changed in changed_objects if changed in blueprints_data.blueprints_from_objects]
print("changed_blueprints", changed_blueprints)
# we only care about local blueprints/collections # we only care about local blueprints/collections
changed_local_blueprints = [blueprint for blueprint in changed_blueprints if blueprint.name in blueprints_data.blueprints_per_name.keys() and blueprint.local] changed_local_blueprints = [blueprint for blueprint in changed_blueprints if blueprint.name in blueprints_data.blueprints_per_name.keys() and blueprint.local]
print("changed_local_blueprints blueprints", changed_local_blueprints) # FIXME: double check this: why are we combining these two ?
changed_blueprints += changed_local_blueprints changed_blueprints += changed_local_blueprints
print("CHANGED BLUEPRINTS", changed_blueprints) # dealt with the different combine modes
if collection_instances_combine_mode == 1: # 0 => split (default) 1 => Embed 2 => Embed external
# we check for object specific overrides ...
filtered_changed_blueprints = []
for blueprint in changed_blueprints:
blueprint_instance = blueprints_data.internal_collection_instances.get(blueprint.name, None)
if blueprint_instance:
combine_mode = blueprint_instance['_combine'] if '_combine' in blueprint_instance else collection_instances_combine_mode # FIXME! yikes, should be "split"
print("combine mode", combine_mode)
if combine_mode == 0: # we only keep changed blueprints if mode is set to split (aka if a blueprint is merged, do not export ? )
# but wait, what if we have ONE instance of merge and others of split ? then we need to still split !
filtered_changed_blueprints.append(blueprint)
changed_blueprints = filtered_changed_blueprints
blueprints_to_export = list(set(changed_blueprints + blueprints_not_on_disk)) blueprints_to_export = list(set(changed_blueprints + blueprints_not_on_disk))
# changed/all blueprints to export # changed/all blueprints to export

View File

@ -2,44 +2,38 @@ import bpy
from ..helpers.helpers_blueprints import check_if_blueprint_on_disk from ..helpers.helpers_blueprints import check_if_blueprint_on_disk
from ..helpers.helpers_scenes import (get_scenes, ) from ..helpers.helpers_scenes import (get_scenes, )
def changed_object_in_scene(scene_name, changes_per_scene, collections, collection_instances_combine_mode): # IF collection_instances_combine_mode is not 'split' check for each scene if any object in changes_per_scene has an instance in the scene
print("BLAAAAAAAAAAAAAAAAAAAAAAAAAAAAH", scene_name, "combo mode", collection_instances_combine_mode, "changes", changes_per_scene, "collections", collections) def changed_object_in_scene(scene_name, changes_per_scene, blueprints_data, collection_instances_combine_mode):
# TODO: IF collection_instances_combine_mode is not 'split' check for each scene if any object in changes_per_scene has an instance in the scene
# Embed / EmbedExternal # Embed / EmbedExternal
if collection_instances_combine_mode == 0: # 1 => Embed if collection_instances_combine_mode == 0: # 1 => Embed
return False return False
"""if scene_name in list(changes_per_scene.keys()):
print("here", scene_name)""" blueprints_from_objects = blueprints_data.blueprints_from_objects
bluprint_instances_in_scene = blueprints_data.blueprint_instances_per_main_scene[scene_name]
changed_objects = [object_name for change in changes_per_scene.values() for object_name in change.keys()]
changed_blueprints = [blueprints_from_objects[changed] for changed in changed_objects if changed in blueprints_from_objects]
changed_blueprints_with_instances_in_scene = [bla for bla in changed_blueprints if bla.name in bluprint_instances_in_scene]#[blueprints_from_objects[changed] for changed in changed_objects if changed in blueprints_from_objects and changed in bluprint_instances_in_scene]
level_needs_export = len(changed_blueprints_with_instances_in_scene) > 0
print("changed_blueprints", changed_blueprints)
print("bluprint_instances_in_scene", bluprint_instances_in_scene, "changed_objects", changed_objects, "changed_blueprints_with_instances_in_scene", changed_blueprints_with_instances_in_scene)
return level_needs_export
for scene_name_current in list(bpy.data.scenes.keys()): # this also takes the split/embed mode into account: if a collection instance changes AND embed is active, its container level/world should also be exported
for object in bpy.data.scenes[scene_name_current].objects:
print("foo", changes_per_scene[scene_name_current])
if object.instance_type == 'COLLECTION':
collection_name = object.instance_collection.name
if object.name in list(changes_per_scene[scene_name_current].keys()):
print("changed object", object.name)
return True # even a single object is enough to flag the scene
# TODO: this should also take the split/embed mode into account: if a collection instance changes AND embed is active, its container level/world should also be exported
def get_levels_to_export(changes_per_scene, changed_export_parameters, blueprints_data, addon_prefs): def get_levels_to_export(changes_per_scene, changed_export_parameters, blueprints_data, addon_prefs):
print("TOTOOO")
export_change_detection = getattr(addon_prefs, "export_change_detection") export_change_detection = getattr(addon_prefs, "export_change_detection")
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension") export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
export_models_path = getattr(addon_prefs, "export_models_path") export_models_path = getattr(addon_prefs, "export_models_path")
collection_instances_combine_mode = getattr(addon_prefs, "collection_instances_combine_mode") collection_instances_combine_mode = getattr(addon_prefs, "collection_instances_combine_mode")
[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)
# or changed_object_in_scene(scene_name, changes_per_scene, collections, collection_instances_combine_mode)
# print("levels export", "export_change_detection", export_change_detection, "changed_export_parameters",changed_export_parameters, "export_models_path", export_models_path, "export_gltf_extension", export_gltf_extension, "changes_per_scene", changes_per_scene)
# determine list of main scenes to export # determine list of main scenes to export
# we have more relaxed rules to determine if the main scenes have changed : any change is ok, (allows easier handling of changes, render settings etc) # we have more relaxed rules to determine if the main scenes have changed : any change is ok, (allows easier handling of changes, render settings etc)
main_scenes_to_export = [scene_name for scene_name in main_scene_names if not export_change_detection or changed_export_parameters or scene_name in changes_per_scene.keys() or not check_if_blueprint_on_disk(scene_name, export_models_path, export_gltf_extension) ] main_scenes_to_export = [scene_name for scene_name in main_scene_names if not export_change_detection or changed_export_parameters or scene_name in changes_per_scene.keys() or changed_object_in_scene(scene_name, changes_per_scene, blueprints_data, collection_instances_combine_mode) or not check_if_blueprint_on_disk(scene_name, export_models_path, export_gltf_extension) ]
print("main_scenes_to_export", main_scenes_to_export, changes_per_scene) print("main_scenes_to_export", main_scenes_to_export, changes_per_scene)
return (main_scenes_to_export) return (main_scenes_to_export)

View File

@ -215,6 +215,9 @@ def blueprints_scan(main_scenes, library_scenes, addon_prefs):
internal_blueprints = [] internal_blueprints = []
external_blueprints = [] external_blueprints = []
blueprints_per_scenes = {} blueprints_per_scenes = {}
blueprint_instances_per_library_scene = {}
for blueprint in blueprints_per_name.values(): for blueprint in blueprints_per_name.values():
blueprints.append(blueprint) blueprints.append(blueprint)
if blueprint.local: if blueprint.local:
@ -223,9 +226,12 @@ def blueprints_scan(main_scenes, library_scenes, addon_prefs):
if not blueprint.scene.name in blueprints_per_scenes: if not blueprint.scene.name in blueprints_per_scenes:
blueprints_per_scenes[blueprint.scene.name] = [] blueprints_per_scenes[blueprint.scene.name] = []
blueprints_per_scenes[blueprint.scene.name].append(blueprint.name) # meh blueprints_per_scenes[blueprint.scene.name].append(blueprint.name) # meh
else: else:
external_blueprints.append(blueprint) external_blueprints.append(blueprint)
# we also need to have blueprint instances for
data = { data = {
"blueprints": blueprints, "blueprints": blueprints,
"blueprints_per_name": blueprints_per_name, "blueprints_per_name": blueprints_per_name,
@ -236,10 +242,12 @@ def blueprints_scan(main_scenes, library_scenes, addon_prefs):
"external_blueprints": external_blueprints, "external_blueprints": external_blueprints,
"blueprints_per_scenes": blueprints_per_scenes, "blueprints_per_scenes": blueprints_per_scenes,
"blueprint_instances_per_main_scene": blueprint_instances_per_main_scene "blueprint_instances_per_main_scene": blueprint_instances_per_main_scene,
"blueprint_instances_per_library_scene": blueprint_instances_per_library_scene,
# not sure about these two # not sure about these two
#internal_collection_instances, "internal_collection_instances": internal_collection_instances,
#external_collection_instances "external_collection_instances":external_collection_instances,
} }
return SimpleNamespace(**data) return SimpleNamespace(**data)

View File

@ -94,7 +94,7 @@ def copy_animation_data(source, target):
def duplicate_object(object, parent, combine_mode, destination_collection, blueprints_data, legacy_mode, nester=""): def duplicate_object(object, parent, combine_mode, destination_collection, blueprints_data, legacy_mode, nester=""):
copy = None copy = None
internal_blueprint_names = [blueprint.name for blueprint in blueprints_data.internal_blueprints] internal_blueprint_names = [blueprint.name for blueprint in blueprints_data.internal_blueprints]
print("COMBINE MODE", combine_mode)
if object.instance_type == 'COLLECTION' and (combine_mode == 'Split' or (combine_mode == 'EmbedExternal' and (object.instance_collection.name in internal_blueprint_names)) ): if object.instance_type == 'COLLECTION' and (combine_mode == 'Split' or (combine_mode == 'EmbedExternal' and (object.instance_collection.name in internal_blueprint_names)) ):
#print("creating empty for", object.name, object.instance_collection.name, internal_blueprint_names, combine_mode) #print("creating empty for", object.name, object.instance_collection.name, internal_blueprint_names, combine_mode)
collection_name = object.instance_collection.name collection_name = object.instance_collection.name
@ -102,6 +102,7 @@ def duplicate_object(object, parent, combine_mode, destination_collection, bluep
object.name = original_name + "____bak" object.name = original_name + "____bak"
empty_obj = make_empty(original_name, object.location, object.rotation_euler, object.scale, destination_collection) empty_obj = make_empty(original_name, object.location, object.rotation_euler, object.scale, destination_collection)
"""we inject the collection/blueprint name, as a component called 'BlueprintName', but we only do this in the empty, not the original object""" """we inject the collection/blueprint name, as a component called 'BlueprintName', but we only do this in the empty, not the original object"""
empty_obj['BlueprintName'] = '"'+collection_name+'"' if legacy_mode else '("'+collection_name+'")' empty_obj['BlueprintName'] = '"'+collection_name+'"' if legacy_mode else '("'+collection_name+'")'
empty_obj['SpawnHere'] = '()' empty_obj['SpawnHere'] = '()'

View File

@ -209,7 +209,7 @@ def test_export_change_tracking_custom_properties_collection_instances_combine_m
file_path = pathlib.Path(file_path).stem file_path = pathlib.Path(file_path).stem
mapped_files_to_timestamps_and_index[file_path] = (modification_times_first[index], index) mapped_files_to_timestamps_and_index[file_path] = (modification_times_first[index], index)
# now add a custom property to the cube in the main scene & export again # now add a custom property to the cube in the library scene & export again
print("----------------") print("----------------")
print("library change (custom property)") print("library change (custom property)")
print("----------------") print("----------------")

View File

@ -30,14 +30,16 @@
- [x] get_source_scene => remove, unused - [x] get_source_scene => remove, unused
- [x] assets_list["BlueprintsList"] - [x] assets_list["BlueprintsList"]
BLUEPRINTS LIST {'Blueprint1': [], 'Blueprint6_animated': [], 'Blueprint4_nested': ['Blueprint3'], 'Blueprint3': [], 'Blueprint7_hierarchy': [], 'External_blueprint': [], 'External_blueprint2': ['External_blueprint3'], 'External_blueprint3': [], 'Blueprint8_animated_no_bones': []} BLUEPRINTS LIST {'Blueprint1': [], 'Blueprint6_animated': [], 'Blueprint4_nested': ['Blueprint3'], 'Blueprint3': [], 'Blueprint7_hierarchy': [], 'External_blueprint': [], 'External_blueprint2': ['External_blueprint3'], 'External_blueprint3': [], 'Blueprint8_animated_no_bones': []}
- [x] internal_collections => replace with "internal_collections" or "local_collections" - [x] internal_collections => replace with "internal_collections" or "local_collections"
- [ ] fix COMBINE MODE passed as int instead of enum value
- [x] move all things that alter data "permanently" to pre-save - [x] move all things that alter data "permanently" to pre-save
- [x] lighting/ scene components injection - [x] lighting/ scene components injection
- [x] blueprintNames ? - [x] blueprintNames ?
- [x] or more simple: just remove them after save as we do for others: lighting_components - [x] or more simple: just remove them after save as we do for others: lighting_components
- [ ] if we want the blueprintsList / future paths of blueprints to be present inside external assets, we are going to need to keep them around, ie: inject them in pre-save & not remove them
- [ ] update cleanup_materials - [ ] update cleanup_materials
- [ ] remove bulk of tracker related code - [ ] remove bulk of tracker related code