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
This commit is contained in:
parent
ea982d330f
commit
b957f0573b
|
@ -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
|
||||
- [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
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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])
|
||||
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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...")
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue