@@ -64,7 +64,7 @@ use bevy_platform::{
6464} ;
6565use bevy_tasks:: IoTaskPool ;
6666use futures_io:: ErrorKind ;
67- use futures_lite:: { AsyncReadExt , AsyncWriteExt , StreamExt } ;
67+ use futures_lite:: { AsyncWriteExt , StreamExt } ;
6868use futures_util:: { select_biased, FutureExt } ;
6969use std:: {
7070 path:: { Path , PathBuf } ,
@@ -966,9 +966,6 @@ impl AssetProcessor {
966966 err,
967967 } ;
968968
969- // Note: we get the asset source reader first because we don't want to create meta files for assets that don't have source files
970- let mut byte_reader = reader. read ( path) . await . map_err ( reader_err) ?;
971-
972969 let ( mut source_meta, meta_bytes, processor) = match reader. read_meta_bytes ( path) . await {
973970 Ok ( meta_bytes) => {
974971 let minimal: AssetMetaMinimal = ron:: de:: from_bytes ( & meta_bytes) . map_err ( |e| {
@@ -1023,19 +1020,14 @@ impl AssetProcessor {
10231020
10241021 let processed_writer = source. processed_writer ( ) ?;
10251022
1026- let mut asset_bytes = Vec :: new ( ) ;
1027- byte_reader
1028- . read_to_end ( & mut asset_bytes)
1029- . await
1030- . map_err ( |e| ProcessError :: AssetReaderError {
1031- path : asset_path. clone ( ) ,
1032- err : AssetReaderError :: Io ( e. into ( ) ) ,
1033- } ) ?;
1034-
1035- // PERF: in theory these hashes could be streamed if we want to avoid allocating the whole asset.
1036- // The downside is that reading assets would need to happen twice (once for the hash and once for the asset loader)
1037- // Hard to say which is worse
1038- let new_hash = get_asset_hash ( & meta_bytes, & asset_bytes) ;
1023+ let new_hash = {
1024+ // Create a reader just for computing the hash. Keep this scoped here so that we drop it
1025+ // as soon as the hash is computed.
1026+ let mut reader_for_hash = reader. read ( path) . await . map_err ( reader_err) ?;
1027+ get_asset_hash ( & meta_bytes, & mut reader_for_hash)
1028+ . await
1029+ . map_err ( reader_err) ?
1030+ } ;
10391031 let mut new_processed_info = ProcessedInfo {
10401032 hash : new_hash,
10411033 full_hash : new_hash,
@@ -1066,6 +1058,16 @@ impl AssetProcessor {
10661058 }
10671059 }
10681060
1061+ // Create a reader just for the actual process. Note: this means that we're performing two
1062+ // reads for the same file (but we avoid having to load the whole file into memory). For
1063+ // some sources (like local file systems), this is not a big deal, but for other sources
1064+ // like an HTTP asset sources, this could be an entire additional download (if the asset
1065+ // source doesn't do any caching). In practice, most sources being processed are likely to
1066+ // be local, and processing in general is a publish-time operation, so it's not likely to be
1067+ // too big a deal. If in the future, we decide we want to avoid this repeated read, we could
1068+ // "ask" the asset source if it prefers avoiding repeated reads or not.
1069+ let mut reader_for_process = reader. read ( path) . await . map_err ( reader_err) ?;
1070+
10691071 // Note: this lock must remain alive until all processed asset and meta writes have finished (or failed)
10701072 // See ProcessedAssetInfo::file_transaction_lock docs for more info
10711073 let _transaction_lock = {
@@ -1081,8 +1083,12 @@ impl AssetProcessor {
10811083 if let Some ( processor) = processor {
10821084 let mut writer = processed_writer. write ( path) . await . map_err ( writer_err) ?;
10831085 let mut processed_meta = {
1084- let mut context =
1085- ProcessContext :: new ( self , asset_path, & asset_bytes, & mut new_processed_info) ;
1086+ let mut context = ProcessContext :: new (
1087+ self ,
1088+ asset_path,
1089+ reader_for_process,
1090+ & mut new_processed_info,
1091+ ) ;
10861092 processor
10871093 . process ( & mut context, source_meta, & mut * writer)
10881094 . await ?
@@ -1112,10 +1118,13 @@ impl AssetProcessor {
11121118 . await
11131119 . map_err ( writer_err) ?;
11141120 } else {
1115- processed_writer
1116- . write_bytes ( path , & asset_bytes )
1121+ let mut writer = processed_writer. write ( path ) . await . map_err ( writer_err ) ? ;
1122+ futures_lite :: io :: copy ( & mut reader_for_process , & mut writer )
11171123 . await
1118- . map_err ( writer_err) ?;
1124+ . map_err ( |err| ProcessError :: AssetWriterError {
1125+ path : asset_path. clone_owned ( ) ,
1126+ err : err. into ( ) ,
1127+ } ) ?;
11191128 * source_meta. processed_info_mut ( ) = Some ( new_processed_info. clone ( ) ) ;
11201129 let meta_bytes = source_meta. serialize ( ) ;
11211130 processed_writer
0 commit comments