mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-23 07:22:52 +08:00
AWC/XML conversion improvements
This commit is contained in:
parent
665a2d67e5
commit
5b0fafa121
@ -18,18 +18,18 @@ namespace CodeWalker.GameFiles
|
|||||||
public string ErrorMessage { get; set; }
|
public string ErrorMessage { get; set; }
|
||||||
|
|
||||||
public uint Magic { get; set; } = 0x54414441;
|
public uint Magic { get; set; } = 0x54414441;
|
||||||
public ushort Version { get; set; }
|
public ushort Version { get; set; } = 1;
|
||||||
public ushort Flags { get; set; } = 0xFF00;
|
public ushort Flags { get; set; } = 0xFF00;
|
||||||
public int StreamCount { get; set; }
|
public int StreamCount { get; set; }
|
||||||
public int DataOffset { get; set; }
|
public int DataOffset { get; set; }
|
||||||
|
|
||||||
public bool UnkUshortsFlag { get { return ((Flags & 1) == 1); } set { Flags = (ushort)((Flags & 0xFFFE) + (value ? 1 : 0)); } }
|
public bool ChunkIndicesFlag { get { return ((Flags & 1) == 1); } set { Flags = (ushort)((Flags & 0xFFFE) + (value ? 1 : 0)); } }
|
||||||
public bool SingleChannelEncryptFlag { get { return ((Flags & 2) == 2); } set { Flags = (ushort)((Flags & 0xFFFD) + (value ? 2 : 0)); } }
|
public bool SingleChannelEncryptFlag { get { return ((Flags & 2) == 2); } set { Flags = (ushort)((Flags & 0xFFFD) + (value ? 2 : 0)); } }
|
||||||
public bool MultiChannelFlag { get { return ((Flags & 4) == 4); } set { Flags = (ushort)((Flags & 0xFFFB) + (value ? 4 : 0)); } }
|
public bool MultiChannelFlag { get { return ((Flags & 4) == 4); } set { Flags = (ushort)((Flags & 0xFFFB) + (value ? 4 : 0)); } }
|
||||||
public bool MultiChannelEncryptFlag { get { return ((Flags & 8) == 8); } set { Flags = (ushort)((Flags & 0xFFF7) + (value ? 8 : 0)); } }
|
public bool MultiChannelEncryptFlag { get { return ((Flags & 8) == 8); } set { Flags = (ushort)((Flags & 0xFFF7) + (value ? 8 : 0)); } }
|
||||||
|
|
||||||
public ushort[] UnkUshorts { get; set; } //offsets of some sort?
|
public ushort[] ChunkIndices { get; set; } //index of first chunk for each stream
|
||||||
|
public AwcChunkInfo[] ChunkInfos { get; set; } // just for browsing convenience really
|
||||||
|
|
||||||
public bool WholeFileEncrypted { get; set; }
|
public bool WholeFileEncrypted { get; set; }
|
||||||
|
|
||||||
@ -147,25 +147,26 @@ namespace CodeWalker.GameFiles
|
|||||||
DataOffset = r.ReadInt32();
|
DataOffset = r.ReadInt32();
|
||||||
|
|
||||||
|
|
||||||
|
if (ChunkIndicesFlag)
|
||||||
|
{
|
||||||
|
ChunkIndices = new ushort[StreamCount]; //index of first chunk for each stream
|
||||||
|
for (int i = 0; i < StreamCount; i++)
|
||||||
|
{
|
||||||
|
ChunkIndices[i] = r.ReadUInt16();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//if ((Flags >> 8) != 0xFF)
|
//if ((Flags >> 8) != 0xFF)
|
||||||
//{ }//no hit
|
//{ }//no hit
|
||||||
|
|
||||||
if (UnkUshortsFlag)
|
//var infoStart = 16 + (ChunkIndicesFlag ? (StreamCount * 2) : 0);
|
||||||
{
|
|
||||||
UnkUshorts = new ushort[StreamCount]; //offsets of some sort?
|
|
||||||
for (int i = 0; i < StreamCount; i++)
|
|
||||||
{
|
|
||||||
UnkUshorts[i] = r.ReadUInt16();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//var infoStart = 16 + (UnkUshortsFlag ? (StreamCount * 2) : 0);
|
|
||||||
//if (r.Position != infoStart)
|
//if (r.Position != infoStart)
|
||||||
//{ }//no hit
|
//{ }//no hit
|
||||||
|
|
||||||
|
|
||||||
var infos = new List<AwcStreamInfo>();
|
var infos = new List<AwcStreamInfo>();
|
||||||
|
var chunks = new List<AwcChunkInfo>();
|
||||||
|
|
||||||
for (int i = 0; i < StreamCount; i++)
|
for (int i = 0; i < StreamCount; i++)
|
||||||
{
|
{
|
||||||
@ -180,11 +181,12 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
var chunk = new AwcChunkInfo();
|
var chunk = new AwcChunkInfo();
|
||||||
chunk.Read(r);
|
chunk.Read(r);
|
||||||
|
chunks.Add(chunk);
|
||||||
info.Chunks[j] = chunk;
|
info.Chunks[j] = chunk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StreamInfos = infos.ToArray();
|
StreamInfos = infos.ToArray();
|
||||||
|
ChunkInfos = chunks.ToArray();
|
||||||
|
|
||||||
//var dataOffset = infoStart + StreamCount * 4;
|
//var dataOffset = infoStart + StreamCount * 4;
|
||||||
//foreach (var info in infos) dataOffset += (int)info.ChunkCount * 8;
|
//foreach (var info in infos) dataOffset += (int)info.ChunkCount * 8;
|
||||||
@ -204,8 +206,6 @@ namespace CodeWalker.GameFiles
|
|||||||
stream.Read(r);
|
stream.Read(r);
|
||||||
streams.Add(stream);
|
streams.Add(stream);
|
||||||
|
|
||||||
stream.UnkUshort = (UnkUshorts != null) ? (ushort?)UnkUshorts[i] : null;
|
|
||||||
|
|
||||||
if (MultiChannelFlag && (stream.DataChunk != null))
|
if (MultiChannelFlag && (stream.DataChunk != null))
|
||||||
{
|
{
|
||||||
MultiChannelSource = stream;
|
MultiChannelSource = stream;
|
||||||
@ -217,12 +217,14 @@ namespace CodeWalker.GameFiles
|
|||||||
MultiChannelSource?.AssignMultiChannelSources(Streams);
|
MultiChannelSource?.AssignMultiChannelSources(Streams);
|
||||||
|
|
||||||
BuildStreamDict();
|
BuildStreamDict();
|
||||||
|
|
||||||
|
//TestChunkOrdering(r.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Write(DataWriter w)
|
private void Write(DataWriter w)
|
||||||
{
|
{
|
||||||
StreamCount = StreamInfos?.Length ?? 0;
|
StreamCount = StreamInfos?.Length ?? 0;
|
||||||
var infoStart = 16 + (UnkUshortsFlag ? (StreamCount * 2) : 0);
|
var infoStart = 16 + (ChunkIndicesFlag ? (StreamCount * 2) : 0);
|
||||||
var dataOffset = infoStart + StreamCount * 4;
|
var dataOffset = infoStart + StreamCount * 4;
|
||||||
foreach (var info in StreamInfos) dataOffset += (int)info.ChunkCount * 8;
|
foreach (var info in StreamInfos) dataOffset += (int)info.ChunkCount * 8;
|
||||||
DataOffset = dataOffset;
|
DataOffset = dataOffset;
|
||||||
@ -233,11 +235,11 @@ namespace CodeWalker.GameFiles
|
|||||||
w.Write(StreamCount);
|
w.Write(StreamCount);
|
||||||
w.Write(DataOffset);
|
w.Write(DataOffset);
|
||||||
|
|
||||||
if (UnkUshortsFlag)
|
if (ChunkIndicesFlag)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < StreamCount; i++)
|
for (int i = 0; i < StreamCount; i++)
|
||||||
{
|
{
|
||||||
w.Write((i < (UnkUshorts?.Length ?? 0)) ? UnkUshorts[i] : (ushort)0);
|
w.Write((i < (ChunkIndices?.Length ?? 0)) ? ChunkIndices[i] : (ushort)0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,29 +257,21 @@ namespace CodeWalker.GameFiles
|
|||||||
chunkinfo.Write(w);
|
chunkinfo.Write(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (MultiChannelFlag)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < StreamCount; i++)
|
|
||||||
{
|
|
||||||
var stream = Streams[i];
|
|
||||||
stream.Write(w);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < StreamCount; i++)
|
|
||||||
{
|
|
||||||
var stream = Streams[i];
|
|
||||||
stream.WriteDataChunks(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < StreamCount; i++)
|
|
||||||
{
|
|
||||||
var stream = Streams[i];
|
|
||||||
stream.Write(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
var chunks = GetSortedChunks();
|
||||||
|
foreach (var chunk in chunks)
|
||||||
|
{
|
||||||
|
var chunkinfo = chunk.ChunkInfo;
|
||||||
|
var align = chunkinfo.Align;
|
||||||
|
if (align > 0)
|
||||||
|
{
|
||||||
|
var padc = (align - (w.Position % align)) % align;
|
||||||
|
if (padc > 0) w.Write(new byte[padc]);
|
||||||
|
}
|
||||||
|
chunk.Write(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,6 +280,10 @@ namespace CodeWalker.GameFiles
|
|||||||
public void WriteXml(StringBuilder sb, int indent, string wavfolder)
|
public void WriteXml(StringBuilder sb, int indent, string wavfolder)
|
||||||
{
|
{
|
||||||
AwcXml.ValueTag(sb, indent, "Version", Version.ToString());
|
AwcXml.ValueTag(sb, indent, "Version", Version.ToString());
|
||||||
|
if (ChunkIndicesFlag)
|
||||||
|
{
|
||||||
|
AwcXml.ValueTag(sb, indent, "ChunkIndices", true.ToString());
|
||||||
|
}
|
||||||
if (MultiChannelFlag)
|
if (MultiChannelFlag)
|
||||||
{
|
{
|
||||||
AwcXml.ValueTag(sb, indent, "MultiChannel", true.ToString());
|
AwcXml.ValueTag(sb, indent, "MultiChannel", true.ToString());
|
||||||
@ -308,10 +306,9 @@ namespace CodeWalker.GameFiles
|
|||||||
public void ReadXml(XmlNode node, string wavfolder)
|
public void ReadXml(XmlNode node, string wavfolder)
|
||||||
{
|
{
|
||||||
Version = (ushort)Xml.GetChildUIntAttribute(node, "Version");
|
Version = (ushort)Xml.GetChildUIntAttribute(node, "Version");
|
||||||
|
ChunkIndicesFlag = Xml.GetChildBoolAttribute(node, "ChunkIndices");
|
||||||
MultiChannelFlag = Xml.GetChildBoolAttribute(node, "MultiChannel");
|
MultiChannelFlag = Xml.GetChildBoolAttribute(node, "MultiChannel");
|
||||||
|
|
||||||
var hasUshorts = false;
|
|
||||||
|
|
||||||
var snode = node.SelectSingleNode("Streams");
|
var snode = node.SelectSingleNode("Streams");
|
||||||
if (snode != null)
|
if (snode != null)
|
||||||
{
|
{
|
||||||
@ -323,8 +320,6 @@ namespace CodeWalker.GameFiles
|
|||||||
stream.ReadXml(inode, wavfolder);
|
stream.ReadXml(inode, wavfolder);
|
||||||
slist.Add(stream);
|
slist.Add(stream);
|
||||||
|
|
||||||
hasUshorts = hasUshorts || stream.UnkUshort.HasValue;
|
|
||||||
|
|
||||||
if (MultiChannelFlag && (stream.StreamFormatChunk != null) && (stream.Hash == 0))
|
if (MultiChannelFlag && (stream.StreamFormatChunk != null) && (stream.Hash == 0))
|
||||||
{
|
{
|
||||||
MultiChannelSource = stream;
|
MultiChannelSource = stream;
|
||||||
@ -338,19 +333,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasUshorts)
|
BuildChunkIndices();
|
||||||
{
|
|
||||||
var unkUshorts = new List<ushort>();
|
|
||||||
if (Streams != null)
|
|
||||||
{
|
|
||||||
foreach (var stream in Streams)
|
|
||||||
{
|
|
||||||
unkUshorts.Add(stream.UnkUshort ?? 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UnkUshorts = unkUshorts.ToArray();
|
|
||||||
UnkUshortsFlag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
BuildStreamInfos();
|
BuildStreamInfos();
|
||||||
|
|
||||||
@ -372,6 +355,157 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public AwcChunk[] GetSortedChunks()
|
||||||
|
{
|
||||||
|
var chunks = new List<AwcChunk>();
|
||||||
|
|
||||||
|
if (Streams != null)
|
||||||
|
{
|
||||||
|
foreach (var stream in Streams)
|
||||||
|
{
|
||||||
|
if (stream.Chunks != null)
|
||||||
|
{
|
||||||
|
chunks.AddRange(stream.Chunks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var issorted = MultiChannelFlag || !SingleChannelEncryptFlag;
|
||||||
|
if (issorted)
|
||||||
|
{
|
||||||
|
chunks.Sort((a, b) => b.ChunkInfo?.SortOrder.CompareTo(a.ChunkInfo?.SortOrder ?? 0) ?? -1);
|
||||||
|
chunks.Reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TestChunkOrdering(long datalength)
|
||||||
|
{
|
||||||
|
if (Streams == null) return;
|
||||||
|
if (StreamInfos == null) return;
|
||||||
|
|
||||||
|
var issorted = MultiChannelFlag || !SingleChannelEncryptFlag;
|
||||||
|
|
||||||
|
var chunklist = ChunkInfos.ToList();
|
||||||
|
chunklist.Sort((a, b) => a.Offset.CompareTo(b.Offset));
|
||||||
|
var chunks = chunklist.ToArray();
|
||||||
|
|
||||||
|
//var chunks2 = GetAllChunks();
|
||||||
|
|
||||||
|
var infoStart = 16 + (ChunkIndicesFlag ? (StreamCount * 2) : 0);
|
||||||
|
var offset = infoStart + (StreamCount * 4) + (chunks.Length * 8);
|
||||||
|
foreach (var chunk in chunks)
|
||||||
|
{
|
||||||
|
if (issorted)
|
||||||
|
{
|
||||||
|
var align = chunk.Align;
|
||||||
|
if (align != 0)
|
||||||
|
{
|
||||||
|
offset += ((align - (offset % align)) % align);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (chunk.Type)
|
||||||
|
{
|
||||||
|
case AwcChunkType.animation:
|
||||||
|
if (issorted)
|
||||||
|
{ }//no hit
|
||||||
|
switch (chunk.Offset - offset)
|
||||||
|
{
|
||||||
|
case 12:
|
||||||
|
case 8:
|
||||||
|
case 0:
|
||||||
|
case 4:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;//no hit
|
||||||
|
}
|
||||||
|
offset = chunk.Offset;//what is correct padding for this? seems to be inconsistent
|
||||||
|
break;
|
||||||
|
case AwcChunkType.gesture:
|
||||||
|
if (issorted)
|
||||||
|
{ }//no hit
|
||||||
|
switch (chunk.Offset - offset)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;//no hit
|
||||||
|
}
|
||||||
|
offset = chunk.Offset;//what is correct padding for this? seems to be inconsistent
|
||||||
|
break;
|
||||||
|
case AwcChunkType.seektable:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((chunk.Offset - offset) != 0)
|
||||||
|
{ offset = chunk.Offset; }//no hit
|
||||||
|
offset += chunk.Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WholeFileEncrypted) offset += (4 - (offset % 4)) % 4;
|
||||||
|
if ((datalength - offset) != 0)
|
||||||
|
{ }//no hit
|
||||||
|
|
||||||
|
|
||||||
|
if (issorted)
|
||||||
|
{
|
||||||
|
|
||||||
|
bool datachunk = false;
|
||||||
|
bool markerchunk = false;
|
||||||
|
foreach (var chunk in chunks)
|
||||||
|
{
|
||||||
|
if ((chunk.Type == AwcChunkType.data) || (chunk.Type == AwcChunkType.mid)) datachunk = true;
|
||||||
|
else if (datachunk)
|
||||||
|
{ }//no hit
|
||||||
|
if ((chunk.Type == AwcChunkType.markers) || (chunk.Type == AwcChunkType.granulargrains) || (chunk.Type == AwcChunkType.granularloops)) markerchunk = true;
|
||||||
|
else if (markerchunk && !datachunk)
|
||||||
|
{ }//no hit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ChunkInfos[0].Type != AwcChunkType.data)
|
||||||
|
{ }//no hit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BuildChunkIndices()
|
||||||
|
{
|
||||||
|
if (Streams == null) return;
|
||||||
|
|
||||||
|
var inds = new List<ushort>();
|
||||||
|
ushort ind = 0;
|
||||||
|
foreach (var stream in Streams)
|
||||||
|
{
|
||||||
|
inds.Add(ind);
|
||||||
|
ind += (ushort)(stream.Chunks?.Length ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (ChunkIndices != null)
|
||||||
|
//{
|
||||||
|
// if (ChunkIndices.Length == inds.Count)
|
||||||
|
// {
|
||||||
|
// for (int i = 0; i < inds.Count; i++)
|
||||||
|
// {
|
||||||
|
// if (inds[i] != ChunkIndices[i])
|
||||||
|
// { }//no hit
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// { }//no hit
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (ChunkIndicesFlag)
|
||||||
|
{
|
||||||
|
ChunkIndices = inds.ToArray();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ChunkIndices = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void BuildStreamInfos()
|
public void BuildStreamInfos()
|
||||||
{
|
{
|
||||||
@ -380,78 +514,30 @@ namespace CodeWalker.GameFiles
|
|||||||
var chunkinfos = new List<AwcChunkInfo>();
|
var chunkinfos = new List<AwcChunkInfo>();
|
||||||
if (Streams != null)
|
if (Streams != null)
|
||||||
{
|
{
|
||||||
var streamCount = Streams?.Length ?? 0;
|
var streamCount = Streams.Length;
|
||||||
var infoStart = 16 + (UnkUshortsFlag ? (streamCount * 2) : 0);
|
var infoStart = 16 + (ChunkIndicesFlag ? (streamCount * 2) : 0);
|
||||||
var dataOffset = infoStart + streamCount * 4;
|
var dataOffset = infoStart + streamCount * 4;
|
||||||
foreach (var stream in Streams)
|
foreach (var stream in Streams)
|
||||||
{
|
{
|
||||||
dataOffset += (stream?.Chunks?.Length ?? 0) * 8;
|
dataOffset += (stream?.Chunks?.Length ?? 0) * 8;
|
||||||
}
|
}
|
||||||
if (MultiChannelFlag)
|
|
||||||
|
var chunks = GetSortedChunks();
|
||||||
|
foreach (var chunk in chunks)
|
||||||
{
|
{
|
||||||
foreach (var stream in Streams)
|
var chunkinfo = chunk.ChunkInfo;
|
||||||
|
var size = chunk.ChunkSize;
|
||||||
|
var align = chunkinfo.Align;
|
||||||
|
if (align > 0)
|
||||||
{
|
{
|
||||||
if (stream.Chunks != null)
|
var padc = (align - (dataOffset % align)) % align;
|
||||||
{
|
|
||||||
foreach (var chunk in stream.Chunks)
|
|
||||||
{
|
|
||||||
if (!(chunk is AwcDataChunk))
|
|
||||||
{
|
|
||||||
if (chunk is AwcMarkersChunk)
|
|
||||||
{
|
|
||||||
//align to 4 bytes
|
|
||||||
var padc = (4 - (dataOffset % 4)) % 4;
|
|
||||||
dataOffset += padc;
|
dataOffset += padc;
|
||||||
}
|
}
|
||||||
|
chunkinfo.Size = size;
|
||||||
|
chunkinfo.Offset = dataOffset;
|
||||||
|
dataOffset += size;
|
||||||
|
}
|
||||||
|
|
||||||
var chunkinfo = chunk.ChunkInfo;
|
|
||||||
var size = chunk.ChunkSize;
|
|
||||||
chunkinfo.Size = size;
|
|
||||||
chunkinfo.Offset = dataOffset;
|
|
||||||
dataOffset += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var stream in Streams)
|
|
||||||
{
|
|
||||||
if (stream.Chunks != null)
|
|
||||||
{
|
|
||||||
foreach (var chunk in stream.Chunks)
|
|
||||||
{
|
|
||||||
if (chunk is AwcDataChunk)
|
|
||||||
{
|
|
||||||
//align to 16 bytes
|
|
||||||
var padc = (16 - (dataOffset % 16)) % 16;
|
|
||||||
dataOffset += padc;
|
|
||||||
|
|
||||||
var chunkinfo = chunk.ChunkInfo;
|
|
||||||
var size = chunk.ChunkSize;
|
|
||||||
chunkinfo.Size = size;
|
|
||||||
chunkinfo.Offset = dataOffset;
|
|
||||||
dataOffset += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var stream in Streams)
|
|
||||||
{
|
|
||||||
if (stream.Chunks != null)
|
|
||||||
{
|
|
||||||
foreach (var chunk in stream.Chunks)
|
|
||||||
{
|
|
||||||
var chunkinfo = chunk.ChunkInfo;
|
|
||||||
var size = chunk.ChunkSize;
|
|
||||||
chunkinfo.Size = size;
|
|
||||||
chunkinfo.Offset = dataOffset;
|
|
||||||
dataOffset += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var stream in Streams)
|
foreach (var stream in Streams)
|
||||||
{
|
{
|
||||||
var streaminfo = stream.StreamInfo;
|
var streaminfo = stream.StreamInfo;
|
||||||
@ -524,6 +610,49 @@ namespace CodeWalker.GameFiles
|
|||||||
public int Size { get; set; }
|
public int Size { get; set; }
|
||||||
public int Offset { get; set; }
|
public int Offset { get; set; }
|
||||||
|
|
||||||
|
public int SortOrder
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case AwcChunkType.data:
|
||||||
|
case AwcChunkType.mid:
|
||||||
|
return 3;
|
||||||
|
case AwcChunkType.markers:
|
||||||
|
case AwcChunkType.granulargrains:
|
||||||
|
case AwcChunkType.granularloops:
|
||||||
|
case AwcChunkType.animation:
|
||||||
|
case AwcChunkType.gesture:
|
||||||
|
return 2;
|
||||||
|
case AwcChunkType.seektable:
|
||||||
|
return 1;
|
||||||
|
case AwcChunkType.peak:
|
||||||
|
case AwcChunkType.format:
|
||||||
|
case AwcChunkType.streamformat:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int Align
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case AwcChunkType.data:
|
||||||
|
case AwcChunkType.mid:
|
||||||
|
return 16;
|
||||||
|
case AwcChunkType.markers:
|
||||||
|
case AwcChunkType.granulargrains:
|
||||||
|
case AwcChunkType.granularloops:
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Read(DataReader r)
|
public void Read(DataReader r)
|
||||||
{
|
{
|
||||||
RawVal = r.ReadUInt64();
|
RawVal = r.ReadUInt64();
|
||||||
@ -581,8 +710,6 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ushort? UnkUshort { get; set; } // stored in root of AWC, will have value if present
|
|
||||||
|
|
||||||
public MetaHash Hash
|
public MetaHash Hash
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -753,42 +880,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public void Write(DataWriter w)
|
public void Write(DataWriter w)
|
||||||
{
|
{
|
||||||
if (Chunks != null)
|
//not used since chunks are collected and sorted, then written separately
|
||||||
{
|
|
||||||
foreach (var chunk in Chunks)
|
|
||||||
{
|
|
||||||
if (!((chunk is AwcDataChunk) && Awc.MultiChannelFlag))
|
|
||||||
{
|
|
||||||
if (Awc.MultiChannelFlag && (chunk is AwcMarkersChunk))
|
|
||||||
{
|
|
||||||
//write padding to align to 4 bytes
|
|
||||||
var padc = (4 - (w.Position % 4)) % 4;
|
|
||||||
if (padc > 0) w.Write(new byte[padc]);
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk.Write(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void WriteDataChunks(DataWriter w)
|
|
||||||
{
|
|
||||||
//for use by multichannel only, to write the data at the end
|
|
||||||
|
|
||||||
if (Chunks != null)
|
|
||||||
{
|
|
||||||
foreach (var chunk in Chunks)
|
|
||||||
{
|
|
||||||
if (chunk is AwcDataChunk)
|
|
||||||
{
|
|
||||||
//write padding to align to 16 bytes
|
|
||||||
var padc = (16 - (w.Position % 16)) % 16;
|
|
||||||
if (padc > 0) w.Write(new byte[padc]);
|
|
||||||
|
|
||||||
chunk.Write(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteXml(StringBuilder sb, int indent, string wavfolder)
|
public void WriteXml(StringBuilder sb, int indent, string wavfolder)
|
||||||
@ -825,10 +917,6 @@ namespace CodeWalker.GameFiles
|
|||||||
catch
|
catch
|
||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
if (UnkUshort.HasValue)
|
|
||||||
{
|
|
||||||
AwcXml.ValueTag(sb, indent, "UnkUshort", UnkUshort.Value.ToString());
|
|
||||||
}
|
|
||||||
if (StreamFormat != null)
|
if (StreamFormat != null)
|
||||||
{
|
{
|
||||||
AwcXml.OpenTag(sb, indent, "StreamFormat");
|
AwcXml.OpenTag(sb, indent, "StreamFormat");
|
||||||
@ -851,11 +939,6 @@ namespace CodeWalker.GameFiles
|
|||||||
public void ReadXml(XmlNode node, string wavfolder)
|
public void ReadXml(XmlNode node, string wavfolder)
|
||||||
{
|
{
|
||||||
Hash = XmlMeta.GetHash(Xml.GetChildInnerText(node, "Name"));
|
Hash = XmlMeta.GetHash(Xml.GetChildInnerText(node, "Name"));
|
||||||
var unode = node.SelectSingleNode("UnkUshort");
|
|
||||||
if (unode != null)
|
|
||||||
{
|
|
||||||
UnkUshort = (ushort)Xml.GetUIntAttribute(unode, "value");
|
|
||||||
}
|
|
||||||
var fnode = node.SelectSingleNode("StreamFormat");
|
var fnode = node.SelectSingleNode("StreamFormat");
|
||||||
if (fnode != null)
|
if (fnode != null)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user