@@ -458,26 +458,36 @@ public static object SearchAssets(JObject @params)
458458 try
459459 {
460460 string [ ] guids = AssetDatabase . FindAssets ( string . Join ( " " , searchFilters ) , folderScope ) ;
461- List < object > results = new List < object > ( ) ;
461+
462+ // Optimization: Filter paths first without creating full data objects
463+ List < string > matchedPaths = new List < string > ( ) ;
462464 int totalFound = 0 ;
463465
464466 foreach ( string guid in guids )
465467 {
466468 string assetPath = AssetDatabase . GUIDToAssetPath ( guid ) ;
467469 if ( string . IsNullOrEmpty ( assetPath ) ) continue ;
468470
471+ // I/O Check only if filter is active
469472 if ( filterDateAfter . HasValue )
470473 {
471474 DateTime lastWriteTime = File . GetLastWriteTimeUtc ( Path . Combine ( Directory . GetCurrentDirectory ( ) , assetPath ) ) ;
472475 if ( lastWriteTime <= filterDateAfter . Value ) continue ;
473476 }
474477
478+ matchedPaths . Add ( assetPath ) ;
475479 totalFound ++ ;
476- results . Add ( GetAssetData ( assetPath , generatePreview ) ) ;
477480 }
478481
482+ // Optimization: Page BEFORE fetching heavy data
479483 int startIndex = ( pageNumber - 1 ) * pageSize ;
480- var pagedResults = results . Skip ( startIndex ) . Take ( pageSize ) . ToList ( ) ;
484+ var pagedPaths = matchedPaths . Skip ( startIndex ) . Take ( pageSize ) ;
485+
486+ List < object > pagedResults = new List < object > ( ) ;
487+ foreach ( var path in pagedPaths )
488+ {
489+ pagedResults . Add ( GetAssetData ( path , generatePreview ) ) ;
490+ }
481491
482492 return new SuccessResponse (
483493 $ "Found { totalFound } asset(s). Returning page { pageNumber } ({ pagedResults . Count } assets).",
@@ -606,27 +616,45 @@ private static bool ApplyObjectProperties(UnityEngine.Object target, JObject pro
606616 return modified ;
607617 }
608618
619+ // --- Reflection Cache ---
620+ private static readonly Dictionary < ( Type , string ) , System . Reflection . PropertyInfo > _propertyCache = new Dictionary < ( Type , string ) , System . Reflection . PropertyInfo > ( ) ;
621+ private static readonly Dictionary < ( Type , string ) , System . Reflection . FieldInfo > _fieldCache = new Dictionary < ( Type , string ) , System . Reflection . FieldInfo > ( ) ;
622+
609623 private static bool SetPropertyOrField ( object target , string memberName , JToken value , Type type )
610624 {
611625 type = type ?? target . GetType ( ) ;
612- System . Reflection . BindingFlags flags = System . Reflection . BindingFlags . Public | System . Reflection . BindingFlags . Instance | System . Reflection . BindingFlags . IgnoreCase ;
613-
626+ // System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase;
627+ // Note: Caching logic assumes flags don't change.
628+
614629 try {
615- System . Reflection . PropertyInfo propInfo = type . GetProperty ( memberName , flags ) ;
630+ // Try Property Cache
631+ if ( ! _propertyCache . TryGetValue ( ( type , memberName ) , out var propInfo ) )
632+ {
633+ propInfo = type . GetProperty ( memberName , System . Reflection . BindingFlags . Public | System . Reflection . BindingFlags . Instance | System . Reflection . BindingFlags . IgnoreCase ) ;
634+ if ( propInfo != null ) _propertyCache [ ( type , memberName ) ] = propInfo ;
635+ }
636+
616637 if ( propInfo != null && propInfo . CanWrite ) {
617638 object val = ConvertJTokenToType ( value , propInfo . PropertyType ) ;
618639 if ( val != null && ! object . Equals ( propInfo . GetValue ( target ) , val ) ) {
619640 propInfo . SetValue ( target , val ) ;
620641 return true ;
621642 }
622- } else {
623- System . Reflection . FieldInfo fieldInfo = type . GetField ( memberName , flags ) ;
624- if ( fieldInfo != null ) {
625- object val = ConvertJTokenToType ( value , fieldInfo . FieldType ) ;
626- if ( val != null && ! object . Equals ( fieldInfo . GetValue ( target ) , val ) ) {
627- fieldInfo . SetValue ( target , val ) ;
628- return true ;
629- }
643+ return false ; // Found but didn't change or couldn't convert
644+ }
645+
646+ // Try Field Cache
647+ if ( ! _fieldCache . TryGetValue ( ( type , memberName ) , out var fieldInfo ) )
648+ {
649+ fieldInfo = type . GetField ( memberName , System . Reflection . BindingFlags . Public | System . Reflection . BindingFlags . Instance | System . Reflection . BindingFlags . IgnoreCase ) ;
650+ if ( fieldInfo != null ) _fieldCache [ ( type , memberName ) ] = fieldInfo ;
651+ }
652+
653+ if ( fieldInfo != null ) {
654+ object val = ConvertJTokenToType ( value , fieldInfo . FieldType ) ;
655+ if ( val != null && ! object . Equals ( fieldInfo . GetValue ( target ) , val ) ) {
656+ fieldInfo . SetValue ( target , val ) ;
657+ return true ;
630658 }
631659 }
632660 } catch ( Exception ex ) {
@@ -680,35 +708,42 @@ private static object GetAssetData(string path, bool generatePreview = false)
680708
681709 string guid = AssetDatabase . AssetPathToGUID ( path ) ;
682710 Type assetType = AssetDatabase . GetMainAssetTypeAtPath ( path ) ;
683- UnityEngine . Object asset = AssetDatabase . LoadAssetAtPath < UnityEngine . Object > ( path ) ;
711+
712+ // Lazy Load: Only load object if preview is requested
713+ UnityEngine . Object asset = null ;
684714 string previewBase64 = null ;
685715 int previewWidth = 0 ;
686716 int previewHeight = 0 ;
717+ int instanceID = 0 ;
687718
688- if ( generatePreview && asset != null )
719+ if ( generatePreview )
689720 {
690- Texture2D preview = AssetPreview . GetAssetPreview ( asset ) ;
691- if ( preview != null ) {
692- try {
693- // (Preview generation logic omitted for brevity in summary, assume same logic)
694- RenderTexture rt = RenderTexture . GetTemporary ( preview . width , preview . height ) ;
695- Graphics . Blit ( preview , rt ) ;
696- RenderTexture previous = RenderTexture . active ;
697- RenderTexture . active = rt ;
698- Texture2D readablePreview = new Texture2D ( preview . width , preview . height , TextureFormat . RGB24 , false ) ;
699- readablePreview . ReadPixels ( new Rect ( 0 , 0 , rt . width , rt . height ) , 0 , 0 ) ;
700- readablePreview . Apply ( ) ;
701- RenderTexture . active = previous ;
702- RenderTexture . ReleaseTemporary ( rt ) ;
703-
704- byte [ ] pngData = readablePreview . EncodeToPNG ( ) ;
705- if ( pngData != null ) {
706- previewBase64 = Convert . ToBase64String ( pngData ) ;
707- previewWidth = readablePreview . width ;
708- previewHeight = readablePreview . height ;
709- }
710- UnityEngine . Object . DestroyImmediate ( readablePreview ) ;
711- } catch { }
721+ asset = AssetDatabase . LoadAssetAtPath < UnityEngine . Object > ( path ) ;
722+ if ( asset != null )
723+ {
724+ instanceID = asset . GetInstanceID ( ) ;
725+ Texture2D preview = AssetPreview . GetAssetPreview ( asset ) ;
726+ if ( preview != null ) {
727+ try {
728+ RenderTexture rt = RenderTexture . GetTemporary ( preview . width , preview . height ) ;
729+ Graphics . Blit ( preview , rt ) ;
730+ RenderTexture previous = RenderTexture . active ;
731+ RenderTexture . active = rt ;
732+ Texture2D readablePreview = new Texture2D ( preview . width , preview . height , TextureFormat . RGB24 , false ) ;
733+ readablePreview . ReadPixels ( new Rect ( 0 , 0 , rt . width , rt . height ) , 0 , 0 ) ;
734+ readablePreview . Apply ( ) ;
735+ RenderTexture . active = previous ;
736+ RenderTexture . ReleaseTemporary ( rt ) ;
737+
738+ byte [ ] pngData = readablePreview . EncodeToPNG ( ) ;
739+ if ( pngData != null ) {
740+ previewBase64 = Convert . ToBase64String ( pngData ) ;
741+ previewWidth = readablePreview . width ;
742+ previewHeight = readablePreview . height ;
743+ }
744+ UnityEngine . Object . DestroyImmediate ( readablePreview ) ;
745+ } catch { }
746+ }
712747 }
713748 }
714749
@@ -720,7 +755,7 @@ private static object GetAssetData(string path, bool generatePreview = false)
720755 name = Path . GetFileNameWithoutExtension ( path ) ,
721756 fileName = Path . GetFileName ( path ) ,
722757 isFolder = AssetDatabase . IsValidFolder ( path ) ,
723- instanceID = asset ? . GetInstanceID ( ) ?? 0 ,
758+ instanceID = instanceID , // 0 if not loaded
724759 lastWriteTimeUtc = File . GetLastWriteTimeUtc ( Path . Combine ( Directory . GetCurrentDirectory ( ) , path ) ) . ToString ( "o" ) ,
725760 previewBase64 = previewBase64 ,
726761 previewWidth = previewWidth ,
0 commit comments