R26_dev8 - First public commit

This commit is contained in:
dexyfex
2017-09-21 20:33:05 +10:00
Unverified
commit a8243c3e0e
391 changed files with 157678 additions and 0 deletions
+641
View File
@@ -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);
}
}
}
+377
View File
@@ -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
+910
View File
@@ -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();
}
}
}
+856
View File
@@ -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));
}
}
}
+295
View File
@@ -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(); }
}
}