diff --git a/CodeWalker.Core/GameFiles/GameFileCache.cs b/CodeWalker.Core/GameFiles/GameFileCache.cs index 4a1ce3f..b4229dd 100644 --- a/CodeWalker.Core/GameFiles/GameFileCache.cs +++ b/CodeWalker.Core/GameFiles/GameFileCache.cs @@ -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(); 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,24 +3460,25 @@ namespace CodeWalker.GameFiles YedFile yed = new YedFile(rfe); RpfMan.LoadFile(yed, rfe); - var xml = YedXml.GetXml(yed); - var yed2 = XmlYed.GetYed(xml); - var data2 = yed2.Save(); - var yed3 = new YedFile(); - RpfFile.LoadResourceFile(yed3, data2, 25);//full roundtrip - var xml2 = YedXml.GetXml(yed3); - if (xml != xml2) - { } + if (xmltest) + { + var xml = YedXml.GetXml(yed); + var yed2 = XmlYed.GetYed(xml); + var data2 = yed2.Save(); + var yed3 = new YedFile(); + 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); + //} } } diff --git a/CodeWalker.Core/GameFiles/Resources/Expression.cs b/CodeWalker.Core/GameFiles/Resources/Expression.cs index 2770581..836995d 100644 --- a/CodeWalker.Core/GameFiles/Resources/Expression.cs +++ b/CodeWalker.Core/GameFiles/Resources/Expression.cs @@ -38,11 +38,8 @@ namespace CodeWalker.GameFiles [TC(typeof(EXP))] public class ExpressionDictionary : ResourceFileBase { - // pgDictionaryBase - // pgDictionary + // pgDictionary : 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 ExpressionNameHashes { get; set; } public ResourcePointerList64 Expressions { get; set; } - public Dictionary 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>(); - this.Expressions = reader.ReadBlock>(); - + Unknown_10h = reader.ReadUInt32(); + Unknown_14h = reader.ReadUInt32(); + Unknown_18h = reader.ReadUInt32(); + Unknown_1Ch = reader.ReadUInt32(); + ExpressionNameHashes = reader.ReadBlock>(); + Expressions = reader.ReadBlock>(); 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>(); - this.Tracks = reader.ReadBlock>(); - this.Springs = reader.ReadBlock>(); - this.Variables = reader.ReadBlock>(); - 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>(); + Tracks = reader.ReadBlock>(); + Springs = reader.ReadBlock>(); + Variables = reader.ReadBlock>(); + 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( - this.NamePointer // offset - ); + Name = reader.ReadBlockAt(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(); @@ -471,7 +383,6 @@ namespace CodeWalker.GameFiles Springs = new ResourceSimpleList64(); Springs.data_items = springs.ToArray(); } - public void UpdateVariables() { var dict = new Dictionary(); @@ -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(); 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>(); - var instructions = new List(); - while (s3.Position < s3.Length) + //dexy: removed unresolvedjumps stuff from here as it should all resolve to jump.Data3Offset+1 + + for (int i = 0; i < insts.Length; i++) { - var loc = (s1.Position, s2.Position, s3.Position); - - var type = (ExpressionInstrType)r3.ReadByte(); - if (type == ExpressionInstrType.None) + var type = (ExpressionInstrType)Data3[i]; + if (type == ExpressionInstrType.End) { - if (s3.Position != s3.Length) + 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; - } - 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(); - unresolvedJumps[targetLoc] = jumps; - } - jumps.Add(j); - } + insts[i] = instr; } - // 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(node, "Sources"); + NumSourceWeights = Math.Max(Xml.GetChildUIntAttribute(node, "NumSourceWeights"), 1); + var sources = XmlMeta.ReadItemArray(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() diff --git a/CodeWalker.Core/GameFiles/Resources/ResourceBuilder.cs b/CodeWalker.Core/GameFiles/Resources/ResourceBuilder.cs index fce51fc..dd61b98 100644 --- a/CodeWalker.Core/GameFiles/Resources/ResourceBuilder.cs +++ b/CodeWalker.Core/GameFiles/Resources/ResourceBuilder.cs @@ -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++) {