mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2026-05-15 04:54:48 +08:00
R26_dev8 - First public commit
This commit is contained in:
@@ -0,0 +1,641 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
public class MetaBuilder
|
||||
{
|
||||
|
||||
List<MetaBuilderBlock> Blocks = new List<MetaBuilderBlock>();
|
||||
|
||||
int MaxBlockLength = 0x2000; //TODO: figure what this should be!
|
||||
|
||||
|
||||
public MetaBuilderBlock EnsureBlock(MetaName type)
|
||||
{
|
||||
foreach (var block in Blocks)
|
||||
{
|
||||
if (block.StructureNameHash == type)
|
||||
{
|
||||
if (block.TotalSize < MaxBlockLength)
|
||||
{
|
||||
return block;
|
||||
}
|
||||
}
|
||||
}
|
||||
MetaBuilderBlock b = new MetaBuilderBlock();
|
||||
b.StructureNameHash = type;
|
||||
b.Index = Blocks.Count;
|
||||
Blocks.Add(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
public MetaBuilderPointer AddItem<T>(MetaName type, T item) where T : struct
|
||||
{
|
||||
MetaBuilderBlock block = EnsureBlock(type);
|
||||
byte[] data = MetaTypes.ConvertToBytes(item);
|
||||
int brem = data.Length % 16;
|
||||
if (brem > 0)
|
||||
{
|
||||
int newlen = data.Length - brem + 16;
|
||||
byte[] newdata = new byte[newlen];
|
||||
Buffer.BlockCopy(data, 0, newdata, 0, data.Length);
|
||||
data = newdata; //make sure item size is multiple of 16... so pointers don't need sub offsets!
|
||||
}
|
||||
int idx = block.AddItem(data);
|
||||
MetaBuilderPointer r = new MetaBuilderPointer();
|
||||
r.Block = block.Index + 1;
|
||||
r.Offset = (idx * data.Length) / 16;
|
||||
r.Length = data.Length;
|
||||
return r;
|
||||
}
|
||||
public MetaBuilderPointer AddItemArray<T>(MetaName type, T[] items) where T : struct
|
||||
{
|
||||
MetaBuilderBlock block = EnsureBlock(type);
|
||||
byte[] data = MetaTypes.ConvertArrayToBytes(items);
|
||||
int datalen = data.Length;
|
||||
int newlen = datalen;
|
||||
int lenrem = newlen % 16;
|
||||
if (lenrem != 0)
|
||||
{
|
||||
newlen += (16 - lenrem);
|
||||
}
|
||||
byte[] newdata = new byte[newlen];
|
||||
Buffer.BlockCopy(data, 0, newdata, 0, datalen);
|
||||
int offs = block.TotalSize / 16;
|
||||
int idx = block.AddItem(newdata);
|
||||
MetaBuilderPointer r = new MetaBuilderPointer();
|
||||
r.Block = block.Index + 1;
|
||||
r.Offset = offs; //(idx * data.Length) / 16;
|
||||
r.Length = items.Length;
|
||||
return r;
|
||||
}
|
||||
public MetaBuilderPointer AddString(string str)
|
||||
{
|
||||
MetaBuilderBlock block = EnsureBlock(MetaName.STRING);
|
||||
byte[] data = Encoding.ASCII.GetBytes(str);
|
||||
int datalen = data.Length;
|
||||
int newlen = datalen;
|
||||
int lenrem = newlen % 16;
|
||||
if (lenrem != 0) //need to pad the data length up to multiple of 16.
|
||||
{
|
||||
newlen += (16 - lenrem);
|
||||
}
|
||||
byte[] newdata = new byte[newlen];
|
||||
Buffer.BlockCopy(data, 0, newdata, 0, datalen);
|
||||
int offs = block.TotalSize / 16;
|
||||
int idx = block.AddItem(newdata);
|
||||
MetaBuilderPointer r = new MetaBuilderPointer();
|
||||
r.Block = block.Index + 1;
|
||||
r.Offset = offs;// (idx * data.Length) / 16;//not sure if this is correct! should also use sub-offset!
|
||||
r.Length = datalen; //actual length of string.
|
||||
return r;
|
||||
}
|
||||
|
||||
public MetaPOINTER AddItemPtr<T>(MetaName type, T item) where T : struct //helper method for AddItem<T>
|
||||
{
|
||||
var ptr = AddItem(type, item);
|
||||
return new MetaPOINTER((ushort)ptr.Block, (ushort)ptr.Offset, 0);
|
||||
}
|
||||
public Array_Structure AddItemArrayPtr<T>(MetaName type, T[] items) where T : struct //helper method for AddItemArray<T>
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_Structure();
|
||||
var ptr = AddItemArray(type, items);
|
||||
return new Array_Structure(ptr);
|
||||
}
|
||||
public Array_uint AddHashArrayPtr(MetaHash[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_uint();
|
||||
var ptr = AddItemArray(MetaName.HASH, items);
|
||||
return new Array_uint(ptr);
|
||||
}
|
||||
public Array_ushort AddUshortArrayPtr(ushort[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_ushort();
|
||||
var ptr = AddItemArray(MetaName.USHORT, items);
|
||||
return new Array_ushort(ptr);
|
||||
}
|
||||
public CharPointer AddStringPtr(string str) //helper method for AddString
|
||||
{
|
||||
var ptr = AddString(str);
|
||||
return new CharPointer(ptr);
|
||||
}
|
||||
|
||||
|
||||
public Array_StructurePointer AddPointerArray(MetaPOINTER[] arr)
|
||||
{
|
||||
if ((arr == null) || (arr.Length == 0)) return new Array_StructurePointer();
|
||||
var ptr = AddItemArray(MetaName.POINTER, arr);
|
||||
Array_StructurePointer sp = new Array_StructurePointer();
|
||||
sp.Count1 = (ushort)arr.Length;
|
||||
sp.Count2 = sp.Count1;
|
||||
sp.Pointer = ptr.Pointer;
|
||||
return sp;
|
||||
}
|
||||
|
||||
public Array_StructurePointer AddItemPointerArrayPtr<T>(MetaName type, T[] items) where T : struct
|
||||
{
|
||||
//helper method for creating a pointer array
|
||||
if ((items == null) || (items.Length == 0)) return new Array_StructurePointer();
|
||||
|
||||
MetaPOINTER[] ptrs = new MetaPOINTER[items.Length];
|
||||
for (int i = 0; i < items.Length; i++)
|
||||
{
|
||||
ptrs[i] = AddItemPtr(type, items[i]);
|
||||
}
|
||||
return AddPointerArray(ptrs);
|
||||
|
||||
//Array_StructurePointer sp = new Array_StructurePointer();
|
||||
//sp.Count1 = (ushort)items.Length;
|
||||
//sp.Count2 = sp.Count1;
|
||||
//for (int i = 0; i < items.Length; i++)
|
||||
//{
|
||||
// var item = items[i];
|
||||
// var meptr = AddItemPtr(type, item);
|
||||
// var mptr = AddItem(MetaName.POINTER, meptr);
|
||||
// if (i == 0)
|
||||
// {
|
||||
// sp.Pointer = mptr.Pointer; //main pointer points to the first item.
|
||||
// }
|
||||
//}
|
||||
//return sp;
|
||||
}
|
||||
|
||||
|
||||
public Array_StructurePointer AddWrapperArrayPtr(MetaWrapper[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_StructurePointer();
|
||||
|
||||
|
||||
MetaPOINTER[] ptrs = new MetaPOINTER[items.Length];
|
||||
for (int i = 0; i < items.Length; i++)
|
||||
{
|
||||
ptrs[i] = items[i].Save(this);
|
||||
}
|
||||
return AddPointerArray(ptrs);
|
||||
|
||||
//Array_StructurePointer sp = new Array_StructurePointer();
|
||||
//sp.Count1 = (ushort)items.Length;
|
||||
//sp.Count2 = sp.Count1;
|
||||
//for (int i = 0; i < items.Length; i++)
|
||||
//{
|
||||
// var item = items[i];
|
||||
// var meptr = item.Save(this);
|
||||
// var mptr = AddItem(MetaName.POINTER, meptr);
|
||||
// if (i == 0)
|
||||
// {
|
||||
// sp.Pointer = mptr.Pointer; //main pointer points to the first item.
|
||||
// }
|
||||
//}
|
||||
//return sp;
|
||||
}
|
||||
|
||||
public Array_Structure AddWrapperArray(MetaWrapper[] items)
|
||||
{
|
||||
if ((items == null) || (items.Length == 0)) return new Array_Structure();
|
||||
|
||||
var sa = new Array_Structure();
|
||||
sa.Count1 = (ushort)items.Length;
|
||||
sa.Count2 = sa.Count1;
|
||||
for (int i = 0; i < items.Length; i++)
|
||||
{
|
||||
var item = items[i];
|
||||
var meptr = item.Save(this);
|
||||
if (i == 0)
|
||||
{
|
||||
MetaBuilderPointer mbp = new MetaBuilderPointer();
|
||||
mbp.Block = meptr.BlockID;
|
||||
mbp.Offset = meptr.ItemOffset;
|
||||
sa.Pointer = mbp.Pointer;
|
||||
}
|
||||
}
|
||||
return sa;
|
||||
}
|
||||
|
||||
|
||||
public byte[] GetData()
|
||||
{
|
||||
int totlen = 0;
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
totlen += Blocks[i].TotalSize;
|
||||
}
|
||||
byte[] data = new byte[totlen];
|
||||
int offset = 0;
|
||||
for (int i = 0; i < Blocks.Count; i++)
|
||||
{
|
||||
var block = Blocks[i];
|
||||
for (int j = 0; j < block.Items.Count; j++)
|
||||
{
|
||||
var bdata = block.Items[j];
|
||||
Buffer.BlockCopy(bdata, 0, data, offset, bdata.Length);
|
||||
offset += bdata.Length;
|
||||
}
|
||||
}
|
||||
if (offset != data.Length)
|
||||
{ }
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Dictionary<MetaName, MetaStructureInfo> StructureInfos = new Dictionary<MetaName, MetaStructureInfo>();
|
||||
Dictionary<MetaName, MetaEnumInfo> EnumInfos = new Dictionary<MetaName, MetaEnumInfo>();
|
||||
|
||||
public void AddStructureInfo(MetaName name)
|
||||
{
|
||||
if (!StructureInfos.ContainsKey(name))
|
||||
{
|
||||
MetaStructureInfo si = MetaTypes.GetStructureInfo(name);
|
||||
if (si != null)
|
||||
{
|
||||
StructureInfos[name] = si;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void AddEnumInfo(MetaName name)
|
||||
{
|
||||
if (!EnumInfos.ContainsKey(name))
|
||||
{
|
||||
MetaEnumInfo ei = MetaTypes.GetEnumInfo(name);
|
||||
if (ei != null)
|
||||
{
|
||||
EnumInfos[name] = ei;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public Meta GetMeta()
|
||||
{
|
||||
Meta m = new Meta();
|
||||
m.FileVFT = 0x405bc808;
|
||||
m.FileUnknown = 1;
|
||||
m.Unknown_10h = 0x50524430;
|
||||
m.Unknown_14h = 0x0079;
|
||||
|
||||
m.RootBlockIndex = 1; //assume first block is root. todo: make adjustable?
|
||||
|
||||
m.StructureInfos = new ResourceSimpleArray<MetaStructureInfo>();
|
||||
foreach (var si in StructureInfos.Values)
|
||||
{
|
||||
m.StructureInfos.Add(si);
|
||||
}
|
||||
m.StructureInfosCount = (short)m.StructureInfos.Count;
|
||||
|
||||
m.EnumInfos = new ResourceSimpleArray<MetaEnumInfo>();
|
||||
foreach (var ei in EnumInfos.Values)
|
||||
{
|
||||
m.EnumInfos.Add(ei);
|
||||
}
|
||||
m.EnumInfosCount = (short)m.EnumInfos.Count;
|
||||
|
||||
m.DataBlocks = new ResourceSimpleArray<MetaDataBlock>();
|
||||
foreach (var bb in Blocks)
|
||||
{
|
||||
m.DataBlocks.Add(bb.GetMetaDataBlock());
|
||||
}
|
||||
m.DataBlocksCount = (short)m.DataBlocks.Count;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class MetaBuilderBlock
|
||||
{
|
||||
public MetaName StructureNameHash { get; set; }
|
||||
public List<byte[]> Items { get; set; } = new List<byte[]>();
|
||||
public int TotalSize { get; set; } = 0;
|
||||
public int Index { get; set; } = 0;
|
||||
|
||||
public int AddItem(byte[] item)
|
||||
{
|
||||
int idx = Items.Count;
|
||||
Items.Add(item);
|
||||
TotalSize += item.Length;
|
||||
return idx;
|
||||
}
|
||||
|
||||
public uint BasePointer
|
||||
{
|
||||
get
|
||||
{
|
||||
return (((uint)Index + 1) & 0xFFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public MetaDataBlock GetMetaDataBlock()
|
||||
{
|
||||
if (TotalSize <= 0) return null;
|
||||
|
||||
byte[] data = new byte[TotalSize];
|
||||
int offset = 0;
|
||||
for (int j = 0; j < Items.Count; j++)
|
||||
{
|
||||
var bdata = Items[j];
|
||||
Buffer.BlockCopy(bdata, 0, data, offset, bdata.Length);
|
||||
offset += bdata.Length;
|
||||
}
|
||||
|
||||
MetaDataBlock db = new MetaDataBlock();
|
||||
db.StructureNameHash = StructureNameHash;
|
||||
db.DataLength = TotalSize;
|
||||
db.Data = data;
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public struct MetaBuilderPointer
|
||||
{
|
||||
public int Block { get; set; } //0-based index
|
||||
public int Offset { get; set; } //(byteoffset/16)
|
||||
public int Length { get; set; } //for temp use...
|
||||
public uint Pointer
|
||||
{
|
||||
get
|
||||
{
|
||||
uint bidx = (((uint)Block) & 0xFFF);
|
||||
uint offs = (((uint)Offset) & 0xFFFF) << 16;
|
||||
return bidx + offs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,910 @@
|
||||
/*
|
||||
Copyright(c) 2015 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.
|
||||
*/
|
||||
|
||||
//shamelessly stolen and mangled
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
|
||||
public enum PsoSection : uint
|
||||
{
|
||||
PSIN = 0x5053494E,
|
||||
PMAP = 0x504D4150,
|
||||
PSCH = 0x50534348,
|
||||
PSIG = 0x50534947,
|
||||
STRF = 0x53545246,
|
||||
STRS = 0x53545253,
|
||||
STRE = 0x53545245,
|
||||
CHKS = 0x43484B53,
|
||||
}
|
||||
|
||||
public enum PsoDataType : byte
|
||||
{
|
||||
//BYTE_00h = 0x00,
|
||||
//LONG_01h = 0x01,
|
||||
//BYTE_02h = 0x02,
|
||||
//SHORT_03h = 0x03,
|
||||
//SHORT_04h = 0x04,
|
||||
//INT_05h = 0x05,
|
||||
//INT_06h = 0x06,
|
||||
//Float = 0x07,
|
||||
//LONG_08h = 0x08,
|
||||
//TYPE_09h = 0x09,
|
||||
//TYPE_0Ah = 0x0a,
|
||||
//INT_0Bh = 0x0b, //Hash? Name
|
||||
//Structure = 0x0c,
|
||||
//Array = 0x0d,
|
||||
//BYTE_ENUM_VALUE = 0x0e,
|
||||
//SHORT_0Fh = 0x0f, //short flags
|
||||
//TYPE_10h = 0x10,
|
||||
//TYPE_14h = 0x14,
|
||||
//Vector4 = 0x15,
|
||||
//SHORT_1Eh = 0x1e,
|
||||
//LONG_20h = 0x20
|
||||
|
||||
Boolean = 0x00,
|
||||
Byte1 = 0x01, //signed byte..
|
||||
Byte2 = 0x02,
|
||||
SHORT_03h = 0x03, //signed short?
|
||||
SHORT_04h = 0x04,
|
||||
INT_05h = 0x05, //signed int?
|
||||
Integer = 0x06, //...unsigned?
|
||||
Float = 0x07,
|
||||
Float2 = 0x08,
|
||||
Float3 = 0x09,
|
||||
Float4 = 0x0a,
|
||||
String = 0x0b,
|
||||
Structure = 0x0c,
|
||||
Array = 0x0d,
|
||||
Enum = 0x0e,
|
||||
Flags = 0x0f,
|
||||
Map = 0x10,
|
||||
Float3a = 0x14,
|
||||
Float3b = 0x15,
|
||||
SHORT_1Eh = 0x1e,
|
||||
LONG_20h = 0x20
|
||||
|
||||
}
|
||||
public static class PsoDataTypes
|
||||
{
|
||||
public static string GetCSharpTypeName(PsoDataType t)
|
||||
{
|
||||
//MetaStructureEntryDataType mdt = (MetaStructureEntryDataType)t;
|
||||
switch (t)
|
||||
{
|
||||
case PsoDataType.Boolean: return "bool";
|
||||
case PsoDataType.Byte1: return "sbyte"; //was LONG_01h.. why?
|
||||
case PsoDataType.Byte2: return "byte";
|
||||
case PsoDataType.SHORT_03h: return "short";
|
||||
case PsoDataType.SHORT_04h: return "short";
|
||||
case PsoDataType.INT_05h: return "int";
|
||||
case PsoDataType.Integer: return "int";
|
||||
case PsoDataType.Float: return "float";
|
||||
case PsoDataType.Float2: return "long";
|
||||
case PsoDataType.String: return "uint"; //hash? NEEDS WORK?
|
||||
case PsoDataType.Enum: return "byte";
|
||||
case PsoDataType.Flags: return "short";
|
||||
case PsoDataType.SHORT_1Eh: return "short";
|
||||
case PsoDataType.LONG_20h: return "long";
|
||||
case PsoDataType.Float3:
|
||||
case PsoDataType.Float4:
|
||||
case PsoDataType.Map:
|
||||
case PsoDataType.Float3a:
|
||||
case PsoDataType.Float3b:
|
||||
case PsoDataType.Structure:
|
||||
case PsoDataType.Array:
|
||||
default:
|
||||
return t.ToString();
|
||||
|
||||
//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 class PsoFile
|
||||
{
|
||||
public PsoDataSection DataSection { get; set; }
|
||||
public PsoDataMapSection DataMapSection { get; set; }
|
||||
public PsoSchemaSection SchemaSection { get; set; }
|
||||
public PsoSTRFSection STRFSection { get; set; }
|
||||
public PsoSTRSSection STRSSection { get; set; }
|
||||
public PsoPSIGSection PSIGSection { get; set; }
|
||||
public PsoSTRESection STRESection { get; set; }
|
||||
public PsoCHKSSection CHKSSection { get; set; }
|
||||
|
||||
public void Load(string fileName)
|
||||
{
|
||||
using (var stream = new FileStream(fileName, FileMode.Open))
|
||||
Load(stream);
|
||||
}
|
||||
|
||||
public virtual void Load(Stream stream)
|
||||
{
|
||||
stream.Position = 0;
|
||||
|
||||
var reader = new DataReader(stream, Endianess.BigEndian);
|
||||
while (reader.Position < reader.Length)
|
||||
{
|
||||
var identInt = reader.ReadUInt32();
|
||||
var ident = (PsoSection)identInt;
|
||||
var length = reader.ReadInt32();
|
||||
|
||||
reader.Position -= 8;
|
||||
|
||||
var sectionData = reader.ReadBytes(length);
|
||||
var sectionStream = new MemoryStream(sectionData);
|
||||
var sectionReader = new DataReader(sectionStream, Endianess.BigEndian);
|
||||
|
||||
switch (ident)
|
||||
{
|
||||
case PsoSection.PSIN: //0x5053494E "PSIN" - ID / data section
|
||||
DataSection = new PsoDataSection();
|
||||
DataSection.Read(sectionReader);
|
||||
break;
|
||||
case PsoSection.PMAP: //0x504D4150 "PMAP" //data mapping
|
||||
DataMapSection = new PsoDataMapSection();
|
||||
DataMapSection.Read(sectionReader);
|
||||
break;
|
||||
case PsoSection.PSCH: //0x50534348 "PSCH" //schema
|
||||
SchemaSection = new PsoSchemaSection();
|
||||
SchemaSection.Read(sectionReader);
|
||||
break;
|
||||
case PsoSection.STRF: //0x53545246 "STRF" //paths/STRINGS (folder strings?)
|
||||
STRFSection = new PsoSTRFSection();
|
||||
STRFSection.Read(sectionReader);
|
||||
break;
|
||||
case PsoSection.STRS: //0x53545253 "STRS" //names/strings (DES_)
|
||||
STRSSection = new PsoSTRSSection();
|
||||
STRSSection.Read(sectionReader);
|
||||
break;
|
||||
case PsoSection.STRE: //0x53545245 "STRE" //probably encrypted strings.....
|
||||
STRESection = new PsoSTRESection();
|
||||
STRESection.Read(sectionReader);
|
||||
break;
|
||||
case PsoSection.PSIG: //0x50534947 "PSIG" //signature?
|
||||
PSIGSection = new PsoPSIGSection();
|
||||
PSIGSection.Read(sectionReader);
|
||||
break;
|
||||
case PsoSection.CHKS: //0x43484B53 "CHKS" //checksum?
|
||||
CHKSSection = new PsoCHKSSection();
|
||||
CHKSSection.Read(sectionReader);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(string fileName)
|
||||
{
|
||||
using (var stream = new FileStream(fileName, FileMode.Create))
|
||||
Save(stream);
|
||||
}
|
||||
|
||||
public virtual void Save(Stream stream)
|
||||
{
|
||||
var writer = new DataWriter(stream, Endianess.BigEndian);
|
||||
if (DataSection != null) DataSection.Write(writer);
|
||||
if (DataMapSection != null) DataMapSection.Write(writer);
|
||||
if (SchemaSection != null) SchemaSection.Write(writer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public PsoDataMappingEntry GetBlock(int id)
|
||||
{
|
||||
if (DataMapSection == null) return null;
|
||||
if (DataMapSection.Entries == null) return null;
|
||||
PsoDataMappingEntry block = null;
|
||||
var ind = id - 1;
|
||||
var blocks = DataMapSection.Entries;
|
||||
if ((ind >= 0) && (ind < blocks.Length))
|
||||
{
|
||||
block = blocks[ind];
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static bool IsPSO(Stream stream)
|
||||
{
|
||||
//return !IsRBF(stream);
|
||||
|
||||
//1347635534
|
||||
var reader = new DataReader(stream, Endianess.BigEndian);
|
||||
var identInt = reader.ReadUInt32();
|
||||
stream.Position = 0;
|
||||
return ((identInt ) == 1347635534); //"PSIN"
|
||||
|
||||
}
|
||||
|
||||
public static bool IsRBF(Stream stream)
|
||||
{
|
||||
var reader = new DataReader(stream, Endianess.BigEndian);
|
||||
var identInt = reader.ReadUInt32();
|
||||
stream.Position = 0;
|
||||
return ((identInt & 0xFFFFFF00) == 0x52424600);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoDataSection
|
||||
{
|
||||
public uint Ident { get; set; } = 0x5053494E;
|
||||
public int Length { get; private set; }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
Ident = reader.ReadUInt32();
|
||||
Length = reader.ReadInt32();
|
||||
reader.Position -= 8;
|
||||
Data = reader.ReadBytes(Length);
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
writer.Write(Data);
|
||||
writer.Position -= Data.Length;
|
||||
writer.Write((uint)0x5053494E);
|
||||
writer.Write((uint)(Data.Length));
|
||||
writer.Position += Data.Length - 8;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Ident.ToString() + ": " + Length.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoDataMapSection
|
||||
{
|
||||
public int Ident { get; set; } = 0x504D4150;
|
||||
public int Length { get; private set; }
|
||||
public int RootId { get; set; }
|
||||
public short EntriesCount { get; private set; }
|
||||
public short Unknown_Eh { get; set; } = 0x7070;
|
||||
public PsoDataMappingEntry[] Entries { get; set; }
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
Ident = reader.ReadInt32();
|
||||
Length = reader.ReadInt32();
|
||||
RootId = reader.ReadInt32();
|
||||
EntriesCount = reader.ReadInt16();
|
||||
Unknown_Eh = reader.ReadInt16();
|
||||
Entries = new PsoDataMappingEntry[EntriesCount];
|
||||
for (int i = 0; i < EntriesCount; i++)
|
||||
{
|
||||
var entry = new PsoDataMappingEntry();
|
||||
entry.Read(reader);
|
||||
Entries[i] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
// update...
|
||||
EntriesCount = (short)Entries.Length;
|
||||
Length = 16 + EntriesCount * 16;
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write(Length);
|
||||
writer.Write(RootId);
|
||||
writer.Write(EntriesCount);
|
||||
writer.Write(Unknown_Eh);
|
||||
foreach (var entry in Entries)
|
||||
{
|
||||
entry.Write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Ident.ToString() + ": " + EntriesCount.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoDataMappingEntry
|
||||
{
|
||||
public MetaName NameHash { get; set; }
|
||||
public int Offset { get; set; }
|
||||
public int Unknown_8h { get; set; } = 0x00000000;
|
||||
public int Length { get; set; }
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
this.NameHash = (MetaName)reader.ReadUInt32();
|
||||
this.Offset = reader.ReadInt32();
|
||||
this.Unknown_8h = reader.ReadInt32();
|
||||
this.Length = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
writer.Write((uint)NameHash);
|
||||
writer.Write(Offset);
|
||||
writer.Write(Unknown_8h);
|
||||
writer.Write(Length);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return NameHash.ToString() + ": " + Offset.ToString() + ": " + Length.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoSchemaSection
|
||||
{
|
||||
public int Ident { get; private set; } = 0x50534348;
|
||||
public int Length { get; set; }
|
||||
public uint Count { get; set; }
|
||||
|
||||
public PsoElementIndexInfo[] EntriesIdx { get; set; }
|
||||
public PsoElementInfo[] Entries { get; set; }
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
Ident = reader.ReadInt32();
|
||||
Length = reader.ReadInt32();
|
||||
Count = reader.ReadUInt32();
|
||||
|
||||
this.EntriesIdx = new PsoElementIndexInfo[Count];
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
var entry = new PsoElementIndexInfo();
|
||||
entry.Read(reader);
|
||||
EntriesIdx[i] = entry;
|
||||
}
|
||||
|
||||
this.Entries = new PsoElementInfo[Count];
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
reader.Position = EntriesIdx[i].Offset;
|
||||
var type = reader.ReadByte();
|
||||
|
||||
reader.Position = EntriesIdx[i].Offset;
|
||||
if (type == 0)
|
||||
{
|
||||
var entry = new PsoStructureInfo();
|
||||
entry.Read(reader);
|
||||
entry.IndexInfo = EntriesIdx[i];
|
||||
Entries[i] = entry;
|
||||
}
|
||||
else if (type == 1)
|
||||
{
|
||||
var entry = new PsoEnumInfo();
|
||||
entry.Read(reader);
|
||||
entry.IndexInfo = EntriesIdx[i];
|
||||
Entries[i] = entry;
|
||||
}
|
||||
else
|
||||
throw new Exception("unknown type!");
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
|
||||
var entriesStream = new MemoryStream();
|
||||
var entriesWriter = new DataWriter(entriesStream, Endianess.BigEndian);
|
||||
for (int i = 0; i < Entries.Length; i++)
|
||||
{
|
||||
EntriesIdx[i].Offset = 12 + 8 * Entries.Length + (int)entriesWriter.Position;
|
||||
Entries[i].Write(entriesWriter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
var indexStream = new MemoryStream();
|
||||
var indexWriter = new DataWriter(indexStream, Endianess.BigEndian);
|
||||
foreach (var entry in EntriesIdx)
|
||||
entry.Write(indexWriter);
|
||||
|
||||
|
||||
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write((int)(12 + entriesStream.Length + indexStream.Length));
|
||||
writer.Write((int)(Entries.Length));
|
||||
|
||||
// write entries index data
|
||||
var buf1 = new byte[indexStream.Length];
|
||||
indexStream.Position = 0;
|
||||
indexStream.Read(buf1, 0, buf1.Length);
|
||||
writer.Write(buf1);
|
||||
|
||||
// write entries data
|
||||
var buf2 = new byte[entriesStream.Length];
|
||||
entriesStream.Position = 0;
|
||||
entriesStream.Read(buf2, 0, buf2.Length);
|
||||
writer.Write(buf2);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Ident.ToString() + ": " + Count.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoElementIndexInfo
|
||||
{
|
||||
public MetaName NameHash { get; set; }
|
||||
public int Offset { get; set; }
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
this.NameHash = (MetaName)reader.ReadUInt32();
|
||||
this.Offset = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
writer.Write((uint)NameHash);
|
||||
writer.Write(Offset);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return NameHash.ToString() + ": " + Offset.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public abstract class PsoElementInfo
|
||||
{
|
||||
public PsoElementIndexInfo IndexInfo { get; set; }
|
||||
|
||||
public abstract void Read(DataReader reader);
|
||||
|
||||
public abstract void Write(DataWriter writer);
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoStructureInfo : PsoElementInfo
|
||||
{
|
||||
public byte Type { get; set; } = 0;
|
||||
public short EntriesCount { get; private set; }
|
||||
public byte Unk { get; set; }
|
||||
public int StructureLength { get; set; }
|
||||
public uint Unk_Ch { get; set; } = 0x00000000;
|
||||
public PsoStructureEntryInfo[] Entries { get; set; }
|
||||
|
||||
public override void Read(DataReader reader)
|
||||
{
|
||||
uint x = reader.ReadUInt32();
|
||||
this.Type = (byte)((x & 0xFF000000) >> 24);
|
||||
this.EntriesCount = (short)(x & 0xFFFF);
|
||||
this.Unk = (byte)((x & 0x00FF0000) >> 16);
|
||||
this.StructureLength = reader.ReadInt32();
|
||||
this.Unk_Ch = reader.ReadUInt32();
|
||||
|
||||
Entries = new PsoStructureEntryInfo[EntriesCount];
|
||||
for (int i = 0; i < EntriesCount; i++)
|
||||
{
|
||||
var entry = new PsoStructureEntryInfo();
|
||||
entry.Read(reader);
|
||||
Entries[i] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(DataWriter writer)
|
||||
{
|
||||
Type = 0;
|
||||
EntriesCount = (short)Entries.Length;
|
||||
|
||||
uint typeAndEntriesCount = (uint)(Type << 24) | (uint)(Unk << 16) | (ushort)EntriesCount;
|
||||
writer.Write(typeAndEntriesCount);
|
||||
writer.Write(StructureLength);
|
||||
writer.Write(Unk_Ch);
|
||||
|
||||
foreach (var entry in Entries)
|
||||
{
|
||||
entry.Write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return IndexInfo.ToString() + " - " + Type.ToString() + ": " + EntriesCount.ToString();
|
||||
}
|
||||
|
||||
public PsoStructureEntryInfo FindEntry(MetaName name)
|
||||
{
|
||||
if (Entries != null)
|
||||
{
|
||||
foreach (var entry in Entries)
|
||||
{
|
||||
if (entry.EntryNameHash == name) return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public PsoStructureEntryInfo GetEntry(int id)
|
||||
{
|
||||
if ((Entries != null) && (id >= 0) && (id < Entries.Length))
|
||||
{
|
||||
return Entries[id];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoStructureEntryInfo
|
||||
{
|
||||
public MetaName EntryNameHash { get; set; }
|
||||
public PsoDataType Type { get; set; }
|
||||
public byte Unk_5h { get; set; }
|
||||
public ushort DataOffset { get; set; }
|
||||
public uint ReferenceKey { get; set; } // when array -> entry index with type
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
this.EntryNameHash = (MetaName)reader.ReadUInt32();
|
||||
this.Type = (PsoDataType)reader.ReadByte();
|
||||
this.Unk_5h = reader.ReadByte();
|
||||
this.DataOffset = reader.ReadUInt16();
|
||||
this.ReferenceKey = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
writer.Write((uint)EntryNameHash);
|
||||
writer.Write((byte)Type);
|
||||
writer.Write(Unk_5h);
|
||||
writer.Write(DataOffset);
|
||||
writer.Write(ReferenceKey);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if(ReferenceKey!=0)
|
||||
{
|
||||
return EntryNameHash.ToString() + ": " + Type.ToString() + ": " + DataOffset.ToString() + ": " + ((MetaName)ReferenceKey).ToString();
|
||||
}
|
||||
return EntryNameHash.ToString() + ": " + Type.ToString() + ": " + DataOffset.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoEnumInfo : PsoElementInfo
|
||||
{
|
||||
public byte Type { get; private set; } = 1;
|
||||
public int EntriesCount { get; private set; }
|
||||
public PsoEnumEntryInfo[] Entries { get; set; }
|
||||
|
||||
public override void Read(DataReader reader)
|
||||
{
|
||||
uint x = reader.ReadUInt32();
|
||||
this.Type = (byte)((x & 0xFF000000) >> 24);
|
||||
this.EntriesCount = (int)(x & 0x00FFFFFF);
|
||||
|
||||
Entries = new PsoEnumEntryInfo[EntriesCount];
|
||||
for (int i = 0; i < EntriesCount; i++)
|
||||
{
|
||||
var entry = new PsoEnumEntryInfo();
|
||||
entry.Read(reader);
|
||||
Entries[i] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(DataWriter writer)
|
||||
{
|
||||
// update...
|
||||
Type = 1;
|
||||
EntriesCount = Entries.Length;
|
||||
|
||||
uint typeAndEntriesCount = (uint)(Type << 24) | (uint)EntriesCount;
|
||||
writer.Write(typeAndEntriesCount);
|
||||
|
||||
foreach (var entry in Entries)
|
||||
{
|
||||
entry.Write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public PsoEnumEntryInfo FindEntry(int val)
|
||||
{
|
||||
if (Entries == null) return null;
|
||||
for (int i = 0; i < Entries.Length; i++)
|
||||
{
|
||||
var entry = Entries[i];
|
||||
if (entry.EntryKey == val)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return IndexInfo.ToString() + " - " + Type.ToString() + ": " + EntriesCount.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoEnumEntryInfo
|
||||
{
|
||||
public MetaName EntryNameHash { get; set; }
|
||||
public int EntryKey { get; set; }
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
this.EntryNameHash = (MetaName)reader.ReadUInt32();
|
||||
this.EntryKey = reader.ReadInt32();
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
writer.Write((uint)EntryNameHash);
|
||||
writer.Write(EntryKey);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return EntryNameHash.ToString() + ": " + EntryKey.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoSTRFSection
|
||||
{
|
||||
public int Ident { get; private set; } = 0x53545246;
|
||||
public int Length { get; set; }
|
||||
public string[] Strings { get; set; }
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
Ident = reader.ReadInt32();
|
||||
Length = reader.ReadInt32();
|
||||
List<string> strs = new List<string>();
|
||||
while (reader.Position < reader.Length)
|
||||
{
|
||||
strs.Add(reader.ReadString());
|
||||
}
|
||||
foreach (var str in strs)
|
||||
{
|
||||
JenkIndex.Ensure(str);
|
||||
JenkIndex.Ensure(str.ToLowerInvariant());
|
||||
}
|
||||
Strings = strs.ToArray();
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write(Length);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Ident.ToString() + ": " + Length.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoSTRSSection
|
||||
{
|
||||
public int Ident { get; private set; } = 0x53545253;
|
||||
public int Length { get; set; }
|
||||
public string[] Strings { get; set; }
|
||||
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
Ident = reader.ReadInt32();
|
||||
Length = reader.ReadInt32();
|
||||
|
||||
List<string> strs = new List<string>();
|
||||
while (reader.Position < reader.Length)
|
||||
{
|
||||
strs.Add(reader.ReadString());
|
||||
}
|
||||
foreach (var str in strs)
|
||||
{
|
||||
JenkIndex.Ensure(str);
|
||||
JenkIndex.Ensure(str.ToLowerInvariant());
|
||||
}
|
||||
Strings = strs.ToArray();
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write(Length);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Ident.ToString() + ": " + Length.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoSTRESection
|
||||
{
|
||||
public int Ident { get; private set; } = 0x53545245;
|
||||
public int Length { get; set; }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
//public MetaHash[] Hashes { get; set; }
|
||||
//public byte[] Decr1 { get; set; }
|
||||
//public byte[] Decr2 { get; set; }
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
Ident = reader.ReadInt32();
|
||||
Length = reader.ReadInt32();
|
||||
|
||||
if (Length > 8)
|
||||
{
|
||||
Data = reader.ReadBytes(Length - 8);
|
||||
|
||||
//reader.Position = 8;
|
||||
//List<MetaHash> hashes = new List<MetaHash>();
|
||||
//while (reader.Position < reader.Length)
|
||||
//{
|
||||
// hashes.Add(reader.ReadUInt32());
|
||||
//}
|
||||
//Hashes = hashes.ToArray();
|
||||
|
||||
//Decr1 = GTACrypto.DecryptAES(Data);
|
||||
//Decr2 = GTACrypto.DecryptNG(Data, )
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write(Length);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Ident.ToString() + ": " + Length.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoPSIGSection
|
||||
{
|
||||
public int Ident { get; private set; } = 0x50534947;
|
||||
public int Length { get; set; }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
Ident = reader.ReadInt32();
|
||||
Length = reader.ReadInt32();
|
||||
|
||||
if (Length > 8)
|
||||
{
|
||||
Data = reader.ReadBytes(Length - 8);
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write(Length);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Ident.ToString() + ": " + Length.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoCHKSSection
|
||||
{
|
||||
public int Ident { get; private set; } = 0x43484B53;
|
||||
public int Length { get; set; }
|
||||
public uint FileSize { get; set; }
|
||||
public uint Checksum { get; set; }
|
||||
public uint Unk0 { get; set; } = 0x79707070; // "yppp"
|
||||
|
||||
public void Read(DataReader reader)
|
||||
{
|
||||
Ident = reader.ReadInt32();
|
||||
Length = reader.ReadInt32();
|
||||
|
||||
if (Length != 20)
|
||||
{ return; }
|
||||
|
||||
FileSize = reader.ReadUInt32();
|
||||
Checksum = reader.ReadUInt32();
|
||||
Unk0 = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public void Write(DataWriter writer)
|
||||
{
|
||||
|
||||
writer.Write(Ident);
|
||||
writer.Write(Length);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Ident.ToString() + ": " + Length.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,856 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using TC = System.ComponentModel.TypeConverterAttribute;
|
||||
using EXP = System.ComponentModel.ExpandableObjectConverter;
|
||||
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
public static class PsoTypes
|
||||
{
|
||||
//for parsing schema info in PSO files to generate structs for PSO parsing.
|
||||
//equivalent of MetaTypes but for PSO.
|
||||
|
||||
public static Dictionary<MetaName, PsoEnumInfo> EnumDict = new Dictionary<MetaName, PsoEnumInfo>();
|
||||
public static Dictionary<MetaName, PsoStructureInfo> StructDict = new Dictionary<MetaName, PsoStructureInfo>();
|
||||
|
||||
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
StructDict.Clear();
|
||||
}
|
||||
|
||||
public static void EnsurePsoTypes(PsoFile pso)
|
||||
{
|
||||
|
||||
if ((pso.SchemaSection == null) || (pso.SchemaSection.Entries == null) || (pso.SchemaSection.EntriesIdx == null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < pso.SchemaSection.Entries.Length; i++)
|
||||
{
|
||||
var entry = pso.SchemaSection.Entries[i];
|
||||
var enuminfo = entry as PsoEnumInfo;
|
||||
var structinfo = entry as PsoStructureInfo;
|
||||
|
||||
if (enuminfo != null)
|
||||
{
|
||||
if (!EnumDict.ContainsKey(enuminfo.IndexInfo.NameHash))
|
||||
{
|
||||
EnumDict.Add(enuminfo.IndexInfo.NameHash, enuminfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
PsoEnumInfo oldei = EnumDict[enuminfo.IndexInfo.NameHash];
|
||||
if (!ComparePsoEnumInfos(oldei, enuminfo))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (structinfo != null)
|
||||
{
|
||||
if (!StructDict.ContainsKey(structinfo.IndexInfo.NameHash))
|
||||
{
|
||||
StructDict.Add(structinfo.IndexInfo.NameHash, structinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
PsoStructureInfo oldsi = StructDict[structinfo.IndexInfo.NameHash];
|
||||
if (!ComparePsoStructureInfos(oldsi, structinfo))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static bool ComparePsoEnumInfos(PsoEnumInfo a, PsoEnumInfo b)
|
||||
{
|
||||
//returns true if they are the same.
|
||||
|
||||
if (a.Entries.Length != b.Entries.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < a.Entries.Length; i++)
|
||||
{
|
||||
if ((a.Entries[i].EntryNameHash != b.Entries[i].EntryNameHash) ||
|
||||
(a.Entries[i].EntryKey != b.Entries[i].EntryKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public static bool ComparePsoStructureInfos(PsoStructureInfo a, PsoStructureInfo b)
|
||||
{
|
||||
//returns true if they are the same.
|
||||
|
||||
if (a.Entries.Length != b.Entries.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < a.Entries.Length; i++)
|
||||
{
|
||||
if ((a.Entries[i].EntryNameHash != b.Entries[i].EntryNameHash) ||
|
||||
(a.Entries[i].DataOffset != b.Entries[i].DataOffset) ||
|
||||
(a.Entries[i].Type != b.Entries[i].Type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static string GetTypesString()
|
||||
{
|
||||
StringBuilder sbe = new StringBuilder();
|
||||
StringBuilder sbs = new StringBuilder();
|
||||
|
||||
sbe.AppendLine("//Enum infos");
|
||||
sbs.AppendLine("//Struct infos");
|
||||
|
||||
|
||||
foreach (var kvp in EnumDict)
|
||||
{
|
||||
var ei = kvp.Value;
|
||||
string name = GetSafeName(ei.IndexInfo.NameHash, ei.Type);
|
||||
sbe.AppendLine("public enum " + name + " //Type:" + ei.Type.ToString());
|
||||
sbe.AppendLine("{");
|
||||
foreach (var entry in ei.Entries)
|
||||
{
|
||||
string eename = GetSafeName(entry.EntryNameHash, (uint)entry.EntryKey);
|
||||
sbe.AppendFormat(" {0} = {1},", eename, entry.EntryKey);
|
||||
sbe.AppendLine();
|
||||
}
|
||||
sbe.AppendLine("}");
|
||||
sbe.AppendLine();
|
||||
}
|
||||
|
||||
foreach (var kvp in StructDict)
|
||||
{
|
||||
var si = kvp.Value;
|
||||
string name = GetSafeName(si.IndexInfo.NameHash, si.Type);
|
||||
sbs.AppendLine("public struct " + name + " //" + si.StructureLength.ToString() + " bytes, Type:" + si.Type.ToString());
|
||||
sbs.AppendLine("{");
|
||||
for (int i = 0; i < si.Entries.Length; i++)
|
||||
{
|
||||
var entry = si.Entries[i];
|
||||
|
||||
if ((entry.DataOffset == 0) && (entry.EntryNameHash == MetaName.ARRAYINFO)) //referred to by array
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
string sename = GetSafeName(entry.EntryNameHash, entry.ReferenceKey);
|
||||
string fmt = " public {0} {1}; //{2} {3}";
|
||||
|
||||
if (entry.Type == PsoDataType.Array)
|
||||
{
|
||||
if (entry.ReferenceKey >= si.Entries.Length)
|
||||
{
|
||||
sbs.AppendFormat(fmt, entry.Type.ToString(), sename, entry.DataOffset, entry.ToString() + " { unexpected key! " + entry.ReferenceKey.ToString() + "}");
|
||||
sbs.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
var structentry = si.Entries[(int)entry.ReferenceKey];
|
||||
var typename = "Array_" + PsoDataTypes.GetCSharpTypeName(structentry.Type);
|
||||
sbs.AppendFormat(fmt, typename, sename, entry.DataOffset, entry.ToString() + " {" + structentry.ToString() + "}");
|
||||
sbs.AppendLine();
|
||||
}
|
||||
}
|
||||
else if (entry.Type == PsoDataType.Structure)
|
||||
{
|
||||
var typename = GetSafeName((MetaName)entry.ReferenceKey, entry.ReferenceKey);
|
||||
sbs.AppendFormat(fmt, typename, sename, entry.DataOffset, entry.ToString());
|
||||
sbs.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
var typename = PsoDataTypes.GetCSharpTypeName(entry.Type);
|
||||
sbs.AppendFormat(fmt, typename, sename, entry.DataOffset, entry);
|
||||
sbs.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
sbs.AppendLine("}");
|
||||
sbs.AppendLine();
|
||||
}
|
||||
|
||||
|
||||
sbe.AppendLine();
|
||||
sbe.AppendLine();
|
||||
sbe.AppendLine();
|
||||
sbe.AppendLine();
|
||||
sbe.AppendLine();
|
||||
sbe.Append(sbs.ToString());
|
||||
|
||||
string result = sbe.ToString();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static string GetSafeName(MetaName namehash, uint key)
|
||||
{
|
||||
string name = namehash.ToString();
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = "Unk_" + key;
|
||||
}
|
||||
if (!char.IsLetter(name[0]))
|
||||
{
|
||||
name = "Unk_" + name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static T ConvertDataRaw<T>(byte[] data) where T : struct
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
var h = handle.AddrOfPinnedObject();
|
||||
var r = Marshal.PtrToStructure<T>(h);
|
||||
handle.Free();
|
||||
return r;
|
||||
}
|
||||
public static T ConvertDataRaw<T>(byte[] data, int offset) where T : struct
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
var h = handle.AddrOfPinnedObject();
|
||||
var r = Marshal.PtrToStructure<T>(h + offset);
|
||||
handle.Free();
|
||||
return r;
|
||||
}
|
||||
public static T ConvertData<T>(byte[] data, int offset) where T : struct, IPsoSwapEnd
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
var h = handle.AddrOfPinnedObject();
|
||||
var r = Marshal.PtrToStructure<T>(h + offset);
|
||||
handle.Free();
|
||||
r.SwapEnd();
|
||||
return r;
|
||||
}
|
||||
public static T[] ConvertDataArrayRaw<T>(byte[] data, int offset, int count) where T : struct
|
||||
{
|
||||
T[] items = new T[count];
|
||||
int itemsize = Marshal.SizeOf(typeof(T));
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int off = offset + i * itemsize;
|
||||
items[i] = ConvertDataRaw<T>(data, off);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
public static T GetItem<T>(PsoFile pso, int offset) where T : struct, IPsoSwapEnd
|
||||
{
|
||||
return ConvertData<T>(pso.DataSection.Data, offset);
|
||||
}
|
||||
public static T GetRootItem<T>(PsoFile pso) where T : struct, IPsoSwapEnd
|
||||
{
|
||||
var i = pso.DataMapSection.RootId - 1;
|
||||
var e = pso.DataMapSection.Entries[i];
|
||||
return GetItem<T>(pso, e.Offset);
|
||||
}
|
||||
public static PsoDataMappingEntry GetRootEntry(PsoFile pso)
|
||||
{
|
||||
var i = pso.DataMapSection.RootId - 1;
|
||||
var e = pso.DataMapSection.Entries[i];
|
||||
return e;
|
||||
}
|
||||
|
||||
public static T[] GetItemArrayRaw<T>(PsoFile pso, Array_Structure arr) where T : struct
|
||||
{
|
||||
if ((arr.Count1 > 0) && (arr.Pointer > 0))
|
||||
{
|
||||
var entry = pso.DataMapSection.Entries[(int)arr.PointerDataIndex];
|
||||
return ConvertDataArrayRaw<T>(pso.DataSection.Data, entry.Offset, arr.Count1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static T[] GetItemArray<T>(PsoFile pso, Array_Structure arr) where T : struct, IPsoSwapEnd
|
||||
{
|
||||
if ((arr.Count1 > 0) && (arr.Pointer > 0))
|
||||
{
|
||||
var entry = pso.DataMapSection.Entries[(int)arr.PointerDataIndex];
|
||||
var res = ConvertDataArrayRaw<T>(pso.DataSection.Data, entry.Offset, arr.Count1);
|
||||
if (res != null)
|
||||
{
|
||||
for (int i = 0; i < res.Length; i++)
|
||||
{
|
||||
res[i].SwapEnd();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static uint[] GetUintArrayRaw(PsoFile pso, Array_uint arr)
|
||||
{
|
||||
byte[] data = pso.DataSection.Data;
|
||||
var entryid = arr.Pointer & 0xFFF;
|
||||
if ((entryid == 0) || (entryid > pso.DataMapSection.EntriesCount))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var entryoffset = (arr.Pointer & 0xFFFFFF) >> 12;
|
||||
var arrentry = pso.DataMapSection.Entries[(int)entryid - 1];
|
||||
int totoffset = arrentry.Offset + (int)entryoffset;
|
||||
uint[] readdata = ConvertDataArrayRaw<uint>(data, totoffset, arr.Count1);
|
||||
return readdata;
|
||||
}
|
||||
public static uint[] GetUintArray(PsoFile pso, Array_uint arr)
|
||||
{
|
||||
uint[] uints = GetUintArrayRaw(pso, arr);
|
||||
if (uints == null) return null;
|
||||
for (int i = 0; i < uints.Length; i++)
|
||||
{
|
||||
uints[i] = MetaTypes.SwapBytes(uints[i]);
|
||||
}
|
||||
return uints;
|
||||
}
|
||||
|
||||
public static MetaHash[] GetHashArray(PsoFile pso, Array_uint arr)
|
||||
{
|
||||
uint[] uints = GetUintArrayRaw(pso, arr);
|
||||
if (uints == null) return null;
|
||||
MetaHash[] hashes = new MetaHash[uints.Length];
|
||||
for (int n = 0; n < uints.Length; n++)
|
||||
{
|
||||
hashes[n].Hash = MetaTypes.SwapBytes(uints[n]);
|
||||
}
|
||||
return hashes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static float[] GetFloatArrayRaw(PsoFile pso, Array_float arr)
|
||||
{
|
||||
byte[] data = pso.DataSection.Data;
|
||||
var entryid = arr.Pointer & 0xFFF;
|
||||
if ((entryid == 0) || (entryid > pso.DataMapSection.EntriesCount))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var entryoffset = (arr.Pointer & 0xFFFFFF) >> 12;
|
||||
var arrentry = pso.DataMapSection.Entries[(int)entryid - 1];
|
||||
int totoffset = arrentry.Offset + (int)entryoffset;
|
||||
float[] readdata = ConvertDataArrayRaw<float>(data, totoffset, arr.Count1);
|
||||
return readdata;
|
||||
}
|
||||
public static float[] GetFloatArray(PsoFile pso, Array_float arr)
|
||||
{
|
||||
float[] floats = GetFloatArrayRaw(pso, arr);
|
||||
if (floats == null) return null;
|
||||
for (int i = 0; i < floats.Length; i++)
|
||||
{
|
||||
floats[i] = MetaTypes.SwapBytes(floats[i]);
|
||||
}
|
||||
return floats;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static ushort[] GetUShortArrayRaw(PsoFile pso, Array_Structure arr)
|
||||
{
|
||||
byte[] data = pso.DataSection.Data;
|
||||
var entryid = arr.Pointer & 0xFFF;
|
||||
if ((entryid == 0) || (entryid > pso.DataMapSection.EntriesCount))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var entryoffset = (arr.Pointer & 0xFFFFFF) >> 12;
|
||||
var arrentry = pso.DataMapSection.Entries[(int)entryid - 1];
|
||||
int totoffset = arrentry.Offset + (int)entryoffset;
|
||||
ushort[] readdata = ConvertDataArrayRaw<ushort>(data, totoffset, arr.Count1);
|
||||
return readdata;
|
||||
}
|
||||
public static ushort[] GetUShortArray(PsoFile pso, Array_Structure arr)
|
||||
{
|
||||
ushort[] ushorts = GetUShortArrayRaw(pso, arr);
|
||||
if (ushorts == null) return null;
|
||||
for (int i = 0; i < ushorts.Length; i++)
|
||||
{
|
||||
ushorts[i] = MetaTypes.SwapBytes(ushorts[i]);
|
||||
}
|
||||
return ushorts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static T[] GetObjectArray<T, U>(PsoFile pso, Array_Structure arr) where U : struct, IPsoSwapEnd where T : PsoClass<U>, new()
|
||||
{
|
||||
U[] items = GetItemArray<U>(pso, arr);
|
||||
if (items == null) return null;
|
||||
if (items.Length == 0) return null;
|
||||
T[] result = new T[items.Length];
|
||||
for (int i = 0; i < items.Length; i++)
|
||||
{
|
||||
T newitem = new T();
|
||||
newitem.Init(pso, ref items[i]);
|
||||
result[i] = newitem;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static byte[] GetByteArray(PsoFile pso, PsoStructureEntryInfo entry, int offset)
|
||||
{
|
||||
var aCount = (entry.ReferenceKey >> 16) & 0x0000FFFF;
|
||||
var aBlockId = (int)entry.ReferenceKey & 0x0000FFFF;
|
||||
var block = pso.GetBlock(aBlockId);
|
||||
if (block == null) return null;
|
||||
|
||||
//block.Offset
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static PsoPOINTER[] GetPointerArray(PsoFile pso, Array_StructurePointer array)
|
||||
{
|
||||
uint count = array.Count1;
|
||||
if (count == 0) return null;
|
||||
|
||||
int ptrsize = Marshal.SizeOf(typeof(MetaPOINTER));
|
||||
int itemsleft = (int)count; //large arrays get split into chunks...
|
||||
uint ptr = array.Pointer;
|
||||
int ptrindex = (int)(ptr & 0xFFF) - 1;
|
||||
int ptroffset = (int)((ptr >> 12) & 0xFFFFF);
|
||||
var ptrblock = (ptrindex < pso.DataMapSection.EntriesCount) ? pso.DataMapSection.Entries[ptrindex] : null;
|
||||
if ((ptrblock == null) || (ptrblock.NameHash != MetaName.PsoPOINTER))
|
||||
{ return null; }
|
||||
|
||||
var offset = ptrblock.Offset;
|
||||
int boffset = offset + ptroffset;
|
||||
|
||||
var ptrs = ConvertDataArrayRaw<PsoPOINTER>(pso.DataSection.Data, boffset, (int)count);
|
||||
if (ptrs != null)
|
||||
{
|
||||
for (int i = 0; i < ptrs.Length; i++)
|
||||
{
|
||||
ptrs[i].SwapEnd();
|
||||
}
|
||||
}
|
||||
|
||||
return ptrs;
|
||||
}
|
||||
|
||||
|
||||
public static T[] ConvertDataArray<T>(PsoFile pso, Array_StructurePointer array) where T : struct, IPsoSwapEnd
|
||||
{
|
||||
uint count = array.Count1;
|
||||
if (count == 0) return null;
|
||||
PsoPOINTER[] ptrs = GetPointerArray(pso, array);
|
||||
if (ptrs == null) return null;
|
||||
if (ptrs.Length < count)
|
||||
{ return null; }
|
||||
|
||||
T[] items = new T[count];
|
||||
int itemsize = Marshal.SizeOf(typeof(T));
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var sptr = ptrs[i];
|
||||
int blocki = sptr.BlockID - 1;
|
||||
int offset = (int)sptr.ItemOffset;// * 16;//block data size...
|
||||
if (blocki >= pso.DataMapSection.EntriesCount)
|
||||
{ continue; }
|
||||
var block = pso.DataMapSection.Entries[blocki];
|
||||
|
||||
if ((offset < 0) || (offset >= block.Length))
|
||||
{ continue; }
|
||||
|
||||
int boffset = block.Offset + offset;
|
||||
|
||||
items[i] = ConvertData<T>(pso.DataSection.Data, boffset);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static string GetString(PsoFile pso, CharPointer ptr)
|
||||
{
|
||||
if (ptr.Count1 == 0) return null;
|
||||
|
||||
var blocki = (int)ptr.PointerDataId;// (ptr.Pointer & 0xFFF) - 1;
|
||||
var offset = (int)ptr.PointerDataOffset;// (ptr.Pointer >> 12) & 0xFFFFF;
|
||||
|
||||
var block = pso.GetBlock(blocki);
|
||||
if (block == null)
|
||||
{ return null; }
|
||||
|
||||
var length = ptr.Count1;
|
||||
var lastbyte = offset + length;
|
||||
if (lastbyte >= block.Length)
|
||||
{ return null; }
|
||||
|
||||
var data = pso.DataSection?.Data;
|
||||
if (data == null)
|
||||
{ return null; }
|
||||
|
||||
var doffset = block.Offset + offset;
|
||||
|
||||
string s = Encoding.ASCII.GetString(data, doffset, length);
|
||||
|
||||
//if (meta.Strings == null) return null;
|
||||
//if (offset < 0) return null;
|
||||
//if (offset >= meta.Strings.Length) return null;
|
||||
//string s = meta.Strings[offset];
|
||||
|
||||
return s;
|
||||
}
|
||||
public static string GetString(PsoFile pso, DataBlockPointer ptr)
|
||||
{
|
||||
var blocki = (int)ptr.PointerDataId;// (ptr.Pointer & 0xFFF) - 1;
|
||||
var offset = (int)ptr.PointerDataOffset;// (ptr.Pointer >> 12) & 0xFFFFF;
|
||||
|
||||
var block = pso.GetBlock(blocki);
|
||||
if (block == null)
|
||||
{ return null; }
|
||||
|
||||
//var length = ptr.Count1;
|
||||
//var lastbyte = offset + length;
|
||||
//if (lastbyte >= block.Length)
|
||||
//{ return null; }
|
||||
|
||||
var data = pso.DataSection?.Data;
|
||||
if (data == null)
|
||||
{ return null; }
|
||||
|
||||
//var doffset = block.Offset + offset;
|
||||
|
||||
//string s = Encoding.ASCII.GetString(data, doffset, length);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
var o = block.Offset + offset;
|
||||
char c = (char)data[o];
|
||||
while (c != 0)
|
||||
{
|
||||
sb.Append(c);
|
||||
o++;
|
||||
c = (char)data[o];
|
||||
}
|
||||
var s = sb.ToString();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public interface IPsoSwapEnd
|
||||
{
|
||||
void SwapEnd();
|
||||
}
|
||||
|
||||
public abstract class PsoClass<T> where T : struct, IPsoSwapEnd
|
||||
{
|
||||
public abstract void Init(PsoFile pso, ref T v);
|
||||
}
|
||||
|
||||
|
||||
public struct PsoChar64
|
||||
{
|
||||
public byte b00, b01, b02, b03, b04, b05, b06, b07, b08, b09,
|
||||
b10, b11, b12, b13, b14, b15, b16, b17, b18, b19,
|
||||
b20, b21, b22, b23, b24, b25, b26, b27, b28, b29,
|
||||
b30, b31, b32, b33, b34, b35, b36, b37, b38, b39,
|
||||
b40, b41, b42, b43, b44, b45, b46, b47, b48, b49,
|
||||
b50, b51, b52, b53, b54, b55, b56, b57, b58, b59,
|
||||
b60, b61, b62, b63;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
byte[] bytes = new byte[]
|
||||
{
|
||||
b00, b01, b02, b03, b04, b05, b06, b07, b08, b09,
|
||||
b10, b11, b12, b13, b14, b15, b16, b17, b18, b19,
|
||||
b20, b21, b22, b23, b24, b25, b26, b27, b28, b29,
|
||||
b30, b31, b32, b33, b34, b35, b36, b37, b38, b39,
|
||||
b40, b41, b42, b43, b44, b45, b46, b47, b48, b49,
|
||||
b50, b51, b52, b53, b54, b55, b56, b57, b58, b59,
|
||||
b60, b61, b62, b63
|
||||
};
|
||||
return Encoding.ASCII.GetString(bytes).Replace("\0", string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
[TC(typeof(EXP))] public struct PsoPOINTER : IPsoSwapEnd //8 bytes - pointer to data item
|
||||
{
|
||||
public uint Pointer { get; set; }
|
||||
public uint Unk2 { get; set; }
|
||||
|
||||
public ushort BlockID { get { return (ushort)(Pointer & 0xFFF); } } //1-based ID
|
||||
public uint ItemOffset { get { return (ushort)((Pointer>>12) & 0xFFFFF); } } //byte offset
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return BlockID.ToString() + ", " + ItemOffset.ToString() + ", " + Unk2.ToString();
|
||||
}
|
||||
|
||||
public void SwapEnd()
|
||||
{
|
||||
Pointer = MetaTypes.SwapBytes(Pointer);
|
||||
Unk2 = MetaTypes.SwapBytes(Unk2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Struct infos
|
||||
[TC(typeof(EXP))] public struct CPackFileMetaData : IPsoSwapEnd //96 bytes, Type:0
|
||||
{
|
||||
public Array_Structure MapDataGroups; //0 MapDataGroups: Array: 0 {256: Structure: 0: 3260758307}
|
||||
public Array_Structure HDTxdBindingArray; //16 HDTxdBindingArray: Array: 16: 2 {256: Structure: 0: CHDTxdAssetBinding}
|
||||
public Array_Structure imapDependencies; //32 imapDependencies: Array: 32: 4 {256: Structure: 0: 3501026914}
|
||||
public Array_Structure imapDependencies_2; //48 imapDependencies_2: Array: 48: 6 {256: Structure: 0: 3240050401}
|
||||
public Array_Structure itypDependencies_2; //64 itypDependencies_2: Array: 64: 8 {256: Structure: 0: 1515605584}
|
||||
public Array_Structure Interiors; //80 Interiors: Array: 80: 10 {256: Structure: 0: 741495440}
|
||||
|
||||
public void SwapEnd()
|
||||
{
|
||||
MapDataGroups.SwapEnd();
|
||||
HDTxdBindingArray.SwapEnd();
|
||||
imapDependencies.SwapEnd();
|
||||
imapDependencies_2.SwapEnd();
|
||||
itypDependencies_2.SwapEnd();
|
||||
Interiors.SwapEnd();
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))] public struct CMapDataGroup : IPsoSwapEnd //56 bytes, Type:0
|
||||
{
|
||||
public MetaHash Name { get; set; } //0 Name: INT_0Bh: 0
|
||||
public uint Unused0 { get; set; } //4
|
||||
public Array_uint Bounds { get; set; } //8 Bounds//3298223272: Array: 8: 1 {256: INT_0Bh: 0}
|
||||
public ushort Flags { get; set; } //24 Flags: SHORT_0Fh: 24: 2097155
|
||||
public ushort Unused1 { get; set; }//26
|
||||
public uint Unused2 { get; set; }//28
|
||||
public Array_uint WeatherTypes { get; set; } //32 WeatherTypes: Array: 32: 5 {256: INT_0Bh: 0}
|
||||
public uint HoursOnOff { get; set; } //48 HoursOnOff//4190815249: INT_06h: 48
|
||||
public uint Unused3 { get; set; }//52
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name.ToString() + ": ybn:" + Bounds.Count1.ToString() + ", wt:" + WeatherTypes.Count1.ToString() + ", flags:" + Flags.ToString() + ", hours:" + HoursOnOff.ToString();
|
||||
}
|
||||
|
||||
public void SwapEnd()
|
||||
{
|
||||
Name = new MetaHash(MetaTypes.SwapBytes(Name.Hash));
|
||||
var b = Bounds; b.SwapEnd(); Bounds = b;
|
||||
var w = WeatherTypes; w.SwapEnd(); WeatherTypes = w;
|
||||
HoursOnOff = MetaTypes.SwapBytes(HoursOnOff);
|
||||
Flags = MetaTypes.SwapBytes(Flags);
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))] public struct CHDTxdAssetBinding : IPsoSwapEnd //132 bytes, Type:0
|
||||
{
|
||||
public byte assetType { get; set; } //0 assetType: BYTE_ENUM_VALUE: 0: 3387532954
|
||||
public byte Unused01 { get; set; }//1
|
||||
public ushort Unused02 { get; set; }//2
|
||||
public PsoChar64 targetAsset { get; set; } //4 targetAsset: INT_0Bh: 4: 4194304
|
||||
public PsoChar64 HDTxd { get; set; } //68 HDTxd: INT_0Bh: 68: 4194304
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return assetType.ToString() + ": " + targetAsset.ToString() + ": " + HDTxd.ToString();
|
||||
}
|
||||
public void SwapEnd()
|
||||
{
|
||||
//targetAsset.Hash = MetaTypes.SwapBytes(targetAsset.Hash);
|
||||
//HDTxd.Hash = MetaTypes.SwapBytes(HDTxd.Hash);
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))] public struct CImapDependency : IPsoSwapEnd //12 bytes, Type:0 // CImapDependency//3501026914
|
||||
{
|
||||
public MetaHash imapName { get; set; } //0 imapName: INT_0Bh: 0
|
||||
public MetaHash itypName { get; set; } //4 itypName//2890158180: INT_0Bh: 4
|
||||
public MetaHash packFileName { get; set; } //8 packFileName//4216494073: INT_0Bh: 8
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return imapName.ToString() + ", " + itypName.ToString() + ", " + packFileName.ToString();
|
||||
}
|
||||
public void SwapEnd()
|
||||
{
|
||||
imapName = new MetaHash(MetaTypes.SwapBytes(imapName.Hash));
|
||||
itypName = new MetaHash(MetaTypes.SwapBytes(itypName.Hash));
|
||||
packFileName = new MetaHash(MetaTypes.SwapBytes(packFileName.Hash));
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))] public struct CImapDependencies : IPsoSwapEnd //24 bytes, Type:0 // CImapDependencies//3240050401 imapDependencies_2
|
||||
{
|
||||
public MetaHash imapName { get; set; } //0 imapName: INT_0Bh: 0 //name hash
|
||||
public ushort manifestFlags { get; set; } //4 manifestFlags//1683136603: SHORT_0Fh: 4: 2097153
|
||||
public ushort Unused0 { get; set; } //6
|
||||
public Array_uint itypDepArray { get; set; } //8 itypDepArray//2410949350: Array: 8: 3 {256: INT_0Bh: 0} //children...
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return imapName.ToString() + ": " + manifestFlags.ToString() + ": " + itypDepArray.ToString();
|
||||
}
|
||||
public void SwapEnd()
|
||||
{
|
||||
imapName = new MetaHash(MetaTypes.SwapBytes(imapName.Hash));
|
||||
manifestFlags = MetaTypes.SwapBytes(manifestFlags);
|
||||
var d = itypDepArray; d.SwapEnd(); itypDepArray = d;
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))] public struct CItypDependencies : IPsoSwapEnd //24 bytes, Type:0 // CItypDependencies//1515605584 itypDependencies_2
|
||||
{
|
||||
public MetaHash itypName { get; set; } //0 itypName//2890158180: INT_0Bh: 0
|
||||
public ushort manifestFlags { get; set; } //4 manifestFlags//1683136603: SHORT_0Fh: 4: 2097153
|
||||
public ushort Unused0 { get; set; } //6
|
||||
public Array_uint itypDepArray { get; set; } //8 itypDepArray//2410949350: Array: 8: 3 {256: INT_0Bh: 0}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return itypName.ToString() + ": " + manifestFlags.ToString() + ": " + itypDepArray.ToString();
|
||||
}
|
||||
public void SwapEnd()
|
||||
{
|
||||
itypName = new MetaHash(MetaTypes.SwapBytes(itypName.Hash));
|
||||
manifestFlags = MetaTypes.SwapBytes(manifestFlags);
|
||||
var d = itypDepArray; d.SwapEnd(); itypDepArray = d;
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))] public struct Unk_741495440 : IPsoSwapEnd //24 bytes, Type:0 // Interiors
|
||||
{
|
||||
public MetaHash Name { get; set; } //0 Name: INT_0Bh: 0
|
||||
public uint Unused0 { get; set; } //4
|
||||
public Array_uint Bounds { get; set; } //8 Bounds//3298223272: Array: 8: 1 {256: INT_0Bh: 0}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return JenkIndex.GetString(Name);
|
||||
}
|
||||
public void SwapEnd()
|
||||
{
|
||||
Name = new MetaHash(MetaTypes.SwapBytes(Name.Hash));
|
||||
var b = Bounds; b.SwapEnd(); Bounds = b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[TC(typeof(EXP))] public struct CScenarioPointManifest : IPsoSwapEnd //56 bytes, Type:0
|
||||
{
|
||||
public int VersionNumber { get; set; } //0 VersionNumber: INT_05h: 0
|
||||
public uint Unused0 { get; set; } //4
|
||||
public Array_StructurePointer RegionDefs { get; set; } //8 RegionDefs: Array: 8: 1 {ARRAYINFO: Structure: 0}
|
||||
public Array_StructurePointer Groups { get; set; } //24 Groups: Array: 24: 3 {ARRAYINFO: Structure: 0}
|
||||
public Array_uint InteriorNames { get; set; } //40 InteriorNames: Array: 40: 5 {ARRAYINFO: INT_0Bh: 0}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return VersionNumber.ToString();
|
||||
}
|
||||
public void SwapEnd()
|
||||
{
|
||||
VersionNumber = MetaTypes.SwapBytes(VersionNumber);
|
||||
var r = RegionDefs; r.SwapEnd(); RegionDefs = r;
|
||||
var g = Groups; g.SwapEnd(); Groups = g;
|
||||
var i = InteriorNames; i.SwapEnd(); InteriorNames = i;
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))] public struct CScenarioPointRegionDef : IPsoSwapEnd //64 bytes, Type:0
|
||||
{
|
||||
public MetaHash Name { get; set; } //0 Name: INT_0Bh: 0
|
||||
public uint Unused0 { get; set; } //4
|
||||
public uint Unused1 { get; set; } //8
|
||||
public uint Unused2 { get; set; } //12
|
||||
public rage__spdAABB AABB { get; set; } //16 AABB: Structure: 16: rage__spdAABB
|
||||
public uint Unused3 { get; set; } //48
|
||||
public uint Unused4 { get; set; } //52
|
||||
public uint Unused5 { get; set; } //56
|
||||
public uint Unused6 { get; set; } //60
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name.ToString() + ", " + AABB.ToString();
|
||||
}
|
||||
public void SwapEnd()
|
||||
{
|
||||
Name = new MetaHash(MetaTypes.SwapBytes(Name.Hash));
|
||||
var aabb = AABB; aabb.SwapEnd(); AABB = aabb;
|
||||
}
|
||||
}
|
||||
|
||||
[TC(typeof(EXP))] public struct CScenarioPointGroup : IPsoSwapEnd //8 bytes, Type:0
|
||||
{
|
||||
public MetaHash Name { get; set; } //0 Name: INT_0Bh: 0
|
||||
public byte EnabledByDefault { get; set; } //4 EnabledByDefault: BYTE_00h: 4
|
||||
public byte Unused0 { get; set; } //5
|
||||
public ushort Unused1 { get; set; } //6
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name.ToString();
|
||||
}
|
||||
public void SwapEnd()
|
||||
{
|
||||
Name = new MetaHash(MetaTypes.SwapBytes(Name.Hash));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
Copyright(c) 2015 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.
|
||||
*/
|
||||
|
||||
//shamelessly stolen and mangled
|
||||
|
||||
|
||||
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 RbfFile
|
||||
{
|
||||
private const int RBF_IDENT = 0x30464252;
|
||||
|
||||
public RbfStructure current { get; set; }
|
||||
public Stack<RbfStructure> stack { get; set; }
|
||||
public List<RbfEntryDescription> descriptors { get; set; }
|
||||
|
||||
public RbfStructure Load(string fileName)
|
||||
{
|
||||
using (var fileStream = new FileStream(fileName, FileMode.Open))
|
||||
{
|
||||
return Load(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
public RbfStructure Load(Stream stream)
|
||||
{
|
||||
stack = new Stack<RbfStructure>();
|
||||
descriptors = new List<RbfEntryDescription>();
|
||||
|
||||
var reader = new DataReader(stream);
|
||||
var ident = reader.ReadInt32();
|
||||
if (ident != RBF_IDENT)
|
||||
throw new Exception("The file identifier does not match.");
|
||||
|
||||
while (reader.Position < reader.Length)
|
||||
{
|
||||
var descriptorIndex = reader.ReadByte();
|
||||
if (descriptorIndex == 0xFF) // close tag
|
||||
{
|
||||
var b = reader.ReadByte();
|
||||
if (b != 0xFF)
|
||||
throw new Exception("Expected 0xFF but was " + b.ToString("X2"));
|
||||
|
||||
if (stack.Count > 0)
|
||||
{
|
||||
current = stack.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reader.Position != reader.Length)
|
||||
throw new Exception("Expected end of stream but was not.");
|
||||
return current;
|
||||
}
|
||||
}
|
||||
else if (descriptorIndex == 0xFD) // bytes
|
||||
{
|
||||
var b = reader.ReadByte();
|
||||
if (b != 0xFF)
|
||||
throw new Exception("Expected 0xFF but was " + b.ToString("X2"));
|
||||
|
||||
var dataLength = reader.ReadInt32();
|
||||
var data = reader.ReadBytes(dataLength);
|
||||
|
||||
var bytesValue = new RbfBytes();
|
||||
bytesValue.Value = data;
|
||||
current.Children.Add(bytesValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dataType = reader.ReadByte();
|
||||
if (descriptorIndex == descriptors.Count) // new descriptor + data
|
||||
{
|
||||
var nameLength = reader.ReadInt16();
|
||||
var nameBytes = reader.ReadBytes(nameLength);
|
||||
var name = Encoding.ASCII.GetString(nameBytes);
|
||||
|
||||
var descriptor = new RbfEntryDescription();
|
||||
descriptor.Name = name;
|
||||
descriptor.Type = dataType;
|
||||
descriptors.Add(descriptor);
|
||||
|
||||
ParseElement(reader, descriptors.Count - 1, dataType);
|
||||
}
|
||||
else // existing descriptor + data
|
||||
{
|
||||
if (dataType != descriptors[descriptorIndex].Type)
|
||||
{
|
||||
//throw new Exception("Data type does not match. Expected "
|
||||
// + descriptors[descriptorIndex].Type.ToString() + " but found "
|
||||
// + dataType.ToString() + ". Descriptor: " + descriptors[descriptorIndex].Name);
|
||||
}
|
||||
|
||||
ParseElement(reader, descriptorIndex, dataType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("Unexpected end of stream.");
|
||||
}
|
||||
|
||||
private void ParseElement(DataReader reader, int descriptorIndex, byte dataType)
|
||||
{
|
||||
var descriptor = descriptors[descriptorIndex];
|
||||
switch (dataType) //(descriptor.Type)
|
||||
{
|
||||
case 0: // open element...
|
||||
{
|
||||
var structureValue = new RbfStructure();
|
||||
structureValue.Name = descriptor.Name;
|
||||
|
||||
if (current != null)
|
||||
{
|
||||
current.Children.Add(structureValue);
|
||||
stack.Push(current);
|
||||
}
|
||||
|
||||
current = structureValue;
|
||||
|
||||
// 6 bytes
|
||||
var x1 = reader.ReadInt16();
|
||||
var x2 = reader.ReadInt16();
|
||||
var x3 = reader.ReadInt16();
|
||||
//if (x1 != 0)
|
||||
// throw new Exception("unexpected");
|
||||
//if (x2 != 0)
|
||||
// throw new Exception("unexpected");
|
||||
//if (x3 != 0)
|
||||
// throw new Exception("unexpected");
|
||||
break;
|
||||
}
|
||||
case 0x10:
|
||||
{
|
||||
var intValue = new RbfUint32();
|
||||
intValue.Name = descriptor.Name;
|
||||
intValue.Value = reader.ReadUInt32();
|
||||
current.Children.Add(intValue);
|
||||
break;
|
||||
}
|
||||
case 0x20:
|
||||
{
|
||||
var booleanValue = new RbfBoolean();
|
||||
booleanValue.Name = descriptor.Name;
|
||||
booleanValue.Value = true;
|
||||
current.Children.Add(booleanValue);
|
||||
break;
|
||||
}
|
||||
case 0x30:
|
||||
{
|
||||
var booleanValue = new RbfBoolean();
|
||||
booleanValue.Name = descriptor.Name;
|
||||
booleanValue.Value = false;
|
||||
current.Children.Add(booleanValue);
|
||||
break;
|
||||
}
|
||||
case 0x40:
|
||||
{
|
||||
var floatValue = new RbfFloat();
|
||||
floatValue.Name = descriptor.Name;
|
||||
floatValue.Value = reader.ReadSingle();
|
||||
current.Children.Add(floatValue);
|
||||
break;
|
||||
}
|
||||
case 0x50:
|
||||
{
|
||||
var floatVectorValue = new RbfFloat3();
|
||||
floatVectorValue.Name = descriptor.Name;
|
||||
floatVectorValue.X = reader.ReadSingle();
|
||||
floatVectorValue.Y = reader.ReadSingle();
|
||||
floatVectorValue.Z = reader.ReadSingle();
|
||||
current.Children.Add(floatVectorValue);
|
||||
break;
|
||||
}
|
||||
case 0x60:
|
||||
{
|
||||
var valueLength = reader.ReadInt16();
|
||||
var valueBytes = reader.ReadBytes(valueLength);
|
||||
var value = Encoding.ASCII.GetString(valueBytes);
|
||||
var stringValue = new RbfString();
|
||||
stringValue.Name = descriptor.Name;
|
||||
stringValue.Value = value;
|
||||
current.Children.Add(stringValue);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Exception("Unsupported data type.");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsRBF(Stream stream)
|
||||
{
|
||||
var reader = new DataReader(stream);
|
||||
var origpos = stream.Position;
|
||||
var ident = reader.ReadInt32();
|
||||
var isrbf = (ident == RBF_IDENT);
|
||||
stream.Position = origpos;
|
||||
return isrbf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfEntryDescription
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Type { get; set; }
|
||||
public override string ToString() { return Name + ": " + Type.ToString(); }
|
||||
}
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public interface IRbfType
|
||||
{
|
||||
string Name { get; set; }
|
||||
}
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfBoolean : IRbfType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public bool Value { get; set; }
|
||||
public override string ToString() { return Name + ": " + Value.ToString(); }
|
||||
}
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfBytes : IRbfType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public byte[] Value { get; set; }
|
||||
public override string ToString() { return Name + ": " + Value.ToString(); }
|
||||
}
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfFloat : IRbfType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public float Value { get; set; }
|
||||
public override string ToString() { return Name + ": " + Value.ToString(); }
|
||||
}
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfFloat3 : IRbfType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public float X { get; set; }
|
||||
public float Y { get; set; }
|
||||
public float Z { get; set; }
|
||||
public override string ToString() { return string.Format("{0}: X:{1}, Y:{2}, Z:{3}", Name, X, Y, Z); }
|
||||
}
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfString : IRbfType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Value { get; set; }
|
||||
public override string ToString() { return Name + ": " + Value.ToString(); }
|
||||
}
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfStructure : IRbfType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<IRbfType> Children { get; set; } = new List<IRbfType>();
|
||||
public override string ToString() { return Name + ": {" + Children.Count.ToString() + "}"; }
|
||||
public IRbfType FindChild(string name)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (child == null) continue;
|
||||
if (child.Name == name) return child;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfUint32 : IRbfType
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public uint Value { get; set; }
|
||||
public override string ToString() { return Name + ": " + Value.ToString(); }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user