@@ -557,6 +557,108 @@ def export_material_ref(self, bobject: bpy.types.Object, material, index, o):
557557 self .material_array .append (material )
558558 o ['material_refs' ].append (arm .utils .asset_name (material ))
559559
560+ def collect_tilesheet_meshes (self , scene : bpy .types .Scene ):
561+ """Collects meshes and materials referenced by tilesheet actions.
562+
563+ When a tilesheet action references a mesh for swapping, that mesh and its
564+ materials need to be exported even though they're not directly in the scene.
565+ """
566+ print (f"[Tilesheet] Collecting meshes from scene: { scene .name } " )
567+
568+ # Collect all objects including those inside collection instances
569+ objects_to_check = list (scene .collection .all_objects .values ())
570+
571+ # Also check inside collection instances (for linked collections)
572+ for bobject in scene .collection .all_objects .values ():
573+ if bobject .instance_type == 'COLLECTION' and bobject .instance_collection is not None :
574+ for cobj in bobject .instance_collection .all_objects :
575+ if cobj not in objects_to_check :
576+ objects_to_check .append (cobj )
577+
578+ for bobject in objects_to_check :
579+ if bobject .type != 'MESH' :
580+ continue
581+ if not bobject .arm_tilesheet_enabled :
582+ continue
583+
584+ print (f"[Tilesheet] Found tilesheet object: { bobject .name } " )
585+ print (f"[Tilesheet] Actions count: { len (bobject .arm_tilesheet_actionlist )} " )
586+
587+ # Get the library path if this object's mesh is linked
588+ library_path = None
589+ if bobject .data and bobject .data .library :
590+ library_path = bobject .data .library .filepath
591+ print (f"[Tilesheet] Library path: { library_path } " )
592+
593+ for action in bobject .arm_tilesheet_actionlist :
594+ print (f"[Tilesheet] Action: { action .name } , mesh_prop: '{ action .mesh_prop } '" )
595+ if action .mesh_prop == '' :
596+ continue
597+
598+ # Look up the mesh in bpy.data.meshes
599+ mesh_data = bpy .data .meshes .get (action .mesh_prop )
600+
601+ # If mesh not found and we have a library path, try to link it
602+ if mesh_data is None and library_path is not None :
603+ print (f"[Tilesheet] Mesh '{ action .mesh_prop } ' not in scene, linking from library..." )
604+ mesh_data = self .link_mesh_from_library (library_path , action .mesh_prop )
605+
606+ print (f"[Tilesheet] Mesh lookup result: { mesh_data } " )
607+ if mesh_data is None :
608+ print (f"[Tilesheet] WARNING: Mesh '{ action .mesh_prop } ' not found!" )
609+ continue
610+
611+ # Add mesh to mesh_array if not already present
612+ if mesh_data not in self .mesh_array :
613+ struct_name = arm .utils .asset_name (mesh_data )
614+ self .mesh_array [mesh_data ] = {"structName" : struct_name , "objectTable" : [bobject ]}
615+ print (f"[Tilesheet] Added mesh to export: { struct_name } " )
616+
617+ # Collect materials from the mesh
618+ for mat in mesh_data .materials :
619+ if mat is None :
620+ continue
621+ # Create tilesheet variant if needed
622+ if mat .library is not None :
623+ # For linked materials, set the flag directly
624+ mat .arm_tilesheet_flag = True
625+ mat .arm_cached = False
626+ if mat not in self .material_array :
627+ self .material_array .append (mat )
628+ print (f"[Tilesheet] Added linked material: { mat .name } " )
629+ else :
630+ # For local materials, create a variant with _armtile suffix
631+ variant_name = mat .name + '_armtile'
632+ variant_mat = bpy .data .materials .get (variant_name )
633+ if variant_mat is None :
634+ variant_mat = mat .copy ()
635+ variant_mat .name = variant_name
636+ variant_mat .arm_tilesheet_flag = True
637+ if variant_mat not in self .material_array :
638+ self .material_array .append (variant_mat )
639+ print (f"[Tilesheet] Added material variant: { variant_mat .name } " )
640+
641+ def link_mesh_from_library (self , library_path : str , mesh_name : str ):
642+ """Links a mesh from an external library file.
643+
644+ Returns the linked mesh data or None if not found.
645+ """
646+ try :
647+ # Use link instead of append to maintain the library reference
648+ with bpy .data .libraries .load (library_path , link = True ) as (data_from , data_to ):
649+ if mesh_name in data_from .meshes :
650+ data_to .meshes = [mesh_name ]
651+ print (f"[Tilesheet] Linking mesh '{ mesh_name } ' from { library_path } " )
652+ else :
653+ print (f"[Tilesheet] Mesh '{ mesh_name } ' not found in library. Available: { data_from .meshes [:10 ]} " )
654+ return None
655+
656+ # Return the newly linked mesh
657+ return bpy .data .meshes .get (mesh_name )
658+ except Exception as e :
659+ print (f"[Tilesheet] Error linking mesh: { e } " )
660+ return None
661+
560662 def export_particle_system_ref (self , psys : bpy .types .ParticleSystem , out_object ):
561663 if psys .settings .instance_object is None or psys .settings .render_type != 'OBJECT' or not psys .settings .instance_object .arm_export :
562664 return
@@ -2772,6 +2874,9 @@ def execute(self):
27722874 else :
27732875 self .output ['gravity' ] = [0.0 , 0.0 , 0.0 ]
27742876
2877+ # Collect meshes and materials referenced by tilesheet actions
2878+ self .collect_tilesheet_meshes (self .scene )
2879+
27752880 self .export_objects (self .scene )
27762881
27772882 # Create Viewport camera
0 commit comments