@@ -125,10 +125,11 @@ await IOUtil.UnzipFiles(path, tempFolder, (file) =>
125
125
126
126
127
127
128
- var defaultOption = JsonConvert . DeserializeObject < PMPOptionJson > ( File . ReadAllText ( defModPath ) , new JsonSerializerSettings
128
+ var defaultOption = JsonConvert . DeserializeObject < PmpDefaultMod > ( File . ReadAllText ( defModPath ) , new JsonSerializerSettings
129
129
{
130
130
NullValueHandling = NullValueHandling . Ignore
131
131
} ) ;
132
+ defaultOption . Name = "Default" ;
132
133
133
134
var groups = new List < PMPGroupJson > ( ) ;
134
135
@@ -368,12 +369,15 @@ private static void ValidateOption(PmpStandardOptionJson op)
368
369
}
369
370
else if ( group . Type == "Multi" )
370
371
{
371
- var ordered = group . Options . OrderBy ( x => ( ( PmpStandardOptionJson ) x ) . Priority ) . ToList ( ) ;
372
+ var ordered = group . Options . OrderBy ( x => ( ( PmpMultiOptionJson ) x ) . Priority ) . ToList ( ) ;
372
373
373
374
// Bitmask options. Install in priority order.
374
375
foreach ( var op in ordered )
375
376
{
376
- var i = group . Options . IndexOf ( op ) ;
377
+ var multiGroup = group as PMPMultiGroupJson ;
378
+ var multiOpt = op as PmpMultiOptionJson ;
379
+
380
+ var i = multiGroup . OptionData . IndexOf ( multiOpt ) ;
377
381
var value = 1UL << i ;
378
382
if ( ( selected & value ) > 0 )
379
383
{
@@ -750,13 +754,14 @@ public static async Task CreateSimplePmp(string destination, BaseModpackData mod
750
754
{
751
755
Meta = new PMPMetaJson ( ) ,
752
756
Groups = new List < PMPGroupJson > ( ) ,
753
- DefaultMod = new PMPOptionJson ( ) ,
757
+ DefaultMod = new PmpDefaultMod ( ) ,
754
758
} ;
755
759
756
760
757
761
var files = await FileIdentifier . IdentifierListFromDictionary ( fileInfos ) ;
758
762
759
- pmp . DefaultMod = await CreatePmpStandardOption ( workingPath , "Default" , "The only option." , files , otherManipulations ) ;
763
+ pmp . DefaultMod = new PmpDefaultMod ( ) ;
764
+ await PopulatePmpStandardOption ( pmp . DefaultMod , workingPath , files , otherManipulations ) ;
760
765
761
766
pmp . Meta . Author = modpackMeta . Author ;
762
767
pmp . Meta . Name = modpackMeta . Name ;
@@ -823,17 +828,11 @@ public static async Task WritePmp(PMPJson pmp, string workingDirectory, string z
823
828
}
824
829
}
825
830
826
- public static async Task < PmpStandardOptionJson > CreatePmpStandardOption ( string workingPath , string name , string description , IEnumerable < FileIdentifier > files , IEnumerable < PMPManipulationWrapperJson > otherManipulations = null , string imagePath = null , int priority = 0 )
831
+ public static async Task PopulatePmpStandardOption ( PmpStandardOptionJson opt , string workingPath , IEnumerable < FileIdentifier > files , IEnumerable < PMPManipulationWrapperJson > otherManipulations = null )
827
832
{
828
- var opt = new PmpStandardOptionJson ( )
829
- {
830
- Name = name ,
831
- Description = description ,
832
- Files = new Dictionary < string , string > ( ) ,
833
- FileSwaps = new Dictionary < string , string > ( ) ,
834
- Manipulations = new List < PMPManipulationWrapperJson > ( ) ,
835
- Priority = priority ,
836
- } ;
833
+ opt . Files = new ( ) ;
834
+ opt . FileSwaps = new ( ) ;
835
+ opt . Manipulations = new ( ) ;
837
836
838
837
// TODO - Could paralell this? Unsure how big the gains would really be though,
839
838
// since the primary tasks are already paralelled internally, and there's little else heavy going on.
@@ -886,7 +885,6 @@ public static async Task<PmpStandardOptionJson> CreatePmpStandardOption(string w
886
885
opt . Manipulations . Add ( manip ) ;
887
886
}
888
887
}
889
- return opt ;
890
888
}
891
889
892
890
@@ -1271,7 +1269,7 @@ await Task.Run(async () =>
1271
1269
public class PMPJson
1272
1270
{
1273
1271
public PMPMetaJson Meta { get ; set ; }
1274
- public PMPOptionJson DefaultMod { get ; set ; }
1272
+ public PmpDefaultMod DefaultMod { get ; set ; }
1275
1273
public List < PMPGroupJson > Groups { get ; set ; }
1276
1274
1277
1275
[ JsonIgnore ]
@@ -1322,14 +1320,17 @@ public class PMPMetaJson
1322
1320
}
1323
1321
1324
1322
[ JsonConverter ( typeof ( JsonSubtypes ) , "Type" ) ]
1323
+ [ JsonSubtypes . KnownSubType ( typeof ( PMPSingleGroupJson ) , "Single" ) ]
1324
+ [ JsonSubtypes . KnownSubType ( typeof ( PMPMultiGroupJson ) , "Multi" ) ]
1325
1325
[ JsonSubtypes . KnownSubType ( typeof ( PMPImcGroupJson ) , "Imc" ) ]
1326
1326
public class PMPGroupJson
1327
1327
{
1328
+ public int Version = 0 ;
1328
1329
public string Name = "" ;
1329
1330
public string Description = "" ;
1330
- public int Priority ;
1331
1331
public string Image = "" ;
1332
1332
public int Page ;
1333
+ public int Priority ;
1333
1334
1334
1335
// "Multi", "Single", or "Imc"
1335
1336
public string Type = "" ;
@@ -1340,7 +1341,24 @@ public class PMPGroupJson
1340
1341
// Either single Index or Bitflag.
1341
1342
public ulong DefaultSettings ;
1342
1343
1343
- public List < PMPOptionJson > Options = new List < PMPOptionJson > ( ) ;
1344
+ [ JsonIgnore ]
1345
+ public virtual IReadOnlyList < PMPOptionJson > Options => throw new NotImplementedException ( $ "Unimplemented PMP group type: { Type } ") ;
1346
+ }
1347
+
1348
+ public class PMPSingleGroupJson : PMPGroupJson
1349
+ {
1350
+ [ JsonProperty ( PropertyName = "Options" , Order = 99 ) ]
1351
+ public List < PmpSingleOptionJson > OptionData = new ( ) ;
1352
+
1353
+ public override IReadOnlyList < PMPOptionJson > Options => OptionData ;
1354
+ }
1355
+
1356
+ public class PMPMultiGroupJson : PMPGroupJson
1357
+ {
1358
+ [ JsonProperty ( PropertyName = "Options" , Order = 99 ) ]
1359
+ public List < PmpMultiOptionJson > OptionData = new ( ) ;
1360
+
1361
+ public override IReadOnlyList < PMPOptionJson > Options => OptionData ;
1344
1362
}
1345
1363
1346
1364
public class PMPImcGroupJson : PMPGroupJson
@@ -1350,6 +1368,11 @@ public class PMPImcGroupJson : PMPGroupJson
1350
1368
public bool AllVariants ;
1351
1369
public bool OnlyAttributes ;
1352
1370
1371
+ [ JsonProperty ( PropertyName = "Options" , Order = 99 ) ]
1372
+ public List < PmpImcOptionJson > OptionData = new ( ) ;
1373
+
1374
+ public override IReadOnlyList < PMPOptionJson > Options => OptionData ;
1375
+
1353
1376
public XivDependencyRoot GetRoot ( )
1354
1377
{
1355
1378
var root = PMPExtensions . GetRootFromPenumbraValues ( Identifier . ObjectType , Identifier . PrimaryId , Identifier . BodySlot , Identifier . SecondaryId , Identifier . EquipSlot ) ;
@@ -1396,35 +1419,73 @@ public static PmpIdentifierJson FromRoot(XivDependencyRootInfo root, int variant
1396
1419
}
1397
1420
}
1398
1421
1399
- [ JsonConverter ( typeof ( JsonSubtypes ) ) ]
1400
- [ JsonSubtypes . FallBackSubType ( typeof ( PmpStandardOptionJson ) ) ]
1401
- [ JsonSubtypes . KnownSubTypeWithProperty ( typeof ( PmpDisableImcOptionJson ) , "IsDisableSubMod" ) ]
1402
- [ JsonSubtypes . KnownSubTypeWithProperty ( typeof ( PmpImcOptionJson ) , "AttributeMask" ) ]
1422
+ // This type will not be deserialized directly, as the correct sub-type will be known in advance
1403
1423
public class PMPOptionJson
1404
1424
{
1425
+ // For some reason the default order is that base class fields ordered last instead of first ...
1426
+ // Manually specifying the order of a bunch of option-related fields to fix that
1427
+ [ JsonProperty ( Order = - 10 ) ]
1405
1428
public string Name = "" ;
1429
+ [ JsonProperty ( Order = - 10 ) ]
1406
1430
public string Description = "" ;
1431
+ [ JsonProperty ( Order = - 10 ) ]
1407
1432
public string Image = "" ;
1433
+
1434
+ // TexTools loads/saves default_mod.json as this type, but these fields should not be present in default_mod
1435
+ [ JsonIgnore ] public virtual bool IsDataContainerOnly => false ;
1436
+
1437
+ public bool ShouldSerializeName ( ) { return ! IsDataContainerOnly ; }
1438
+ public bool ShouldSerializeDescription ( ) { return ! IsDataContainerOnly ; }
1439
+ public bool ShouldSerializeImage ( ) { return ! IsDataContainerOnly ; }
1408
1440
}
1409
1441
1410
1442
public class PmpStandardOptionJson : PMPOptionJson
1411
1443
{
1412
- public int Priority = 0 ;
1444
+ [ JsonProperty ( Order = 10 ) ]
1413
1445
public Dictionary < string , string > Files = new ( ) ;
1446
+ [ JsonProperty ( Order = 10 ) ]
1414
1447
public Dictionary < string , string > FileSwaps = new ( ) ;
1448
+ [ JsonProperty ( Order = 10 ) ]
1415
1449
public List < PMPManipulationWrapperJson > Manipulations = new ( ) ;
1416
1450
1417
1451
[ JsonIgnore ] public bool IsEmptyOption => ! (
1418
1452
( FileSwaps != null && FileSwaps . Count > 0 ) ||
1419
1453
( Manipulations != null && Manipulations . Count > 0 ) ||
1420
1454
( Files != null && Files . Count > 0 )
1421
1455
) ;
1456
+
1457
+ // TODO: Comment this out in the future to mimic Penumbra's behavior
1458
+ /*
1459
+ public bool ShouldSerializeFiles() { return Files != null && Files.Count > 0; }
1460
+ public bool ShouldSerializeFileSwaps() { return FileSwaps != null && FileSwaps.Count > 0; }
1461
+ public bool ShouldSerializeManipulations() { return Manipulations != null && Manipulations.Count > 0; }
1462
+ */
1463
+ }
1464
+
1465
+ public class PmpDefaultMod : PmpStandardOptionJson
1466
+ {
1467
+ [ JsonProperty ( Order = - 99 ) ]
1468
+ public int Version = 0 ;
1469
+ [ JsonIgnore ] public override bool IsDataContainerOnly => true ;
1470
+ }
1471
+
1472
+ public class PmpSingleOptionJson : PmpStandardOptionJson
1473
+ {
1474
+ }
1475
+
1476
+ public class PmpMultiOptionJson : PmpStandardOptionJson
1477
+ {
1478
+ [ JsonProperty ( Order = 2 ) ]
1479
+ public int Priority = 0 ;
1422
1480
}
1423
1481
1424
1482
public class PmpDisableImcOptionJson : PMPOptionJson
1425
1483
{
1426
- public bool IsDisableSubMod ;
1484
+ public bool IsDisableSubMod = true ;
1427
1485
}
1486
+
1487
+ [ JsonConverter ( typeof ( JsonSubtypes ) ) ]
1488
+ [ JsonSubtypes . KnownSubTypeWithProperty ( typeof ( PmpDisableImcOptionJson ) , "IsDisableSubMod" ) ]
1428
1489
public class PmpImcOptionJson : PMPOptionJson
1429
1490
{
1430
1491
public ushort AttributeMask ;
0 commit comments