2
2
using Assets . Scripts . Core . Buriko ;
3
3
using BGICompiler . Compiler ;
4
4
using MOD . Scripts . Core . Audio ;
5
+ using Newtonsoft . Json ;
5
6
using System ;
6
7
using System . Collections . Generic ;
7
8
using System . ComponentModel ;
8
9
using System . IO ;
9
10
using System . Linq ;
11
+ using System . Security . Cryptography ;
10
12
using UnityEngine ;
11
13
12
14
namespace Assets . Scripts . Core . AssetManagement
@@ -225,12 +227,127 @@ public string PathToAssetWithName(string name, PathCascadeList artset)
225
227
return null ;
226
228
}
227
229
230
+ class ScriptInfo
231
+ {
232
+ public string name ;
233
+ public DateTime lastWriteTime ;
234
+ public long length ;
235
+ public string md5String ;
236
+
237
+ public static ScriptInfo TryGetOrNull ( string path )
238
+ {
239
+ try
240
+ {
241
+ string md5String ;
242
+ using ( var md5 = MD5 . Create ( ) )
243
+ {
244
+ using ( var stream = File . OpenRead ( path ) )
245
+ {
246
+ md5String = BitConverter . ToString ( md5 . ComputeHash ( stream ) ) . Replace ( "-" , "" ) ;
247
+ }
248
+ }
249
+
250
+ FileInfo fileInfo = new FileInfo ( path ) ;
251
+
252
+ return new ScriptInfo
253
+ {
254
+ name = Path . GetFileNameWithoutExtension ( fileInfo . Name ) ,
255
+ lastWriteTime = fileInfo . LastWriteTime ,
256
+ length = fileInfo . Length ,
257
+ md5String = md5String ,
258
+ } ;
259
+ }
260
+ catch ( Exception e )
261
+ {
262
+ Debug . LogError ( $ "Failed to get script info for { path } : { e } ") ;
263
+ }
264
+
265
+ return null ;
266
+ }
267
+ }
268
+
269
+ private bool ScriptNeedsCompile ( Dictionary < string , ScriptInfo > oldInfoDictionary , ScriptInfo txt , ScriptInfo mg , string textDescription , string mgDescription )
270
+ {
271
+ // If the mg file doensn't exist or can't be accessed, do re-compile
272
+ if ( mg == null )
273
+ {
274
+ Debug . Log ( $ "ScriptNeedsCompile(): Compiling { textDescription } as mg file { mgDescription } does not exist or can't be accessed") ;
275
+ return true ;
276
+ }
277
+
278
+ // This implies the txt file doesn't exist, which should never happen but just try to recompile anyway in this case
279
+ if ( txt == null )
280
+ {
281
+ Debug . Log ( $ "ScriptNeedsCompile(): WARNING: { textDescription } can't be accessed or does not exist - trying to compile anyway") ;
282
+ return true ;
283
+ }
284
+
285
+ //// Compile if the .txt is newer than the .mg file
286
+ //if (txt.lastWriteTime > mg.lastWriteTime)
287
+ //{
288
+ // Debug.Log($"ScriptNeedsCompile(): Compiling {textDescription} as it is newer than mg file {mgDescription} (txt: {txt.lastWriteTime}), mg: {mg.lastWriteTime}");
289
+ // return true;
290
+ //}
291
+
292
+ // Compare the current .txt file against the last recorded information about the .txt file
293
+ if ( oldInfoDictionary . TryGetValue ( txt . name , out ScriptInfo oldInfo ) )
294
+ {
295
+ // Compile if the file size has changed since last time
296
+ if ( oldInfo . length != txt . length )
297
+ {
298
+ Debug . Log ( $ "ScriptNeedsCompile(): Compiling { textDescription } as size differs from previous (old: { oldInfo . length } bytes, new: { txt . length } bytes)") ;
299
+ return true ;
300
+ }
301
+
302
+ // Compile if the file's MD5 has changed
303
+ if ( oldInfo . md5String != txt . md5String )
304
+ {
305
+ Debug . Log ( $ "ScriptNeedsCompile(): Compiling { textDescription } as MD5 differs from previous (old: { oldInfo . md5String } , new: { txt . md5String } )") ;
306
+ return true ;
307
+ }
308
+ }
309
+ else
310
+ {
311
+ // If the file hasn't been recorded in the dictionary, re-compile it
312
+ Debug . Log ( $ "ScriptNeedsCompile(): Compiling { textDescription } as it doesn't exist in the .txt info dictionary.") ;
313
+ return true ;
314
+ }
315
+
316
+ return false ;
317
+ }
318
+
228
319
public void CompileFolder ( string srcDir , string destDir )
229
320
{
321
+ JsonSerializer jsonSerializer = new JsonSerializer ( ) ;
322
+ string txtInfoDictionaryPath = Path . Combine ( destDir , "txtInfoDictionary.json" ) ;
230
323
string [ ] txtList1 = Directory . GetFiles ( srcDir , "*.txt" ) ;
231
324
string [ ] mgList1 = Directory . GetFiles ( destDir , "*.mg" ) ;
232
325
List < string > txtFilenameNoExtensionList = new List < string > ( ) ;
233
326
327
+ Dictionary < string , ScriptInfo > oldTxtInfoDictionary = new Dictionary < string , ScriptInfo > ( ) ;
328
+ Dictionary < string , ScriptInfo > newTxtInfoDictionary = new Dictionary < string , ScriptInfo > ( ) ;
329
+
330
+ try
331
+ {
332
+ if ( File . Exists ( txtInfoDictionaryPath ) )
333
+ {
334
+ using ( StreamReader sw = new StreamReader ( txtInfoDictionaryPath ) )
335
+ using ( JsonReader reader = new JsonTextReader ( sw ) )
336
+ {
337
+ List < ScriptInfo > scriptInfoList = jsonSerializer . Deserialize < List < ScriptInfo > > ( reader ) ;
338
+ foreach ( ScriptInfo info in scriptInfoList )
339
+ {
340
+ oldTxtInfoDictionary [ info . name ] = info ;
341
+ }
342
+ }
343
+
344
+ }
345
+ }
346
+ catch ( Exception e )
347
+ {
348
+ Debug . LogError ( $ "CompileFolder(): Failed to deserialize { txtInfoDictionaryPath } : { e } ") ;
349
+ }
350
+
234
351
string [ ] txtList = txtList1 ;
235
352
foreach ( string txtPath1 in txtList )
236
353
{
@@ -242,16 +359,13 @@ public void CompileFolder(string srcDir, string destDir)
242
359
string txtPath = txtPath1 ;
243
360
string mgPath = Path . Combine ( destDir , fileNameWithoutExtension ) + ".mg" ;
244
361
245
- // (Re-)compile scripts if:
246
- // - the corresponding .mg file doesn't exist
247
- // - the corresponding .mg file is newer than the source .txt file
248
- if ( File . Exists ( mgPath ) )
362
+ ScriptInfo txtInfo = ScriptInfo . TryGetOrNull ( txtPath ) ;
363
+ ScriptInfo mgInfo = File . Exists ( mgPath ) ? ScriptInfo . TryGetOrNull ( mgPath ) : null ;
364
+
365
+ if ( ! ScriptNeedsCompile ( oldTxtInfoDictionary , txtInfo , mgInfo , Path . GetFileName ( txtPath ) , Path . GetFileName ( mgPath ) ) )
249
366
{
250
- if ( File . GetLastWriteTime ( txtPath ) <= File . GetLastWriteTime ( mgPath ) )
251
- {
252
- continue ;
253
- }
254
- Debug . Log ( $ "Script { mgPath } last compiled { File . GetLastWriteTime ( mgPath ) } (source { txtPath } updated on { File . GetLastWriteTime ( txtPath ) } )") ;
367
+ newTxtInfoDictionary [ txtInfo . name ] = txtInfo ;
368
+ continue ;
255
369
}
256
370
257
371
// Try to compile the file, but if an exception occurs just ignore it and move on to the next script
@@ -260,6 +374,7 @@ public void CompileFolder(string srcDir, string destDir)
260
374
{
261
375
new BGItoMG ( txtPath , mgPath ) ;
262
376
numCompileOK ++ ;
377
+ newTxtInfoDictionary [ txtInfo . name ] = txtInfo ;
263
378
}
264
379
catch ( Exception arg )
265
380
{
@@ -269,6 +384,17 @@ public void CompileFolder(string srcDir, string destDir)
269
384
}
270
385
}
271
386
387
+ if ( numCompileOK > 0 && numCompileFail == 0 )
388
+ {
389
+ // save scriptInfoDictionary to file as at least one .txt file has changed and succesfully been compiled
390
+ // we don't want to update the dictionary if any script file failed to compile as from then on it would never be updated
391
+ using ( StreamWriter sw = new StreamWriter ( txtInfoDictionaryPath ) )
392
+ using ( JsonTextWriter writer = new JsonTextWriter ( sw ) )
393
+ {
394
+ jsonSerializer . Serialize ( writer , newTxtInfoDictionary . Values . ToList ( ) ) ;
395
+ }
396
+ }
397
+
272
398
// Delete .mg files with no corresponding .txt file
273
399
string [ ] mgList = mgList1 ;
274
400
foreach ( string mgPath in mgList )
0 commit comments