CodeWalker/GameFiles/MetaTypes/Meta.cs
2017-09-21 20:33:05 +10:00

641 lines
23 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class Meta : ResourceFileBase
{
public override long BlockLength
{
get { return 112; }
}
// structure data
public int Unknown_10h { get; set; } = 0x50524430;
public short Unknown_14h { get; set; } = 0x0079;
public byte HasUselessData { get; set; }
public byte Unknown_17h { get; set; } = 0x00;
public int Unknown_18h { get; set; } = 0x00000000;
public int RootBlockIndex { get; set; }
public long StructureInfosPointer { get; set; }
public long EnumInfosPointer { get; set; }
public long DataBlocksPointer { get; set; }
public long NamePointer { get; set; }
public long UselessPointer { get; set; }
public short StructureInfosCount { get; set; }
public short EnumInfosCount { get; set; }
public short DataBlocksCount { get; set; }
public short Unknown_4Eh { get; set; } = 0x0000;
public uint Unknown_50h { get; set; } = 0x00000000;
public uint Unknown_54h { get; set; } = 0x00000000;
public uint Unknown_58h { get; set; } = 0x00000000;
public uint Unknown_5Ch { get; set; } = 0x00000000;
public uint Unknown_60h { get; set; } = 0x00000000;
public uint Unknown_64h { get; set; } = 0x00000000;
public uint Unknown_68h { get; set; } = 0x00000000;
public uint Unknown_6Ch { get; set; } = 0x00000000;
// reference data
public ResourceSimpleArray<MetaStructureInfo> StructureInfos { get; set; }
public ResourceSimpleArray<MetaEnumInfo> EnumInfos { get; set; }
public ResourceSimpleArray<MetaDataBlock> DataBlocks { get; set; }
public string Name { get; private set; }
//public string[] Strings { get; set; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
// read structure data
this.Unknown_10h = reader.ReadInt32();
this.Unknown_14h = reader.ReadInt16();
this.HasUselessData = reader.ReadByte();
this.Unknown_17h = reader.ReadByte();
this.Unknown_18h = reader.ReadInt32();
this.RootBlockIndex = reader.ReadInt32();
this.StructureInfosPointer = reader.ReadInt64();
this.EnumInfosPointer = reader.ReadInt64();
this.DataBlocksPointer = reader.ReadInt64();
this.NamePointer = reader.ReadInt64();
this.UselessPointer = reader.ReadInt64();
this.StructureInfosCount = reader.ReadInt16();
this.EnumInfosCount = reader.ReadInt16();
this.DataBlocksCount = reader.ReadInt16();
this.Unknown_4Eh = reader.ReadInt16();
this.Unknown_50h = reader.ReadUInt32();
this.Unknown_54h = reader.ReadUInt32();
this.Unknown_58h = reader.ReadUInt32();
this.Unknown_5Ch = reader.ReadUInt32();
this.Unknown_60h = reader.ReadUInt32();
this.Unknown_64h = reader.ReadUInt32();
this.Unknown_68h = reader.ReadUInt32();
this.Unknown_6Ch = reader.ReadUInt32();
// read reference data
this.StructureInfos = reader.ReadBlockAt<ResourceSimpleArray<MetaStructureInfo>>(
(ulong)this.StructureInfosPointer, // offset
this.StructureInfosCount
);
this.EnumInfos = reader.ReadBlockAt<ResourceSimpleArray<MetaEnumInfo>>(
(ulong)this.EnumInfosPointer, // offset
this.EnumInfosCount
);
this.DataBlocks = reader.ReadBlockAt<ResourceSimpleArray<MetaDataBlock>>(
(ulong)this.DataBlocksPointer, // offset
this.DataBlocksCount
);
this.Name = reader.ReadStringAt(//BlockAt<string_r>(
(ulong)this.NamePointer // offset
);
//Strings = MetaTypes.GetStrings(this);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
// update structure data
this.StructureInfosPointer = this.StructureInfos?.FilePosition ?? 0;
this.EnumInfosPointer = this.EnumInfos?.FilePosition ?? 0;
this.DataBlocksPointer = this.DataBlocks?.FilePosition ?? 0;
//this.NamePointer = this.Name?.Position ?? 0; //TODO: fix
this.UselessPointer = 0;
this.StructureInfosCount = (short)(this.StructureInfos?.Count ?? 0);
this.EnumInfosCount = (short)(this.EnumInfos?.Count ?? 0);
this.DataBlocksCount = (short)(this.DataBlocks?.Count ?? 0);
// write structure data
writer.Write(this.Unknown_10h);
writer.Write(this.Unknown_14h);
writer.Write(this.HasUselessData);
writer.Write(this.Unknown_17h);
writer.Write(this.Unknown_18h);
writer.Write(this.RootBlockIndex);
writer.Write(this.StructureInfosPointer);
writer.Write(this.EnumInfosPointer);
writer.Write(this.DataBlocksPointer);
writer.Write(this.NamePointer);
writer.Write(this.UselessPointer);
writer.Write(this.StructureInfosCount);
writer.Write(this.EnumInfosCount);
writer.Write(this.DataBlocksCount);
writer.Write(this.Unknown_4Eh);
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);
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>(base.GetReferences());
if ((StructureInfos != null) && (StructureInfos.Count > 0)) list.Add(StructureInfos);
if ((EnumInfos != null) && (EnumInfos.Count > 0)) list.Add(EnumInfos);
if ((DataBlocks != null) && (DataBlocks.Count > 0)) list.Add(DataBlocks);
//if (Name != null) list.Add(Name); //TODO: fix
return list.ToArray();
}
public MetaDataBlock FindBlock(MetaName name)
{
if (DataBlocks == null) return null;
foreach (var block in DataBlocks)
{
if (block.StructureNameHash == name)
{
return block;
}
}
return null;
}
public MetaDataBlock GetRootBlock()
{
MetaDataBlock block = null;
var rootind = RootBlockIndex - 1;
if ((rootind >= 0) && (rootind < DataBlocks.Count) && (DataBlocks.Data != null))
{
block = DataBlocks[rootind];
}
return block;
}
public MetaDataBlock GetBlock(int id)
{
MetaDataBlock block = null;
var ind = id - 1;
if ((ind >= 0) && (ind < DataBlocks.Count) && (DataBlocks.Data != null))
{
block = DataBlocks[ind];
}
return block;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class MetaStructureInfo : ResourceSystemBlock
{
public override long BlockLength
{
get { return 32; }
}
// structure data
public MetaName StructureNameHash { get; set; }
public uint StructureKey { get; set; }
public uint Unknown_8h { get; set; }
public uint Unknown_Ch { get; set; } = 0x00000000;
public long EntriesPointer { get; private set; }
public int StructureSize { get; set; }
public short Unknown_1Ch { get; set; } = 0x0000;
public short EntriesCount { get; private set; }
// reference data
public MetaStructureEntryInfo_s[] Entries { get; private set; }
private ResourceSystemStructBlock<MetaStructureEntryInfo_s> EntriesBlock = null;
public MetaStructureInfo()
{ }
public MetaStructureInfo(MetaName nameHash, uint key, uint unknown, int length, params MetaStructureEntryInfo_s[] entries)
{
StructureNameHash = nameHash;
StructureKey = key;
Unknown_8h = unknown;
StructureSize = length;
Entries = entries;
}
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.StructureNameHash = (MetaName)reader.ReadInt32();
this.StructureKey = reader.ReadUInt32();
this.Unknown_8h = reader.ReadUInt32();
this.Unknown_Ch = reader.ReadUInt32();
this.EntriesPointer = reader.ReadInt64();
this.StructureSize = reader.ReadInt32();
this.Unknown_1Ch = reader.ReadInt16();
this.EntriesCount = reader.ReadInt16();
// read reference data
this.Entries = reader.ReadStructsAt<MetaStructureEntryInfo_s>((ulong)this.EntriesPointer, (uint)this.EntriesCount);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// update structure data
//this.EntriesPointer = this.Entries?.Position ?? 0; //TODO: fix
//this.EntriesCount = (short)(this.Entries?.Count ?? 0);
this.EntriesPointer = this.EntriesBlock?.FilePosition ?? 0; //TODO: fix
this.EntriesCount = (short)(this.EntriesBlock?.ItemCount ?? 0);
// write structure data
writer.Write((int)this.StructureNameHash);
writer.Write(this.StructureKey);
writer.Write(this.Unknown_8h);
writer.Write(this.Unknown_Ch);
writer.Write(this.EntriesPointer);
writer.Write(this.StructureSize);
writer.Write(this.Unknown_1Ch);
writer.Write(this.EntriesCount);
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if (EntriesBlock == null)
{
EntriesBlock = new ResourceSystemStructBlock<MetaStructureEntryInfo_s>(Entries);
}
if (EntriesBlock != null) list.Add(EntriesBlock);
//if (Entries != null) list.Add(Entries); //TODO: fix
return list.ToArray();
}
public override string ToString()
{
return StructureNameHash.ToString();
}
}
public enum MetaStructureEntryDataType : byte
{
Boolean = 0x01,
SignedByte = 0x10,
UnsignedByte = 0x11, // OCCURS IN ARRAY
SignedShort = 0x12,
UnsignedShort = 0x13, // OCCURS IN ARRAY
SignedInt = 0x14,
UnsignedInt = 0x15, // OCCURS IN ARRAY
Float = 0x21, // OCCURS IN ARRAY
Float_XYZ = 0x33, // OCCURS IN ARRAY
Float_XYZW = 0x34,
ByteEnum = 0x60, // has enum name hash in info
IntEnum = 0x62, // has enum name hash in info
ShortFlags = 0x64, // has enum name hash in info
IntFlags1 = 0x63, // has enum name hash in info
IntFlags2 = 0x65, // has enum name hash in info (optional?)
Hash = 0x4A, // OCCURS IN ARRAY
Array = 0x52,
ArrayOfChars = 0x40, // has length in info
ArrayOfBytes = 0x50, // has length in info
DataBlockPointer = 0x59,
CharPointer = 0x44,
StructurePointer = 0x07, // OCCURS IN ARRAY
Structure = 0x05 // has structure name hash in info, OCCURS IN ARRAY
}
public static class MetaStructureEntryDataTypes
{
public static string GetCSharpTypeName(MetaStructureEntryDataType t)
{
switch (t)
{
case MetaStructureEntryDataType.Boolean: return "bool";
case MetaStructureEntryDataType.SignedByte: return "sbyte";
case MetaStructureEntryDataType.UnsignedByte: return "byte";
case MetaStructureEntryDataType.SignedShort: return "short";
case MetaStructureEntryDataType.UnsignedShort: return "ushort";
case MetaStructureEntryDataType.SignedInt: return "int";
case MetaStructureEntryDataType.UnsignedInt: return "uint";
case MetaStructureEntryDataType.Float: return "float";
case MetaStructureEntryDataType.Float_XYZ: return "Vector3";
case MetaStructureEntryDataType.Float_XYZW: return "Vector4";
case MetaStructureEntryDataType.Hash: return "uint"; //uint hashes...
case MetaStructureEntryDataType.ByteEnum: return "byte"; //convert to enum later..
case MetaStructureEntryDataType.IntEnum: return "int";
case MetaStructureEntryDataType.ShortFlags: return "short";
case MetaStructureEntryDataType.IntFlags1: return "int";
case MetaStructureEntryDataType.IntFlags2: return "int";
case MetaStructureEntryDataType.Array:
case MetaStructureEntryDataType.ArrayOfChars:
case MetaStructureEntryDataType.ArrayOfBytes:
case MetaStructureEntryDataType.DataBlockPointer:
case MetaStructureEntryDataType.CharPointer:
case MetaStructureEntryDataType.StructurePointer:
case MetaStructureEntryDataType.Structure:
default:
return t.ToString();
}
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct MetaStructureEntryInfo_s
{
// structure data
public MetaName EntryNameHash { get; set; }
public int DataOffset { get; set; }
public MetaStructureEntryDataType DataType { get; set; }
public byte Unknown_9h { get; set; }
public short ReferenceTypeIndex { get; set; }
public MetaName ReferenceKey { get; set; }
public MetaStructureEntryInfo_s(MetaName nameHash, int dataOffset, MetaStructureEntryDataType dataType, byte unk9h, short referenceTypeIndex, MetaName referenceKey)
{
EntryNameHash = nameHash;
DataOffset = dataOffset;
DataType = dataType;
Unknown_9h = unk9h;
ReferenceTypeIndex = referenceTypeIndex;
ReferenceKey = referenceKey;
}
public override string ToString()
{
return DataOffset.ToString() + ": " + DataType.ToString() + ": " + ReferenceKey.ToString() + ": " + EntryNameHash.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class MetaEnumInfo : ResourceSystemBlock
{
public override long BlockLength
{
get { return 24; }
}
// structure data
public MetaName EnumNameHash { get; set; }
public uint EnumKey { get; set; }
public long EntriesPointer { get; private set; }
public int EntriesCount { get; private set; }
public int Unknown_14h { get; set; } = 0x00000000;
// reference data
//public ResourceSimpleArray<MetaEnumEntryInfo> Entries;
public MetaEnumEntryInfo_s[] Entries { get; private set; }
private ResourceSystemStructBlock<MetaEnumEntryInfo_s> EntriesBlock = null;
public MetaEnumInfo()
{ }
public MetaEnumInfo(MetaName nameHash, uint key, params MetaEnumEntryInfo_s[] entries)
{
EnumNameHash = nameHash;
EnumKey = key;
Entries = entries;
}
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.EnumNameHash = (MetaName)reader.ReadInt32();
this.EnumKey = reader.ReadUInt32();
this.EntriesPointer = reader.ReadInt64();
this.EntriesCount = reader.ReadInt32();
this.Unknown_14h = reader.ReadInt32();
// read reference data
//this.Entries = reader.ReadBlockAt<ResourceSimpleArray<MetaEnumEntryInfo>>(
// (ulong)this.EntriesPointer, // offset
// this.EntriesCount
//);
this.Entries = reader.ReadStructsAt<MetaEnumEntryInfo_s>((ulong)this.EntriesPointer, (uint)this.EntriesCount);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// update structure data
//this.EntriesPointer = this.Entries?.Position ?? 0; //TODO: fix
//this.EntriesCount = this.Entries?.Count ?? 0;
this.EntriesPointer = this.EntriesBlock?.FilePosition ?? 0; //TODO: fix
this.EntriesCount = (short)(this.EntriesBlock?.ItemCount ?? 0);
// write structure data
writer.Write((int)this.EnumNameHash);
writer.Write(this.EnumKey);
writer.Write(this.EntriesPointer);
writer.Write(this.EntriesCount);
writer.Write(this.Unknown_14h);
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
//if (Entries != null) list.Add(Entries);
if (EntriesBlock == null)
{
EntriesBlock = new ResourceSystemStructBlock<MetaEnumEntryInfo_s>(Entries);
}
if (EntriesBlock != null) list.Add(EntriesBlock);
return list.ToArray();
}
public override string ToString()
{
return EnumNameHash.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct MetaEnumEntryInfo_s
{
// structure data
public MetaName EntryNameHash { get; set; }
public int EntryValue { get; set; }
public MetaEnumEntryInfo_s(MetaName nameHash, int value)
{
EntryNameHash = nameHash;
EntryValue = value;
}
public override string ToString()
{
return EntryNameHash.ToString() + ": " + EntryValue.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class MetaDataBlock : ResourceSystemBlock
{
public override long BlockLength
{
get { return 16; }
}
// structure data
public MetaName StructureNameHash { get; set; }
public int DataLength { get; set; }
public long DataPointer { get; private set; }
// reference data
public byte[] Data { get; set; }
private ResourceSystemDataBlock DataBlock = null;
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.StructureNameHash = (MetaName)reader.ReadInt32();
this.DataLength = reader.ReadInt32();
this.DataPointer = reader.ReadInt64();
this.Data = reader.ReadBytesAt((ulong)this.DataPointer, (uint)DataLength);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// update structure data
this.DataLength = this.Data?.Length ?? 0;
//this.DataPointer = (this.Data!=null)? DataPos : 0; //TODO:fix...
this.DataPointer = this.DataBlock?.FilePosition ?? 0;
// write structure data
writer.Write((int)this.StructureNameHash);
writer.Write(this.DataLength);
writer.Write(this.DataPointer);
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if (DataBlock == null)
{
DataBlock = new ResourceSystemDataBlock(Data);
}
if (DataBlock != null) list.Add(DataBlock);
//if (Data != null) list.Add(Data);
return list.ToArray();
}
public override string ToString()
{
return StructureNameHash.ToString() + ": " + DataPointer.ToString() + " (" + DataLength.ToString() + ")";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct MetaHash
{
public uint Hash { get; set; }
public string Hex
{
get
{
return Hash.ToString("X").PadLeft(8, '0');
}
}
public MetaHash(uint h) { Hash = h; }
public override string ToString()
{
var str = JenkIndex.TryGetString(Hash);
if (!string.IsNullOrEmpty(str)) return str;
return GlobalText.GetString(Hash);
}
public static implicit operator uint(MetaHash h)
{
return h.Hash; //implicit conversion
}
public static implicit operator MetaHash(uint v)
{
return new MetaHash(v);
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct TextHash
{
public uint Hash { get; set; }
public string Hex
{
get
{
return Hash.ToString("X");
}
}
public TextHash(uint h) { Hash = h; }
public override string ToString()
{
return GlobalText.GetString(Hash);
}
public static implicit operator uint(TextHash h)
{
return h.Hash; //implicit conversion
}
public static implicit operator TextHash(uint v)
{
return new TextHash(v);
}
}
}