mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-26 08:52:52 +08:00
YNV/XML conversion
This commit is contained in:
parent
6268298207
commit
4751818703
@ -4,6 +4,7 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using SharpDX;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
@ -29,6 +30,9 @@ namespace CodeWalker.GameFiles
|
||||
public bool HasChanged { get; set; } = false;
|
||||
public List<string> SaveWarnings = null;
|
||||
|
||||
public bool BuildStructsOnSave { get; set; } = true;
|
||||
|
||||
|
||||
public PathBVH BVH { get; set; }
|
||||
|
||||
|
||||
@ -92,102 +96,7 @@ namespace CodeWalker.GameFiles
|
||||
Nav = rd.ReadBlock<NavMesh>();
|
||||
|
||||
|
||||
if (Nav != null)
|
||||
{
|
||||
Vector3 posoffset = Nav.SectorTree?.AABBMin.XYZ() ?? Vector3.Zero;
|
||||
Vector3 aabbsize = Nav.AABBSize;
|
||||
|
||||
if (Nav.Vertices != null)
|
||||
{
|
||||
var verts = Nav.Vertices.GetFullList();
|
||||
Vertices = new List<Vector3>(verts.Count);
|
||||
for (int i = 0; i < verts.Count; i++)
|
||||
{
|
||||
var ov = verts[i].ToVector3();
|
||||
Vertices.Add(posoffset + ov * aabbsize);
|
||||
}
|
||||
}
|
||||
if (Nav.Indices != null)
|
||||
{
|
||||
Indices = Nav.Indices.GetFullList();
|
||||
}
|
||||
if (Nav.Edges != null)
|
||||
{
|
||||
var edges = Nav.Edges.GetFullList();
|
||||
Edges = new List<YnvEdge>(edges.Count);
|
||||
for (int i = 0; i < edges.Count; i++)
|
||||
{
|
||||
YnvEdge edge = new YnvEdge();
|
||||
edge.Init(this, edges[i]);
|
||||
Edges.Add(edge);
|
||||
}
|
||||
}
|
||||
if (Nav.Polys != null)
|
||||
{
|
||||
var polys = Nav.Polys.GetFullList();
|
||||
Polys = new List<YnvPoly>(polys.Count);
|
||||
for (int i = 0; i < polys.Count; i++)
|
||||
{
|
||||
YnvPoly poly = new YnvPoly();
|
||||
poly.Init(this, polys[i]);
|
||||
poly.Index = i;
|
||||
Polys.Add(poly);
|
||||
}
|
||||
}
|
||||
if (Nav.Portals != null)
|
||||
{
|
||||
var portals = Nav.Portals;
|
||||
Portals = new List<YnvPortal>(portals.Length);
|
||||
for (int i = 0; i < portals.Length; i++)
|
||||
{
|
||||
YnvPortal portal = new YnvPortal();
|
||||
portal.Init(this, portals[i]);
|
||||
portal.Index = i;
|
||||
portal.PositionFrom = posoffset + portal._RawData.PositionFrom.ToVector3() * aabbsize;
|
||||
portal.PositionTo = posoffset + portal._RawData.PositionTo.ToVector3() * aabbsize;
|
||||
Portals.Add(portal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////### add points to the list and calculate positions...
|
||||
var treestack = new Stack<NavMeshSector>();
|
||||
var pointi = 0;
|
||||
if (Nav.SectorTree != null)
|
||||
{
|
||||
treestack.Push(Nav.SectorTree);
|
||||
}
|
||||
while (treestack.Count > 0)
|
||||
{
|
||||
var sector = treestack.Pop();
|
||||
if (sector.Data != null)
|
||||
{
|
||||
var points = sector.Data.Points;
|
||||
if (points != null)
|
||||
{
|
||||
if (Points == null)
|
||||
{
|
||||
Points = new List<YnvPoint>();
|
||||
}
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
YnvPoint point = new YnvPoint();
|
||||
point.Init(this, points[i]);
|
||||
point.Index = pointi; pointi++;
|
||||
point.Position = posoffset + point._RawData.Position * aabbsize;
|
||||
Points.Add(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sector.SubTree1 != null) treestack.Push(sector.SubTree1);
|
||||
if (sector.SubTree2 != null) treestack.Push(sector.SubTree2);
|
||||
if (sector.SubTree3 != null) treestack.Push(sector.SubTree3);
|
||||
if (sector.SubTree4 != null) treestack.Push(sector.SubTree4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
InitFromNav();
|
||||
|
||||
UpdateAllNodePositions();
|
||||
|
||||
@ -200,16 +109,119 @@ namespace CodeWalker.GameFiles
|
||||
LoadQueued = true;
|
||||
}
|
||||
|
||||
public void InitFromNav()
|
||||
{
|
||||
if (Nav == null) return;
|
||||
|
||||
Vector3 posoffset = Nav.SectorTree?.AABBMin.XYZ() ?? Vector3.Zero;
|
||||
Vector3 aabbsize = Nav.AABBSize;
|
||||
|
||||
if (Nav.Vertices != null)
|
||||
{
|
||||
var verts = Nav.Vertices.GetFullList();
|
||||
Vertices = new List<Vector3>(verts.Count);
|
||||
for (int i = 0; i < verts.Count; i++)
|
||||
{
|
||||
var ov = verts[i].ToVector3();
|
||||
Vertices.Add(posoffset + ov * aabbsize);
|
||||
}
|
||||
}
|
||||
if (Nav.Indices != null)
|
||||
{
|
||||
Indices = Nav.Indices.GetFullList();
|
||||
}
|
||||
if (Nav.Edges != null)
|
||||
{
|
||||
var edges = Nav.Edges.GetFullList();
|
||||
Edges = new List<YnvEdge>(edges.Count);
|
||||
for (int i = 0; i < edges.Count; i++)
|
||||
{
|
||||
YnvEdge edge = new YnvEdge();
|
||||
edge.Init(this, edges[i]);
|
||||
Edges.Add(edge);
|
||||
}
|
||||
}
|
||||
if (Nav.Polys != null)
|
||||
{
|
||||
var polys = Nav.Polys.GetFullList();
|
||||
Polys = new List<YnvPoly>(polys.Count);
|
||||
for (int i = 0; i < polys.Count; i++)
|
||||
{
|
||||
YnvPoly poly = new YnvPoly();
|
||||
poly.Init(this, polys[i]);
|
||||
poly.Index = i;
|
||||
Polys.Add(poly);
|
||||
}
|
||||
}
|
||||
if (Nav.Portals != null)
|
||||
{
|
||||
var portals = Nav.Portals;
|
||||
Portals = new List<YnvPortal>(portals.Length);
|
||||
for (int i = 0; i < portals.Length; i++)
|
||||
{
|
||||
YnvPortal portal = new YnvPortal();
|
||||
portal.Init(this, portals[i]);
|
||||
portal.Index = i;
|
||||
portal.PositionFrom = posoffset + portal._RawData.PositionFrom.ToVector3() * aabbsize;
|
||||
portal.PositionTo = posoffset + portal._RawData.PositionTo.ToVector3() * aabbsize;
|
||||
Portals.Add(portal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////### add points to the list and calculate positions...
|
||||
var treestack = new Stack<NavMeshSector>();
|
||||
var pointi = 0;
|
||||
if (Nav.SectorTree != null)
|
||||
{
|
||||
treestack.Push(Nav.SectorTree);
|
||||
}
|
||||
while (treestack.Count > 0)
|
||||
{
|
||||
var sector = treestack.Pop();
|
||||
if (sector.Data != null)
|
||||
{
|
||||
var points = sector.Data.Points;
|
||||
if (points != null)
|
||||
{
|
||||
if (Points == null)
|
||||
{
|
||||
Points = new List<YnvPoint>();
|
||||
}
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
YnvPoint point = new YnvPoint();
|
||||
point.Init(this, points[i]);
|
||||
point.Index = pointi; pointi++;
|
||||
point.Position = posoffset + point._RawData.Position * aabbsize;
|
||||
Points.Add(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sector.SubTree1 != null) treestack.Push(sector.SubTree1);
|
||||
if (sector.SubTree2 != null) treestack.Push(sector.SubTree2);
|
||||
if (sector.SubTree3 != null) treestack.Push(sector.SubTree3);
|
||||
if (sector.SubTree4 != null) treestack.Push(sector.SubTree4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
BuildStructs();
|
||||
if (BuildStructsOnSave)
|
||||
{
|
||||
BuildStructs();
|
||||
}
|
||||
|
||||
byte[] data = ResourceBuilder.Build(Nav, 2); //ynv is version 2...
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
private void BuildStructs()
|
||||
{
|
||||
Vector3 posoffset = Nav.SectorTree?.AABBMin.XYZ() ?? Vector3.Zero;
|
||||
@ -326,7 +338,8 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
var point = Points[i];
|
||||
var pdata = point.RawData;
|
||||
pdata.Position = point.Position;
|
||||
pdata.Position = (point.Position - posoffset) * aabbsizeinv;
|
||||
point.RawData = pdata;
|
||||
}
|
||||
}
|
||||
|
||||
@ -398,8 +411,9 @@ namespace CodeWalker.GameFiles
|
||||
root.SetAABBs(orig.AABBMin.XYZ(), orig.AABBMax.XYZ());
|
||||
|
||||
uint pointindex = 0;
|
||||
var pointflags = new bool[Points?.Count ?? 0];
|
||||
|
||||
BuildSectorTree(root, depth, ref pointindex);
|
||||
BuildSectorTree(root, depth, ref pointindex, pointflags);
|
||||
|
||||
Nav.SectorTree = root;
|
||||
|
||||
@ -418,13 +432,12 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
|
||||
|
||||
private void BuildSectorTree(NavMeshSector node, int depth, ref uint pointindex)
|
||||
private void BuildSectorTree(NavMeshSector node, int depth, ref uint pointindex, bool[] pointflags)
|
||||
{
|
||||
Vector3 min = node.AABBMin.XYZ();
|
||||
Vector3 max = node.AABBMax.XYZ();
|
||||
Vector3 cen = (min + max) * 0.5f;
|
||||
|
||||
//totbytes += (uint)node.BlockLength;
|
||||
|
||||
if (depth <= 0)
|
||||
{
|
||||
@ -434,7 +447,6 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
data.PointsStartID = pointindex;
|
||||
|
||||
//totbytes += (uint)data.BlockLength;
|
||||
|
||||
if (Polys != null)
|
||||
{
|
||||
@ -452,7 +464,6 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
data.PolyIDs = polyids.ToArray();
|
||||
}
|
||||
//totbytes += (uint)(polyids.Count * 2);
|
||||
}
|
||||
|
||||
if (Points != null)
|
||||
@ -461,17 +472,18 @@ namespace CodeWalker.GameFiles
|
||||
for (int i = 0; i < Points.Count; i++)
|
||||
{
|
||||
var point = Points[i];
|
||||
if (IsInBox(point.Position, min, max))
|
||||
if (IsInBox(point.Position, min, max, true) && (pointflags[i] == false))
|
||||
{
|
||||
points.Add(point.RawData);
|
||||
pointflags[i] = true;
|
||||
}
|
||||
}
|
||||
if (points.Count > 0)
|
||||
{
|
||||
data.Points = points.ToArray();
|
||||
data.PointsCount = (ushort)points.Count;
|
||||
pointindex += (uint)points.Count;
|
||||
}
|
||||
//totbytes += (uint)(points.Count * 8);
|
||||
}
|
||||
|
||||
}
|
||||
@ -487,18 +499,97 @@ namespace CodeWalker.GameFiles
|
||||
node.SubTree2.SetAABBs(new Vector3(cen.X, min.Y, 0.0f), new Vector3(max.X, cen.Y, 0.0f));
|
||||
node.SubTree3.SetAABBs(new Vector3(min.X, min.Y, min.Z), new Vector3(cen.X, cen.Y, cen.Z));
|
||||
node.SubTree4.SetAABBs(new Vector3(min.X, cen.Y, 0.0f), new Vector3(cen.X, max.Y, 0.0f));
|
||||
BuildSectorTree(node.SubTree1, cdepth, ref pointindex);
|
||||
BuildSectorTree(node.SubTree2, cdepth, ref pointindex);
|
||||
BuildSectorTree(node.SubTree3, cdepth, ref pointindex);
|
||||
BuildSectorTree(node.SubTree4, cdepth, ref pointindex);
|
||||
BuildSectorTree(node.SubTree1, cdepth, ref pointindex, pointflags);
|
||||
BuildSectorTree(node.SubTree2, cdepth, ref pointindex, pointflags);
|
||||
BuildSectorTree(node.SubTree3, cdepth, ref pointindex, pointflags);
|
||||
BuildSectorTree(node.SubTree4, cdepth, ref pointindex, pointflags);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsInBox(Vector3 p, Vector3 min, Vector3 max)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void WriteXml(StringBuilder sb, int indent)
|
||||
{
|
||||
return (p.X >= min.X) && (p.X < max.X) &&
|
||||
(p.Y >= min.Y) && (p.Y < max.Y);// &&
|
||||
//(p.Z >= min.Z) && (p.Z < max.Z);
|
||||
YnvXml.StringTag(sb, indent, "ContentFlags", Nav.ContentFlags.ToString());
|
||||
YnvXml.ValueTag(sb, indent, "AreaID", AreaID.ToString());
|
||||
YnvXml.SelfClosingTag(sb, indent, "BBMin " + FloatUtil.GetVector3XmlString(Nav.AABBMin));
|
||||
YnvXml.SelfClosingTag(sb, indent, "BBMax " + FloatUtil.GetVector3XmlString(Nav.AABBMax));
|
||||
YnvXml.SelfClosingTag(sb, indent, "BBSize " + FloatUtil.GetVector3XmlString(Nav.AABBSize));
|
||||
YnvXml.WriteItemArray(sb, AllPolys, indent, "Polygons");
|
||||
YnvXml.WriteItemArray(sb, AllPortals, indent, "Portals");
|
||||
YnvXml.WriteItemArray(sb, AllPoints, indent, "Points");
|
||||
}
|
||||
public void ReadXml(XmlNode node)
|
||||
{
|
||||
Nav = new NavMesh();
|
||||
Nav.SectorTree = new NavMeshSector();
|
||||
Nav.ContentFlags = Xml.GetChildEnumInnerText<NavMeshFlags>(node, "ContentFlags");
|
||||
Nav.AreaID = Xml.GetChildUIntAttribute(node, "AreaID");
|
||||
Nav.AABBMin = Xml.GetChildVector3Attributes(node, "BBMin");
|
||||
Nav.AABBMax = Xml.GetChildVector3Attributes(node, "BBMax");
|
||||
Nav.AABBSize = Xml.GetChildVector3Attributes(node, "BBSize");
|
||||
Polys = XmlYnv.ReadItemList<YnvPoly>(node, "Polygons");
|
||||
Portals = XmlYnv.ReadItemList<YnvPortal>(node, "Portals");
|
||||
Points = XmlYnv.ReadItemList<YnvPoint>(node, "Points");
|
||||
|
||||
if (Polys != null)
|
||||
{
|
||||
for (int i = 0; i < Polys.Count; i++)
|
||||
{
|
||||
var poly = Polys[i];
|
||||
poly.Ynv = this;
|
||||
poly.Index = i;
|
||||
poly.AreaID = (ushort)AreaID;
|
||||
}
|
||||
}
|
||||
if (Portals != null)
|
||||
{
|
||||
for (int i = 0; i < Portals.Count; i++)
|
||||
{
|
||||
var portal = Portals[i];
|
||||
portal.Ynv = this;
|
||||
portal.Index = i;
|
||||
portal.AreaIDFrom = (ushort)AreaID;
|
||||
portal.AreaIDTo = (ushort)AreaID;
|
||||
}
|
||||
}
|
||||
if (Points != null)
|
||||
{
|
||||
for (int i = 0; i < Points.Count; i++)
|
||||
{
|
||||
var point = Points[i];
|
||||
point.Ynv = this;
|
||||
point.Index = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool vehicle = ((Nav.ContentFlags & NavMeshFlags.Vehicle) != 0);
|
||||
Nav.VersionUnk1 = 0x00010011;
|
||||
Nav.VersionUnk2 = vehicle ? 0 : 0x85CB3561;
|
||||
Nav.Transform = Matrix.Identity;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private bool IsInBox(Vector3 p, Vector3 min, Vector3 max, bool outer)
|
||||
{
|
||||
if (outer)
|
||||
return (p.X >= min.X) && (p.X <= max.X) &&
|
||||
(p.Y >= min.Y) && (p.Y <= max.Y);// &&
|
||||
//(p.Z >= min.Z) && (p.Z < max.Z);
|
||||
else
|
||||
return (p.X >= min.X) && (p.X < max.X) &&
|
||||
(p.Y >= min.Y) && (p.Y < max.Y);// &&
|
||||
//(p.Z >= min.Z) && (p.Z < max.Z);
|
||||
}
|
||||
private bool BoxOverlaps(Vector3 bmin, Vector3 bmax, Vector3 min, Vector3 max)
|
||||
{
|
||||
@ -528,19 +619,6 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
|
||||
public void UpdateContentFlags(bool vehicle)
|
||||
{
|
||||
NavMeshFlags f = NavMeshFlags.None;
|
||||
//if (Nav.VerticesCount > 0) f = f | NavMeshFlags.Vertices;
|
||||
//if (Nav.PortalsCount > 0) f = f | NavMeshFlags.Portals;
|
||||
if (Polys?.Count > 0) f = f | NavMeshFlags.Vertices;
|
||||
if (Portals?.Count > 0) f = f | NavMeshFlags.Portals;
|
||||
if (vehicle) f = f | NavMeshFlags.Vehicle;
|
||||
else f = f | NavMeshFlags.Unknown8;
|
||||
Nav.ContentFlags = f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void UpdateAllNodePositions()
|
||||
{
|
||||
@ -636,6 +714,19 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
|
||||
public void UpdateContentFlags(bool vehicle)
|
||||
{
|
||||
NavMeshFlags f = NavMeshFlags.None;
|
||||
if (Polys?.Count > 0) f = f | NavMeshFlags.Polygons;
|
||||
if (Portals?.Count > 0) f = f | NavMeshFlags.Portals;
|
||||
if (vehicle) f = f | NavMeshFlags.Vehicle;
|
||||
else f = f | NavMeshFlags.Unknown8; //what exactly is this?
|
||||
Nav.ContentFlags = f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void BuildBVH()
|
||||
{
|
||||
var nodes = new List<BasePathNode>();
|
||||
@ -662,7 +753,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvPoly
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvPoly : IMetaXmlItem
|
||||
{
|
||||
public NavMeshPoly _RawData;
|
||||
public NavMeshPoly RawData { get { return _RawData; } set { _RawData = value; } }
|
||||
@ -673,45 +764,45 @@ namespace CodeWalker.GameFiles
|
||||
public ushort PartID { get { return _RawData.PartID; } set { _RawData.PartID = value; } }
|
||||
public uint PortalLinkID { get { return _RawData.PortalLinkID; } set { _RawData.PortalLinkID = value; } }
|
||||
public byte PortalLinkCount { get { return _RawData.PortalLinkCount; } set { _RawData.PortalLinkCount = value; } }
|
||||
public byte Flags1 { get { return (byte)(_RawData.Unknown_00h & 0xFF); } set { _RawData.Unknown_00h = (ushort)((_RawData.Unknown_00h & 0xFF00) | (value & 0xFF)); } }
|
||||
public byte Flags2 { get { return (byte)((_RawData.Unknown_24h.Value >> 0) & 0xFF); } set { _RawData.Unknown_24h = ((_RawData.Unknown_24h.Value & 0xFFFFFF00u) | ((value & 0xFFu) << 0)); } }
|
||||
public byte Flags3 { get { return (byte)((_RawData.Unknown_24h.Value >> 9) & 0xFF); } set { _RawData.Unknown_24h = ((_RawData.Unknown_24h.Value & 0xFFFE01FFu) | ((value & 0xFFu) << 9)); } }
|
||||
public byte Flags4 { get { return (byte)((_RawData.Unknown_28h.Value >> 16) & 0xFF); } set { _RawData.Unknown_28h = ((_RawData.Unknown_28h.Value & 0x0000FFFFu) | ((value & 0xFFu) << 16)); } }
|
||||
public bool B00_AvoidUnk { get { return (_RawData.Unknown_00h & 1) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 0, value); } }
|
||||
public bool B01_AvoidUnk { get { return (_RawData.Unknown_00h & 2) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 1, value); } }
|
||||
public bool B02_IsFootpath { get { return (_RawData.Unknown_00h & 4) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 2, value); } }
|
||||
public bool B03_IsUnderground { get { return (_RawData.Unknown_00h & 8) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 3, value); } }
|
||||
//public bool B04_Unused { get { return (_RawData.Unknown_00h & 16) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 4, value); } }
|
||||
//public bool B05_Unused { get { return (_RawData.Unknown_00h & 32) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 5, value); } }
|
||||
public bool B06_SteepSlope { get { return (_RawData.Unknown_00h & 64) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 6, value); } }
|
||||
public bool B07_IsWater { get { return (_RawData.Unknown_00h & 128) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 7, value); } }
|
||||
public bool B08_UndergroundUnk0 { get { return (_RawData.Unknown_24h.Value & 1) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 0, value); } }
|
||||
public bool B09_UndergroundUnk1 { get { return (_RawData.Unknown_24h.Value & 2) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 1, value); } }
|
||||
public bool B10_UndergroundUnk2 { get { return (_RawData.Unknown_24h.Value & 4) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 2, value); } }
|
||||
public bool B11_UndergroundUnk3 { get { return (_RawData.Unknown_24h.Value & 8) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 3, value); } }
|
||||
//public bool B12_Unused { get { return (_RawData.Unknown_24h.Value & 16) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 4, value); } }
|
||||
public bool B13_HasPathNode { get { return (_RawData.Unknown_24h.Value & 32) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 5, value); } }
|
||||
public bool B14_IsInterior { get { return (_RawData.Unknown_24h.Value & 64) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 6, value); } }
|
||||
public bool B15_InteractionUnk { get { return (_RawData.Unknown_24h.Value & 128) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 7, value); } }
|
||||
//public bool B16_Unused { get { return (_RawData.Unknown_24h.Value & 256) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 8, value); } }
|
||||
public bool B17_IsFlatGround { get { return (_RawData.Unknown_24h.Value & 512) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 9, value); } }
|
||||
public bool B18_IsRoad { get { return (_RawData.Unknown_24h.Value & 1024) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 10, value); } }
|
||||
public bool B19_IsCellEdge { get { return (_RawData.Unknown_24h.Value & 2048) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 11, value); } }
|
||||
public bool B20_IsTrainTrack { get { return (_RawData.Unknown_24h.Value & 4096) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 12, value); } }
|
||||
public bool B21_IsShallowWater { get { return (_RawData.Unknown_24h.Value & 8192) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 13, value); } }
|
||||
public bool B22_FootpathUnk1 { get { return (_RawData.Unknown_24h.Value & 16384) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 14, value); } }
|
||||
public bool B23_FootpathUnk2 { get { return (_RawData.Unknown_24h.Value & 32768) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 15, value); } }
|
||||
public bool B24_FootpathMall { get { return (_RawData.Unknown_24h.Value & 65536) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 16, value); } }
|
||||
public bool B25_SlopeSouth { get { return (_RawData.Unknown_28h.Value & 65536) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 16, value); } }
|
||||
public bool B26_SlopeSouthEast { get { return (_RawData.Unknown_28h.Value & 131072) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 17, value); } }
|
||||
public bool B27_SlopeEast { get { return (_RawData.Unknown_28h.Value & 262144) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 18, value); } }
|
||||
public bool B28_SlopeNorthEast { get { return (_RawData.Unknown_28h.Value & 524288) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 19, value); } }
|
||||
public bool B29_SlopeNorth { get { return (_RawData.Unknown_28h.Value & 1048576) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 20, value); } }
|
||||
public bool B30_SlopeNorthWest { get { return (_RawData.Unknown_28h.Value & 2097152) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 21, value); } }
|
||||
public bool B31_SlopeWest { get { return (_RawData.Unknown_28h.Value & 4194304) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 22, value); } }
|
||||
public bool B32_SlopeSouthWest { get { return (_RawData.Unknown_28h.Value & 8388608) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 23, value); } }
|
||||
public byte UnkX { get { return _RawData.Unknown_28h_8a; } set { _RawData.Unknown_28h_8a = value; } }
|
||||
public byte UnkY { get { return _RawData.Unknown_28h_8b; } set { _RawData.Unknown_28h_8b = value; } }
|
||||
public byte Flags1 { get { return _RawData.Flags1; } set { _RawData.Flags1 = value; } }
|
||||
public byte Flags2 { get { return _RawData.Flags2; } set { _RawData.Flags2 = value; } }
|
||||
public byte Flags3 { get { return _RawData.Flags3; } set { _RawData.Flags3 = value; } }
|
||||
public byte Flags4 { get { return _RawData.Flags4; } set { _RawData.Flags4 = value; } }
|
||||
public bool B00_AvoidUnk { get { return (_RawData.PolyFlags0 & 1) > 0; } set { _RawData.PolyFlags0 = (ushort)BitUtil.UpdateBit(_RawData.PolyFlags0, 0, value); } }
|
||||
public bool B01_AvoidUnk { get { return (_RawData.PolyFlags0 & 2) > 0; } set { _RawData.PolyFlags0 = (ushort)BitUtil.UpdateBit(_RawData.PolyFlags0, 1, value); } }
|
||||
public bool B02_IsFootpath { get { return (_RawData.PolyFlags0 & 4) > 0; } set { _RawData.PolyFlags0 = (ushort)BitUtil.UpdateBit(_RawData.PolyFlags0, 2, value); } }
|
||||
public bool B03_IsUnderground { get { return (_RawData.PolyFlags0 & 8) > 0; } set { _RawData.PolyFlags0 = (ushort)BitUtil.UpdateBit(_RawData.PolyFlags0, 3, value); } }
|
||||
public bool B04_Unused { get { return (_RawData.PolyFlags0 & 16) > 0; } set { _RawData.PolyFlags0 = (ushort)BitUtil.UpdateBit(_RawData.PolyFlags0, 4, value); } }
|
||||
public bool B05_Unused { get { return (_RawData.PolyFlags0 & 32) > 0; } set { _RawData.PolyFlags0 = (ushort)BitUtil.UpdateBit(_RawData.PolyFlags0, 5, value); } }
|
||||
public bool B06_SteepSlope { get { return (_RawData.PolyFlags0 & 64) > 0; } set { _RawData.PolyFlags0 = (ushort)BitUtil.UpdateBit(_RawData.PolyFlags0, 6, value); } }
|
||||
public bool B07_IsWater { get { return (_RawData.PolyFlags0 & 128) > 0; } set { _RawData.PolyFlags0 = (ushort)BitUtil.UpdateBit(_RawData.PolyFlags0, 7, value); } }
|
||||
public bool B08_UndergroundUnk0 { get { return (_RawData.PolyFlags1 & 1) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 0, value); } }
|
||||
public bool B09_UndergroundUnk1 { get { return (_RawData.PolyFlags1 & 2) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 1, value); } }
|
||||
public bool B10_UndergroundUnk2 { get { return (_RawData.PolyFlags1 & 4) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 2, value); } }
|
||||
public bool B11_UndergroundUnk3 { get { return (_RawData.PolyFlags1 & 8) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 3, value); } }
|
||||
public bool B12_Unused { get { return (_RawData.PolyFlags1 & 16) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 4, value); } }
|
||||
public bool B13_HasPathNode { get { return (_RawData.PolyFlags1 & 32) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 5, value); } }
|
||||
public bool B14_IsInterior { get { return (_RawData.PolyFlags1 & 64) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 6, value); } }
|
||||
public bool B15_InteractionUnk { get { return (_RawData.PolyFlags1 & 128) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 7, value); } }
|
||||
public bool B16_Unused { get { return (_RawData.PolyFlags1 & 256) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 8, value); } }
|
||||
public bool B17_IsFlatGround { get { return (_RawData.PolyFlags1 & 512) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 9, value); } }
|
||||
public bool B18_IsRoad { get { return (_RawData.PolyFlags1 & 1024) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 10, value); } }
|
||||
public bool B19_IsCellEdge { get { return (_RawData.PolyFlags1 & 2048) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 11, value); } }
|
||||
public bool B20_IsTrainTrack { get { return (_RawData.PolyFlags1 & 4096) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 12, value); } }
|
||||
public bool B21_IsShallowWater { get { return (_RawData.PolyFlags1 & 8192) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 13, value); } }
|
||||
public bool B22_FootpathUnk1 { get { return (_RawData.PolyFlags1 & 16384) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 14, value); } }
|
||||
public bool B23_FootpathUnk2 { get { return (_RawData.PolyFlags1 & 32768) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 15, value); } }
|
||||
public bool B24_FootpathMall { get { return (_RawData.PolyFlags1 & 65536) > 0; } set { _RawData.PolyFlags1 = BitUtil.UpdateBit(_RawData.PolyFlags1, 16, value); } }
|
||||
public bool B25_SlopeSouth { get { return (_RawData.PolyFlags2 & 65536) > 0; } set { _RawData.PolyFlags2 = BitUtil.UpdateBit(_RawData.PolyFlags2, 16, value); } }
|
||||
public bool B26_SlopeSouthEast { get { return (_RawData.PolyFlags2 & 131072) > 0; } set { _RawData.PolyFlags2 = BitUtil.UpdateBit(_RawData.PolyFlags2, 17, value); } }
|
||||
public bool B27_SlopeEast { get { return (_RawData.PolyFlags2 & 262144) > 0; } set { _RawData.PolyFlags2 = BitUtil.UpdateBit(_RawData.PolyFlags2, 18, value); } }
|
||||
public bool B28_SlopeNorthEast { get { return (_RawData.PolyFlags2 & 524288) > 0; } set { _RawData.PolyFlags2 = BitUtil.UpdateBit(_RawData.PolyFlags2, 19, value); } }
|
||||
public bool B29_SlopeNorth { get { return (_RawData.PolyFlags2 & 1048576) > 0; } set { _RawData.PolyFlags2 = BitUtil.UpdateBit(_RawData.PolyFlags2, 20, value); } }
|
||||
public bool B30_SlopeNorthWest { get { return (_RawData.PolyFlags2 & 2097152) > 0; } set { _RawData.PolyFlags2 = BitUtil.UpdateBit(_RawData.PolyFlags2, 21, value); } }
|
||||
public bool B31_SlopeWest { get { return (_RawData.PolyFlags2 & 4194304) > 0; } set { _RawData.PolyFlags2 = BitUtil.UpdateBit(_RawData.PolyFlags2, 22, value); } }
|
||||
public bool B32_SlopeSouthWest { get { return (_RawData.PolyFlags2 & 8388608) > 0; } set { _RawData.PolyFlags2 = BitUtil.UpdateBit(_RawData.PolyFlags2, 23, value); } }
|
||||
public byte UnkX { get { return _RawData.UnkX; } set { _RawData.UnkX = value; } }
|
||||
public byte UnkY { get { return _RawData.UnkY; } set { _RawData.UnkY = value; } }
|
||||
|
||||
|
||||
public Vector3 Position { get; set; }
|
||||
@ -805,7 +896,7 @@ namespace CodeWalker.GameFiles
|
||||
public Color4 GetColour()
|
||||
{
|
||||
var colour = new Color4();
|
||||
var u0 = _RawData.Unknown_00h;
|
||||
var u0 = _RawData.PolyFlags0;
|
||||
if ((u0 & 1) > 0) colour.Red += 0.01f;//avoid? loiter?
|
||||
if ((u0 & 2) > 0) colour.Red += 0.01f; //avoid?
|
||||
if ((u0 & 4) > 0) colour.Green += 0.25f; //ped/footpath
|
||||
@ -816,7 +907,7 @@ namespace CodeWalker.GameFiles
|
||||
if ((u0 & 128) > 0) colour.Blue += 0.25f; //water
|
||||
//if (u0 >= 256) colour.Green += 1.0f;//other bits unused...
|
||||
|
||||
var u2 = _RawData.Unknown_24h.Value;
|
||||
var u2 = _RawData.PolyFlags1;
|
||||
//colour.Green = (u2 & 15) / 15.0f; //maybe underground amount..?
|
||||
//if ((u2 & 1) > 0) colour.Blue += 1.0f; //peds interact with something? underground?
|
||||
//if ((u2 & 2) > 0) colour.Green += 1.0f;//underneath something?
|
||||
@ -837,7 +928,7 @@ namespace CodeWalker.GameFiles
|
||||
if ((u2 & 65536) > 0) colour.Green = 0.2f;//footpaths - mall areas? eg mall, vinewood blvd
|
||||
//if (u2 >= 131072) { }//other bits unused
|
||||
|
||||
var u5 = _RawData.Unknown_28h.Value; //32 bits
|
||||
var u5 = _RawData.PolyFlags2; //32 bits
|
||||
//colour.Red = poly.Unknown_28h_8a / 255.0f; //heuristic vals..?
|
||||
//colour.Green = poly.Unknown_28h_8b / 255.0f; //heuristic vals..?
|
||||
//if ((u5 & 65536) > 0) colour.Red += 1.0f; //slope facing -Y (south)
|
||||
@ -904,13 +995,83 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
|
||||
|
||||
public void WriteXml(StringBuilder sb, int indent)
|
||||
{
|
||||
byte[] flags = { Flags1, Flags2, Flags3, Flags4, UnkX, UnkY };
|
||||
YnvXml.WriteRawArray(sb, flags, indent, "Flags", "");
|
||||
YnvXml.WriteRawArray(sb, Vertices, indent, "Vertices", "", YnvXml.FormatVector3, 1);
|
||||
var cind = indent + 1;
|
||||
YnvXml.OpenTag(sb, indent, "Edges");
|
||||
foreach (var e in Edges)
|
||||
{
|
||||
YnvXml.Indent(sb, cind);
|
||||
sb.AppendFormat("{0}:{1}, {2}:{3}", e.AreaID1, e.PolyID1, e.AreaID2, e.PolyID2);
|
||||
sb.AppendLine();
|
||||
}
|
||||
YnvXml.CloseTag(sb, indent, "Edges");
|
||||
if ((PortalLinks != null) && (PortalLinks.Length > 0))
|
||||
{
|
||||
YnvXml.WriteRawArray(sb, PortalLinks, indent, "Portals", "");
|
||||
}
|
||||
}
|
||||
public void ReadXml(XmlNode node)
|
||||
{
|
||||
var flags = Xml.GetChildRawByteArrayNullable(node, "Flags", 10);
|
||||
if (flags != null)
|
||||
{
|
||||
Flags1 = (flags.Length > 0) ? flags[0] : (byte)0;
|
||||
Flags2 = (flags.Length > 1) ? flags[1] : (byte)0;
|
||||
Flags3 = (flags.Length > 2) ? flags[2] : (byte)0;
|
||||
Flags4 = (flags.Length > 3) ? flags[3] : (byte)0;
|
||||
UnkX = (flags.Length > 4) ? flags[4] : (byte)0;
|
||||
UnkY = (flags.Length > 5) ? flags[5] : (byte)0;
|
||||
}
|
||||
Vertices = Xml.GetChildRawVector3Array(node, "Vertices");
|
||||
Indices = new ushort[Vertices?.Length ?? 0];//needs to be present for later
|
||||
var edgesstr = Xml.GetChildInnerText(node, "Edges");
|
||||
var edgesstrarr = edgesstr.Trim().Split('\n');
|
||||
var edges = new List<YnvEdge>();
|
||||
foreach (var edgestr in edgesstrarr)
|
||||
{
|
||||
var estrparts = edgestr.Trim().Split(',');
|
||||
if (estrparts.Length != 2)
|
||||
{ continue; }
|
||||
var estrp0 = estrparts[0].Trim().Split(':');
|
||||
var estrp1 = estrparts[1].Trim().Split(':');
|
||||
if (estrp0.Length != 2)
|
||||
{ continue; }
|
||||
if (estrp1.Length != 2)
|
||||
{ continue; }
|
||||
|
||||
uint aid1, aid2, pid1, pid2;
|
||||
uint.TryParse(estrp0[0].Trim(), out aid1);
|
||||
uint.TryParse(estrp0[1].Trim(), out pid1);
|
||||
uint.TryParse(estrp1[0].Trim(), out aid2);
|
||||
uint.TryParse(estrp1[1].Trim(), out pid2);
|
||||
|
||||
var e = new YnvEdge();
|
||||
e.AreaID1 = aid1;
|
||||
e.AreaID2 = aid2;
|
||||
e.PolyID1 = pid1;
|
||||
e.PolyID2 = pid2;
|
||||
edges.Add(e);
|
||||
}
|
||||
if (edges.Count > 0)
|
||||
{
|
||||
Edges = edges.ToArray();
|
||||
}
|
||||
|
||||
PortalLinks = Xml.GetChildRawUshortArrayNullable(node, "Portals");
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return AreaID.ToString() + ", " + Index.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvPortal : BasePathNode
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvPortal : BasePathNode, IMetaXmlItem
|
||||
{
|
||||
public NavMeshPortal _RawData;
|
||||
|
||||
@ -930,7 +1091,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
set
|
||||
{
|
||||
Angle = (byte)(value * 255.0f / ((float)Math.PI * 2.0f));
|
||||
Angle = (byte)Math.Round(value * 255.0f / ((float)Math.PI * 2.0f));
|
||||
}
|
||||
}
|
||||
public Quaternion Orientation
|
||||
@ -945,15 +1106,15 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
|
||||
public int Index { get; set; }
|
||||
public byte Type { get { return _RawData.Type; } set { _RawData.Type = value; } }
|
||||
public ushort AreaIDFrom { get { return _RawData.AreaIDFrom; } set { _RawData.AreaIDFrom = value; } }
|
||||
public ushort AreaIDTo { get { return _RawData.AreaIDTo; } set { _RawData.AreaIDTo = value; } }
|
||||
public byte Type { get { return _RawData.Type; } set { _RawData.Type = value; } }//1,2,3
|
||||
public ushort AreaIDFrom { get { return _RawData.AreaIDFrom; } set { _RawData.AreaIDFrom = value; } }//always Ynv.AreaID
|
||||
public ushort AreaIDTo { get { return _RawData.AreaIDTo; } set { _RawData.AreaIDTo = value; } }//always Ynv.AreaID
|
||||
public ushort PolyIDFrom1 { get { return _RawData.PolyIDFrom1; } set { _RawData.PolyIDFrom1 = value; } }
|
||||
public ushort PolyIDFrom2 { get { return _RawData.PolyIDFrom2; } set { _RawData.PolyIDFrom2 = value; } }
|
||||
public ushort PolyIDTo1 { get { return _RawData.PolyIDTo1; } set { _RawData.PolyIDTo1 = value; } }
|
||||
public ushort PolyIDTo2 { get { return _RawData.PolyIDTo2; } set { _RawData.PolyIDTo2 = value; } }
|
||||
public ushort Unk1 { get { return _RawData.FlagsUnk; } set { _RawData.FlagsUnk = value; } }
|
||||
public byte Unk2 { get { return _RawData.AreaUnk; } set { _RawData.AreaUnk = value; } }
|
||||
public ushort Unk1 { get { return _RawData.FlagsUnk; } set { _RawData.FlagsUnk = value; } }//always 0
|
||||
public byte Unk2 { get { return _RawData.AreaUnk; } set { _RawData.AreaUnk = value; } }//always 0
|
||||
|
||||
|
||||
public void Init(YnvFile ynv, NavMeshPortal portal)
|
||||
@ -974,13 +1135,32 @@ namespace CodeWalker.GameFiles
|
||||
Orientation = orientation;
|
||||
}
|
||||
|
||||
public void WriteXml(StringBuilder sb, int indent)
|
||||
{
|
||||
YnvXml.ValueTag(sb, indent, "Type", Type.ToString());
|
||||
YnvXml.ValueTag(sb, indent, "Angle", FloatUtil.ToString(Direction));
|
||||
YnvXml.ValueTag(sb, indent, "PolyFrom", PolyIDFrom1.ToString());
|
||||
YnvXml.ValueTag(sb, indent, "PolyTo", PolyIDTo1.ToString());
|
||||
YnvXml.SelfClosingTag(sb, indent, "PositionFrom " + FloatUtil.GetVector3XmlString(PositionFrom));
|
||||
YnvXml.SelfClosingTag(sb, indent, "PositionTo " + FloatUtil.GetVector3XmlString(PositionTo));
|
||||
}
|
||||
public void ReadXml(XmlNode node)
|
||||
{
|
||||
Type = (byte)Xml.GetChildUIntAttribute(node, "Type");
|
||||
Direction = Xml.GetChildFloatAttribute(node, "Angle");
|
||||
PolyIDFrom1 = PolyIDFrom2 = (ushort)Xml.GetChildUIntAttribute(node, "PolyFrom");
|
||||
PolyIDTo1 = PolyIDTo2 = (ushort)Xml.GetChildUIntAttribute(node, "PolyTo");
|
||||
PositionFrom = Xml.GetChildVector3Attributes(node, "PositionFrom");
|
||||
PositionTo = Xml.GetChildVector3Attributes(node, "PositionTo");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Index.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvPoint : BasePathNode
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvPoint : BasePathNode, IMetaXmlItem
|
||||
{
|
||||
public NavMeshPoint _RawData;
|
||||
|
||||
@ -997,7 +1177,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
set
|
||||
{
|
||||
Angle = (byte)(value * 255.0f / ((float)Math.PI * 2.0f));
|
||||
Angle = (byte)Math.Round(value * 255.0f / ((float)Math.PI * 2.0f));
|
||||
}
|
||||
}
|
||||
public Quaternion Orientation
|
||||
@ -1012,7 +1192,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
|
||||
public int Index { get; set; }
|
||||
public byte Type { get { return _RawData.Type; } set { _RawData.Type = value; } }
|
||||
public byte Type { get { return _RawData.Type; } set { _RawData.Type = value; } }//0,1,2,3,4,5,128,171,254
|
||||
|
||||
public void Init(YnvFile ynv, NavMeshPoint point)
|
||||
{
|
||||
@ -1030,11 +1210,23 @@ namespace CodeWalker.GameFiles
|
||||
Orientation = orientation;
|
||||
}
|
||||
|
||||
public void WriteXml(StringBuilder sb, int indent)
|
||||
{
|
||||
YnvXml.ValueTag(sb, indent, "Type", Type.ToString());
|
||||
YnvXml.ValueTag(sb, indent, "Angle", FloatUtil.ToString(Direction));
|
||||
YnvXml.SelfClosingTag(sb, indent, "Position " + FloatUtil.GetVector3XmlString(Position));
|
||||
}
|
||||
public void ReadXml(XmlNode node)
|
||||
{
|
||||
Type = (byte)Xml.GetChildUIntAttribute(node, "Type");
|
||||
Direction = Xml.GetChildFloatAttribute(node, "Angle");
|
||||
Position = Xml.GetChildVector3Attributes(node, "Position");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Index.ToString() + ": " + Type.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1090,4 +1282,83 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public class YnvXml : MetaXmlBase
|
||||
{
|
||||
|
||||
public static string GetXml(YnvFile ynv)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine(XmlHeader);
|
||||
|
||||
if ((ynv != null) && (ynv.Nav != null))
|
||||
{
|
||||
var name = "NavMesh";
|
||||
|
||||
OpenTag(sb, 0, name);
|
||||
|
||||
ynv.WriteXml(sb, 1);
|
||||
|
||||
CloseTag(sb, 0, name);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class XmlYnv
|
||||
{
|
||||
|
||||
public static YnvFile GetYnv(string xml)
|
||||
{
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.LoadXml(xml);
|
||||
return GetYnv(doc);
|
||||
}
|
||||
|
||||
public static YnvFile GetYnv(XmlDocument doc)
|
||||
{
|
||||
YnvFile ynv = new YnvFile();
|
||||
ynv.ReadXml(doc.DocumentElement);
|
||||
return ynv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static List<T> ReadItemList<T>(XmlNode node, string name) where T : IMetaXmlItem, new()
|
||||
{
|
||||
var vnode2 = node.SelectSingleNode(name);
|
||||
if (vnode2 != null)
|
||||
{
|
||||
var inodes = vnode2.SelectNodes("Item");
|
||||
if (inodes?.Count > 0)
|
||||
{
|
||||
var vlist = new List<T>();
|
||||
foreach (XmlNode inode in inodes)
|
||||
{
|
||||
var v = new T();
|
||||
v.ReadXml(inode);
|
||||
vlist.Add(v);
|
||||
}
|
||||
return vlist;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -195,6 +195,7 @@ namespace CodeWalker.GameFiles
|
||||
//TestYdds();
|
||||
//TestYfts();
|
||||
//TestYpts();
|
||||
//TestYnvs();
|
||||
//TestYmaps();
|
||||
//TestPlacements();
|
||||
//TestDrawables();
|
||||
@ -4057,6 +4058,80 @@ namespace CodeWalker.GameFiles
|
||||
if (errorfiles.Count > 0)
|
||||
{ }
|
||||
}
|
||||
public void TestYnvs()
|
||||
{
|
||||
bool xmltest = true;
|
||||
var savetest = false;
|
||||
var errorfiles = new List<RpfEntry>();
|
||||
foreach (RpfFile file in AllRpfs)
|
||||
{
|
||||
foreach (RpfEntry entry in file.AllEntries)
|
||||
{
|
||||
//try
|
||||
{
|
||||
if (entry.NameLower.EndsWith(".ynv"))
|
||||
{
|
||||
UpdateStatus(string.Format(entry.Path));
|
||||
YnvFile ynv = null;
|
||||
try
|
||||
{
|
||||
ynv = RpfMan.GetFile<YnvFile>(entry);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateStatus("Error! " + ex.ToString());
|
||||
errorfiles.Add(entry);
|
||||
}
|
||||
if (xmltest && (ynv != null) && (ynv.Nav != null))
|
||||
{
|
||||
var xml = YnvXml.GetXml(ynv);
|
||||
if (xml != null)
|
||||
{ }
|
||||
var ynv2 = XmlYnv.GetYnv(xml);
|
||||
if (ynv2 != null)
|
||||
{ }
|
||||
var ynv2b = ynv2.Save();
|
||||
if (ynv2b != null)
|
||||
{ }
|
||||
var ynv3 = new YnvFile();
|
||||
RpfFile.LoadResourceFile(ynv3, ynv2b, 2);
|
||||
var xml3 = YnvXml.GetXml(ynv3);
|
||||
if (xml.Length != xml3.Length)
|
||||
{ }
|
||||
var xmllines = xml.Split('\n');
|
||||
var xml3lines = xml3.Split('\n');
|
||||
if (xmllines.Length != xml3lines.Length)
|
||||
{ }
|
||||
}
|
||||
if (savetest && (ynv != null) && (ynv.Nav != null))
|
||||
{
|
||||
var fentry = entry as RpfFileEntry;
|
||||
if (fentry == null)
|
||||
{ continue; } //shouldn't happen
|
||||
|
||||
var bytes = ynv.Save();
|
||||
|
||||
string origlen = TextUtil.GetBytesReadable(fentry.FileSize);
|
||||
string bytelen = TextUtil.GetBytesReadable(bytes.Length);
|
||||
|
||||
var ynv2 = new YnvFile();
|
||||
RpfFile.LoadResourceFile(ynv2, bytes, 2);
|
||||
|
||||
if (ynv2.Nav == null)
|
||||
{ continue; }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// UpdateStatus("Error! " + ex.ToString());
|
||||
//}
|
||||
}
|
||||
}
|
||||
if (errorfiles.Count > 0)
|
||||
{ }
|
||||
}
|
||||
public void TestYmaps()
|
||||
{
|
||||
foreach (RpfFile file in AllRpfs)
|
||||
|
@ -62,6 +62,11 @@ namespace CodeWalker.GameFiles
|
||||
YndFile ynd = RpfFile.GetFile<YndFile>(e, data);
|
||||
return GetXml(ynd, out filename);
|
||||
}
|
||||
else if (fnl.EndsWith(".ynv"))
|
||||
{
|
||||
YnvFile ynv = RpfFile.GetFile<YnvFile>(e, data);
|
||||
return GetXml(ynv, out filename);
|
||||
}
|
||||
else if (fnl.EndsWith(".ycd"))
|
||||
{
|
||||
YcdFile ycd = RpfFile.GetFile<YcdFile>(e, data);
|
||||
@ -172,6 +177,12 @@ namespace CodeWalker.GameFiles
|
||||
filename = fn + ".xml";
|
||||
return YndXml.GetXml(ynd);
|
||||
}
|
||||
public static string GetXml(YnvFile ynv, out string filename)
|
||||
{
|
||||
var fn = (ynv?.RpfFileEntry?.Name) ?? "";
|
||||
filename = fn + ".xml";
|
||||
return YnvXml.GetXml(ynv);
|
||||
}
|
||||
public static string GetXml(YcdFile ycd, out string filename)
|
||||
{
|
||||
var fn = (ycd?.RpfFileEntry?.Name) ?? "";
|
||||
@ -2127,15 +2138,16 @@ namespace CodeWalker.GameFiles
|
||||
CacheFile = 4,
|
||||
AudioRel = 5,
|
||||
Ynd = 6,
|
||||
Ycd = 7,
|
||||
Ybn = 8,
|
||||
Ytd = 9,
|
||||
Ydr = 10,
|
||||
Ydd = 11,
|
||||
Yft = 12,
|
||||
Ypt = 13,
|
||||
Yld = 14,
|
||||
Awc = 15,
|
||||
Ynv = 7,
|
||||
Ycd = 8,
|
||||
Ybn = 9,
|
||||
Ytd = 10,
|
||||
Ydr = 11,
|
||||
Ydd = 12,
|
||||
Yft = 13,
|
||||
Ypt = 14,
|
||||
Yld = 15,
|
||||
Awc = 16,
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
@ -44,12 +45,12 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
public NavMeshFlags ContentFlags { get; set; }
|
||||
public uint VersionUnk1 { get; set; } // 0x00010011
|
||||
public uint VersionUnk1 { get; set; } = 0x00010011; // 0x00010011
|
||||
public uint Unused_018h { get; set; } // 0x00000000
|
||||
public uint Unused_01Ch { get; set; } // 0x00000000
|
||||
public Matrix Transform { get; set; } //(1,0,0,NaN),(0,1,0,NaN),(0,0,1,NaN),(0,0,0,NaN)
|
||||
public Vector3 AABBSize { get; set; }
|
||||
public float AABBUnk { get; set; } // 0x7F800001 //NaN
|
||||
public uint AABBUnk { get; set; } = 0x7F800001; // 0x7F800001 //NaN
|
||||
public ulong VerticesPointer { get; set; }
|
||||
public uint Unused_078h { get; set; } // 0x00000000
|
||||
public uint Unused_07Ch { get; set; } // 0x00000000
|
||||
@ -71,7 +72,7 @@ namespace CodeWalker.GameFiles
|
||||
public uint Unused_154h { get; set; } // 0x00000000
|
||||
public uint Unused_158h { get; set; } // 0x00000000
|
||||
public uint Unused_15Ch { get; set; } // 0x00000000
|
||||
public uint VersionUnk2 { get; set; } //2244687201 (0x85CB3561) for grid ynv's
|
||||
public MetaHash VersionUnk2 { get; set; } //2244687201 (0x85CB3561) for grid ynv's
|
||||
public uint Unused_164h { get; set; } // 0x00000000
|
||||
public uint Unused_168h { get; set; } // 0x00000000
|
||||
public uint Unused_16Ch { get; set; } // 0x00000000
|
||||
@ -92,6 +93,37 @@ namespace CodeWalker.GameFiles
|
||||
private ResourceSystemStructBlock<ushort> PortalLinksBlock = null;
|
||||
|
||||
|
||||
public Vector3 AABBMin
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SectorTree != null) return SectorTree.AABBMin.XYZ();
|
||||
return AABBSize * -0.5f;//shouldn't get here
|
||||
}
|
||||
set
|
||||
{
|
||||
if (SectorTree != null)
|
||||
{
|
||||
SectorTree.AABBMin = new Vector4(value, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
public Vector3 AABBMax
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SectorTree != null) return SectorTree.AABBMax.XYZ();
|
||||
return AABBSize * 0.5f;//shouldn't get here
|
||||
}
|
||||
set
|
||||
{
|
||||
if (SectorTree != null)
|
||||
{
|
||||
SectorTree.AABBMax = new Vector4(value, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override void Read(ResourceDataReader reader, params object[] parameters)
|
||||
@ -104,7 +136,7 @@ namespace CodeWalker.GameFiles
|
||||
Unused_01Ch = reader.ReadUInt32();
|
||||
Transform = reader.ReadMatrix();
|
||||
AABBSize = reader.ReadVector3();
|
||||
AABBUnk = reader.ReadSingle();
|
||||
AABBUnk = reader.ReadUInt32();
|
||||
VerticesPointer = reader.ReadUInt64();
|
||||
Unused_078h = reader.ReadUInt32();
|
||||
Unused_07Ch = reader.ReadUInt32();
|
||||
@ -142,6 +174,43 @@ namespace CodeWalker.GameFiles
|
||||
PortalLinks = reader.ReadUshortsAt(PortalLinksPointer, PortalLinksCount);
|
||||
|
||||
|
||||
|
||||
|
||||
////testing!
|
||||
//if (VersionUnk1 != 0x00010011)
|
||||
//{ }
|
||||
//if (Unused_018h != 0)
|
||||
//{ }
|
||||
//if (Unused_01Ch != 0)
|
||||
//{ }
|
||||
//if (AABBUnk != 0x7F800001)
|
||||
//{ }
|
||||
//if (Unused_078h != 0)
|
||||
//{ }
|
||||
//if (Unused_07Ch != 0)
|
||||
//{ }
|
||||
//if (Unused_154h != 0)
|
||||
//{ }
|
||||
//if (Unused_158h != 0)
|
||||
//{ }
|
||||
//if (Unused_15Ch != 0)
|
||||
//{ }
|
||||
//if (Unused_164h != 0)
|
||||
//{ }
|
||||
//if (Unused_168h != 0)
|
||||
//{ }
|
||||
//if (Unused_16Ch != 0)
|
||||
//{ }
|
||||
//switch (VersionUnk2.Hash)
|
||||
//{
|
||||
// case 0: //vehicle
|
||||
// break;
|
||||
// case 0x85CB3561: //grid
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
//}
|
||||
//UpdateCounts();
|
||||
}
|
||||
|
||||
public override void Write(ResourceDataWriter writer, params object[] parameters)
|
||||
@ -157,38 +226,7 @@ namespace CodeWalker.GameFiles
|
||||
PortalLinksPointer = (ulong)(PortalLinksBlock?.FilePosition ?? 0);
|
||||
|
||||
|
||||
|
||||
//uint totbytes = 0;
|
||||
//Stack<NavMeshSector> sectorstack = new Stack<NavMeshSector>();
|
||||
//if (SectorTree != null) sectorstack.Push(SectorTree);
|
||||
//while (sectorstack.Count > 0)
|
||||
//{
|
||||
// var sector = sectorstack.Pop();
|
||||
// if (sector.SubTree1 != null) sectorstack.Push(sector.SubTree1);
|
||||
// if (sector.SubTree2 != null) sectorstack.Push(sector.SubTree2);
|
||||
// if (sector.SubTree3 != null) sectorstack.Push(sector.SubTree3);
|
||||
// if (sector.SubTree4 != null) sectorstack.Push(sector.SubTree4);
|
||||
// if (sector.Data != null)
|
||||
// {
|
||||
// var sdata = sector.Data;
|
||||
// totbytes += (uint)(sdata.PolyIDsBlock?.BlockLength ?? 0);
|
||||
// totbytes += (uint)(sdata.PointsBlock?.BlockLength ?? 0);
|
||||
// }
|
||||
//}
|
||||
//totbytes += PadSize(VerticesCount * (uint)Vertices.ItemSize);
|
||||
//totbytes += PadSize(EdgesIndicesCount * (uint)Indices.ItemSize);
|
||||
//totbytes += PadSize(EdgesIndicesCount * (uint)Edges.ItemSize);
|
||||
//totbytes += PadSize(PolysCount * (uint)Polys.ItemSize);
|
||||
////totbytes += (uint)BlockLength;
|
||||
//totbytes += (uint)Vertices.ListParts.BlockLength;//Vertices.ListPartsCount * 16;
|
||||
//totbytes += (uint)Indices.ListParts.BlockLength;//Indices.ListPartsCount * 16;
|
||||
//totbytes += (uint)Edges.ListParts.BlockLength;//Edges.ListPartsCount * 16;
|
||||
//totbytes += (uint)Polys.ListParts.BlockLength;//Polys.ListPartsCount * 16;
|
||||
//totbytes += (uint)(PortalsBlock?.BlockLength ?? 0);//PortalsCount * 28;
|
||||
//totbytes += (uint)(PortalLinksBlock?.BlockLength ?? 0);//PortalLinksCount * 2;
|
||||
//int remaining = ((int)TotalBytes) - ((int)totbytes);
|
||||
//if (totbytes != TotalBytes)
|
||||
//{ }
|
||||
UpdateCounts();
|
||||
|
||||
|
||||
writer.Write((uint)ContentFlags);
|
||||
@ -225,13 +263,6 @@ namespace CodeWalker.GameFiles
|
||||
writer.Write(Unused_16Ch);
|
||||
}
|
||||
|
||||
private uint PadSize(uint s)
|
||||
{
|
||||
const uint align = 16;
|
||||
if ((s % align) != 0) s += (align - (s % align));
|
||||
return s;
|
||||
}
|
||||
|
||||
public override IResourceBlock[] GetReferences()
|
||||
{
|
||||
var list = new List<IResourceBlock>(base.GetReferences());
|
||||
@ -261,6 +292,54 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void UpdateCounts()
|
||||
{
|
||||
EdgesIndicesCount = Indices?.ItemCount ?? 0;
|
||||
VerticesCount = Vertices?.ItemCount ?? 0;
|
||||
PolysCount = Polys?.ItemCount ?? 0;
|
||||
PortalsCount = (uint)(Portals?.Length ?? 0);
|
||||
PortalLinksCount = (uint)(PortalLinks?.Length ?? 0);
|
||||
|
||||
|
||||
|
||||
uint totbytes = 0;
|
||||
uint pointcount = 0;
|
||||
var treestack = new Stack<NavMeshSector>();
|
||||
if (SectorTree != null)
|
||||
{
|
||||
treestack.Push(SectorTree);
|
||||
}
|
||||
while (treestack.Count > 0)
|
||||
{
|
||||
var sector = treestack.Pop();
|
||||
totbytes += sector.ByteCount;
|
||||
pointcount += sector.PointCount;
|
||||
if (sector.SubTree1 != null) treestack.Push(sector.SubTree1);
|
||||
if (sector.SubTree2 != null) treestack.Push(sector.SubTree2);
|
||||
if (sector.SubTree3 != null) treestack.Push(sector.SubTree3);
|
||||
if (sector.SubTree4 != null) treestack.Push(sector.SubTree4);
|
||||
}
|
||||
|
||||
totbytes += Vertices?.ByteCount ?? 0;
|
||||
totbytes += Indices?.ByteCount ?? 0;
|
||||
totbytes += Edges?.ByteCount ?? 0;
|
||||
totbytes += Polys?.ByteCount ?? 0;
|
||||
totbytes += PortalsCount * 28;
|
||||
if ((TotalBytes != totbytes) && (TotalBytes != 0))
|
||||
{ }
|
||||
TotalBytes = totbytes;
|
||||
|
||||
|
||||
|
||||
if ((PointsCount != pointcount) && (PointsCount != 0))
|
||||
{ }
|
||||
PointsCount = pointcount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void SetDefaults(bool vehicle)
|
||||
{
|
||||
VersionUnk1 = 0x00010011;
|
||||
@ -449,6 +528,16 @@ namespace CodeWalker.GameFiles
|
||||
private ResourceSystemStructBlock<uint> ListOffsetsBlock = null;
|
||||
public int ItemSize { get { return System.Runtime.InteropServices.Marshal.SizeOf<T>(); } }
|
||||
|
||||
public uint ByteCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return ItemCount * (uint)ItemSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override void Read(ResourceDataReader reader, params object[] parameters)
|
||||
{
|
||||
VFT = reader.ReadUInt32();
|
||||
@ -635,9 +724,9 @@ namespace CodeWalker.GameFiles
|
||||
public void FromVector3(Vector3 v)
|
||||
{
|
||||
const float usmax = ushort.MaxValue;
|
||||
X = (ushort)(v.X * usmax);
|
||||
Y = (ushort)(v.Y * usmax);
|
||||
Z = (ushort)(v.Z * usmax);
|
||||
X = (ushort)Math.Round(v.X * usmax);
|
||||
Y = (ushort)Math.Round(v.Y * usmax);
|
||||
Z = (ushort)Math.Round(v.Z * usmax);
|
||||
}
|
||||
|
||||
public static NavMeshVertex Create(Vector3 v)
|
||||
@ -665,12 +754,12 @@ namespace CodeWalker.GameFiles
|
||||
public Vector3 Min
|
||||
{
|
||||
get { return new Vector3(MinX / 4.0f, MinY / 4.0f, MinZ / 4.0f); }
|
||||
set { var v = value * 4.0f; MinX = (short)v.X; MinY = (short)v.Y; MinZ = (short)v.Z; }
|
||||
set { var v = value * 4.0f; MinX = (short)Math.Floor(v.X); MinY = (short)Math.Floor(v.Y); MinZ = (short)Math.Floor(v.Z); }
|
||||
}
|
||||
public Vector3 Max
|
||||
{
|
||||
get { return new Vector3(MaxX / 4.0f, MaxY / 4.0f, MaxZ / 4.0f); }
|
||||
set { var v = value * 4.0f; MaxX = (short)v.X; MaxY = (short)v.Y; MaxZ = (short)v.Z; }
|
||||
set { var v = value * 4.0f; MaxX = (short)Math.Ceiling(v.X); MaxY = (short)Math.Ceiling(v.Y); MaxZ = (short)Math.Ceiling(v.Z); }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@ -726,17 +815,17 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshPoly
|
||||
{
|
||||
public ushort Unknown_00h { get; set; }
|
||||
public ushort PolyFlags0 { get; set; }
|
||||
public ushort IndexFlags { get; set; }
|
||||
public ushort IndexID { get; set; }
|
||||
public ushort AreaID { get; set; }
|
||||
public ushort AreaID { get; set; } //always current ynv's AreaID
|
||||
public uint Unused_08h { get; set; } // 0x00000000
|
||||
public uint Unused_0Ch { get; set; } // 0x00000000
|
||||
public uint Unused_10h { get; set; } // 0x00000000
|
||||
public uint Unused_14h { get; set; } // 0x00000000
|
||||
public NavMeshAABB CellAABB { get; set; }
|
||||
public FlagsUint Unknown_24h { get; set; }
|
||||
public FlagsUint Unknown_28h { get; set; }
|
||||
public uint PolyFlags1 { get; set; }
|
||||
public uint PolyFlags2 { get; set; }
|
||||
public uint PartFlags { get; set; }
|
||||
|
||||
|
||||
@ -749,22 +838,29 @@ namespace CodeWalker.GameFiles
|
||||
public uint PortalLinkID { get { return ((PartFlags >> 15) & 0x1FFFF); } set { PartFlags = ((PartFlags & 0x7FFF) | ((value & 0x1FFFF) << 15)); } }
|
||||
|
||||
|
||||
public ushort Unknown_28h_16 { get { return (ushort)((Unknown_28h.Value & 0xFFFF)); } set { Unknown_28h = (Unknown_28h.Value & 0xFFFF0000) | (value & 0xFFFFu); } }
|
||||
public byte Unknown_28h_8a { get { return (byte)((Unknown_28h.Value >> 0) & 0xFF); } set { Unknown_28h = (Unknown_28h.Value & 0xFFFFFF00) | ((value & 0xFFu)<<0); } }
|
||||
public byte Unknown_28h_8b { get { return (byte)((Unknown_28h.Value >> 8) & 0xFF); } set { Unknown_28h = (Unknown_28h.Value & 0xFFFF00FF) | ((value & 0xFFu)<<8); } }
|
||||
public byte UnkX { get { return (byte)((PolyFlags2 >> 0) & 0xFF); } set { PolyFlags2 = (PolyFlags2 & 0xFFFFFF00) | ((value & 0xFFu)<<0); } }
|
||||
public byte UnkY { get { return (byte)((PolyFlags2 >> 8) & 0xFF); } set { PolyFlags2 = (PolyFlags2 & 0xFFFF00FF) | ((value & 0xFFu)<<8); } }
|
||||
|
||||
public byte Flags1 { get { return (byte)(PolyFlags0 & 0xFF); } set { PolyFlags0 = (ushort)((PolyFlags0 & 0xFF00) | (value & 0xFF)); } }
|
||||
public byte Flags2 { get { return (byte)((PolyFlags1 >> 0) & 0xFF); } set { PolyFlags1 = ((PolyFlags1 & 0xFFFFFF00u) | ((value & 0xFFu) << 0)); } }
|
||||
public byte Flags3 { get { return (byte)((PolyFlags1 >> 9) & 0xFF); } set { PolyFlags1 = ((PolyFlags1 & 0xFFFE01FFu) | ((value & 0xFFu) << 9)); } }
|
||||
public byte Flags4 { get { return (byte)((PolyFlags2 >> 16) & 0xFF); } set { PolyFlags2 = ((PolyFlags2 & 0xFF00FFFFu) | ((value & 0xFFu) << 16)); } }
|
||||
|
||||
//public uint UnkFlags0 { get { return (uint)((PolyFlags0 >> 8) & 0xFF); } } //always 0
|
||||
//public uint UnkFlags1 { get { return (uint)((PolyFlags1 >> 17) & 0xFFFF); } } //always 0
|
||||
//public uint UnkFlags2 { get { return (uint)((PolyFlags2 >> 24) & 0xFF); } } //always 0
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
//Unknown_28h.Bin + ", (" + Unknown_28h_8a.ToString() + ", " + Unknown_28h_8b.ToString() + "), " +
|
||||
Unknown_00h.ToString() + ", " +
|
||||
PolyFlags0.ToString() + ", " +
|
||||
//IndexFlags.ToString() + ", " +
|
||||
IndexCount.ToString() + ", " + //IndexUnk.ToString() + ", " +
|
||||
IndexID.ToString() + ", " + AreaID.ToString() + ", " +
|
||||
CellAABB.ToString() + ", " +
|
||||
Unknown_24h.Hex + ", " +
|
||||
Unknown_28h.Hex + ", " +
|
||||
//PolyFlags1.ToString() + ", " +
|
||||
//PolyFlags2.ToString() + ", " +
|
||||
//PartFlags.ToString() + ", " + //PartUnk1.ToString() + ", " +
|
||||
PartID.ToString() + ", " +
|
||||
PortalLinkCount.ToString() + ", " +
|
||||
@ -799,6 +895,29 @@ namespace CodeWalker.GameFiles
|
||||
public NavMeshSector SubTree3 { get; set; }
|
||||
public NavMeshSector SubTree4 { get; set; }
|
||||
|
||||
public uint ByteCount
|
||||
{
|
||||
get
|
||||
{
|
||||
uint totbytes = (uint)BlockLength;
|
||||
if (Data != null)
|
||||
{
|
||||
totbytes += ((uint)Data.BlockLength);
|
||||
totbytes += ((uint)Data.PolyIDsCount * 2);
|
||||
totbytes += ((uint)Data.PointsCount * 8);
|
||||
}
|
||||
return totbytes;
|
||||
}
|
||||
}
|
||||
public uint PointCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Data == null) return 0;
|
||||
return Data.PointsCount;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Read(ResourceDataReader reader, params object[] parameters)
|
||||
{
|
||||
AABBMin = reader.ReadVector4();
|
||||
@ -951,7 +1070,7 @@ namespace CodeWalker.GameFiles
|
||||
public ushort Y { get; set; }
|
||||
public ushort Z { get; set; }
|
||||
public byte Angle { get; set; }
|
||||
public byte Type { get; set; }
|
||||
public byte Type { get; set; }//0,1,2,3,4,5,128,171,254
|
||||
|
||||
|
||||
public Vector3 Position
|
||||
@ -964,9 +1083,9 @@ namespace CodeWalker.GameFiles
|
||||
set
|
||||
{
|
||||
const float usmax = ushort.MaxValue;
|
||||
X = (ushort)(value.X * usmax);
|
||||
Y = (ushort)(value.Y * usmax);
|
||||
Z = (ushort)(value.Z * usmax);
|
||||
X = (ushort)Math.Round(value.X * usmax);
|
||||
Y = (ushort)Math.Round(value.Y * usmax);
|
||||
Z = (ushort)Math.Round(value.Z * usmax);
|
||||
}
|
||||
}
|
||||
|
||||
@ -982,20 +1101,20 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshPortal
|
||||
{
|
||||
public byte Type { get; set; }
|
||||
public byte Type { get; set; }//1,2,3
|
||||
public byte Angle { get; set; }
|
||||
public ushort FlagsUnk { get; set; }
|
||||
public ushort FlagsUnk { get; set; }//always 0
|
||||
public NavMeshVertex PositionFrom { get; set; }
|
||||
public NavMeshVertex PositionTo { get; set; }
|
||||
public ushort PolyIDFrom1 { get; set; }
|
||||
public ushort PolyIDFrom2 { get; set; }
|
||||
public ushort PolyIDFrom2 { get; set; } //always same as PolyIDFrom1
|
||||
public ushort PolyIDTo1 { get; set; }
|
||||
public ushort PolyIDTo2 { get; set; }
|
||||
public ushort PolyIDTo2 { get; set; } //always same as PolyIDTo1
|
||||
public uint AreaFlags { get; set; }
|
||||
|
||||
public ushort AreaIDFrom { get { return (ushort)(AreaFlags & 0x3FFF); } set { AreaFlags = (AreaFlags & 0xFFFFC000) | (value & 0x3FFFu); } }
|
||||
public ushort AreaIDTo { get { return (ushort)((AreaFlags >> 14) & 0x3FFF); } set { AreaFlags = (AreaFlags & 0xF0003FFF) | ((value & 0x3FFFu) << 14); } }
|
||||
public byte AreaUnk { get { return (byte)((AreaFlags >> 28) & 0xF); } set { AreaFlags = (AreaFlags & 0x0FFFFFFF) | ((value & 0xFu) << 28); } }
|
||||
public ushort AreaIDFrom { get { return (ushort)(AreaFlags & 0x3FFF); } set { AreaFlags = (AreaFlags & 0xFFFFC000) | (value & 0x3FFFu); } }//always Ynv.AreaID
|
||||
public ushort AreaIDTo { get { return (ushort)((AreaFlags >> 14) & 0x3FFF); } set { AreaFlags = (AreaFlags & 0xF0003FFF) | ((value & 0x3FFFu) << 14); } }//always Ynv.AreaID
|
||||
public byte AreaUnk { get { return (byte)((AreaFlags >> 28) & 0xF); } set { AreaFlags = (AreaFlags & 0x0FFFFFFF) | ((value & 0xFu) << 28); } }//always 0
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
@ -1013,7 +1132,7 @@ namespace CodeWalker.GameFiles
|
||||
[Flags] public enum NavMeshFlags : uint
|
||||
{
|
||||
None = 0,
|
||||
Vertices = 1,
|
||||
Polygons = 1,
|
||||
Portals = 2,
|
||||
Vehicle = 4,
|
||||
Unknown8 = 8,
|
||||
|
@ -274,7 +274,7 @@ namespace CodeWalker
|
||||
InitFileType(".pso", "Metadata (PSO)", 6, FileTypeAction.ViewJPso, true);
|
||||
InitFileType(".gfx", "Scaleform Flash", 7);
|
||||
InitFileType(".ynd", "Path Nodes", 8, FileTypeAction.ViewYnd, true);
|
||||
InitFileType(".ynv", "Nav Mesh", 9, FileTypeAction.ViewModel);
|
||||
InitFileType(".ynv", "Nav Mesh", 9, FileTypeAction.ViewModel, true);
|
||||
InitFileType(".yvr", "Vehicle Record", 9, FileTypeAction.ViewYvr);
|
||||
InitFileType(".ywr", "Waypoint Record", 9, FileTypeAction.ViewYwr);
|
||||
InitFileType(".fxc", "Compiled Shaders", 9, FileTypeAction.ViewFxc);
|
||||
@ -2603,6 +2603,10 @@ namespace CodeWalker
|
||||
{
|
||||
mformat = MetaFormat.Ynd;
|
||||
}
|
||||
if (fnamel.EndsWith(".ynv.xml"))
|
||||
{
|
||||
mformat = MetaFormat.Ynv;
|
||||
}
|
||||
if (fnamel.EndsWith(".ycd.xml"))
|
||||
{
|
||||
mformat = MetaFormat.Ycd;
|
||||
@ -2711,6 +2715,17 @@ namespace CodeWalker
|
||||
data = ynd.Save();
|
||||
break;
|
||||
}
|
||||
case MetaFormat.Ynv:
|
||||
{
|
||||
var ynv = XmlYnv.GetYnv(doc);
|
||||
if (ynv.Nav == null)
|
||||
{
|
||||
MessageBox.Show(fname + ": Schema not supported.", "Cannot import YNV XML");
|
||||
continue;
|
||||
}
|
||||
data = ynv.Save();
|
||||
break;
|
||||
}
|
||||
case MetaFormat.Ycd:
|
||||
{
|
||||
var ycd = XmlYcd.GetYcd(doc);
|
||||
|
24
CodeWalker/Project/Panels/EditYnvPanel.Designer.cs
generated
24
CodeWalker/Project/Panels/EditYnvPanel.Designer.cs
generated
@ -47,7 +47,7 @@
|
||||
this.YnvFlagsUnknownCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.YnvFlagsVehicleCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.YnvFlagsPortalsCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.YnvFlagsVerticesCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.YnvFlagsPolygonsCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.YnvVersionUnkHashTextBox = new System.Windows.Forms.TextBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
@ -200,7 +200,7 @@
|
||||
this.YnvFlagsGroupBox.Controls.Add(this.YnvFlagsUnknownCheckBox);
|
||||
this.YnvFlagsGroupBox.Controls.Add(this.YnvFlagsVehicleCheckBox);
|
||||
this.YnvFlagsGroupBox.Controls.Add(this.YnvFlagsPortalsCheckBox);
|
||||
this.YnvFlagsGroupBox.Controls.Add(this.YnvFlagsVerticesCheckBox);
|
||||
this.YnvFlagsGroupBox.Controls.Add(this.YnvFlagsPolygonsCheckBox);
|
||||
this.YnvFlagsGroupBox.Location = new System.Drawing.Point(247, 48);
|
||||
this.YnvFlagsGroupBox.Name = "YnvFlagsGroupBox";
|
||||
this.YnvFlagsGroupBox.Size = new System.Drawing.Size(103, 115);
|
||||
@ -241,16 +241,16 @@
|
||||
this.YnvFlagsPortalsCheckBox.UseVisualStyleBackColor = true;
|
||||
this.YnvFlagsPortalsCheckBox.CheckedChanged += new System.EventHandler(this.YnvFlagsPortalsCheckBox_CheckedChanged);
|
||||
//
|
||||
// YnvFlagsVerticesCheckBox
|
||||
// YnvFlagsPolygonsCheckBox
|
||||
//
|
||||
this.YnvFlagsVerticesCheckBox.AutoSize = true;
|
||||
this.YnvFlagsVerticesCheckBox.Location = new System.Drawing.Point(12, 19);
|
||||
this.YnvFlagsVerticesCheckBox.Name = "YnvFlagsVerticesCheckBox";
|
||||
this.YnvFlagsVerticesCheckBox.Size = new System.Drawing.Size(64, 17);
|
||||
this.YnvFlagsVerticesCheckBox.TabIndex = 0;
|
||||
this.YnvFlagsVerticesCheckBox.Text = "Vertices";
|
||||
this.YnvFlagsVerticesCheckBox.UseVisualStyleBackColor = true;
|
||||
this.YnvFlagsVerticesCheckBox.CheckedChanged += new System.EventHandler(this.YnvFlagsVerticesCheckBox_CheckedChanged);
|
||||
this.YnvFlagsPolygonsCheckBox.AutoSize = true;
|
||||
this.YnvFlagsPolygonsCheckBox.Location = new System.Drawing.Point(12, 19);
|
||||
this.YnvFlagsPolygonsCheckBox.Name = "YnvFlagsPolygonsCheckBox";
|
||||
this.YnvFlagsPolygonsCheckBox.Size = new System.Drawing.Size(69, 17);
|
||||
this.YnvFlagsPolygonsCheckBox.TabIndex = 0;
|
||||
this.YnvFlagsPolygonsCheckBox.Text = "Polygons";
|
||||
this.YnvFlagsPolygonsCheckBox.UseVisualStyleBackColor = true;
|
||||
this.YnvFlagsPolygonsCheckBox.CheckedChanged += new System.EventHandler(this.YnvFlagsVerticesCheckBox_CheckedChanged);
|
||||
//
|
||||
// YnvVersionUnkHashTextBox
|
||||
//
|
||||
@ -402,7 +402,7 @@
|
||||
private System.Windows.Forms.CheckBox YnvFlagsUnknownCheckBox;
|
||||
private System.Windows.Forms.CheckBox YnvFlagsVehicleCheckBox;
|
||||
private System.Windows.Forms.CheckBox YnvFlagsPortalsCheckBox;
|
||||
private System.Windows.Forms.CheckBox YnvFlagsVerticesCheckBox;
|
||||
private System.Windows.Forms.CheckBox YnvFlagsPolygonsCheckBox;
|
||||
private System.Windows.Forms.TextBox YnvVersionUnkHashTextBox;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
|
@ -87,7 +87,7 @@ namespace CodeWalker.Project.Panels
|
||||
YnvAreaIDYUpDown.Value = Ynv.CellY;
|
||||
YnvAreaIDInfoLabel.Text = "ID: " + Ynv.AreaID.ToString();
|
||||
YnvAABBSizeTextBox.Text = FloatUtil.GetVector3String(nv.AABBSize);
|
||||
YnvFlagsVerticesCheckBox.Checked = nv.ContentFlags.HasFlag(NavMeshFlags.Vertices);
|
||||
YnvFlagsPolygonsCheckBox.Checked = nv.ContentFlags.HasFlag(NavMeshFlags.Polygons);
|
||||
YnvFlagsPortalsCheckBox.Checked = nv.ContentFlags.HasFlag(NavMeshFlags.Portals);
|
||||
YnvFlagsVehicleCheckBox.Checked = nv.ContentFlags.HasFlag(NavMeshFlags.Vehicle);
|
||||
YnvFlagsUnknownCheckBox.Checked = nv.ContentFlags.HasFlag(NavMeshFlags.Unknown8);
|
||||
@ -97,7 +97,7 @@ namespace CodeWalker.Project.Panels
|
||||
YnvPortalLinkCountLabel.Text = "Portal link count: " + nv.PortalLinksCount.ToString();
|
||||
YnvPointCountLabel.Text = "Point count: " + nv.PointsCount.ToString();
|
||||
YnvByteCountLabel.Text = "Byte count: " + nv.TotalBytes.ToString();
|
||||
YnvVersionUnkHashTextBox.Text = nv.VersionUnk2.ToString();
|
||||
YnvVersionUnkHashTextBox.Text = nv.VersionUnk2.Hash.ToString();
|
||||
YnvAdjAreaIDsTextBox.Text = GetAdjAreaIDsString(nv.AdjAreaIDs.Values);
|
||||
populatingui = false;
|
||||
}
|
||||
@ -154,7 +154,7 @@ namespace CodeWalker.Project.Panels
|
||||
{
|
||||
if (populatingui) return;
|
||||
if (Ynv?.Nav == null) return;
|
||||
var verts = YnvFlagsVerticesCheckBox.Checked ? NavMeshFlags.Vertices : NavMeshFlags.None;
|
||||
var verts = YnvFlagsPolygonsCheckBox.Checked ? NavMeshFlags.Polygons : NavMeshFlags.None;
|
||||
var ports = YnvFlagsPortalsCheckBox.Checked ? NavMeshFlags.Portals : NavMeshFlags.None;
|
||||
var vehcs = YnvFlagsVehicleCheckBox.Checked ? NavMeshFlags.Vehicle : NavMeshFlags.None;
|
||||
var unk8s = YnvFlagsUnknownCheckBox.Checked ? NavMeshFlags.Unknown8 : NavMeshFlags.None;
|
||||
|
Loading…
Reference in New Issue
Block a user