feat(Blenvy):

* fixed handling of gltf dummy file & settings storage
 * experimenting with best approach for settings diffing for auto export
 * started (wip) moving out bevy_components settings from registry to indenpendant settings
 * minor tweaks
This commit is contained in:
kaosat.dev 2024-05-25 11:57:10 +02:00
parent 4f742e7735
commit 26e75742b2
9 changed files with 99 additions and 22 deletions

View File

@ -66,6 +66,10 @@ Components:
- [ ] handle missing types in registry for keys & values - [ ] handle missing types in registry for keys & values
- [ ] Add correct upgrade handling from individual component to bevy_components - [ ] Add correct upgrade handling from individual component to bevy_components
- [ ] Settings handling:
- [ ] move saveable settings out to a settings file
- [ ] update save & load
- [ ] add handling of polling frequency & enabling
General things to solve: General things to solve:
@ -84,4 +88,5 @@ General issues:
- they normally need/have unique export paths (otherwise, user error, perhaps show it ?) - 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 - perhaps a simple hashing of the parent's path would be enought
- [x] addon-prefs => settings - [x] addon-prefs => settings
- [x] generate_gltf_export_preferences => should not use add-on prefs at all ? since we are not overriding gltf settings that way anymore ? - [x] generate_gltf_export_preferences => should not use add-on prefs at all ? since we are not overriding gltf settings that way anymore ?
- [ ] remove hard coded path for standard gltf settings

View File

@ -4,7 +4,7 @@ import bpy
from .helpers.generate_complete_preferences_dict import generate_complete_preferences_dict_gltf from .helpers.generate_complete_preferences_dict import generate_complete_preferences_dict_gltf
def cleanup_file(): def cleanup_file():
gltf_filepath = "/home/ckaos/projects/bevy/Blender_bevy_components_worklflow/testing/bevy_example/assets/____dummy____.glb" gltf_filepath = bpy.context.window_manager.auto_export_tracker.dummy_file_path
if os.path.exists(gltf_filepath): if os.path.exists(gltf_filepath):
os.remove(gltf_filepath) os.remove(gltf_filepath)
return None return None
@ -14,18 +14,19 @@ def cleanup_file():
def gltf_post_export_callback(data): def gltf_post_export_callback(data):
#print("post_export", data) #print("post_export", data)
blenvy = bpy.context.window_manager.blenvy blenvy = bpy.context.window_manager.blenvy
bpy.context.window_manager.auto_export_tracker.export_finished() tracker = bpy.context.window_manager.auto_export_tracker
tracker.export_finished()
gltf_settings_backup = blenvy.auto_export.gltf_settings_backup gltf_settings_backup = tracker.gltf_settings_backup
gltf_filepath = data["gltf_filepath"] gltf_filepath = data["gltf_filepath"]
gltf_export_id = data['gltf_export_id'] gltf_export_id = data['gltf_export_id']
if gltf_export_id == "gltf_auto_export": if gltf_export_id == "gltf_auto_export":
# some more absurdity: apparently the file is not QUITE done when the export callback is called, so we have to introduce this timer to remove the temporary file correctly # some more absurdity: apparently the file is not QUITE done when the export callback is called, so we have to introduce this timer to remove the temporary file correctly
bpy.context.window_manager.auto_export_tracker.dummy_file_path = gltf_filepath tracker.dummy_file_path = gltf_filepath
try: try:
bpy.app.timers.unregister(cleanup_file) bpy.app.timers.unregister(cleanup_file)
except:pass except:pass
bpy.app.timers.register(cleanup_file, first_interval=1) bpy.app.timers.register(cleanup_file, first_interval=2)
# get the parameters # get the parameters
scene = bpy.context.scene scene = bpy.context.scene
@ -43,9 +44,9 @@ def gltf_post_export_callback(data):
else: else:
if "glTF2ExportSettings" in scene: if "glTF2ExportSettings" in scene:
del scene["glTF2ExportSettings"] del scene["glTF2ExportSettings"]
blenvy.auto_export.gltf_settings_backup = "" tracker.gltf_settings_backup = ""
# the absurd length one has to go through to RESET THE OPERATOR because it has global state !!!!! AAAAAHHH # 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 last_operator = tracker.last_operator
last_operator.filepath = "" last_operator.filepath = ""
last_operator.gltf_export_id = "" last_operator.gltf_export_id = ""

View File

@ -16,7 +16,7 @@ def prepare_and_export():
# determine changed objects # determine changed objects
per_scene_changes = get_changes_per_scene() per_scene_changes = get_changes_per_scene()
# determine changed parameters # determine changed parameters
setting_changes = get_setting_changes() setting_changes = get_setting_changes(auto_export_settings)
# do the actual export # do the actual export
auto_export(per_scene_changes, setting_changes, blenvy) auto_export(per_scene_changes, setting_changes, blenvy)

View File

@ -4,6 +4,7 @@ from ...settings import are_settings_identical, load_settings, upsert_settings
# which settings are specific to auto_export # TODO: can we infer this ? # which settings are specific to auto_export # TODO: can we infer this ?
auto_export_parameter_names = [ auto_export_parameter_names = [
# blenvy core
'project_root_path', 'project_root_path',
'assets_path', 'assets_path',
'blueprints_path', 'blueprints_path',
@ -12,6 +13,7 @@ auto_export_parameter_names = [
#'main_scene_names', #'main_scene_names',
#'library_scene_names', #'library_scene_names',
# auto export
'export_scene_settings', 'export_scene_settings',
'export_blueprints', 'export_blueprints',
'export_separate_dynamic_and_static_objects', 'export_separate_dynamic_and_static_objects',
@ -20,13 +22,14 @@ auto_export_parameter_names = [
'export_marked_assets' 'export_marked_assets'
] ]
def get_setting_changes(): def get_setting_changes(auto_export_settings):
print("get setting changes", dict(auto_export_settings))
previous_gltf_settings = load_settings(".blenvy_gltf_settings_previous") previous_gltf_settings = load_settings(".blenvy_gltf_settings_previous")
current_gltf_settings = load_settings(".blenvy_gltf_settings") current_gltf_settings = load_settings(".blenvy_gltf_settings")
gltf_settings_changed = not are_settings_identical(previous_gltf_settings, current_gltf_settings) gltf_settings_changed = not are_settings_identical(previous_gltf_settings, current_gltf_settings)
previous_export_settings = load_settings(".blenvy_export_settings_previous") previous_export_settings = load_settings(".blenvy_export_settings_previous")
current_export_settings = load_settings(".blenvy_export_settings") current_export_settings = dict(auto_export_settings) #load_settings(".blenvy_export_settings")
export_settings_changed = not are_settings_identical(previous_export_settings, current_export_settings) export_settings_changed = not are_settings_identical(previous_export_settings, current_export_settings)
# if there were no setting before, it is new, we need export # if there were no setting before, it is new, we need export
@ -37,7 +40,7 @@ def get_setting_changes():
# write the new settings to the old settings # write the new settings to the old settings
upsert_settings(".blenvy_gltf_settings_previous", current_gltf_settings) upsert_settings(".blenvy_gltf_settings_previous", current_gltf_settings)
upsert_settings(".blenvy_export_settings_previous", current_gltf_settings) upsert_settings(".blenvy_export_settings_previous", current_export_settings)
return gltf_settings_changed or export_settings_changed return gltf_settings_changed or export_settings_changed

View File

@ -14,9 +14,18 @@ class AutoExportTracker(PropertyGroup):
change_detection_enabled = True change_detection_enabled = True
export_params_changed = False export_params_changed = False
gltf_settings_backup = None
last_operator = None last_operator = None
dummy_file_path = ""
dummy_file_path: StringProperty()# 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
exports_total : IntProperty( exports_total : IntProperty(
name='exports_total', name='exports_total',
@ -77,7 +86,7 @@ class AutoExportTracker(PropertyGroup):
scene = bpy.context.scene scene = bpy.context.scene
if "glTF2ExportSettings" in scene: if "glTF2ExportSettings" in scene:
existing_setting = scene["glTF2ExportSettings"] existing_setting = scene["glTF2ExportSettings"]
bpy.context.window_manager.gltf_settings_backup = json.dumps(dict(existing_setting)) bpy.context.window_manager.auto_export_tracker.gltf_settings_backup = json.dumps(dict(existing_setting))
# we force saving params # we force saving params
active_operator.will_save_settings = True active_operator.will_save_settings = True

View File

@ -83,10 +83,4 @@ class AutoExportSettings(PropertyGroup):
default="DISABLED" default="DISABLED"
) # type: ignore ) # 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

View File

@ -63,6 +63,7 @@ class ComponentsRegistry(PropertyGroup):
description="path to the registry schema file", description="path to the registry schema file",
default="registry.json" default="registry.json"
)# type: ignore )# type: ignore
schemaFullPath : bpy.props.StringProperty( schemaFullPath : bpy.props.StringProperty(
name="schema full path", name="schema full path",
description="path to the registry schema file", description="path to the registry schema file",

View File

@ -0,0 +1,65 @@
import bpy
from bpy_types import (PropertyGroup)
from bpy.props import (EnumProperty, PointerProperty, StringProperty, BoolProperty, CollectionProperty, IntProperty)
# 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)
except Exception as error:
pass
else:
self.watcher_active = True
bpy.app.timers.register(watch_schema)
def watch_schema():
self = bpy.context.window_manager.components_registry
# print("watching schema file for changes")
try:
stamp = os.stat(self.schemaFullPath).st_mtime
stamp = str(stamp)
if stamp != self.schemaTimeStamp and self.schemaTimeStamp != "":
print("FILE CHANGED !!", stamp, self.schemaTimeStamp)
# see here for better ways : https://stackoverflow.com/questions/11114492/check-if-a-file-is-not-open-nor-being-used-by-another-process
"""try:
os.rename(path, path)
#return False
except OSError: # file is in use
print("in use")
#return True"""
#bpy.ops.object.reload_registry()
# we need to add an additional delay as the file might not have loaded yet
bpy.app.timers.register(lambda: bpy.ops.object.reload_registry(), first_interval=1)
self.schemaTimeStamp = stamp
except Exception as error:
pass
return self.watcher_poll_frequency if self.watcher_enabled else None
class ComponentsSettings(PropertyGroup):
schemaPath: StringProperty(
name="schema path",
description="path to the registry schema file",
default="registry.json"
)# type: ignore
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(
name="watcher poll frequency",
description="frequency (s) at wich to poll for changes to the registry file",
min=1,
max=10,
default=1
)# type: ignore
schemaTimeStamp: StringProperty(
name="last timestamp of schema file",
description="",
default=""
)# type: ignore

View File

@ -15,7 +15,6 @@ def get_main_and_library_scenes(settings):
level_scene_names= list(map(lambda scene: scene.name, getattr(settings,"main_scenes"))) level_scene_names= list(map(lambda scene: scene.name, getattr(settings,"main_scenes")))
library_scene_names = list(map(lambda scene: scene.name, getattr(settings,"library_scenes"))) library_scene_names = list(map(lambda scene: scene.name, getattr(settings,"library_scenes")))
print("level_scene_names", level_scene_names)
level_scene_names = list(filter(lambda name: name in bpy.data.scenes, level_scene_names)) level_scene_names = list(filter(lambda name: name in bpy.data.scenes, level_scene_names))
library_scene_names = list(filter(lambda name: name in bpy.data.scenes, library_scene_names)) library_scene_names = list(filter(lambda name: name in bpy.data.scenes, library_scene_names))