Skip to content

Commit 241d661

Browse files
committed
- Some low level bugfixes + addition of STM file reading.
1 parent c4b767e commit 241d661

File tree

3 files changed

+315
-24
lines changed

3 files changed

+315
-24
lines changed

xivModdingFramework/Cache/XivDependencyGraph.cs

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -635,38 +635,41 @@ public async Task<List<string>> GetMaterialFiles(int materialVariant = -1, Index
635635
}
636636
}
637637

638-
if (materialVariant <= 0)
638+
if (mdlMats != null)
639639
{
640-
foreach (var mat in mdlMats)
640+
if (materialVariant <= 0)
641641
{
642-
var m = mat;
643-
644-
// Human types have their material ID automatically changed over.
645-
if (Info.PrimaryType == XivItemType.human && Info.SecondaryType != XivItemType.hair)
642+
foreach (var mat in mdlMats)
646643
{
647-
m = secondaryRex.Replace(m, secondaryTypePrefix + Info.SecondaryId.ToString().PadLeft(4, '0'));
644+
var m = mat;
645+
646+
// Human types have their material ID automatically changed over.
647+
if (Info.PrimaryType == XivItemType.human && Info.SecondaryType != XivItemType.hair)
648+
{
649+
m = secondaryRex.Replace(m, secondaryTypePrefix + Info.SecondaryId.ToString().PadLeft(4, '0'));
650+
}
651+
materials.Add(m);
648652
}
649-
materials.Add(m);
650653
}
651-
}
652-
else
653-
{
654-
var replacement = "v" + materialVariant.ToString().PadLeft(4, '0');
655-
foreach (var mat in mdlMats)
654+
else
656655
{
657-
// Replace any material set references with the new one.
658-
// The hash set will scrub us down to just a single copy.
659-
// This is faster than re-scanning the MDL file.
660-
// And a little more thorough than simply skipping over non-matching refs.
661-
// Since some materials may not have variant references.
662-
var m = _materialSetRegex.Replace(mat, replacement);
663-
664-
// Human types have their material ID automatically fixed to match.
665-
if (Info.PrimaryType == XivItemType.human && Info.SecondaryType != XivItemType.hair)
656+
var replacement = "v" + materialVariant.ToString().PadLeft(4, '0');
657+
foreach (var mat in mdlMats)
666658
{
667-
m = secondaryRex.Replace(m, secondaryTypePrefix + Info.SecondaryId.ToString().PadLeft(4, '0'));
659+
// Replace any material set references with the new one.
660+
// The hash set will scrub us down to just a single copy.
661+
// This is faster than re-scanning the MDL file.
662+
// And a little more thorough than simply skipping over non-matching refs.
663+
// Since some materials may not have variant references.
664+
var m = _materialSetRegex.Replace(mat, replacement);
665+
666+
// Human types have their material ID automatically fixed to match.
667+
if (Info.PrimaryType == XivItemType.human && Info.SecondaryType != XivItemType.hair)
668+
{
669+
m = secondaryRex.Replace(m, secondaryTypePrefix + Info.SecondaryId.ToString().PadLeft(4, '0'));
670+
}
671+
materials.Add(m);
668672
}
669-
materials.Add(m);
670673
}
671674
}
672675
}

xivModdingFramework/Helpers/IOUtil.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public static async Task<byte[]> Decompressor(byte[] compressedBytes, int uncomp
7474
while ((bytesRead = await ds.ReadAsync(decompressedBytes, offset, uncompressedSize - offset)) > 0)
7575
{
7676
offset += bytesRead; // offset in buffer for results of next reading
77+
if (bytesRead == uncompressedSize) break;
7778
}
7879
}
7980
}
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
using HelixToolkit.SharpDX.Core.Helper;
2+
using SharpDX;
3+
using SixLabors.ImageSharp.PixelFormats;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
using xivModdingFramework.Cache;
11+
using xivModdingFramework.Items.DataContainers;
12+
using xivModdingFramework.Mods;
13+
using xivModdingFramework.Mods.DataContainers;
14+
using xivModdingFramework.SqPack.DataContainers;
15+
using xivModdingFramework.SqPack.FileTypes;
16+
17+
namespace xivModdingFramework.Materials.FileTypes
18+
{
19+
/// <summary>
20+
/// Staining Template File Handler
21+
/// </summary>
22+
public static class STM
23+
{
24+
public const string GearStainingTemplatePath = "chara/base_material/stainingtemplate.stm";
25+
26+
public static ushort GetTemplateKeyFromMaterialData(ushort data)
27+
{
28+
return (ushort)(data >> 5);
29+
}
30+
31+
public static async Task<StainingTemplateFile> GetStainingTemplateFile(bool forceOriginal = false, IndexFile index = null, ModList modlist = null)
32+
{
33+
var _dat = new Dat(XivCache.GameInfo.GameDirectory);
34+
35+
var data = await _dat.GetType2Data(GearStainingTemplatePath, forceOriginal, index, modlist);
36+
37+
var ret = new StainingTemplateFile(data);
38+
return ret;
39+
}
40+
41+
public static async Task SaveStainingTemplateFile(StainingTemplateFile file, string applicationSource, IndexFile index = null, ModList modlist = null)
42+
{
43+
var data = new byte[0];//file.GetBytes();
44+
45+
var _dat = new Dat(XivCache.GameInfo.GameDirectory);
46+
47+
var dummyItem = new XivGenericItemModel()
48+
{
49+
Name = "Equipment Staining Template",
50+
SecondaryCategory = "Raw Files"
51+
};
52+
53+
await _dat.ImportType2Data(data, GearStainingTemplatePath, applicationSource, null, index, modlist);
54+
55+
}
56+
}
57+
58+
public enum StainingTemplateArrayType
59+
{
60+
Singleton,
61+
OneToOne,
62+
Indexed
63+
}
64+
65+
public class StainingTemplateEntry
66+
{
67+
public int Size
68+
{
69+
get
70+
{
71+
return 0;
72+
}
73+
}
74+
75+
List<Half[]> DiffuseEntries = new List<Half[]>();
76+
List<Half[]> SpecularEntries = new List<Half[]>();
77+
List<Half[]> EmissiveEntries = new List<Half[]>();
78+
List<Half> TileMaterialEntries = new List<Half>();
79+
List<Half> GlossEntries = new List<Half>();
80+
81+
public StainingTemplateEntry(byte[] data, int offset)
82+
{
83+
var arrayEnds = new List<ushort>();
84+
var start = offset;
85+
86+
87+
// This format sucks.
88+
for (int i = 0; i < 5; i++)
89+
{
90+
arrayEnds.Add(BitConverter.ToUInt16(data, offset));
91+
offset += 2;
92+
}
93+
const int headerSize = 10;
94+
95+
96+
var lastOffset = 0;
97+
for (int x = 0; x < 5; x++)
98+
{
99+
var elementSize = 3;
100+
if(x > 2)
101+
{
102+
elementSize = 1;
103+
}
104+
105+
var arraySize = (arrayEnds[x] - lastOffset) / elementSize;
106+
var type = StainingTemplateArrayType.OneToOne;
107+
108+
// Calculate the data type.
109+
var indexStart = 0;
110+
if (arraySize == 1)
111+
{
112+
// Single entry used for everything.
113+
type = StainingTemplateArrayType.Singleton;
114+
}
115+
if(arraySize == 0)
116+
{
117+
// No data.
118+
continue;
119+
}
120+
else if (arraySize < 128)
121+
{
122+
// Indexed array, where we have [n] # of real entries,
123+
// then 128 one-byte index entries referencing those [n] entries.
124+
var totalBytes = (arrayEnds[x] - lastOffset) *2;
125+
var remBytes = totalBytes - 128;
126+
127+
indexStart = start + headerSize + (lastOffset * 2) + remBytes;
128+
129+
arraySize = remBytes / 2 / elementSize;
130+
type = StainingTemplateArrayType.Indexed;
131+
}
132+
133+
var arrayStart = lastOffset;
134+
var offsetStart = (start + 10 + (arrayStart * 2));
135+
136+
List<Half[]> halfData = new List<Half[]>();
137+
138+
for (int i = 0; i < arraySize; i++)
139+
{
140+
141+
Half[] halfs = new Half[3];
142+
143+
var elementStart = offsetStart + (i * 2);
144+
145+
var reversed = new byte[] { data[elementStart + 1], data[elementStart] };
146+
var test = new Half(BitConverter.ToUInt16(reversed, 0));
147+
halfs[0] = new Half(BitConverter.ToUInt16(data, elementStart));
148+
if (elementSize > 1)
149+
{
150+
halfs[1] = new Half(BitConverter.ToUInt16(data, elementStart + 2));
151+
halfs[2] = new Half(BitConverter.ToUInt16(data, elementStart + 4));
152+
}
153+
154+
halfData.Add(halfs);
155+
}
156+
157+
if(type == StainingTemplateArrayType.Indexed)
158+
{
159+
var nArray = new List<Half[]>();
160+
for (int i = 0; i < 128; i++)
161+
{
162+
var index = data[indexStart + i];
163+
var entry = new Half[3];
164+
if (index == 255)
165+
{
166+
nArray.Add(new Half[] { new Half(), new Half(), new Half() } );
167+
continue;
168+
}
169+
170+
if(index == 0)
171+
{
172+
nArray.Add(new Half[] { new Half(), new Half(), new Half() });
173+
continue;
174+
}
175+
nArray.Add(halfData[index - 1]);
176+
}
177+
178+
halfData = nArray;
179+
}
180+
181+
if (halfData.Count == 1)
182+
{
183+
for (int i = 0; i < 127; i++)
184+
{
185+
halfData.Add(halfData[0]);
186+
}
187+
}
188+
189+
190+
foreach (var arr in halfData)
191+
{
192+
193+
if (x == 0)
194+
{
195+
DiffuseEntries.Add(arr);
196+
}
197+
else if (x == 1)
198+
{
199+
SpecularEntries.Add(arr);
200+
}
201+
else if (x == 2)
202+
{
203+
EmissiveEntries.Add(arr);
204+
}
205+
else if (x == 3)
206+
{
207+
TileMaterialEntries.Add(arr[0]);
208+
}
209+
else if (x == 4)
210+
{
211+
GlossEntries.Add(arr[0]);
212+
}
213+
}
214+
215+
lastOffset = arrayEnds[x];
216+
}
217+
218+
var length = lastOffset;
219+
}
220+
221+
}
222+
223+
public class StainingTemplateFile
224+
{
225+
private uint Header;
226+
private Dictionary<ushort, StainingTemplateEntry> Templates = new Dictionary<ushort, StainingTemplateEntry>();
227+
228+
public List<ushort> GetKeys()
229+
{
230+
return Templates.Keys.ToList();
231+
}
232+
233+
public void SetTemplate(ushort key, StainingTemplateEntry entry)
234+
{
235+
if (Templates.ContainsKey(key))
236+
{
237+
Templates[key] = entry;
238+
}
239+
else
240+
{
241+
Templates.Add(key, entry);
242+
}
243+
}
244+
public StainingTemplateEntry GetTemplate(ushort key)
245+
{
246+
return Templates[key];
247+
}
248+
public StainingTemplateFile(byte[] data)
249+
{
250+
var Header = BitConverter.ToInt32(data, 0);
251+
var entryCount = BitConverter.ToUInt16(data, 4);
252+
253+
254+
Dictionary<ushort, ushort> entries = new Dictionary<ushort, ushort>();
255+
List<ushort> keys = new List<ushort>();
256+
List<ushort> values = new List<ushort>();
257+
List<int> sizes = new List<int>();
258+
var offset = 8;
259+
for (int i = 0; i < entryCount; i++)
260+
{
261+
var key = BitConverter.ToUInt16(data, offset);
262+
entries.Add(key, 0);
263+
keys.Add(key);
264+
offset += 2;
265+
}
266+
267+
var endOfHeader = (8 + (4 * entryCount));
268+
269+
for (int i = 0; i < entryCount; i++)
270+
{
271+
entries[keys[i]] = (ushort) ((BitConverter.ToUInt16(data, offset) * 2) + endOfHeader);
272+
offset += 2;
273+
}
274+
275+
276+
var idx = 0;
277+
foreach (var kv in entries)
278+
{
279+
var entry = new StainingTemplateEntry(data, kv.Value);
280+
Templates.Add(kv.Key, entry);
281+
idx++;
282+
}
283+
}
284+
285+
286+
}
287+
}

0 commit comments

Comments
 (0)