Skip to content

Commit 88ac960

Browse files
committed
Update 2.0.12.6
2 parents ff2c433 + f5d259f commit 88ac960

File tree

4 files changed

+131
-65
lines changed

4 files changed

+131
-65
lines changed

xivModdingFramework/Materials/DataContainers/XivMtrl.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,11 @@ public class XivMtrl
5858
/// <remarks>
5959
/// Can be 0 if there is no ColorSet Data
6060
/// </remarks>
61-
public ushort ColorSetDataSize { get; set; }
61+
public ushort ColorSetDataSize { get {
62+
var size = ColorSetData.Count * 2;
63+
size += ColorSetExtraData == null ? 0 : ColorSetExtraData.Length;
64+
return (ushort) size;
65+
} }
6266

6367
/// <summary>
6468
/// The size of the Material Data section
@@ -442,7 +446,6 @@ public void SetShaderInfo(ShaderInfo info, bool forced = false)
442446
ColorSetCount = 1;
443447
ColorSetData = new List<Half>();
444448
ColorSetExtraData = null;
445-
ColorSetDataSize = 0;
446449
} else
447450
{
448451
if(ColorSetCount == 0 || ColorSetData == null || ColorSetData.Count != 256)
@@ -454,9 +457,6 @@ public void SetShaderInfo(ShaderInfo info, bool forced = false)
454457
{
455458
ColorSetExtraData = Tex.GetColorsetExtraDataFromDDS(Tex.GetDefaultTexturePath(XivTexType.ColorSet));
456459
}
457-
458-
// Standard Colorset Size. -- This could really be generated automatically later.
459-
ColorSetDataSize = 544;
460460
}
461461

462462

@@ -465,13 +465,16 @@ public void SetShaderInfo(ShaderInfo info, bool forced = false)
465465
{
466466
TexturePathUnknownList[idx] = 0;
467467
}
468+
468469
for (var idx = 0; idx < Unknown2.Length; idx++)
469470
{
470-
Unknown2[idx] = 0;
471-
}
472-
if (Unknown2.Length > 0)
473-
{
474-
Unknown2[0] = 12;
471+
if(idx == 0)
472+
{
473+
Unknown2[idx] = 12;
474+
} else
475+
{
476+
Unknown2[idx] = 0;
477+
}
475478
}
476479
}
477480

xivModdingFramework/Materials/FileTypes/Mtrl.cs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -331,15 +331,15 @@ await Task.Run((Func<Task>)(async () =>
331331
{
332332
Signature = br.ReadInt32(),
333333
FileSize = br.ReadInt16(),
334-
ColorSetDataSize = br.ReadUInt16(),
335-
MaterialDataSize = br.ReadUInt16(),
336-
TexturePathsDataSize = br.ReadUInt16(),
337-
TextureCount = br.ReadByte(),
338-
MapCount = br.ReadByte(),
339-
ColorSetCount = br.ReadByte(),
340-
UnknownDataSize = br.ReadByte(),
341-
MTRLPath = mtrlPath
342334
};
335+
var colorSetDataSize = br.ReadUInt16();
336+
xivMtrl.MaterialDataSize = br.ReadUInt16();
337+
xivMtrl.TexturePathsDataSize = br.ReadUInt16();
338+
xivMtrl.TextureCount = br.ReadByte();
339+
xivMtrl.MapCount = br.ReadByte();
340+
xivMtrl.ColorSetCount = br.ReadByte();
341+
xivMtrl.UnknownDataSize = br.ReadByte();
342+
xivMtrl.MTRLPath = mtrlPath;
343343

344344
var pathSizeList = new List<int>();
345345

@@ -453,7 +453,7 @@ await Task.Run((Func<Task>)(async () =>
453453

454454
xivMtrl.ColorSetData = new List<Half>();
455455
xivMtrl.ColorSetExtraData = null;
456-
if (xivMtrl.ColorSetDataSize > 0)
456+
if (colorSetDataSize > 0)
457457
{
458458
// Color Data is always 512 (6 x 14 = 64 x 8bpp = 512)
459459
var colorDataSize = 512;
@@ -464,7 +464,7 @@ await Task.Run((Func<Task>)(async () =>
464464
}
465465

466466
// If the color set is 544 in length, it has an extra 32 bytes at the end
467-
if (xivMtrl.ColorSetDataSize == 544)
467+
if (colorSetDataSize == 544)
468468
{
469469
xivMtrl.ColorSetExtraData = br.ReadBytes(32);
470470
}
@@ -594,16 +594,14 @@ public Task<XivTex> MtrlToXivTex(XivMtrl xivMtrl, TexTypePath ttp)
594594
/// <param name="race">The selected race for the item</param>
595595
public void SaveColorSetExtraData(IItem item, XivMtrl xivMtrl, DirectoryInfo saveDirectory, XivRace race)
596596
{
597-
if (xivMtrl.ColorSetExtraData != null)
598-
{
599-
var path = IOUtil.MakeItemSavePath(item, saveDirectory, race);
597+
var toWrite = xivMtrl.ColorSetExtraData != null ? xivMtrl.ColorSetExtraData : new byte[32];
598+
var path = IOUtil.MakeItemSavePath(item, saveDirectory, race);
600599

601-
Directory.CreateDirectory(path);
600+
Directory.CreateDirectory(path);
602601

603-
var savePath = Path.Combine(path, Path.GetFileNameWithoutExtension(xivMtrl.MTRLPath) + ".dat");
602+
var savePath = Path.Combine(path, Path.GetFileNameWithoutExtension(xivMtrl.MTRLPath) + ".dat");
604603

605-
File.WriteAllBytes(savePath, xivMtrl.ColorSetExtraData);
606-
}
604+
File.WriteAllBytes(savePath, toWrite);
607605
}
608606

609607

@@ -757,6 +755,7 @@ public byte[] CreateMtrlFile(XivMtrl xivMtrl, IItem item)
757755
// Write the actual string list (including padding).
758756
mtrlBytes.AddRange(stringListBytes);
759757

758+
// Don't know what these (4) bytes do, but hey, whatever.
760759
mtrlBytes.AddRange(xivMtrl.Unknown2);
761760

762761
foreach (var colorSetHalf in xivMtrl.ColorSetData)

xivModdingFramework/SqPack/FileTypes/Index.cs

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ public Task<bool> HaveFilesAddedByTexTools(XivDataFile dataFile)
199199
});
200200
}
201201

202+
public async Task<int> GetDataOffset(string fullPath)
203+
{
204+
var dataFile = IOUtil.GetDataFileFromPath(fullPath);
205+
206+
var pathHash = HashGenerator.GetHash(fullPath.Substring(0, fullPath.LastIndexOf("/", StringComparison.Ordinal)));
207+
var fileHash = HashGenerator.GetHash(Path.GetFileName(fullPath));
208+
return await GetDataOffset(pathHash, fileHash, dataFile);
209+
210+
}
202211
/// <summary>
203212
/// Gets the offset for the data in the .dat file
204213
/// </summary>
@@ -372,14 +381,32 @@ public async Task<bool> FileExists(string fullPath)
372381
return await FileExists(fileHash, pathHash, dataFile);
373382
}
374383

375-
/// <summary>
376-
/// Determines whether the given file path exists
377-
/// </summary>
378-
/// <param name="fileHash">The hashed file</param>
379-
/// <param name="folderHash">The hashed folder</param>
380-
/// <param name="dataFile">The data file</param>
381-
/// <returns>True if it exists, False otherwise</returns>
382-
public async Task<bool> FileExists(int fileHash, int folderHash, XivDataFile dataFile)
384+
385+
/// <summary>
386+
/// Tests if a given file path in FFXIV's internal directory structure
387+
/// is one that ships with FFXIV, or something added by the framework.
388+
/// </summary>
389+
/// <returns></returns>
390+
public async Task<bool> IsDefaultFilePath(string fullPath)
391+
{
392+
// The framework adds flag files alongside every custom created file.
393+
// This lets you check for them even if the Modlist gets corrupted/lost.
394+
var exists = await FileExists(fullPath);
395+
var hasFlag = await FileExists(fullPath + ".flag");
396+
397+
// In order to be considered a DEFAULT file, the file must both EXIST *and* not have a flag.
398+
var stockFile = exists && !hasFlag;
399+
return stockFile;
400+
}
401+
402+
/// <summary>
403+
/// Determines whether the given file path exists
404+
/// </summary>
405+
/// <param name="fileHash">The hashed file</param>
406+
/// <param name="folderHash">The hashed folder</param>
407+
/// <param name="dataFile">The data file</param>
408+
/// <returns>True if it exists, False otherwise</returns>
409+
public async Task<bool> FileExists(int fileHash, int folderHash, XivDataFile dataFile)
383410
{
384411
var indexPath = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");
385412

@@ -747,13 +774,26 @@ public bool DeleteFileDescriptor(string fullPath, XivDataFile dataFile)
747774
// Update folder size
748775
if (iHash == uPathHash)
749776
{
750-
foundFolder = true;
751-
Array.Copy(BitConverter.GetBytes(iFolderSize - 16), 0, modifiedIndex, position + 8, 4);
777+
if(iFolderSize == 0)
778+
{
779+
// No more files in the folder, the folder needs to be deleted from the listing
780+
// (0 size folders are not listed, even if they're parent folders for other folders)
781+
remainder = modifiedIndex.Length - position - 16;
782+
Array.Copy(modifiedIndex, position + 16, modifiedIndex, position, remainder);
783+
784+
var newIndex = new byte[modifiedIndex.Length - 16];
785+
Array.Copy(modifiedIndex, 0, modifiedIndex, 0, newIndex.Length);
786+
foundFolder = true;
787+
} else
788+
{
789+
Array.Copy(BitConverter.GetBytes(iFolderSize - 16), 0, modifiedIndex, position + 8, 4);
790+
}
752791
}
753792
}
754793

755794
if (!foundFolder)
756795
{
796+
// Something went wrong here / The index is in a bad state.
757797
return false;
758798
}
759799

@@ -876,13 +916,14 @@ public bool DeleteFileDescriptor(string fullPath, XivDataFile dataFile)
876916
return true;
877917
}
878918

879-
/// <summary>
880-
/// Adds a new file descriptor/stub into the Index files.
881-
/// </summary>
882-
/// <param name="fullPath">Full path to the new file.</param>
883-
/// <param name="dataOffset">Raw DAT file offset to use for the new file.</param>
884-
/// <param name="dataFile">Which data file set to use.</param>
885-
/// <returns></returns>
919+
920+
/// <summary>
921+
/// Adds a new file descriptor/stub into the Index files.
922+
/// </summary>
923+
/// <param name="fullPath">Full path to the new file.</param>
924+
/// <param name="dataOffset">Raw DAT file offset to use for the new file.</param>
925+
/// <param name="dataFile">Which data file set to use.</param>
926+
/// <returns></returns>
886927
public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataFile)
887928
{
888929
fullPath = fullPath.Replace("\\", "/");
@@ -910,7 +951,6 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
910951

911952
// Dump the index into memory, since we're going to have to inject data.
912953
byte[] originalIndex = File.ReadAllBytes(indexPath);
913-
byte[] modifiedIndex = new byte[originalIndex.Length + 16];
914954

915955
// Get all the segment header data
916956
for (int i = 0; i < SegmentHeaders.Length; i++)
@@ -946,6 +986,11 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
946986
injectLocation = position;
947987
break;
948988
}
989+
} else if (iPathHash > uPathHash)
990+
{
991+
// This is where the folder should go, it just has no files currently.
992+
injectLocation = position;
993+
break;
949994
}
950995
else
951996
{
@@ -958,11 +1003,9 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
9581003
}
9591004
}
9601005

961-
// Cancel if we failed to find the path.
962-
if (foundFolder == false)
963-
{
964-
return false;
965-
}
1006+
1007+
var totalInjectSize = foundFolder ? 16 : 32;
1008+
byte[] modifiedIndex = new byte[originalIndex.Length + totalInjectSize];
9661009

9671010
// Split the file at the injection point.
9681011
int remainder = originalIndex.Length - injectLocation;
@@ -983,8 +1026,16 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
9831026
// Update other segments' offsets.
9841027
else
9851028
{
1029+
9861030
SegmentOffsets[i] += 16;
9871031
Array.Copy(BitConverter.GetBytes(SegmentOffsets[i]), 0, modifiedIndex, SegmentHeaders[i] + 4, 4);
1032+
1033+
// We need to create the folder as well.
1034+
if (i == 3 && !foundFolder)
1035+
{
1036+
SegmentSizes[i] += 16;
1037+
Array.Copy(BitConverter.GetBytes(SegmentSizes[i]), 0, modifiedIndex, SegmentHeaders[i] + 8, 4);
1038+
}
9881039
}
9891040
}
9901041

@@ -995,7 +1046,6 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
9951046

9961047
// Update the folder structure
9971048
var folderCount = SegmentSizes[3] / 16;
998-
foundFolder = false;
9991049

10001050
for (int i = 0; i < folderCount; i++)
10011051
{
@@ -1010,19 +1060,24 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
10101060
Array.Copy(BitConverter.GetBytes(iOffset + 16), 0, modifiedIndex, position + 4, 4);
10111061
}
10121062

1013-
// Update folder size
1063+
// Folder exists, but needs its size updated.
10141064
if (iHash == uPathHash)
10151065
{
1016-
foundFolder = true;
10171066
Array.Copy(BitConverter.GetBytes(iFolderSize + 16), 0, modifiedIndex, position + 8, 4);
1067+
} else if (foundFolder == false && iHash > uPathHash) {
1068+
foundFolder = true;
1069+
// This is where we need to cut the index the second time to make room for the folder data.
1070+
remainder = modifiedIndex.Length - position - 16;
1071+
Array.Copy(modifiedIndex, position, modifiedIndex, position +16, remainder);
1072+
1073+
// The new folder entry now goes at the 16 bytes starting at position
1074+
Array.Copy(BitConverter.GetBytes(uPathHash), 0, modifiedIndex, position, 4);
1075+
Array.Copy(BitConverter.GetBytes(injectLocation), 0, modifiedIndex, position + 4, 4);
1076+
Array.Copy(BitConverter.GetBytes(16), 0, modifiedIndex, position + 8, 4);
1077+
Array.Copy(BitConverter.GetBytes(16), 0, modifiedIndex, position + 12, 4);
10181078
}
10191079
}
10201080

1021-
if(!foundFolder)
1022-
{
1023-
return false;
1024-
}
1025-
10261081
// Update SHA-1 Hashes.
10271082
SHA1 sha = new SHA1CryptoServiceProvider();
10281083
byte[] shaHash;

xivModdingFramework/Textures/FileTypes/Tex.cs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -992,16 +992,16 @@ public async Task<int> TexColorImporter(XivMtrl xivMtrl, DirectoryInfo ddsFileDi
992992

993993

994994
colorSetData = GetColorsetDataFromDDS(ddsFileDirectory);
995-
996-
// If the colorset size is 544, it contains extra data that must be imported
997-
if (xivMtrl.ColorSetDataSize == 544)
998-
{
999-
colorSetExtraData = GetColorsetExtraDataFromDDS(ddsFileDirectory);
1000-
}
995+
colorSetExtraData = GetColorsetExtraDataFromDDS(ddsFileDirectory);
1001996

1002997
// Replace the color set data with the imported data
1003998
xivMtrl.ColorSetData = colorSetData;
1004999
xivMtrl.ColorSetExtraData = colorSetExtraData;
1000+
if (xivMtrl.Unknown2.Length > 0)
1001+
{
1002+
// This byte enables the dye set if it's not already enabled.
1003+
xivMtrl.Unknown2[0] = 12;
1004+
}
10051005

10061006
var mtrl = new Mtrl(_gameDirectory, xivMtrl.TextureTypePathList[0].DataFile, lang);
10071007
return await mtrl.ImportMtrl(xivMtrl, item, source);
@@ -1098,15 +1098,24 @@ public byte[] DDStoMtrlData(XivMtrl xivMtrl, DirectoryInfo ddsFileDirectory, IIt
10981098

10991099
var colorSetExtraData = new byte[32];
11001100
// If the colorset size is 544, it contains extra data that must be imported
1101-
if (xivMtrl.ColorSetDataSize == 544)
1101+
try
11021102
{
11031103
colorSetExtraData = GetColorsetExtraDataFromDDS(ddsFileDirectory);
1104+
} catch
1105+
{
1106+
colorSetExtraData = new byte[32];
11041107
}
11051108

11061109
// Replace the color set data with the imported data
11071110
xivMtrl.ColorSetData = colorSetData;
11081111
xivMtrl.ColorSetExtraData = colorSetExtraData;
11091112

1113+
if (xivMtrl.Unknown2.Length > 0)
1114+
{
1115+
// This byte enables the dye set if it's not already enabled.
1116+
xivMtrl.Unknown2[0] = 12;
1117+
}
1118+
11101119
var mtrl = new Mtrl(_gameDirectory, xivMtrl.TextureTypePathList[0].DataFile, lang);
11111120
return mtrl.CreateMtrlFile(xivMtrl, item);
11121121
}

0 commit comments

Comments
 (0)