@@ -4407,14 +4407,29 @@ public async Task AddRacialModel(int setId, string slot, XivRace newRace, string
4407
4407
/// <param name="originalPath"></param>
4408
4408
/// <param name="newPath"></param>
4409
4409
/// <returns></returns>
4410
- public async Task < long > CopyModel ( string originalPath , string newPath , string source )
4410
+ public async Task < long > CopyModel ( string originalPath , string newPath , string source , bool copyTextures = false )
4411
4411
{
4412
4412
var _dat = new Dat ( _gameDirectory ) ;
4413
- var model = await GetModel ( originalPath ) ;
4414
- var xMdl = await GetRawMdlData ( originalPath ) ;
4413
+ var _index = new Index ( _gameDirectory ) ;
4414
+ var _modding = new Modding ( _gameDirectory ) ;
4415
+
4416
+ var fromRoot = await XivCache . GetFirstRoot ( originalPath ) ;
4417
+ var toRoot = await XivCache . GetFirstRoot ( newPath ) ;
4418
+
4419
+ IItem item = null ;
4420
+ if ( toRoot != null )
4421
+ {
4422
+ item = toRoot . GetFirstItem ( ) ;
4423
+ }
4424
+
4425
+ var df = IOUtil . GetDataFileFromPath ( originalPath ) ;
4426
+
4427
+ var index = await _index . GetIndexFile ( df ) ;
4428
+ var modlist = await _modding . GetModListAsync ( ) ;
4415
4429
4416
- var root = await XivCache . GetFirstRoot ( newPath ) ;
4417
- var item = root . GetFirstItem ( ) ;
4430
+ var offset = index . Get8xDataOffset ( originalPath ) ;
4431
+ var xMdl = await GetRawMdlData ( originalPath , false , offset ) ;
4432
+ var model = TTModel . FromRaw ( xMdl ) ;
4418
4433
4419
4434
var originalRace = IOUtil . GetRaceFromPath ( originalPath ) ;
4420
4435
var newRace = IOUtil . GetRaceFromPath ( newPath ) ;
@@ -4426,56 +4441,127 @@ public async Task<long> CopyModel(string originalPath, string newPath, string so
4426
4441
ModelModifiers . FixUpSkinReferences ( model , newPath ) ;
4427
4442
}
4428
4443
4429
- var _imc = new Imc ( _gameDirectory ) ;
4430
-
4431
- var imcEntries = await _imc . GetEntries ( await root . GetImcEntryPaths ( ) ) ;
4432
-
4433
- var materialSets = new HashSet < byte > ( ) ;
4434
- imcEntries . ForEach ( x => materialSets . Add ( x . MaterialSet ) ) ;
4435
-
4436
4444
// Language is irrelevant here.
4437
4445
var _mtrl = new Mtrl ( _gameDirectory , IOUtil . GetDataFileFromPath ( newPath ) , XivLanguage . None ) ;
4438
4446
4439
4447
// Get all variant materials.
4440
- var materialPaths = await GetReferencedMaterialPaths ( originalPath , - 1 , false , false ) ;
4448
+ var materialPaths = await GetReferencedMaterialPaths ( originalPath , - 1 , false , false , index , modlist ) ;
4449
+
4441
4450
4442
4451
var _raceRegex = new Regex ( "c[0-9]{4}" ) ;
4443
4452
4453
+ Dictionary < string , string > validNewMaterials = new Dictionary < string , string > ( ) ;
4454
+ HashSet < string > copiedPaths = new HashSet < string > ( ) ;
4444
4455
// Update Material References and clone materials.
4445
- foreach ( var material in materialPaths )
4456
+ foreach ( var material in materialPaths )
4446
4457
{
4447
- var newMtrlPath = _raceRegex . Replace ( material , "c" + newRace . GetRaceCode ( ) ) ;
4448
- if ( newMtrlPath == material ) continue ;
4449
4458
4459
+ // Get the new path.
4460
+ var path = RootCloner . UpdatePath ( fromRoot , toRoot , material ) ;
4461
+
4462
+ // Adjust race code entries if needed.
4463
+ if ( toRoot . Info . PrimaryType == XivItemType . equipment || toRoot . Info . PrimaryType == XivItemType . accessory )
4464
+ {
4465
+ path = _raceRegex . Replace ( path , "c" + newRace . GetRaceCode ( ) ) ;
4466
+ }
4467
+
4468
+ // Get file names.
4450
4469
var io = material . LastIndexOf ( "/" , StringComparison . Ordinal ) ;
4451
- var baseMatName = material . Substring ( io , material . Length - io ) ;
4470
+ var originalMatName = material . Substring ( io , material . Length - io ) ;
4471
+
4472
+ io = path . LastIndexOf ( "/" , StringComparison . Ordinal ) ;
4473
+ var newMatName = path . Substring ( io , path . Length - io ) ;
4474
+
4452
4475
4453
- io = newMtrlPath . LastIndexOf ( "/" , StringComparison . Ordinal ) ;
4454
- var newMatName = newMtrlPath . Substring ( io , newMtrlPath . Length - io ) ;
4455
4476
// Time to copy the materials!
4456
4477
try
4457
4478
{
4458
- var mtrlData = await _dat . GetType2Data ( material , false ) ;
4459
- var compressedData = await _dat . CreateType2Data ( mtrlData ) ;
4460
- await _dat . WriteModFile ( compressedData , newMtrlPath , source , item ) ;
4479
+ offset = index . Get8xDataOffset ( material ) ;
4480
+ var mtrl = await _mtrl . GetMtrlData ( offset , material , 11 ) ;
4481
+
4482
+ if ( copyTextures )
4483
+ {
4484
+ for ( int i = 0 ; i < mtrl . TexturePathList . Count ; i ++ )
4485
+ {
4486
+ var tex = mtrl . TexturePathList [ i ] ;
4487
+ var ntex = RootCloner . UpdatePath ( fromRoot , toRoot , tex ) ;
4488
+ if ( toRoot . Info . PrimaryType == XivItemType . equipment || toRoot . Info . PrimaryType == XivItemType . accessory )
4489
+ {
4490
+ ntex = _raceRegex . Replace ( ntex , "c" + newRace . GetRaceCode ( ) ) ;
4491
+ }
4492
+
4493
+ mtrl . TexturePathList [ i ] = ntex ;
4494
+
4495
+ await _dat . CopyFile ( tex , ntex , source , true , item , index , modlist ) ;
4496
+ }
4497
+ }
4498
+
4499
+ mtrl . MTRLPath = path ;
4500
+ await _mtrl . ImportMtrl ( mtrl , item , source , index , modlist ) ;
4501
+
4502
+ if ( ! validNewMaterials . ContainsKey ( newMatName ) )
4503
+ {
4504
+ validNewMaterials . Add ( newMatName , path ) ;
4505
+ }
4506
+ copiedPaths . Add ( path ) ;
4507
+
4461
4508
4462
4509
// Switch out any material references to the material in the model file.
4463
- foreach ( var m in model . MeshGroups )
4510
+ foreach ( var m in model . MeshGroups )
4464
4511
{
4465
- if ( m . Material == baseMatName )
4512
+ if ( m . Material == originalMatName )
4466
4513
{
4467
4514
m . Material = newMatName ;
4468
4515
}
4469
4516
}
4517
+
4470
4518
} catch ( Exception ex )
4471
4519
{
4472
4520
// Hmmm. The original material didn't exist. This is pretty not awesome, but I guess a non-critical error...?
4473
4521
}
4474
4522
}
4475
4523
4524
+ if ( Imc . UsesImc ( toRoot ) && Imc . UsesImc ( fromRoot ) )
4525
+ {
4526
+ var _imc = new Imc ( XivCache . GameInfo . GameDirectory ) ;
4527
+
4528
+ var toEntries = await _imc . GetEntries ( await toRoot . GetImcEntryPaths ( ) , false , index , modlist ) ;
4529
+ var fromEntries = await _imc . GetEntries ( await fromRoot . GetImcEntryPaths ( ) , false , index , modlist ) ;
4530
+
4531
+ var toSets = toEntries . Select ( x => x . MaterialSet ) . Where ( x => x != 0 ) . ToList ( ) ;
4532
+ var fromSets = fromEntries . Select ( x => x . MaterialSet ) . Where ( x => x != 0 ) . ToList ( ) ;
4533
+
4534
+ if ( fromSets . Count > 0 && toSets . Count > 0 )
4535
+ {
4536
+ var vReplace = new Regex ( "/v[0-9]{4}/" ) ;
4537
+
4538
+ // Validate that sufficient material sets have been created at the destination root.
4539
+ foreach ( var mkv in validNewMaterials )
4540
+ {
4541
+ var validPath = mkv . Value ;
4542
+ foreach ( var msetId in toSets )
4543
+ {
4544
+ var testPath = vReplace . Replace ( validPath , "/v" + msetId . ToString ( ) . PadLeft ( 4 , '0' ) + "/" ) ;
4545
+ var copied = copiedPaths . Contains ( testPath ) ;
4546
+
4547
+ // Missing a material set, copy in the known valid material.
4548
+ if ( ! copied )
4549
+ {
4550
+ await _dat . CopyFile ( validPath , testPath , source , true , item , index , modlist ) ;
4551
+ }
4552
+ }
4553
+ }
4554
+ }
4555
+ }
4556
+
4557
+
4476
4558
// Save the final modified mdl.
4477
4559
var data = await MakeNewMdlFile ( model , xMdl ) ;
4478
- var offset = await _dat . WriteModFile ( data , newPath , source , item ) ;
4560
+ offset = await _dat . WriteModFile ( data , newPath , source , item , index , modlist ) ;
4561
+
4562
+ await _index . SaveIndexFile ( index ) ;
4563
+ await _modding . SaveModListAsync ( modlist ) ;
4564
+
4479
4565
return offset ;
4480
4566
}
4481
4567
0 commit comments