@@ -201,7 +201,7 @@ public Half[] GetData(int offset, int dyeId = 0)
201
201
} } ,
202
202
} ;
203
203
204
- public StainingTemplateEntry ( byte [ ] data , int offset , EStainingTemplate templateType )
204
+ public StainingTemplateEntry ( byte [ ] data , int offset , EStainingTemplate templateType , bool oldFormat = false )
205
205
{
206
206
var arrayEnds = new List < ushort > ( ) ;
207
207
var start = offset ;
@@ -212,9 +212,9 @@ public StainingTemplateEntry(byte[] data, int offset, EStainingTemplate template
212
212
_ItemCount = 5 ;
213
213
}
214
214
215
+ var numDyes = oldFormat ? 128 : 254 ;
215
216
216
217
// This format sucks.
217
- var moreData = new List < ushort > ( ) ;
218
218
for ( int i = 0 ; i < _ItemCount ; i ++ )
219
219
{
220
220
arrayEnds . Add ( BitConverter . ToUInt16 ( data , offset ) ) ;
@@ -244,17 +244,17 @@ public StainingTemplateEntry(byte[] data, int offset, EStainingTemplate template
244
244
// Single entry used for everything.
245
245
type = StainingTemplateArrayType . Singleton ;
246
246
}
247
- if ( arraySize == 0 )
247
+ else if ( arraySize == 0 )
248
248
{
249
249
// No data.
250
250
continue ;
251
251
}
252
- else if ( arraySize < 128 )
252
+ else
253
253
{
254
254
// Indexed array, where we have [n] # of real entries,
255
- // then 128 one-byte index entries referencing those [n] entries.
255
+ // then 254 one-byte index entries referencing those [n] entries.
256
256
var totalBytes = ( arrayEnds [ x ] - lastOffset ) * 2 ;
257
- var remBytes = totalBytes - 128 ;
257
+ var remBytes = totalBytes - numDyes ;
258
258
259
259
indexStart = start + headerSize + ( lastOffset * 2 ) + remBytes ;
260
260
@@ -287,9 +287,7 @@ public StainingTemplateEntry(byte[] data, int offset, EStainingTemplate template
287
287
if ( type == StainingTemplateArrayType . Indexed )
288
288
{
289
289
var nArray = new List < Half [ ] > ( ) ;
290
- var indexes = new byte [ 128 ] ;
291
- var indexCopy = data . Skip ( indexStart ) . Take ( 129 ) . ToArray ( ) ;
292
- for ( int i = 0 ; i < 128 ; i ++ )
290
+ for ( int i = 0 ; i < numDyes ; i ++ )
293
291
{
294
292
try
295
293
{
@@ -321,7 +319,7 @@ public StainingTemplateEntry(byte[] data, int offset, EStainingTemplate template
321
319
322
320
if ( halfData . Count == 1 )
323
321
{
324
- for ( int i = 0 ; i < 127 ; i ++ )
322
+ for ( int i = 0 ; i < numDyes ; i ++ )
325
323
{
326
324
halfData . Add ( halfData [ 0 ] ) ;
327
325
}
@@ -337,8 +335,6 @@ public StainingTemplateEntry(byte[] data, int offset, EStainingTemplate template
337
335
338
336
lastOffset = arrayEnds [ x ] ;
339
337
}
340
-
341
- var length = lastOffset ;
342
338
}
343
339
344
340
}
@@ -378,41 +374,50 @@ public StainingTemplateFile(byte[] data, EStainingTemplate templateType)
378
374
TemplateType = templateType ;
379
375
// Get header size and # of entries.
380
376
var Header = BitConverter . ToUInt16 ( data , 0 ) ;
377
+ var Version = BitConverter . ToUInt16 ( data , 2 ) ;
381
378
var entryCount = BitConverter . ToUInt16 ( data , 4 ) ;
382
379
var unknown = BitConverter . ToUInt16 ( data , 6 ) ;
383
380
381
+ // Number got bigger since Patch 7.2
382
+ // stainingtemplate_gud.stm (DT / non-legacy) can be distinguished by Version number
383
+ // stainingtemplate.stm (EW / legacy) instead uses a janky heuristic
384
+ // Once CN/KR are updated to 7.2, this logic can be removed
385
+ bool oldFormat = false ;
386
+ if ( templateType == EStainingTemplate . Dawntrail && Version < 0x201 )
387
+ oldFormat = true ;
388
+ else if ( templateType == EStainingTemplate . Endwalker && ( data [ 0x0A ] != 0x00 || data [ 0x0B ] != 0x00 ) )
389
+ oldFormat = true ;
384
390
385
- Dictionary < ushort , int > entryOffsets = new Dictionary < ushort , int > ( ) ;
391
+ Dictionary < uint , int > entryOffsets = new Dictionary < uint , int > ( ) ;
386
392
387
- List < ushort > keys = new List < ushort > ( ) ;
388
- List < ushort > values = new List < ushort > ( ) ;
389
- List < int > sizes = new List < int > ( ) ;
393
+ List < uint > keys = new List < uint > ( ) ;
390
394
var offset = 8 ;
391
395
392
396
// Read template Ids
393
397
for ( int i = 0 ; i < entryCount ; i ++ )
394
398
{
395
- var key = BitConverter . ToUInt16 ( data , offset ) ;
399
+ var key = oldFormat ? ( uint ) BitConverter . ToUInt16 ( data , offset ) : BitConverter . ToUInt32 ( data , offset ) ;
396
400
entryOffsets . Add ( key , 0 ) ;
397
401
keys . Add ( key ) ;
398
- offset += 2 ;
402
+ offset += oldFormat ? 2 : 4 ;
399
403
}
400
404
401
- const int _headerEntrySize = 4 ;
405
+ const int _headerEntrySize = 8 ;
402
406
var endOfHeader = ( 8 + ( _headerEntrySize * entryCount ) ) ;
403
407
404
408
for ( int i = 0 ; i < entryCount ; i ++ )
405
409
{
406
- entryOffsets [ keys [ i ] ] = ( ( BitConverter . ToUInt16 ( data , offset ) * 2 ) + endOfHeader ) ;
407
- offset += 2 ;
410
+ var rawOffset = oldFormat ? ( uint ) BitConverter . ToUInt16 ( data , offset ) : BitConverter . ToUInt32 ( data , offset ) ;
411
+ entryOffsets [ keys [ i ] ] = ( int ) rawOffset * 2 + endOfHeader ;
412
+ offset += oldFormat ? 2 : 4 ;
408
413
}
409
414
410
415
411
416
var idx = 0 ;
412
417
foreach ( var kv in entryOffsets )
413
418
{
414
- var entry = new StainingTemplateEntry ( data , kv . Value , templateType ) ;
415
- Templates . Add ( kv . Key , entry ) ;
419
+ var entry = new StainingTemplateEntry ( data , kv . Value , templateType , oldFormat ) ;
420
+ Templates . Add ( ( ushort ) kv . Key , entry ) ;
416
421
idx ++ ;
417
422
}
418
423
}
0 commit comments