Skip to content

Commit 966bc1f

Browse files
committed
- Further refinements to hair cloning logic.
1 parent 8d454d9 commit 966bc1f

File tree

2 files changed

+76
-34
lines changed

2 files changed

+76
-34
lines changed

xivModdingFramework/Materials/FileTypes/Mtrl.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,62 @@ public string GetMtrlFolder(XivDependencyRootInfo root, int materialSet = -1)
11161116

11171117
}
11181118

1119+
/// <summary>
1120+
/// Hair is extremely annoying and uses literal hard-coded paths for things based on hair ID.
1121+
/// </summary>
1122+
/// <param name="root"></param>
1123+
/// <returns></returns>
1124+
public static XivDependencyRootInfo GetHairMaterialRoot(XivDependencyRootInfo root)
1125+
{
1126+
if(root.PrimaryType != XivItemType.human || root.SecondaryType != XivItemType.hair)
1127+
{
1128+
throw new InvalidDataException("Cannot get hair material info for non-hair root.");
1129+
}
11191130

1131+
if(root.SecondaryId < 101)
1132+
{
1133+
// Racial uniques.
1134+
return root;
1135+
} else if (root.SecondaryId < 116)
1136+
{
1137+
// 101-115 have Midlander M/F, and Miqo M/F
1138+
if (root.PrimaryId == 701 || root.PrimaryId == 801)
1139+
{
1140+
return root;
1141+
}
1142+
else
1143+
{
1144+
var isFemale = ((root.PrimaryId / 100) % 2) == 0;
1145+
return new XivDependencyRootInfo()
1146+
{
1147+
PrimaryId = isFemale ? 201 : 101,
1148+
PrimaryType = root.PrimaryType,
1149+
SecondaryType = root.SecondaryType,
1150+
SecondaryId = root.SecondaryId,
1151+
Slot = root.Slot
1152+
};
1153+
}
1154+
1155+
} else if (root.SecondaryId < 201)
1156+
{
1157+
// These have just Midlander M/F
1158+
var isFemale = ((root.PrimaryId / 100) % 2) == 0;
1159+
return new XivDependencyRootInfo()
1160+
{
1161+
PrimaryId = isFemale ? 201 : 101,
1162+
PrimaryType = root.PrimaryType,
1163+
SecondaryType = root.SecondaryType,
1164+
SecondaryId = root.SecondaryId,
1165+
Slot = root.Slot
1166+
};
1167+
1168+
} else
1169+
{
1170+
// Back to uniques.
1171+
return root;
1172+
}
1173+
1174+
}
11201175
public void Dipose()
11211176
{
11221177
_semaphoreSlim?.Dispose();

xivModdingFramework/Mods/RootCloner.cs

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -463,25 +463,19 @@ private static string UpdateFolder(XivDependencyRoot Source, XivDependencyRoot D
463463
{
464464
if(Destination.Info.PrimaryType == XivItemType.human && Destination.Info.SecondaryType == XivItemType.hair && Path.GetExtension(path) == ".mtrl")
465465
{
466-
// Hair material paths are actually hard-coded into the game, so there's some wild stuff that has to go on here.
467-
if (Destination.Info.SecondaryId > 115 && Destination.Info.SecondaryId <= 200)
468-
{
469-
// Hairs between 115 and 200 have forced material path sharing enabled.
470-
var digit3 = Destination.Info.SecondaryId / 100;
471-
var race = digit3 % 2 == 0 ? 101 : 201;
466+
var hairRoot = Mtrl.GetHairMaterialRoot(Destination.Info);
472467

473-
// Force the race code to the appropriate one.
474-
var raceReplace = new Regex("/c[0-9]{4}");
475-
path = raceReplace.Replace(path, "/c" + race.ToString().PadLeft(4, '0'));
468+
// Force the race code to the appropriate one.
469+
var raceReplace = new Regex("/c[0-9]{4}");
470+
path = raceReplace.Replace(path, "/c" + hairRoot.PrimaryId.ToString().PadLeft(4, '0'));
476471

477-
var hairReplace= new Regex("/h[0-9]{4}");
478-
path = hairReplace.Replace(path, "/h" + Destination.Info.SecondaryId.ToString().PadLeft(4, '0'));
472+
var hairReplace= new Regex("/h[0-9]{4}");
473+
path = hairReplace.Replace(path, "/h" + hairRoot.SecondaryId.ToString().PadLeft(4, '0'));
479474

480-
// Hairs between 115 and 200 have forced material path sharing enabled.
481-
path = Path.GetDirectoryName(path);
482-
path = path.Replace('\\', '/');
483-
return path;
484-
}
475+
// Hairs between 115 and 200 have forced material path sharing enabled.
476+
path = Path.GetDirectoryName(path);
477+
path = path.Replace('\\', '/');
478+
return path;
485479
}
486480

487481
// So first off, just copy anything from the old root folder to the new one.
@@ -511,28 +505,21 @@ private static string UpdateFileName(XivDependencyRoot Source, XivDependencyRoot
511505

512506
if (Destination.Info.PrimaryType == XivItemType.human && Destination.Info.SecondaryType == XivItemType.hair && Path.GetExtension(path) == ".mtrl")
513507
{
514-
// Hair material paths are actually hard-coded into the game, so there's some wild stuff that has to go on here.
515-
if (Destination.Info.SecondaryId > 115 && Destination.Info.SecondaryId <= 200)
516-
{
517-
// Hairs between 115 and 200 have forced material path sharing enabled.
518-
var digit3 = Destination.Info.SecondaryId / 100;
519-
var race = digit3 % 2 == 0 ? 101 : 201;
508+
var hairRoot = Mtrl.GetHairMaterialRoot(Destination.Info);
520509

521-
// Force the race code to the appropriate one.
522-
var raceReplace = new Regex("^mt_c[0-9]{4}h[0-9]{4}");
523-
file = raceReplace.Replace(file, "mt_c" + race.ToString().PadLeft(4, '0') + "h" + Destination.Info.SecondaryId.ToString().PadLeft(4, '0'));
510+
// Force replace the root information to the correct one for this target hair.
511+
var raceReplace = new Regex("^mt_c[0-9]{4}h[0-9]{4}");
512+
file = raceReplace.Replace(file, "mt_c" + hairRoot.PrimaryId.ToString().PadLeft(4, '0') + "h" + hairRoot.SecondaryId.ToString().PadLeft(4, '0'));
524513

525-
// So for these, the first half of the filename is hard-coded locked (the c#### part)
526-
// We have to get gimmicky and play around with the suffixing.
527-
var initialPartRex = new Regex("^(mt_c[0-9]{4}h[0-9]{4})(?:_c[0-9]{4})?(.+)$");
528-
var m = initialPartRex.Match(file);
514+
// Jam in a suffix into the MTRL to make it unique/non-colliding.
515+
var initialPartRex = new Regex("^(mt_c[0-9]{4}h[0-9]{4})(?:_c[0-9]{4})?(.+)$");
516+
var m = initialPartRex.Match(file);
529517

530-
// ???
531-
if (!m.Success) return file;
518+
// ???
519+
if (!m.Success) return file;
532520

533-
file = m.Groups[1].Value + "_c" + Destination.Info.PrimaryId.ToString().PadLeft(4, '0') + m.Groups[2].Value;
534-
return file;
535-
}
521+
file = m.Groups[1].Value + "_c" + Destination.Info.PrimaryId.ToString().PadLeft(4, '0') + m.Groups[2].Value;
522+
return file;
536523
}
537524

538525
var rex = new Regex("[a-z][0-9]{4}([a-z][0-9]{4})");

0 commit comments

Comments
 (0)