YBN/XML conversion

This commit is contained in:
dexy 2020-01-16 18:03:24 +11:00
parent cad632ba6f
commit 2939e76118
6 changed files with 676 additions and 165 deletions

View File

@ -5,6 +5,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.GameFiles
{
@ -87,4 +88,115 @@ namespace CodeWalker.GameFiles
}
}
public class YbnXml : MetaXmlBase
{
public static string GetXml(YbnFile ybn)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(XmlHeader);
var name = "BoundsFile";
OpenTag(sb, 0, name);
if (ybn?.Bounds != null)
{
Bounds.WriteXmlNode(ybn.Bounds, sb, 1);
}
CloseTag(sb, 0, name);
return sb.ToString();
}
public static string FormatBoundMaterialColour(BoundMaterialColour c) //for use with WriteItemArray
{
return c.R.ToString() + ", " + c.G.ToString() + ", " + c.B.ToString() + ", " + c.A.ToString();
}
}
public class XmlYbn
{
public static YbnFile GetYbn(string xml)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
return GetYbn(doc);
}
public static YbnFile GetYbn(XmlDocument doc)
{
YbnFile r = new YbnFile();
var node = doc.DocumentElement;
var bnode = node?.SelectSingleNode("Bounds");
if (bnode != null)
{
r.Bounds = Bounds.ReadXmlNode(bnode, r);
}
return r;
}
public static BoundMaterialColour[] GetRawBoundMaterialColourArray(XmlNode node)
{
if (node == null) return null;
byte r, g, b, a;
var items = new List<BoundMaterialColour>();
var split = node.InnerText.Split('\n');// Regex.Split(node.InnerText, @"[\s\r\n\t]");
for (int i = 0; i < split.Length; i++)
{
var s = split[i]?.Trim();
if (string.IsNullOrEmpty(s)) continue;
var split2 = s.Split(',');// Regex.Split(s, @"[\s\t]");
int c = 0;
r = 0; g = 0; b = 0; a = 0;
for (int n = 0; n < split2.Length; n++)
{
var ts = split2[n]?.Trim();
if (string.IsNullOrEmpty(ts)) continue;
byte v = 0;
byte.TryParse(ts, out v);
switch (c)
{
case 0: r = v; break;
case 1: g = v; break;
case 2: b = v; break;
case 3: a = v; break;
}
c++;
}
if (c >= 2)
{
var val = new BoundMaterialColour();
val.R = r;
val.G = g;
val.B = b;
val.A = a;
items.Add(val);
}
}
return (items.Count > 0) ? items.ToArray() : null;
}
public static BoundMaterialColour[] GetChildRawBoundMaterialColourArray(XmlNode node, string name)
{
var cnode = node.SelectSingleNode(name);
return GetRawBoundMaterialColourArray(cnode);
}
}
}

View File

@ -3516,7 +3516,8 @@ namespace CodeWalker.GameFiles
}
public void TestYbns()
{
bool savetest = true;
bool xmltest = true;
bool savetest = false;
bool reloadtest = false;
var errorfiles = new List<RpfEntry>();
foreach (RpfFile file in AllRpfs)
@ -3538,6 +3539,14 @@ namespace CodeWalker.GameFiles
UpdateStatus("Error! " + ex.ToString());
errorfiles.Add(entry);
}
if (xmltest && (ybn != null) && (ybn.Bounds != null))
{
var xml = YbnXml.GetXml(ybn);
var ybn2 = XmlYbn.GetYbn(xml);
var xml2 = YbnXml.GetXml(ybn2);
if (xml.Length != xml2.Length)
{ }
}
if (savetest && (ybn != null) && (ybn.Bounds != null))
{
var fentry = entry as RpfFileEntry;

View File

@ -61,6 +61,11 @@ namespace CodeWalker.GameFiles
YcdFile ycd = RpfFile.GetFile<YcdFile>(e, data);
return GetXml(ycd, out filename);
}
else if (fnl.EndsWith(".ybn"))
{
YbnFile ybn = RpfFile.GetFile<YbnFile>(e, data);
return GetXml(ybn, out filename);
}
filename = fn;
return string.Empty;
}
@ -132,6 +137,12 @@ namespace CodeWalker.GameFiles
filename = fn + ".xml";
return YcdXml.GetXml(ycd);
}
public static string GetXml(YbnFile ybn, out string filename)
{
var fn = (ybn?.RpfFileEntry?.Name) ?? "";
filename = fn + ".xml";
return YbnXml.GetXml(ybn);
}
@ -1815,6 +1826,27 @@ namespace CodeWalker.GameFiles
SelfClosingTag(sb, ind, name);
}
}
public static void WriteCustomItemArray<T>(StringBuilder sb, T[] arr, int ind, string name) where T : IMetaXmlItem
{
var itemCount = arr?.Length ?? 0;
if (itemCount > 0)
{
OpenTag(sb, ind, name);
var cind = ind + 1;
for (int i = 0; i < itemCount; i++)
{
if (arr[i] != null)
{
arr[i].WriteXml(sb, cind);
}
}
CloseTag(sb, ind, name);
}
else
{
SelfClosingTag(sb, ind, name);
}
}
public static void WriteHashItemArray(StringBuilder sb, MetaHash[] arr, int ind, string name)
{
var itemCount = arr?.Length ?? 0;
@ -1996,6 +2028,7 @@ namespace CodeWalker.GameFiles
AudioRel = 5,
Ynd = 6,
Ycd = 7,
Ybn = 8,
}
}

View File

@ -30,6 +30,7 @@ using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Xml;
using System.Text;
using System.Threading.Tasks;
using CodeWalker.World;
@ -259,9 +260,6 @@ namespace CodeWalker.GameFiles
}
}
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
@ -368,10 +366,6 @@ namespace CodeWalker.GameFiles
}
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
@ -399,13 +393,95 @@ namespace CodeWalker.GameFiles
writer.Write(this.Unknown_60h);
writer.Write(this.Volume);
}
public virtual void WriteXml(StringBuilder sb, int indent)
{
YbnXml.SelfClosingTag(sb, indent, "BoxMin " + FloatUtil.GetVector3XmlString(BoxMin));
YbnXml.SelfClosingTag(sb, indent, "BoxMax " + FloatUtil.GetVector3XmlString(BoxMax));
YbnXml.SelfClosingTag(sb, indent, "BoxCenter " + FloatUtil.GetVector3XmlString(BoxCenter));
YbnXml.SelfClosingTag(sb, indent, "SphereCenter " + FloatUtil.GetVector3XmlString(SphereCenter));
YbnXml.ValueTag(sb, indent, "SphereRadius", FloatUtil.ToString(SphereRadius));
YbnXml.ValueTag(sb, indent, "Margin", FloatUtil.ToString(Margin));
YbnXml.ValueTag(sb, indent, "Volume", FloatUtil.ToString(Volume));
YbnXml.SelfClosingTag(sb, indent, "Inertia " + FloatUtil.GetVector3XmlString(Unknown_60h));
YbnXml.ValueTag(sb, indent, "MaterialIndex", MaterialIndex.ToString());
YbnXml.ValueTag(sb, indent, "MaterialColourIndex", MaterialColorIndex.ToString());
YbnXml.ValueTag(sb, indent, "ProceduralID", ProceduralId.ToString());
YbnXml.ValueTag(sb, indent, "RoomID", RoomId.ToString());
YbnXml.ValueTag(sb, indent, "PedDensity", PedDensity.ToString());
YbnXml.ValueTag(sb, indent, "UnkFlags", UnkFlags.ToString());
YbnXml.ValueTag(sb, indent, "PolyFlags", PolyFlags.ToString());
YbnXml.ValueTag(sb, indent, "UnkType", Unknown_3Ch.ToString());
if (Parent != null)
{
YbnXml.SelfClosingTag(sb, indent, "CompositePosition " + FloatUtil.GetVector3XmlString(Position));
YbnXml.SelfClosingTag(sb, indent, "CompositeRotation " + FloatUtil.GetVector4XmlString(Orientation.ToVector4()));
YbnXml.SelfClosingTag(sb, indent, "CompositeScale " + FloatUtil.GetVector3XmlString(Scale));
YbnXml.StringTag(sb, indent, "CompositeFlags1", CompositeFlags1.Flags1.ToString());
YbnXml.StringTag(sb, indent, "CompositeFlags2", CompositeFlags1.Flags2.ToString());
}
}
public virtual void ReadXml(XmlNode node)
{
BoxMin = Xml.GetChildVector3Attributes(node, "BoxMin", "x", "y", "z");
BoxMax = Xml.GetChildVector3Attributes(node, "BoxMax", "x", "y", "z");
BoxCenter = Xml.GetChildVector3Attributes(node, "BoxCenter", "x", "y", "z");
SphereCenter = Xml.GetChildVector3Attributes(node, "SphereCenter", "x", "y", "z");
SphereRadius = Xml.GetChildFloatAttribute(node, "SphereRadius", "value");
Margin = Xml.GetChildFloatAttribute(node, "Margin", "value");
Volume = Xml.GetChildFloatAttribute(node, "Volume", "value");
Unknown_60h = Xml.GetChildVector3Attributes(node, "Inertia", "x", "y", "z");
MaterialIndex = (byte)Xml.GetChildUIntAttribute(node, "MaterialIndex", "value");
MaterialColorIndex = (byte)Xml.GetChildUIntAttribute(node, "MaterialColourIndex", "value");
ProceduralId = (byte)Xml.GetChildUIntAttribute(node, "ProceduralID", "value");
RoomId = (byte)Xml.GetChildUIntAttribute(node, "RoomID", "value");
PedDensity = (byte)Xml.GetChildUIntAttribute(node, "PedDensity", "value");
UnkFlags = (byte)Xml.GetChildUIntAttribute(node, "UnkFlags", "value");
PolyFlags = (byte)Xml.GetChildUIntAttribute(node, "PolyFlags", "value");
Unknown_3Ch = (byte)Xml.GetChildUIntAttribute(node, "UnkType", "value");
if (Parent != null)
{
Position = Xml.GetChildVector3Attributes(node, "CompositePosition", "x", "y", "z");
Orientation = Xml.GetChildVector4Attributes(node, "CompositeRotation", "x", "y", "z", "w").ToQuaternion();
Scale = Xml.GetChildVector3Attributes(node, "CompositeScale", "x", "y", "z");
var f = new BoundCompositeChildrenFlags();
f.Flags1 = Xml.GetChildEnumInnerText<EBoundCompositeFlags>(node, "CompositeFlags1");
f.Flags2 = Xml.GetChildEnumInnerText<EBoundCompositeFlags>(node, "CompositeFlags2");
CompositeFlags1 = f;
CompositeFlags2 = f;
}
}
public static void WriteXmlNode(Bounds b, StringBuilder sb, int indent, string name = "Bounds")
{
if (b == null) return;
YbnXml.OpenTag(sb, indent, name + " type=\"" + b.Type.ToString() + "\"");
b.WriteXml(sb, indent + 1);
YbnXml.CloseTag(sb, indent, name);
}
public static Bounds ReadXmlNode(XmlNode node, object owner = null, BoundComposite parent = null)
{
if (node == null) return null;
var typestr = Xml.GetStringAttribute(node, "type");
var type = Xml.GetEnumValue<BoundsType>(typestr);
var b = Create(type);
if (b != null)
{
b.Type = type;
b.Owner = owner;
b.Parent = parent;
b.ReadXml(node);
}
return b;
}
public IResourceSystemBlock GetType(ResourceDataReader reader, params object[] parameters)
{
reader.Position += 16;
var type = (BoundsType)reader.ReadByte();
reader.Position -= 17;
return Create(type);
}
public static Bounds Create(BoundsType type)
{
switch (type)
{
case BoundsType.Sphere: return new BoundSphere();
@ -426,6 +502,7 @@ namespace CodeWalker.GameFiles
if (other == null) return;
SphereRadius = other.SphereRadius;
SphereCenter = other.SphereCenter;
BoxCenter = other.BoxCenter;
BoxMin = other.BoxMin;
BoxMax = other.BoxMax;
Margin = other.Margin;
@ -880,9 +957,6 @@ namespace CodeWalker.GameFiles
private BoundVertex[] VertexObjects = null; //for use by the editor, created as needed by GetVertexObject()
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
@ -984,83 +1058,6 @@ namespace CodeWalker.GameFiles
}
}
private void ReadPolygons(ResourceDataReader reader)
{
if(PolygonsCount==0)
{ return; }
Polygons = new BoundPolygon[PolygonsCount];
uint polybytecount = PolygonsCount * 16;
var polygonData = reader.ReadBytesAt(PolygonsPointer, polybytecount);
for (int i = 0; i < PolygonsCount; i++)
{
var offset = i * 16;
byte b0 = polygonData[offset];
polygonData[offset] = (byte)(b0 & 0xF8);//mask it off
BoundPolygonType type = (BoundPolygonType)(b0 & 7);
BoundPolygon p = CreatePolygon(type);
if (p != null)
{
p.Index = i;
p.Read(polygonData, offset);
}
Polygons[i] = p;
}
}
public BoundVertex GetVertexObject(int index)
{
//gets a cached object which references a single vertex in this geometry
if (Vertices == null) return null;
if ((index < 0) || (index >= Vertices.Length)) return null;
if ((VertexObjects == null) || (VertexObjects.Length != Vertices.Length))
{
VertexObjects = new BoundVertex[Vertices.Length];
}
if (index >= VertexObjects.Length) return null;
var r = VertexObjects[index];
if (r == null)
{
r = new BoundVertex(this, index);
VertexObjects[index] = r;
}
return r;
}
public Vector3 GetVertex(int index)
{
return ((index >= 0) && (index < Vertices.Length)) ? Vertices[index] : Vector3.Zero;
}
public Vector3 GetVertexPos(int index)
{
var v = GetVertex(index) + CenterGeom;
return Vector3.Transform(v, Transform).XYZ();
}
public void SetVertexPos(int index, Vector3 v)
{
if ((index >= 0) && (index < Vertices.Length))
{
var t = Vector3.Transform(v, TransformInv).XYZ() - CenterGeom;
Vertices[index] = t;
}
}
public BoundMaterialColour GetVertexColour(int index)
{
return ((VertexColours != null) && (index >= 0) && (index < VertexColours.Length)) ? VertexColours[index] : new BoundMaterialColour();
}
public void SetVertexColour(int index, BoundMaterialColour c)
{
if ((VertexColours != null) && (index >= 0) && (index < VertexColours.Length))
{
VertexColours[index] = c;
}
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
@ -1122,10 +1119,95 @@ namespace CodeWalker.GameFiles
writer.Write(this.Unknown_128h);
writer.Write(this.Unknown_12Ch);
}
public override void WriteXml(StringBuilder sb, int indent)
{
base.WriteXml(sb, indent);
YbnXml.SelfClosingTag(sb, indent, "GeometryCenter " + FloatUtil.GetVector3XmlString(CenterGeom));
YbnXml.ValueTag(sb, indent, "UnkFloat1", FloatUtil.ToString(Unknown_9Ch));
YbnXml.ValueTag(sb, indent, "UnkFloat2", FloatUtil.ToString(Unknown_ACh));
if (Materials != null)
{
YbnXml.WriteItemArray(sb, Materials, indent, "Materials");
}
if (MaterialColours != null)
{
YbnXml.WriteRawArray(sb, MaterialColours, indent, "MaterialColours", "", YbnXml.FormatBoundMaterialColour, 1);
}
if (Vertices != null)
{
YbnXml.WriteRawArray(sb, Vertices, indent, "Vertices", "", YbnXml.FormatVector3, 1);
}
if (Vertices2 != null)
{
YbnXml.WriteRawArray(sb, Vertices2, indent, "Vertices2", "", YbnXml.FormatVector3, 1);
}
if (VertexColours != null)
{
YbnXml.WriteRawArray(sb, VertexColours, indent, "VertexColours", "", YbnXml.FormatBoundMaterialColour, 1);
}
if (Polygons != null)
{
YbnXml.WriteCustomItemArray(sb, Polygons, indent, "Polygons");
}
if (Unknown1Data != null)
{
YbnXml.OpenTag(sb, indent, "UnkData");
Unknown1Data.WriteXml(sb, indent + 1);
YbnXml.CloseTag(sb, indent, "UnkData");
}
}
public override void ReadXml(XmlNode node)
{
base.ReadXml(node);
CenterGeom = Xml.GetChildVector3Attributes(node, "GeometryCenter", "x", "y", "z");
Unknown_9Ch = Xml.GetChildFloatAttribute(node, "UnkFloat1", "value");
Unknown_ACh = Xml.GetChildFloatAttribute(node, "UnkFloat2", "value");
Materials = XmlMeta.ReadItemArray<BoundMaterial_s>(node, "Materials");
MaterialColours = XmlYbn.GetChildRawBoundMaterialColourArray(node, "MaterialColours");
Vertices = Xml.GetChildRawVector3ArrayNullable(node, "Vertices");
Vertices2 = Xml.GetChildRawVector3ArrayNullable(node, "Vertices2");
VertexColours = XmlYbn.GetChildRawBoundMaterialColourArray(node, "VertexColours");
var pnode = node.SelectSingleNode("Polygons");
if (pnode != null)
{
var inodes = pnode.ChildNodes;
if (inodes?.Count > 0)
{
var polylist = new List<BoundPolygon>();
foreach (XmlNode inode in inodes)
{
var typestr = inode.Name;
var type = Xml.GetEnumValue<BoundPolygonType>(typestr);
var poly = CreatePolygon(type);
if (poly != null)
{
poly.ReadXml(inode);
polylist.Add(poly);
}
}
Polygons = polylist.ToArray();
}
}
var unode = node.SelectSingleNode("UnkData");
if (unode != null)
{
Unknown1Data = new BoundGeomUnknown1();
Unknown1Data.ReadXml(unode);
}
BuildMaterials();
CalculateQuantum();
UpdateEdgeIndices();
UpdateTriangleAreas();
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
BuildMaterials();
@ -1215,6 +1297,82 @@ namespace CodeWalker.GameFiles
return list.ToArray();
}
private void ReadPolygons(ResourceDataReader reader)
{
if(PolygonsCount==0)
{ return; }
Polygons = new BoundPolygon[PolygonsCount];
uint polybytecount = PolygonsCount * 16;
var polygonData = reader.ReadBytesAt(PolygonsPointer, polybytecount);
for (int i = 0; i < PolygonsCount; i++)
{
var offset = i * 16;
byte b0 = polygonData[offset];
polygonData[offset] = (byte)(b0 & 0xF8);//mask it off
BoundPolygonType type = (BoundPolygonType)(b0 & 7);
BoundPolygon p = CreatePolygon(type);
if (p != null)
{
p.Index = i;
p.Read(polygonData, offset);
}
Polygons[i] = p;
}
}
public BoundVertex GetVertexObject(int index)
{
//gets a cached object which references a single vertex in this geometry
if (Vertices == null) return null;
if ((index < 0) || (index >= Vertices.Length)) return null;
if ((VertexObjects == null) || (VertexObjects.Length != Vertices.Length))
{
VertexObjects = new BoundVertex[Vertices.Length];
}
if (index >= VertexObjects.Length) return null;
var r = VertexObjects[index];
if (r == null)
{
r = new BoundVertex(this, index);
VertexObjects[index] = r;
}
return r;
}
public Vector3 GetVertex(int index)
{
return ((index >= 0) && (index < Vertices.Length)) ? Vertices[index] : Vector3.Zero;
}
public Vector3 GetVertexPos(int index)
{
var v = GetVertex(index) + CenterGeom;
return Vector3.Transform(v, Transform).XYZ();
}
public void SetVertexPos(int index, Vector3 v)
{
if ((index >= 0) && (index < Vertices.Length))
{
var t = Vector3.Transform(v, TransformInv).XYZ() - CenterGeom;
Vertices[index] = t;
}
}
public BoundMaterialColour GetVertexColour(int index)
{
return ((VertexColours != null) && (index >= 0) && (index < VertexColours.Length)) ? VertexColours[index] : new BoundMaterialColour();
}
public void SetVertexColour(int index, BoundMaterialColour c)
{
if ((VertexColours != null) && (index >= 0) && (index < VertexColours.Length))
{
VertexColours[index] = c;
}
}
public override SpaceSphereIntersectResult SphereIntersect(ref BoundingSphere sph)
{
var res = new SpaceSphereIntersectResult();
@ -1468,19 +1626,28 @@ namespace CodeWalker.GameFiles
public BoundMaterial_s GetMaterial(int polyIndex)
public int GetMaterialIndex(int polyIndex)
{
var matind = 0;
if ((PolygonMaterialIndices != null) && (polyIndex < PolygonMaterialIndices.Length))
{
matind = PolygonMaterialIndices[polyIndex];
}
if ((Materials != null) && (matind < Materials.Length))
return matind;
}
public BoundMaterial_s GetMaterialByIndex(int matIndex)
{
if ((Materials != null) && (matIndex < Materials.Length))
{
return Materials[matind];
return Materials[matIndex];
}
return new BoundMaterial_s();
}
public BoundMaterial_s GetMaterial(int polyIndex)
{
var matind = GetMaterialIndex(polyIndex);
return GetMaterialByIndex(matind);
}
public void SetMaterial(int polyIndex, BoundMaterial_s mat)
{
//updates the shared material for the given poly.
@ -1911,9 +2078,6 @@ namespace CodeWalker.GameFiles
// reference data
public BVH BVH { get; set; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
@ -1940,10 +2104,6 @@ namespace CodeWalker.GameFiles
//this can happen in some ydr's for some reason
}
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
@ -1962,9 +2122,6 @@ namespace CodeWalker.GameFiles
writer.Write(this.Unknown_14Ch);
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
BuildBVH();
@ -2231,9 +2388,6 @@ namespace CodeWalker.GameFiles
private ResourceSystemStructBlock<BoundCompositeChildrenFlags> ChildrenFlags2Block = null;
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
@ -2317,10 +2471,6 @@ namespace CodeWalker.GameFiles
//{ }//some props ydr's
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
@ -2348,10 +2498,55 @@ namespace CodeWalker.GameFiles
writer.Write(this.Unknown_A4h);
writer.Write(this.BVHPointer);
}
public override void WriteXml(StringBuilder sb, int indent)
{
base.WriteXml(sb, indent);
var c = Children?.data_items;
if ((c == null) || (c.Length == 0))
{
YbnXml.SelfClosingTag(sb, indent, "Children");
}
else
{
var cind = indent + 1;
YbnXml.OpenTag(sb, indent, "Children");
foreach (var child in c)
{
Bounds.WriteXmlNode(child, sb, cind, "Item");
}
YbnXml.CloseTag(sb, indent, "Children");
}
}
public override void ReadXml(XmlNode node)
{
base.ReadXml(node);
var cnode = node.SelectSingleNode("Children");
if (cnode != null)
{
var cnodes = cnode.SelectNodes("Item");
if (cnodes?.Count > 0)
{
var blist = new List<Bounds>();
foreach (XmlNode inode in cnodes)
{
var b = Bounds.ReadXmlNode(inode, Owner, this);
blist.Add(b);
}
var arr = blist.ToArray();
Children = new ResourcePointerArray64<Bounds>();
Children.data_items = arr;
BuildBVH();
UpdateChildrenFlags();
UpdateChildrenBounds();
UpdateChildrenTransformations();
}
}
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
BuildBVH();
@ -2414,7 +2609,7 @@ namespace CodeWalker.GameFiles
}
else
{
//why are we here? yft's hit this...
//why are we here? yft's hit this... (and when loading XML!)
if (!(Owner is FragPhysicsLOD) && !(Owner is FragPhysArchetype) && !(Owner is VerletCloth))
{ }
}
@ -2663,7 +2858,7 @@ namespace CodeWalker.GameFiles
Box = 3,
Cylinder = 4,
}
[TC(typeof(EXP))] public abstract class BoundPolygon
[TC(typeof(EXP))] public abstract class BoundPolygon : IMetaXmlItem
{
public BoundPolygonType Type { get; set; }
public BoundGeometry Owner { get; set; } //for browsing/editing convenience
@ -2680,6 +2875,10 @@ namespace CodeWalker.GameFiles
}
}
public BoundMaterial_s? MaterialCustom; //for editing, when assigning a new material.
public int MaterialIndex
{
get { return Owner?.GetMaterialIndex(Index) ?? -1; }
}
public Vector3[] VertexPositions
{
get
@ -2720,6 +2919,8 @@ namespace CodeWalker.GameFiles
public abstract void GatherVertices(Dictionary<BoundVertex, int> verts);
public abstract void Read(byte[] bytes, int offset);
public abstract void Write(BinaryWriter bw);
public abstract void WriteXml(StringBuilder sb, int indent);
public abstract void ReadXml(XmlNode node);
public virtual string Title
{
get
@ -2930,6 +3131,30 @@ namespace CodeWalker.GameFiles
bw.Write(edgeIndex2);
bw.Write(edgeIndex3);
}
public override void WriteXml(StringBuilder sb, int indent)
{
var s = string.Format("{0} m=\"{1}\" v1=\"{2}\" v2=\"{3}\" v3=\"{4}\" f1=\"{5}\" f2=\"{6}\" f3=\"{7}\"",
Type,
MaterialIndex,
vertIndex1,
vertIndex2,
vertIndex3,
vertFlag1 ? 1 : 0,
vertFlag2 ? 1 : 0,
vertFlag3 ? 1 : 0
);
YbnXml.SelfClosingTag(sb, indent, s);
}
public override void ReadXml(XmlNode node)
{
Material = Owner?.GetMaterialByIndex(Xml.GetIntAttribute(node, "m")) ?? new BoundMaterial_s();
vertIndex1 = Xml.GetIntAttribute(node, "v1");
vertIndex2 = Xml.GetIntAttribute(node, "v2");
vertIndex3 = Xml.GetIntAttribute(node, "v3");
vertFlag1 = Xml.GetIntAttribute(node, "f1") != 0;
vertFlag2 = Xml.GetIntAttribute(node, "f2") != 0;
vertFlag3 = Xml.GetIntAttribute(node, "f3") != 0;
}
public override string ToString()
{
return base.ToString() + ": " + vertIndex1.ToString() + ", " + vertIndex2.ToString() + ", " + vertIndex3.ToString();
@ -3030,6 +3255,22 @@ namespace CodeWalker.GameFiles
bw.Write(unused0);
bw.Write(unused1);
}
public override void WriteXml(StringBuilder sb, int indent)
{
var s = string.Format("{0} m=\"{1}\" v=\"{2}\" radius=\"{3}\"",
Type,
MaterialIndex,
sphereIndex,
FloatUtil.ToString(sphereRadius)
);
YbnXml.SelfClosingTag(sb, indent, s);
}
public override void ReadXml(XmlNode node)
{
Material = Owner?.GetMaterialByIndex(Xml.GetIntAttribute(node, "m")) ?? new BoundMaterial_s();
sphereIndex = (ushort)Xml.GetUIntAttribute(node, "v");
sphereRadius = Xml.GetFloatAttribute(node, "radius");
}
public override string ToString()
{
return base.ToString() + ": " + sphereIndex.ToString() + ", " + sphereRadius.ToString();
@ -3184,6 +3425,24 @@ namespace CodeWalker.GameFiles
bw.Write(unused0);
bw.Write(unused1);
}
public override void WriteXml(StringBuilder sb, int indent)
{
var s = string.Format("{0} m=\"{1}\" v1=\"{2}\" v2=\"{3}\" radius=\"{4}\"",
Type,
Material,
capsuleIndex1,
capsuleIndex2,
FloatUtil.ToString(capsuleRadius)
);
YbnXml.SelfClosingTag(sb, indent, s);
}
public override void ReadXml(XmlNode node)
{
Material = Owner?.GetMaterialByIndex(Xml.GetIntAttribute(node, "m")) ?? new BoundMaterial_s();
capsuleIndex1 = (ushort)Xml.GetUIntAttribute(node, "v1");
capsuleIndex2 = (ushort)Xml.GetUIntAttribute(node, "v2");
capsuleRadius = Xml.GetFloatAttribute(node, "radius");
}
public override string ToString()
{
return base.ToString() + ": " + capsuleIndex1.ToString() + ", " + capsuleIndex2.ToString() + ", " + capsuleRadius.ToString();
@ -3367,6 +3626,26 @@ namespace CodeWalker.GameFiles
bw.Write(boxIndex4);
bw.Write(unused0);
}
public override void WriteXml(StringBuilder sb, int indent)
{
var s = string.Format("{0} m=\"{1}\" v1=\"{2}\" v2=\"{3}\" v3=\"{4}\" v4=\"{5}\"",
Type,
Material,
boxIndex1,
boxIndex2,
boxIndex3,
boxIndex4
);
YbnXml.SelfClosingTag(sb, indent, s);
}
public override void ReadXml(XmlNode node)
{
Material = Owner?.GetMaterialByIndex(Xml.GetIntAttribute(node, "m")) ?? new BoundMaterial_s();
boxIndex1 = (short)Xml.GetIntAttribute(node, "v1");
boxIndex2 = (short)Xml.GetIntAttribute(node, "v2");
boxIndex3 = (short)Xml.GetIntAttribute(node, "v3");
boxIndex4 = (short)Xml.GetIntAttribute(node, "v4");
}
public override string ToString()
{
return base.ToString() + ": " + boxIndex1.ToString() + ", " + boxIndex2.ToString() + ", " + boxIndex3.ToString() + ", " + boxIndex4.ToString();
@ -3521,6 +3800,24 @@ namespace CodeWalker.GameFiles
bw.Write(unused0);
bw.Write(unused1);
}
public override void WriteXml(StringBuilder sb, int indent)
{
var s = string.Format("{0} m=\"{1}\" v1=\"{2}\" v2=\"{3}\" radius=\"{4}\"",
Type,
Material,
cylinderIndex1,
cylinderIndex2,
FloatUtil.ToString(cylinderRadius)
);
YbnXml.SelfClosingTag(sb, indent, s);
}
public override void ReadXml(XmlNode node)
{
Material = Owner?.GetMaterialByIndex(Xml.GetIntAttribute(node, "m")) ?? new BoundMaterial_s();
cylinderIndex1 = (ushort)Xml.GetUIntAttribute(node, "v1");
cylinderIndex2 = (ushort)Xml.GetUIntAttribute(node, "v2");
cylinderRadius = Xml.GetFloatAttribute(node, "radius");
}
public override string ToString()
{
return base.ToString() + ": " + cylinderIndex1.ToString() + ", " + cylinderIndex2.ToString() + ", " + cylinderRadius.ToString();
@ -3615,7 +3912,7 @@ namespace CodeWalker.GameFiles
}
}
[TC(typeof(EXP))] public class BoundGeomUnknown1 : ResourceSystemBlock
[TC(typeof(EXP))] public class BoundGeomUnknown1 : ResourceSystemBlock, IMetaXmlItem
{
public uint[][] Items { get; private set; }
@ -3654,7 +3951,6 @@ namespace CodeWalker.GameFiles
}
}
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
@ -3668,6 +3964,50 @@ namespace CodeWalker.GameFiles
}
}
public void WriteXml(StringBuilder sb, int indent)
{
if (Items == null) return;
foreach (var item in Items)
{
YbnXml.Indent(sb, indent);
if (item != null)
{
bool newline = true;
foreach (var val in item)
{
if (!newline) sb.Append(", ");
sb.Append(val.ToString());
newline = false;
}
}
sb.AppendLine();
}
}
public void ReadXml(XmlNode node)
{
var collist = new List<uint[]>();
var rowlist = new List<uint>();
var str = node.InnerText;
var split = str.Split('\n');
for (int i = 0; i < split.Length; i++)
{
var s = split[i]?.Trim();
//if (string.IsNullOrEmpty(s)) continue;
var split2 = s.Split(',');// Regex.Split(s, @"[\s\t]");
rowlist.Clear();
for (int n = 0; n < split2.Length; n++)
{
var ts = split2[n]?.Trim();
if (string.IsNullOrEmpty(ts)) continue;
if (uint.TryParse(ts, out uint u))
{
rowlist.Add(u);
}
}
collist.Add(rowlist.ToArray());
}
Items = collist.ToArray();
}
public override IResourceBlock[] GetReferences()
{
@ -4240,14 +4580,12 @@ namespace CodeWalker.GameFiles
FLAG_NO_NETWORK_SPAWN = 1 << 14,
FLAG_NO_CAM_COLLISION_ALLOW_CLIPPING = 1 << 15,
}
[TC(typeof(EXP))] public struct BoundMaterial_s
[TC(typeof(EXP))] public struct BoundMaterial_s : IMetaXmlItem
{
public uint Data1;
public uint Data2;
#region Public Properties
public BoundsMaterialType Type
{
get => (BoundsMaterialType)(Data1 & 0xFFu);
@ -4272,18 +4610,6 @@ namespace CodeWalker.GameFiles
set => Data1 = ((Data1 & 0xFF1FFFFFu) | ((value & 0x7u) << 21));
}
//public byte Flags1
//{
// get => (byte)((Data1 >> 24) & 0xFFu);
// set => Data1 = ((Data1 & 0xFFFFFFu) | ((value & 0xFFu) << 24));
//}
//public byte Flags2
//{
// get => (byte)((Data2 >> 24) & 0xFFu);
// set => Data2 = ((Data2 & 0xFFFFFFu) | ((value & 0xFFu) << 24));
//}
public EBoundMaterialFlags Flags
{
get => (EBoundMaterialFlags)(((Data1 >> 24) & 0xFFu) | ((Data2 & 0xFFu) << 8));
@ -4297,7 +4623,7 @@ namespace CodeWalker.GameFiles
public byte MaterialColorIndex
{
get => (byte)((Data2 >> 8) & 0xFFu);
set => Data2 = ((Data2 & 0xFFFF00FFu) | (value & 0xFFu));
set => Data2 = ((Data2 & 0xFFFF00FFu) | ((value & 0xFFu) << 8));
}
public ushort Unk4
@ -4306,6 +4632,28 @@ namespace CodeWalker.GameFiles
set => Data2 = ((Data2 & 0x0000FFFFu) | ((value & 0xFFFFu) << 16));
}
public void WriteXml(StringBuilder sb, int indent)
{
YbnXml.ValueTag(sb, indent, "Type", Type.Index.ToString());
YbnXml.ValueTag(sb, indent, "ProceduralID", ProceduralId.ToString());
YbnXml.ValueTag(sb, indent, "RoomID", RoomId.ToString());
YbnXml.ValueTag(sb, indent, "PedDensity", PedDensity.ToString());
YbnXml.StringTag(sb, indent, "Flags", Flags.ToString());
YbnXml.ValueTag(sb, indent, "MaterialColourIndex", MaterialColorIndex.ToString());
YbnXml.ValueTag(sb, indent, "Unk", Unk4.ToString());
}
public void ReadXml(XmlNode node)
{
Type = (byte)Xml.GetChildUIntAttribute(node, "Type", "value");
ProceduralId = (byte)Xml.GetChildUIntAttribute(node, "ProceduralID", "value");
RoomId = (byte)Xml.GetChildUIntAttribute(node, "RoomID", "value");
PedDensity = (byte)Xml.GetChildUIntAttribute(node, "PedDensity", "value");
Flags = Xml.GetChildEnumInnerText<EBoundMaterialFlags>(node, "Flags");
MaterialColorIndex = (byte)Xml.GetChildUIntAttribute(node, "MaterialColourIndex", "value");
Unk4 = (ushort)Xml.GetChildUIntAttribute(node, "Unk", "value");
}
public override string ToString()
{
return Data1.ToString() + ", " + Data2.ToString() + ", "
@ -4313,7 +4661,6 @@ namespace CodeWalker.GameFiles
+ Flags.ToString() + ", " + MaterialColorIndex.ToString() + ", " + Unk4.ToString();
}
#endregion
}
[TC(typeof(EXP))] public struct BoundMaterialColour
{

View File

@ -374,6 +374,12 @@ namespace CodeWalker
var cnode = node.SelectSingleNode(name);
return GetRawVector3Array(cnode);
}
public static Vector3[] GetChildRawVector3ArrayNullable(XmlNode node, string name)
{
var cnode = node.SelectSingleNode(name);
var arr = GetRawVector3Array(cnode);
return ((arr != null) && (arr.Length > 0)) ? arr : null;
}
public static Vector4[] GetRawVector4Array(XmlNode node)
{

View File

@ -230,10 +230,10 @@ namespace CodeWalker
InitFileType(".sps", "Shader Preset", 5, FileTypeAction.ViewText);
InitFileType(".xml", "XML File", 6, FileTypeAction.ViewXml);
InitFileType(".meta", "Metadata (XML)", 6, FileTypeAction.ViewXml);
InitFileType(".ymt", "Metadata (Binary)", 6, FileTypeAction.ViewYmt);
InitFileType(".pso", "Metadata (PSO)", 6, FileTypeAction.ViewJPso);
InitFileType(".ymt", "Metadata (Binary)", 6, FileTypeAction.ViewYmt, true);
InitFileType(".pso", "Metadata (PSO)", 6, FileTypeAction.ViewJPso, true);
InitFileType(".gfx", "Scaleform Flash", 7);
InitFileType(".ynd", "Path Nodes", 8, FileTypeAction.ViewYnd);
InitFileType(".ynd", "Path Nodes", 8, FileTypeAction.ViewYnd, true);
InitFileType(".ynv", "Nav Mesh", 9, FileTypeAction.ViewModel);
InitFileType(".yvr", "Vehicle Record", 9, FileTypeAction.ViewYvr);
InitFileType(".ywr", "Waypoint Record", 9, FileTypeAction.ViewYwr);
@ -247,9 +247,9 @@ namespace CodeWalker
InitFileType(".yft", "Fragment", 11, FileTypeAction.ViewModel);
InitFileType(".ydr", "Drawable", 11, FileTypeAction.ViewModel);
InitFileType(".ydd", "Drawable Dictionary", 12, FileTypeAction.ViewModel);
InitFileType(".cut", "Cutscene", 12, FileTypeAction.ViewCut);
InitFileType(".cut", "Cutscene", 12, FileTypeAction.ViewCut, true);
InitFileType(".ysc", "Script", 13);
InitFileType(".ymf", "Manifest", 14, FileTypeAction.ViewYmf);
InitFileType(".ymf", "Manifest", 14, FileTypeAction.ViewYmf, true);
InitFileType(".bik", "Bink Video", 15);
InitFileType(".jpg", "JPEG Image", 16);
InitFileType(".jpeg", "JPEG Image", 16);
@ -258,21 +258,21 @@ namespace CodeWalker
InitFileType(".dds", "DirectDraw Surface", 16);
InitFileType(".ytd", "Texture Dictionary", 16, FileTypeAction.ViewYtd);
InitFileType(".mrf", "MRF File", 18);
InitFileType(".ycd", "Clip Dictionary", 18, FileTypeAction.ViewYcd);
InitFileType(".ycd", "Clip Dictionary", 18, FileTypeAction.ViewYcd, true);
InitFileType(".ypt", "Particle Effect", 18, FileTypeAction.ViewModel);
InitFileType(".ybn", "Static Collisions", 19, FileTypeAction.ViewModel);
InitFileType(".ybn", "Static Collisions", 19, FileTypeAction.ViewModel, true);
InitFileType(".ide", "Item Definitions", 20, FileTypeAction.ViewText);
InitFileType(".ytyp", "Archetype Definitions", 20, FileTypeAction.ViewYtyp);
InitFileType(".ymap", "Map Data", 21, FileTypeAction.ViewYmap);
InitFileType(".ytyp", "Archetype Definitions", 20, FileTypeAction.ViewYtyp, true);
InitFileType(".ymap", "Map Data", 21, FileTypeAction.ViewYmap, true);
InitFileType(".ipl", "Item Placements", 21, FileTypeAction.ViewText);
InitFileType(".awc", "Audio Wave Container", 22, FileTypeAction.ViewAwc);
InitFileType(".rel", "Audio Data (REL)", 23, FileTypeAction.ViewRel);
InitFileType(".rel", "Audio Data (REL)", 23, FileTypeAction.ViewRel, true);
InitSubFileType(".dat", "cache_y.dat", "Cache File", 6, FileTypeAction.ViewCacheDat);
}
private void InitFileType(string ext, string name, int imgidx, FileTypeAction defaultAction = FileTypeAction.ViewHex)
private void InitFileType(string ext, string name, int imgidx, FileTypeAction defaultAction = FileTypeAction.ViewHex, bool xmlConvertible = false)
{
var ft = new FileTypeInfo(ext, name, imgidx, defaultAction);
var ft = new FileTypeInfo(ext, name, imgidx, defaultAction, xmlConvertible);
FileTypes[ext] = ft;
}
private void InitSubFileType(string ext, string subext, string name, int imgidx, FileTypeAction defaultAction = FileTypeAction.ViewHex)
@ -280,7 +280,7 @@ namespace CodeWalker
FileTypeInfo pti = null;
if (FileTypes.TryGetValue(ext, out pti))
{
var ft = new FileTypeInfo(subext, name, imgidx, defaultAction);
var ft = new FileTypeInfo(subext, name, imgidx, defaultAction, pti.XmlConvertible);
pti.AddSubType(ft);
}
}
@ -308,7 +308,7 @@ namespace CodeWalker
}
else
{
ft = new FileTypeInfo(ext, ext.Substring(1).ToUpperInvariant() + " File", 4, FileTypeAction.ViewHex);
ft = new FileTypeInfo(ext, ext.Substring(1).ToUpperInvariant() + " File", 4, FileTypeAction.ViewHex, false);
FileTypes[ft.Extension] = ft; //save it for later!
return ft;
}
@ -1323,20 +1323,7 @@ namespace CodeWalker
{
if (item == null) return false;
if (item.FileType == null) return false;
switch (item.FileType.DefaultAction)
{
case FileTypeAction.ViewYmt:
case FileTypeAction.ViewYmf:
case FileTypeAction.ViewYmap:
case FileTypeAction.ViewYtyp:
case FileTypeAction.ViewJPso:
case FileTypeAction.ViewCut:
case FileTypeAction.ViewRel:
case FileTypeAction.ViewYnd:
case FileTypeAction.ViewYcd:
return true;
}
return false;
return item.FileType.XmlConvertible;
}
@ -2465,6 +2452,10 @@ namespace CodeWalker
{
mformat = MetaFormat.Ycd;
}
if (fnamel.EndsWith(".ybn.xml"))
{
mformat = MetaFormat.Ybn;
}
fname = fname.Substring(0, fname.Length - trimlength);
fnamel = fnamel.Substring(0, fnamel.Length - trimlength);
@ -2546,6 +2537,17 @@ namespace CodeWalker
data = ycd.Save();
break;
}
case MetaFormat.Ybn:
{
var ybn = XmlYbn.GetYbn(doc);
if (ybn.Bounds == null)
{
MessageBox.Show(fname + ": Schema not supported.", "Cannot import YBN XML");
continue;
}
data = ybn.Save();
break;
}
}
@ -4181,13 +4183,15 @@ namespace CodeWalker
public int ImageIndex { get; set; }
public FileTypeAction DefaultAction { get; set; }
public List<FileTypeInfo> SubTypes { get; set; }
public bool XmlConvertible { get; set; }
public FileTypeInfo(string extension, string name, int imageindex, FileTypeAction defaultAction)
public FileTypeInfo(string extension, string name, int imageindex, FileTypeAction defaultAction, bool xmlConvertible)
{
Name = name;
Extension = extension;
ImageIndex = imageindex;
DefaultAction = defaultAction;
XmlConvertible = xmlConvertible;
}
public void AddSubType(FileTypeInfo t)