YPDB/XML conversion

This commit is contained in:
dexy 2022-03-30 20:13:01 +11:00
parent 12750ff595
commit 520eee6f81
6 changed files with 212 additions and 27 deletions

View File

@ -2,6 +2,8 @@
using System.IO; using System.IO;
using TC = System.ComponentModel.TypeConverterAttribute; using TC = System.ComponentModel.TypeConverterAttribute;
using EXP = System.ComponentModel.ExpandableObjectConverter; using EXP = System.ComponentModel.ExpandableObjectConverter;
using System.Text;
using System.Xml;
namespace CodeWalker.GameFiles namespace CodeWalker.GameFiles
{ {
@ -137,25 +139,66 @@ namespace CodeWalker.GameFiles
w.Write(Signature); 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<PoseMatcherMatchSample>(node, "Samples");
SamplesCount = (Samples?.Length ?? 0);
}
} }
[TC(typeof(EXP))] [TC(typeof(EXP))] public class PoseMatcherMatchSample : IMetaXmlItem
public class PoseMatcherMatchSample
{ {
// rage::crPoseMatcherData::MatchSample // rage::crPoseMatcherData::MatchSample
public MetaHash ClipSet { get; set; } // from clip_sets.ymt/xml public MetaHash ClipSet { get; set; } // from clip_sets.ymt/xml
public MetaHash Clip { get; set; } 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 PoseMatcherPointCloud PointCloud { get; set; }
public PoseMatcherMatchSample()
{ }
public PoseMatcherMatchSample(DataReader r) public PoseMatcherMatchSample(DataReader r)
{ {
ClipSet = r.ReadUInt32(); ClipSet = r.ReadUInt32();
Clip = r.ReadUInt32(); Clip = r.ReadUInt32();
Unk3 = r.ReadSingle(); Offset = r.ReadSingle();
PointCloud = new PoseMatcherPointCloud(r); 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) public void Write(DataWriter w)
@ -163,29 +206,56 @@ namespace CodeWalker.GameFiles
w.Write(ClipSet); w.Write(ClipSet);
w.Write(Clip); w.Write(Clip);
w.Write(Unk3); w.Write(Offset);
PointCloud.Write(w); 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() public override string ToString()
{ {
return $"{ClipSet}, {Clip}"; return $"{ClipSet}, {Clip}";
} }
} }
[TC(typeof(EXP))] [TC(typeof(EXP))] public class PoseMatcherPointCloud
public class PoseMatcherPointCloud
{ {
// rage::crpmPointCloud // rage::crpmPointCloud
public int PointsCount { get; set; } public int PointsCount { get; set; }
public Vector3[] Points { get; set; } public Vector3[] Points { get; set; }
public int Unk2_Count { get; set; } // == PointsCount public int WeightsCount { get; set; } // == PointsCount
public float[] Unk2_Items { get; set; } public float[] Weights { get; set; }
public Vector3 BoundsMin { get; set; } public Vector3 BoundsMin { get; set; }
public Vector3 BoundsMax { 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) public PoseMatcherPointCloud(DataReader r)
{ {
PointsCount = r.ReadInt32(); PointsCount = r.ReadInt32();
@ -197,22 +267,27 @@ namespace CodeWalker.GameFiles
Points[i] = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); Points[i] = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
} }
Unk2_Count = r.ReadInt32(); WeightsCount = r.ReadInt32();
if (Unk2_Count > 0) if (WeightsCount > 0)
{ {
Unk2_Items = new float[Unk2_Count]; Weights = new float[WeightsCount];
for (int i = 0; i < Unk2_Count; i++) for (int i = 0; i < WeightsCount; i++)
Unk2_Items[i] = r.ReadSingle(); Weights[i] = r.ReadSingle();
} }
BoundsMin = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); BoundsMin = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
BoundsMax = 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 { } // 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) public void Write(DataWriter w)
@ -224,22 +299,29 @@ namespace CodeWalker.GameFiles
w.Write(point); w.Write(point);
} }
w.Write(Unk2_Count); w.Write(WeightsCount);
if (Unk2_Count > 0) if (WeightsCount > 0)
{ {
foreach (var entry in Unk2_Items) foreach (var entry in Weights)
w.Write(entry); w.Write(entry);
} }
w.Write(BoundsMin); w.Write(BoundsMin);
w.Write(BoundsMax); 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))] [TC(typeof(EXP))] public class PoseMatcherWeightSet
public class PoseMatcherWeightSet
{ {
// rage::crWeightSet // rage::crWeightSet
public int WeightsCount { get; set; } public int WeightsCount { get; set; }
@ -256,6 +338,11 @@ namespace CodeWalker.GameFiles
Weights[i] = r.ReadSingle(); Weights[i] = r.ReadSingle();
} }
} }
public PoseMatcherWeightSet(XmlNode n)
{
Weights = Xml.GetChildRawFloatArray(n, "Weights");
WeightsCount = (Weights?.Length ?? 0);
}
public void Write(DataWriter w) public void Write(DataWriter w)
{ {
@ -266,5 +353,59 @@ namespace CodeWalker.GameFiles
w.Write(weight); 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;
}
}
} }

View File

@ -4546,7 +4546,12 @@ namespace CodeWalker.GameFiles
if (ypdb != null) if (ypdb != null)
{ {
var odata = entry.File.ExtractFile(entry as RpfFileEntry); 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) if (ndata.Length == odata.Length)
{ {
for (int i = 0; i < ndata.Length; i++) for (int i = 0; i < ndata.Length; i++)

View File

@ -122,6 +122,11 @@ namespace CodeWalker.GameFiles
YvrFile yvr = RpfFile.GetFile<YvrFile>(e, data); YvrFile yvr = RpfFile.GetFile<YvrFile>(e, data);
return GetXml(yvr, out filename); return GetXml(yvr, out filename);
} }
else if (fnl.EndsWith(".ypdb"))
{
YpdbFile ypdb = RpfFile.GetFile<YpdbFile>(e, data);
return GetXml(ypdb, out filename);
}
else if (fnl.EndsWith(".awc")) else if (fnl.EndsWith(".awc"))
{ {
AwcFile awc = RpfFile.GetFile<AwcFile>(e, data); AwcFile awc = RpfFile.GetFile<AwcFile>(e, data);
@ -274,6 +279,12 @@ namespace CodeWalker.GameFiles
filename = fn + ".xml"; filename = fn + ".xml";
return YvrXml.GetXml(yvr); 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) public static string GetXml(AwcFile awc, out string filename, string outputfolder)
{ {
var fn = (awc?.Name) ?? ""; var fn = (awc?.Name) ?? "";
@ -2207,6 +2218,7 @@ namespace CodeWalker.GameFiles
Yvr = 18, Yvr = 18,
Awc = 19, Awc = 19,
Heightmap = 20, Heightmap = 20,
Ypdb = 21,
} }
} }

View File

@ -55,6 +55,8 @@ namespace CodeWalker.GameFiles
return GetCacheFileData(doc); return GetCacheFileData(doc);
case MetaFormat.Heightmap: case MetaFormat.Heightmap:
return GetHeightmapData(doc); return GetHeightmapData(doc);
case MetaFormat.Ypdb:
return GetYpdbData(doc);
} }
return null; return null;
} }
@ -178,6 +180,12 @@ namespace CodeWalker.GameFiles
if (hmf.MaxHeights == null) return null; if (hmf.MaxHeights == null) return null;
return hmf.Save(); 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) public static string GetXMLFormatName(MetaFormat mformat)
@ -204,6 +212,7 @@ namespace CodeWalker.GameFiles
case MetaFormat.Awc: return "AWC XML"; case MetaFormat.Awc: return "AWC XML";
case MetaFormat.CacheFile: return "CacheFile XML"; case MetaFormat.CacheFile: return "CacheFile XML";
case MetaFormat.Heightmap: return "Heightmap XML"; case MetaFormat.Heightmap: return "Heightmap XML";
case MetaFormat.Ypdb: return "YPDB XML";
default: return "XML"; default: return "XML";
} }
} }
@ -294,6 +303,10 @@ namespace CodeWalker.GameFiles
{ {
mformat = MetaFormat.Heightmap; mformat = MetaFormat.Heightmap;
} }
if (fnamel.EndsWith(".ypdb.xml"))
{
mformat = MetaFormat.Ypdb;
}
return mformat; return mformat;
} }

View File

@ -309,7 +309,7 @@ namespace CodeWalker
InitFileType(".awc", "Audio Wave Container", 22, FileTypeAction.ViewAwc, true); InitFileType(".awc", "Audio Wave Container", 22, FileTypeAction.ViewAwc, true);
InitFileType(".rel", "Audio Data (REL)", 23, FileTypeAction.ViewRel, true); InitFileType(".rel", "Audio Data (REL)", 23, FileTypeAction.ViewRel, true);
InitFileType(".nametable", "Name Table", 5, FileTypeAction.ViewNametable); 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", "cache_y.dat", "Cache File", 6, FileTypeAction.ViewCacheDat, true);
InitSubFileType(".dat", "heightmap.dat", "Heightmap", 6, FileTypeAction.ViewHeightmap, 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) private void ViewYpdb(string name, string path, byte[] data, RpfFileEntry e)
{ {
var ypdb = RpfFile.GetFile<YpdbFile>(e, data); var ypdb = RpfFile.GetFile<YpdbFile>(e, data);
GenericForm f = new GenericForm(this); MetaForm f = new MetaForm(this);
f.Show(); f.Show();
f.LoadFile(ypdb, ypdb.RpfFileEntry); f.LoadMeta(ypdb);
} }
private RpfFileEntry CreateFileEntry(string name, string path, ref byte[] data) private RpfFileEntry CreateFileEntry(string name, string path, ref byte[] data)

View File

@ -374,6 +374,20 @@ namespace CodeWalker.Forms
metaFormat = MetaFormat.Heightmap; 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;
}
}