mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-26 00:43:00 +08:00
View/edit YND files as XML
This commit is contained in:
parent
fa268ec9c8
commit
ec6eefe0e1
@ -157,6 +157,21 @@ namespace CodeWalker.GameFiles
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static uint TryFindHash(string text)
|
||||||
|
{
|
||||||
|
lock (syncRoot)
|
||||||
|
{
|
||||||
|
foreach (var kvp in Index)
|
||||||
|
{
|
||||||
|
if (kvp.Value == text)
|
||||||
|
{
|
||||||
|
return kvp.Key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
namespace CodeWalker.GameFiles
|
namespace CodeWalker.GameFiles
|
||||||
{
|
{
|
||||||
@ -48,6 +49,7 @@ namespace CodeWalker.GameFiles
|
|||||||
public bool HasChanged { get; set; } = false;
|
public bool HasChanged { get; set; } = false;
|
||||||
public List<string> SaveWarnings = null;
|
public List<string> SaveWarnings = null;
|
||||||
|
|
||||||
|
public bool BuildStructsOnSave { get; set; } = true;
|
||||||
|
|
||||||
|
|
||||||
public YndFile() : base(null, GameFileType.Ynd)
|
public YndFile() : base(null, GameFileType.Ynd)
|
||||||
@ -85,39 +87,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
NodeDictionary = rd.ReadBlock<NodeDictionary>();
|
NodeDictionary = rd.ReadBlock<NodeDictionary>();
|
||||||
|
|
||||||
if (NodeDictionary != null)
|
InitNodesFromDictionary();
|
||||||
{
|
|
||||||
if (NodeDictionary.Nodes != null)
|
|
||||||
{
|
|
||||||
var nodes = NodeDictionary.Nodes;
|
|
||||||
Nodes = new YndNode[nodes.Length];
|
|
||||||
for (int i = 0; i < nodes.Length; i++)
|
|
||||||
{
|
|
||||||
var n = new YndNode();
|
|
||||||
n.Init(this, nodes[i]);
|
|
||||||
Nodes[i] = n;
|
|
||||||
if (n.NodeID != i)
|
|
||||||
{ } //never hit here - nodeid's have to match the index!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((NodeDictionary.JunctionRefs != null) && (NodeDictionary.Junctions != null))
|
|
||||||
{
|
|
||||||
var juncrefs = NodeDictionary.JunctionRefs;
|
|
||||||
var juncs = NodeDictionary.Junctions;
|
|
||||||
Junctions = new YndJunction[juncrefs.Length];
|
|
||||||
for (int i = 0; i < juncrefs.Length; i++)
|
|
||||||
{
|
|
||||||
var juncref = NodeDictionary.JunctionRefs[i];
|
|
||||||
if (juncref.JunctionID >= juncs.Length)
|
|
||||||
{ continue; }
|
|
||||||
|
|
||||||
var j = new YndJunction();
|
|
||||||
j.Init(this, juncs[juncref.JunctionID], juncref);
|
|
||||||
j.Heightmap = new YndJunctionHeightmap(NodeDictionary.JunctionHeightmapBytes, j);
|
|
||||||
Junctions[i] = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateAllNodePositions();
|
UpdateAllNodePositions();
|
||||||
|
|
||||||
@ -143,8 +113,10 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public byte[] Save()
|
public byte[] Save()
|
||||||
{
|
{
|
||||||
|
if (BuildStructsOnSave)
|
||||||
|
{
|
||||||
BuildStructs();
|
BuildStructs();
|
||||||
|
}
|
||||||
|
|
||||||
byte[] data = ResourceBuilder.Build(NodeDictionary, 1); //ynd is version 1...
|
byte[] data = ResourceBuilder.Build(NodeDictionary, 1); //ynd is version 1...
|
||||||
|
|
||||||
@ -243,6 +215,44 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void InitNodesFromDictionary()
|
||||||
|
{
|
||||||
|
if (NodeDictionary != null)
|
||||||
|
{
|
||||||
|
if (NodeDictionary.Nodes != null)
|
||||||
|
{
|
||||||
|
var nodes = NodeDictionary.Nodes;
|
||||||
|
Nodes = new YndNode[nodes.Length];
|
||||||
|
for (int i = 0; i < nodes.Length; i++)
|
||||||
|
{
|
||||||
|
var n = new YndNode();
|
||||||
|
n.Init(this, nodes[i]);
|
||||||
|
Nodes[i] = n;
|
||||||
|
if (n.NodeID != i)
|
||||||
|
{ } //never hit here - nodeid's have to match the index!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((NodeDictionary.JunctionRefs != null) && (NodeDictionary.Junctions != null))
|
||||||
|
{
|
||||||
|
var juncrefs = NodeDictionary.JunctionRefs;
|
||||||
|
var juncs = NodeDictionary.Junctions;
|
||||||
|
Junctions = new YndJunction[juncrefs.Length];
|
||||||
|
for (int i = 0; i < juncrefs.Length; i++)
|
||||||
|
{
|
||||||
|
var juncref = juncrefs[i];
|
||||||
|
if (juncref.JunctionID >= juncs.Length)
|
||||||
|
{ continue; }
|
||||||
|
|
||||||
|
var j = new YndJunction();
|
||||||
|
j.Init(this, juncs[juncref.JunctionID], juncref);
|
||||||
|
j.Heightmap = new YndJunctionHeightmap(NodeDictionary.JunctionHeightmapBytes, j);
|
||||||
|
Junctions[i] = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public YndNode AddNode()
|
public YndNode AddNode()
|
||||||
{
|
{
|
||||||
int cnt = Nodes?.Length ?? 0;
|
int cnt = Nodes?.Length ?? 0;
|
||||||
@ -1306,4 +1316,85 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class YndXml : MetaXmlBase
|
||||||
|
{
|
||||||
|
|
||||||
|
public static string GetXml(YndFile ynd)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.AppendLine(XmlHeader);
|
||||||
|
|
||||||
|
if ((ynd != null) && (ynd.NodeDictionary != null))
|
||||||
|
{
|
||||||
|
var name = "NodeDictionary";
|
||||||
|
|
||||||
|
OpenTag(sb, 0, name);
|
||||||
|
|
||||||
|
ynd.NodeDictionary.WriteXml(sb, 1);
|
||||||
|
|
||||||
|
CloseTag(sb, 0, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class XmlYnd
|
||||||
|
{
|
||||||
|
|
||||||
|
public static YndFile GetYnd(string xml)
|
||||||
|
{
|
||||||
|
XmlDocument doc = new XmlDocument();
|
||||||
|
doc.LoadXml(xml);
|
||||||
|
return GetYnd(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static YndFile GetYnd(XmlDocument doc)
|
||||||
|
{
|
||||||
|
YndFile ynd = new YndFile();
|
||||||
|
ynd.NodeDictionary = new NodeDictionary();
|
||||||
|
ynd.NodeDictionary.ReadXml(doc.DocumentElement);
|
||||||
|
ynd.InitNodesFromDictionary();
|
||||||
|
ynd.BuildStructsOnSave = false; //structs don't need to be rebuilt here!
|
||||||
|
return ynd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static TextHash GetTextHash(string str)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(str))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (str.StartsWith("hash_"))
|
||||||
|
{
|
||||||
|
return Convert.ToUInt32(str.Substring(5), 16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint h = GlobalText.TryFindHash(str);
|
||||||
|
if (h != 0)
|
||||||
|
{
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JenkHash.GenHash(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -228,6 +228,9 @@ namespace CodeWalker.GameFiles
|
|||||||
UpdateStatus("Loading archetypes...");
|
UpdateStatus("Loading archetypes...");
|
||||||
InitArchetypeDicts();
|
InitArchetypeDicts();
|
||||||
|
|
||||||
|
UpdateStatus("Loading strings...");
|
||||||
|
InitStringDicts();
|
||||||
|
|
||||||
IsInited = true;
|
IsInited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,11 @@ namespace CodeWalker.GameFiles
|
|||||||
RelFile rel = RpfFile.GetFile<RelFile>(e, data);
|
RelFile rel = RpfFile.GetFile<RelFile>(e, data);
|
||||||
return GetXml(rel, out filename);
|
return GetXml(rel, out filename);
|
||||||
}
|
}
|
||||||
|
else if (fnl.EndsWith(".ynd"))
|
||||||
|
{
|
||||||
|
YndFile ynd = RpfFile.GetFile<YndFile>(e, data);
|
||||||
|
return GetXml(ynd, out filename);
|
||||||
|
}
|
||||||
filename = fn;
|
filename = fn;
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
@ -110,6 +115,12 @@ namespace CodeWalker.GameFiles
|
|||||||
filename = fn + ".xml";
|
filename = fn + ".xml";
|
||||||
return RelXml.GetXml(rel);
|
return RelXml.GetXml(rel);
|
||||||
}
|
}
|
||||||
|
public static string GetXml(YndFile ynd, out string filename)
|
||||||
|
{
|
||||||
|
var fn = (ynd?.RpfFileEntry?.Name) ?? "";
|
||||||
|
filename = fn + ".xml";
|
||||||
|
return YndXml.GetXml(ynd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1073,7 +1084,7 @@ namespace CodeWalker.GameFiles
|
|||||||
OpenTag(sb, indent, arrTag);
|
OpenTag(sb, indent, arrTag);
|
||||||
if (atyp == null)
|
if (atyp == null)
|
||||||
{
|
{
|
||||||
ErrorXml(sb, indent, ename + ": Array type not found: " + HashString(arrEntry.ReferenceKey));
|
ErrorXml(sb, indent, ename + ": Array type not found: " + HashString((MetaHash)arrEntry.ReferenceKey));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1367,7 +1378,7 @@ namespace CodeWalker.GameFiles
|
|||||||
return strval ?? "";
|
return strval ?? "";
|
||||||
case 7:
|
case 7:
|
||||||
case 8:
|
case 8:
|
||||||
var hashVal = MetaTypes.SwapBytes(MetaTypes.ConvertData<MetaHash>(data, eoffset));
|
var hashVal = (MetaHash)MetaTypes.SwapBytes(MetaTypes.ConvertData<MetaHash>(data, eoffset));
|
||||||
return HashString(hashVal);
|
return HashString(hashVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1813,14 +1824,14 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public static string HashString(MetaName h)
|
public static string HashString(MetaName h)
|
||||||
{
|
{
|
||||||
|
uint uh = (uint)h;
|
||||||
|
if (uh == 0) return "";
|
||||||
|
|
||||||
if (Enum.IsDefined(typeof(MetaName), h))
|
if (Enum.IsDefined(typeof(MetaName), h))
|
||||||
{
|
{
|
||||||
return h.ToString();
|
return h.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint uh = (uint)h;
|
|
||||||
if (uh == 0) return "";
|
|
||||||
|
|
||||||
var str = JenkIndex.TryGetString(uh);
|
var str = JenkIndex.TryGetString(uh);
|
||||||
if (!string.IsNullOrEmpty(str)) return str;
|
if (!string.IsNullOrEmpty(str)) return str;
|
||||||
|
|
||||||
@ -1832,6 +1843,8 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
public static string HashString(MetaHash h)
|
public static string HashString(MetaHash h)
|
||||||
{
|
{
|
||||||
|
if (h == 0) return "";
|
||||||
|
|
||||||
var str = JenkIndex.TryGetString(h);
|
var str = JenkIndex.TryGetString(h);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(str))
|
if (string.IsNullOrEmpty(str))
|
||||||
@ -1846,12 +1859,23 @@ namespace CodeWalker.GameFiles
|
|||||||
//todo: make sure JenkIndex is built!
|
//todo: make sure JenkIndex is built!
|
||||||
//todo: do extra hash lookup here
|
//todo: do extra hash lookup here
|
||||||
|
|
||||||
if (h == 0) return "";
|
|
||||||
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(str)) return str;
|
if (!string.IsNullOrEmpty(str)) return str;
|
||||||
return "hash_" + h.Hex;
|
return "hash_" + h.Hex;
|
||||||
}
|
}
|
||||||
|
public static string HashString(TextHash h)
|
||||||
|
{
|
||||||
|
uint uh = h.Hash;
|
||||||
|
if (uh == 0) return "";
|
||||||
|
|
||||||
|
var str = GlobalText.TryGetString(uh);
|
||||||
|
if (!string.IsNullOrEmpty(str)) return str;
|
||||||
|
|
||||||
|
//TODO: do extra hash lookup here
|
||||||
|
//if(Lookup.TryGetValue(uh, out str)) ...
|
||||||
|
|
||||||
|
return "hash_" + uh.ToString("X").PadLeft(8, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static string UintString(uint h)
|
public static string UintString(uint h)
|
||||||
@ -1900,6 +1924,7 @@ namespace CodeWalker.GameFiles
|
|||||||
RBF = 3,
|
RBF = 3,
|
||||||
CacheFile = 4,
|
CacheFile = 4,
|
||||||
AudioRel = 5,
|
AudioRel = 5,
|
||||||
|
Ynd = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,11 @@ using System.ComponentModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
namespace CodeWalker.GameFiles
|
namespace CodeWalker.GameFiles
|
||||||
{
|
{
|
||||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class NodeDictionary : ResourceFileBase
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class NodeDictionary : ResourceFileBase, IMetaXmlItem
|
||||||
{
|
{
|
||||||
public override long BlockLength
|
public override long BlockLength
|
||||||
{
|
{
|
||||||
@ -186,6 +186,155 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
return list.ToArray();
|
return list.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void WriteXml(StringBuilder sb, int indent)
|
||||||
|
{
|
||||||
|
YndXml.ValueTag(sb, indent, "VehicleNodeCount", NodesCountVehicle.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "PedNodeCount", NodesCountPed.ToString());
|
||||||
|
|
||||||
|
XmlNodeWrapper[] nodes = null;
|
||||||
|
int nodecount = Nodes?.Length ?? 0;
|
||||||
|
if (nodecount > 0)
|
||||||
|
{
|
||||||
|
nodes = new XmlNodeWrapper[nodecount];
|
||||||
|
for (int i = 0; i < nodecount; i++)
|
||||||
|
{
|
||||||
|
nodes[i] = new XmlNodeWrapper(Nodes[i], Links);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
YndXml.WriteItemArray(sb, nodes, indent, "Nodes");
|
||||||
|
|
||||||
|
|
||||||
|
XmlJunctionWrapper[] juncs = null;
|
||||||
|
int junccount = Junctions?.Length ?? 0;
|
||||||
|
if (junccount > 0)
|
||||||
|
{
|
||||||
|
juncs = new XmlJunctionWrapper[junccount];
|
||||||
|
for (int i = 0; i < junccount; i++)
|
||||||
|
{
|
||||||
|
juncs[i] = new XmlJunctionWrapper(Junctions[i], JunctionHeightmapBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
YndXml.WriteItemArray(sb, juncs, indent, "Junctions");
|
||||||
|
|
||||||
|
YndXml.WriteItemArray(sb, JunctionRefs, indent, "JunctionRefs");
|
||||||
|
|
||||||
|
}
|
||||||
|
public void ReadXml(XmlNode node)
|
||||||
|
{
|
||||||
|
NodesCountVehicle = Xml.GetChildUIntAttribute(node, "VehicleNodeCount", "value");
|
||||||
|
NodesCountPed = Xml.GetChildUIntAttribute(node, "PedNodeCount", "value");
|
||||||
|
|
||||||
|
List<Node> nodelist = new List<Node>();
|
||||||
|
List<NodeLink> linklist = new List<NodeLink>();
|
||||||
|
List<NodeJunction> junclist = new List<NodeJunction>();
|
||||||
|
List<byte> jhmblist = new List<byte>();
|
||||||
|
List<NodeJunctionRef> jreflist = new List<NodeJunctionRef>();
|
||||||
|
|
||||||
|
var nodesnode = node.SelectSingleNode("Nodes");
|
||||||
|
if (nodesnode != null)
|
||||||
|
{
|
||||||
|
var nodeitems = nodesnode.SelectNodes("Item");
|
||||||
|
foreach (XmlNode nodeitem in nodeitems)
|
||||||
|
{
|
||||||
|
XmlNodeWrapper n = new XmlNodeWrapper(linklist);
|
||||||
|
n.ReadXml(nodeitem);
|
||||||
|
nodelist.Add(n.Node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var juncsnode = node.SelectSingleNode("Junctions");
|
||||||
|
if (juncsnode != null)
|
||||||
|
{
|
||||||
|
var juncitems = juncsnode.SelectNodes("Item");
|
||||||
|
foreach (XmlNode juncitem in juncitems)
|
||||||
|
{
|
||||||
|
XmlJunctionWrapper j = new XmlJunctionWrapper(jhmblist);
|
||||||
|
j.ReadXml(juncitem);
|
||||||
|
junclist.Add(j.Junction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var jrefsnode = node.SelectSingleNode("JunctionRefs");
|
||||||
|
if (jrefsnode != null)
|
||||||
|
{
|
||||||
|
var jrefitems = jrefsnode.SelectNodes("Item");
|
||||||
|
foreach (XmlNode jrefitem in jrefitems)
|
||||||
|
{
|
||||||
|
NodeJunctionRef jref = new NodeJunctionRef();
|
||||||
|
jref.ReadXml(jrefitem);
|
||||||
|
jreflist.Add(jref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NodesCount = (uint)nodelist.Count;
|
||||||
|
Nodes = nodelist.ToArray();
|
||||||
|
LinksCount = (uint)linklist.Count;
|
||||||
|
Links = linklist.ToArray();
|
||||||
|
JunctionsCount = (uint)junclist.Count;
|
||||||
|
Junctions = junclist.ToArray();
|
||||||
|
JunctionHeightmapBytesCount = (uint)jhmblist.Count;
|
||||||
|
JunctionHeightmapBytes = jhmblist.ToArray();
|
||||||
|
JunctionRefsCount0 = (ushort)jreflist.Count;
|
||||||
|
JunctionRefsCount1 = JunctionRefsCount0;
|
||||||
|
JunctionRefs = jreflist.ToArray();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class XmlNodeWrapper : IMetaXmlItem
|
||||||
|
{
|
||||||
|
public Node Node;
|
||||||
|
private NodeLink[] AllLinks;
|
||||||
|
private List<NodeLink> AllLinksList;
|
||||||
|
|
||||||
|
public XmlNodeWrapper(Node node, NodeLink[] allLinks)
|
||||||
|
{
|
||||||
|
Node = node;
|
||||||
|
AllLinks = allLinks;
|
||||||
|
}
|
||||||
|
public XmlNodeWrapper(List<NodeLink> allLinksList)
|
||||||
|
{
|
||||||
|
AllLinksList = allLinksList;
|
||||||
|
}
|
||||||
|
public void WriteXml(StringBuilder sb, int indent)
|
||||||
|
{
|
||||||
|
Node.WriteXml(sb, indent, AllLinks);
|
||||||
|
}
|
||||||
|
public void ReadXml(XmlNode node)
|
||||||
|
{
|
||||||
|
Node = new Node();
|
||||||
|
Node.ReadXml(node, AllLinksList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class XmlJunctionWrapper : IMetaXmlItem
|
||||||
|
{
|
||||||
|
public NodeJunction Junction;
|
||||||
|
private byte[] AllHeightmapData;
|
||||||
|
private List<byte> AllHeightmapDataList;
|
||||||
|
|
||||||
|
public XmlJunctionWrapper(NodeJunction junc, byte[] allHeightmapData)
|
||||||
|
{
|
||||||
|
Junction = junc;
|
||||||
|
AllHeightmapData = allHeightmapData;
|
||||||
|
}
|
||||||
|
public XmlJunctionWrapper(List<byte> allHeightmapDataList)
|
||||||
|
{
|
||||||
|
AllHeightmapDataList = allHeightmapDataList;
|
||||||
|
}
|
||||||
|
public void WriteXml(StringBuilder sb, int indent)
|
||||||
|
{
|
||||||
|
Junction.WriteXml(sb, indent, AllHeightmapData);
|
||||||
|
}
|
||||||
|
public void ReadXml(XmlNode node)
|
||||||
|
{
|
||||||
|
Junction = new NodeJunction();
|
||||||
|
Junction.ReadXml(node, AllHeightmapDataList);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TypeConverter(typeof(ExpandableObjectConverter))] public struct Node
|
[TypeConverter(typeof(ExpandableObjectConverter))] public struct Node
|
||||||
@ -224,9 +373,74 @@ namespace CodeWalker.GameFiles
|
|||||||
//Flags3.ToString() + ", " + Flags4.ToString();
|
//Flags3.ToString() + ", " + Flags4.ToString();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteXml(StringBuilder sb, int indent, NodeLink[] allLinks)
|
||||||
|
{
|
||||||
|
Vector3 p = new Vector3();
|
||||||
|
p.X = PositionX / 4.0f;
|
||||||
|
p.Y = PositionY / 4.0f;
|
||||||
|
p.Z = PositionZ / 32.0f;
|
||||||
|
int linkCount = LinkCountFlags.Value >> 3;
|
||||||
|
int linkCountUnk = LinkCountFlags.Value & 7;
|
||||||
|
|
||||||
|
YndXml.ValueTag(sb, indent, "AreaID", AreaID.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "NodeID", NodeID.ToString());
|
||||||
|
YndXml.StringTag(sb, indent, "StreetName", YndXml.HashString(StreetName));
|
||||||
|
YndXml.SelfClosingTag(sb, indent, "Position " + FloatUtil.GetVector3XmlString(p));
|
||||||
|
YndXml.ValueTag(sb, indent, "Flags0", Flags0.Value.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "Flags1", Flags1.Value.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "Flags2", Flags2.Value.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "Flags3", Flags3.Value.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "Flags4", Flags4.Value.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "Flags5", linkCountUnk.ToString());
|
||||||
|
|
||||||
|
NodeLink[] links = null;
|
||||||
|
if (linkCount > 0)
|
||||||
|
{
|
||||||
|
links = new NodeLink[linkCount];
|
||||||
|
for (int i = 0; i < linkCount; i++)
|
||||||
|
{
|
||||||
|
links[i] = allLinks[LinkID + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
YndXml.WriteItemArray(sb, links, indent, "Links");
|
||||||
|
|
||||||
|
}
|
||||||
|
public void ReadXml(XmlNode node, List<NodeLink> allLinksList)
|
||||||
|
{
|
||||||
|
AreaID = (ushort)Xml.GetChildUIntAttribute(node, "AreaID", "value");
|
||||||
|
NodeID = (ushort)Xml.GetChildUIntAttribute(node, "NodeID", "value");
|
||||||
|
StreetName = XmlYnd.GetTextHash(Xml.GetChildInnerText(node, "StreetName"));
|
||||||
|
Vector3 p = Xml.GetChildVector3Attributes(node, "Position", "x", "y", "z");
|
||||||
|
PositionX = (short)(p.X * 4.0f);
|
||||||
|
PositionY = (short)(p.Y * 4.0f);
|
||||||
|
PositionZ = (short)(p.Z * 32.0f);
|
||||||
|
Flags0 = (byte)Xml.GetChildUIntAttribute(node, "Flags0", "value");
|
||||||
|
Flags1 = (byte)Xml.GetChildUIntAttribute(node, "Flags1", "value");
|
||||||
|
Flags2 = (byte)Xml.GetChildUIntAttribute(node, "Flags2", "value");
|
||||||
|
Flags3 = (byte)Xml.GetChildUIntAttribute(node, "Flags3", "value");
|
||||||
|
Flags4 = (byte)Xml.GetChildUIntAttribute(node, "Flags4", "value");
|
||||||
|
int linkCountUnk = (byte)Xml.GetChildUIntAttribute(node, "Flags5", "value");
|
||||||
|
|
||||||
|
LinkID = (ushort)allLinksList.Count;
|
||||||
|
int linkCount = 0;
|
||||||
|
var linksnode = node.SelectSingleNode("Links");
|
||||||
|
if (linksnode != null)
|
||||||
|
{
|
||||||
|
var linkitems = linksnode.SelectNodes("Item");
|
||||||
|
foreach (XmlNode linkitem in linkitems)
|
||||||
|
{
|
||||||
|
NodeLink link = new NodeLink();
|
||||||
|
link.ReadXml(linkitem);
|
||||||
|
allLinksList.Add(link);
|
||||||
|
linkCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LinkCountFlags = (byte)((linkCount << 3) + (linkCountUnk & 7));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeLink
|
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeLink : IMetaXmlItem
|
||||||
{
|
{
|
||||||
public ushort AreaID { get; set; }
|
public ushort AreaID { get; set; }
|
||||||
public ushort NodeID { get; set; }
|
public ushort NodeID { get; set; }
|
||||||
@ -239,6 +453,25 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return AreaID.ToString() + ", " + NodeID.ToString() + ", " + Flags0.Value.ToString() + ", " + Flags1.Value.ToString() + ", " + Flags2.Value.ToString() + ", " + LinkLength.Value.ToString();
|
return AreaID.ToString() + ", " + NodeID.ToString() + ", " + Flags0.Value.ToString() + ", " + Flags1.Value.ToString() + ", " + Flags2.Value.ToString() + ", " + LinkLength.Value.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteXml(StringBuilder sb, int indent)
|
||||||
|
{
|
||||||
|
YndXml.ValueTag(sb, indent, "ToAreaID", AreaID.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "ToNodeID", NodeID.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "Flags0", Flags0.Value.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "Flags1", Flags1.Value.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "Flags2", Flags2.Value.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "LinkLength", LinkLength.Value.ToString());
|
||||||
|
}
|
||||||
|
public void ReadXml(XmlNode node)
|
||||||
|
{
|
||||||
|
AreaID = (ushort)Xml.GetChildUIntAttribute(node, "ToAreaID", "value");
|
||||||
|
NodeID = (ushort)Xml.GetChildUIntAttribute(node, "ToNodeID", "value");
|
||||||
|
Flags0 = (byte)Xml.GetChildUIntAttribute(node, "Flags0", "value");
|
||||||
|
Flags1 = (byte)Xml.GetChildUIntAttribute(node, "Flags1", "value");
|
||||||
|
Flags2 = (byte)Xml.GetChildUIntAttribute(node, "Flags2", "value");
|
||||||
|
LinkLength = (byte)Xml.GetChildUIntAttribute(node, "LinkLength", "value");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeJunction
|
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeJunction
|
||||||
@ -255,9 +488,54 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return PositionX.ToString() + ", " + PositionY.ToString() + ": " + MinZ.ToString() + ", " + MaxZ.ToString() + ": " + HeightmapDimX.ToString() + " x " + HeightmapDimY.ToString();
|
return PositionX.ToString() + ", " + PositionY.ToString() + ": " + MinZ.ToString() + ", " + MaxZ.ToString() + ": " + HeightmapDimX.ToString() + " x " + HeightmapDimY.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteXml(StringBuilder sb, int indent, byte[] allHeightmapData)
|
||||||
|
{
|
||||||
|
Vector2 p = new Vector2();
|
||||||
|
p.X = PositionX / 4.0f;
|
||||||
|
p.Y = PositionY / 4.0f;
|
||||||
|
float minz = MinZ / 32.0f;
|
||||||
|
float maxz = MaxZ / 32.0f;
|
||||||
|
|
||||||
|
YndXml.SelfClosingTag(sb, indent, "Position " + FloatUtil.GetVector2XmlString(p));
|
||||||
|
YndXml.ValueTag(sb, indent, "MinZ", FloatUtil.ToString(minz));
|
||||||
|
YndXml.ValueTag(sb, indent, "MaxZ", FloatUtil.ToString(maxz));
|
||||||
|
YndXml.ValueTag(sb, indent, "SizeX", HeightmapDimX.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "SizeY", HeightmapDimY.ToString());
|
||||||
|
|
||||||
|
byte[] hmdata = null;
|
||||||
|
int hmbcount = HeightmapDimX * HeightmapDimY;
|
||||||
|
if (hmbcount > 0)
|
||||||
|
{
|
||||||
|
hmdata = new byte[hmbcount];
|
||||||
|
Buffer.BlockCopy(allHeightmapData, HeightmapPtr, hmdata, 0, hmbcount);
|
||||||
|
}
|
||||||
|
YndXml.WriteRawArray(sb, hmdata, indent, "Heightmap", "", RelXml.FormatHexByte, Math.Max(HeightmapDimX, (byte)1));
|
||||||
|
|
||||||
|
}
|
||||||
|
public void ReadXml(XmlNode node, List<byte> allHeightmapDataList)
|
||||||
|
{
|
||||||
|
Vector2 p = Xml.GetChildVector2Attributes(node, "Position", "x", "y");
|
||||||
|
float minz = Xml.GetChildFloatAttribute(node, "MinZ", "value");
|
||||||
|
float maxz = Xml.GetChildFloatAttribute(node, "MaxZ", "value");
|
||||||
|
HeightmapDimX = (byte)Xml.GetChildUIntAttribute(node, "SizeX", "value");
|
||||||
|
HeightmapDimY = (byte)Xml.GetChildUIntAttribute(node, "SizeY", "value");
|
||||||
|
PositionX = (short)(p.X * 4.0f);
|
||||||
|
PositionY = (short)(p.Y * 4.0f);
|
||||||
|
MinZ = (short)(minz * 32.0f);
|
||||||
|
MaxZ = (short)(maxz * 32.0f);
|
||||||
|
|
||||||
|
byte[] hmdata = Xml.GetChildRawByteArray(node, "Heightmap");
|
||||||
|
HeightmapPtr = (ushort)allHeightmapDataList.Count;
|
||||||
|
if (hmdata != null)
|
||||||
|
{
|
||||||
|
allHeightmapDataList.AddRange(hmdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeJunctionRef
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeJunctionRef : IMetaXmlItem
|
||||||
{
|
{
|
||||||
public ushort AreaID { get; set; }
|
public ushort AreaID { get; set; }
|
||||||
public ushort NodeID { get; set; }
|
public ushort NodeID { get; set; }
|
||||||
@ -268,6 +546,21 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return AreaID.ToString() + ", " + NodeID.ToString() + ", " + JunctionID.ToString();
|
return AreaID.ToString() + ", " + NodeID.ToString() + ", " + JunctionID.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteXml(StringBuilder sb, int indent)
|
||||||
|
{
|
||||||
|
YndXml.ValueTag(sb, indent, "AreaID", AreaID.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "NodeID", NodeID.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "JunctionID", JunctionID.ToString());
|
||||||
|
YndXml.ValueTag(sb, indent, "Unk0", Unk0.ToString());
|
||||||
|
}
|
||||||
|
public void ReadXml(XmlNode node)
|
||||||
|
{
|
||||||
|
AreaID = (ushort)Xml.GetChildUIntAttribute(node, "AreaID", "value");
|
||||||
|
NodeID = (ushort)Xml.GetChildUIntAttribute(node, "NodeID", "value");
|
||||||
|
JunctionID = (ushort)Xml.GetChildUIntAttribute(node, "JunctionID", "value");
|
||||||
|
Unk0 = (ushort)Xml.GetChildUIntAttribute(node, "Unk0", "value");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ namespace CodeWalker
|
|||||||
InitFileType(".ymt", "Metadata (Binary)", 6, FileTypeAction.ViewYmt);
|
InitFileType(".ymt", "Metadata (Binary)", 6, FileTypeAction.ViewYmt);
|
||||||
InitFileType(".pso", "Metadata (PSO)", 6, FileTypeAction.ViewJPso);
|
InitFileType(".pso", "Metadata (PSO)", 6, FileTypeAction.ViewJPso);
|
||||||
InitFileType(".gfx", "Scaleform Flash", 7);
|
InitFileType(".gfx", "Scaleform Flash", 7);
|
||||||
InitFileType(".ynd", "Path Nodes", 8);
|
InitFileType(".ynd", "Path Nodes", 8, FileTypeAction.ViewYnd);
|
||||||
InitFileType(".ynv", "Nav Mesh", 9, FileTypeAction.ViewModel);
|
InitFileType(".ynv", "Nav Mesh", 9, FileTypeAction.ViewModel);
|
||||||
InitFileType(".yvr", "Vehicle Record", 9, FileTypeAction.ViewYvr);
|
InitFileType(".yvr", "Vehicle Record", 9, FileTypeAction.ViewYvr);
|
||||||
InitFileType(".ywr", "Waypoint Record", 9, FileTypeAction.ViewYwr);
|
InitFileType(".ywr", "Waypoint Record", 9, FileTypeAction.ViewYwr);
|
||||||
@ -1302,6 +1302,7 @@ namespace CodeWalker
|
|||||||
case FileTypeAction.ViewYwr:
|
case FileTypeAction.ViewYwr:
|
||||||
case FileTypeAction.ViewYvr:
|
case FileTypeAction.ViewYvr:
|
||||||
case FileTypeAction.ViewYcd:
|
case FileTypeAction.ViewYcd:
|
||||||
|
case FileTypeAction.ViewYnd:
|
||||||
case FileTypeAction.ViewCacheDat:
|
case FileTypeAction.ViewCacheDat:
|
||||||
return true;
|
return true;
|
||||||
case FileTypeAction.ViewHex:
|
case FileTypeAction.ViewHex:
|
||||||
@ -1324,6 +1325,7 @@ namespace CodeWalker
|
|||||||
case FileTypeAction.ViewJPso:
|
case FileTypeAction.ViewJPso:
|
||||||
case FileTypeAction.ViewCut:
|
case FileTypeAction.ViewCut:
|
||||||
case FileTypeAction.ViewRel:
|
case FileTypeAction.ViewRel:
|
||||||
|
case FileTypeAction.ViewYnd:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1425,6 +1427,9 @@ namespace CodeWalker
|
|||||||
case FileTypeAction.ViewYcd:
|
case FileTypeAction.ViewYcd:
|
||||||
ViewYcd(name, path, data, fe);
|
ViewYcd(name, path, data, fe);
|
||||||
break;
|
break;
|
||||||
|
case FileTypeAction.ViewYnd:
|
||||||
|
ViewYnd(name, path, data, fe);
|
||||||
|
break;
|
||||||
case FileTypeAction.ViewCacheDat:
|
case FileTypeAction.ViewCacheDat:
|
||||||
ViewCacheDat(name, path, data, fe);
|
ViewCacheDat(name, path, data, fe);
|
||||||
break;
|
break;
|
||||||
@ -1627,6 +1632,13 @@ namespace CodeWalker
|
|||||||
f.Show();
|
f.Show();
|
||||||
f.LoadYcd(ycd);
|
f.LoadYcd(ycd);
|
||||||
}
|
}
|
||||||
|
private void ViewYnd(string name, string path, byte[] data, RpfFileEntry e)
|
||||||
|
{
|
||||||
|
var ynd = RpfFile.GetFile<YndFile>(e, data);
|
||||||
|
MetaForm f = new MetaForm(this);
|
||||||
|
f.Show();
|
||||||
|
f.LoadMeta(ynd);
|
||||||
|
}
|
||||||
private void ViewCacheDat(string name, string path, byte[] data, RpfFileEntry e)
|
private void ViewCacheDat(string name, string path, byte[] data, RpfFileEntry e)
|
||||||
{
|
{
|
||||||
var cachedat = RpfFile.GetFile<CacheDatFile>(e, data);
|
var cachedat = RpfFile.GetFile<CacheDatFile>(e, data);
|
||||||
@ -2407,6 +2419,10 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
mformat = MetaFormat.AudioRel;
|
mformat = MetaFormat.AudioRel;
|
||||||
}
|
}
|
||||||
|
if (fnamel.EndsWith(".ynd.xml"))
|
||||||
|
{
|
||||||
|
mformat = MetaFormat.Ynd;
|
||||||
|
}
|
||||||
|
|
||||||
fname = fname.Substring(0, fname.Length - trimlength);
|
fname = fname.Substring(0, fname.Length - trimlength);
|
||||||
fnamel = fnamel.Substring(0, fnamel.Length - trimlength);
|
fnamel = fnamel.Substring(0, fnamel.Length - trimlength);
|
||||||
@ -2460,6 +2476,17 @@ namespace CodeWalker
|
|||||||
data = rel.Save();
|
data = rel.Save();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case MetaFormat.Ynd:
|
||||||
|
{
|
||||||
|
var ynd = XmlYnd.GetYnd(doc);
|
||||||
|
if (ynd.NodeDictionary == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show(fname + ": Schema not supported.", "Cannot import YND XML");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
data = ynd.Save();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4131,7 +4158,8 @@ namespace CodeWalker
|
|||||||
ViewYwr = 15,
|
ViewYwr = 15,
|
||||||
ViewYvr = 16,
|
ViewYvr = 16,
|
||||||
ViewYcd = 17,
|
ViewYcd = 17,
|
||||||
ViewCacheDat = 18,
|
ViewYnd = 18,
|
||||||
|
ViewCacheDat = 19,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -303,6 +303,20 @@ namespace CodeWalker.Forms
|
|||||||
if (cut.Pso != null) metaFormat = MetaFormat.PSO;
|
if (cut.Pso != null) metaFormat = MetaFormat.PSO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void LoadMeta(YndFile ynd)
|
||||||
|
{
|
||||||
|
var fn = ((ynd?.RpfFileEntry?.Name) ?? "") + ".xml";
|
||||||
|
Xml = MetaXml.GetXml(ynd, out fn);
|
||||||
|
FileName = fn;
|
||||||
|
RawPropertyGrid.SelectedObject = ynd;
|
||||||
|
rpfFileEntry = ynd?.RpfFileEntry;
|
||||||
|
modified = false;
|
||||||
|
metaFormat = MetaFormat.XML;
|
||||||
|
if (ynd?.RpfFileEntry != null)
|
||||||
|
{
|
||||||
|
metaFormat = MetaFormat.Ynd;
|
||||||
|
}
|
||||||
|
}
|
||||||
public void LoadMeta(CacheDatFile cachedat)
|
public void LoadMeta(CacheDatFile cachedat)
|
||||||
{
|
{
|
||||||
var fn = ((cachedat?.FileEntry?.Name) ?? "") + ".xml";
|
var fn = ((cachedat?.FileEntry?.Name) ?? "") + ".xml";
|
||||||
@ -364,6 +378,15 @@ namespace CodeWalker.Forms
|
|||||||
case MetaFormat.CacheFile:
|
case MetaFormat.CacheFile:
|
||||||
MessageBox.Show("Sorry, CacheFile import is not supported.", "Cannot import CacheFile XML");
|
MessageBox.Show("Sorry, CacheFile import is not supported.", "Cannot import CacheFile XML");
|
||||||
return false;
|
return false;
|
||||||
|
case MetaFormat.Ynd:
|
||||||
|
var ynd = XmlYnd.GetYnd(doc);
|
||||||
|
if (ynd.NodeDictionary == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Schema not supported.", "Cannot import YND XML");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
data = ynd.Save();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
|
Loading…
Reference in New Issue
Block a user