@@ -2,10 +2,14 @@ use alloc::{
22    boxed:: Box , 
33    collections:: BTreeMap , 
44    string:: { String ,  ToString } , 
5+     sync:: Arc , 
56    vec, 
67    vec:: Vec , 
78} ; 
8- use  bevy_platform:: collections:: HashMap ; 
9+ use  bevy_platform:: { 
10+     collections:: HashMap , 
11+     sync:: { Mutex ,  PoisonError } , 
12+ } ; 
913use  bevy_reflect:: TypePath ; 
1014use  core:: marker:: PhantomData ; 
1115use  futures_lite:: AsyncWriteExt ; 
@@ -1033,3 +1037,211 @@ fn asset_processor_processes_all_sources() {
10331037)"# 
10341038    ) ; 
10351039} 
1040+ 
1041+ #[ test]  
1042+ fn  nested_loads_of_processed_asset_reprocesses_on_reload ( )  { 
1043+     let  AppWithProcessor  { 
1044+         mut  app, 
1045+         default_source_dirs : 
1046+             ProcessingDirs  { 
1047+                 source :  default_source_dir, 
1048+                 processed :  default_processed_dir, 
1049+                 source_event_sender :  default_source_events, 
1050+             } , 
1051+         extra_sources_dirs, 
1052+     }  = create_app_with_asset_processor ( & [ "custom" . into ( ) ] ) ; 
1053+     let  ProcessingDirs  { 
1054+         source :  custom_source_dir, 
1055+         processed :  custom_processed_dir, 
1056+         source_event_sender :  custom_source_events, 
1057+     }  = extra_sources_dirs[ "custom" ] . clone ( ) ; 
1058+ 
1059+     #[ derive( Serialize ,  Deserialize ) ]  
1060+     enum  NesterSerialized  { 
1061+         Leaf ( String ) , 
1062+         Path ( String ) , 
1063+     } 
1064+ 
1065+     #[ derive( Asset ,  TypePath ) ]  
1066+     struct  Nester  { 
1067+         value :  String , 
1068+     } 
1069+ 
1070+     struct  NesterLoader ; 
1071+ 
1072+     impl  AssetLoader  for  NesterLoader  { 
1073+         type  Asset  = Nester ; 
1074+         type  Settings  = ( ) ; 
1075+         type  Error  = std:: io:: Error ; 
1076+ 
1077+         async  fn  load ( 
1078+             & self , 
1079+             reader :  & mut  dyn  Reader , 
1080+             _settings :  & Self :: Settings , 
1081+             load_context :  & mut  LoadContext < ' _ > , 
1082+         )  -> Result < Self :: Asset ,  Self :: Error >  { 
1083+             let  mut  bytes = vec ! [ ] ; 
1084+             reader. read_to_end ( & mut  bytes) . await ?; 
1085+ 
1086+             let  serialized:  NesterSerialized  = ron:: de:: from_bytes ( & bytes) . unwrap ( ) ; 
1087+             Ok ( match  serialized { 
1088+                 NesterSerialized :: Leaf ( value)  => Nester  {  value } , 
1089+                 NesterSerialized :: Path ( path)  => { 
1090+                     let  loaded_asset = load_context. loader ( ) . immediate ( ) . load ( path) . await . unwrap ( ) ; 
1091+                     loaded_asset. take ( ) 
1092+                 } 
1093+             } ) 
1094+         } 
1095+ 
1096+         fn  extensions ( & self )  -> & [ & str ]  { 
1097+             & [ "nest" ] 
1098+         } 
1099+     } 
1100+ 
1101+     struct  AddTextToNested ( String ,  Arc < Mutex < u32 > > ) ; 
1102+ 
1103+     impl  MutateAsset < Nester >  for  AddTextToNested  { 
1104+         fn  mutate ( & self ,  asset :  & mut  Nester )  { 
1105+             asset. value . push_str ( & self . 0 ) ; 
1106+ 
1107+             * self . 1 . lock ( ) . unwrap_or_else ( PoisonError :: into_inner)  += 1 ; 
1108+         } 
1109+     } 
1110+ 
1111+     fn  serialize_as_leaf ( value :  String )  -> String  { 
1112+         let  serialized = NesterSerialized :: Leaf ( value) ; 
1113+         ron:: ser:: to_string ( & serialized) . unwrap ( ) 
1114+     } 
1115+ 
1116+     struct  NesterSaver ; 
1117+ 
1118+     impl  AssetSaver  for  NesterSaver  { 
1119+         type  Asset  = Nester ; 
1120+         type  Error  = std:: io:: Error ; 
1121+         type  Settings  = ( ) ; 
1122+         type  OutputLoader  = NesterLoader ; 
1123+ 
1124+         async  fn  save ( 
1125+             & self , 
1126+             writer :  & mut  crate :: io:: Writer , 
1127+             asset :  crate :: saver:: SavedAsset < ' _ ,  Self :: Asset > , 
1128+             _settings :  & Self :: Settings , 
1129+         )  -> Result < <Self :: OutputLoader  as  AssetLoader >:: Settings ,  Self :: Error >  { 
1130+             let  serialized = serialize_as_leaf ( asset. get ( ) . value . clone ( ) ) ; 
1131+             writer. write_all ( serialized. as_bytes ( ) ) . await 
1132+         } 
1133+     } 
1134+ 
1135+     let  process_counter = Arc :: new ( Mutex :: new ( 0 ) ) ; 
1136+ 
1137+     type  NesterProcessor  = LoadTransformAndSave < 
1138+         NesterLoader , 
1139+         RootAssetTransformer < AddTextToNested ,  Nester > , 
1140+         NesterSaver , 
1141+     > ; 
1142+     app. init_asset :: < Nester > ( ) 
1143+         . register_asset_loader ( NesterLoader ) 
1144+         . register_asset_processor ( NesterProcessor :: new ( 
1145+             RootAssetTransformer :: new ( AddTextToNested ( "-he" . into ( ) ,  process_counter. clone ( ) ) ) , 
1146+             NesterSaver , 
1147+         ) ) 
1148+         . set_default_asset_processor :: < NesterProcessor > ( "nest" ) ; 
1149+ 
1150+     // This test also checks that processing of nested assets can occur across asset sources. 
1151+     custom_source_dir. insert_asset_text ( 
1152+         Path :: new ( "top.nest" ) , 
1153+         & ron:: ser:: to_string ( & NesterSerialized :: Path ( "middle.nest" . into ( ) ) ) . unwrap ( ) , 
1154+     ) ; 
1155+     default_source_dir. insert_asset_text ( 
1156+         Path :: new ( "middle.nest" ) , 
1157+         & ron:: ser:: to_string ( & NesterSerialized :: Path ( "custom://bottom.nest" . into ( ) ) ) . unwrap ( ) , 
1158+     ) ; 
1159+     custom_source_dir. insert_asset_text ( Path :: new ( "bottom.nest" ) ,  & serialize_as_leaf ( "he" . into ( ) ) ) ; 
1160+     default_source_dir. insert_asset_text ( 
1161+         Path :: new ( "unrelated.nest" ) , 
1162+         & serialize_as_leaf ( "tee" . into ( ) ) , 
1163+     ) ; 
1164+ 
1165+     run_app_until_finished_processing ( & mut  app) ; 
1166+ 
1167+     // The initial processing step should have processed all assets. 
1168+     assert_eq ! ( 
1169+         read_asset_as_string( & custom_processed_dir,  Path :: new( "bottom.nest" ) ) , 
1170+         serialize_as_leaf( "he-he" . into( ) ) 
1171+     ) ; 
1172+     assert_eq ! ( 
1173+         read_asset_as_string( & default_processed_dir,  Path :: new( "middle.nest" ) ) , 
1174+         serialize_as_leaf( "he-he-he" . into( ) ) 
1175+     ) ; 
1176+     assert_eq ! ( 
1177+         read_asset_as_string( & custom_processed_dir,  Path :: new( "top.nest" ) ) , 
1178+         serialize_as_leaf( "he-he-he-he" . into( ) ) 
1179+     ) ; 
1180+     assert_eq ! ( 
1181+         read_asset_as_string( & default_processed_dir,  Path :: new( "unrelated.nest" ) ) , 
1182+         serialize_as_leaf( "tee-he" . into( ) ) 
1183+     ) ; 
1184+ 
1185+     let  get_process_count = || { 
1186+         * process_counter
1187+             . lock ( ) 
1188+             . unwrap_or_else ( PoisonError :: into_inner) 
1189+     } ; 
1190+     assert_eq ! ( get_process_count( ) ,  4 ) ; 
1191+ 
1192+     // Now we will only send a single source event, but that should still result in all related 
1193+     // assets being reprocessed. 
1194+ 
1195+     custom_source_dir. insert_asset_text ( Path :: new ( "bottom.nest" ) ,  & serialize_as_leaf ( "HEE" . into ( ) ) ) ; 
1196+     custom_source_events
1197+         . send_blocking ( AssetSourceEvent :: ModifiedAsset ( "bottom.nest" . into ( ) ) ) 
1198+         . unwrap ( ) ; 
1199+ 
1200+     run_app_until_finished_processing ( & mut  app) ; 
1201+ 
1202+     assert_eq ! ( 
1203+         read_asset_as_string( & custom_processed_dir,  Path :: new( "bottom.nest" ) ) , 
1204+         serialize_as_leaf( "HEE-he" . into( ) ) 
1205+     ) ; 
1206+     assert_eq ! ( 
1207+         read_asset_as_string( & default_processed_dir,  Path :: new( "middle.nest" ) ) , 
1208+         serialize_as_leaf( "HEE-he-he" . into( ) ) 
1209+     ) ; 
1210+     assert_eq ! ( 
1211+         read_asset_as_string( & custom_processed_dir,  Path :: new( "top.nest" ) ) , 
1212+         serialize_as_leaf( "HEE-he-he-he" . into( ) ) 
1213+     ) ; 
1214+     assert_eq ! ( 
1215+         read_asset_as_string( & default_processed_dir,  Path :: new( "unrelated.nest" ) ) , 
1216+         serialize_as_leaf( "tee-he" . into( ) ) 
1217+     ) ; 
1218+ 
1219+     assert_eq ! ( get_process_count( ) ,  7 ) ; 
1220+ 
1221+     // Send a modify event to the middle asset without changing the asset bytes. This should do 
1222+     // **nothing** since neither its dependencies nor its bytes have changed. 
1223+     default_source_events
1224+         . send_blocking ( AssetSourceEvent :: ModifiedAsset ( "middle.nest" . into ( ) ) ) 
1225+         . unwrap ( ) ; 
1226+ 
1227+     run_app_until_finished_processing ( & mut  app) ; 
1228+ 
1229+     assert_eq ! ( 
1230+         read_asset_as_string( & custom_processed_dir,  Path :: new( "bottom.nest" ) ) , 
1231+         serialize_as_leaf( "HEE-he" . into( ) ) 
1232+     ) ; 
1233+     assert_eq ! ( 
1234+         read_asset_as_string( & default_processed_dir,  Path :: new( "middle.nest" ) ) , 
1235+         serialize_as_leaf( "HEE-he-he" . into( ) ) 
1236+     ) ; 
1237+     assert_eq ! ( 
1238+         read_asset_as_string( & custom_processed_dir,  Path :: new( "top.nest" ) ) , 
1239+         serialize_as_leaf( "HEE-he-he-he" . into( ) ) 
1240+     ) ; 
1241+     assert_eq ! ( 
1242+         read_asset_as_string( & default_processed_dir,  Path :: new( "unrelated.nest" ) ) , 
1243+         serialize_as_leaf( "tee-he" . into( ) ) 
1244+     ) ; 
1245+ 
1246+     assert_eq ! ( get_process_count( ) ,  7 ) ; 
1247+ } 
0 commit comments