Skip to content

Commit 912ba86

Browse files
fix scene properties issue, add on was compoletely broken after introducing class MeshExporterSettings(PropertyGroup)
1 parent 9770f04 commit 912ba86

File tree

5 files changed

+97
-51
lines changed

5 files changed

+97
-51
lines changed

__init__.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,31 +40,44 @@
4040

4141
def register():
4242
logger.info("Begin registration.")
43-
# First register properties
43+
# 1. Properties FIRST
4444
properties.register_properties()
45-
46-
# Then register our classes
45+
logger.info("Properties registered.")
46+
47+
# Debug code to verify registration
48+
test = hasattr(bpy.types.Scene, "mesh_exporter")
49+
logger.info(f"Verification - mesh_exporter exists: {test}")
50+
51+
# 2. Other Classes (Operators, Panels)
4752
for cls in classes:
4853
bpy.utils.register_class(cls)
49-
50-
# Finally register export indicators (including the timer)
54+
logger.info("Panel/Operator classes registered.")
55+
56+
# 3. Indicators
5157
export_indicators.register()
5258
logger.info("Export indicators registered.")
59+
logger.info("Registration complete.")
5360

5461

5562
def unregister():
56-
# First unregister export indicators (handles its own classes)
63+
logger.info("Begin unregistration.")
64+
# Unregister in REVERSE order
65+
66+
# 1. Indicators
5767
export_indicators.unregister()
58-
59-
# Then unregister our other classes
68+
logger.info("Export indicators unregistered.")
69+
70+
# 2. Other Classes
6071
for cls in reversed(classes):
6172
try:
6273
bpy.utils.unregister_class(cls)
6374
except RuntimeError as e:
64-
print(f"Couldn't unregister {cls}: {e}")
65-
66-
# Finally unregister properties
75+
logger.error(f"Couldn't unregister {cls}: {e}")
76+
logger.info("Panel/Operator classes unregistered.")
77+
78+
# 3. Properties LAST
6779
properties.unregister_properties()
80+
logger.info("Properties unregistered.")
6881
logger.info("Unregistration complete.")
6982

7083

export_indicators.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,17 @@ def mark_object_as_exported(obj):
7676

7777
# Ensure timer is registered
7878
if not bpy.app.timers.is_registered(update_timer_callback):
79-
logger.warning("Export indicators timer not registered - registering now")
79+
logger.warning("Export indicators timer not registered - "
80+
"registering now")
8081
try:
8182
bpy.app.timers.register(
8283
update_timer_callback,
8384
first_interval=_TIMER_INTERVAL_SECONDS,
8485
persistent=True
8586
)
8687
except Exception as e:
87-
logger.error(f"Failed to register timer in mark_object_as_exported: {e}")
88+
logger.error(f"Failed to register timer in "
89+
f"mark_object_as_exported: {e}")
8890

8991
# Mark the object
9092
obj[EXPORT_TIME_PROP] = time.time()
@@ -315,7 +317,9 @@ def update_all_export_statuses():
315317

316318
elapsed_time = current_time - export_time
317319
old_status_val = obj.get(EXPORT_STATUS_PROP, ExportStatus.NONE.value)
318-
old_status_name = ExportStatus(old_status_val).name if isinstance(old_status_val, int) else "UNKNOWN"
320+
old_status_name = (ExportStatus(old_status_val).name
321+
if isinstance(old_status_val, int)
322+
else "UNKNOWN")
319323

320324
new_status = ExportStatus.NONE
321325
if elapsed_time < FRESH_DURATION_SECONDS:
@@ -327,7 +331,8 @@ def update_all_export_statuses():
327331

328332
# Only log when there's a status change
329333
if new_status_val != old_status_val:
330-
status_changes.append((obj.name, old_status_name, new_status.name, elapsed_time))
334+
status_changes.append((obj.name, old_status_name,
335+
new_status.name, elapsed_time))
331336
needs_redraw = True
332337

333338
# State transition logic
@@ -352,7 +357,8 @@ def update_all_export_statuses():
352357

353358
# Log status changes together for easier debugging
354359
if status_changes:
355-
logger.info(f"Status changes detected: {len(status_changes)} objects updated")
360+
logger.info(f"Status changes detected: {len(status_changes)} "
361+
f"objects updated")
356362
for change in status_changes:
357363
name, old, new, elapsed = change
358364
logger.info(f" → {name}: {old}{new} (elapsed: {elapsed:.1f}s)")
@@ -392,7 +398,9 @@ def update_timer_callback():
392398
if status_updated:
393399
# More aggressive UI updating
394400
context = bpy.context
395-
if context and hasattr(context, "window_manager") and context.window_manager:
401+
if (context
402+
and hasattr(context, "window_manager")
403+
and context.window_manager):
396404
for window in context.window_manager.windows:
397405
if not hasattr(window, "screen") or not window.screen:
398406
continue
@@ -403,7 +411,8 @@ def update_timer_callback():
403411
except:
404412
pass
405413
else:
406-
logger.warning("Timer callback couldn't redraw: invalid context")
414+
logger.warning("Timer callback couldn't redraw: "
415+
"invalid context")
407416
except Exception as e:
408417
# Log but don't stop the timer
409418
logger.error(f"[MESH_EXPORTER] Timer error: {e}", exc_info=True)
@@ -515,7 +524,8 @@ def register():
515524
first_interval=_TIMER_INTERVAL_SECONDS,
516525
persistent=True # Make timer survive file loads
517526
)
518-
logger.info(f"Export indicator timer registered (interval: {_TIMER_INTERVAL_SECONDS}s, persistent)")
527+
logger.info(f"Export indicator timer registered (interval: "
528+
f"{_TIMER_INTERVAL_SECONDS}s, persistent)")
519529
except Exception as e:
520530
logger.error(f"Failed to register timer: {e}", exc_info=True)
521531

operators.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,22 @@
3535

3636
@contextlib.contextmanager
3737
def temp_selection_context(context, active_object=None, selected_objects=None):
38-
"""Temporarily set the active object and selection using direct API."""
38+
"""
39+
Temporarily set the active object and selection using direct API.
40+
41+
Args:
42+
context (bpy.context): The current Blender context.
43+
active_object (bpy.types.Object, optional):
44+
The object to set as active.
45+
selected_objects (list, optional): List of objects to select.
46+
47+
Returns:
48+
None
49+
"""
3950
# Store original state
4051
original_active = context.view_layer.objects.active
41-
original_selected = [obj for obj in context.scene.objects if obj.select_get()]
42-
original_mode = original_active.mode if original_active else 'OBJECT'
52+
original_selected = [obj for obj in context.scene.objects
53+
if obj.select_get()]
4354

4455
try:
4556
# Deselect all objects directly
@@ -57,7 +68,8 @@ def temp_selection_context(context, active_object=None, selected_objects=None):
5768
try:
5869
obj.select_set(True)
5970
except ReferenceError:
60-
logger.warning(f"Could not select '{obj.name}' - object reference invalid.")
71+
logger.warning(f"Could not select '{obj.name}' "
72+
f"- object reference invalid.")
6173

6274
# Set active object directly
6375
if active_object and active_object.name in context.scene.objects:
@@ -715,7 +727,7 @@ def poll(cls, context):
715727
def execute(self, context):
716728
"""Runs the batch export process."""
717729
scene = context.scene
718-
scene_props = scene
730+
scene_props = scene.mesh_exporter
719731
wm = context.window_manager
720732
start_time = time.time()
721733

@@ -945,11 +957,9 @@ def execute(self, context):
945957
"""Executes the selection using direct API."""
946958
target_obj = bpy.data.objects.get(self.object_name)
947959
if not target_obj:
948-
logger.warning(f"Object '{self.object_name}' not found for selection.")
960+
logger.warning(f"Object '{self.object_name}' "
961+
f"not found for selection.")
949962
return {"CANCELLED"}
950-
951-
# Store original mode
952-
original_mode = context.active_object.mode if context.active_object else 'OBJECT'
953963

954964
# Deselect all objects directly
955965
for obj in context.scene.objects:

panels.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def draw(self, context):
9191
col = layout.column(heading="Triangulate", align=True)
9292
col.prop(settings, "mesh_export_tri")
9393
sub = col.column(align=True)
94-
# sub.enabled = context.scene.mesh_exporter.mesh_export_tri # Enable/disable sub-option
94+
sub.enabled = settings.mesh_export_tri # Enable/disable sub-option
9595
sub.prop(settings, "mesh_export_tri_method")
9696
sub.prop(settings, "mesh_export_keep_normals")
9797

@@ -135,7 +135,10 @@ def poll(cls, context):
135135
# Show only if the main panel exists and path is set
136136
settings = context.scene.mesh_exporter
137137
# Check if the path property itself exists and is not None/empty
138-
return settings and settings.mesh_export_path is not None and settings.mesh_export_path != ""
138+
return (settings
139+
and settings.mesh_export_path
140+
is not None
141+
and settings.mesh_export_path != "")
139142

140143
def draw_header(self, context):
141144
layout = self.layout
@@ -149,7 +152,7 @@ def draw(self, context):
149152
layout.use_property_decorate = False
150153

151154
# Enable/disable based on the header checkbox
152-
# layout.enabled = context.scene.mesh_exporter.mesh_export_lod
155+
layout.enabled = settings.mesh_export_lod
153156

154157
col = layout.column(align=True)
155158
col.prop(settings, "mesh_export_lod_count")

properties.py

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ class MeshExporterSettings(PropertyGroup):
1616
# Export path property
1717
# Default to the current blend file directory
1818
# with a subfolder "exported_meshes"
19-
mesh_export_path = StringProperty(
19+
mesh_export_path: StringProperty(
2020
name="Export Path",
2121
description="Path to export meshes",
2222
default="//exported_meshes/",
2323
subtype="DIR_PATH"
2424
)
2525

2626
# Export format property
27-
mesh_export_format = EnumProperty(
27+
mesh_export_format: EnumProperty(
2828
name="Format",
2929
description="File format to export meshes",
3030
items=[
@@ -38,7 +38,7 @@ class MeshExporterSettings(PropertyGroup):
3838
)
3939

4040
# Scale property
41-
mesh_export_scale = FloatProperty(
41+
mesh_export_scale: FloatProperty(
4242
name="Scale",
4343
description="Scale factor for exported meshes",
4444
default=1.0,
@@ -49,7 +49,7 @@ class MeshExporterSettings(PropertyGroup):
4949
)
5050

5151
# Coordinate system properties
52-
mesh_export_coord_up = EnumProperty(
52+
mesh_export_coord_up: EnumProperty(
5353
name="Up Axis",
5454
description="Up axis for exported meshes",
5555
items=[
@@ -59,7 +59,7 @@ class MeshExporterSettings(PropertyGroup):
5959
default="Z"
6060
)
6161

62-
mesh_export_coord_forward = EnumProperty(
62+
mesh_export_coord_forward: EnumProperty(
6363
name="Forward Axis",
6464
description="Forward axis for exported meshes",
6565
items=[
@@ -70,21 +70,21 @@ class MeshExporterSettings(PropertyGroup):
7070
)
7171

7272
# Zero location property
73-
mesh_export_zero_location = BoolProperty(
73+
mesh_export_zero_location: BoolProperty(
7474
name="Zero Location",
7575
description="Zero location of the object copy before export",
7676
default=True
7777
)
7878

7979
# Triangulate properties
80-
mesh_export_tri = BoolProperty(
80+
mesh_export_tri: BoolProperty(
8181
name="Triangulate Faces",
8282
description="Convert all faces to triangles on the copy",
8383
default=True
8484
)
8585

8686
# Triangulate method property
87-
mesh_export_tri_method = EnumProperty(
87+
mesh_export_tri_method: EnumProperty(
8888
name="Method",
8989
description="Method used for triangulating quads",
9090
items=[
@@ -101,42 +101,42 @@ class MeshExporterSettings(PropertyGroup):
101101
)
102102

103103
# Keep normals property
104-
mesh_export_keep_normals = BoolProperty(
104+
mesh_export_keep_normals: BoolProperty(
105105
name="Keep Normals",
106106
description="Preserve normal vectors during triangulation",
107107
default=True
108108
)
109109

110110
# Prefix and suffix properties
111-
mesh_export_prefix = StringProperty(
111+
mesh_export_prefix: StringProperty(
112112
name="Prefix",
113113
description="Prefix for exported file names",
114114
default=""
115115
)
116116

117-
mesh_export_suffix = StringProperty(
117+
mesh_export_suffix: StringProperty(
118118
name="Suffix",
119119
description="Suffix for exported file names",
120120
default=""
121121
)
122122

123123
# LOD properties
124-
mesh_export_lod = BoolProperty(
124+
mesh_export_lod: BoolProperty(
125125
name="Generate LODs",
126126
description="Generate additional LODs using Decimate (modifies copy)",
127127
default=False
128128
)
129129

130130
# LOD count property
131-
mesh_export_lod_count = IntProperty(
131+
mesh_export_lod_count: IntProperty(
132132
name="Additional LODs",
133133
description="How many additional LODs to generate (LOD1 to LOD4)",
134134
default=4, min=1, max=4, # Max 4 due to 4 ratio properties
135135
)
136136

137137
# LOD type property
138138
# Note: I've excluded "UNSUBDIVIDE" and "DISSOLVE"
139-
mesh_export_lod_type = EnumProperty(
139+
mesh_export_lod_type: EnumProperty(
140140
name="Decimation Type",
141141
description="Type of decimation to use for generating LODs",
142142
items=[
@@ -148,22 +148,22 @@ class MeshExporterSettings(PropertyGroup):
148148
)
149149

150150
# LOD ratio properties
151-
mesh_export_lod_ratio_01 = FloatProperty(
151+
mesh_export_lod_ratio_01: FloatProperty(
152152
name="LOD1 Ratio",
153153
description="Decimate factor for LOD 1",
154154
default=0.75, min=0.0, max=1.0, subtype="FACTOR"
155155
)
156-
mesh_export_lod_ratio_02 = FloatProperty(
156+
mesh_export_lod_ratio_02: FloatProperty(
157157
name="LOD2 Ratio",
158158
description="Decimate factor for LOD 2",
159159
default=0.50, min=0.0, max=1.0, subtype="FACTOR"
160160
)
161-
mesh_export_lod_ratio_03 = FloatProperty(
161+
mesh_export_lod_ratio_03: FloatProperty(
162162
name="LOD3 Ratio",
163163
description="Decimate factor for LOD 3",
164164
default=0.25, min=0.0, max=1.0, subtype="FACTOR"
165165
)
166-
mesh_export_lod_ratio_04 = FloatProperty(
166+
mesh_export_lod_ratio_04: FloatProperty(
167167
name="LOD4 Ratio",
168168
description="Decimate factor for LOD 4",
169169
default=0.10, min=0.0, max=1.0, subtype="FACTOR"
@@ -172,8 +172,18 @@ class MeshExporterSettings(PropertyGroup):
172172

173173
def register_properties():
174174
"""Register the property group and create the Scene property"""
175-
bpy.utils.register_class(MeshExporterSettings)
176-
bpy.types.Scene.mesh_exporter = PointerProperty(type=MeshExporterSettings)
175+
try:
176+
bpy.utils.register_class(MeshExporterSettings)
177+
bpy.types.Scene.mesh_exporter = PointerProperty(
178+
type=MeshExporterSettings)
179+
# Verification
180+
test = bpy.types.Scene.bl_rna.properties.get("mesh_exporter")
181+
if test:
182+
print(f"Successfully registered mesh_exporter: {test}")
183+
else:
184+
print("Failed to register mesh_exporter property")
185+
except Exception as e:
186+
print(f"Error registering properties: {e}")
177187

178188

179189
def unregister_properties():

0 commit comments

Comments
 (0)