From 520eee6f81f50a3e738cc982207cde62e3e4e532 Mon Sep 17 00:00:00 2001 From: dexy Date: Wed, 30 Mar 2022 20:13:01 +1100 Subject: [PATCH] YPDB/XML conversion --- .../GameFiles/FileTypes/YpdbFile.cs | 187 +++++++++++++++--- CodeWalker.Core/GameFiles/GameFileCache.cs | 7 +- .../GameFiles/MetaTypes/MetaXml.cs | 12 ++ .../GameFiles/MetaTypes/XmlMeta.cs | 13 ++ CodeWalker/ExploreForm.cs | 6 +- CodeWalker/Forms/MetaForm.cs | 14 ++ 6 files changed, 212 insertions(+), 27 deletions(-) diff --git a/CodeWalker.Core/GameFiles/FileTypes/YpdbFile.cs b/CodeWalker.Core/GameFiles/FileTypes/YpdbFile.cs index 0405714..064dfca 100644 --- a/CodeWalker.Core/GameFiles/FileTypes/YpdbFile.cs +++ b/CodeWalker.Core/GameFiles/FileTypes/YpdbFile.cs @@ -2,6 +2,8 @@ using System.IO; using TC = System.ComponentModel.TypeConverterAttribute; using EXP = System.ComponentModel.ExpandableObjectConverter; +using System.Text; +using System.Xml; namespace CodeWalker.GameFiles { @@ -137,25 +139,66 @@ namespace CodeWalker.GameFiles w.Write(Signature); } + + + public void WriteXml(StringBuilder sb, int indent) + { + //YpdbXml.ValueTag(sb, indent, "SerializerVersion", SerializerVersion.ToString()); + //YpdbXml.ValueTag(sb, indent, "PoseMatcherVersion", PoseMatcherVersion.ToString()); + YpdbXml.ValueTag(sb, indent, "Signature", Signature.ToString()); + //YpdbXml.ValueTag(sb, indent, "Unk7", FloatUtil.ToString(Unk7)); + //YpdbXml.ValueTag(sb, indent, "Unk8", Unk8.ToString()); + YpdbXml.WriteRawArray(sb, BoneTags, indent, "BoneTags", ""); + WeightSet?.WriteXml(sb, indent); + YpdbXml.WriteItemArray(sb, Samples, indent, "Samples"); + } + public void ReadXml(XmlNode node) + { + SerializerVersion = 2;// Xml.GetChildIntAttribute(node, "SerializerVersion"); + PoseMatcherVersion = 0;// Xml.GetChildIntAttribute(node, "PoseMatcherVersion"); + Signature = Xml.GetChildUIntAttribute(node, "Signature"); + Unk7 = 0.033333f;// Xml.GetChildFloatAttribute(node, "Unk7"); + Unk8 = 1;// Xml.GetChildIntAttribute(node, "Unk8"); + BoneTags = Xml.GetChildRawUshortArray(node, "BoneTags"); + BoneTagsCount = (BoneTags?.Length ?? 0); + WeightSet = new PoseMatcherWeightSet(node); + Samples = XmlMeta.ReadItemArray(node, "Samples"); + SamplesCount = (Samples?.Length ?? 0); + } } - [TC(typeof(EXP))] - public class PoseMatcherMatchSample + [TC(typeof(EXP))] public class PoseMatcherMatchSample : IMetaXmlItem { // rage::crPoseMatcherData::MatchSample public MetaHash ClipSet { get; set; } // from clip_sets.ymt/xml public MetaHash Clip { get; set; } - public float Unk3 { get; set; } + public float Offset { get; set; }//probably time offset, allows for multiple samples per clip public PoseMatcherPointCloud PointCloud { get; set; } + public PoseMatcherMatchSample() + { } public PoseMatcherMatchSample(DataReader r) { ClipSet = r.ReadUInt32(); Clip = r.ReadUInt32(); - Unk3 = r.ReadSingle(); + Offset = r.ReadSingle(); PointCloud = new PoseMatcherPointCloud(r); + + switch (Offset) + { + case 0: + case 0.266f: + case 0.576f: + case 0.366933f: + case 0.599466f: + case 0.506333f: + case 1.09f: + break; + default: + break; + } } public void Write(DataWriter w) @@ -163,29 +206,56 @@ namespace CodeWalker.GameFiles w.Write(ClipSet); w.Write(Clip); - w.Write(Unk3); + w.Write(Offset); PointCloud.Write(w); } + public void WriteXml(StringBuilder sb, int indent) + { + YpdbXml.StringTag(sb, indent, "ClipSet", YpdbXml.HashString(ClipSet)); + YpdbXml.StringTag(sb, indent, "Clip", YpdbXml.HashString(Clip)); + YpdbXml.ValueTag(sb, indent, "Offset", FloatUtil.ToString(Offset)); + PointCloud?.WriteXml(sb, indent); + } + public void ReadXml(XmlNode node) + { + ClipSet = XmlMeta.GetHash(Xml.GetChildInnerText(node, "ClipSet")); + Clip = XmlMeta.GetHash(Xml.GetChildInnerText(node, "Clip")); + Offset = Xml.GetChildFloatAttribute(node, "Offset"); + PointCloud = new PoseMatcherPointCloud(node); + } + public override string ToString() { return $"{ClipSet}, {Clip}"; } } - [TC(typeof(EXP))] - public class PoseMatcherPointCloud + [TC(typeof(EXP))] public class PoseMatcherPointCloud { // rage::crpmPointCloud public int PointsCount { get; set; } public Vector3[] Points { get; set; } - public int Unk2_Count { get; set; } // == PointsCount - public float[] Unk2_Items { get; set; } + public int WeightsCount { get; set; } // == PointsCount + public float[] Weights { get; set; } public Vector3 BoundsMin { get; set; } public Vector3 BoundsMax { get; set; } - public float Unk5 { get; set; } + public float WeightsSum { get; set; } + public PoseMatcherPointCloud(XmlNode n) + { + BoundsMin = Xml.GetChildVector3Attributes(n, "BoundsMin"); + BoundsMax = Xml.GetChildVector3Attributes(n, "BoundsMax"); + Points = Xml.GetChildRawVector3Array(n, "Points"); + PointsCount = (Points?.Length ?? 0); + Weights = Xml.GetChildRawFloatArray(n, "Weights"); + WeightsCount = (Weights?.Length ?? 0); + + var sum = 0.0f; + if (Weights != null) foreach (var v in Weights) sum += v; + WeightsSum = sum; + } public PoseMatcherPointCloud(DataReader r) { PointsCount = r.ReadInt32(); @@ -197,22 +267,27 @@ namespace CodeWalker.GameFiles Points[i] = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); } - Unk2_Count = r.ReadInt32(); - if (Unk2_Count > 0) + WeightsCount = r.ReadInt32(); + if (WeightsCount > 0) { - Unk2_Items = new float[Unk2_Count]; + Weights = new float[WeightsCount]; - for (int i = 0; i < Unk2_Count; i++) - Unk2_Items[i] = r.ReadSingle(); + for (int i = 0; i < WeightsCount; i++) + Weights[i] = r.ReadSingle(); } BoundsMin = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); BoundsMax = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); - Unk5 = r.ReadSingle(); + WeightsSum = r.ReadSingle(); - if (PointsCount != Unk2_Count) + if (PointsCount != WeightsCount) { } // no hit + + //var sum = 0.0f; + //if (Weights != null) foreach (var v in Weights) sum += v; + //if (WeightsSum != sum) + //{ } //no hit } public void Write(DataWriter w) @@ -224,22 +299,29 @@ namespace CodeWalker.GameFiles w.Write(point); } - w.Write(Unk2_Count); - if (Unk2_Count > 0) + w.Write(WeightsCount); + if (WeightsCount > 0) { - foreach (var entry in Unk2_Items) + foreach (var entry in Weights) w.Write(entry); } w.Write(BoundsMin); w.Write(BoundsMax); - w.Write(Unk5); + w.Write(WeightsSum); + } + + public void WriteXml(StringBuilder sb, int indent) + { + YpdbXml.SelfClosingTag(sb, indent, "BoundsMin " + FloatUtil.GetVector3XmlString(BoundsMin)); + YpdbXml.SelfClosingTag(sb, indent, "BoundsMax " + FloatUtil.GetVector3XmlString(BoundsMax)); + YpdbXml.WriteRawArray(sb, Points, indent, "Points", "", YpdbXml.FormatVector3, 1); + YpdbXml.WriteRawArray(sb, Weights, indent, "Weights", "", FloatUtil.ToString); } } - [TC(typeof(EXP))] - public class PoseMatcherWeightSet + [TC(typeof(EXP))] public class PoseMatcherWeightSet { // rage::crWeightSet public int WeightsCount { get; set; } @@ -256,6 +338,11 @@ namespace CodeWalker.GameFiles Weights[i] = r.ReadSingle(); } } + public PoseMatcherWeightSet(XmlNode n) + { + Weights = Xml.GetChildRawFloatArray(n, "Weights"); + WeightsCount = (Weights?.Length ?? 0); + } public void Write(DataWriter w) { @@ -266,5 +353,59 @@ namespace CodeWalker.GameFiles w.Write(weight); } } + + public void WriteXml(StringBuilder sb, int indent) + { + YpdbXml.WriteRawArray(sb, Weights, indent, "Weights", "", FloatUtil.ToString); + } } + + + + + + public class YpdbXml : MetaXmlBase + { + + public static string GetXml(YpdbFile ypdb) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine(XmlHeader); + + if ((ypdb != null) && (ypdb.WeightSet != null)) + { + var name = "PoseMatcher"; + + OpenTag(sb, 0, name); + + ypdb.WriteXml(sb, 1); + + CloseTag(sb, 0, name); + } + + return sb.ToString(); + } + + } + + public class XmlYpdb + { + + public static YpdbFile GetYpdb(string xml) + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + return GetYpdb(doc); + } + + public static YpdbFile GetYpdb(XmlDocument doc) + { + YpdbFile ypdb = new YpdbFile(); + ypdb.ReadXml(doc.DocumentElement); + return ypdb; + } + + } + + } diff --git a/CodeWalker.Core/GameFiles/GameFileCache.cs b/CodeWalker.Core/GameFiles/GameFileCache.cs index 75132b3..b00785a 100644 --- a/CodeWalker.Core/GameFiles/GameFileCache.cs +++ b/CodeWalker.Core/GameFiles/GameFileCache.cs @@ -4546,7 +4546,12 @@ namespace CodeWalker.GameFiles if (ypdb != null) { var odata = entry.File.ExtractFile(entry as RpfFileEntry); - var ndata = ypdb.Save(); + //var ndata = ypdb.Save(); + + var xml = YpdbXml.GetXml(ypdb); + var ypdb2 = XmlYpdb.GetYpdb(xml); + var ndata = ypdb2.Save(); + if (ndata.Length == odata.Length) { for (int i = 0; i < ndata.Length; i++) diff --git a/CodeWalker.Core/GameFiles/MetaTypes/MetaXml.cs b/CodeWalker.Core/GameFiles/MetaTypes/MetaXml.cs index 47926c2..32dc025 100644 --- a/CodeWalker.Core/GameFiles/MetaTypes/MetaXml.cs +++ b/CodeWalker.Core/GameFiles/MetaTypes/MetaXml.cs @@ -122,6 +122,11 @@ namespace CodeWalker.GameFiles YvrFile yvr = RpfFile.GetFile(e, data); return GetXml(yvr, out filename); } + else if (fnl.EndsWith(".ypdb")) + { + YpdbFile ypdb = RpfFile.GetFile(e, data); + return GetXml(ypdb, out filename); + } else if (fnl.EndsWith(".awc")) { AwcFile awc = RpfFile.GetFile(e, data); @@ -274,6 +279,12 @@ namespace CodeWalker.GameFiles filename = fn + ".xml"; return YvrXml.GetXml(yvr); } + public static string GetXml(YpdbFile ypdb, out string filename) + { + var fn = (ypdb?.Name) ?? ""; + filename = fn + ".xml"; + return YpdbXml.GetXml(ypdb); + } public static string GetXml(AwcFile awc, out string filename, string outputfolder) { var fn = (awc?.Name) ?? ""; @@ -2207,6 +2218,7 @@ namespace CodeWalker.GameFiles Yvr = 18, Awc = 19, Heightmap = 20, + Ypdb = 21, } } diff --git a/CodeWalker.Core/GameFiles/MetaTypes/XmlMeta.cs b/CodeWalker.Core/GameFiles/MetaTypes/XmlMeta.cs index ae4cfd4..54b6512 100644 --- a/CodeWalker.Core/GameFiles/MetaTypes/XmlMeta.cs +++ b/CodeWalker.Core/GameFiles/MetaTypes/XmlMeta.cs @@ -55,6 +55,8 @@ namespace CodeWalker.GameFiles return GetCacheFileData(doc); case MetaFormat.Heightmap: return GetHeightmapData(doc); + case MetaFormat.Ypdb: + return GetYpdbData(doc); } return null; } @@ -178,6 +180,12 @@ namespace CodeWalker.GameFiles if (hmf.MaxHeights == null) return null; return hmf.Save(); } + public static byte[] GetYpdbData(XmlDocument doc) + { + var ypdb = XmlYpdb.GetYpdb(doc); + if (ypdb.WeightSet == null) return null; + return ypdb.Save(); + } public static string GetXMLFormatName(MetaFormat mformat) @@ -204,6 +212,7 @@ namespace CodeWalker.GameFiles case MetaFormat.Awc: return "AWC XML"; case MetaFormat.CacheFile: return "CacheFile XML"; case MetaFormat.Heightmap: return "Heightmap XML"; + case MetaFormat.Ypdb: return "YPDB XML"; default: return "XML"; } } @@ -294,6 +303,10 @@ namespace CodeWalker.GameFiles { mformat = MetaFormat.Heightmap; } + if (fnamel.EndsWith(".ypdb.xml")) + { + mformat = MetaFormat.Ypdb; + } return mformat; } diff --git a/CodeWalker/ExploreForm.cs b/CodeWalker/ExploreForm.cs index 07752ec..241d3f6 100644 --- a/CodeWalker/ExploreForm.cs +++ b/CodeWalker/ExploreForm.cs @@ -309,7 +309,7 @@ namespace CodeWalker InitFileType(".awc", "Audio Wave Container", 22, FileTypeAction.ViewAwc, true); InitFileType(".rel", "Audio Data (REL)", 23, FileTypeAction.ViewRel, true); InitFileType(".nametable", "Name Table", 5, FileTypeAction.ViewNametable); - InitFileType(".ypdb", "Pose Matcher Database", 9, FileTypeAction.ViewYpdb); + InitFileType(".ypdb", "Pose Matcher Database", 9, FileTypeAction.ViewYpdb, true); InitSubFileType(".dat", "cache_y.dat", "Cache File", 6, FileTypeAction.ViewCacheDat, true); InitSubFileType(".dat", "heightmap.dat", "Heightmap", 6, FileTypeAction.ViewHeightmap, true); @@ -1813,9 +1813,9 @@ namespace CodeWalker private void ViewYpdb(string name, string path, byte[] data, RpfFileEntry e) { var ypdb = RpfFile.GetFile(e, data); - GenericForm f = new GenericForm(this); + MetaForm f = new MetaForm(this); f.Show(); - f.LoadFile(ypdb, ypdb.RpfFileEntry); + f.LoadMeta(ypdb); } private RpfFileEntry CreateFileEntry(string name, string path, ref byte[] data) diff --git a/CodeWalker/Forms/MetaForm.cs b/CodeWalker/Forms/MetaForm.cs index 2f6a059..8fbc6f6 100644 --- a/CodeWalker/Forms/MetaForm.cs +++ b/CodeWalker/Forms/MetaForm.cs @@ -374,6 +374,20 @@ namespace CodeWalker.Forms metaFormat = MetaFormat.Heightmap; } } + public void LoadMeta(YpdbFile ypdb) + { + var fn = ((ypdb?.RpfFileEntry?.Name) ?? "") + ".xml"; + Xml = MetaXml.GetXml(ypdb, out fn); + FileName = fn; + RawPropertyGrid.SelectedObject = ypdb; + rpfFileEntry = ypdb?.RpfFileEntry; + modified = false; + metaFormat = MetaFormat.XML; + if (ypdb?.RpfFileEntry != null) + { + metaFormat = MetaFormat.Ypdb; + } + }