mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-06 07:07:24 +08:00
1201 lines
43 KiB
C#
1201 lines
43 KiB
C#
using SharpDX;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
/*
|
|
Copyright(c) 2017 Neodymium
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
*/
|
|
|
|
|
|
//ruthlessly stolen
|
|
|
|
|
|
namespace CodeWalker.GameFiles
|
|
{
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class ExpressionDictionary : ResourceFileBase
|
|
{
|
|
// pgDictionaryBase
|
|
// pgDictionary<crExpressions>
|
|
public override long BlockLength => 0x40;
|
|
|
|
// structure data
|
|
public uint Unknown_10h { get; set; }
|
|
public uint Unknown_14h { get; set; }
|
|
public uint Unknown_18h { get; set; }
|
|
public uint Unknown_1Ch { get; set; }
|
|
public ResourceSimpleList64_s<MetaHash> ExpressionNameHashes { get; set; }
|
|
public ResourcePointerList64<Expression> Expressions { get; set; }
|
|
|
|
|
|
public Dictionary<MetaHash, Expression> ExprMap { get; set; }
|
|
|
|
|
|
public override void Read(ResourceDataReader reader, params object[] parameters)
|
|
{
|
|
base.Read(reader, parameters);
|
|
|
|
// read structure data
|
|
this.Unknown_10h = reader.ReadUInt32();
|
|
this.Unknown_14h = reader.ReadUInt32();
|
|
this.Unknown_18h = reader.ReadUInt32();
|
|
this.Unknown_1Ch = reader.ReadUInt32();
|
|
this.ExpressionNameHashes = reader.ReadBlock<ResourceSimpleList64_s<MetaHash>>();
|
|
this.Expressions = reader.ReadBlock<ResourcePointerList64<Expression>>();
|
|
|
|
BuildMap();
|
|
}
|
|
public override void Write(ResourceDataWriter writer, params object[] parameters)
|
|
{
|
|
base.Write(writer, parameters);
|
|
|
|
// write structure data
|
|
writer.Write(this.Unknown_10h);
|
|
writer.Write(this.Unknown_14h);
|
|
writer.Write(this.Unknown_18h);
|
|
writer.Write(this.Unknown_1Ch);
|
|
writer.WriteBlock(this.ExpressionNameHashes);
|
|
writer.WriteBlock(this.Expressions);
|
|
}
|
|
|
|
public override IResourceBlock[] GetReferences()
|
|
{
|
|
var list = new List<IResourceBlock>(base.GetReferences());
|
|
return list.ToArray();
|
|
}
|
|
public override Tuple<long, IResourceBlock>[] GetParts()
|
|
{
|
|
return new Tuple<long, IResourceBlock>[] {
|
|
new Tuple<long, IResourceBlock>(0x20, ExpressionNameHashes),
|
|
new Tuple<long, IResourceBlock>(0x30, Expressions)
|
|
};
|
|
}
|
|
|
|
|
|
public void BuildMap()
|
|
{
|
|
ExprMap = new Dictionary<MetaHash, Expression>();
|
|
|
|
if ((Expressions?.data_items != null) && (ExpressionNameHashes?.data_items != null))
|
|
{
|
|
var exprs = Expressions.data_items;
|
|
var names = ExpressionNameHashes.data_items;
|
|
|
|
for (int i = 0; i < exprs.Length; i++)
|
|
{
|
|
var expr = exprs[i];
|
|
var name = (i < names.Length) ? names[i] : (MetaHash)JenkHash.GenHash(expr?.Name?.ToString()?.ToLowerInvariant() ?? "");
|
|
ExprMap[name] = expr;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class Expression : ResourceSystemBlock
|
|
{
|
|
// pgBase
|
|
// crExpressions
|
|
public override long BlockLength => 0x90;
|
|
|
|
// structure data
|
|
public uint VFT { get; set; }
|
|
public uint Unknown_4h { get; set; } = 1;
|
|
public uint Unknown_8h { get; set; } // 0x00000000
|
|
public uint Unknown_Ch { get; set; } // 0x00000000
|
|
public uint Unknown_10h { get; set; } // 0x00000000
|
|
public uint Unknown_14h { get; set; } // 0x00000000
|
|
public uint Unknown_18h { get; set; } // 0x00000000
|
|
public uint Unknown_1Ch { get; set; } // 0x00000000
|
|
public ResourcePointerList64<ExpressionUnk1> Unknown_20h { get; set; }
|
|
public ResourceSimpleList64_s<ExpressionBoneTrack> BoneTracks { get; set; } // bone tags / animation tracks..??
|
|
public ResourceSimpleList64<ExpressionUnk2> Unknown_40h { get; set; }
|
|
public ResourceSimpleList64_s<MetaHash> Unknown_50h { get; set; } // only for: faceinit.expr, independent_mover.expr
|
|
public ulong NamePointer { get; set; }
|
|
public ushort NameLength { get; set; } // name len
|
|
public ushort NameCapacity { get; set; } // name len+1
|
|
public uint Unknown_6Ch { get; set; } // 0x00000000
|
|
public uint Unknown_70h { get; set; } = 1;
|
|
public MetaHash Unknown_74h { get; set; } // seems to be a hash?
|
|
public ushort Unk1ItemLength { get; set; } // max length of any Unk1 item in Unknown_20h
|
|
public ushort Unknown_7Ah { get; set; } // 0x0000
|
|
public uint Unknown_7Ch { get; set; } // 3 or 2
|
|
public uint Unknown_80h { get; set; } // 0x00000000
|
|
public uint Unknown_84h { get; set; } // 0x00000000
|
|
public uint Unknown_88h { get; set; } // 0x00000000
|
|
public uint Unknown_8Ch { get; set; } // 0x00000000
|
|
|
|
// reference data
|
|
public string_r Name;
|
|
|
|
|
|
public Dictionary<ExpressionBoneTrack, ExpressionBoneTrack> BoneTracksDict { get; set; }
|
|
|
|
|
|
public override void Read(ResourceDataReader reader, params object[] parameters)
|
|
{
|
|
// read structure data
|
|
this.VFT = reader.ReadUInt32();
|
|
this.Unknown_4h = reader.ReadUInt32();
|
|
this.Unknown_8h = reader.ReadUInt32();
|
|
this.Unknown_Ch = reader.ReadUInt32();
|
|
this.Unknown_10h = reader.ReadUInt32();
|
|
this.Unknown_14h = reader.ReadUInt32();
|
|
this.Unknown_18h = reader.ReadUInt32();
|
|
this.Unknown_1Ch = reader.ReadUInt32();
|
|
this.Unknown_20h = reader.ReadBlock<ResourcePointerList64<ExpressionUnk1>>();
|
|
this.BoneTracks = reader.ReadBlock<ResourceSimpleList64_s<ExpressionBoneTrack>>();
|
|
this.Unknown_40h = reader.ReadBlock<ResourceSimpleList64<ExpressionUnk2>>();
|
|
this.Unknown_50h = reader.ReadBlock<ResourceSimpleList64_s<MetaHash>>();
|
|
this.NamePointer = reader.ReadUInt64();
|
|
this.NameLength = reader.ReadUInt16();
|
|
this.NameCapacity = reader.ReadUInt16();
|
|
this.Unknown_6Ch = reader.ReadUInt32();
|
|
this.Unknown_70h = reader.ReadUInt32();
|
|
this.Unknown_74h = reader.ReadUInt32();
|
|
this.Unk1ItemLength = reader.ReadUInt16();
|
|
this.Unknown_7Ah = reader.ReadUInt16();
|
|
this.Unknown_7Ch = reader.ReadUInt32();
|
|
this.Unknown_80h = reader.ReadUInt32();
|
|
this.Unknown_84h = reader.ReadUInt32();
|
|
this.Unknown_88h = reader.ReadUInt32();
|
|
this.Unknown_8Ch = reader.ReadUInt32();
|
|
|
|
// read reference data
|
|
this.Name = reader.ReadBlockAt<string_r>(
|
|
this.NamePointer // offset
|
|
);
|
|
|
|
//if (Unknown_50h?.data_items?.Length > 0)
|
|
//{ } // faceinit.expr, independent_mover.expr
|
|
|
|
BuildBoneTracksDict();
|
|
|
|
#region testing
|
|
//long tlen = 0;
|
|
//if (Unknown_20h?.data_items != null) foreach (var item in Unknown_20h.data_items) tlen = Math.Max(tlen, item.BlockLength);
|
|
//if (Unk1ItemLength != tlen)
|
|
//{ }//no hit
|
|
|
|
//if (Unknown_4h != 1)
|
|
//{ }//no hit
|
|
//if (Unknown_8h != 0)
|
|
//{ }//no hit
|
|
//if (Unknown_Ch != 0)
|
|
//{ }//no hit
|
|
//if (Unknown_10h != 0)
|
|
//{ }//no hit
|
|
//if (Unknown_14h != 0)
|
|
//{ }//no hit
|
|
//if (Unknown_18h != 0)
|
|
//{ }//no hit
|
|
//if (Unknown_1Ch != 0)
|
|
//{ }//no hit
|
|
//if (NameLength != (Name?.Value?.Length ?? 0))
|
|
//{ }//no hit
|
|
//if (NameCapacity != (NameLength + 1))
|
|
//{ }//no hit
|
|
//if (Unknown_6Ch != 0)
|
|
//{ }//no hit
|
|
//if (Unknown_70h != 1)
|
|
//{ }//no hit
|
|
//switch (Unknown_74h)
|
|
//{
|
|
// default:
|
|
// break;
|
|
//}
|
|
//if (Unknown_7Ah != 0)
|
|
//{ }//no hit
|
|
//switch (Unknown_7Ch)
|
|
//{
|
|
// case 3:
|
|
// case 2:
|
|
// break;
|
|
// default:
|
|
// break;//no hit
|
|
//}
|
|
//if (Unknown_80h != 0)
|
|
//{ }//no hit
|
|
//if (Unknown_84h != 0)
|
|
//{ }//no hit
|
|
//if (Unknown_88h != 0)
|
|
//{ }//no hit
|
|
//if (Unknown_8Ch != 0)
|
|
//{ }//no hit
|
|
#endregion
|
|
}
|
|
public override void Write(ResourceDataWriter writer, params object[] parameters)
|
|
{
|
|
// update structure data
|
|
this.NamePointer = (ulong)(this.Name != null ? this.Name.FilePosition : 0);
|
|
|
|
// write structure data
|
|
writer.Write(this.VFT);
|
|
writer.Write(this.Unknown_4h);
|
|
writer.Write(this.Unknown_8h);
|
|
writer.Write(this.Unknown_Ch);
|
|
writer.Write(this.Unknown_10h);
|
|
writer.Write(this.Unknown_14h);
|
|
writer.Write(this.Unknown_18h);
|
|
writer.Write(this.Unknown_1Ch);
|
|
writer.WriteBlock(this.Unknown_20h);
|
|
writer.WriteBlock(this.BoneTracks);
|
|
writer.WriteBlock(this.Unknown_40h);
|
|
writer.WriteBlock(this.Unknown_50h);
|
|
writer.Write(this.NamePointer);
|
|
writer.Write(this.NameLength);
|
|
writer.Write(this.NameCapacity);
|
|
writer.Write(this.Unknown_6Ch);
|
|
writer.Write(this.Unknown_70h);
|
|
writer.Write(this.Unknown_74h);
|
|
writer.Write(this.Unk1ItemLength);
|
|
writer.Write(this.Unknown_7Ah);
|
|
writer.Write(this.Unknown_7Ch);
|
|
writer.Write(this.Unknown_80h);
|
|
writer.Write(this.Unknown_84h);
|
|
writer.Write(this.Unknown_88h);
|
|
writer.Write(this.Unknown_8Ch);
|
|
}
|
|
|
|
public override IResourceBlock[] GetReferences()
|
|
{
|
|
var list = new List<IResourceBlock>();
|
|
if (Name != null) list.Add(Name);
|
|
return list.ToArray();
|
|
}
|
|
public override Tuple<long, IResourceBlock>[] GetParts()
|
|
{
|
|
return new Tuple<long, IResourceBlock>[] {
|
|
new Tuple<long, IResourceBlock>(0x20, Unknown_20h),
|
|
new Tuple<long, IResourceBlock>(0x30, BoneTracks),
|
|
new Tuple<long, IResourceBlock>(0x40, Unknown_40h),
|
|
new Tuple<long, IResourceBlock>(0x50, Unknown_50h)
|
|
};
|
|
}
|
|
|
|
|
|
public void BuildBoneTracksDict()
|
|
{
|
|
BoneTracksDict = new Dictionary<ExpressionBoneTrack, ExpressionBoneTrack>();
|
|
|
|
if (BoneTracks?.data_items == null) return;
|
|
|
|
var mapto = new ExpressionBoneTrack();
|
|
for(int i=0; i< BoneTracks.data_items.Length;i++)
|
|
{
|
|
var bt = BoneTracks.data_items[i];
|
|
if ((bt.Flags & 128) == 0)
|
|
{
|
|
mapto = bt;
|
|
}
|
|
else if (bt.BoneTag != 0)
|
|
{
|
|
bt.Flags &= 0x7F;
|
|
BoneTracksDict[bt] = mapto;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
public override string ToString()
|
|
{
|
|
return (Name?.ToString() ?? base.ToString()) + " " + Unknown_74h.ToString();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public class ExpressionTreeReader
|
|
{
|
|
public byte[] Data1 { get; set; }
|
|
public byte[] Data2 { get; set; }
|
|
public byte[] Data3 { get; set; }
|
|
|
|
public ExpressionUnk1_Base[] Items { get; set; }
|
|
|
|
public ExpressionTreeReader(byte[] d1, byte[] d2, byte[] d3)
|
|
{
|
|
Data1 = d1;
|
|
Data2 = d2;
|
|
Data3 = d3;
|
|
}
|
|
|
|
public ExpressionUnk1_Base[] ReadItems()
|
|
{
|
|
|
|
var ms1 = new MemoryStream(Data1);
|
|
var ms2 = new MemoryStream(Data2);
|
|
var ms3 = new MemoryStream(Data3);
|
|
var dr1 = new DataReader(ms1);
|
|
var dr2 = new DataReader(ms2);
|
|
var dr3 = new DataReader(ms3);
|
|
|
|
var items = new List<ExpressionUnk1_Base>();
|
|
while (ms3.Position < ms3.Length)
|
|
{
|
|
var type = dr3.ReadByte();
|
|
if (type == 0)
|
|
{
|
|
if (ms3.Position != ms3.Length)
|
|
{ }
|
|
break;
|
|
}
|
|
var item = ExpressionUnk1.CreateItem(type);
|
|
item.Type = type;
|
|
item.Read(dr1, dr2, dr3);
|
|
items.Add(item);
|
|
}
|
|
Items = items.ToArray();
|
|
|
|
if ((dr1.Length - dr1.Position) != 0)
|
|
{ }
|
|
if ((dr2.Length - dr2.Position) != 0)
|
|
{ }
|
|
if ((dr3.Length - dr3.Position) != 0)
|
|
{ }
|
|
|
|
return Items;
|
|
}
|
|
|
|
public ExpressionUnk1_Base[] ReadTree()
|
|
{
|
|
|
|
if (Items == null) return null;
|
|
|
|
var stack = new Stack<ExpressionUnk1_Base>();
|
|
|
|
for (int i = 0; i < Items.Length; i++)
|
|
{
|
|
var item = Items[i];
|
|
|
|
switch (item.Type)
|
|
{
|
|
case 0x01: break;
|
|
case 0x03: break;
|
|
case 0x04: break;
|
|
case 0x05: break;
|
|
case 0x06: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x07: break;
|
|
case 0x09: break;
|
|
case 0x0A: break;
|
|
case 0x0B: break;
|
|
case 0x0E: break;
|
|
case 0x10: item.Children = new[] { stack.Pop() }; break; //####### maybe not
|
|
case 0x11: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x1B: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x1D: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x1E: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x1F: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x20: break;//first in list
|
|
case 0x21: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x22: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x23: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x26: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x27: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x28: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x2A: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x2B: item.Children = new[] { stack.Pop(), stack.Pop(), stack.Pop() }; break;
|
|
case 0x2C: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x2D: item.Children = new[] { stack.Pop(), stack.Pop() }; break;//4 maybe?
|
|
case 0x2E: item.Children = new[] { stack.Pop(), stack.Pop() }; break;
|
|
case 0x2F: item.Children = new[] { stack.Pop(), stack.Pop() }; break;
|
|
case 0x30: item.Children = new[] { stack.Pop(), stack.Pop() }; break;
|
|
case 0x31: item.Children = new[] { stack.Pop(), stack.Pop() }; break;
|
|
case 0x32: item.Children = new[] { stack.Pop(), stack.Pop() }; break;
|
|
case 0x33: item.Children = new[] { stack.Pop(), stack.Pop() }; break;
|
|
case 0x35: item.Children = new[] { stack.Pop(), stack.Pop() }; break;//can't be more than 2
|
|
case 0x36: item.Children = new[] { stack.Pop(), stack.Pop() }; break; //can't be more than 2
|
|
case 0x37: item.Children = new[] { stack.Pop(), stack.Pop(), stack.Pop(), stack.Pop() }; break;
|
|
case 0x38: item.Children = new[] { stack.Pop(), stack.Pop(), stack.Pop() }; break;
|
|
case 0x39: item.Children = new[] { stack.Pop(), stack.Pop(), stack.Pop() }; break;
|
|
case 0x3A: item.Children = new[] { stack.Pop(), stack.Pop(), stack.Pop() }; break;
|
|
case 0x3B: item.Children = new[] { stack.Pop(), stack.Pop(), stack.Pop() }; break; //####### maybe not
|
|
case 0x3C: item.Children = new[] { stack.Pop(), stack.Pop() }; break;
|
|
case 0x3D: item.Children = new[] { stack.Pop(), stack.Pop(), stack.Pop() }; break;
|
|
case 0x3E: item.Children = new[] { stack.Pop(), stack.Pop(), stack.Pop() }; break;
|
|
case 0x3F: item.Children = new[] { stack.Pop(), stack.Pop(), stack.Pop() }; break;
|
|
case 0x40: item.Children = new[] { stack.Pop(), stack.Pop() }; break;
|
|
case 0x42: break;//first in list
|
|
case 0x43: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x44: break;
|
|
case 0x45: break;
|
|
case 0x46: item.Children = new[] { stack.Pop() }; break;
|
|
case 0x49: item.Children = new[] { stack.Pop(), stack.Pop(), stack.Pop() }; break;
|
|
default: break;//no hit
|
|
}
|
|
|
|
stack.Push(item);
|
|
}
|
|
|
|
var roots = stack.Reverse().ToArray();
|
|
|
|
return roots;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class ExpressionUnk1 : ResourceSystemBlock
|
|
{
|
|
public override long BlockLength
|
|
{
|
|
get { return 16 + Data1.Length + Data2.Length + Data3.Length; }
|
|
}
|
|
|
|
// structure data
|
|
public MetaHash Unknown_0h { get; set; }
|
|
public uint Data1Length { get; set; }
|
|
public uint Data2Length { get; set; }
|
|
public ushort Data3Length { get; set; }
|
|
public ushort Unknown_Eh { get; set; }
|
|
public byte[] Data1 { get; set; }
|
|
public byte[] Data2 { get; set; }
|
|
public byte[] Data3 { get; set; }
|
|
|
|
|
|
public ExpressionUnk1_Base[] Items { get; set; }
|
|
public ExpressionUnk1_Base[] Roots { get; set; }
|
|
|
|
|
|
|
|
public override void Read(ResourceDataReader reader, params object[] parameters)
|
|
{
|
|
// read structure data
|
|
this.Unknown_0h = reader.ReadUInt32();
|
|
this.Data1Length = reader.ReadUInt32();
|
|
this.Data2Length = reader.ReadUInt32();
|
|
this.Data3Length = reader.ReadUInt16();
|
|
this.Unknown_Eh = reader.ReadUInt16();
|
|
this.Data1 = reader.ReadBytes((int)Data1Length);
|
|
this.Data2 = reader.ReadBytes((int)Data2Length);
|
|
this.Data3 = reader.ReadBytes((int)Data3Length);
|
|
|
|
|
|
var treereader = new ExpressionTreeReader(Data1, Data2, Data3);
|
|
Items = treereader.ReadItems();
|
|
Roots = treereader.ReadTree();
|
|
|
|
#region testing
|
|
//switch (Unknown_Eh)
|
|
//{
|
|
// case 2:
|
|
// case 8:
|
|
// case 4:
|
|
// case 6:
|
|
// case 59:
|
|
// case 5:
|
|
// case 12:
|
|
// case 58:
|
|
// case 20:
|
|
// case 10:
|
|
// case 9:
|
|
// case 1:
|
|
// case 50:
|
|
// case 14:
|
|
// case 19:
|
|
// case 7:
|
|
// case 25:
|
|
// case 15:
|
|
// case 13:
|
|
// case 28:
|
|
// case 17:
|
|
// case 22:
|
|
// case 26:
|
|
// case 18:
|
|
// case 21:
|
|
// case 23:
|
|
// case 11:
|
|
// case 24:
|
|
// case 27:
|
|
// case 30:
|
|
// case 16:
|
|
// case 377:
|
|
// case 31:
|
|
// case 125:
|
|
// case 32:
|
|
// case 34:
|
|
// case 52:
|
|
// case 51:
|
|
// case 345:
|
|
// case 399:
|
|
// break;
|
|
// default:
|
|
// break;//no hit
|
|
//}
|
|
#endregion
|
|
}
|
|
public override void Write(ResourceDataWriter writer, params object[] parameters)
|
|
{
|
|
// write structure data
|
|
writer.Write(this.Unknown_0h);
|
|
writer.Write(this.Data1Length);
|
|
writer.Write(this.Data2Length);
|
|
writer.Write(this.Data3Length);
|
|
writer.Write(this.Unknown_Eh);
|
|
writer.Write(this.Data1);
|
|
writer.Write(this.Data2);
|
|
writer.Write(this.Data3);
|
|
}
|
|
|
|
|
|
|
|
public static ExpressionUnk1_Base CreateItem(byte type)
|
|
{
|
|
switch (type)
|
|
{
|
|
//case 0:
|
|
case 0x21:
|
|
case 0x30:
|
|
case 0x3D:
|
|
case 0x03:
|
|
case 0x01:
|
|
case 0x33:
|
|
case 0x2E:
|
|
case 0x31:
|
|
case 0x32:
|
|
case 0x2F:
|
|
case 0x04:
|
|
case 0x10:
|
|
case 0x3B:
|
|
case 0x36:
|
|
case 0x35:
|
|
case 0x39:
|
|
case 0x38:
|
|
case 0x37:
|
|
case 0x1D:
|
|
case 0x1E:
|
|
case 0x46:
|
|
case 0x1F:
|
|
case 0x3A:
|
|
case 0x22:
|
|
case 0x49:
|
|
case 0x3F:
|
|
case 0x1B:
|
|
case 0x40:
|
|
case 0x3C:
|
|
case 0x11:
|
|
return new ExpressionUnk1_Base();
|
|
|
|
case 0x45:
|
|
case 0x44:
|
|
return new ExpressionUnk1_S1();
|
|
|
|
case 0x07:
|
|
case 0x09:
|
|
case 0x0A:
|
|
case 0x23:
|
|
case 0x26:
|
|
case 0x27:
|
|
case 0x28:
|
|
case 0x20:
|
|
case 0x42:
|
|
case 0x43:
|
|
case 0x2A:
|
|
case 0x06:
|
|
return new ExpressionUnk1_S2();
|
|
|
|
case 0x2B:
|
|
case 0x2C:
|
|
case 0x2D:
|
|
return new ExpressionUnk1_2B2C2D();
|
|
|
|
|
|
case 0x0B: return new ExpressionUnk1_0B();
|
|
case 0x05: return new ExpressionUnk1_05();
|
|
case 0x3E: return new ExpressionUnk1_3E();
|
|
case 0x0E: return new ExpressionUnk1_0E();
|
|
|
|
}
|
|
return new ExpressionUnk1_Base();
|
|
}
|
|
|
|
|
|
public override string ToString()
|
|
{
|
|
return Unknown_0h.ToString();
|
|
}
|
|
}
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class ExpressionUnk1_Base
|
|
{
|
|
public byte Type { get; set; }
|
|
public string TypeStr { get => Type.ToString("X").PadLeft(2, '0'); }
|
|
|
|
public ExpressionUnk1_Base[] Children { get; set; }
|
|
|
|
public virtual void Read(DataReader r1, DataReader r2, DataReader r3)
|
|
{ }
|
|
|
|
public override string ToString()
|
|
{
|
|
return TypeStr;
|
|
}
|
|
}
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class ExpressionUnk1_S1 : ExpressionUnk1_Base
|
|
{
|
|
public uint Length { get; set; }
|
|
public uint ItemCount { get; set; }
|
|
public uint ItemType { get; set; }
|
|
public uint Unk1 { get; set; } // 0x00000000
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class Struct1
|
|
{
|
|
public ushort Unk1 { get; set; }//bone index?
|
|
public ushort Unk2 { get; set; }
|
|
|
|
public float[] Values { get; set; }
|
|
|
|
public void Read(DataReader r)
|
|
{
|
|
Unk1 = r.ReadUInt16();
|
|
Unk2 = r.ReadUInt16();
|
|
|
|
switch (Unk2)
|
|
{
|
|
case 0:
|
|
case 4:
|
|
case 8:
|
|
break;
|
|
default:
|
|
break;//no hit
|
|
}
|
|
}
|
|
public override string ToString()
|
|
{
|
|
var str = Unk1.ToString() + ", " + Unk2.ToString();
|
|
if (Values != null)
|
|
{
|
|
str += " - ";
|
|
for (int i = 0; i < Values.Length; i++)
|
|
{
|
|
if (i != 0) str += ", ";
|
|
str += Values[i].ToString();
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
}
|
|
public Struct1[] Items { get; set; }
|
|
|
|
|
|
public override void Read(DataReader r1, DataReader r2, DataReader r3)
|
|
{
|
|
Length = r1.ReadUInt32();
|
|
ItemCount = r1.ReadUInt32();
|
|
ItemType = r1.ReadUInt32();
|
|
Unk1 = r1.ReadUInt32();
|
|
|
|
var valcnt = ((int)ItemType - 1) * 9 + 6;
|
|
var hlen = (int)ItemCount * 4 + 16;
|
|
var dlen = (int)Length - hlen;
|
|
var tlen = (int)ItemCount * valcnt * 4;
|
|
if (tlen != dlen)
|
|
{ }//no hitting
|
|
|
|
|
|
Items = new Struct1[ItemCount];
|
|
for (int i = 0; i < ItemCount; i++)
|
|
{
|
|
var item1 = new Struct1();
|
|
item1.Read(r1);
|
|
Items[i] = item1;
|
|
Items[i].Values = new float[valcnt];
|
|
}
|
|
for (int n = 0; n < valcnt; n++)
|
|
{
|
|
for (int i = 0; i < ItemCount; i++)
|
|
{
|
|
Items[i].Values[n] = r1.ReadSingle();
|
|
}
|
|
}
|
|
|
|
|
|
switch (ItemCount)
|
|
{
|
|
case 0:
|
|
case 4:
|
|
case 8:
|
|
case 12:
|
|
case 20:
|
|
case 24:
|
|
case 48:
|
|
case 52:
|
|
case 76:
|
|
case 32:
|
|
case 16:
|
|
case 40:
|
|
case 44:
|
|
case 60:
|
|
case 72:
|
|
case 56:
|
|
case 28:
|
|
case 68:
|
|
break;
|
|
default:
|
|
break;//no hit
|
|
}
|
|
switch (ItemType)
|
|
{
|
|
case 1: break;
|
|
case 2: break;
|
|
case 3: break;
|
|
case 4: break;
|
|
default:
|
|
break;//no hit
|
|
}
|
|
if (Unk1 != 0)
|
|
{ }//no hit
|
|
}
|
|
public override string ToString()
|
|
{
|
|
var str = TypeStr + ", 1: - " + Length.ToString() + ", " + ItemCount.ToString() + ", " + ItemType.ToString();
|
|
if (Items != null)
|
|
{
|
|
str += " - " + Items.Length.ToString() + " items";
|
|
}
|
|
return str;
|
|
}
|
|
}
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class ExpressionUnk1_S2 : ExpressionUnk1_Base
|
|
{
|
|
public ushort Unk00 { get; set; }
|
|
public ushort Unk02 { get; set; }
|
|
public byte Unk04 { get; set; }
|
|
public byte Unk05 { get; set; }
|
|
public byte Unk06 { get; set; }
|
|
public byte Unk07 { get; set; }
|
|
|
|
public override void Read(DataReader r1, DataReader r2, DataReader r3)
|
|
{
|
|
Unk00 = r2.ReadUInt16();
|
|
Unk02 = r2.ReadUInt16();
|
|
Unk04 = r2.ReadByte();
|
|
Unk05 = r2.ReadByte();
|
|
Unk06 = r2.ReadByte();
|
|
Unk07 = r2.ReadByte();
|
|
}
|
|
public override string ToString()
|
|
{
|
|
return TypeStr + ", 2: - " + Unk00.ToString() + ", " + Unk02.ToString() + ", " + Unk04.ToString() + ", " + Unk05.ToString() + ", " + Unk06.ToString() + ", " + Unk07.ToString();
|
|
}
|
|
}
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class ExpressionUnk1_2B2C2D : ExpressionUnk1_Base
|
|
{
|
|
public uint UnkUint1 { get; set; }
|
|
public uint UnkUint2 { get; set; }
|
|
public uint UnkUint3 { get; set; }
|
|
|
|
public override void Read(DataReader r1, DataReader r2, DataReader r3)
|
|
{
|
|
UnkUint1 = r2.ReadUInt32();
|
|
UnkUint2 = r2.ReadUInt32();
|
|
UnkUint3 = r2.ReadUInt32();
|
|
|
|
switch (UnkUint1)//flags?
|
|
{
|
|
case 0:
|
|
case 128:
|
|
case 464:
|
|
case 352:
|
|
case 240:
|
|
case 16:
|
|
break;
|
|
default:
|
|
break;//no hit
|
|
}
|
|
switch (UnkUint2)//some index?
|
|
{
|
|
case 24:
|
|
case 12:
|
|
case 0:
|
|
case 8:
|
|
case 60:
|
|
case 48:
|
|
case 20:
|
|
case 44:
|
|
case 16:
|
|
case 52:
|
|
case 28:
|
|
case 4:
|
|
case 88:
|
|
case 64:
|
|
case 128:
|
|
case 104:
|
|
case 68:
|
|
case 80:
|
|
case 92:
|
|
case 84:
|
|
case 56:
|
|
case 108:
|
|
case 116:
|
|
case 72:
|
|
case 32:
|
|
case 40:
|
|
case 512:
|
|
case 36:
|
|
case 100:
|
|
case 140:
|
|
break;
|
|
default:
|
|
break;//no hit
|
|
}
|
|
switch (UnkUint3)//some index?
|
|
{
|
|
case 5:
|
|
case 4:
|
|
case 2:
|
|
case 3:
|
|
case 6:
|
|
case 17:
|
|
case 16:
|
|
case 15:
|
|
case 14:
|
|
case 12:
|
|
case 7:
|
|
case 19:
|
|
case 34:
|
|
case 26:
|
|
case 22:
|
|
case 18:
|
|
case 11:
|
|
case 20:
|
|
case 8:
|
|
case 30:
|
|
case 9:
|
|
case 10:
|
|
case 24:
|
|
case 77:
|
|
case 38:
|
|
break;
|
|
default:
|
|
break;//no hit
|
|
}
|
|
|
|
}
|
|
public override string ToString()
|
|
{
|
|
return TypeStr + ", 2: - " + UnkUint1.ToString() + ", " + UnkUint2.ToString() + ", " + UnkUint3.ToString();
|
|
}
|
|
}
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class ExpressionUnk1_0B : ExpressionUnk1_Base
|
|
{
|
|
public Vector4 UnkVec1 { get; set; }
|
|
|
|
public override void Read(DataReader r1, DataReader r2, DataReader r3)
|
|
{
|
|
UnkVec1 = r1.ReadVector4();
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
var str = TypeStr + ", 1: - " + UnkVec1.ToString();
|
|
return str;
|
|
}
|
|
}
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class ExpressionUnk1_05 : ExpressionUnk1_Base
|
|
{
|
|
public float UnkFloat { get; set; }
|
|
|
|
public override void Read(DataReader r1, DataReader r2, DataReader r3)
|
|
{
|
|
UnkFloat = r2.ReadSingle();
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return TypeStr + ", 2: - " + UnkFloat.ToString();
|
|
}
|
|
}
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class ExpressionUnk1_3E : ExpressionUnk1_Base
|
|
{
|
|
public Vector4 UnkVec1 { get; set; }
|
|
public uint UnkUint1 { get; set; } // 0, 1, 2
|
|
public uint UnkUint2 { get; set; } // 0, 2
|
|
public uint UnkUint3 { get; set; } // 0, 2
|
|
public uint UnkUint4 { get; set; } // 0x00000000
|
|
|
|
public override void Read(DataReader r1, DataReader r2, DataReader r3)
|
|
{
|
|
UnkVec1 = r1.ReadVector4();
|
|
UnkUint1 = r1.ReadUInt32();
|
|
UnkUint2 = r1.ReadUInt32();
|
|
UnkUint3 = r1.ReadUInt32();
|
|
UnkUint4 = r1.ReadUInt32();
|
|
|
|
switch (UnkUint1)
|
|
{
|
|
case 0:
|
|
case 2:
|
|
case 1:
|
|
break;
|
|
default:
|
|
break;//no hit
|
|
}
|
|
switch (UnkUint2)
|
|
{
|
|
case 2:
|
|
case 0:
|
|
break;
|
|
default:
|
|
break;//no hit
|
|
}
|
|
switch (UnkUint3)
|
|
{
|
|
case 2:
|
|
case 0:
|
|
break;
|
|
default:
|
|
break;//no hit
|
|
}
|
|
switch (UnkUint4)
|
|
{
|
|
case 0:
|
|
break;
|
|
default:
|
|
break;//no hit
|
|
}
|
|
}
|
|
public override string ToString()
|
|
{
|
|
return TypeStr + ", 1: - " + UnkVec1.ToString() + " - " + UnkUint1.ToString() + ", " + UnkUint2.ToString() + ", " + UnkUint3.ToString() + ", " + UnkUint4.ToString();
|
|
}
|
|
}
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class ExpressionUnk1_0E : ExpressionUnk1_Base
|
|
{
|
|
public Vector3 UnkVec1 { get; set; }
|
|
public MetaHash UnkUint1 { get; set; }
|
|
public Vector3 UnkVec2 { get; set; }
|
|
public MetaHash UnkUint2 { get; set; }
|
|
public Vector3 UnkVec3 { get; set; }
|
|
public MetaHash UnkUint3 { get; set; }
|
|
public Vector3 UnkVec4 { get; set; }
|
|
public MetaHash UnkUint4 { get; set; }
|
|
public Vector3 UnkVec5 { get; set; }
|
|
public MetaHash UnkUint5 { get; set; }
|
|
public Vector3 UnkVec6 { get; set; }
|
|
public MetaHash UnkUint6 { get; set; }
|
|
public Vector3 UnkVec7 { get; set; }
|
|
public MetaHash UnkUint7 { get; set; }
|
|
public Vector3 UnkVec8 { get; set; }
|
|
public MetaHash UnkUint8 { get; set; }
|
|
public Vector3 UnkVec9 { get; set; }
|
|
public MetaHash UnkUint9 { get; set; }
|
|
public Vector3 UnkVec10 { get; set; }
|
|
public MetaHash UnkUint10 { get; set; }
|
|
public MetaHash UnkUint11 { get; set; }
|
|
public MetaHash UnkUint12 { get; set; }
|
|
public MetaHash UnkUint13 { get; set; }
|
|
public MetaHash UnkUint14 { get; set; }
|
|
|
|
public override void Read(DataReader r1, DataReader r2, DataReader r3)
|
|
{
|
|
UnkVec1 = r1.ReadVector3();
|
|
UnkUint1 = r1.ReadUInt32();//2x short
|
|
UnkVec2 = r1.ReadVector3();
|
|
UnkUint2 = r1.ReadUInt32();//2x short
|
|
UnkVec3 = r1.ReadVector3();
|
|
UnkUint3 = r1.ReadUInt32();//2x short
|
|
UnkVec4 = r1.ReadVector3();
|
|
UnkUint4 = r1.ReadUInt32();//1x short, 2 bytes (first 0)
|
|
UnkVec5 = r1.ReadVector3();//0
|
|
UnkUint5 = r1.ReadUInt32();//1x short, 2 bytes (first 0)
|
|
UnkVec6 = r1.ReadVector3();//0
|
|
UnkUint6 = r1.ReadUInt32();//0
|
|
UnkVec7 = r1.ReadVector3();//0
|
|
UnkUint7 = r1.ReadUInt32();//1x short, 2 bytes (first 0)
|
|
UnkVec8 = r1.ReadVector3();//0
|
|
UnkUint8 = r1.ReadUInt32();//1x short (0), 2 bytes
|
|
UnkVec9 = r1.ReadVector3();//down vector (0,0,-1)
|
|
UnkUint9 = r1.ReadUInt32();//1x short, 2 bytes (first 0)
|
|
UnkVec10 = r1.ReadVector3();//gravity vector? (0, 0, -9.8)
|
|
UnkUint10 = r1.ReadUInt32();//2x short (2nd 0)
|
|
UnkUint11 = r1.ReadUInt32();
|
|
UnkUint12 = r1.ReadUInt32();
|
|
UnkUint13 = r1.ReadUInt32();
|
|
UnkUint14 = r1.ReadUInt32();
|
|
}
|
|
public override string ToString()
|
|
{
|
|
return TypeStr + ", 1: - " + UnkVec1.ToString() + ", " + UnkVec2.ToString() + ", " + UnkVec3.ToString() + ", " + UnkVec4.ToString() + " ...";
|
|
}
|
|
}
|
|
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class ExpressionUnk2 : ResourceSystemBlock
|
|
{
|
|
public override long BlockLength => 0xA0;
|
|
|
|
// structure data
|
|
public float Unknown_00h { get; set; }
|
|
public float Unknown_04h { get; set; }
|
|
public float Unknown_08h { get; set; }
|
|
public MetaHash Unknown_0Ch { get; set; }
|
|
public float Unknown_10h { get; set; }
|
|
public float Unknown_14h { get; set; }
|
|
public float Unknown_18h { get; set; }
|
|
public MetaHash Unknown_1Ch { get; set; }
|
|
public float Unknown_20h { get; set; }
|
|
public float Unknown_24h { get; set; }
|
|
public float Unknown_28h { get; set; }
|
|
public MetaHash Unknown_2Ch { get; set; }
|
|
public float Unknown_30h { get; set; }
|
|
public float Unknown_34h { get; set; }
|
|
public float Unknown_38h { get; set; }
|
|
public MetaHash Unknown_3Ch { get; set; }
|
|
public float Unknown_40h { get; set; }
|
|
public float Unknown_44h { get; set; }
|
|
public float Unknown_48h { get; set; }
|
|
public MetaHash Unknown_4Ch { get; set; }
|
|
public float Unknown_50h { get; set; }
|
|
public float Unknown_54h { get; set; }
|
|
public float Unknown_58h { get; set; }
|
|
public MetaHash Unknown_5Ch { get; set; }
|
|
public float Unknown_60h { get; set; }
|
|
public float Unknown_64h { get; set; }
|
|
public float Unknown_68h { get; set; }
|
|
public MetaHash Unknown_6Ch { get; set; }
|
|
public float Unknown_70h { get; set; }
|
|
public float Unknown_74h { get; set; }
|
|
public float Unknown_78h { get; set; }
|
|
public MetaHash Unknown_7Ch { get; set; }
|
|
public float Unknown_80h { get; set; }
|
|
public float Unknown_84h { get; set; }
|
|
public float Unknown_88h { get; set; }
|
|
public MetaHash Unknown_8Ch { get; set; }
|
|
public float Unknown_90h { get; set; }
|
|
public float Unknown_94h { get; set; }
|
|
public float Unknown_98h { get; set; }
|
|
public MetaHash Unknown_9Ch { get; set; }
|
|
|
|
public override void Read(ResourceDataReader reader, params object[] parameters)
|
|
{
|
|
// read structure data
|
|
this.Unknown_00h = reader.ReadSingle();
|
|
this.Unknown_04h = reader.ReadSingle();
|
|
this.Unknown_08h = reader.ReadSingle();
|
|
this.Unknown_0Ch = reader.ReadUInt32();
|
|
this.Unknown_10h = reader.ReadSingle();
|
|
this.Unknown_14h = reader.ReadSingle();
|
|
this.Unknown_18h = reader.ReadSingle();
|
|
this.Unknown_1Ch = reader.ReadUInt32();
|
|
this.Unknown_20h = reader.ReadSingle();
|
|
this.Unknown_24h = reader.ReadSingle();
|
|
this.Unknown_28h = reader.ReadSingle();
|
|
this.Unknown_2Ch = reader.ReadUInt32();
|
|
this.Unknown_30h = reader.ReadSingle();
|
|
this.Unknown_34h = reader.ReadSingle();
|
|
this.Unknown_38h = reader.ReadSingle();
|
|
this.Unknown_3Ch = reader.ReadUInt32();
|
|
this.Unknown_40h = reader.ReadSingle();
|
|
this.Unknown_44h = reader.ReadSingle();
|
|
this.Unknown_48h = reader.ReadSingle();
|
|
this.Unknown_4Ch = reader.ReadUInt32();
|
|
this.Unknown_50h = reader.ReadSingle();
|
|
this.Unknown_54h = reader.ReadSingle();
|
|
this.Unknown_58h = reader.ReadSingle();
|
|
this.Unknown_5Ch = reader.ReadUInt32();
|
|
this.Unknown_60h = reader.ReadSingle();
|
|
this.Unknown_64h = reader.ReadSingle();
|
|
this.Unknown_68h = reader.ReadSingle();
|
|
this.Unknown_6Ch = reader.ReadUInt32();
|
|
this.Unknown_70h = reader.ReadSingle();
|
|
this.Unknown_74h = reader.ReadSingle();
|
|
this.Unknown_78h = reader.ReadSingle();
|
|
this.Unknown_7Ch = reader.ReadUInt32();
|
|
this.Unknown_80h = reader.ReadSingle();
|
|
this.Unknown_84h = reader.ReadSingle();
|
|
this.Unknown_88h = reader.ReadSingle();
|
|
this.Unknown_8Ch = reader.ReadUInt32();
|
|
this.Unknown_90h = reader.ReadSingle();
|
|
this.Unknown_94h = reader.ReadSingle();
|
|
this.Unknown_98h = reader.ReadSingle();
|
|
this.Unknown_9Ch = reader.ReadUInt32();
|
|
}
|
|
public override void Write(ResourceDataWriter writer, params object[] parameters)
|
|
{
|
|
// write structure data
|
|
writer.Write(this.Unknown_00h);
|
|
writer.Write(this.Unknown_04h);
|
|
writer.Write(this.Unknown_08h);
|
|
writer.Write(this.Unknown_0Ch);
|
|
writer.Write(this.Unknown_10h);
|
|
writer.Write(this.Unknown_14h);
|
|
writer.Write(this.Unknown_18h);
|
|
writer.Write(this.Unknown_1Ch);
|
|
writer.Write(this.Unknown_20h);
|
|
writer.Write(this.Unknown_24h);
|
|
writer.Write(this.Unknown_28h);
|
|
writer.Write(this.Unknown_2Ch);
|
|
writer.Write(this.Unknown_30h);
|
|
writer.Write(this.Unknown_34h);
|
|
writer.Write(this.Unknown_38h);
|
|
writer.Write(this.Unknown_3Ch);
|
|
writer.Write(this.Unknown_40h);
|
|
writer.Write(this.Unknown_44h);
|
|
writer.Write(this.Unknown_48h);
|
|
writer.Write(this.Unknown_4Ch);
|
|
writer.Write(this.Unknown_50h);
|
|
writer.Write(this.Unknown_54h);
|
|
writer.Write(this.Unknown_58h);
|
|
writer.Write(this.Unknown_5Ch);
|
|
writer.Write(this.Unknown_60h);
|
|
writer.Write(this.Unknown_64h);
|
|
writer.Write(this.Unknown_68h);
|
|
writer.Write(this.Unknown_6Ch);
|
|
writer.Write(this.Unknown_70h);
|
|
writer.Write(this.Unknown_74h);
|
|
writer.Write(this.Unknown_78h);
|
|
writer.Write(this.Unknown_7Ch);
|
|
writer.Write(this.Unknown_80h);
|
|
writer.Write(this.Unknown_84h);
|
|
writer.Write(this.Unknown_88h);
|
|
writer.Write(this.Unknown_8Ch);
|
|
writer.Write(this.Unknown_90h);
|
|
writer.Write(this.Unknown_94h);
|
|
writer.Write(this.Unknown_98h);
|
|
writer.Write(this.Unknown_9Ch);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
[TypeConverter(typeof(ExpandableObjectConverter))] public struct ExpressionBoneTrack
|
|
{
|
|
public ushort BoneTag { get; set; }
|
|
public byte Track { get; set; }
|
|
public byte Flags { get; set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return BoneTag.ToString() + ", " + Track.ToString() + ", " + Flags.ToString();
|
|
}
|
|
}
|
|
|
|
|
|
}
|