mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-25 16:32:55 +08:00
Animations XML conversion
This commit is contained in:
parent
918ed7fccf
commit
7e43271a67
@ -5,6 +5,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
@ -19,6 +20,7 @@ namespace CodeWalker.GameFiles
|
||||
public ClipMapEntry[] ClipMapEntries { get; set; }
|
||||
public AnimationMapEntry[] AnimMapEntries { get; set; }
|
||||
|
||||
public string LoadException { get; set; }
|
||||
|
||||
public YcdFile() : base(null, GameFileType.Ycd)
|
||||
{
|
||||
@ -41,91 +43,58 @@ namespace CodeWalker.GameFiles
|
||||
throw new Exception("File entry wasn't a resource! (is it binary data?)");
|
||||
}
|
||||
|
||||
ResourceDataReader rd = new ResourceDataReader(resentry, data);
|
||||
ResourceDataReader rd = null;
|
||||
try
|
||||
{
|
||||
rd = new ResourceDataReader(resentry, data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//data = entry.File.DecompressBytes(data); //??
|
||||
LoadException = ex.ToString();
|
||||
}
|
||||
|
||||
ClipDictionary = rd?.ReadBlock<ClipDictionary>();
|
||||
|
||||
ClipDictionary = rd.ReadBlock<ClipDictionary>();
|
||||
InitDictionaries();
|
||||
}
|
||||
|
||||
ClipMap = new Dictionary<MetaHash, ClipMapEntry>();
|
||||
AnimMap = new Dictionary<MetaHash, AnimationMapEntry>();
|
||||
if (ClipDictionary != null)
|
||||
public void InitDictionaries()
|
||||
{
|
||||
if ((ClipDictionary.Clips != null) && (ClipDictionary.Clips.data_items != null))
|
||||
{
|
||||
foreach (var cme in ClipDictionary.Clips.data_items)
|
||||
{
|
||||
if (cme != null)
|
||||
{
|
||||
ClipMap[cme.Hash] = cme;
|
||||
var nxt = cme.Next;
|
||||
while (nxt != null)
|
||||
{
|
||||
ClipMap[nxt.Hash] = nxt;
|
||||
nxt = nxt.Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((ClipDictionary.Animations != null) && (ClipDictionary.Animations.Animations != null) && (ClipDictionary.Animations.Animations.data_items != null))
|
||||
{
|
||||
foreach (var ame in ClipDictionary.Animations.Animations.data_items)
|
||||
{
|
||||
if (ame != null)
|
||||
{
|
||||
AnimMap[ame.Hash] = ame;
|
||||
var nxt = ame.NextEntry;
|
||||
while (nxt != null)
|
||||
{
|
||||
AnimMap[nxt.Hash] = nxt;
|
||||
nxt = nxt.NextEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ClipMap = ClipDictionary?.ClipMap ?? new Dictionary<MetaHash, ClipMapEntry>();
|
||||
AnimMap = ClipDictionary?.AnimMap ?? new Dictionary<MetaHash, AnimationMapEntry>();
|
||||
|
||||
foreach (var cme in ClipMap.Values)
|
||||
{
|
||||
var clip = cme.Clip;
|
||||
if (clip == null) continue;
|
||||
clip.Ycd = this;
|
||||
if (string.IsNullOrEmpty(clip.Name)) continue;
|
||||
string name = clip.Name.Replace('\\', '/');
|
||||
var slidx = name.LastIndexOf('/');
|
||||
if ((slidx >= 0) && (slidx < name.Length - 1))
|
||||
{
|
||||
name = name.Substring(slidx + 1);
|
||||
}
|
||||
var didx = name.LastIndexOf('.');
|
||||
if ((didx > 0) && (didx < name.Length))
|
||||
{
|
||||
name = name.Substring(0, didx);
|
||||
}
|
||||
clip.ShortName = name;
|
||||
name = name.ToLowerInvariant();
|
||||
JenkIndex.Ensure(name);
|
||||
|
||||
|
||||
//if (name.EndsWith("_uv_0")) //hash for these entries match string with this removed, +1
|
||||
//{
|
||||
//}
|
||||
//if (name.EndsWith("_uv_1")) //same as above, but +2
|
||||
//{
|
||||
//}
|
||||
|
||||
if (cme?.Clip != null) cme.Clip.Ycd = this;
|
||||
}
|
||||
foreach (var ame in AnimMap.Values)
|
||||
{
|
||||
var anim = ame.Animation;
|
||||
if (anim == null) continue;
|
||||
anim.Ycd = this;
|
||||
if (ame?.Animation != null) ame.Animation.Ycd = this;
|
||||
}
|
||||
|
||||
|
||||
ClipMapEntries = ClipMap.Values.ToArray();
|
||||
AnimMapEntries = AnimMap.Values.ToArray();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
//if (BuildStructsOnSave)
|
||||
//{
|
||||
// BuildStructs();
|
||||
//}
|
||||
|
||||
byte[] data = ResourceBuilder.Build(ClipDictionary, 46); //ycd is 46...
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void SaveOpenFormatsAnimation(Animation crAnim, Stream outStream)
|
||||
{
|
||||
var seqs = new int[(crAnim.Frames / crAnim.SequenceFrameLimit) + 1];
|
||||
@ -171,7 +140,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
else if (chList.Length == 1)
|
||||
{
|
||||
if (chList[0] is AnimChannelStaticSmallestThreeQuaternion)
|
||||
if (chList[0] is AnimChannelStaticQuaternion)
|
||||
{
|
||||
isRotation = true;
|
||||
}
|
||||
@ -201,7 +170,7 @@ namespace CodeWalker.GameFiles
|
||||
return " Static";
|
||||
}
|
||||
}
|
||||
else if (chan is AnimChannelStaticFloat || chan is AnimChannelStaticVector3 || chan is AnimChannelStaticSmallestThreeQuaternion)
|
||||
else if (chan is AnimChannelStaticFloat || chan is AnimChannelStaticVector3 || chan is AnimChannelStaticQuaternion)
|
||||
{
|
||||
return " Static";
|
||||
}
|
||||
@ -245,10 +214,10 @@ namespace CodeWalker.GameFiles
|
||||
switch (chan)
|
||||
{
|
||||
case AnimChannelStaticFloat sf:
|
||||
return $" {sf.FloatValue}\r\n";
|
||||
return $" {sf.Value}\r\n";
|
||||
case AnimChannelStaticVector3 v3:
|
||||
return $" {v3.Value[0]} {v3.Value[1]} {v3.Value[2]}\r\n";
|
||||
case AnimChannelStaticSmallestThreeQuaternion q3:
|
||||
case AnimChannelStaticQuaternion q3:
|
||||
return $" {q3.Value[0]} {q3.Value[1]} {q3.Value[2]} {q3.Value[3]}\r\n";
|
||||
default:
|
||||
{
|
||||
@ -303,4 +272,61 @@ namespace CodeWalker.GameFiles
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public class YcdXml : MetaXmlBase
|
||||
{
|
||||
|
||||
public static string GetXml(YcdFile ycd)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine(XmlHeader);
|
||||
|
||||
if ((ycd != null) && (ycd.ClipDictionary != null))
|
||||
{
|
||||
var name = "ClipDictionary";
|
||||
|
||||
OpenTag(sb, 0, name);
|
||||
|
||||
ycd.ClipDictionary.WriteXml(sb, 1);
|
||||
|
||||
CloseTag(sb, 0, name);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class XmlYcd
|
||||
{
|
||||
|
||||
public static YcdFile GetYcd(string xml)
|
||||
{
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.LoadXml(xml);
|
||||
return GetYcd(doc);
|
||||
}
|
||||
|
||||
public static YcdFile GetYcd(XmlDocument doc)
|
||||
{
|
||||
YcdFile ycd = new YcdFile();
|
||||
ycd.ClipDictionary = new ClipDictionary();
|
||||
ycd.ClipDictionary.ReadXml(doc.DocumentElement);
|
||||
ycd.InitDictionaries();
|
||||
//ycd.BuildStructsOnSave = false; //structs don't need to be rebuilt here!
|
||||
return ycd;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -2964,18 +2964,255 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
public void TestYcds()
|
||||
{
|
||||
var errorfiles = new List<YcdFile>();
|
||||
var errorentries = new List<RpfEntry>();
|
||||
|
||||
foreach (RpfFile file in AllRpfs)
|
||||
{
|
||||
foreach (RpfEntry entry in file.AllEntries)
|
||||
{
|
||||
try
|
||||
{
|
||||
//try
|
||||
//{
|
||||
if (entry.NameLower.EndsWith(".ycd"))
|
||||
{
|
||||
UpdateStatus(string.Format(entry.Path));
|
||||
YcdFile ycdfile = RpfMan.GetFile<YcdFile>(entry);
|
||||
if ((ycdfile != null))// && (ycdfile.Meta != null))
|
||||
YcdFile ycd1 = RpfMan.GetFile<YcdFile>(entry);
|
||||
if (ycd1 == null)
|
||||
{
|
||||
errorentries.Add(entry);
|
||||
}
|
||||
else if (ycd1?.LoadException != null)
|
||||
{
|
||||
errorfiles.Add(ycd1);//these ones have file corruption issues and won't load as resource...
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ycd1.ClipDictionary == null)
|
||||
{ continue; }
|
||||
|
||||
var t = true;
|
||||
if (t)//just here to test loading only
|
||||
{ continue; }
|
||||
|
||||
var xml = YcdXml.GetXml(ycd1);
|
||||
var ycdX = XmlYcd.GetYcd(xml);
|
||||
var data = ycdX.Save();
|
||||
var ycd2 = new YcdFile();
|
||||
RpfFile.LoadResourceFile(ycd2, data, 46);//full roundtrip
|
||||
|
||||
|
||||
if (ycd2 == null)
|
||||
{ continue; }
|
||||
if (ycd2.ClipDictionary == null)
|
||||
{ continue; }
|
||||
|
||||
var c1 = ycd1.ClipDictionary.Clips?.data_items;
|
||||
var c2 = ycd2.ClipDictionary.Clips?.data_items;
|
||||
if ((c1 == null) || (c2 == null))
|
||||
{ continue; }
|
||||
if (c1.Length != c2.Length)
|
||||
{ continue; }
|
||||
|
||||
var a1 = ycd1.ClipDictionary.Animations?.Animations?.data_items;
|
||||
var a2 = ycd2.ClipDictionary.Animations?.Animations?.data_items;
|
||||
if ((a1 == null) || (a2 == null))
|
||||
{ continue; }
|
||||
if (a1.Length != a2.Length)
|
||||
{ continue; }
|
||||
|
||||
var m1 = ycd1.AnimMap;
|
||||
var m2 = ycd2.AnimMap;
|
||||
if ((m1 == null) || (m2 == null))
|
||||
{ continue; }
|
||||
if (m1.Count != m2.Count)
|
||||
{ continue; }
|
||||
foreach (var kvp1 in m1)
|
||||
{
|
||||
var an1 = kvp1.Value;
|
||||
var an2 = an1;
|
||||
if(!m2.TryGetValue(kvp1.Key, out an2))
|
||||
{ continue; }
|
||||
|
||||
var sa1 = an1?.Animation?.Sequences?.data_items;
|
||||
var sa2 = an2?.Animation?.Sequences?.data_items;
|
||||
if ((sa1 == null) || (sa2 == null))
|
||||
{ continue; }
|
||||
if (sa1.Length != sa2.Length)
|
||||
{ continue; }
|
||||
for (int s = 0; s < sa1.Length; s++)
|
||||
{
|
||||
var s1 = sa1[s];
|
||||
var s2 = sa2[s];
|
||||
if ((s1?.Sequences == null) || (s2?.Sequences == null))
|
||||
{ continue; }
|
||||
|
||||
if (s1.NumFrames != s2.NumFrames)
|
||||
{ }
|
||||
if (s1.ChunkSize != s2.ChunkSize)
|
||||
{ }
|
||||
if (s1.FrameOffset != s2.FrameOffset)
|
||||
{ }
|
||||
if (s1.DataLength != s2.DataLength)
|
||||
{ }
|
||||
else
|
||||
{
|
||||
//for (int b = 0; b < s1.DataLength; b++)
|
||||
//{
|
||||
// var b1 = s1.Data[b];
|
||||
// var b2 = s2.Data[b];
|
||||
// if (b1 != b2)
|
||||
// { }
|
||||
//}
|
||||
}
|
||||
|
||||
for (int ss = 0; ss < s1.Sequences.Length; ss++)
|
||||
{
|
||||
var ss1 = s1.Sequences[ss];
|
||||
var ss2 = s2.Sequences[ss];
|
||||
if ((ss1?.Channels == null) || (ss2?.Channels == null))
|
||||
{ continue; }
|
||||
if (ss1.Channels.Length != ss2.Channels.Length)
|
||||
{ continue; }
|
||||
|
||||
|
||||
for (int c = 0; c < ss1.Channels.Length; c++)
|
||||
{
|
||||
var sc1 = ss1.Channels[c];
|
||||
var sc2 = ss2.Channels[c];
|
||||
if ((sc1 == null) || (sc2 == null))
|
||||
{ continue; }
|
||||
if (sc1.Type == AnimChannelType.LinearFloat)
|
||||
{ continue; }
|
||||
if (sc1.Type != sc2.Type)
|
||||
{ continue; }
|
||||
if (sc1.Index != sc2.Index)
|
||||
{ continue; }
|
||||
if (sc1.Type == AnimChannelType.StaticQuaternion)
|
||||
{
|
||||
var acsq1 = sc1 as AnimChannelStaticQuaternion;
|
||||
var acsq2 = sc2 as AnimChannelStaticQuaternion;
|
||||
var vdiff = acsq1.Value - acsq2.Value;
|
||||
var len = vdiff.Length();
|
||||
var v1len = Math.Max(acsq1.Value.Length(), 1);
|
||||
if (len > 1e-2f * v1len)
|
||||
{ continue; }
|
||||
}
|
||||
else if (sc1.Type == AnimChannelType.StaticVector3)
|
||||
{
|
||||
var acsv1 = sc1 as AnimChannelStaticVector3;
|
||||
var acsv2 = sc2 as AnimChannelStaticVector3;
|
||||
var vdiff = acsv1.Value - acsv2.Value;
|
||||
var len = vdiff.Length();
|
||||
var v1len = Math.Max(acsv1.Value.Length(), 1);
|
||||
if (len > 1e-2f * v1len)
|
||||
{ continue; }
|
||||
}
|
||||
else if (sc1.Type == AnimChannelType.StaticFloat)
|
||||
{
|
||||
var acsf1 = sc1 as AnimChannelStaticFloat;
|
||||
var acsf2 = sc2 as AnimChannelStaticFloat;
|
||||
var vdiff = Math.Abs(acsf1.Value - acsf2.Value);
|
||||
var v1len = Math.Max(Math.Abs(acsf1.Value), 1);
|
||||
if (vdiff > 1e-2f * v1len)
|
||||
{ continue; }
|
||||
}
|
||||
else if (sc1.Type == AnimChannelType.RawFloat)
|
||||
{
|
||||
var acrf1 = sc1 as AnimChannelRawFloat;
|
||||
var acrf2 = sc2 as AnimChannelRawFloat;
|
||||
for (int v = 0; v < acrf1.Values.Length; v++)
|
||||
{
|
||||
var v1 = acrf1.Values[v];
|
||||
var v2 = acrf2.Values[v];
|
||||
var vdiff = Math.Abs(v1 - v2);
|
||||
var v1len = Math.Max(Math.Abs(v1), 1);
|
||||
if (vdiff > 1e-2f * v1len)
|
||||
{ break; }
|
||||
}
|
||||
}
|
||||
else if (sc1.Type == AnimChannelType.QuantizeFloat)
|
||||
{
|
||||
var acqf1 = sc1 as AnimChannelQuantizeFloat;
|
||||
var acqf2 = sc2 as AnimChannelQuantizeFloat;
|
||||
if (acqf1.ValueBits != acqf2.ValueBits)
|
||||
{ continue; }
|
||||
if (Math.Abs(acqf1.Offset - acqf2.Offset) > (0.001f * Math.Abs(acqf1.Offset)))
|
||||
{ continue; }
|
||||
if (Math.Abs(acqf1.Quantum - acqf2.Quantum) > 0.00001f)
|
||||
{ continue; }
|
||||
for (int v = 0; v < acqf1.Values.Length; v++)
|
||||
{
|
||||
var v1 = acqf1.Values[v];
|
||||
var v2 = acqf2.Values[v];
|
||||
var vdiff = Math.Abs(v1 - v2);
|
||||
var v1len = Math.Max(Math.Abs(v1), 1);
|
||||
if (vdiff > 1e-2f * v1len)
|
||||
{ break; }
|
||||
}
|
||||
}
|
||||
else if (sc1.Type == AnimChannelType.IndirectQuantizeFloat)
|
||||
{
|
||||
var aciqf1 = sc1 as AnimChannelIndirectQuantizeFloat;
|
||||
var aciqf2 = sc2 as AnimChannelIndirectQuantizeFloat;
|
||||
if (aciqf1.FrameBits != aciqf2.FrameBits)
|
||||
{ continue; }
|
||||
if (aciqf1.ValueBits != aciqf2.ValueBits)
|
||||
{ continue; }
|
||||
if (Math.Abs(aciqf1.Offset - aciqf2.Offset) > (0.001f * Math.Abs(aciqf1.Offset)))
|
||||
{ continue; }
|
||||
if (Math.Abs(aciqf1.Quantum - aciqf2.Quantum) > 0.00001f)
|
||||
{ continue; }
|
||||
for (int f = 0; f < aciqf1.Frames.Length; f++)
|
||||
{
|
||||
if (aciqf1.Frames[f] != aciqf2.Frames[f])
|
||||
{ break; }
|
||||
}
|
||||
for (int v = 0; v < aciqf1.Values.Length; v++)
|
||||
{
|
||||
var v1 = aciqf1.Values[v];
|
||||
var v2 = aciqf2.Values[v];
|
||||
var vdiff = Math.Abs(v1 - v2);
|
||||
var v1len = Math.Max(Math.Abs(v1), 1);
|
||||
if (vdiff > 1e-2f * v1len)
|
||||
{ break; }
|
||||
}
|
||||
}
|
||||
else if ((sc1.Type == AnimChannelType.CachedQuaternion1)||(sc1.Type == AnimChannelType.CachedQuaternion2))
|
||||
{
|
||||
var acrf1 = sc1 as AnimChannelCachedQuaternion;
|
||||
var acrf2 = sc2 as AnimChannelCachedQuaternion;
|
||||
if (acrf1.QuatIndex != acrf2.QuatIndex)
|
||||
{ continue; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//for (int f = 0; f < s1.NumFrames; f++)
|
||||
//{
|
||||
// var v1 = ss1.EvaluateVector(f);
|
||||
// var v2 = ss2.EvaluateVector(f);
|
||||
// var vdiff = v1 - v2;
|
||||
// var len = vdiff.Length();
|
||||
// var v1len = Math.Max(v1.Length(), 1);
|
||||
// if (len > 1e-2f*v1len)
|
||||
// { }
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
//if (entry.NameLower.EndsWith(".awc")) //awcs can also contain clip dicts..
|
||||
//{
|
||||
@ -2984,18 +3221,17 @@ namespace CodeWalker.GameFiles
|
||||
// if ((awcfile != null))
|
||||
// { }
|
||||
//}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateStatus("Error! " + ex.ToString());
|
||||
}
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// UpdateStatus("Error! " + ex.ToString());
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
//var sd = Sequence.SeqDict;
|
||||
//if (sd != null)
|
||||
//{
|
||||
//}
|
||||
if (errorfiles.Count > 0)
|
||||
{ }
|
||||
|
||||
}
|
||||
public void TestYtds()
|
||||
{
|
||||
|
@ -1384,18 +1384,6 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
}
|
||||
|
||||
public static string XmlEscape(string unescaped)
|
||||
{
|
||||
if (unescaped == null) return null;
|
||||
XmlDocument doc = new XmlDocument();
|
||||
XmlNode node = doc.CreateElement("root");
|
||||
node.InnerText = unescaped;
|
||||
var escaped = node.InnerXml;
|
||||
if (escaped != unescaped)
|
||||
{ }
|
||||
return node.InnerXml;
|
||||
}
|
||||
|
||||
|
||||
public class PsoCont
|
||||
{
|
||||
@ -1741,11 +1729,18 @@ namespace CodeWalker.GameFiles
|
||||
var cind = ind + 1;
|
||||
var cind2 = ind + 2;
|
||||
for (int i = 0; i < itemCount; i++)
|
||||
{
|
||||
if (arr[i] != null)
|
||||
{
|
||||
OpenTag(sb, cind, "Item");
|
||||
arr[i].WriteXml(sb, cind2);
|
||||
CloseTag(sb, cind, "Item");
|
||||
}
|
||||
else
|
||||
{
|
||||
SelfClosingTag(sb, cind, "Item");
|
||||
}
|
||||
}
|
||||
CloseTag(sb, ind, name);
|
||||
}
|
||||
else
|
||||
@ -1891,6 +1886,22 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
|
||||
|
||||
public static string XmlEscape(string unescaped)
|
||||
{
|
||||
if (unescaped == null) return null;
|
||||
XmlDocument doc = new XmlDocument();
|
||||
XmlNode node = doc.CreateElement("root");
|
||||
node.InnerText = unescaped;
|
||||
var escaped = node.InnerXml;
|
||||
if (escaped != unescaped)
|
||||
{ }
|
||||
return node.InnerXml;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public enum XmlTagMode
|
||||
{
|
||||
None = 0,
|
||||
|
@ -813,6 +813,78 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static T[] ReadItemArray<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.ToArray();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static T[] ReadItemArrayNullable<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)
|
||||
{
|
||||
if (inode.HasChildNodes)
|
||||
{
|
||||
var v = new T();
|
||||
v.ReadXml(inode);
|
||||
vlist.Add(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
vlist.Add(default(T));
|
||||
}
|
||||
}
|
||||
return vlist.ToArray();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static MetaHash[] ReadHashItemArray(XmlNode node, string name)
|
||||
{
|
||||
var vnode = node.SelectSingleNode(name);
|
||||
if (vnode != null)
|
||||
{
|
||||
var inodes = vnode.SelectNodes("Item");
|
||||
if (inodes?.Count > 0)
|
||||
{
|
||||
var vlist = new List<MetaHash>();
|
||||
foreach (XmlNode inode in inodes)
|
||||
{
|
||||
vlist.Add(GetHash(inode.InnerText));
|
||||
}
|
||||
return vlist.ToArray();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct ArrayResults
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -748,7 +748,7 @@ namespace CodeWalker.GameFiles
|
||||
public ushort EntriesCapacity { get; private set; }
|
||||
|
||||
// reference data
|
||||
public T[] data_items { get; private set; }
|
||||
public T[] data_items { get; set; }
|
||||
|
||||
private ResourceSystemStructBlock<T> data_block;//used for saving.
|
||||
|
||||
|
@ -218,11 +218,35 @@ namespace CodeWalker
|
||||
return GetRawByteArray(cnode);
|
||||
}
|
||||
|
||||
public static uint[] GetRawUintArray(XmlNode node)
|
||||
{
|
||||
if (node == null) return new uint[0];
|
||||
var data = new List<uint>();
|
||||
var split = Regex.Split(node.InnerText, @"[\s\r\n\t]");
|
||||
for (int i = 0; i < split.Length; i++)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(split[i]))
|
||||
{
|
||||
var str = split[i];
|
||||
if (string.IsNullOrEmpty(str)) continue;
|
||||
var val = 0u;
|
||||
uint.TryParse(str, out val);
|
||||
data.Add(val);
|
||||
}
|
||||
}
|
||||
return data.ToArray();
|
||||
}
|
||||
public static uint[] GetChildRawUintArray(XmlNode node, string name)
|
||||
{
|
||||
var cnode = node.SelectSingleNode(name);
|
||||
return GetRawUintArray(cnode);
|
||||
}
|
||||
|
||||
public static float[] GetRawFloatArray(XmlNode node)
|
||||
{
|
||||
if (node == null) return new float[0];
|
||||
var items = new List<float>();
|
||||
var split = node.InnerText.Split('\n');// Regex.Split(node.InnerText, @"[\s\r\n\t]");
|
||||
var split = Regex.Split(node.InnerText, @"[\s\r\n\t]");//node.InnerText.Split('\n');//
|
||||
for (int i = 0; i < split.Length; i++)
|
||||
{
|
||||
var s = split[i]?.Trim();
|
||||
|
102
Forms/YcdForm.Designer.cs
generated
102
Forms/YcdForm.Designer.cs
generated
@ -28,6 +28,7 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.Windows.Forms.ListViewGroup listViewGroup1 = new System.Windows.Forms.ListViewGroup("Clips", System.Windows.Forms.HorizontalAlignment.Left);
|
||||
System.Windows.Forms.ListViewGroup listViewGroup2 = new System.Windows.Forms.ListViewGroup("Animations", System.Windows.Forms.HorizontalAlignment.Left);
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(YcdForm));
|
||||
@ -35,10 +36,18 @@
|
||||
this.MainListView = new System.Windows.Forms.ListView();
|
||||
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.MainPropertyGrid = new CodeWalker.WinForms.ReadOnlyPropertyGrid();
|
||||
this.MainTabControl = new System.Windows.Forms.TabControl();
|
||||
this.DetailsTabPage = new System.Windows.Forms.TabPage();
|
||||
this.XmlTabPage = new System.Windows.Forms.TabPage();
|
||||
this.XmlTextBox = new FastColoredTextBoxNS.FastColoredTextBox();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
this.MainTabControl.SuspendLayout();
|
||||
this.DetailsTabPage.SuspendLayout();
|
||||
this.XmlTabPage.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.XmlTextBox)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// splitContainer1
|
||||
@ -55,7 +64,7 @@
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.MainPropertyGrid);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(763, 474);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(751, 442);
|
||||
this.splitContainer1.SplitterDistance = 254;
|
||||
this.splitContainer1.TabIndex = 1;
|
||||
//
|
||||
@ -78,7 +87,7 @@
|
||||
this.MainListView.Location = new System.Drawing.Point(3, 3);
|
||||
this.MainListView.MultiSelect = false;
|
||||
this.MainListView.Name = "MainListView";
|
||||
this.MainListView.Size = new System.Drawing.Size(248, 468);
|
||||
this.MainListView.Size = new System.Drawing.Size(248, 436);
|
||||
this.MainListView.TabIndex = 0;
|
||||
this.MainListView.UseCompatibleStateImageBehavior = false;
|
||||
this.MainListView.View = System.Windows.Forms.View.Details;
|
||||
@ -98,15 +107,92 @@
|
||||
this.MainPropertyGrid.Location = new System.Drawing.Point(3, 3);
|
||||
this.MainPropertyGrid.Name = "MainPropertyGrid";
|
||||
this.MainPropertyGrid.ReadOnly = false;
|
||||
this.MainPropertyGrid.Size = new System.Drawing.Size(499, 468);
|
||||
this.MainPropertyGrid.Size = new System.Drawing.Size(487, 436);
|
||||
this.MainPropertyGrid.TabIndex = 0;
|
||||
//
|
||||
// MainTabControl
|
||||
//
|
||||
this.MainTabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.MainTabControl.Controls.Add(this.DetailsTabPage);
|
||||
this.MainTabControl.Controls.Add(this.XmlTabPage);
|
||||
this.MainTabControl.Location = new System.Drawing.Point(2, 3);
|
||||
this.MainTabControl.Name = "MainTabControl";
|
||||
this.MainTabControl.SelectedIndex = 0;
|
||||
this.MainTabControl.Size = new System.Drawing.Size(759, 468);
|
||||
this.MainTabControl.TabIndex = 2;
|
||||
this.MainTabControl.SelectedIndexChanged += new System.EventHandler(this.MainTabControl_SelectedIndexChanged);
|
||||
//
|
||||
// DetailsTabPage
|
||||
//
|
||||
this.DetailsTabPage.Controls.Add(this.splitContainer1);
|
||||
this.DetailsTabPage.Location = new System.Drawing.Point(4, 22);
|
||||
this.DetailsTabPage.Name = "DetailsTabPage";
|
||||
this.DetailsTabPage.Size = new System.Drawing.Size(751, 442);
|
||||
this.DetailsTabPage.TabIndex = 0;
|
||||
this.DetailsTabPage.Text = "Details";
|
||||
this.DetailsTabPage.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// XmlTabPage
|
||||
//
|
||||
this.XmlTabPage.Controls.Add(this.XmlTextBox);
|
||||
this.XmlTabPage.Location = new System.Drawing.Point(4, 22);
|
||||
this.XmlTabPage.Name = "XmlTabPage";
|
||||
this.XmlTabPage.Size = new System.Drawing.Size(751, 442);
|
||||
this.XmlTabPage.TabIndex = 1;
|
||||
this.XmlTabPage.Text = "XML";
|
||||
this.XmlTabPage.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// XmlTextBox
|
||||
//
|
||||
this.XmlTextBox.AutoCompleteBracketsList = new char[] {
|
||||
'(',
|
||||
')',
|
||||
'{',
|
||||
'}',
|
||||
'[',
|
||||
']',
|
||||
'\"',
|
||||
'\"',
|
||||
'\'',
|
||||
'\''};
|
||||
this.XmlTextBox.AutoIndentChars = false;
|
||||
this.XmlTextBox.AutoIndentCharsPatterns = "";
|
||||
this.XmlTextBox.AutoIndentExistingLines = false;
|
||||
this.XmlTextBox.AutoScrollMinSize = new System.Drawing.Size(27, 14);
|
||||
this.XmlTextBox.BackBrush = null;
|
||||
this.XmlTextBox.CharHeight = 14;
|
||||
this.XmlTextBox.CharWidth = 8;
|
||||
this.XmlTextBox.CommentPrefix = null;
|
||||
this.XmlTextBox.Cursor = System.Windows.Forms.Cursors.IBeam;
|
||||
this.XmlTextBox.DelayedEventsInterval = 1;
|
||||
this.XmlTextBox.DisabledColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(180)))), ((int)(((byte)(180)))), ((int)(((byte)(180)))));
|
||||
this.XmlTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.XmlTextBox.Font = new System.Drawing.Font("Courier New", 9.75F);
|
||||
this.XmlTextBox.IsReplaceMode = false;
|
||||
this.XmlTextBox.Language = FastColoredTextBoxNS.Language.XML;
|
||||
this.XmlTextBox.LeftBracket = '<';
|
||||
this.XmlTextBox.LeftBracket2 = '(';
|
||||
this.XmlTextBox.Location = new System.Drawing.Point(0, 0);
|
||||
this.XmlTextBox.Name = "XmlTextBox";
|
||||
this.XmlTextBox.Paddings = new System.Windows.Forms.Padding(0);
|
||||
this.XmlTextBox.RightBracket = '>';
|
||||
this.XmlTextBox.RightBracket2 = ')';
|
||||
this.XmlTextBox.SelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255)))));
|
||||
this.XmlTextBox.ServiceColors = ((FastColoredTextBoxNS.ServiceColors)(resources.GetObject("XmlTextBox.ServiceColors")));
|
||||
this.XmlTextBox.Size = new System.Drawing.Size(751, 442);
|
||||
this.XmlTextBox.TabIndex = 1;
|
||||
this.XmlTextBox.Zoom = 100;
|
||||
this.XmlTextBox.TextChanged += new System.EventHandler<FastColoredTextBoxNS.TextChangedEventArgs>(this.XmlTextBox_TextChanged);
|
||||
this.XmlTextBox.VisibleRangeChangedDelayed += new System.EventHandler(this.XmlTextBox_VisibleRangeChangedDelayed);
|
||||
//
|
||||
// YcdForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(763, 474);
|
||||
this.Controls.Add(this.splitContainer1);
|
||||
this.Controls.Add(this.MainTabControl);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Name = "YcdForm";
|
||||
this.Text = "Clip Dictionary Inspector - CodeWalker by dexyfex";
|
||||
@ -114,6 +200,10 @@
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
this.MainTabControl.ResumeLayout(false);
|
||||
this.DetailsTabPage.ResumeLayout(false);
|
||||
this.XmlTabPage.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.XmlTextBox)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
@ -123,5 +213,9 @@
|
||||
private System.Windows.Forms.ListView MainListView;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader1;
|
||||
private WinForms.ReadOnlyPropertyGrid MainPropertyGrid;
|
||||
private System.Windows.Forms.TabControl MainTabControl;
|
||||
private System.Windows.Forms.TabPage DetailsTabPage;
|
||||
private System.Windows.Forms.TabPage XmlTabPage;
|
||||
private FastColoredTextBoxNS.FastColoredTextBox XmlTextBox;
|
||||
}
|
||||
}
|
132
Forms/YcdForm.cs
132
Forms/YcdForm.cs
@ -1,4 +1,5 @@
|
||||
using CodeWalker.GameFiles;
|
||||
using FastColoredTextBoxNS;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
@ -29,6 +30,8 @@ namespace CodeWalker.Forms
|
||||
}
|
||||
public string FilePath { get; set; }
|
||||
|
||||
private bool LoadingXml = false;
|
||||
private bool DelayHighlight = false;
|
||||
|
||||
|
||||
public YcdForm()
|
||||
@ -43,30 +46,7 @@ namespace CodeWalker.Forms
|
||||
|
||||
private void ExportOnim_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (MainListView.SelectedItems[0].Tag is Animation anim)
|
||||
{
|
||||
var saveFileDialog = new SaveFileDialog();
|
||||
|
||||
string newfn = $"{Path.GetFileNameWithoutExtension(Ycd.Name)}_{MainListView.SelectedItems[0].Text}.onim";
|
||||
|
||||
saveFileDialog.FileName = newfn;
|
||||
if (saveFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
string path = saveFileDialog.FileName;
|
||||
|
||||
try
|
||||
{
|
||||
using (var file = File.OpenWrite(path))
|
||||
{
|
||||
Ycd.SaveOpenFormatsAnimation(anim, file);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("Error saving file " + path + ":\n" + ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFormTitle()
|
||||
@ -74,6 +54,49 @@ namespace CodeWalker.Forms
|
||||
Text = fileName + " - Clip Dictionary Inspector - CodeWalker by dexyfex";
|
||||
}
|
||||
|
||||
private void UpdateXmlTextBox(string xml)
|
||||
{
|
||||
LoadingXml = true;
|
||||
XmlTextBox.Text = "";
|
||||
XmlTextBox.Language = Language.XML;
|
||||
DelayHighlight = false;
|
||||
|
||||
if (string.IsNullOrEmpty(xml))
|
||||
{
|
||||
LoadingXml = false;
|
||||
return;
|
||||
}
|
||||
//if (xml.Length > (1048576 * 5))
|
||||
//{
|
||||
// XmlTextBox.Language = Language.Custom;
|
||||
// XmlTextBox.Text = "[XML size > 10MB - Not shown due to performance limitations - Please use an external viewer for this file.]";
|
||||
// return;
|
||||
//}
|
||||
//else
|
||||
if (xml.Length > (1024 * 512))
|
||||
{
|
||||
XmlTextBox.Language = Language.Custom;
|
||||
DelayHighlight = true;
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// XmlTextBox.Language = Language.XML;
|
||||
//}
|
||||
|
||||
|
||||
Cursor = Cursors.WaitCursor;
|
||||
|
||||
|
||||
|
||||
XmlTextBox.Text = xml;
|
||||
//XmlTextBox.IsChanged = false;
|
||||
XmlTextBox.ClearUndo();
|
||||
|
||||
Cursor = Cursors.Default;
|
||||
LoadingXml = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void LoadYcd(YcdFile ycd)
|
||||
{
|
||||
@ -120,8 +143,60 @@ namespace CodeWalker.Forms
|
||||
|
||||
}
|
||||
|
||||
public void LoadXml()
|
||||
{
|
||||
if (Ycd != null)
|
||||
{
|
||||
var xml = YcdXml.GetXml(Ycd);
|
||||
UpdateXmlTextBox(xml);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void HTMLSyntaxHighlight(Range range)
|
||||
{
|
||||
try
|
||||
{
|
||||
Style BlueStyle = new TextStyle(Brushes.Blue, null, FontStyle.Regular);
|
||||
Style RedStyle = new TextStyle(Brushes.Red, null, FontStyle.Regular);
|
||||
Style MaroonStyle = new TextStyle(Brushes.Maroon, null, FontStyle.Regular);
|
||||
|
||||
//clear style of changed range
|
||||
range.ClearStyle(BlueStyle, MaroonStyle, RedStyle);
|
||||
//tag brackets highlighting
|
||||
range.SetStyle(BlueStyle, @"<|/>|</|>");
|
||||
//tag name
|
||||
range.SetStyle(MaroonStyle, @"<(?<range>[!\w]+)");
|
||||
//end of tag
|
||||
range.SetStyle(MaroonStyle, @"</(?<range>\w+)>");
|
||||
//attributes
|
||||
range.SetStyle(RedStyle, @"(?<range>\S+?)='[^']*'|(?<range>\S+)=""[^""]*""|(?<range>\S+)=\S+");
|
||||
//attribute values
|
||||
range.SetStyle(BlueStyle, @"\S+?=(?<range>'[^']*')|\S+=(?<range>""[^""]*"")|\S+=(?<range>\S+)");
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
|
||||
private void XmlTextBox_VisibleRangeChangedDelayed(object sender, EventArgs e)
|
||||
{
|
||||
//this approach is much faster to load, but no outlining is available
|
||||
|
||||
//highlight only visible area of text
|
||||
if (DelayHighlight)
|
||||
{
|
||||
HTMLSyntaxHighlight(XmlTextBox.VisibleRange);
|
||||
}
|
||||
}
|
||||
|
||||
private void XmlTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (!LoadingXml)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void MainListView_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (MainListView.SelectedItems.Count == 1)
|
||||
@ -143,5 +218,16 @@ namespace CodeWalker.Forms
|
||||
//MainPropertyGrid.SelectedObject = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void MainTabControl_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (MainTabControl.SelectedTab == XmlTabPage)
|
||||
{
|
||||
if (string.IsNullOrEmpty(XmlTextBox.Text))
|
||||
{
|
||||
LoadXml();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -117,6 +117,24 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="XmlTextBox.ServiceColors" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>
|
||||
AAEAAAD/////AQAAAAAAAAAMAgAAAFdGYXN0Q29sb3JlZFRleHRCb3gsIFZlcnNpb249Mi4xNi4yNC4w
|
||||
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWZiOGFhMTJiOTk0ZWY2MWIMAwAAAFFTeXN0
|
||||
ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2Vu
|
||||
PWIwM2Y1ZjdmMTFkNTBhM2EFAQAAACJGYXN0Q29sb3JlZFRleHRCb3hOUy5TZXJ2aWNlQ29sb3JzBgAA
|
||||
ACg8Q29sbGFwc2VNYXJrZXJGb3JlQ29sb3I+a19fQmFja2luZ0ZpZWxkKDxDb2xsYXBzZU1hcmtlckJh
|
||||
Y2tDb2xvcj5rX19CYWNraW5nRmllbGQqPENvbGxhcHNlTWFya2VyQm9yZGVyQ29sb3I+a19fQmFja2lu
|
||||
Z0ZpZWxkJjxFeHBhbmRNYXJrZXJGb3JlQ29sb3I+a19fQmFja2luZ0ZpZWxkJjxFeHBhbmRNYXJrZXJC
|
||||
YWNrQ29sb3I+a19fQmFja2luZ0ZpZWxkKDxFeHBhbmRNYXJrZXJCb3JkZXJDb2xvcj5rX19CYWNraW5n
|
||||
RmllbGQEBAQEBAQUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5c3RlbS5EcmF3aW5nLkNvbG9yAwAA
|
||||
ABRTeXN0ZW0uRHJhd2luZy5Db2xvcgMAAAAUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5c3RlbS5E
|
||||
cmF3aW5nLkNvbG9yAwAAABRTeXN0ZW0uRHJhd2luZy5Db2xvcgMAAAACAAAABfz///8UU3lzdGVtLkRy
|
||||
YXdpbmcuQ29sb3IEAAAABG5hbWUFdmFsdWUKa25vd25Db2xvcgVzdGF0ZQEAAAAJBwcDAAAACgAAAAAA
|
||||
AAAAlgABAAH7/////P///woAAAAAAAAAAKQAAQAB+v////z///8KAAAAAAAAAACWAAEAAfn////8////
|
||||
CgAAAAAAAAAATgABAAH4/////P///woAAAAAAAAAAKQAAQAB9/////z///8KAAAAAAAAAACWAAEACw==
|
||||
</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
|
14
Peds/PedsForm.Designer.cs
generated
14
Peds/PedsForm.Designer.cs
generated
@ -108,6 +108,7 @@
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.ToolsTabControl = new System.Windows.Forms.TabControl();
|
||||
this.ToolsPanel = new System.Windows.Forms.Panel();
|
||||
this.EnableRootMotionCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.ConsolePanel.SuspendLayout();
|
||||
this.ToolsOptionsTabPage.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.TimeOfDayTrackBar)).BeginInit();
|
||||
@ -656,6 +657,7 @@
|
||||
//
|
||||
// ToolsPedTabPage
|
||||
//
|
||||
this.ToolsPedTabPage.Controls.Add(this.EnableRootMotionCheckBox);
|
||||
this.ToolsPedTabPage.Controls.Add(this.label23);
|
||||
this.ToolsPedTabPage.Controls.Add(this.label22);
|
||||
this.ToolsPedTabPage.Controls.Add(this.ClipComboBox);
|
||||
@ -1064,6 +1066,17 @@
|
||||
this.ToolsPanel.TabIndex = 7;
|
||||
this.ToolsPanel.Visible = false;
|
||||
//
|
||||
// EnableRootMotionCheckBox
|
||||
//
|
||||
this.EnableRootMotionCheckBox.AutoSize = true;
|
||||
this.EnableRootMotionCheckBox.Location = new System.Drawing.Point(54, 503);
|
||||
this.EnableRootMotionCheckBox.Name = "EnableRootMotionCheckBox";
|
||||
this.EnableRootMotionCheckBox.Size = new System.Drawing.Size(114, 17);
|
||||
this.EnableRootMotionCheckBox.TabIndex = 32;
|
||||
this.EnableRootMotionCheckBox.Text = "Enable root motion";
|
||||
this.EnableRootMotionCheckBox.UseVisualStyleBackColor = true;
|
||||
this.EnableRootMotionCheckBox.CheckedChanged += new System.EventHandler(this.EnableRootMotionCheckBox_CheckedChanged);
|
||||
//
|
||||
// PedsForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
@ -1184,5 +1197,6 @@
|
||||
private System.Windows.Forms.Label label21;
|
||||
private System.Windows.Forms.ComboBox ClipDictComboBox;
|
||||
private System.Windows.Forms.Label label23;
|
||||
private System.Windows.Forms.CheckBox EnableRootMotionCheckBox;
|
||||
}
|
||||
}
|
142
Peds/PedsForm.cs
142
Peds/PedsForm.cs
@ -92,6 +92,7 @@ namespace CodeWalker.Peds
|
||||
public ClipMapEntry AnimClip { get; set; } = null;
|
||||
public Drawable[] Drawables { get; set; } = new Drawable[12];
|
||||
public Texture[] Textures { get; set; } = new Texture[12];
|
||||
public bool EnableRootMotion { get; set; } = false; //used to toggle whether or not to include root motion when playing animations
|
||||
}
|
||||
|
||||
PedSelection SelectedPed = new PedSelection();
|
||||
@ -971,6 +972,80 @@ namespace CodeWalker.Peds
|
||||
|
||||
|
||||
|
||||
private void LoadClipDict(string name)
|
||||
{
|
||||
var ycdhash = JenkHash.GenHash(name.ToLowerInvariant());
|
||||
var ycd = GameFileCache.GetYcd(ycdhash);
|
||||
while ((ycd != null) && (!ycd.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
ycd = GameFileCache.GetYcd(ycdhash);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//if (ycd != null)
|
||||
//{
|
||||
// ////// TESTING XML CONVERSIONS
|
||||
// var xml = YcdXml.GetXml(ycd);
|
||||
// var ycd2 = XmlYcd.GetYcd(xml);
|
||||
// var data = ycd2.Save();
|
||||
// var ycd3 = new YcdFile();
|
||||
// RpfFile.LoadResourceFile(ycd3, data, 46);
|
||||
// //var xml2 = YcdXml.GetXml(ycd3);
|
||||
// //if (xml != xml2)
|
||||
// //{ }
|
||||
// ycd = ycd3;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
SelectedPed.Ycd = ycd;
|
||||
|
||||
ClipComboBox.Items.Clear();
|
||||
ClipComboBox.Items.Add("");
|
||||
|
||||
if (ycd?.ClipMapEntries == null)
|
||||
{
|
||||
ClipComboBox.SelectedIndex = 0;
|
||||
SelectedPed.AnimClip = null;
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> items = new List<string>();
|
||||
|
||||
foreach (var cme in ycd.ClipMapEntries)
|
||||
{
|
||||
var animclip = cme.Clip as ClipAnimation;
|
||||
if (animclip != null)
|
||||
{
|
||||
items.Add(animclip.ShortName);
|
||||
continue;
|
||||
}
|
||||
var animcliplist = cme.Clip as ClipAnimationList;
|
||||
if (animcliplist?.Animations?.Data != null)
|
||||
{
|
||||
items.Add(animcliplist.ShortName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
items.Sort();
|
||||
foreach (var item in items)
|
||||
{
|
||||
ClipComboBox.Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectClip(string name)
|
||||
{
|
||||
MetaHash cliphash = JenkHash.GenHash(name);
|
||||
ClipMapEntry cme = null;
|
||||
SelectedPed.Ycd?.ClipMap?.TryGetValue(cliphash, out cme);
|
||||
SelectedPed.AnimClip = cme;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1193,6 +1268,10 @@ namespace CodeWalker.Peds
|
||||
|
||||
var td = SelectedPed.Ytd?.TextureDict;
|
||||
var ac = SelectedPed.AnimClip;
|
||||
if (ac != null)
|
||||
{
|
||||
ac.EnableRootMotion = SelectedPed.EnableRootMotion;
|
||||
}
|
||||
|
||||
var skel = SelectedPed.Yft?.Fragment?.Drawable?.Skeleton;
|
||||
if (skel != null)
|
||||
@ -1788,69 +1867,22 @@ namespace CodeWalker.Peds
|
||||
|
||||
private void ClipDictComboBox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
var ycdhash = JenkHash.GenHash(ClipDictComboBox.Text.ToLowerInvariant());
|
||||
var ycd = GameFileCache.GetYcd(ycdhash);
|
||||
while ((ycd != null) && (!ycd.Loaded))
|
||||
{
|
||||
Thread.Sleep(20);//kinda hacky
|
||||
ycd = GameFileCache.GetYcd(ycdhash);
|
||||
}
|
||||
|
||||
SelectedPed.Ycd = ycd;
|
||||
|
||||
ClipComboBox.Items.Clear();
|
||||
ClipComboBox.Items.Add("");
|
||||
|
||||
if (ycd?.ClipMapEntries == null)
|
||||
{
|
||||
ClipComboBox.SelectedIndex = 0;
|
||||
SelectedPed.AnimClip = null;
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> items = new List<string>();
|
||||
|
||||
foreach (var cme in ycd.ClipMapEntries)
|
||||
{
|
||||
var animclip = cme.Clip as ClipAnimation;
|
||||
if (animclip != null)
|
||||
{
|
||||
items.Add(animclip.ShortName);
|
||||
continue;
|
||||
}
|
||||
var animcliplist = cme.Clip as ClipAnimationList;
|
||||
if (animcliplist?.Animations?.Data != null)
|
||||
{
|
||||
items.Add(animcliplist.ShortName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
items.Sort();
|
||||
foreach (var item in items)
|
||||
{
|
||||
ClipComboBox.Items.Add(item);
|
||||
}
|
||||
|
||||
|
||||
LoadClipDict(ClipDictComboBox.Text);
|
||||
}
|
||||
|
||||
private void ClipComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
var name = ClipComboBox.Text;
|
||||
|
||||
MetaHash cliphash = JenkHash.GenHash(name);
|
||||
ClipMapEntry cme = null;
|
||||
SelectedPed.Ycd?.ClipMap?.TryGetValue(cliphash, out cme);
|
||||
SelectedPed.AnimClip = cme;
|
||||
SelectClip(ClipComboBox.Text);
|
||||
}
|
||||
|
||||
private void ClipComboBox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
ClipComboBox_SelectedIndexChanged(sender, e);
|
||||
SelectClip(ClipComboBox.Text);
|
||||
}
|
||||
|
||||
private void EnableRootMotionCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
SelectedPed.EnableRootMotion = EnableRootMotionCheckBox.Checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +79,8 @@ namespace CodeWalker.Rendering
|
||||
|
||||
public Matrix3_s[] BoneTransforms;
|
||||
public List<Bone> Bones;
|
||||
public bool EnableRootMotion = false; //used to toggle whether or not to include root motion when playing animations
|
||||
|
||||
|
||||
public override void Init(DrawableBase drawable)
|
||||
{
|
||||
@ -385,39 +387,39 @@ namespace CodeWalker.Rendering
|
||||
BoneTransforms[i] = bt;
|
||||
}
|
||||
|
||||
//var drawbl = Key;
|
||||
//if (AllModels == null) return;
|
||||
//for (int i = 0; i < AllModels.Length; i++)
|
||||
//{
|
||||
// var model = AllModels[i];
|
||||
// if (model?.Geometries == null) continue;
|
||||
// for (int g = 0; g < model.Geometries.Length; g++)
|
||||
// {
|
||||
// var geom = model.Geometries[g];
|
||||
// var boneids = geom?.DrawableGeom?.BoneIds;
|
||||
// if (boneids == null) continue;
|
||||
// if (boneids.Length != Bones.Count)
|
||||
// {
|
||||
// var idc = boneids.Length;
|
||||
// if (geom.BoneTransforms == null)
|
||||
// {
|
||||
// geom.BoneTransforms = new Matrix3_s[idc];
|
||||
// }
|
||||
// for (int b = 0; b < idc; b++)
|
||||
// {
|
||||
// var id = boneids[b];
|
||||
// if (id < BoneTransforms.Length)
|
||||
// {
|
||||
// geom.BoneTransforms[b] = BoneTransforms[id];
|
||||
// if (id != b)
|
||||
// { }
|
||||
// }
|
||||
// else
|
||||
// { }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
var drawbl = Key;
|
||||
if (AllModels == null) return;
|
||||
for (int i = 0; i < AllModels.Length; i++)
|
||||
{
|
||||
var model = AllModels[i];
|
||||
if (model?.Geometries == null) continue;
|
||||
for (int g = 0; g < model.Geometries.Length; g++)
|
||||
{
|
||||
var geom = model.Geometries[g];
|
||||
var boneids = geom?.DrawableGeom?.BoneIds;
|
||||
if (boneids == null) continue;
|
||||
if (boneids.Length != Bones.Count)
|
||||
{
|
||||
var idc = boneids.Length;
|
||||
if (geom.BoneTransforms == null)
|
||||
{
|
||||
geom.BoneTransforms = new Matrix3_s[idc];
|
||||
}
|
||||
for (int b = 0; b < idc; b++)
|
||||
{
|
||||
var id = boneids[b];
|
||||
if (id < BoneTransforms.Length)
|
||||
{
|
||||
geom.BoneTransforms[b] = BoneTransforms[id];
|
||||
if (id != b)
|
||||
{ }
|
||||
}
|
||||
else
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -428,6 +430,8 @@ namespace CodeWalker.Rendering
|
||||
if (CurrentAnimTime == realTime) return;//already updated this!
|
||||
CurrentAnimTime = realTime;
|
||||
|
||||
EnableRootMotion = ClipMapEntry?.EnableRootMotion ?? false;
|
||||
|
||||
if (ClipMapEntry != null)
|
||||
{
|
||||
UpdateAnim(ClipMapEntry); //animate skeleton/models
|
||||
@ -451,6 +455,7 @@ namespace CodeWalker.Rendering
|
||||
}
|
||||
private void UpdateAnim(ClipMapEntry cme)
|
||||
{
|
||||
|
||||
if (cme.Next != null)
|
||||
{
|
||||
UpdateAnim(cme.Next);
|
||||
@ -545,10 +550,13 @@ namespace CodeWalker.Rendering
|
||||
case 5://root motion vector
|
||||
if (bone.Tag != 0)
|
||||
{ }
|
||||
//v0 = aseq.EvaluateVector(f0);
|
||||
//v1 = aseq.EvaluateVector(f1);
|
||||
//v = interpolate ? (v0 * ialpha) + (v1 * falpha) : v0;
|
||||
//bone.AnimTranslation += v.XYZ();
|
||||
if (EnableRootMotion)
|
||||
{
|
||||
v0 = aseq.EvaluateVector(f0);
|
||||
v1 = aseq.EvaluateVector(f1);
|
||||
v = interpolate ? (v0 * ialpha) + (v1 * falpha) : v0;
|
||||
bone.AnimTranslation += v.XYZ();
|
||||
}
|
||||
break;
|
||||
case 6://quaternion... root rotation?
|
||||
if (bone.Tag != 0)
|
||||
@ -574,6 +582,8 @@ namespace CodeWalker.Rendering
|
||||
{ }
|
||||
break;
|
||||
default:
|
||||
if (bone.Tag != 0)
|
||||
{ }
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -832,7 +842,7 @@ namespace CodeWalker.Rendering
|
||||
public bool isHair = false;
|
||||
public bool disableRendering = false;
|
||||
|
||||
//public Matrix3_s[] BoneTransforms = null;
|
||||
public Matrix3_s[] BoneTransforms = null;
|
||||
|
||||
public static ShaderParamNames[] GetTextureSamplerList()
|
||||
{
|
||||
|
@ -801,11 +801,11 @@ namespace CodeWalker.Rendering
|
||||
}
|
||||
|
||||
|
||||
//if (geom.BoneTransforms != null)
|
||||
//{
|
||||
// SetBoneMatrices(context, geom.BoneTransforms);
|
||||
// defaultBoneMatricesBound = false;
|
||||
//}
|
||||
if (geom.BoneTransforms != null)
|
||||
{
|
||||
SetBoneMatrices(context, geom.BoneTransforms);
|
||||
defaultBoneMatricesBound = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -358,11 +358,11 @@ namespace CodeWalker.Rendering
|
||||
}
|
||||
|
||||
|
||||
//if (geom.BoneTransforms != null)
|
||||
//{
|
||||
// SetBoneMatrices(context, geom.BoneTransforms);
|
||||
// defaultBoneMatricesBound = false;
|
||||
//}
|
||||
if (geom.BoneTransforms != null)
|
||||
{
|
||||
SetBoneMatrices(context, geom.BoneTransforms);
|
||||
defaultBoneMatricesBound = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user