Fixed YED/XML conversion

This commit is contained in:
dexy 2024-07-22 21:06:18 +10:00
parent 5d3849b682
commit 97c24710e4
3 changed files with 333 additions and 460 deletions

View File

@ -3203,9 +3203,7 @@ namespace CodeWalker.GameFiles
{
foreach (RpfEntry entry in file.AllEntries)
{
#if !DEBUG
try
#endif
//try
{
var n = entry.NameLower;
if (!(n.EndsWith(".pso") ||
@ -3273,13 +3271,11 @@ namespace CodeWalker.GameFiles
}
}
}
#if !DEBUG
catch (Exception ex)
{
UpdateStatus("Error! " + ex.ToString());
exceptions.Add(ex);
}
#endif
//catch (Exception ex)
//{
// UpdateStatus("Error! " + ex.ToString());
// exceptions.Add(ex);
//}
}
}
@ -3381,9 +3377,7 @@ namespace CodeWalker.GameFiles
{
foreach (RpfEntry entry in file.AllEntries)
{
#if !DEBUG
try
#endif
//try
{
var rfe = entry as RpfFileEntry;
if (rfe == null) continue;
@ -3398,13 +3392,11 @@ namespace CodeWalker.GameFiles
//PsoTypes.EnsurePsoTypes(cut.Pso);
}
}
#if !DEBUG
catch (Exception ex)
{
UpdateStatus("Error! " + ex.ToString());
exceptions.Add(ex);
}
#endif
//catch (Exception ex)
//{
// UpdateStatus("Error! " + ex.ToString());
// exceptions.Add(ex);
//}
}
}
@ -3422,9 +3414,7 @@ namespace CodeWalker.GameFiles
{
foreach (RpfEntry entry in file.AllEntries)
{
#if !DEBUG
try
#endif
//try
{
var rfe = entry as RpfFileEntry;
if (rfe == null) continue;
@ -3438,13 +3428,11 @@ namespace CodeWalker.GameFiles
}
}
#if !DEBUG
catch (Exception ex)
{
UpdateStatus("Error! " + ex.ToString());
exceptions.Add(ex);
}
#endif
//catch (Exception ex)
//{
// UpdateStatus("Error! " + ex.ToString());
// exceptions.Add(ex);
//}
}
}
@ -3453,16 +3441,14 @@ namespace CodeWalker.GameFiles
}
public void TestYeds()
{
bool xmltest = true;
var exceptions = new List<Exception>();
foreach (RpfFile file in AllRpfs)
{
foreach (RpfEntry entry in file.AllEntries)
{
#if !DEBUG
try
#endif
//try
{
var rfe = entry as RpfFileEntry;
if (rfe == null) continue;
@ -3474,6 +3460,8 @@ namespace CodeWalker.GameFiles
YedFile yed = new YedFile(rfe);
RpfMan.LoadFile(yed, rfe);
if (xmltest)
{
var xml = YedXml.GetXml(yed);
var yed2 = XmlYed.GetYed(xml);
var data2 = yed2.Save();
@ -3481,17 +3469,16 @@ namespace CodeWalker.GameFiles
RpfFile.LoadResourceFile(yed3, data2, 25);//full roundtrip
var xml2 = YedXml.GetXml(yed3);
if (xml != xml2)
{ }
{ }//no hitting
}
}
}
#if !DEBUG
catch (Exception ex)
{
UpdateStatus("Error! " + ex.ToString());
exceptions.Add(ex);
}
#endif
//catch (Exception ex)
//{
// UpdateStatus("Error! " + ex.ToString());
// exceptions.Add(ex);
//}
}
}
@ -4370,9 +4357,7 @@ namespace CodeWalker.GameFiles
{
foreach (RpfEntry entry in file.AllEntries)
{
#if !DEBUG
try
#endif
//try
{
var rfe = entry as RpfFileEntry;
if (rfe == null) continue;
@ -4397,13 +4382,11 @@ namespace CodeWalker.GameFiles
}
}
#if !DEBUG
catch (Exception ex)
{
UpdateStatus("Error! " + ex.ToString());
exceptions.Add(ex);
}
#endif
//catch (Exception ex)
//{
// UpdateStatus("Error! " + ex.ToString());
// exceptions.Add(ex);
//}
}
}
@ -4419,9 +4402,7 @@ namespace CodeWalker.GameFiles
{
foreach (RpfEntry entry in file.AllEntries)
{
#if !DEBUG
try
#endif
//try
{
var rfe = entry as RpfFileEntry;
if (rfe == null) continue;
@ -4444,13 +4425,11 @@ namespace CodeWalker.GameFiles
}
}
#if !DEBUG
catch (Exception ex)
{
UpdateStatus("Error! " + ex.ToString());
exceptions.Add(ex);
}
#endif
//catch (Exception ex)
//{
// UpdateStatus("Error! " + ex.ToString());
// exceptions.Add(ex);
//}
}
}

View File

@ -38,11 +38,8 @@ namespace CodeWalker.GameFiles
[TC(typeof(EXP))] public class ExpressionDictionary : ResourceFileBase
{
// pgDictionaryBase
// pgDictionary<crExpressions>
// pgDictionary<crExpressions> : pgDictionaryBase
public override long BlockLength => 0x40;
// structure data
public uint Unknown_10h { get; set; } = 0;
public uint Unknown_14h { get; set; } = 0;
public uint Unknown_18h { get; set; } = 1;
@ -50,40 +47,32 @@ namespace CodeWalker.GameFiles
public ResourceSimpleList64_s<MetaHash> ExpressionNameHashes { get; set; }
public ResourcePointerList64<Expression> Expressions { get; set; }
public Dictionary<MetaHash, Expression> ExprMap { get; set; }
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
// read structure data
this.Unknown_10h = reader.ReadUInt32();
this.Unknown_14h = reader.ReadUInt32();
this.Unknown_18h = reader.ReadUInt32();
this.Unknown_1Ch = reader.ReadUInt32();
this.ExpressionNameHashes = reader.ReadBlock<ResourceSimpleList64_s<MetaHash>>();
this.Expressions = reader.ReadBlock<ResourcePointerList64<Expression>>();
Unknown_10h = reader.ReadUInt32();
Unknown_14h = reader.ReadUInt32();
Unknown_18h = reader.ReadUInt32();
Unknown_1Ch = reader.ReadUInt32();
ExpressionNameHashes = reader.ReadBlock<ResourceSimpleList64_s<MetaHash>>();
Expressions = reader.ReadBlock<ResourcePointerList64<Expression>>();
BuildMap();
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
// write structure data
writer.Write(this.Unknown_10h);
writer.Write(this.Unknown_14h);
writer.Write(this.Unknown_18h);
writer.Write(this.Unknown_1Ch);
writer.WriteBlock(this.ExpressionNameHashes);
writer.WriteBlock(this.Expressions);
writer.Write(Unknown_10h);
writer.Write(Unknown_14h);
writer.Write(Unknown_18h);
writer.Write(Unknown_1Ch);
writer.WriteBlock(ExpressionNameHashes);
writer.WriteBlock(Expressions);
}
public void WriteXml(StringBuilder sb, int indent)
{
if (Expressions?.data_items != null)
{
foreach (var e in Expressions.data_items)
@ -93,7 +82,6 @@ namespace CodeWalker.GameFiles
YedXml.CloseTag(sb, indent, "Item");
}
}
}
public void ReadXml(XmlNode node)
{
@ -108,6 +96,12 @@ namespace CodeWalker.GameFiles
var e = new Expression();
e.ReadXml(inode);
expressions.Add(e);
}
//expressions in the file should be sorted by hash
expressions.Sort((a, b) => a.NameHash.Hash.CompareTo(b.NameHash.Hash));
foreach (var e in expressions)
{
expressionhashes.Add(e.NameHash);
}
}
@ -182,11 +176,8 @@ namespace CodeWalker.GameFiles
[TC(typeof(EXP))] public class Expression : ResourceSystemBlock
{
// pgBase
// crExpressions
// crExpressions : pgBase
public override long BlockLength => 0x90;
// structure data
public uint VFT { get; set; }
public uint Unknown_4h { get; set; } = 1;
public uint Unknown_8h { get; set; } // 0x00000000
@ -206,13 +197,12 @@ namespace CodeWalker.GameFiles
public uint Unknown_70h { get; set; } = 1;
public uint Signature { get; set; }
public uint MaxStreamSize { get; set; } // max length of any item in Streams
public uint Unknown_7Ch { get; set; } // 3 or 2
public uint Unknown_7Ch { get; set; } // 3 or 2 - type or flags?
public uint Unknown_80h { get; set; } // 0x00000000
public uint Unknown_84h { get; set; } // 0x00000000
public uint Unknown_88h { get; set; } // 0x00000000
public uint Unknown_8Ch { get; set; } // 0x00000000
// reference data
public string_r Name { get; set; }
public MetaHash NameHash { get; set; }
@ -221,36 +211,32 @@ namespace CodeWalker.GameFiles
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.VFT = reader.ReadUInt32();
this.Unknown_4h = reader.ReadUInt32();
this.Unknown_8h = reader.ReadUInt32();
this.Unknown_Ch = reader.ReadUInt32();
this.Unknown_10h = reader.ReadUInt32();
this.Unknown_14h = reader.ReadUInt32();
this.Unknown_18h = reader.ReadUInt32();
this.Unknown_1Ch = reader.ReadUInt32();
this.Streams = reader.ReadBlock<ResourcePointerList64<ExpressionStream>>();
this.Tracks = reader.ReadBlock<ResourceSimpleList64_s<ExpressionTrack>>();
this.Springs = reader.ReadBlock<ResourceSimpleList64<ExpressionSpringDescriptionBlock>>();
this.Variables = reader.ReadBlock<ResourceSimpleList64_s<MetaHash>>();
this.NamePointer = reader.ReadUInt64();
this.NameLength = reader.ReadUInt16();
this.NameCapacity = reader.ReadUInt16();
this.Unknown_6Ch = reader.ReadUInt32();
this.Unknown_70h = reader.ReadUInt32();
this.Signature = reader.ReadUInt32();
this.MaxStreamSize = reader.ReadUInt32();
this.Unknown_7Ch = reader.ReadUInt32();
this.Unknown_80h = reader.ReadUInt32();
this.Unknown_84h = reader.ReadUInt32();
this.Unknown_88h = reader.ReadUInt32();
this.Unknown_8Ch = reader.ReadUInt32();
VFT = reader.ReadUInt32();
Unknown_4h = reader.ReadUInt32();
Unknown_8h = reader.ReadUInt32();
Unknown_Ch = reader.ReadUInt32();
Unknown_10h = reader.ReadUInt32();
Unknown_14h = reader.ReadUInt32();
Unknown_18h = reader.ReadUInt32();
Unknown_1Ch = reader.ReadUInt32();
Streams = reader.ReadBlock<ResourcePointerList64<ExpressionStream>>();
Tracks = reader.ReadBlock<ResourceSimpleList64_s<ExpressionTrack>>();
Springs = reader.ReadBlock<ResourceSimpleList64<ExpressionSpringDescriptionBlock>>();
Variables = reader.ReadBlock<ResourceSimpleList64_s<MetaHash>>();
NamePointer = reader.ReadUInt64();
NameLength = reader.ReadUInt16();
NameCapacity = reader.ReadUInt16();
Unknown_6Ch = reader.ReadUInt32();
Unknown_70h = reader.ReadUInt32();
Signature = reader.ReadUInt32();
MaxStreamSize = reader.ReadUInt32();
Unknown_7Ch = reader.ReadUInt32();
Unknown_80h = reader.ReadUInt32();
Unknown_84h = reader.ReadUInt32();
Unknown_88h = reader.ReadUInt32();
Unknown_8Ch = reader.ReadUInt32();
// read reference data
this.Name = reader.ReadBlockAt<string_r>(
this.NamePointer // offset
);
Name = reader.ReadBlockAt<string_r>(NamePointer);
JenkIndex.Ensure(GetShortName());
@ -261,120 +247,46 @@ namespace CodeWalker.GameFiles
#region testing
//if (Streams?.data_items != null)
//{ }
////if ((this.JiggleData?.data_items?.Length ?? 0) > 0)
//{
// var cnt1 = JiggleData?.data_items?.Length ?? 0;
// var cnt2 = 0;
// foreach (var stream in Streams.data_items)
// {
// foreach (var node in stream.Items)
// {
// if (node is ExpressionNodeJiggle jnode)
// {
// var trackrot = BoneTracks.data_items[jnode.BoneTrackRot];
// var trackpos = BoneTracks.data_items[jnode.BoneTrackPos];
// var jd1 = jnode.JiggleData;
// var jd2 = JiggleData.data_items[cnt2].JiggleData;
// if (!jd1.Compare(jd2))
// { }//no hit
// if (jd2.BoneTag != trackrot.BoneTag)
// { }//no hit
// cnt2++;
// }
// }
// }
// if (cnt1 != cnt2)
// { }//no hit
//}
//long tlen = 0;
//if (Streams?.data_items != null) foreach (var item in Streams.data_items) tlen = Math.Max(tlen, item.BlockLength);
//if (MaxStreamSize != tlen)
//{ }//no hit
//if (Unknown_4h != 1)
//{ }//no hit
//if (Unknown_8h != 0)
//{ }//no hit
//if (Unknown_Ch != 0)
//{ }//no hit
//if (Unknown_10h != 0)
//{ }//no hit
//if (Unknown_14h != 0)
//{ }//no hit
//if (Unknown_18h != 0)
//{ }//no hit
//if (Unknown_1Ch != 0)
//{ }//no hit
//if (NameLength != (Name?.Value?.Length ?? 0))
//{ }//no hit
//if (NameCapacity != (NameLength + 1))
//{ }//no hit
//if (Unknown_6Ch != 0)
//{ }//no hit
//if (Unknown_70h != 1)
//{ }//no hit
//switch (Unknown_74h)
//{
// default:
// break;
//}
//switch (Unknown_7Ch)
//{
// case 3:
// case 2:
// break;
// default:
// break;//no hit
//}
//if (Unknown_80h != 0)
//{ }//no hit
//if (Unknown_84h != 0)
//{ }//no hit
//if (Unknown_88h != 0)
//{ }//no hit
//if (Unknown_8Ch != 0)
//{ }//no hit
#endregion
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// update structure data
this.NamePointer = (ulong)(this.Name != null ? this.Name.FilePosition : 0);
NamePointer = (ulong)(Name != null ? Name.FilePosition : 0);
// write structure data
writer.Write(this.VFT);
writer.Write(this.Unknown_4h);
writer.Write(this.Unknown_8h);
writer.Write(this.Unknown_Ch);
writer.Write(this.Unknown_10h);
writer.Write(this.Unknown_14h);
writer.Write(this.Unknown_18h);
writer.Write(this.Unknown_1Ch);
writer.WriteBlock(this.Streams);
writer.WriteBlock(this.Tracks);
writer.WriteBlock(this.Springs);
writer.WriteBlock(this.Variables);
writer.Write(this.NamePointer);
writer.Write(this.NameLength);
writer.Write(this.NameCapacity);
writer.Write(this.Unknown_6Ch);
writer.Write(this.Unknown_70h);
writer.Write(this.Signature);
writer.Write(this.MaxStreamSize);
writer.Write(this.Unknown_7Ch);
writer.Write(this.Unknown_80h);
writer.Write(this.Unknown_84h);
writer.Write(this.Unknown_88h);
writer.Write(this.Unknown_8Ch);
writer.Write(VFT);
writer.Write(Unknown_4h);
writer.Write(Unknown_8h);
writer.Write(Unknown_Ch);
writer.Write(Unknown_10h);
writer.Write(Unknown_14h);
writer.Write(Unknown_18h);
writer.Write(Unknown_1Ch);
writer.WriteBlock(Streams);
writer.WriteBlock(Tracks);
writer.WriteBlock(Springs);
writer.WriteBlock(Variables);
writer.Write(NamePointer);
writer.Write(NameLength);
writer.Write(NameCapacity);
writer.Write(Unknown_6Ch);
writer.Write(Unknown_70h);
writer.Write(Signature);
writer.Write(MaxStreamSize);
writer.Write(Unknown_7Ch);
writer.Write(Unknown_80h);
writer.Write(Unknown_84h);
writer.Write(Unknown_88h);
writer.Write(Unknown_8Ch);
}
public void WriteXml(StringBuilder sb, int indent)
{
YedXml.StringTag(sb, indent, "Name", Name?.Value ?? "");
YedXml.ValueTag(sb, indent, "Signature", Signature.ToString()); // TODO: calculate signature
YedXml.ValueTag(sb, indent, "Signature", Signature.ToString()); // TODO: calculate signature?
YedXml.ValueTag(sb, indent, "Unk7C", Unknown_7Ch.ToString());
if ((Tracks?.data_items?.Length ?? 0) > 0)
@ -408,6 +320,7 @@ namespace CodeWalker.GameFiles
BuildSpringsList();
UpdateVariables();
UpdateStreamBuffers();
UpdateJumpInstructions();
}
public override IResourceBlock[] GetReferences()
@ -449,7 +362,6 @@ namespace CodeWalker.GameFiles
}
}
public void BuildSpringsList()
{
var springs = new List<ExpressionSpringDescriptionBlock>();
@ -471,7 +383,6 @@ namespace CodeWalker.GameFiles
Springs = new ResourceSimpleList64<ExpressionSpringDescriptionBlock>();
Springs.data_items = springs.ToArray();
}
public void UpdateVariables()
{
var dict = new Dictionary<MetaHash, uint>();
@ -513,7 +424,6 @@ namespace CodeWalker.GameFiles
Variables.data_items = list.ToArray();
}
public void UpdateStreamBuffers()
{
MaxStreamSize = 0;
@ -526,6 +436,26 @@ namespace CodeWalker.GameFiles
}
}
}
public void UpdateJumpInstructions()
{
if (Streams?.data_items != null)
{
foreach (var stream in Streams.data_items)
{
if (stream?.Instructions == null) continue;
foreach (var node in stream.Instructions)
{
if (node is ExpressionInstrJump jump)
{
//indexes and offsets need to be updated already - done by UpdateMaxStreamSize()
var target = stream.Instructions[jump.Index + jump.Data3Offset];
jump.Data1Offset = (uint)(target.Offset1 - jump.Offset1);
jump.Data2Offset = (uint)(target.Offset2 - jump.Offset2);
}
}
}
}
}
public string GetShortName()
@ -544,17 +474,12 @@ namespace CodeWalker.GameFiles
[TC(typeof(EXP))] public class ExpressionStream : ResourceSystemBlock, IMetaXmlItem
{
public override long BlockLength
{
get { return 16 + Data1.Length + Data2.Length + Data3.Length; }
}
// structure data
public MetaHash NameHash { get; set; }//presumably name hash
public override long BlockLength => 16 + Data1.Length + Data2.Length + Data3.Length;
public MetaHash NameHash { get; set; }
public uint Data1Length { get; set; }
public uint Data2Length { get; set; }
public ushort Data3Length { get; set; }
public ushort Unk0E { get; set; }//what is this? possibly max hierarchy depth
public ushort Depth { get; set; }//or stack size?
public byte[] Data1 { get; set; }
public byte[] Data2 { get; set; }
public byte[] Data3 { get; set; }
@ -566,37 +491,32 @@ namespace CodeWalker.GameFiles
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.NameHash = reader.ReadUInt32();
this.Data1Length = reader.ReadUInt32();
this.Data2Length = reader.ReadUInt32();
this.Data3Length = reader.ReadUInt16();
this.Unk0E = reader.ReadUInt16();
this.Data1 = reader.ReadBytes((int)Data1Length);
this.Data2 = reader.ReadBytes((int)Data2Length);
this.Data3 = reader.ReadBytes((int)Data3Length);
NameHash = reader.ReadUInt32();
Data1Length = reader.ReadUInt32();
Data2Length = reader.ReadUInt32();
Data3Length = reader.ReadUInt16();
Depth = reader.ReadUInt16();
Data1 = reader.ReadBytes((int)Data1Length);
Data2 = reader.ReadBytes((int)Data2Length);
Data3 = reader.ReadBytes((int)Data3Length);
ReadInstructions();
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
//WriteItems();//should already be done by Expression.UpdateStreamBuffers
// write structure data
writer.Write(this.NameHash);
writer.Write(this.Data1Length);
writer.Write(this.Data2Length);
writer.Write(this.Data3Length);
writer.Write(this.Unk0E);
writer.Write(this.Data1);
writer.Write(this.Data2);
writer.Write(this.Data3);
//WriteInstructions();//should already be done by Expression.UpdateStreamBuffers
writer.Write(NameHash);
writer.Write(Data1Length);
writer.Write(Data2Length);
writer.Write(Data3Length);
writer.Write(Depth);
writer.Write(Data1);
writer.Write(Data2);
writer.Write(Data3);
}
public void WriteXml(StringBuilder sb, int indent)
{
YedXml.StringTag(sb, indent, "Name", YedXml.HashString(NameHash));
YedXml.ValueTag(sb, indent, "Unk0E", Unk0E.ToString());
YedXml.ValueTag(sb, indent, "Depth", Depth.ToString());
YedXml.OpenTag(sb, indent, "Instructions");
var cind = indent + 1;
@ -621,7 +541,7 @@ namespace CodeWalker.GameFiles
public void ReadXml(XmlNode node)
{
NameHash = XmlMeta.GetHash(Xml.GetChildInnerText(node, "Name"));
Unk0E = (ushort)Xml.GetChildUIntAttribute(node, "Unk0E", "value");
Depth = (ushort)Xml.GetChildUIntAttribute(node, "Depth", "value");
var items = new List<ExpressionInstrBase>();
var instnode = node.SelectSingleNode("Instructions");
@ -639,6 +559,8 @@ namespace CodeWalker.GameFiles
item.ReadXml(inode);
items.Add(item);
}
else
{ }
}
}
}
@ -647,81 +569,37 @@ namespace CodeWalker.GameFiles
public void ReadInstructions()
{
var insts = new ExpressionInstrBase[Data3.Length];
var s1 = new MemoryStream(Data1);
var s2 = new MemoryStream(Data2);
var s3 = new MemoryStream(Data3);
var r1 = new DataReader(s1);
var r2 = new DataReader(s2);
var r3 = new DataReader(s3);
var unresolvedJumps = new Dictionary<(long, long, long), List<ExpressionInstrJump>>();
var instructions = new List<ExpressionInstrBase>();
while (s3.Position < s3.Length)
{
var loc = (s1.Position, s2.Position, s3.Position);
//dexy: removed unresolvedjumps stuff from here as it should all resolve to jump.Data3Offset+1
var type = (ExpressionInstrType)r3.ReadByte();
if (type == ExpressionInstrType.None)
for (int i = 0; i < insts.Length; i++)
{
if (s3.Position != s3.Length)
var type = (ExpressionInstrType)Data3[i];
if (type == ExpressionInstrType.End)
{
if (i != insts.Length - 1)
{ }//no hit
break;
}
var instr = CreateInstruction(type);
instr.Type = type;
instr.Index = i;
instr.Offset1 = (int)r1.Position;
instr.Offset2 = (int)r2.Position;
instr.Read(r1, r2);
var instrIndex = (uint)instructions.Count;
instructions.Add(instr);
// resolve jumps by converting data byte offsets to instruction indices offsets
// this is to make it easier to edit the XML
if (unresolvedJumps.TryGetValue(loc, out var jumps))
{
foreach (var jump in jumps)
{
// relative offset between jump and target instructions
jump.InstructionOffset = instrIndex - jump.InstructionOffset;
insts[i] = instr;
}
unresolvedJumps.Remove(loc);
}
if (instr is ExpressionInstrJump j)
{
j.InstructionOffset = instrIndex;
var targetLoc = (s1.Position + j.Data1Offset, s2.Position + j.Data2Offset, s3.Position + j.Data3Offset);
if (!unresolvedJumps.TryGetValue(targetLoc, out jumps))
{
jumps = new List<ExpressionInstrJump>();
unresolvedJumps[targetLoc] = jumps;
}
jumps.Add(j);
}
}
// special case to resolve jumps to the end of the instructions list since we don't store the finish marker instruction
var endLoc = (s1.Position, s2.Position, s3.Position - 1);
if (unresolvedJumps.TryGetValue(endLoc, out var endJumps))
{
foreach (var jump in endJumps)
{
jump.InstructionOffset = (uint)instructions.Count - jump.InstructionOffset;
}
unresolvedJumps.Remove(endLoc);
}
if ((r1.Length - r1.Position) != 0)
{ }//no hit
if ((r2.Length - r2.Position) != 0)
{ }//no hit
if ((r3.Length - r3.Position) != 0)
{ }//no hit
// there should be no unresolved jumps at this point
if (unresolvedJumps.Count != 0)
{ }//no hit
Instructions = instructions.ToArray();
Instructions = insts;
}
public void WriteInstructions()
@ -735,10 +613,12 @@ namespace CodeWalker.GameFiles
foreach (var instr in Instructions)
{
instr.Offset1 = (int)w1.Position;
instr.Offset2 = (int)w2.Position;
instr.Index = (int)w3.Position;
w3.Write((byte)instr.Type);
instr.Write(w1, w2);
}
w3.Write((byte)0);
Data1 = s1.ToArray();
Data2 = s2.ToArray();
@ -753,6 +633,7 @@ namespace CodeWalker.GameFiles
{
switch (type)
{
case ExpressionInstrType.End:
case ExpressionInstrType.Pop:
case ExpressionInstrType.Dup:
case ExpressionInstrType.Push0:
@ -838,7 +719,7 @@ namespace CodeWalker.GameFiles
public enum ExpressionInstrType : byte
{
None = 0,
End = 0,
Pop = 0x01,
Dup = 0x02,
Push0 = 0x03,
@ -903,6 +784,9 @@ namespace CodeWalker.GameFiles
[TC(typeof(EXP))] public abstract class ExpressionInstrBase
{
public ExpressionInstrType Type { get; set; }
public int Offset1 { get; set; }
public int Offset2 { get; set; }
public int Index { get; set; }
public virtual void Read(DataReader r1, DataReader r2)
{ }
@ -922,12 +806,22 @@ namespace CodeWalker.GameFiles
{ }
[TC(typeof(EXP))] public class ExpressionInstrBlend : ExpressionInstrBase
{
public struct SourceInfo
{
public ushort TrackIndex;
public ushort ComponentOffset;
public override string ToString()
{
return $"{TrackIndex} : {ComponentOffset}";
}
}
[TC(typeof(EXP))] public class SourceComponent : IMetaXmlItem
{
public float[] Weights { get; set; }
public float[] Offsets { get; set; }
public float[] Thresholds { get; set; }
public SourceComponent() { }
public SourceComponent(uint numSourceWeights)
{
Weights = new float[numSourceWeights];
@ -941,25 +835,59 @@ namespace CodeWalker.GameFiles
YedXml.WriteRawArray(sb, Offsets, indent, "Offsets", "", FloatUtil.ToString, 32);
YedXml.WriteRawArray(sb, Thresholds, indent, "Thresholds", "", FloatUtil.ToString, 32);
}
public void ReadXml(XmlNode node)
{
throw new NotImplementedException();
if (node == null) return;
Weights = Xml.GetChildRawFloatArray(node, "Weights");
Offsets = Xml.GetChildRawFloatArray(node, "Offsets");
Thresholds = Xml.GetChildRawFloatArray(node, "Thresholds");
}
}
[TC(typeof(EXP))] public class Source : IMetaXmlItem
{
public ushort TrackIndex { get; set; }
public ushort ComponentOffset { get; set; }
public SourceInfo Info { get; set; }
public SourceComponent X { get; set; }
public SourceComponent Y { get; set; }
public SourceComponent Z { get; set; }
public Source()
{ }
public Source(SourceInfo info, uint numSourceWeights, int index, Vector4[] values)
{
Info = info;
X = new SourceComponent(numSourceWeights);
Y = new SourceComponent(numSourceWeights);
Z = new SourceComponent(numSourceWeights);
var j = index / 4;
var k = index % 4;
var v = j * (6 + 9 * (int)(numSourceWeights - 1));
X.Weights[0] = values[v + 0][k];
Y.Weights[0] = values[v + 1][k];
Z.Weights[0] = values[v + 2][k];
X.Offsets[0] = values[v + 3][k];
Y.Offsets[0] = values[v + 4][k];
Z.Offsets[0] = values[v + 5][k];
for (int n = 1; n < numSourceWeights; n++)
{
var m = n - 1;
var b = v + 6 + (9 * m);
X.Thresholds[m] = values[b + 0][k];
Y.Thresholds[m] = values[b + 1][k];
Z.Thresholds[m] = values[b + 2][k];
X.Weights[n] = values[b + 3][k];
Y.Weights[n] = values[b + 4][k];
Z.Weights[n] = values[b + 5][k];
X.Offsets[n] = values[b + 6][k];
Y.Offsets[n] = values[b + 7][k];
Z.Offsets[n] = values[b + 8][k];
}
}
public void WriteXml(StringBuilder sb, int indent)
{
YedXml.ValueTag(sb, indent, "TrackIndex", TrackIndex.ToString());
YedXml.ValueTag(sb, indent, "ComponentIndex", (ComponentOffset / 4).ToString());
YedXml.ValueTag(sb, indent, "TrackIndex", Info.TrackIndex.ToString());
YedXml.ValueTag(sb, indent, "ComponentIndex", (Info.ComponentOffset / 4).ToString());
YedXml.OpenTag(sb, indent, "X");
X.WriteXml(sb, indent + 1);
YedXml.CloseTag(sb, indent, "X");
@ -970,25 +898,74 @@ namespace CodeWalker.GameFiles
Z.WriteXml(sb, indent + 1);
YedXml.CloseTag(sb, indent, "Z");
}
public void ReadXml(XmlNode node)
{
throw new NotImplementedException();
var info = new SourceInfo();
info.TrackIndex = (ushort)Xml.GetChildUIntAttribute(node, "TrackIndex", "value");
info.ComponentOffset = (ushort)(Xml.GetChildUIntAttribute(node, "ComponentIndex", "value") * 4);
Info = info;
X = new SourceComponent();
X.ReadXml(node.SelectSingleNode("X"));
Y = new SourceComponent();
Y.ReadXml(node.SelectSingleNode("Y"));
Z = new SourceComponent();
Z.ReadXml(node.SelectSingleNode("Z"));
}
public void UpdateValues(uint numSourceWeights, int index, Vector4[] values)
{
if (X == null) return;
if (Y == null) return;
if (Z == null) return;
if (X.Weights?.Length < numSourceWeights) return;
if (Y.Weights?.Length < numSourceWeights) return;
if (Z.Weights?.Length < numSourceWeights) return;
if (X.Offsets?.Length < numSourceWeights) return;
if (Y.Offsets?.Length < numSourceWeights) return;
if (Z.Offsets?.Length < numSourceWeights) return;
if (X.Thresholds?.Length < (numSourceWeights - 1)) return;
if (Y.Thresholds?.Length < (numSourceWeights - 1)) return;
if (Z.Thresholds?.Length < (numSourceWeights - 1)) return;
var j = index / 4;
var k = index % 4;
var v = j * (6 + 9 * (int)(numSourceWeights - 1));
values[v + 0][k] = X.Weights[0];
values[v + 1][k] = Y.Weights[0];
values[v + 2][k] = Z.Weights[0];
values[v + 3][k] = X.Offsets[0];
values[v + 4][k] = Y.Offsets[0];
values[v + 5][k] = Z.Offsets[0];
for (int n = 1; n < numSourceWeights; n++)
{
var m = n - 1;
var b = v + 6 + (9 * m);
values[b + 0][k] = X.Thresholds[m];
values[b + 1][k] = Y.Thresholds[m];
values[b + 2][k] = Z.Thresholds[m];
values[b + 3][k] = X.Weights[n];
values[b + 4][k] = Y.Weights[n];
values[b + 5][k] = Z.Weights[n];
values[b + 6][k] = X.Offsets[n];
values[b + 7][k] = Y.Offsets[n];
values[b + 8][k] = Z.Offsets[n];
}
}
public override string ToString()
{
return "TODO"; // TODO
return $"TrackIndex {Info.TrackIndex}, ComponentIndex {Info.ComponentOffset / 4} (offset {Info.ComponentOffset})";
}
}
public uint ByteLength { get; set; } //updated automatically
public uint SourceCount { get; set; } //updated automatically
public uint NumSourceWeights { get; set; }
public uint SourceCount { get; set; } //updated automatically //0-84+, multiple of 4
public uint NumSourceWeights { get; set; }//1-4
public uint Unk1 { get; set; } // 0x00000000
public Source[] Sources { get; set; }
public SourceInfo[] SourceInfos { get; set; }
public Vector4[] Values { get; set; }
public uint RequiredValueCount => (SourceCount / 4) * (6 + ((NumSourceWeights - 1) * 9));
public override void Read(DataReader r1, DataReader r2)
{
ByteLength = r1.ReadUInt32();
@ -996,106 +973,23 @@ namespace CodeWalker.GameFiles
NumSourceWeights = r1.ReadUInt32();
Unk1 = r1.ReadUInt32();
Sources = new Source[SourceCount];
SourceInfos = new SourceInfo[SourceCount];
for (int i = 0; i < SourceCount; i++)
{
var s = new Source();
var s = new SourceInfo();
s.TrackIndex = r1.ReadUInt16();
s.ComponentOffset = r1.ReadUInt16();
s.X = new SourceComponent(NumSourceWeights);
s.Y = new SourceComponent(NumSourceWeights);
s.Z = new SourceComponent(NumSourceWeights);
Sources[i] = s;
SourceInfos[i] = s;
}
// TODO: rename
var numIters = SourceCount / 4;
var numSubpasses = NumSourceWeights - 1;
var numValues = (numIters * 6) + (numIters * numSubpasses * 9);
Values = new Vector4[numValues];
for (int i = 0; i < numValues; i++)
Values = new Vector4[RequiredValueCount];
for (int i = 0; i < Values.Length; i++)
{
Values[i] = r1.ReadVector4();
}
switch (SourceCount)
{
case 0:
case 4:
case 8:
case 12:
case 20:
case 24:
case 48:
case 52:
case 76:
case 32:
case 16:
case 40:
case 44:
case 60:
case 72:
case 56:
case 28:
case 68:
break;
default:
break; //no hit
}
switch (NumSourceWeights)
{
case 1: break;
case 2: break;
case 3: break;
case 4: break;
default:
break; //no hit
}
if (Unk1 != 0)
{
} //no hit
// organize data into more human-readable layout
// the file layout is optimized for vectorized operations
for (int i = 0; i < (Sources.Length / 4); i++)
{
var it = i * 4;
int v = i * 6 + (i * (int)(NumSourceWeights - 1) * 9);
for (int k = 0; k < 4; k++)
{
Sources[it + k].X.Weights[0] = Values[v + 0][k];
Sources[it + k].Y.Weights[0] = Values[v + 1][k];
Sources[it + k].Z.Weights[0] = Values[v + 2][k];
Sources[it + k].X.Offsets[0] = Values[v + 3][k];
Sources[it + k].Y.Offsets[0] = Values[v + 4][k];
Sources[it + k].Z.Offsets[0] = Values[v + 5][k];
for (int n = 1; n < NumSourceWeights; n++)
{
int b = v + 6 + (n - 1) * 9;
Sources[it + k].X.Thresholds[n - 1] = Values[b + 0][k];
Sources[it + k].Y.Thresholds[n - 1] = Values[b + 1][k];
Sources[it + k].Z.Thresholds[n - 1] = Values[b + 2][k];
Sources[it + k].X.Weights[n] = Values[b + 3][k];
Sources[it + k].Y.Weights[n] = Values[b + 4][k];
Sources[it + k].Z.Weights[n] = Values[b + 5][k];
Sources[it + k].X.Offsets[n] = Values[b + 6][k];
Sources[it + k].Y.Offsets[n] = Values[b + 7][k];
Sources[it + k].Z.Offsets[n] = Values[b + 8][k];
}
}
}
}
public override void Write(DataWriter w1, DataWriter w2)
{
// TODO
SourceCount = (uint)(Sources?.Length ?? 0);
SourceCount = (uint)(SourceInfos?.Length ?? 0);
NumSourceWeights = Math.Max(NumSourceWeights, 1);
var valcnt = (NumSourceWeights - 1) * 9 + 6;
var hlen = SourceCount * 4 + 16;
@ -1107,32 +1001,43 @@ namespace CodeWalker.GameFiles
w1.Write(NumSourceWeights);
w1.Write(Unk1);
// TODO
for (int i = 0; i < SourceCount; i++)
{
// Sources[i].Write(w1);
var si = SourceInfos[i];
w1.Write(si.TrackIndex);
w1.Write(si.ComponentOffset);
}
for (int i = 0; i < Values.Length; i++)
{
w1.Write(Values[i]);
}
// TODO
// for (int n = 0; n < valcnt; n++)
// {
// for (int i = 0; i < ItemCount; i++)
// {
// var vals = Items[i].Values;
// w1.Write((n < (vals?.Length ?? 0)) ? vals[n] : 0.0f);
// }
// }
}
public override void WriteXml(StringBuilder sb, int indent)
{
YedXml.ValueTag(sb, indent, "NumSourceWeights", NumSourceWeights.ToString());
YedXml.WriteItemArray(sb, Sources, indent, "Sources");
// organize data into more human-readable layout
// the file layout is optimized for vectorized operations
var sources = new Source[SourceCount];
for (int i = 0; i < SourceCount; i++)
{
sources[i] = new Source(SourceInfos[i], NumSourceWeights, i, Values);
}
YedXml.ValueTag(sb, indent, "NumSourceWeights", NumSourceWeights.ToString());
YedXml.WriteItemArray(sb, sources, indent, "Sources");
}
public override void ReadXml(XmlNode node)
{
NumSourceWeights = Xml.GetChildUIntAttribute(node, "NumSourceWeights");
Sources = XmlMeta.ReadItemArray<Source>(node, "Sources");
NumSourceWeights = Math.Max(Xml.GetChildUIntAttribute(node, "NumSourceWeights"), 1);
var sources = XmlMeta.ReadItemArray<Source>(node, "Sources");
SourceCount = (uint)(sources?.Length ?? 0);
SourceInfos = new SourceInfo[SourceCount];
Values = new Vector4[RequiredValueCount];
for (int i = 0; i < SourceCount; i++)
{
var s = sources[i];
SourceInfos[i] = s.Info;
s.UpdateValues(NumSourceWeights, i, Values);
}
}
public override string ToString()
@ -1140,7 +1045,6 @@ namespace CodeWalker.GameFiles
return base.ToString() + " - " + SourceCount + ", " + NumSourceWeights;
}
}
[TC(typeof(EXP))] public class ExpressionInstrBone : ExpressionInstrBase
{
public ushort TrackIndex { get; set; } //index of the BoneTag in the Expression.BoneTracks array
@ -1179,7 +1083,7 @@ namespace CodeWalker.GameFiles
}
public override void ReadXml(XmlNode node)
{
TrackIndex = (ushort)Xml.GetChildUIntAttribute(node, "BoneTrack", "value");
TrackIndex = (ushort)Xml.GetChildUIntAttribute(node, "TrackIndex", "value");
BoneId = (ushort)Xml.GetChildUIntAttribute(node, "BoneId", "value");
Track = (byte)Xml.GetChildUIntAttribute(node, "Track", "value");
Format = (byte)Xml.GetChildUIntAttribute(node, "Format", "value");
@ -1223,12 +1127,9 @@ namespace CodeWalker.GameFiles
}
[TC(typeof(EXP))] public class ExpressionInstrJump : ExpressionInstrBase
{
// note: unsigned so can only jump forwards
public uint Data1Offset { get; set; }
public uint Data1Offset { get; set; } // note: unsigned so can only jump forwards
public uint Data2Offset { get; set; }
public uint Data3Offset { get; set; }
public uint InstructionOffset { get; set; }
public uint Data3Offset { get; set; } //instruction offset
public override void Read(DataReader r1, DataReader r2)
{
@ -1244,18 +1145,11 @@ namespace CodeWalker.GameFiles
}
public override void WriteXml(StringBuilder sb, int indent)
{
YedXml.ValueTag(sb, indent, "InstructionOffset", InstructionOffset.ToString());
// YedXml.ValueTag(sb, indent, "Data1Offset", Data1Offset.ToString());
// YedXml.ValueTag(sb, indent, "Data2Offset", Data2Offset.ToString());
// YedXml.ValueTag(sb, indent, "Data3Offset", Data3Offset.ToString());
YedXml.ValueTag(sb, indent, "InstructionOffset", Data3Offset.ToString());
}
public override void ReadXml(XmlNode node)
{
// TODO: calculate data offsets
InstructionOffset = Xml.GetChildUIntAttribute(node, "InstructionOffset");
// Data1Offset = Xml.GetChildUIntAttribute(node, "Data1Offset");
// Data2Offset = Xml.GetChildUIntAttribute(node, "Data2Offset");
// Data3Offset = Xml.GetChildUIntAttribute(node, "Data3Offset");
Data3Offset = Xml.GetChildUIntAttribute(node, "InstructionOffset");
}
public override string ToString()

View File

@ -343,11 +343,11 @@ namespace CodeWalker.GameFiles
//BaseSize = 0x2000 << BaseShift (max BaseShift = 0xF)
//then allocate page counts for the page sizes:
//allows for 5 page sizes, each double the size of the previous, with max counts 0x7F, 0x3F, 0xF, 3, 1
//also allows for 4 tail pages, each half the size of the previous, only one page of each size
//also allows for 4 tail pages, each half the size of the previous, only one page of each size [TODO?]
var sys = (basePosition == 0x50000000);
var maxPageSizeMult = 16L;//the biggest page is 16x the base page size.
var maxPageSize = (0x2000 << 0xF) * maxPageSizeMult; //this is the size of the biggest possible page [256MB!]
var maxPageSize = (0x2000 << 0xF) * maxPageSizeMult; //this is the size of the biggest possible page [4GB!]
var maxBlockSize = 0L;
var minBlockSize = (blocks.Count == 0) ? 0 : maxPageSize;
foreach (var block in blocks)
@ -389,7 +389,6 @@ namespace CodeWalker.GameFiles
pageSizes[i] = null;
}
var testOk = true;
var largestPageSizeI = 0;
var largestPageSize = baseSize;
while (largestPageSize < maxBlockSize)
@ -457,6 +456,7 @@ namespace CodeWalker.GameFiles
}
}
var testOk = true;
var totalPageCount = 0u;
for (int i = 0; i < 5; i++)
{