From b957f0573bc80292753ac1aa0ead5274890a2c65 Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Sun, 26 May 2024 18:33:06 +0200 Subject: [PATCH] feat(Blenvy): settings coherency pass * restructured component settings to be used instead of the registry * removed settings from registry * fixed data access for the above * added saving of component parameters * added component settings pointer in blenvy core * added loading of both auto_export & component settings in blenvy core's load_settings --- tools/blenvy/TODO.md | 9 +- tools/blenvy/__init__.py | 6 +- .../generate_complete_preferences_dict.py | 18 --- tools/blenvy/add_ons/auto_export/settings.py | 42 +++++-- .../bevy_components/registry/operators.py | 6 +- .../bevy_components/registry/registry.py | 112 +----------------- .../add_ons/bevy_components/registry/ui.py | 19 ++- .../add_ons/bevy_components/settings.py | 79 ++++++++++-- tools/blenvy/add_ons/bevy_components/ui.py | 11 +- tools/blenvy/core/blenvy_manager.py | 46 ++++--- tools/blenvy/core/ui/scenes_list.py | 12 +- tools/blenvy/core/ui/ui.py | 10 +- tools/blenvy/settings.py | 37 +++++- tools/blenvy/tests/setup_data.py | 4 +- tools/blenvy/tests/test_components.py | 10 +- tools/blenvy/tests/test_registry.py | 2 +- tools/blenvy/tests/test_rename_components.py | 10 +- tools/blenvy/tests/test_shuffler.py | 2 +- 18 files changed, 223 insertions(+), 212 deletions(-) diff --git a/tools/blenvy/TODO.md b/tools/blenvy/TODO.md index 2b4760c..a8b1591 100644 --- a/tools/blenvy/TODO.md +++ b/tools/blenvy/TODO.md @@ -80,6 +80,7 @@ General things to solve: - [x] rename all path stuff using the old naming convention : "blueprints_path_full" - [x] generate the full paths directly when setting them in the UI - [x] problem : how to deal with defaults: do it on start/load ? +- [x] filter out scenes that have already been used in scenes list General issues: - there is no safeguard for naming collisions for naming across blender files @@ -87,6 +88,12 @@ General issues: - "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 + + - [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 ? - - [ ] remove hard coded path for standard gltf settings \ No newline at end of file + - [x] remove hard coded path for standard gltf settings + - [ ] load settings on file load + - [x] auto_export + - [ ] components + - [ ] add handling of errors when trying to load settings \ No newline at end of file diff --git a/tools/blenvy/__init__.py b/tools/blenvy/__init__.py index 3396fc2..b5e026f 100644 --- a/tools/blenvy/__init__.py +++ b/tools/blenvy/__init__.py @@ -26,6 +26,7 @@ from .add_ons.bevy_components.components.lists import GENERIC_LIST_OT_actions, G from .add_ons.bevy_components.components.maps import GENERIC_MAP_OT_actions from .add_ons.bevy_components.components.definitions_list import (ComponentDefinitionsList, ClearComponentDefinitionsList) from .add_ons.bevy_components.components.ui import (BEVY_COMPONENTS_PT_ComponentsPanel) +from .add_ons.bevy_components.settings import ComponentsSettings # auto export from .add_ons.auto_export import gltf_post_export_callback @@ -67,6 +68,7 @@ classes = [ BLENVY_PT_SidePanel, # bevy components + ComponentsSettings, AddComponentOperator, CopyComponentOperator, PasteComponentOperator, @@ -110,6 +112,7 @@ classes = [ GENERIC_MAP_OT_actions, + # gltf auto export AutoExportTracker, AutoExportSettings, @@ -143,9 +146,6 @@ def post_save(scene, depsgraph): @persistent def post_load(file_name): print("POST LOAD") - registry = bpy.context.window_manager.components_registry - if registry is not None: - registry.load_settings() blenvy = bpy.context.window_manager.blenvy if blenvy is not None: blenvy.load_settings() diff --git a/tools/blenvy/add_ons/auto_export/helpers/generate_complete_preferences_dict.py b/tools/blenvy/add_ons/auto_export/helpers/generate_complete_preferences_dict.py index 5a9b020..219fa1f 100644 --- a/tools/blenvy/add_ons/auto_export/helpers/generate_complete_preferences_dict.py +++ b/tools/blenvy/add_ons/auto_export/helpers/generate_complete_preferences_dict.py @@ -26,21 +26,3 @@ def generate_complete_preferences_dict_gltf(settings): complete_preferences = dict(filter(filter_out, dict(complete_preferences).items())) return complete_preferences -# given the input (actual) auto settings, filters out any invalid/useless params & params that are equal to defaults -def generate_complete_preferences_dict_auto(settings, presets): - complete_preferences = {} - defaults = {} - - for k in presets.__annotations__: - item = presets.__annotations__[k] - default = item.keywords.get('default', None) - #complete_preferences[k] = default - defaults[k] = default - - for key in list(settings.keys()): - if key in defaults: - if settings[key] != defaults[key]: # only write out values different from defaults - complete_preferences[key] = settings[key] - else: - complete_preferences[key] = settings[key] - return complete_preferences diff --git a/tools/blenvy/add_ons/auto_export/settings.py b/tools/blenvy/add_ons/auto_export/settings.py index bfb6d4f..fd7a441 100644 --- a/tools/blenvy/add_ons/auto_export/settings.py +++ b/tools/blenvy/add_ons/auto_export/settings.py @@ -1,19 +1,30 @@ import bpy from bpy_types import (PropertyGroup) from bpy.props import (EnumProperty, PointerProperty, StringProperty, BoolProperty, CollectionProperty, IntProperty) +from blenvy.settings import upsert_settings, generate_complete_preferences_dict, load_settings + +def save_settings(settings, context): + print("save settings", settings, context, dict(settings)) + bla = generate_complete_preferences_dict(settings, AutoExportSettings, []) + print("bla", bla) + upsert_settings(settings.settings_save_path, dict(settings)) class AutoExportSettings(PropertyGroup): + settings_save_path = ".blenvy_export_settings" # where to store data in bpy.texts + auto_export: BoolProperty( name='Auto export', description='Automatically export to gltf on save', - default=False + default=False, + update=save_settings ) # type: ignore #### general change_detection: BoolProperty( name='Change detection', description='Use change detection to determine what/if should be exported', - default=True + default=True, + update=save_settings ) # type: ignore # scenes @@ -22,14 +33,16 @@ class AutoExportSettings(PropertyGroup): export_scene_settings: BoolProperty( name='Export scene settings', description='Export scene settings ie AmbientLighting, Bloom, AO etc', - default=False + default=False, + update=save_settings ) # type: ignore # blueprint settings export_blueprints: BoolProperty( name='Export Blueprints', description='Replaces collection instances with an Empty with a BlueprintName custom property, and enabled a lot more features !', - default=True + default=True, + update=save_settings ) # type: ignore export_separate_dynamic_and_static_objects: BoolProperty( @@ -37,13 +50,15 @@ class AutoExportSettings(PropertyGroup): description="""For MAIN scenes only (aka levels), toggle this to generate 2 files per level: - one with all dynamic data: collection or instances marked as dynamic/ saveable - one with all static data: anything else that is NOT marked as dynamic""", - default=False + default=False, + update=save_settings ) # type: ignore export_materials_library: BoolProperty( name='Export materials library', description='remove materials from blueprints and use the material library instead', - default=False + default=False, + update=save_settings ) # type: ignore @@ -63,13 +78,15 @@ class AutoExportSettings(PropertyGroup): ('EmbedExternal', 'EmbedExternal', 'treat instances of external (not specifified in the current blend file) collections (aka assets etc) as embeded objects and do not replace them with empties'), #('Inject', 'Inject', 'inject components from sub collection instances into the curent object') ), - default='Split' + default='Split', + update=save_settings ) # type: ignore export_marked_assets: BoolProperty( name='Auto export marked assets', description='Collections that have been marked as assets will be systematically exported, even if not in use in another scene', - default=True + default=True, + update=save_settings ) # type: ignore dry_run: EnumProperty( @@ -80,7 +97,14 @@ class AutoExportSettings(PropertyGroup): ("NO_EXPORT", "No export", "do not actually export gltf files"), ("NO_PREPARE", "No prepare", "do not actually export gltf files AND do not prepare the exports either (ie no creating fake scenes etc)"), ), - default="DISABLED" + default="DISABLED", ) # type: ignore + def load_settings(self): + settings = load_settings(self.settings_save_path) + if settings is not None: + for setting in settings: + print("setting", setting, settings[setting]) + setattr(self, setting, settings[setting]) + diff --git a/tools/blenvy/add_ons/bevy_components/registry/operators.py b/tools/blenvy/add_ons/bevy_components/registry/operators.py index e216ed5..eaf3f32 100644 --- a/tools/blenvy/add_ons/bevy_components/registry/operators.py +++ b/tools/blenvy/add_ons/bevy_components/registry/operators.py @@ -11,7 +11,7 @@ from ..propGroups.prop_groups import generate_propertyGroups_for_components class ReloadRegistryOperator(Operator): """Reloads registry (schema file) from disk, generates propertyGroups for components & ensures all objects have metadata """ - bl_idname = "object.reload_registry" + bl_idname = "blenvy.reload_components_registry" bl_label = "Reload Registry" bl_options = {"UNDO"} @@ -191,10 +191,8 @@ class OT_OpenSchemaFileBrowser(Operator, ImportHelper): folder_path = os.path.dirname(file_path) relative_path = os.path.relpath(self.filepath, folder_path) - registry = context.window_manager.components_registry - registry.schemaPath = relative_path - blenvy = context.window_manager.blenvy + blenvy.components.schema_path = relative_path upsert_settings(blenvy.settings_save_path, {"components_schemaPath": relative_path}) return {'FINISHED'} diff --git a/tools/blenvy/add_ons/bevy_components/registry/registry.py b/tools/blenvy/add_ons/bevy_components/registry/registry.py index a1af589..88f33d8 100644 --- a/tools/blenvy/add_ons/bevy_components/registry/registry.py +++ b/tools/blenvy/add_ons/bevy_components/registry/registry.py @@ -5,10 +5,7 @@ import uuid from pathlib import Path from bpy_types import (PropertyGroup) from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty) - -from blenvy.settings import load_settings -from ..propGroups.prop_groups import generate_propertyGroups_for_components -from ..components.metadata import ComponentMetadata, ensure_metadata_for_all_items +from ..components.metadata import ComponentMetadata # helper class to store missing bevy types information class MissingBevyType(bpy.types.PropertyGroup): @@ -16,59 +13,9 @@ class MissingBevyType(bpy.types.PropertyGroup): name="type", ) # type: ignore -# 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 - # this is where we store the information for all available components class ComponentsRegistry(PropertyGroup): - - settings_save_path = ".bevy_components_settings" # where to store data in bpy.texts - - schemaPath: bpy.props.StringProperty( - name="schema path", - description="path to the registry schema file", - default="registry.json" - )# type: ignore - - schemaFullPath : bpy.props.StringProperty( - name="schema full path", - description="path to the registry schema file", - )# type: ignore - registry: bpy.props. StringProperty( name="registry", description="component registry" @@ -81,25 +28,6 @@ class ComponentsRegistry(PropertyGroup): disable_all_object_updates: BoolProperty(name="disable_object_updates", default=False) # type: ignore - ## file watcher - 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 - - missing_types_list: CollectionProperty(name="missing types list", type=MissingBevyType)# type: ignore missing_types_list_index: IntProperty(name = "Index for missing types list", default = 0)# type: ignore @@ -218,29 +146,22 @@ class ComponentsRegistry(PropertyGroup): @classmethod def register(cls): bpy.types.WindowManager.components_registry = PointerProperty(type=ComponentsRegistry) - bpy.context.window_manager.components_registry.watcher_active = False @classmethod def unregister(cls): - bpy.context.window_manager.components_registry.watcher_active = False - for propgroup_name in cls.component_propertyGroups.keys(): try: delattr(ComponentMetadata, propgroup_name) - #print("unregistered propertyGroup", propgroup_name) except Exception as error: pass - #print("failed to remove", error, "ComponentMetadata") - try: - bpy.app.timers.unregister(watch_schema) - except Exception as error: - pass - del bpy.types.WindowManager.components_registry def load_schema(self): print("load schema", self) + blenvy = bpy.context.window_manager.blenvy + component_settings = blenvy.components + # cleanup previous data if any self.propGroupIdCounter = 0 self.long_names_to_propgroup_names.clear() @@ -252,23 +173,13 @@ class ComponentsRegistry(PropertyGroup): self.invalid_components.clear() # now prepare paths to load data - file_path = bpy.data.filepath - # Get the folder - folder_path = os.path.dirname(file_path) - path = os.path.join(folder_path, self.schemaPath) - self.schemaFullPath = path - f = Path(bpy.path.abspath(path)) # make a path object of abs path - with open(path) as f: + with open(component_settings.schema_path_full) as f: data = json.load(f) defs = data["$defs"] self.registry = json.dumps(defs) # FIXME:meh ? - # start timer - if not self.watcher_active and self.watcher_enabled: - self.watcher_active = True - print("registering function", watch_schema) - bpy.app.timers.register(watch_schema) + component_settings.start_schema_watcher() # we load the json once, so we do not need to do it over & over again @@ -279,17 +190,6 @@ class ComponentsRegistry(PropertyGroup): def has_type_infos(self): return len(self.type_infos.keys()) != 0 - def load_settings(self): - print("loading settings") - settings = load_settings(self.settings_save_path) - - if settings!= None: - self.schemaPath = settings["components_schemaPath"] - self.load_schema() - generate_propertyGroups_for_components() - ensure_metadata_for_all_items() - - # we keep a list of component propertyGroup around def register_component_propertyGroup(self, name, propertyGroup): self.component_propertyGroups[name] = propertyGroup diff --git a/tools/blenvy/add_ons/bevy_components/registry/ui.py b/tools/blenvy/add_ons/bevy_components/registry/ui.py index 3c73740..afc6091 100644 --- a/tools/blenvy/add_ons/bevy_components/registry/ui.py +++ b/tools/blenvy/add_ons/bevy_components/registry/ui.py @@ -5,13 +5,11 @@ from bpy.props import (StringProperty) from ..utils import get_selection_type -from ..components.operators import OT_rename_component, RemoveComponentFromAllItemsOperator, RemoveComponentOperator +from ..components.operators import OT_rename_component, RemoveComponentFromAllItemsOperator from .operators import( COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_PROPGROUPS_FROM_CUSTOM_PROPERTIES_CURRENT, - OT_OpenSchemaFileBrowser, - OT_select_component_name_to_replace, - OT_select_object, ReloadRegistryOperator, + OT_OpenSchemaFileBrowser, ReloadRegistryOperator, COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_ALL, COMPONENTS_OT_REFRESH_CUSTOM_PROPERTIES_CURRENT) @@ -34,23 +32,24 @@ class BEVY_COMPONENTS_PT_Configuration(bpy.types.Panel): def draw(self, context): layout = self.layout registry = context.window_manager.components_registry + blenvy = context.window_manager.blenvy + component_settings = blenvy.components - row = layout.row() col = row.column() col.enabled = False - col.prop(registry, "schemaPath", text="Registry Schema path") + col.prop(component_settings, "schema_path", text="Registry Schema path") col = row.column() - col.operator(OT_OpenSchemaFileBrowser.bl_idname, text="Browse for registry schema file (json)") + col.operator("blenvy.open_schemafilebrowser", text="Browse for registry schema file (json)") layout.separator() - layout.operator(ReloadRegistryOperator.bl_idname, text="reload registry" , icon="FILE_REFRESH") + layout.operator("blenvy.reload_components_registry", text="reload registry" , icon="FILE_REFRESH") layout.separator() row = layout.row() - row.prop(registry, "watcher_enabled", text="enable registry file polling") - row.prop(registry, "watcher_poll_frequency", text="registry file poll frequency (s)") + row.prop(component_settings, "watcher_enabled", text="enable registry file polling") + row.prop(component_settings, "watcher_poll_frequency", text="registry file poll frequency (s)") layout.separator() layout.separator() diff --git a/tools/blenvy/add_ons/bevy_components/settings.py b/tools/blenvy/add_ons/bevy_components/settings.py index 35394e9..280f4e9 100644 --- a/tools/blenvy/add_ons/bevy_components/settings.py +++ b/tools/blenvy/add_ons/bevy_components/settings.py @@ -1,7 +1,18 @@ +import os import bpy from bpy_types import (PropertyGroup) from bpy.props import (EnumProperty, PointerProperty, StringProperty, BoolProperty, CollectionProperty, IntProperty) +from blenvy.settings import load_settings, upsert_settings +from .propGroups.prop_groups import generate_propertyGroups_for_components +from .components.metadata import ensure_metadata_for_all_items +# list of settings we do NOT want to save +settings_black_list = ['watcher_active'] + +def save_settings(settings, context): + print("save settings", settings, context, dict(settings)) + settings_dict = dict(settings) + upsert_settings(settings.settings_save_path, {key: settings_dict[key] for key in settings_dict.keys() if key not in settings_black_list}) # helper function to deal with timer def toggle_watcher(self, context): @@ -14,15 +25,17 @@ def toggle_watcher(self, context): else: self.watcher_active = True bpy.app.timers.register(watch_schema) + save_settings(self, context) def watch_schema(): - self = bpy.context.window_manager.components_registry - # print("watching schema file for changes") + blenvy = bpy.context.window_manager.blenvy + component_settings = blenvy.components + #print("watching schema file for changes") try: - stamp = os.stat(self.schemaFullPath).st_mtime + stamp = os.stat(component_settings.schema_path_full).st_mtime stamp = str(stamp) - if stamp != self.schemaTimeStamp and self.schemaTimeStamp != "": - print("FILE CHANGED !!", stamp, self.schemaTimeStamp) + if stamp != component_settings.schemaTimeStamp and component_settings.schemaTimeStamp != "": + print("FILE CHANGED !!", stamp, component_settings.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) @@ -34,19 +47,29 @@ def watch_schema(): # 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 + component_settings.schemaTimeStamp = stamp except Exception as error: pass - return self.watcher_poll_frequency if self.watcher_enabled else None + return component_settings.watcher_poll_frequency if component_settings.watcher_enabled else None class ComponentsSettings(PropertyGroup): - schemaPath: StringProperty( + + settings_save_path = ".blenvy_components_settings" # where to store data in bpy.texts + + schema_path: StringProperty( name="schema path", description="path to the registry schema file", - default="registry.json" + default="registry.json", + update=save_settings )# type: ignore + schema_path_full: StringProperty( + name="schema full path", + description="path to the registry schema file", + get=lambda self: os.path.abspath(os.path.join(os.path.dirname(bpy.data.filepath), self.schema_path)) + ) # 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 @@ -55,11 +78,45 @@ class ComponentsSettings(PropertyGroup): description="frequency (s) at wich to poll for changes to the registry file", min=1, max=10, - default=1 + default=1, + update=save_settings )# type: ignore schemaTimeStamp: StringProperty( name="last timestamp of schema file", description="", - default="" + default="", + update=save_settings )# type: ignore + + + @classmethod + def register(cls): + pass + #bpy.context.window_manager.blenvy.components.watcher_active = False + + @classmethod + def unregister(cls): + bpy.context.window_manager.blenvy.components.watcher_active = False + try: + bpy.app.timers.unregister(watch_schema) + except Exception as error: + pass + + def start_schema_watcher(self): + # start timer + if not self.watcher_active and self.watcher_enabled: + self.watcher_active = True + print("registering function", watch_schema) + bpy.app.timers.register(watch_schema) + + def load_settings(self): + settings = load_settings(self.settings_save_path) + if settings is not None: + for setting in settings: + print("setting", setting, settings[setting]) + setattr(self, setting, settings[setting]) + registry = bpy.context.components_registry + registry.load_schema() + generate_propertyGroups_for_components() + ensure_metadata_for_all_items() diff --git a/tools/blenvy/add_ons/bevy_components/ui.py b/tools/blenvy/add_ons/bevy_components/ui.py index ee07f3b..d52662f 100644 --- a/tools/blenvy/add_ons/bevy_components/ui.py +++ b/tools/blenvy/add_ons/bevy_components/ui.py @@ -1,19 +1,20 @@ -def draw_settings_ui(layout, registry): +def draw_settings_ui(layout, component_settings): + row = layout.row() col = row.column() col.enabled = False - col.prop(registry, "schemaPath", text="Registry Schema path") + col.prop(component_settings, "schema_path", text="Registry Schema path") col = row.column() col.operator(operator="blenvy.open_schemafilebrowser", text="Browse for registry schema file (json)") layout.separator() - layout.operator(operator="object.reload_registry", text="reload registry" , icon="FILE_REFRESH") + layout.operator(operator="blenvy.reload_components_registry", text="reload registry" , icon="FILE_REFRESH") layout.separator() row = layout.row() - row.prop(registry, "watcher_enabled", text="enable registry file polling") - row.prop(registry, "watcher_poll_frequency", text="registry file poll frequency (s)") + row.prop(component_settings, "watcher_enabled", text="enable registry file polling") + row.prop(component_settings, "watcher_poll_frequency", text="registry file poll frequency (s)") layout.separator() layout.separator() \ No newline at end of file diff --git a/tools/blenvy/core/blenvy_manager.py b/tools/blenvy/core/blenvy_manager.py index 939c0b2..e7ddb3e 100644 --- a/tools/blenvy/core/blenvy_manager.py +++ b/tools/blenvy/core/blenvy_manager.py @@ -5,27 +5,36 @@ from bpy.props import (EnumProperty, PointerProperty, StringProperty, Collection from .scene_helpers import SceneSelector from ..settings import upsert_settings, load_settings import blenvy.add_ons.auto_export.settings as auto_export_settings +import blenvy.add_ons.bevy_components.settings as component_settings -def update_scene_lists(self, context): - blenvy = self# context.window_manager.blenvy +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, {"common_main_scene_names": [scene.name for scene in blenvy.main_scenes]}) upsert_settings(blenvy.settings_save_path, {"common_library_scene_names": [scene.name for scene in blenvy.library_scenes]}) -def update_asset_folders(self, context): - blenvy = self # context.window_manager.blenvy +def update_asset_folders(blenvy, 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)}) -def update_mode(self, context): - blenvy = self +def update_mode(blenvy, context): upsert_settings(blenvy.settings_save_path, {"mode": blenvy.mode }) + +def is_scene_ok(self, scene): + try: + + print("SELF", self) + + return scene.name not in self.main_scenes and scene.name not in self.library_scenes + except: + print("FAILURE") + return True + class BlenvyManager(PropertyGroup): - settings_save_path = ".blenvy_settings" # where to store data in bpy.texts + settings_save_path = ".blenvy_common_settings" # where to store data in bpy.texts mode: EnumProperty( items=( @@ -109,27 +118,20 @@ class BlenvyManager(PropertyGroup): # sub ones auto_export: PointerProperty(type=auto_export_settings.AutoExportSettings) # type: ignore - #components: PointerProperty(type=bevy_component_settings.ComponentSettings) # type: ignore + components: PointerProperty(type=component_settings.ComponentsSettings) # type: ignore - def is_scene_ok(self, scene): - try: - operator = bpy.context.space_data.active_operator - return scene.name not in operator.main_scenes and scene.name not in operator.library_scenes - except: - return True + main_scene_selector: PointerProperty(type=bpy.types.Scene, name="main scene", description="main_scene_picker", poll=is_scene_ok)# type: ignore + library_scene_selector: PointerProperty(type=bpy.types.Scene, name="library scene", description="library_scene_picker", poll=is_scene_ok)# type: ignore + + @classmethod def register(cls): - bpy.types.WindowManager.main_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="main scene", description="main_scene_picker", poll=cls.is_scene_ok) - bpy.types.WindowManager.library_scene = bpy.props.PointerProperty(type=bpy.types.Scene, name="library scene", description="library_scene_picker", poll=cls.is_scene_ok) - bpy.types.WindowManager.blenvy = PointerProperty(type=BlenvyManager) @classmethod def unregister(cls): del bpy.types.WindowManager.blenvy - del bpy.types.WindowManager.main_scene - del bpy.types.WindowManager.library_scene def load_settings(self): print("LOAD SETTINGS") @@ -150,3 +152,9 @@ class BlenvyManager(PropertyGroup): for asset_path_name in asset_path_names: if asset_path_name in settings: setattr(self, asset_path_name, settings[asset_path_name]) + + # now load auto_export settings + self.auto_export.load_settings() + + # now load component 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 f13f127..ea872fe 100644 --- a/tools/blenvy/core/ui/scenes_list.py +++ b/tools/blenvy/core/ui/scenes_list.py @@ -95,19 +95,19 @@ class SCENES_LIST_OT_actions(Operator): if self.action == 'ADD': new_scene_name = None if self.scene_type == "LEVEL": - if context.window_manager.main_scene: - new_scene_name = context.window_manager.main_scene.name + if context.window_manager.blenvy.main_scene_selector: + new_scene_name = context.window_manager.blenvy.main_scene_selector.name else: - if context.window_manager.library_scene: - new_scene_name = context.window_manager.library_scene.name + if context.window_manager.blenvy.library_scene_selector: + new_scene_name = context.window_manager.blenvy.library_scene_selector.name if new_scene_name: item = target.add() item.name = new_scene_name if self.scene_type == "LEVEL": - context.window_manager.main_scene = None + context.window_manager.blenvy.main_scene_selector = None else: - context.window_manager.library_scene = None + context.window_manager.blenvy.library_scene_selector = None setattr(source, target_index, len(target) - 1) diff --git a/tools/blenvy/core/ui/ui.py b/tools/blenvy/core/ui/ui.py index a4cb5cd..2482885 100644 --- a/tools/blenvy/core/ui/ui.py +++ b/tools/blenvy/core/ui/ui.py @@ -104,7 +104,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel): rows = 2 row = section.row() row.label(text="main scenes") - row.prop(context.window_manager, "main_scene", text='') + row.prop(blenvy, "main_scene_selector", text='') row = section.row() row.template_list("SCENE_UL_Blenvy", "level scenes", blenvy, "main_scenes", blenvy, "main_scenes_index", rows=rows) @@ -115,7 +115,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel): add_operator.action = 'ADD' add_operator.scene_type = 'LEVEL' #add_operator.operator = operator - sub_row.enabled = context.window_manager.main_scene is not None + sub_row.enabled = blenvy.main_scene_selector is not None sub_row = col.row() remove_operator = sub_row.operator("scene_list.list_action", icon='REMOVE', text="") @@ -126,7 +126,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel): # library scenes row = section.row() row.label(text="library scenes") - row.prop(context.window_manager, "library_scene", text='') + row.prop(blenvy, "library_scene_selector", text='') row = section.row() row.template_list("SCENE_UL_Blenvy", "library scenes", blenvy, "library_scenes", blenvy, "library_scenes_index", rows=rows) @@ -136,7 +136,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel): add_operator = sub_row.operator("scene_list.list_action", icon='ADD', text="") add_operator.action = 'ADD' add_operator.scene_type = 'LIBRARY' - sub_row.enabled = context.window_manager.library_scene is not None + sub_row.enabled = blenvy.library_scene_selector is not None sub_row = col.row() @@ -148,7 +148,7 @@ class BLENVY_PT_SidePanel(bpy.types.Panel): header, panel = layout.panel("components", default_closed=False) header.label(text="Components") if panel: - components_ui.draw_settings_ui(panel, context.window_manager.components_registry) + components_ui.draw_settings_ui(panel, blenvy.components) header, panel = layout.panel("auto_export", default_closed=False) header.label(text="Auto Export") diff --git a/tools/blenvy/settings.py b/tools/blenvy/settings.py index b89ef76..f07301d 100644 --- a/tools/blenvy/settings.py +++ b/tools/blenvy/settings.py @@ -2,7 +2,7 @@ import json import bpy def upsert_settings(name, data): - stored_settings = bpy.data.texts[name] if name in bpy.data.texts else None#bpy.data.texts.new(name) + stored_settings = bpy.data.texts[name] if name in bpy.data.texts else None if stored_settings is None: stored_settings = bpy.data.texts.new(name) stored_settings.write(json.dumps(data)) @@ -21,6 +21,41 @@ def load_settings(name): return None return None + +# given the input (actual) settings, filters out any invalid/useless params & params that are equal to defaults +def generate_complete_preferences_dict(settings, presets, ignore_list=[]): + complete_preferences = {} + defaults = {} + + def filter_out(pair): + key, value = pair + if key in ignore_list: + return False + return True + + for k in presets.__annotations__: + item = presets.__annotations__[k] + default = item.keywords.get('default', None) + defaults[k] = default + #complete_preferences[k] = default + # print("defaults", defaults) + + + for key in list(settings.keys()): + if key in defaults and settings[key] != defaults[key]: # only write out values different from defaults + complete_preferences[key] = getattr(settings, key, None) + + print("complete_preferences", complete_preferences) + + """for key in list(settings.keys()): + if key in defaults and settings[key] != defaults[key]: # only write out values different from defaults + complete_preferences[key] = settings[key]""" + + complete_preferences = dict(filter(filter_out, dict(complete_preferences).items())) + + return complete_preferences + + # checks if old & new settings (dicts really) are identical def are_settings_identical(old, new, white_list=None): if old is None and new is None: diff --git a/tools/blenvy/tests/setup_data.py b/tools/blenvy/tests/setup_data.py index 53be3de..e86bbf4 100644 --- a/tools/blenvy/tests/setup_data.py +++ b/tools/blenvy/tests/setup_data.py @@ -5,9 +5,9 @@ import pytest def setup_data(request): print("\nSetting up resources...") - schemaPath = "../../testing/bevy_example/assets/registry.json" + schema_path = "../../testing/bevy_example/assets/registry.json" - yield {"schema_path": schemaPath} + yield {"schema_path": schema_path} def finalizer(): print("\nPerforming teardown...") diff --git a/tools/blenvy/tests/test_components.py b/tools/blenvy/tests/test_components.py index 6aabe59..b52b17f 100644 --- a/tools/blenvy/tests/test_components.py +++ b/tools/blenvy/tests/test_components.py @@ -11,7 +11,7 @@ from .setup_data import setup_data def test_components_should_generate_correct_custom_properties(setup_data): registry = bpy.context.window_manager.components_registry - registry.schemaPath = setup_data["components_schemaPath"] + registry.schema_path = setup_data["components_schemaPath"] bpy.ops.object.reload_registry() type_infos = registry.type_infos @@ -58,7 +58,7 @@ def test_components_should_generate_correct_custom_properties(setup_data): def test_components_should_generate_correct_custom_properties_with_randomized_values(setup_data): registry = bpy.context.window_manager.components_registry - registry.schemaPath = setup_data["components_schemaPath"] + registry.schema_path = setup_data["components_schemaPath"] bpy.ops.object.reload_registry() type_infos = registry.type_infos @@ -108,7 +108,7 @@ def test_components_should_generate_correct_custom_properties_with_randomized_va def test_components_should_generate_correct_propertyGroup_values_from_custom_properties(setup_data): registry = bpy.context.window_manager.components_registry - registry.schemaPath = setup_data["components_schemaPath"] + registry.schema_path = setup_data["components_schemaPath"] bpy.ops.object.reload_registry() type_infos = registry.type_infos @@ -166,7 +166,7 @@ def test_components_should_generate_correct_propertyGroup_values_from_custom_pro def test_remove_components(setup_data): registry = bpy.context.window_manager.components_registry - registry.schemaPath = setup_data["components_schemaPath"] + registry.schema_path = setup_data["components_schemaPath"] bpy.ops.object.reload_registry() type_infos = registry.type_infos @@ -207,7 +207,7 @@ def test_remove_components(setup_data): def test_copy_paste_components(setup_data): context = bpy.context registry = context.window_manager.components_registry - registry.schemaPath = setup_data["components_schemaPath"] + registry.schema_path = setup_data["components_schemaPath"] bpy.ops.object.reload_registry() long_name = "bevy_example::test_components::BasicTest" diff --git a/tools/blenvy/tests/test_registry.py b/tools/blenvy/tests/test_registry.py index b9e40fc..8ed5d7a 100644 --- a/tools/blenvy/tests/test_registry.py +++ b/tools/blenvy/tests/test_registry.py @@ -3,7 +3,7 @@ from .setup_data import setup_data def test_blend(setup_data): registry = bpy.context.window_manager.components_registry - registry.schemaPath = setup_data["components_schemaPath"] + registry.schema_path = setup_data["components_schemaPath"] bpy.ops.object.reload_registry() long_name = "bevy_example::test_components::BasicTest" diff --git a/tools/blenvy/tests/test_rename_components.py b/tools/blenvy/tests/test_rename_components.py index aea3b59..97f482d 100644 --- a/tools/blenvy/tests/test_rename_components.py +++ b/tools/blenvy/tests/test_rename_components.py @@ -24,7 +24,7 @@ def get_component_propGroup(registry, component_name, component_meta): def test_rename_component_single_unit_struct(setup_data): registry = bpy.context.window_manager.components_registry - registry.schemaPath = setup_data["components_schemaPath"] + registry.schema_path = setup_data["components_schemaPath"] bpy.ops.object.reload_registry() rename_component_operator = bpy.ops.object.rename_bevy_component @@ -47,7 +47,7 @@ def test_rename_component_single_unit_struct(setup_data): def test_rename_component_single_complex_struct(setup_data): registry = bpy.context.window_manager.components_registry - registry.schemaPath = setup_data["components_schemaPath"] + registry.schema_path = setup_data["components_schemaPath"] bpy.ops.object.reload_registry() rename_component_operator = bpy.ops.object.rename_bevy_component @@ -70,7 +70,7 @@ def test_rename_component_single_complex_struct(setup_data): def test_rename_component_bulk(setup_data): registry = bpy.context.window_manager.components_registry - registry.schemaPath = setup_data["components_schemaPath"] + registry.schema_path = setup_data["components_schemaPath"] bpy.ops.object.reload_registry() rename_component_operator = bpy.ops.object.rename_bevy_component @@ -95,7 +95,7 @@ def test_rename_component_bulk(setup_data): def test_rename_component_single_error_handling(setup_data): registry = bpy.context.window_manager.components_registry - registry.schemaPath = setup_data["components_schemaPath"] + registry.schema_path = setup_data["components_schemaPath"] bpy.ops.object.reload_registry() rename_component_operator = bpy.ops.object.rename_bevy_component @@ -125,7 +125,7 @@ def test_rename_component_single_error_handling(setup_data): def test_rename_component_single_error_handling_clean_errors(setup_data): registry = bpy.context.window_manager.components_registry - registry.schemaPath = setup_data["components_schemaPath"] + registry.schema_path = setup_data["components_schemaPath"] bpy.ops.object.reload_registry() rename_component_operator = bpy.ops.object.rename_bevy_component diff --git a/tools/blenvy/tests/test_shuffler.py b/tools/blenvy/tests/test_shuffler.py index e52ac3c..d86fc7c 100644 --- a/tools/blenvy/tests/test_shuffler.py +++ b/tools/blenvy/tests/test_shuffler.py @@ -5,7 +5,7 @@ from .setup_data import setup_data def test_shuffler(setup_data): registry = bpy.context.window_manager.components_registry - registry.schemaPath = setup_data["schema_path"] + registry.schema_path = setup_data["schema_path"] bpy.ops.object.reload_registry() type_infos = registry.type_infos